dms_tailscalectl/skills/dms-plugin-dev/docs/cheatsheets.md
vybe 01ac7e9041 feat: add dms-plugin-dev agent skill for Dank Material Shell plugin development
- Introduces a general-purpose opencode skill to help agents build, debug, and publish DMS plugins.
- Includes orientation, decision trees (plugin types), condensed cheat sheets, ecosystem map, and four generic vertical-slice starter templates (bar widget, popout widget, launcher, desktop widget).
- Skill is versioned here for this project while remaining available as a global opencode skill.
- Updated .gitignore to ignore globally-installed copies of the skill.

Written by AI agent working for @jtmorris. Model: grok-build-0.1.
2026-05-24 09:31:06 +00:00

142 lines
No EOL
5.9 KiB
Markdown

# DMS Plugin Cheat Sheets
These are deliberately condensed surfaces. For full details and current property lists, read the official plugin-development guide for the exact DMS version in use.
## plugin.json — Fields That Actually Matter
Required for all:
- `id` (camelCase, unique, used for reload and data keys)
- `name`, `description`, `version`, `author`
- `type`: "widget" | "launcher" | "daemon" | "desktop"
- `component`: relative path to the root QML file
Strongly recommended:
- `icon` (Material icon name shown in the Plugins list)
- `permissions`: array — `"settings_write"` is required if you provide a settings component using `PluginSettings`
- `capabilities`: helps the UI know where to offer the plugin (e.g. `["dankbar-widget"]`, `["control-center"]`, `["desktop-widget"]`, `["launcher"]`)
- `settings`: relative path to the settings QML (only if you want a UI in Settings → Plugins)
Launcher-specific:
- `trigger`: the prefix string (or `""` for always-visible)
- `viewMode`: "list" | "grid" | "tile"
- `viewModeEnforced`: boolean
Desktop-specific:
- `requires_dms`: e.g. `">=1.2.0"`
`requires` (array of external tools) is used for documentation and install hints.
## PluginComponent (the base for almost every widget)
Auto-injected (never declare these yourself):
- `pluginData` — reactive object containing everything saved via the settings system for this plugin
- `pluginService`
- `pluginId`
- `axis`, `section`, `parentScreen`, `widgetThickness`, `barThickness`, `iconSize`, `variants`
You define:
- `horizontalBarPill: Component { ... }`
- `verticalBarPill: Component { ... }` (can be the same or different layout)
- `popoutContent: Component { PopoutComponent { ... } }` (optional but very common)
- `popoutWidth`, `popoutHeight`
- `layerNamespacePlugin: "unique-name"` (strongly recommended for any popout widget)
- `pillClickAction` / `pillRightClickAction` (to override the default popout behavior)
For Control Center presence, also define:
- `ccWidgetIcon`, `ccWidgetPrimaryText`, `ccWidgetSecondaryText`, `ccWidgetIsActive`
- `onCcWidgetToggled`
- `ccDetailContent` (for the expandable detail panel on CompoundPill)
## PopoutComponent
Convenience wrapper that gives you a consistent header + details area + `closePopout()` function.
Expose `headerHeight` and `detailsHeight` so your content can compute the remaining space correctly.
## PluginService Data APIs (three different stores)
1. **Settings** (`savePluginData` / `loadPluginData`)
- Persisted in the shared `plugin_settings.json`
- Shown/edited via the `*Setting` components inside `PluginSettings`
- Use for user preferences
2. **State** (`savePluginState` / `loadPluginState`)
- Per-plugin `_state.json` file in `~/.local/state/DankMaterialShell/plugins/`
- Not shown in settings UI
- Good for command history, recent items, runtime caches that should survive reloads
3. **Global Variables** (`getGlobalVar` / `setGlobalVar` + `PluginGlobalVar` helper)
- In-memory, reactive across **all instances** of the same plugin
- Not persisted
- Perfect for "current selection", counters, shared UI state on multi-monitor bars
The modern settings UI components (`StringSetting`, `ToggleSetting`, `ColorSetting`, `SliderSetting`, `SelectionSetting`, `ListSettingWithInput`, etc.) live inside a `PluginSettings { pluginId: "..." }` root and handle load/save automatically.
## Launcher Plugin Shape (different from widgets)
Root must be a `QtObject { id: root ... }`
You must provide (at minimum):
- `getItems(query)` → array of item objects
- `executeItem(item)`
Optional but powerful:
- `getContextMenuActions(item)` → array of `{icon, text, action, closeLauncher?}`
- `getCategories()` + `setCategory(id)`
- `getPasteText(item)` and/or `getPasteArgs(item)` for Shift+Enter paste support
Item shape includes `name`, `icon` (or `unicode:...`), `comment`, `action`, `imageUrl`, `animated`, `attribution`, `categories`, `keywords`.
Call `pluginService.requestLauncherUpdate(pluginId)` after async data arrives.
## External Commands
Prefer `Proc.runCommand(id, argv, (stdout, exitCode) => {...}, debounceMs)` from `qs.Common`.
It gives you captured stdout, automatic cleanup, and debouncing by id.
Only fall back to a raw `Process` item when you truly need a long-lived or streaming process.
## Desktop Widgets (DesktopPluginComponent)
- Set `minWidth` / `minHeight` (and optionally `defaultWidth` / `defaultHeight`, `forceSquare`)
- Read `widgetWidth`, `widgetHeight`, `pluginData`
- Use the helper methods `getData(key, default)` and `setData(key, value)` if you want the thin wrappers
- Position/size is persisted automatically per screen
- User interaction: right-click-drag anywhere to move, right-click-drag bottom-right corner to resize
## Permissions (the one that bites agents)
If your plugin has a `settings` component that uses `PluginSettings`, you **must** list `"settings_write"` in the `permissions` array.
Without it the settings UI will show an error instead of your form.
Other permissions (`settings_read`, `process`, `network`) are declared for documentation and future enforcement.
## Layer Namespaces for Popouts
On any `PluginComponent` that opens a popout:
```qml
layerNamespacePlugin: "my-unique-popout"
```
This gives the popout its own layer namespace under `dms:plugins:...` and avoids focus/z-order fights with other DMS popouts.
## Hot Reload & Debugging
- `dms ipc call plugins reload <id>`
- `dms ipc call plugins list`
- `dms ipc call plugins status <id>`
- Run the shell from a terminal (`dms run` or equivalent) so you see QML errors and `console.log`
## Theme, Toast, I18n
Always go through the singletons:
- `Theme.*` for colors, spacing, font sizes, corner radii
- `ToastService.showInfo(...)` / `showError(...)`
- `I18n.tr("text", "context for translators")`
Never hard-code colors or sizes.
This is enough to get 80% of plugins correct on the first serious attempt. For the remaining 20%, go to the official development guide for the exact property lists and edge cases.