- 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.
142 lines
No EOL
5.9 KiB
Markdown
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. |