universal-plugin 0.12.2 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/.codex-plugin/plugin.json +1 -1
  3. package/.cursor-plugin/plugin.json +1 -1
  4. package/dist/cli.mjs +5197 -4028
  5. package/package.json +2 -1
  6. package/plugin.json +30 -1
  7. package/readme.md +7 -6
  8. package/references/plugin-design.md +21 -9
  9. package/schema/extension.schema.json +31 -0
  10. package/skills/adopt-upx/SKILL.md +4 -2
  11. package/skills/adopt-upx/scripts/rewrite-upx.mjs +92 -129
  12. package/skills/build-plugin/README.md +1 -1
  13. package/skills/build-plugin/SKILL.md +17 -8
  14. package/skills/build-plugin/scripts/build.mjs +51 -10
  15. package/skills/doctor-universal-plugin/SKILL.md +53 -23
  16. package/skills/doctor-universal-plugin/scripts/doctor.mjs +249 -365
  17. package/skills/init-universal-plugin/SKILL.md +13 -2
  18. package/skills/init-universal-plugin/references/create.md +9 -6
  19. package/skills/init-universal-plugin/references/standard.md +1 -1
  20. package/skills/init-universal-plugin/references/vendors/copilot-cli.md +2 -2
  21. package/skills/init-universal-plugin/scripts/init.mjs +51 -10
  22. package/skills/marketplace/references/init.md +1 -1
  23. package/skills/marketplace/scripts/add.mjs +51 -10
  24. package/skills/marketplace/scripts/install-docs.mjs +100 -96
  25. package/skills/marketplace/scripts/marketplace.mjs +51 -10
  26. package/skills/marketplace/scripts/validate.mjs +51 -10
  27. package/skills/migrate-plugin/SKILL.md +1 -1
  28. package/skills/remove-plugin/SKILL.md +1 -1
  29. package/skills/upgrade-plugin/SKILL.md +2 -0
  30. package/skills/version/README.md +24 -18
  31. package/skills/version/SKILL.md +80 -47
  32. package/skills/version/scripts/version.mjs +51 -10
@@ -19,8 +19,9 @@ and that judgment belongs to the skill that owns the write.
19
19
  node scripts/doctor.mjs
20
20
  ```
21
21
 
22
- Resolve that path against this skill's own directory. It runs the CLI that shipped beside it against
23
- the current working directory, so nothing is downloaded; add `--root <path>` to diagnose elsewhere.
22
+ Resolve that path against this skill's own directory. It asks the project's installed CLI
23
+ (`pnpm exec universal-plugin`), else the CLI pinned to this skill's version (`npx`), about the
24
+ current working directory; add `--root <path>` to diagnose elsewhere.
24
25
  Add `--marketplace-root <path>` (repeatable) to also check a **separately-cloned** shared marketplace
25
26
  repository (e.g. a local clone of `cyberuni/marketplace`) — see
26
27
  [Catalogs are checked at the repository root](#catalogs-are-checked-at-the-repository-root).
@@ -70,27 +71,32 @@ Each `code` below is what the script emits.
70
71
 
71
72
  | Finding | What it means | Repair |
72
73
  | --- | --- | --- |
73
- | `no-manifest` | no root `plugin.json` — this is not a plugin yet | `/universal-plugin:init-universal-plugin` |
74
- | `legacy-manifest` | root `plugin.json` with neither `$schema` nor `extensions` — a single-vendor manifest on the canonical path | `/universal-plugin:init-universal-plugin`, adopt route |
75
- | `vendor-only` | a vendor manifest with no canonical manifest above it | `/universal-plugin:init-universal-plugin`, adopt route |
76
- | `unbuilt` | a declared vendor whose output path holds no file — that runtime sees no plugin | `/universal-plugin:build-plugin` |
77
- | `stale` | a derived manifest older than `plugin.json`; for a derived directory (`com.github.copilot/`), its newest file is what is compared | `/universal-plugin:build-plugin` |
74
+ | `no-manifest` | no root `plugin.json` — this is not a plugin yet | `/universal-plugin:init-universal-plugin` (pnpm install: `pnpm-universal-plugin-init-universal-plugin`) |
75
+ | `legacy-manifest` | root `plugin.json` with neither `$schema` nor `extensions` — a single-vendor manifest on the canonical path | `/universal-plugin:init-universal-plugin` (pnpm install: `pnpm-universal-plugin-init-universal-plugin`), adopt route |
76
+ | `vendor-only` | a vendor manifest with no canonical manifest above it | `/universal-plugin:init-universal-plugin` (pnpm install: `pnpm-universal-plugin-init-universal-plugin`), adopt route |
77
+ | `unbuilt` | a declared vendor whose output path holds no file — that runtime sees no plugin | `/universal-plugin:build-plugin` (pnpm install: `pnpm-universal-plugin-build-plugin`) |
78
+ | `stale` | a derived manifest older than `plugin.json`; for a derived directory (`com.github.copilot/`), its newest file is what is compared | `/universal-plugin:build-plugin` (pnpm install: `pnpm-universal-plugin-build-plugin`) |
78
79
  | `hand-edited` | a derived manifest that `build` would rewrite — the edit is already lost, it just has not been overwritten yet | move the field to the canonical manifest or to `harnesses.<vendor>`, then rebuild |
79
80
  | `unknown-vendor` | a `vendors` entry no build target matches; reported as `skipped` plus a warning | fix the id in `plugin.json` |
80
81
  | `unsupported-component` | a component path on the shared extension names a component one targeted vendor has none of (`agents` for Codex, `rules` for Claude Code, …); the build leaves it out of that vendor's manifest | declare the path under `harnesses.<vendor>` for the vendors that read it, or leave it — nothing is lost |
81
- | `undeliverable-override` | `harnesses["copilot-cli"]` sets fields that reach nothing | `/universal-plugin:init-universal-plugin`, update route — move them to a vendor that has a derived manifest, or drop them |
82
+ | `stale-script` | a compiled skill script (`scripts` in the extension) is missing, or no longer matches what its source compiles to. A script that differs only in its embedded version is `version-drift` instead, never both | `/universal-plugin:build-plugin` (pnpm install: `pnpm-universal-plugin-build-plugin`), then commit the compiled script |
83
+ | `script-compile-failed` | a declared script entry could not be compiled into one self-contained file — usually an import that does not resolve from the plugin root | fix the entry, then `/universal-plugin:build-plugin` (pnpm install: `pnpm-universal-plugin-build-plugin`) |
84
+ | `script-over-budget` | a compiled skill script is over the 150 KB budget | have the skill call the installed CLI instead: `pnpm exec <bin>` with a pinned `npx` fallback |
85
+ | `skill-link-escapes` | a relative Markdown link in a skill climbs out of the skill folder (`../../readme.md`). pnpm links or copies each skill folder on its own, and a plugin cache keeps only what ships, so the link resolves to nothing there | copy the file into the skill and link it relatively, or link it by URL |
86
+ | `undeliverable-override` | `harnesses["copilot-cli"]` sets fields that reach nothing | `/universal-plugin:init-universal-plugin` (pnpm install: `pnpm-universal-plugin-init-universal-plugin`), update route — move them to a vendor that has a derived manifest, or drop them |
82
87
  | `codex-fields-missing` | Codex is targeted without `version` or `description`; the build fails and writes **nothing at all**, including for the other vendors | add both to the canonical top level |
83
- | `version-drift` | the `packagePath` `package.json` and the canonical manifest carry different versions | `/universal-plugin:version` |
84
- | `unreleased-content` | shipped content was committed after the commit that set the current version — a consumer keyed on that version never re-extracts it | `/universal-plugin:version` |
85
- | `copilot-root-components` | agents, commands, rules, hooks, or LSP servers sit at the plugin root with no copy under `com.github.copilot/` — Copilot CLI reads them only from there in spec mode, so it loads none of them, silently | `/universal-plugin:build-plugin` |
86
- | `stale-github-plugin` | a leftover `.github/plugin/plugin.json` from an older build — shadowed by root and no longer generated | `/universal-plugin:remove-plugin` |
87
- | `shadowing-manifest` | a `.plugin/plugin.json` exists — it outranks root in Copilot CLI's search order and silently shadows the canonical manifest | `/universal-plugin:remove-plugin` |
88
- | `no-vendors` | no vendor is declared, so the build writes nothing and no runtime reads the plugin. When the repository carries `vendorExtensions` or a `.plugin/plugin.json`, the build stops rather than reporting an empty result, and the detail says so — read it beside `legacy-manifest` and `shadowing-manifest`, which name the signals | `/universal-plugin:init-universal-plugin`, adopt route when `vendorExtensions` or `.plugin/plugin.json` is present, else update route |
88
+ | `version-drift` | one file carries a different version from the release's number — the canonical manifest, a derived vendor manifest, a catalog entry, a skill pin, a marked `mcpServers` entry, or the version a compiled skill script embeds; one finding per file, named by path | `/universal-plugin:version` (pnpm install: `pnpm-universal-plugin-version`) (for a package-sourced drift, `universal-plugin plugin version --from-package`); then [offer the CI check](#offer-the-check-to-ci) |
89
+ | `unstamped` | a place holds `0.0.0-development`, semantic-release's placeholder. The release has not stamped it yet, so it is not drift (severity low) | in `prepareCmd`, `plugin version ${nextRelease.version}`, and commit the stamped files back with `@semantic-release/git`; see `/universal-plugin:version` (pnpm install: `pnpm-universal-plugin-version`) |
90
+ | `unreleased-content` | shipped content was committed after the commit that set the current version — a consumer keyed on that version never re-extracts it | `/universal-plugin:version` (pnpm install: `pnpm-universal-plugin-version`) |
91
+ | `copilot-root-components` | agents, commands, rules, hooks, or LSP servers sit at the plugin root with no copy under `com.github.copilot/` — Copilot CLI reads them only from there in spec mode, so it loads none of them, silently | `/universal-plugin:build-plugin` (pnpm install: `pnpm-universal-plugin-build-plugin`) |
92
+ | `stale-github-plugin` | a leftover `.github/plugin/plugin.json` from an older build — shadowed by root and no longer generated | `/universal-plugin:remove-plugin` (pnpm install: `pnpm-universal-plugin-remove-plugin`) |
93
+ | `shadowing-manifest` | a `.plugin/plugin.json` exists — it outranks root in Copilot CLI's search order and silently shadows the canonical manifest | `/universal-plugin:remove-plugin` (pnpm install: `pnpm-universal-plugin-remove-plugin`) |
94
+ | `no-vendors` | no vendor is declared, so the build writes nothing and no runtime reads the plugin. When the repository carries `vendorExtensions` or a `.plugin/plugin.json`, the build stops rather than reporting an empty result, and the detail says so — read it beside `legacy-manifest` and `shadowing-manifest`, which name the signals | `/universal-plugin:init-universal-plugin` (pnpm install: `pnpm-universal-plugin-init-universal-plugin`), adopt route when `vendorExtensions` or `.plugin/plugin.json` is present, else update route |
89
95
  | `package-path-missing` | `packagePath` names a directory with no readable `package.json` | fix `packagePath`, or create the package |
90
96
  | `package-path-unknown` | the CLI could not report `packagePath` (a version too old to read it), so `version-drift` and `unreleased-content` were skipped rather than guessed | upgrade universal-plugin |
91
97
  | `misplaced-package-path` | `plugin.json` declares `packagePath` under `extensions["org.cyberuni.universal-plugin"]`, where the CLI never reads it — the plugin is silently treated as not shipping to npm | move it to `.agents/universal-plugin.json`, relative to the plugin root |
92
98
  | `unparsable-manifest` | root `plugin.json` is not valid JSON | fix the syntax error |
93
- | `invalid-catalog` | a marketplace catalog — at the repository root, or at a `--marketplace-root` clone — is not a shape its runtime loads — it is found, read, and refused at install time, in the user's terminal | `/universal-plugin:marketplace` |
99
+ | `invalid-catalog` | a marketplace catalog — at the repository root, or at a `--marketplace-root` clone — is not a shape its runtime loads — it is found, read, and refused at install time, in the user's terminal | `/universal-plugin:marketplace` (pnpm install: `pnpm-universal-plugin-marketplace`) |
94
100
  | `marketplace-root-missing` | a `--marketplace-root` path does not exist, so it could not be checked at all | clone the marketplace repository, or fix the path |
95
101
 
96
102
  ## Catalogs are checked at the repository root
@@ -99,7 +105,7 @@ The marketplace catalogs sit above the plugin in a monorepo, so the catalog chec
99
105
  repository root rather than `--root`. It reports only a catalog that would be **refused**: a missing
100
106
  one is not a fault, and nothing here has an opinion on which catalogs a repository ought to carry.
101
107
 
102
- The detail names the key at fault, so hand it to `/universal-plugin:marketplace` as it stands. An
108
+ The detail names the key at fault, so hand it to `/universal-plugin:marketplace` (pnpm install: `pnpm-universal-plugin-marketplace`) as it stands. An
103
109
  entry's fields are derived from the plugin's `plugin.json`, and the catalog's own `name` and `owner`
104
110
  are authored in the catalog — which half is at fault decides where the repair goes.
105
111
 
@@ -137,13 +143,37 @@ user can run, or ask before running it yourself.
137
143
 
138
144
  ## Version drift
139
145
 
140
- Two files carry an authored version: the canonical `plugin.json`, and the `package.json` at the
141
- `packagePath` the CLI reports (`config get --key packagePath`), resolved from the plugin root. The script compares
142
- them and emits `version-drift`.
146
+ A version lives in five places. Two are authored: the canonical `plugin.json`, and the `package.json`
147
+ at the `packagePath` the CLI reports (`config get --key packagePath`), resolved from the plugin root.
148
+ The rest are stamped from them by `plugin version`: the vendor manifests, this plugin's entry in each
149
+ repository catalog, the `npx`/`upx <package>@<version>` pins in the skills, and each `mcpServers`
150
+ entry marked `pinToPluginVersion`.
143
151
 
144
- They diverge when someone ran `npm version`, or when changesets released a number that never flowed
145
- back. Both are `/universal-plugin:version`'s to fix — never patch one file by hand to match the
146
- other.
152
+ The script asks `universal-plugin publish check-version` for the comparison and emits one
153
+ `version-drift` per file that disagrees. The reference is the release's number: the `package.json`
154
+ when `packagePath` is declared, else `plugin.json`. Pins are compared only when there is a package to
155
+ pin, and a pin-exempt skill or a pin that is not a version (`<version>`, `latest`) is skipped. A place
156
+ holding `0.0.0-development` is reported as `unstamped`, not as `version-drift`.
157
+
158
+ Files diverge when someone ran `npm version`, or when a release tool (changesets, release-please,
159
+ semantic-release) moved `package.json` and nothing stamped the number on. All of it is
160
+ `/universal-plugin:version` (pnpm install: `pnpm-universal-plugin-version`)'s to fix — never patch one file by hand to match another.
161
+
162
+ ### Offer the check to CI
163
+
164
+ `doctor` is advisory and always exits 0. `publish check-version` is the same comparison, read-only,
165
+ and exits 1 on drift, so a repository can fail the release PR instead of publishing a plugin that
166
+ claims the old version. Once the version findings are reported, check whether the repository
167
+ already runs it: search its `package.json` scripts and `.github/workflows/` for `check-version`. If
168
+ it does not, offer to add it — ask first, because both are the user's files:
169
+
170
+ - a `verify` (or `check`) script step: `universal-plugin publish check-version --root <plugin-root>`;
171
+ - or a CI step after install on pull requests, for the release PR a changesets, release-please, or
172
+ semantic-release bot opens.
173
+
174
+ Use the locked `universal-plugin` from the repository's devDependencies when it has one; otherwise
175
+ `npx universal-plugin@0.14.0`, pinned. This check matters most where the release tool picks the
176
+ number, because nothing else runs between that bump and publish.
147
177
 
148
178
  ## Unreleased content
149
179
 
@@ -161,7 +191,7 @@ Two cases are deliberately silent. A plugin that declares `packagePath` is skipp
161
191
  release picks the number ([ADR-0010](https://github.com/cyberuni/universal-plugin/blob/main/packages/universal-plugin/.agents/spec/design/decisions/0010-version-policy.md) §2) and content waiting ahead of the last released version is the
162
192
  normal state of a branch. A tree with no git history is skipped rather than guessed at.
163
193
 
164
- The repair is the bump, and it belongs to `/universal-plugin:version`. Judge first whether the change
194
+ The repair is the bump, and it belongs to `/universal-plugin:version` (pnpm install: `pnpm-universal-plugin-version`). Judge first whether the change
165
195
  is meant to ship — content that is still being worked on is not a finding to act on.
166
196
 
167
197
  ## Rules