1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-06-27 05:25:19 -04:00

skill(dms-plugin-dev): update for composite plugins, startupCheck, IPC discovery (#2699)

- Add composite plugin type with multi-surface components field
- Add startupCheck manifest field and dependency gating docs
- Add IPC runtime plugin discovery commands (plugin-scan target)
- Add getPluginPath() to data persistence reference
- Document bar reveal visibility optimization for widget plugins
- Sync plugin-schema.json with source, add dependencies field
- Bump skill version to 1.1
This commit is contained in:
Bruno Rocha
2026-06-25 16:53:07 +01:00
committed by GitHub
parent 1e7ee25e13
commit 92994061da
5 changed files with 289 additions and 34 deletions
@@ -166,6 +166,16 @@ function increment() {
| Cross-instance sync (multi-monitor data) | `PluginGlobalVar` or `getGlobalVar`/`setGlobalVar` | No (runtime only) | All instances |
| Quick reactive reads from settings | `pluginData` property | N/A (read-only) | Per instance |
## Plugin Path
Retrieve a plugin's installation directory at runtime:
```qml
var dir = pluginService.getPluginPath(pluginId)
```
Returns the absolute path to the plugin's directory (e.g., `~/.config/DankMaterialShell/plugins/MyPlugin`), or an empty string if the plugin is not found. Useful for loading bundled assets (images, data files) relative to the plugin's location.
## Important Notes
1. **pluginData is reactive** - bindings update automatically when data changes
@@ -9,15 +9,22 @@
| `description` | string | Short description (shown in UI) | Non-empty |
| `version` | string | Semantic version | Pattern `^\d+\.\d+\.\d+(-[a-zA-Z0-9.-]+)?(\+[a-zA-Z0-9.-]+)?$` |
| `author` | string | Creator name or email | Non-empty |
| `type` | string | Plugin type | One of: `widget`, `daemon`, `launcher`, `desktop` |
| `type` | string | Plugin type | One of: `widget`, `daemon`, `launcher`, `desktop`, `composite` |
| `capabilities` | array | Plugin capabilities | At least 1 string item |
| `component` | string | Path to main QML file | Must start with `./`, end with `.qml` |
One of `component` or `components` is required (not both):
| Field | Type | Description | Validation |
|-------|------|-------------|------------|
| `component` | string | Path to main QML file (single-surface plugins) | Must start with `./`, end with `.qml` |
| `components` | object | Map of surface name to QML path (multi-surface plugins) | At least 1 entry; keys: `widget`, `desktop`, `daemon`, `launcher` |
## Conditional Requirements
| Condition | Required Field | Description |
|-----------|---------------|-------------|
| `type: "launcher"` | `trigger` | Trigger string for launcher activation (e.g., `=`, `#`, `!`) |
| `components` has `launcher` key | `trigger` | Same requirement applies to composite plugins with a launcher surface |
## Optional Fields
@@ -25,8 +32,10 @@
|-------|------|-------------|
| `icon` | string | Material Design icon name (displayed in plugin list UI) |
| `settings` | string | Path to settings QML file (must start with `./`, end with `.qml`) |
| `startupCheck` | string | Path to a QtObject component that gates plugin activation via a `check(done)` function (must start with `./`, end with `.qml`). See Startup Check section below. |
| `requires_dms` | string | Minimum DMS version (e.g., `>=0.1.18`), pattern `^(>=?\|<=?\|=\|>\|<)\d+\.\d+\.\d+$` |
| `requires` | array | System tool dependencies (e.g., `["curl", "jq"]`) |
| `dependencies` | array | System tool dependencies (e.g., `["curl", "jq"]`). Registry metadata. |
| `requires` | array | Deprecated alias for `dependencies` |
| `permissions` | array | Required permissions |
| `trigger` | string | Launcher trigger string (required for launcher type) |
@@ -53,6 +62,65 @@ Capabilities are free-form strings that describe what the plugin does. Common va
- `ai` - AI/LLM integration
- `slideout` - uses slideout panel
## Startup Check
The `startupCheck` field points to a non-visual `QtObject` component that gates plugin activation on dependency checks. The component must expose a `check(done)` function:
```qml
import QtQuick
import qs.Common
QtObject {
function check(done) {
Proc.runCommand("myPlugin.depCheck", ["sh", "-c", "command -v mytool"], (stdout, exitCode) => {
if (exitCode === 0) {
done(null);
return;
}
done({
"title": I18n.tr("mytool is required"),
"details": I18n.tr("Install 'mytool' and re-enable this plugin.")
});
});
}
}
```
The `done` callback accepts:
- `null` - allow activation
- A string - block with a short error message
- `{ title, details }` - block with a title and expandable details
A synchronous variant (no `done` parameter, return the result directly) is also supported.
Failed startup checks show a toast error and store the error in `pluginService.pluginLoadErrors`.
## Components (Composite Plugins)
The `components` field maps surface names to QML paths, allowing a single plugin to register multiple surfaces:
```json
{
"id": "myComposite",
"name": "My Composite Plugin",
"description": "Daemon + widget + desktop from one plugin",
"version": "1.0.0",
"author": "Developer Name",
"type": "composite",
"capabilities": ["daemon", "dankbar-widget", "desktop-widget"],
"icon": "extension",
"components": {
"daemon": "./MyDaemon.qml",
"widget": "./MyBarWidget.qml",
"desktop": "./MyDesktopWidget.qml"
},
"settings": "./Settings.qml",
"permissions": ["settings_read", "settings_write"]
}
```
Valid surface keys: `widget`, `desktop`, `daemon`, `launcher`. Provide any subset. Each surface is loaded independently in the appropriate registry.
## Complete Example
```json
@@ -67,8 +135,9 @@ Capabilities are free-form strings that describe what the plugin does. Common va
"component": "./MyWidget.qml",
"icon": "extension",
"settings": "./Settings.qml",
"startupCheck": "./StartupCheck.qml",
"requires_dms": ">=0.1.18",
"requires": ["curl", "jq"],
"dependencies": ["curl", "jq"],
"permissions": ["settings_read", "settings_write", "process", "network"]
}
```
@@ -235,10 +235,12 @@ Conditionally show/hide the bar pill:
```qml
PluginComponent {
visibilityCommand: "pgrep -x myapp"
visibilityInterval: 5 // seconds between checks; polling pauses while the bar is hidden
visibilityInterval: 5 // seconds between checks
}
```
**Bar reveal optimization:** The visibility timer automatically pauses while the bar is hidden (auto-hide mode) and resumes checks when the bar is revealed. This is handled via the internal `_barRevealed` property - no plugin code needed. Plugins using `visibilityCommand` with `visibilityInterval` benefit from this automatically.
## Popout Namespace
For plugins with multiple popout instances, use `layerNamespacePlugin` to isolate popout state: