From 85c13788765e471b7ccc113e783dbdd1fe8c598d Mon Sep 17 00:00:00 2001 From: Bonanza Date: Fri, 24 Jul 2026 09:34:17 -0700 Subject: [PATCH 01/11] fix(deploy): install path com.twopanez -> AppOS (audit B1) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The host's on-disk storage root is ~/Library/Application Support/AppOS/ (AppOS-Desktop AppStoragePaths.swift:20,27-32; PluginHostConfiguration.swift:65,70 appends 'plugins' to that root). The com.twopanez path was never the shipping install dir for the AppOS host, and the 'installer has not been renamed' note was false — deleted. Remaining com.twopanez mentions live only in compiled/ artifacts, which get the same substitution in the compiled-refresh commit. --- README.md | 2 +- plugins/appos-dev/commands/deploy.md | 8 +++----- plugins/appos-dev/skills/appos-plugin-dev/SKILL.md | 6 +++--- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 40dc66b..a1bc8a4 100644 --- a/README.md +++ b/README.md @@ -72,7 +72,7 @@ claude --plugin-dir /path/to/appos-dev-plugin/ - Max 2 WebView panels per plugin, 6 globally - WebView CSP blocks inline scripts/styles/handlers — everything external, ES modules only - `pipeShellToWebPanel` lives on `ctx.ui`, NOT `ctx.shell` (stale docs are wrong) -- Install path: `~/Library/Application Support/com.twopanez/plugins/{plugin-id}/` (see `/appos-dev:deploy`) +- Install path: `~/Library/Application Support/AppOS/plugins/{plugin-id}/` (see `/appos-dev:deploy`) ## License diff --git a/plugins/appos-dev/commands/deploy.md b/plugins/appos-dev/commands/deploy.md index 36f40f7..c881e78 100644 --- a/plugins/appos-dev/commands/deploy.md +++ b/plugins/appos-dev/commands/deploy.md @@ -5,9 +5,7 @@ description: Deploy the current AppOS plugin to the local plugins directory # Deploy the current AppOS plugin -Deploy the built plugin to `~/Library/Application Support/com.twopanez/plugins/`. - -**Destination path note**: The host app's on-disk bundle ID is `com.twopanez` (legacy identifier). Do not change this path; the installer has not been renamed. +Deploy the built plugin to `~/Library/Application Support/AppOS/plugins/`. ## 1. Find and read plugin.json @@ -28,7 +26,7 @@ If the plugin has a `webview/` directory, also verify at least one `webview/*/in ```bash PLUGIN_ID="{id-from-plugin.json}" -INSTALL_DIR="$HOME/Library/Application Support/com.twopanez/plugins/$PLUGIN_ID" +INSTALL_DIR="$HOME/Library/Application Support/AppOS/plugins/$PLUGIN_ID" mkdir -p "$INSTALL_DIR" rsync -av --delete --delete-excluded \ @@ -74,7 +72,7 @@ Report the deployment path and next steps: ``` Deployed {plugin-name} ({plugin-id}) to: - ~/Library/Application Support/com.twopanez/plugins/{plugin-id}/ + ~/Library/Application Support/AppOS/plugins/{plugin-id}/ Files installed: - plugin.json diff --git a/plugins/appos-dev/skills/appos-plugin-dev/SKILL.md b/plugins/appos-dev/skills/appos-plugin-dev/SKILL.md index 8069196..8625a1d 100644 --- a/plugins/appos-dev/skills/appos-plugin-dev/SKILL.md +++ b/plugins/appos-dev/skills/appos-plugin-dev/SKILL.md @@ -509,7 +509,7 @@ if (isWatch) { ## Deploy -Install to the user plugin directory. The on-disk bundle ID prefix is `com.twopanez` (legacy host identifier — do not rename), not `space.appos`: +Install to the user plugin directory `~/Library/Application Support/AppOS/plugins/$PLUGIN_ID/`: ```bash rsync -av --delete --delete-excluded \ @@ -519,7 +519,7 @@ rsync -av --delete --delete-excluded \ --exclude='package.json' --exclude='package-lock.json' \ --exclude='CLAUDE.md' --exclude='AGENTS.md' --exclude='SPEC.md' \ --exclude='types/' --exclude='dist/main.js.map' \ - ./ "$HOME/Library/Application Support/com.twopanez/plugins/$PLUGIN_ID/" + ./ "$HOME/Library/Application Support/AppOS/plugins/$PLUGIN_ID/" ``` **Critical flags:** @@ -546,7 +546,7 @@ Then restart AppOS to pick up the new plugin (plugins are loaded at startup). - **`--ignore-config`** or equivalent on every wrapped CLI invocation — neutralize ambient user config that could inject dangerous flags. - **`minHostVersion` is the HOST version**, NOT the SDK version. Default to `"1.0.0"`. - **Host does not expose `unregisterFilterType`** — smart folder filters auto-clean on unload. Use a `disposed` flag guard. -- **Install path**: `~/Library/Application Support/com.twopanez/plugins/$PLUGIN_ID/` (note `com.twopanez`, not `space.appos`). +- **Install path**: `~/Library/Application Support/AppOS/plugins/$PLUGIN_ID/`. ## Reference files From b9434dfd730e7946d107c12d2ef42611e4a82f54 Mon Sep 17 00:00:00 2001 From: Bonanza Date: Fri, 24 Jul 2026 09:34:57 -0700 Subject: [PATCH 02/11] fix(docs): host version 1.7.0 -> 1.0.0, 2Panez.app -> AppOS.app (audit M1) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ground truth from AppOS-Desktop project.yml:14 (MARKETING_VERSION 1.0.0) and project.yml:85 (PRODUCT_NAME AppOS -> /Applications/AppOS.app). The 1.7.0 / 2Panez.app values described a pre-rename dev build that never shipped. Also drops the '(legacy name, do not rename)' caveat in CLAUDE.md — the shipping bundle is AppOS.app. compiled/ artifacts get the same substitution in the compiled-refresh commit. --- CLAUDE.md | 4 ++-- plugins/appos-dev/agents/plugin-architect.md | 2 +- plugins/appos-dev/commands/new-plugin.md | 2 +- plugins/appos-dev/commands/validate.md | 2 +- plugins/appos-dev/skills/appos-plugin-dev/SKILL.md | 4 ++-- .../skills/appos-plugin-dev/reference/extension-api.md | 2 +- .../appos-dev/skills/appos-plugin-dev/reference/patterns.md | 4 ++-- 7 files changed, 10 insertions(+), 10 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index e5d891d..7b99483 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -39,12 +39,12 @@ Before editing anything, be aware of these external sources of truth: - **Flagship reference plugin**: `~/Documents/GitHub/AppOS/appos-plugin-ytdlp/` — all patterns in the skills match this plugin's implementation. When in doubt, read its source files. - **SDK source**: `~/Documents/GitHub/AppOS/plugin-sdk/packages/plugin-types/dist/` — the current declaration-only TypeScript types. Use for reference when validating API shapes in skills or commands. -- **Host version**: read `/Applications/2Panez.app/Contents/Info.plist` → `CFBundleShortVersionString` (currently `1.7.0`). This is the host app's on-disk bundle (legacy name, do not rename); its version is what `plugin.json` `minHostVersion` is compared against, NOT the SDK package version. +- **Host version**: read `/Applications/AppOS.app/Contents/Info.plist` → `CFBundleShortVersionString` (currently `1.0.0`). The host version is what `plugin.json` `minHostVersion` is compared against, NOT the SDK package version. ## Conventions - **Plugin IDs**: use `space.appos.*` for flagship plugins (the ones shipped with AppOS), `com.community.*` for community plugins, other reverse-domain for private/personal plugins. -- **minHostVersion**: always default to `"1.0.0"`. The single biggest cause of "plugin installed but not appearing in Settings" is conflating the SDK version (`2.4.x`) with the host version (`1.7.x`). The `appos-plugin-dev` skill has a "minHostVersion landmine" section; keep it prominent. +- **minHostVersion**: always default to `"1.0.0"`. The single biggest cause of "plugin installed but not appearing in Settings" is conflating the SDK version (`2.4.x`) with the host version (`1.0.x`). The `appos-plugin-dev` skill has a "minHostVersion landmine" section; keep it prominent. - **tsconfig**: always include `verbatimModuleSyntax: true`. Without it, TypeScript emits broken runtime imports from the declaration-only `@appos.space/plugin-types` package. - **Entry point**: always `globalThis.activate = activate` + `globalThis.deactivate = deactivate`, never ESM `export`. ESM exports disappear inside the IIFE closure and the host can't find them. - **Parameter naming**: always `ctx`, never `pluginContext`. Matches `appos-plugin-ytdlp` and every reference plugin. diff --git a/plugins/appos-dev/agents/plugin-architect.md b/plugins/appos-dev/agents/plugin-architect.md index b1c1d29..1e42438 100644 --- a/plugins/appos-dev/agents/plugin-architect.md +++ b/plugins/appos-dev/agents/plugin-architect.md @@ -144,7 +144,7 @@ Recommend settings based on what should be user-configurable. Setting types: `st ### 7. minHostVersion -**Always default to `"1.0.0"`.** Do NOT use the SDK version from `@appos.space/plugin-types` — that's a different number. The host compares `minHostVersion` against its `CFBundleShortVersionString` (currently `1.7.0`), and too-high values cause silent plugin rejection. See `appos-plugin-dev` skill → "minHostVersion landmine". +**Always default to `"1.0.0"`.** Do NOT use the SDK version from `@appos.space/plugin-types` — that's a different number. The host compares `minHostVersion` against its `CFBundleShortVersionString` (currently `1.0.0`), and too-high values cause silent plugin rejection. See `appos-plugin-dev` skill → "minHostVersion landmine". ### 8. Output format diff --git a/plugins/appos-dev/commands/new-plugin.md b/plugins/appos-dev/commands/new-plugin.md index 8751de1..27cb2c5 100644 --- a/plugins/appos-dev/commands/new-plugin.md +++ b/plugins/appos-dev/commands/new-plugin.md @@ -150,7 +150,7 @@ if (isWatch) { ## 8. Write plugin.json -**LANDMINE**: `minHostVersion` refers to the host app's `CFBundleShortVersionString` (currently `1.7.0`), NOT the `@appos.space/plugin-types` SDK version. Defaulting to the SDK version (e.g. `"2.4.0"`) will cause `DependencyResolver.swift` to silently reject the plugin before it reaches the plugins sheet. **Always default to `"1.0.0"`.** +**LANDMINE**: `minHostVersion` refers to the host app's `CFBundleShortVersionString` (currently `1.0.0`), NOT the `@appos.space/plugin-types` SDK version. Defaulting to the SDK version (e.g. `"2.4.0"`) will cause `DependencyResolver.swift` to silently reject the plugin before it reaches the plugins sheet. **Always default to `"1.0.0"`.** ```json { diff --git a/plugins/appos-dev/commands/validate.md b/plugins/appos-dev/commands/validate.md index e64633b..814498e 100644 --- a/plugins/appos-dev/commands/validate.md +++ b/plugins/appos-dev/commands/validate.md @@ -22,7 +22,7 @@ Read `plugin.json` and check: - **Version**: valid semver (MAJOR.MINOR.PATCH) - **minHostVersion**: **LANDMINE CHECK** — this must be the host app `CFBundleShortVersionString`, NOT the `@appos.space/plugin-types` SDK version. If it's set to `"2.0.0"`, `"2.1.0"`, `"2.2.0"`, `"2.3.0"`, `"2.4.0"`, or similar SDK-like values, flag it as an ERROR. Default safe value: `"1.0.0"`. Host version can be read via: ```bash - defaults read /Applications/2Panez.app/Contents/Info.plist CFBundleShortVersionString + defaults read /Applications/AppOS.app/Contents/Info.plist CFBundleShortVersionString ``` - **Permissions**: must be from the valid set (see below) diff --git a/plugins/appos-dev/skills/appos-plugin-dev/SKILL.md b/plugins/appos-dev/skills/appos-plugin-dev/SKILL.md index 8625a1d..c003e1b 100644 --- a/plugins/appos-dev/skills/appos-plugin-dev/SKILL.md +++ b/plugins/appos-dev/skills/appos-plugin-dev/SKILL.md @@ -435,10 +435,10 @@ const token = ctx.lifecycle.onDependencyStatusChanged((statuses) => { ### minHostVersion LANDMINE -`minHostVersion` is compared against the host app's `CFBundleShortVersionString` (e.g., `1.7.0` for `/Applications/2Panez.app`), **NOT** the `@appos.space/plugin-types` SDK version (`2.4.x`). Conflating them causes silent plugin load failures — `DependencyResolver` emits `hostVersionTooLow` and the plugin never appears in the Settings sheet. +`minHostVersion` is compared against the host app's `CFBundleShortVersionString` (e.g., `1.0.0` for `/Applications/AppOS.app`), **NOT** the `@appos.space/plugin-types` SDK version (`2.4.x`). Conflating them causes silent plugin load failures — `DependencyResolver` emits `hostVersionTooLow` and the plugin never appears in the Settings sheet. - Default to `"1.0.0"` unless you know you need a newer host. -- Check the real host version with `defaults read /Applications/2Panez.app/Contents/Info.plist CFBundleShortVersionString`. +- Check the real host version with `defaults read /Applications/AppOS.app/Contents/Info.plist CFBundleShortVersionString`. - If a plugin doesn't appear after install + restart, CHECK THIS FIRST. ### Permissions diff --git a/plugins/appos-dev/skills/appos-plugin-dev/reference/extension-api.md b/plugins/appos-dev/skills/appos-plugin-dev/reference/extension-api.md index 001e00b..9b7f6d4 100644 --- a/plugins/appos-dev/skills/appos-plugin-dev/reference/extension-api.md +++ b/plugins/appos-dev/skills/appos-plugin-dev/reference/extension-api.md @@ -2,7 +2,7 @@ This is a high-level map of the `@appos.space/plugin-types` SDK surface. For exact type signatures, read `plugin-api.d.ts` in this directory (a consolidated snapshot of the live SDK declaration files). For working examples of every API, read `~/Documents/GitHub/AppOS/appos-plugin-ytdlp/`. -SDK version: **2.4.0-fn50**. Host version: check `/Applications/2Panez.app/Contents/Info.plist` → `CFBundleShortVersionString` (currently `1.7.0`). +SDK version: **2.4.0-fn50**. Host version: check `/Applications/AppOS.app/Contents/Info.plist` → `CFBundleShortVersionString` (currently `1.0.0`). ## The PluginContext diff --git a/plugins/appos-dev/skills/appos-plugin-dev/reference/patterns.md b/plugins/appos-dev/skills/appos-plugin-dev/reference/patterns.md index 8c57b21..0587265 100644 --- a/plugins/appos-dev/skills/appos-plugin-dev/reference/patterns.md +++ b/plugins/appos-dev/skills/appos-plugin-dev/reference/patterns.md @@ -532,12 +532,12 @@ rsync -av --delete --delete-excluded \ } ``` -**ALWAYS** default `minHostVersion` to `"1.0.0"`. The host compares this against its `CFBundleShortVersionString` (currently `1.7.0`), NOT the SDK package version (`2.4.x`). Setting `minHostVersion` to `"2.4.0"` because you saw that number in `@appos.space/plugin-types/package.json` will cause `DependencyResolver.swift` to silently reject the plugin before it reaches the Settings → Plugins sheet. No error dialog, no log entry you'll think to check. +**ALWAYS** default `minHostVersion` to `"1.0.0"`. The host compares this against its `CFBundleShortVersionString` (currently `1.0.0`), NOT the SDK package version (`2.4.x`). Setting `minHostVersion` to `"2.4.0"` because you saw that number in `@appos.space/plugin-types/package.json` will cause `DependencyResolver.swift` to silently reject the plugin before it reaches the Settings → Plugins sheet. No error dialog, no log entry you'll think to check. To verify the actual host version: ```bash -defaults read /Applications/2Panez.app/Contents/Info.plist CFBundleShortVersionString +defaults read /Applications/AppOS.app/Contents/Info.plist CFBundleShortVersionString ``` ## 17. WebView panel with plugin-to-webview messaging From 256ac0cba986d2789931b66a3fa67d33c01cf35a Mon Sep 17 00:00:00 2001 From: Bonanza Date: Fri, 24 Jul 2026 09:36:29 -0700 Subject: [PATCH 03/11] fix(validate): schema-driven manifest validation via plugin-sdk plugin-v1.json (audit B2) Replaces the stale closed 33-item permission list with validation against the SDK's authoritative schemas/plugin-v1.json (which also covers required fields and shapes). Two documented mechanisms, both verified against the flagship appos-plugin-ytdlp manifest (origin/main 22d1c63): - Preferred: curl the schema from the public appos/plugin-sdk repo + 'npx -p ajv-cli -p ajv-formats ajv validate --spec=draft2020' -> exit 0, 'ytdlp-plugin.json valid' - Alternative: 'node scripts/validate-schema.mjs ' from a plugin-sdk clone (positional manifest paths) -> exit 0, '1 passed, 0 failed' The old list was wrong in both directions: it contained permissions that do not exist in the schema and omitted dozens that do (events.*, store.*, vault.*, clipboard.*.register, ...). --- plugins/appos-dev/commands/validate.md | 31 ++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/plugins/appos-dev/commands/validate.md b/plugins/appos-dev/commands/validate.md index 814498e..b361780 100644 --- a/plugins/appos-dev/commands/validate.md +++ b/plugins/appos-dev/commands/validate.md @@ -24,10 +24,33 @@ Read `plugin.json` and check: ```bash defaults read /Applications/AppOS.app/Contents/Info.plist CFBundleShortVersionString ``` -- **Permissions**: must be from the valid set (see below) +- **Permissions**: validated by the manifest schema (next step). Do NOT hand-check against a hardcoded list — the authoritative permission set lives in the SDK's `schemas/plugin-v1.json` and grows with each SDK release. -Valid permissions (33 total, from `@appos.space/plugin-types`): -`ui.sidebar`, `ui.statusBar`, `ui.contextMenu`, `ui.notifications`, `ui.sheets`, `ui.shortcuts`, `ui.themes`, `ui.preview`, `ui.webPanel`, `ui.quickActions`, `filesystem.read`, `filesystem.write`, `filesystem.watch`, `filesystem.readAll`, `filesystem.writeAll`, `shell.execute`, `clipboard.read`, `clipboard.write`, `network`, `network.outbound`, `network.unrestricted`, `cache`, `feedback`, `feedback.confirm`, `workspaces`, `menubar`, `smartFolders`, `webview`, `keychain.plugin`, `interPlugin.declare`, `interPlugin.contribute`, `interPlugin.query`, `interPlugin.emit` +### Schema validation (authoritative) + +Validate the whole manifest against the SDK's published JSON Schema. This checks required fields, field shapes, and the full permissions enum in one step. + +**Preferred (no clone needed)** — fetch the schema from the public `appos/plugin-sdk` repo and validate with ajv: + +```bash +curl -fsSL -o /tmp/appos-plugin-v1.schema.json \ + https://raw.githubusercontent.com/appos/plugin-sdk/main/schemas/plugin-v1.json +npx --yes -p ajv-cli -p ajv-formats ajv validate \ + --spec=draft2020 -c ajv-formats \ + -s /tmp/appos-plugin-v1.schema.json -d plugin.json +``` + +Exit 0 with `plugin.json valid` = pass. On failure, ajv prints the offending JSON paths — e.g., an unknown permission string fails the `permissions` items enum. + +**Alternative (plugin-sdk clone available)** — the SDK ships its own validator with friendlier output. From the clone root: + +```bash +node scripts/validate-schema.mjs /path/to/plugin.json +``` + +Positional manifest paths are supported; with no args it runs the SDK's own fixture suite instead. + +If you're offline and have no clone, fall back to the structural checks above (required fields, ID format, minHostVersion landmine) and state in the report that the permission set could NOT be authoritatively verified. If the manifest declares `shell.execute`, verify `"shellCommands"` is present and non-empty. The AppOS sandbox blocks any command not in that list. @@ -121,7 +144,7 @@ Plugin Validation: {plugin-name} Manifest: ✓ Required fields present ✓ Valid ID format (space.appos.filestats) ✓ minHostVersion: 1.0.0 (safe) - ✓ Valid permissions + ✓ Schema validation passed (plugin-v1.json) SDK Layout: ✓ build.mjs present ✓ tsconfig verbatimModuleSyntax: true From 0b247d1ce4ce6cb557314cb6553faa1a64f17eac Mon Sep 17 00:00:00 2001 From: Bonanza Date: Fri, 24 Jul 2026 09:37:30 -0700 Subject: [PATCH 04/11] fix(new-plugin): scaffold npm deps ^2.4.0, drop maintainer-path assumptions (audit B3) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Scaffolded package.json now depends on the published npm packages (@appos.space/plugin-types ^2.4.0 devDep; plugin-utils + view-builders ^2.4.0 deps), matching the flagship appos-plugin-ytdlp @ origin/main 22d1c63. The file: variant survives as a collapsed 'SDK contributors only' note. Also removes the ~/Documents/GitHub/AppOS/... home-path assumptions from steps 1 and 5 — third-party devs pick any target directory. Verified in a scratch dir: the exact scaffold (package.json + tsconfig.json + build.mjs + minimal src/main.ts importing all three packages) npm-installs from the registry, 'npm run build' emits a dist/main.js IIFE with both globalThis entry points, and 'tsc --noEmit' passes. --- plugins/appos-dev/commands/new-plugin.md | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/plugins/appos-dev/commands/new-plugin.md b/plugins/appos-dev/commands/new-plugin.md index 27cb2c5..8f212ec 100644 --- a/plugins/appos-dev/commands/new-plugin.md +++ b/plugins/appos-dev/commands/new-plugin.md @@ -15,7 +15,8 @@ Create a new AppOS plugin targeting the SDK pattern (`@appos.space/plugin-types` If a plugin name was provided as an argument, use it. Otherwise ask for: - **Plugin name** (kebab-case, e.g. `file-stats`) - **One-sentence description** -- **Flagship or community?** — flagships use `space.appos.*` IDs and live under `~/Documents/GitHub/AppOS/appos-plugin-{name}/`. Community plugins use `com.community.*` IDs and live under a community-plugins repo of the user's choice. +- **Flagship or community?** — flagships (first-party, shipped with AppOS) use `space.appos.*` IDs; community plugins use `com.community.*` IDs. +- **Target directory** — where to create the project (any location works; ask if not obvious from context). - **Rendering mode** — WebView panel (rich UI, streaming progress, media), ViewDescriptor sidebar (simple lists, native feel), or both. If unsure, ask the user what the primary UI looks like. Generate the plugin ID: @@ -57,9 +58,7 @@ If WebView panels are needed, also create `$TARGET/webview/{panelId}/` and `$TAR ## 5. Write package.json -**CRITICAL**: `@appos.space/plugin-types` is the declaration-only SDK. `@appos.space/plugin-utils` and `@appos.space/view-builders` are runtime packages. - -For local development against the SDK in the AppOS repo, use `file:` dependencies. Adjust the relative paths to reach `~/Documents/GitHub/AppOS/plugin-sdk/packages/*` from the target directory. +**CRITICAL**: `@appos.space/plugin-types` is the declaration-only SDK. `@appos.space/plugin-utils` and `@appos.space/view-builders` are runtime packages. All three are published on npm — depend on them by version: ```json { @@ -73,19 +72,26 @@ For local development against the SDK in the AppOS repo, use `file:` dependencie "typecheck": "tsc --noEmit" }, "devDependencies": { - "@appos.space/plugin-types": "file:../plugin-sdk/packages/plugin-types", + "@appos.space/plugin-types": "^2.4.0", "esbuild": "^0.20.0", "typescript": "^5.4.0" }, "dependencies": { - "@appos.space/plugin-utils": "file:../plugin-sdk/packages/plugin-utils", - "@appos.space/view-builders": "file:../plugin-sdk/packages/view-builders" + "@appos.space/plugin-utils": "^2.4.0", + "@appos.space/view-builders": "^2.4.0" } } ``` If the plugin doesn't use ViewDescriptor panels at all, you can drop `@appos.space/view-builders` from `dependencies`. If it doesn't need runtime helpers, drop `@appos.space/plugin-utils` too. **`@appos.space/plugin-types` stays in `devDependencies` always** — it's type-only. +
+SDK contributors only: developing against a local plugin-sdk checkout + +If you are working on the SDK itself, point the three `@appos.space/*` entries at your clone with `file:` dependencies instead of npm versions — e.g. `"@appos.space/plugin-types": "file:../plugin-sdk/packages/plugin-types"` (adjust the relative path to reach your clone's `packages/*` from the plugin directory). Re-run `npm install` after switching. Do not scaffold `file:` paths for third-party plugin authors. + +
+ ## 6. Write tsconfig.json **MANDATORY**: `verbatimModuleSyntax: true` is required because `@appos.space/plugin-types` is declaration-only. Without this flag, TypeScript emits runtime `import` statements that try to resolve a non-existent module at runtime. From 7c87b9837553c3b577cfc5fa9dbb3b00f14a1dca Mon Sep 17 00:00:00 2001 From: Bonanza Date: Fri, 24 Jul 2026 09:40:05 -0700 Subject: [PATCH 05/11] fix(skills): panels/ -> webview/ bundle tree; lifecycle query APIs are host-wired (audit M2+M3) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit M2: the flagship appos-plugin-ytdlp (origin/main 22d1c63) ships its WebView assets under webview/ (src/panels/*.ts registers htmlPath 'webview/download/index.html'); the docs' panels/ bundle tree never matched. src/panels/*.ts references stay — that IS the real TS source layout. M3: ctx.lifecycle.getDependencyStatus() / recheckDependencies() are wired in the host (AppOS-Desktop PluginContextBridge.swift:1795,1859 delegating to PluginLifecycleManager.recheckDependencies(for:) at :3913) and ytdlp calls both in production (src/main.ts:269,430; download-panel.ts:337; library-panel.ts:208). Removed the 'types-only -- do NOT call' warnings and documented the subscribe-first-then-read ordering instead. reference/plugin-api.d.ts:1286 ('panels/output.html' @example) intentionally untouched: it is a synced snapshot of the host's own plugin-api.d.ts (AppOS-Desktop :2454); fixing it belongs upstream. --- .../skills/appos-plugin-dev/SKILL.md | 18 ++++++------ .../reference/extension-api.md | 6 ++-- .../appos-plugin-dev/reference/patterns.md | 28 ++++++++++--------- 3 files changed, 27 insertions(+), 25 deletions(-) diff --git a/plugins/appos-dev/skills/appos-plugin-dev/SKILL.md b/plugins/appos-dev/skills/appos-plugin-dev/SKILL.md index c003e1b..10ce292 100644 --- a/plugins/appos-dev/skills/appos-plugin-dev/SKILL.md +++ b/plugins/appos-dev/skills/appos-plugin-dev/SKILL.md @@ -100,7 +100,7 @@ The leading `;` on the globalThis assignments prevents ASI hazards when the prec | Need | API | Rendering | Notes | |---|---|---|---| -| Rich forms, streaming progress, media playback | `ctx.ui.registerWebPanel()` | WKWebView | Bundle HTML/CSS/JS under `panels//`. Use for yt-dlp-style UIs. | +| Rich forms, streaming progress, media playback | `ctx.ui.registerWebPanel()` | WKWebView | Bundle HTML/CSS/JS under `webview//`. Use for yt-dlp-style UIs. | | Lightweight sidebar (file annotations, git status, file stats) | `ctx.ui.registerPanel()` | SwiftUI via ViewDescriptor | Cheap, reactive, composes well. | | Activity bar icon + sidebar | `ctx.ui.registerActivityView()` | SwiftUI via ViewDescriptor | Use for primary feature entry points. | | Menu bar status item (with badge) | `ctx.menubar.register()` / `setBadge()` | NSStatusItem | Subscribe to `menubar.clicked` event to handle clicks. | @@ -110,7 +110,7 @@ The leading `;` on the globalThis assignments prevents ASI hazards when the prec | Keyboard shortcuts | `ctx.shortcuts.register({ commandId, keys })` | — | Must bind to an already-registered `ctx.commands.register()`. | | Persistent state (queue, library, history) | `ctx.cache.set(key, value, { persist: true })` | SQLite write-through | Default is memory-only — pass `persist: true` for durability. `cache.get()` returns deserialized values — do NOT `JSON.parse`. | | Run a CLI with streaming output | `ctx.ui.pipeShellToWebPanel(panelId, shellOpts)` | Chunks flow into the webview | **Method lives on `ctx.ui`, NOT `ctx.shell`.** Hard 120s timeout — use resume-loops for long jobs. | -| React to dependency changes | `ctx.lifecycle.onDependencyStatusChanged(fn)` | — | Host pushes status at activation. `getDependencyStatus()` / `recheckDependencies()` are types-only — do NOT call. | +| React to dependency changes | `ctx.lifecycle.onDependencyStatusChanged(fn)` | — | Host pushes status at activation. `getDependencyStatus()` reads on demand; `recheckDependencies()` re-probes (both host-wired). | ### Two WebView panels maximum per plugin @@ -136,8 +136,8 @@ The SDK defines **17 ViewDescriptor types**: `vstack`, `hstack`, `scroll`, `list ``` my-plugin/ - src/main.ts # registerWebPanel('main-panel', { htmlPath: 'panels/main/index.html' }) - panels/ + src/main.ts # registerWebPanel('main-panel', { htmlPath: 'webview/main/index.html' }) + webview/ main/ index.html # Entry point (NO inline