universal-plugin 0.16.2 → 0.17.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.
package/CHANGELOG.md ADDED
@@ -0,0 +1,704 @@
1
+ # universal-plugin
2
+
3
+ ## 0.17.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 08e9790: Add `marketplace update <name>`, which changes one entry a repository's catalogs already list and keeps every field it is not asked to change. Move an entry to a new source (a new git source keeps the old pin), bump `--ref` or `--sha`, set one field such as `--description` or `--category`, or remove one with `--unset`. Each catalog is validated before anything is written, and an update that would introduce an issue writes nothing.
8
+
9
+ ### Patch Changes
10
+
11
+ - 2dc4e84: Depend on `cyber-agentkit` `^2.0.0`. The docs now name `reference load`, which replaces `reference show`.
12
+ - 80582de: Move `commander`, `semver`, `cyber-agentkit`, and `@toon-format/toon` to `devDependencies`. The `universal-plugin` bin already inlines them, so installing the package no longer pulls them in.
13
+ - b53f4c8: The `publish-plugin` skill now changes an entry already listed in the marketplace with `marketplace update` instead of editing the catalogs by hand, so curator fields are kept and each catalog is validated before it is written.
14
+
15
+ ## 0.16.3
16
+
17
+ ### Patch Changes
18
+
19
+ - 3fd0b8c: Include `CHANGELOG.md` in the published package.
20
+
21
+ ## 0.16.2
22
+
23
+ ### Patch Changes
24
+
25
+ - 7dafe8e: `plugin build` no longer takes minutes on a script that inlines a module with a very long run of identifier characters, such as a base64 source map. The main-guard scan now runs in linear time and skips modules that never use `import.meta`.
26
+
27
+ ## 0.16.1
28
+
29
+ ### Patch Changes
30
+
31
+ - 7490bca: Depend on `cyber-agentkit` instead of `@cyberuni/agent-harness`, which is no longer maintained. The shipped skills and references now name the `cyber-agentkit` plugin, and `npx cyber-agentkit reference show <name>` reads this package's documents.
32
+
33
+ ## 0.16.0
34
+
35
+ ### Minor Changes
36
+
37
+ - 0362f45: `marketplace init` and `marketplace add` now write each runtime only the entry sources it installs. Codex takes `path npm url git-subdir`, Copilot CLI `path github url`, and Cursor `path github url git-subdir`. A `github` source becomes a `url` (or `git-subdir`) entry for Codex, and a `git-subdir` on GitHub becomes `github` plus `path` for Copilot CLI, with `ref` and `sha` kept. Entries that cannot be mapped are omitted with a warning naming the entry and the runtime, because one `npm` or `git-subdir` entry makes Copilot CLI refuse the whole marketplace. Copilot CLI and Cursor read the Claude catalog when they have none of their own, so their catalogs are now written whenever the Claude one holds an entry they cannot install. `marketplace validate` reports unsupported sources, including in the Claude catalog for a runtime that falls back to it. The README install section lists which plugins each runtime cannot install.
38
+
39
+ ## 0.15.0
40
+
41
+ ### Minor Changes
42
+
43
+ - 30858ab: `plugin build --check` writes nothing and exits 1 when a compiled script is `missing`, `stale` or `version`, naming each one, so CI can fail on a committed script that is behind its source without parsing `--dry-run --format json`. `--dry-run` alone still exits 0.
44
+ - 104a784: A script entry can set `alias` and `keepNames` for its bundle: `{ "source": "src/a.ts", "alias": { "jsonc-parser": "jsonc-parser/lib/esm/main.js" }, "keepNames": true }`.
45
+
46
+ ### Patch Changes
47
+
48
+ - 30858ab: `plugin build` now writes invisible characters in a compiled script's string, template and regular-expression literals as `\uXXXX` escapes, so a script that inlines a dependency such as `yaml` passes invisible-Unicode skill checks. It warns, naming the file, line and code point, about any it cannot escape.
49
+ - 104a784: `plugin build` no longer fails a script entry whose inlined code dynamically imports a module it already inlines, or calls `import(variable)`.
50
+
51
+ ## 0.14.1
52
+
53
+ ### Patch Changes
54
+
55
+ - ebf7ebe: The `publish-plugin`, `marketplace`, and `doctor-universal-plugin` skills now name `cyberuni/cyberplace` as the default shared marketplace, replacing the retired `cyberuni/marketplace`.
56
+ - fb60407: `plugin build` now names the tsconfig file and the `extends` path when rolldown cannot load one, and says to add `.json`, instead of reporting only `Tsconfig not found`.
57
+ - ebf7ebe: `publish-plugin` now checks whether the target marketplace takes pull requests at all. With only read access, it reads the target's workflows and Contributing section live; for a curated catalog that closes outside PRs or takes submissions by form, it drafts the entry in that catalog's own shape and hands over the submission link instead of opening a PR.
58
+ - 490dd69: `plugin build` now keeps only the entry's main guard when a script entry imports another script that is itself a CLI. Inlined modules share the compiled file's `import.meta.url`, so before this every inlined CLI ran alongside the entry's.
59
+
60
+ ## 0.14.0
61
+
62
+ ### Minor Changes
63
+
64
+ - 2fa9ef4: `plugin build` adds the pnpm skill name beside each `/<plugin>:<skill>` reference in a skill's Markdown: `` `/my-plugin:doctor` (pnpm install: `pnpm-my-plugin-doctor`) ``. pnpm links a skill as `pnpm-<package>-<skill>` (a scoped `@scope/name` becomes `pnpm-@scope+name-<skill>`), so the plugin-qualified name alone resolves to nothing there. Authors still write the reference once. The name comes from the plugin root's `package.json`; references to other plugins or unknown skills, fenced code, and already-rewritten references are left alone.
65
+
66
+ ## 0.13.0
67
+
68
+ ### Minor Changes
69
+
70
+ - d89e609: `plugin build` compiles skill script entries into self-contained `.mjs` files. Declare them under `extensions["org.cyberuni.universal-plugin"].scripts`, mapping an output path to a source (`"skills/doctor/scripts/doctor.mjs": "src/skills/doctor.ts"`, or `{ "source", "command" }`). Each entry is compiled with rolldown: Node built-ins stay imports and everything else is inlined, so the script works from a skill that pnpm links or copies on its own. Commit the output.
71
+
72
+ - Each compiled file embeds `globalThis.__SKILL_SCRIPT__`: the package and bin that ship the plugin, the version from `plugin.json`, and a map from every declared command path to its entry.
73
+ - `--dry-run` reports each committed script as `unchanged`, `missing`, `stale` or `version`. `doctor` reports a missing or stale one as `stale-script`. A script behind only on its embedded version is `version-drift`, which `publish check-version` now checks, so one file is never reported twice.
74
+ - A compiled script over 150 KB warns that the skill should call the installed CLI instead.
75
+ - `plugin version` stamps the new version into each compiled script's header, and nothing else in it. Pins inside compiled code are left to the build.
76
+ - 517d001: Add `publish check-version`, a read-only check that fails when the `packagePath` `package.json`, `plugin.json`, the derived vendor manifests, the repository catalogs, or the skill `npx`/`upx` pins carry different versions, naming each file left behind. `doctor` now reports one `version-drift` finding per such file, and offers to add the check to the repository's verify script or CI.
77
+ - ec08877: `plugin init --npm` copies the package `version` into the `plugin.json` it writes, and in a changesets repository wires the root `version` script (`changeset version && universal-plugin plugin version --from-package --root <plugin-root>`) plus a `universal-plugin` devDependency. A custom `version` script is left alone and init prints the line to add. A script still running `publish sync-version` is told to switch.
78
+ - b105a4d: `plugin version` is now the single version stamp. One call writes the version into `plugin.json`, the `packagePath` `package.json`, the `npx`/`upx` pins in every skill file (scripts included), `.plugin/pins.json`, and each authored `mcpServers` entry marked `pinToPluginVersion`, then re-derives the vendor manifests. It takes the number from a release type, an explicit version (semantic-release's `prepareCmd`), or the new `--from-package` (changesets and release-please). Where `packagePath` is declared, a release type is refused, because the release picks the number.
79
+
80
+ `plugin build` no longer decides any version: a marked `mcpServers` entry is copied as authored and only its marker is stripped. `plugin bundle` and `publish sync-version` are deprecated aliases that warn, and are removed in the next minor release. `publish check-version` and `doctor` report a place holding `0.0.0-development` as unstamped rather than as drift, and compare the marked `mcpServers` pin too.
81
+ - d89e609: `plugin build` warns on a relative Markdown link in a skill that climbs out of the skill folder (`../../readme.md`). pnpm links or copies each skill folder on its own, so such a link resolves to nothing there. `doctor` reports it as `skill-link-escapes`.
82
+
83
+ ### Patch Changes
84
+
85
+ - ab48ed1: Fix universal-plugin's own skill scripts when pnpm copies a skill instead of linking it. The six that run a CLI command (`plugin build`, `plugin init`, `plugin version`, `marketplace add`, `marketplace init`, `marketplace validate`) call the installed CLI (`pnpm exec universal-plugin`), else `npx universal-plugin@<version>` pinned to the plugin's version. `doctor`, `rewrite-upx` and `install-docs` are self-contained. `doctor` now accepts a `$schema` only when it is hosted on `agent-plugins.org`, not a URL that merely mentions the name.
86
+ - d5e6c0d: `plugin build`, `plugin version`, `publish sync-version` and `plugin init` now write JSON in the format the file already has: its indentation, line ending, trailing newline, and the original text of every value they leave unchanged, so an array a formatter collapsed onto one line stays there. A new file, or one with no indentation to read, takes the indentation `.editorconfig` sets for it.
87
+ - ca9abcb: Document in the `plugin-design` reference that `rules` is for the HCF of all agents only, and that role- or task-scoped guidance ships as a reference loaded on demand.
88
+
89
+ ## 0.12.2
90
+
91
+ ### Patch Changes
92
+
93
+ - d3650b6: Fix stale and dangling references in the shipped skills and the agentskills-specialist agent: point skills at `doctor-universal-plugin`, link ADRs by URL, state current rules instead of migration-relative ones, and drop the project-specific commit and memory rules from the agent.
94
+
95
+ ## 0.12.1
96
+
97
+ ### Patch Changes
98
+
99
+ - da18173: Depend on `@cyberuni/agent-harness` `^0.5.0`. That release ships the `agent-harness` CLI, so `npx @cyberuni/agent-harness reference show <name>` reads this package's documents without a version pin.
100
+ - 1904555: Point reference loading at the `cyber-agent-harness` plugin. The `reference` skill moved there from `buddy-agent-harness` in buddy-agent-harness@0.20.0, so the shipped skills and references now name `cyber-agent-harness`, and the plugin declares it as a dependency.
101
+
102
+ ## 0.12.0
103
+
104
+ ### Minor Changes
105
+
106
+ - c82b27b: `plugin build` now checks each declared dependency against the marketplace catalogs it refreshes. A bare dependency the catalog does not list, or one qualified with a marketplace the catalog does not allow in `allowCrossMarketplaceDependenciesOn`, warns and names the fix. Pass `--strict-dependencies` to fail the build on it instead. A dependency that declares a `source`, such as `{ "name": "cyber-asana", "source": { "source": "npm", "package": "cyber-asana" } }`, is listed in the catalog for you.
107
+ - 602e1c8: `plugin build` no longer warns about a dependency qualified with the catalog's own name, such as `cyber-asana@uip-pods-local`, when the catalog does not list it. Only a plain dependency (a bare name, or an object with no `marketplace`) has to be listed in the catalog. Naming a marketplace is an explicit choice by the author.
108
+ - f87bfc8: `marketplace validate` now checks, in the Claude catalog, that each listed plugin's dependencies can resolve from it. A plain dependency (a bare name, or an object with no `marketplace`) the catalog does not list is an issue, and so is a dependency on another marketplace that the catalog does not allow in `allowCrossMarketplaceDependenciesOn`. It reads what is on disk: an entry's own `dependencies`, and the manifest of a plugin at a `./` source. `marketplace init --force` now keeps a catalog's `allowCrossMarketplaceDependenciesOn` when it regenerates the file.
109
+ - b0558cd: The `publish-plugin` skill now reads the plugin's dependencies. A plain dependency the target marketplace does not list is listed in the same PR, or the skill stops and asks for it to be published first. A dependency on another marketplace gets an offer to add it to the catalog's `allowCrossMarketplaceDependenciesOn`.
110
+
111
+ ## 0.11.3
112
+
113
+ ### Patch Changes
114
+
115
+ - 4a0e9ac: `doctor` no longer reports `com.github.copilot/` as stale after a rebuild. It compares the newest file in the directory against `plugin.json`, because a directory's own mtime does not move when its files are rewritten in place.
116
+ - 4a0e9ac: `publish sync-version` now re-derives the vendor manifests after it moves the version, the same way `plugin version` does, so they no longer keep the old number. Pass `--no-build` to skip that step when your release script runs `plugin build` itself. The `version` and `doctor-universal-plugin` skills now name `build-plugin` as the follow-up step.
117
+
118
+ ## 0.11.2
119
+
120
+ ### Patch Changes
121
+
122
+ - c8b81c8: `plugin build` no longer writes Codex custom prompts to `~/.codex/prompts/`. Codex invokes plugin skills natively with `$name` or `/skills`, and its custom prompts are deprecated and no longer read, so the build now writes nothing outside the plugin tree. You can delete prompts that an earlier build left in `~/.codex/prompts/`.
123
+ - 642f70e: `plugin build` now leaves a component path out of a vendor's derived manifest when that vendor has no such component, and warns: `codex has no "agents" component — the path is left out of .codex-plugin/plugin.json`. Codex reads `skills`, `commands`, `apps`, `hooks`, and `mcpServers`; Cursor reads `skills`, `commands`, `agents`, `rules`, `hooks`, and `mcpServers`; Claude Code reads every component except `rules` and `apps`. A `harnesses.<vendor>` override is never filtered. `doctor` reports the case as `unsupported-component`.
124
+
125
+ ## 0.11.1
126
+
127
+ ### Patch Changes
128
+
129
+ - d8bfd5b: Skills now load references with the `reference` skill in the `buddy-agent-harness` plugin, which replaces its `load-reference` skill. The line reads "Load `plugin-design` with the `reference` skill in the `buddy-agent-harness` plugin."
130
+
131
+ ## 0.11.0
132
+
133
+ ### Minor Changes
134
+
135
+ - 55fdc24: Remove the retired `governance` command. `governance show` and `governance list` are now unknown commands. Use `buddy-agent-harness reference show|list|search`, or the `load-reference` skill in the `buddy-agent-harness` plugin, to read the same documents.
136
+
137
+ ### Patch Changes
138
+
139
+ - dd275ba: `plugin init --scaffold` creates `references/` instead of `governances/`, the folder `buddy-agent-harness reference` reads.
140
+ - 4ad2dc8: `prepare` now reads installed plugins the way each harness records them. It reads Claude Code's version 2 `installed_plugins.json` by plugin name and scope, and it reads Copilot CLI's `installed-plugins` folders and the Codex plugin cache. Plugin paths come from `@cyberuni/agent-harness`, which honors `CLAUDE_CONFIG_DIR`, `CODEX_HOME`, and `COPILOT_HOME`.
141
+ - 4ad2dc8: The vendor registry no longer carries `globalManifest` or `globalPluginDir`, and Cursor's local plugin folder now comes from `@cyberuni/agent-harness`. `plugin install` for Cursor therefore honors the harness's config directory. A `localPluginDir` in `~/.agents/universal-plugin-vendors.json` still wins.
142
+
143
+ ## 0.10.0
144
+
145
+ ### Minor Changes
146
+
147
+ - e0b672d: A new `build-plugin` skill is the entry point for `plugin build`. It runs the project's own build script when one exists, and otherwise the CLI shipped beside it through `scripts/build.mjs`, so nothing is downloaded. It reads the vendor and catalog rows back, reports each warning about something a vendor cannot represent, and hands a `built 0` result to `doctor-universal-plugin`.
148
+ - 738df81: `marketplace add` lists a plugin the repository does not hold, so a repository can curate a marketplace instead of only publishing its own plugins. One positional says where the plugin lives and is read by shape: a `./` path, an `owner/repo` slug, a git URL, an npm package (`npm:pkg` or `@scope/pkg`), or `<plugin>@<marketplace>` — with `--path`, `--npm`, `--github`, `--url`, and `--from-marketplace` to force the reading where `owner/repo` and a relative path collide. Nothing is fetched: metadata comes from a path's own `plugin.json`, an installed `node_modules` copy, the entry being copied, or the `--description`/`--version`/`--homepage`/`--repository`/`--license`/`--keywords` flags. A `<plugin>@<marketplace>` entry is resolved from a marketplace the runtime has already added, or from `--from <dir>`. A source that is relative to *that* marketplace is rewritten rather than copied, against the origin the runtime recorded for it or its clone's own git remote: `./plugins/aced` in `cyberuni/cyberplace` becomes `{ "source": "git-subdir", "url": "https://github.com/cyberuni/cyberplace.git", "path": "plugins/aced" }`, and an entry at the marketplace root becomes `github` or `url`. An entry only reaches a catalog whose runtime resolves that source — npm goes to Claude Code and Codex, and Copilot CLI and Cursor are reported `skipped` with the reason rather than written a source they refuse.
149
+
150
+ A regeneration no longer discards the entries it did not derive. `marketplace init`, `plugin build`, and `plugin init` keep an entry whose source is not a local path, and keep a non-local source on a plugin they *do* discover while refreshing its derived metadata — so a plugin distributed through npm is not rewritten to a repository path holding gitignored build output, and `add` and `init` compose on one repository. A local-path entry discovery no longer finds is still dropped.
151
+
152
+ The `marketplace` skill is now a gateway over three routes (`init`, `add`, `validate`), each with its own reference, and ships a `scripts/add.mjs` wrapper.
153
+ - 2ba0e9c: Retire `governance` and the build's governance copies in favor of `buddy-agent-harness reference` and its `load-reference` skill.
154
+
155
+ - `governance show` and `governance list` no longer read documents. For this release they print the replacement (`buddy-agent-harness reference show <name>`, or the `load-reference` skill in the `buddy-agent-harness` plugin) and exit 1. The next release removes the command.
156
+ - `plugin build` no longer copies governances into `skills/*/references/governances/`, and `plugin build --check` is gone. Remove `--check` from CI; it now fails as an unknown option.
157
+ - The documents this package owns (`plugin-design`, `slash-invocation`, and a `universal-plugin` pointer to `plugin-design`) ship under `references/` instead of `governances/`, so `reference show` finds them in any project that depends on `universal-plugin`.
158
+ - The `init-universal-plugin` skill loads `plugin-design` through the `load-reference` skill.
159
+
160
+ ### Patch Changes
161
+
162
+ - c430c4a: `publish sync-version` no longer requires `packagePath`. With none set in `.agents/universal-plugin.json`, it reads the `package.json` at the plugin root, so a single-package repository where `package.json` sits beside `plugin.json` needs no config file. It fails only when that file is missing too, and the error names both places it looked. An explicit `packagePath` still wins.
163
+
164
+ ## 0.9.0
165
+
166
+ ### Minor Changes
167
+
168
+ - 8fde5f7: `plugin build` copies each governance into the skills that use it, so a skill reads its rule sets from disk instead of running `npx <pkg> governance show <name>` at run time — no registry lookup per read, and no network while the skill works. The `.md` files already in `<skill>/references/governances/` declare which governances that skill uses; the build rewrites each from the package that owns it, copies the governances those reference, transitively, and rewrites every `governance show <other>` pointer inside a copy into an instruction to load the sibling copy. The build fails when a declared file names no governance, when a referenced one has no copy to point at, or when `SKILL.md` does not list a copy under References. Commit the copies — a git-sourced install has no build step — and run the new `plugin build --check` in CI, which writes nothing and exits non-zero naming each copy that differs from its source.
169
+ - 7836787: Rename the `doctor` skill to `doctor-universal-plugin`. Other plugins ship their own `doctor` skill, and the bare name collided when more than one was installed — `buddy-agent-harness` already resolved this by namespacing its own as `doctor-buddy-agent-harness`. Invoke it as `/universal-plugin:doctor-universal-plugin`; the CLI's own next-step hints now name that too.
170
+
171
+ ## 0.8.0
172
+
173
+ ### Minor Changes
174
+
175
+ - cbda7c2: `config get --key packagePath` now reads `packagePath` instead of rejecting it. `--format json` prints the declared path as a JSON string, relative to the plugin root, or `null` when no npm package is declared. `plugin version`, `publish sync-version`, and `config get` share one reader, so they cannot disagree about a declaration. `config add --key packagePath` is still rejected: the key is a string, not a plugin-registered array.
176
+ - 1eab810: Move the `upx` runner into its own package, `@repobuddy/upx`.
177
+
178
+ A generic package runner is broader than this package's build/derivation charter — a placement note
179
+ in the spec has said so since it landed. It also made the wrong trade for `upx` itself: the runner's
180
+ value is *install once globally, use everywhere*, and that install should be small, so requiring
181
+ `npm i -g universal-plugin` to get a runner word worked against it.
182
+
183
+ Nothing about `upx`'s behavior changed, and the emitter side stays here: `plugin bundle --runner upx`,
184
+ the `adopt-upx` skill, and `upgrade-plugin`'s runner-word handling all still live in this package.
185
+ Their coupling was always to the *word* `upx`, never to its code.
186
+
187
+ **Install `@repobuddy/upx` directly** — `npm i -g @repobuddy/upx`. The `upx` bin on this package now
188
+ re-exports it so existing global installs keep working, and prints a deprecation notice on `--help`
189
+ (never on a normal call — `upx` is a transparent exec wrapper). It will be removed in the next major.
190
+ - 49f1036: Add `universal-plugin plugin validate`, which checks the root `plugin.json` without building anything. It reports every problem in one pass, in two groups:
191
+
192
+ - **Schema violations** against the Agent Plugins 1.0.0 schema: `$schema` and `name` are required, `name` must match the schema's pattern, fields must have the right types, and top-level keys the standard does not define are rejected.
193
+ - **Vendor violations**: for example, Codex requires `description` and `version`. `--vendor <id>` limits these checks to one vendor.
194
+
195
+ An unknown vendor key in `harnesses` is a warning, and `--strict` makes it a violation. Output is TOON by default, with `--format json` and `--full` available. Running `universal-plugin plugin` with no subcommand now validates the current project and lists its declared harnesses, instead of printing help.
196
+
197
+ A manifest without `$schema` now fails `plugin validate`. `plugin build` does not check `$schema` and still accepts it. `plugin init` already writes `$schema`.
198
+
199
+ ### Patch Changes
200
+
201
+ - a40d5b0: `doctor` now reads `packagePath` only from `.agents/universal-plugin.json`, resolved from the plugin root — the same file and base `plugin version` and `publish sync-version` use. It no longer falls back to `extensions["org.cyberuni.universal-plugin"].packagePath`, which the CLI never honored, so doctor could pass a plugin that `version` still treated as not shipping to npm. A `packagePath` declared in the manifest extension is now reported as `misplaced-package-path`.
202
+ - f0be1fa: `doctor` now accepts a repeatable `--marketplace-root <path>` flag to also validate a separately-cloned shared marketplace repository (e.g. a local clone of `cyberuni/marketplace`) — previously only the plugin's own repository root was checked, so a bad entry that reached the shared catalog another way went unnoticed. A named `--marketplace-root` that does not exist is reported as `marketplace-root-missing` instead of being silently skipped.
203
+ - 0211cae: State the CLI's dependency bundling explicitly in the build config.
204
+
205
+ `dist/cli.mjs` already shipped with its runtime dependencies inlined, and that is what lets the
206
+ shipped skill launchers run from an installed plugin directory at all — those directories are copies
207
+ of a source checkout, so their `node_modules` is absent or incomplete. The build now declares that
208
+ intent through an explicit `deps.alwaysBundle` block rather than relying on it incidentally, so a
209
+ dependency added later cannot quietly become external and break the launchers.
210
+
211
+ `@repobuddy/upx` is deliberately excluded. It is reachable only from the separate `bin/upx.mjs` shim,
212
+ which is not a build entry, so the `upx` bin still resolves it at runtime from an installed tree.
213
+ - becd7ef: Fix `plugin build` ending with a next-step hint for `universal-plugin plugin validate`, a command that does not exist yet. A build that refreshed a marketplace catalog now points at `universal-plugin marketplace validate` (with `--root` for that repository), and any other successful build points at `/universal-plugin:doctor`.
214
+ - 2469986: Fix `universal-plugin --version` (and `-V`) always printing `0.0.0` instead of the installed package's actual version.
215
+ - c6304c5: `migrate-plugin` now bundles the package's CLI with tsdown as part of the migration, so the CLI runs from an installed plugin directory that has no `node_modules`. It splits `tsdown.config.ts` into a library config that keeps dependencies external and a CLI config that inlines them through `deps.alwaysBundle`. It then proves the result by running the CLI from an extracted tarball.
216
+
217
+ The skill also covers plugins that live in a sibling workspace member such as `plugins/<name>/`, merges a colliding readme instead of overwriting it, and notes that `publish sync-version` reads `packagePath` from `.agents/universal-plugin.json`, not from the manifest. It also repoints lint excludes, marketplace sources, and spec paths.
218
+ - 1f82ccd: `schema/extension.schema.json` and the `init-universal-plugin` standard reference no longer advertise `packagePath` under `extensions["org.cyberuni.universal-plugin"]`. The CLI never read it there, so a plugin that declared it where the schema said silently fell back to the author-picks release model. `packagePath` lives in `.agents/universal-plugin.json` beside `plugin.json`, as a path relative to the plugin root; a namespace `packagePath` now fails schema validation.
219
+ - 4161472: The `doctor` and `publish-plugin` skills now ask the CLI for `packagePath` (`config get --key packagePath`) instead of reading `.agents/universal-plugin.json` themselves, so they cannot drift from `plugin version`. When the CLI is too old to answer, doctor reports `package-path-unknown` and skips `version-drift` and `unreleased-content` rather than guessing.
220
+
221
+ ## 0.7.0
222
+
223
+ ### Minor Changes
224
+
225
+ - af44d02: `plugin build` now separates "nothing was declared" from "this layout is one I cannot read".
226
+
227
+ A repository left on the pre-0.6 layout — a top-level `vendorExtensions` block, or a
228
+ `.plugin/plugin.json` shadowing the canonical manifest — derives nothing, and until now that was
229
+ reported as a definitive empty state: `built 0`, exit 0. Chained behind a release script it read as
230
+ success, and a released version silently never reached the vendor manifests.
231
+
232
+ Deriving nothing from a canonical manifest that genuinely declares no harnesses is still an empty
233
+ result (exit 0), and its stderr now names `/universal-plugin:doctor` as the next step rather than
234
+ `plugin validate`, which has nothing to say about it. Deriving nothing because the layout predates
235
+ this CLI is a failed read: the build exits 1, names the signal it found, and points at `doctor`. The
236
+ check only fires where the target set was already empty, so a project carrying one of those signals
237
+ whose harnesses still derive is unaffected.
238
+
239
+ `doctor`'s description now covers this case — `built 0`, "nothing to build", the
240
+ `No vendors declared in harnesses` warning, a major upgrade, a leftover `.plugin/plugin.json` or
241
+ `vendorExtensions` — so an agent seeing the symptom routes to the skill that diagnoses it.
242
+
243
+ Closes #61
244
+ - b87c872: `plugin build` now derives the `com.github.copilot/` component tree, so a plugin's agents reach
245
+ GitHub Copilot CLI.
246
+
247
+ `plugin init` always writes the canonical `$schema`, which puts every plugin this CLI builds into
248
+ Copilot CLI's spec mode. Spec mode reads the runtime's native components — agents, commands, rules,
249
+ `hooks/hooks.json` and `lsp.json` — **only** under `com.github.copilot/`, and no longer from the
250
+ plugin root. The build derived nothing for `copilot-cli`, so every plugin it shipped loaded none of
251
+ them on Copilot CLI, with no warning from anywhere. Skills kept working, which is what made it easy
252
+ to miss.
253
+
254
+ Authoring does not move. You keep declaring `agents`, `commands`, `rules`, `hooks` and `lspServers`
255
+ at their canonical locations, and the build derives the namespace tree from them: the directory kinds
256
+ are copied — with agents renamed to Copilot CLI's `.agent.md` convention, since the canonical
257
+ `agents/` is the Claude Code-shaped `*.md` and a file under the other name is ignored — the hooks file
258
+ is translated (so a handler Copilot CLI cannot run is now dropped from a
259
+ real derived file rather than reported as ignored at runtime), and a declared `lspServers` **path**
260
+ is copied to `com.github.copilot/lsp.json`. An **inline** `lspServers` map is not delivered — the
261
+ file's top-level shape is undocumented, so the build warns rather than guessing. `skills/` and
262
+ `mcp.json` do not move and are not copied. `com.github.copilot/extensions/` runs the other way: it is
263
+ authored there, passed through untouched, and left alone by `--clean`.
264
+
265
+ `copilot-cli` now reports `built` at `com.github.copilot/` when it derives any of this, and still
266
+ reports `canonical` at `plugin.json` when the plugin declares none of the moved kinds. Its manifest
267
+ is unchanged — root `plugin.json` still serves it, so a `harnesses.copilot-cli` override and a
268
+ `pinToPluginVersion` MCP entry are still undelivered and still warn. `plugin init --npm` wires
269
+ `com.github.copilot/` into `package.json` `files`.
270
+
271
+ `doctor` gains `copilot-root-components`: components sitting at the plugin root with no namespace
272
+ copy, which is the shape of the defect above.
273
+
274
+ Verified against `@github/copilot-linux-x64` 1.0.83; the move landed in Copilot CLI 1.0.80-0. The
275
+ published CLI plugin reference still describes the old layout and is stale. Recorded as ADR-0015,
276
+ with the evidence and its confidence under `.research/copilot-spec-mode-namespace/`.
277
+
278
+ Closes #67
279
+ - c152a2e: Stop vendoring the Agent Plugins Specification manifest schema; ship a schema for only the
280
+ `org.cyberuni.universal-plugin` extension namespace.
281
+
282
+ The repository carried `schema/v1.json`, a local fork of the upstream Agent Plugins Specification
283
+ v1.0.0 manifest schema. Every `plugin.json` already declares the published schema
284
+ (`https://agent-plugins.org/schemas/1.0.0/plugin.schema.json`), so the fork added nothing on the
285
+ envelope and could only drift from a spec this project does not own.
286
+
287
+ Upstream deliberately assigns no semantics inside `extensions[<namespace>]`, and that is where all
288
+ of this tool's configuration lives. The file is therefore split along the ownership line: the
289
+ envelope copy is deleted, and the namespace body is retained as
290
+ `schema/extension.schema.json`, now shipped in the package so a consumer resolving these fields
291
+ against an installed dependency can validate against a schema instead of reimplementing the rule.
292
+
293
+ Validating that namespace for the first time surfaced two defects, both fixed:
294
+
295
+ - `plugin build` resolved only the string form of a component path. The array and
296
+ `{ "paths": [...] }` forms — both valid — fell through to `./skills/` without complaint, so a
297
+ plugin declaring its skills either way had them silently left underived. All three forms now
298
+ resolve, every declared directory is searched, and a declared directory that does not exist warns
299
+ instead of being replaced by the default.
300
+ - The per-harness override blocks were a closed field set while the build copies each one verbatim
301
+ into the derived manifest. A harness field newer than the schema now rides along rather than being
302
+ rejected.
303
+ - e8bdb8a: `plugin build` stamps the plugin's version onto an MCP invocation that asks for it.
304
+
305
+ A plugin whose MCP server is its own npm package writes `{"command": "npx", "args": ["-y",
306
+ "my-server", "mcp"]}`, and nothing pins it: a consumer on 1.4.0 gets 1.4.0's skills and whatever
307
+ `npx` resolves as latest for the server, so skills and server drift apart silently. The version is
308
+ known at build time and nowhere else — `mcp.json` expands only `${PLUGIN_ROOT}` and `${PLUGIN_DATA}`,
309
+ so a runtime placeholder would reach the client literally.
310
+
311
+ An `mcpServers` entry now opts in with `"pinToPluginVersion": true`, and the build rewrites that
312
+ entry's package specifier to `<pkg>@<manifest version>`. Opt-in is required and a name match is never
313
+ used — a plugin may publish its server under a package name that is not the plugin's, and
314
+ `npx -y widget-cli` must never be stamped with this plugin's version. The marker is a build
315
+ directive, so it is stripped from every derived manifest and derived MCP file; the authored
316
+ `plugin.json` and `mcp.json` are left as written. Delivery follows the hooks rule: with nothing
317
+ marked, the declaration passes through and nothing is derived; with an entry marked, the pinned map
318
+ is delivered inline when the canonical declared it inline, else as `<vendor-dir>/mcp.json` with the
319
+ vendor's `mcpServers` repointed there.
320
+
321
+ ### Patch Changes
322
+
323
+ - a286459: `init`: stop the vendor table from reading as though Copilot CLI needs nothing derived.
324
+
325
+ Copilot CLI has no derived *manifest* — that part was right. But declaring the canonical `$schema`
326
+ puts a plugin in Open Plugin Spec mode, and Copilot CLI then reads its native components (agents,
327
+ commands, rules, hooks) from a `com.github.copilot/` directory rather than the plugin root. The
328
+ table's "Extra requirements: none" cell was the inaccurate one, and it now names the requirement.
329
+
330
+ Superseded within this release: the build derives that directory now, so the table names the
331
+ requirement as met rather than as tracked.
332
+ - 1524e07: `init`: adoption no longer drops Copilot CLI's non-spec root fields in silence.
333
+
334
+ A pre-0.6 project's root `plugin.json` *was* Copilot CLI's derived manifest, so it carries fields
335
+ like `category` and `tags` that the closed Agent Plugins Spec field set cannot hold. The adopt route
336
+ now enumerates every non-spec field on the pre-adoption root manifest and reports it by name and
337
+ value before overwriting the file, and the losslessness diff includes root `plugin.json` — the one
338
+ vendor manifest that can lose fields, and the one the proof used to skip.
339
+
340
+ `references/vendors/copilot-cli.md` now records what is actually known about `category` and `tags`:
341
+ Copilot CLI documents both as manifest fields, nothing in its documentation consumes either, and the
342
+ Agent Plugins Spec bars a conformant client from assigning unknown fields meaning — so dropping them
343
+ costs nothing observable. What remains unestablished is written down as open questions rather than
344
+ guessed at.
345
+
346
+ The field-sorting table also routes a pre-0.6 top-level `vendorExtensions` block explicitly: it is
347
+ the old name for `harnesses`, not an undeliverable field, and dropping it would discard every
348
+ per-harness override the project had.
349
+
350
+ The Copilot CLI reference is now settled against the shipped runtime rather than the vendor's field
351
+ table: `category` and `tags` have no `plugin.json` handling at all in Copilot CLI 1.0.83 — the
352
+ manifest validator treats them as unknown-and-ignored — and are real only on a `marketplace.json`
353
+ catalog entry. Adoption therefore folds them into `keywords`, a spec field the validator does know,
354
+ instead of dropping them.
355
+
356
+ ## 0.6.0
357
+
358
+ ### Minor Changes
359
+
360
+ - 4c15a40: New `universal-plugin marketplace validate` — check the catalogs a repository carries against the
361
+ schema each runtime loads.
362
+
363
+ A catalog is read at install time, in someone else's terminal, so a broken one is silent here and
364
+ loud there. `validate` moves the refusal to the repository: per target it reports `valid`, `invalid`,
365
+ or `missing` (`--required` makes missing a failure), exits 1 when any selected catalog is invalid, and
366
+ names the key at fault plus the value to write instead — `owner must be an object with a name, not
367
+ string`. The rules are the official Claude Code marketplace schema for Claude Code, Cursor, and
368
+ Copilot CLI, and Codex's own document shape for Codex; a `./` source is also checked for existing on
369
+ disk. Nothing is repaired or written.
370
+
371
+ The same rules now run wherever a catalog is produced: `marketplace init` validates every planned
372
+ artifact and fails before any write, while `plugin init` and `plugin build` — which fold one entry
373
+ into a file they did not author — report the issues as notes and warnings.
374
+
375
+ The `marketplace` skill gained the validation step and now refuses to hand-author a catalog.
376
+
377
+ ### Patch Changes
378
+
379
+ - 4c15a40: Catalog entries now carry manifest metadata in the shape the catalog schema states.
380
+
381
+ A `plugin.json` written from a `package.json` carries `repository` as `{ type, url }`, and every
382
+ generated entry copied that object through. Claude Code refuses such a catalog —
383
+ `plugins[0].repository: expected string` — so a repository could generate a catalog nobody could
384
+ install from. An npm-shaped `repository` now becomes its URL, with any `git+` prefix removed, and a
385
+ manifest field that cannot be reduced to the type the schema states is omitted rather than written.
386
+ - 4c15a40: `doctor` now reports a marketplace catalog its runtime would refuse.
387
+
388
+ The catalogs sit at the repository root, above the plugin in a monorepo, and each is read at install
389
+ time — so a broken one is silent in diagnosis and loud in a user's terminal. The new `invalid-catalog`
390
+ finding names the key at fault and hands the repair to `/universal-plugin:marketplace`. A missing
391
+ catalog is still not a fault.
392
+
393
+ ## 0.5.0
394
+
395
+ ### Minor Changes
396
+
397
+ - f3e6979: `plugin build` now keeps the repository's local marketplace catalogs true. Each build re-derives this
398
+ plugin's entry in every catalog the repository already carries, for the vendors it is building, so a
399
+ catalog entry's version follows the canonical manifest instead of drifting from it (ADR-0010 §3,
400
+ ADR-0014). A version move reaches the catalogs in both release models with no extra command, since
401
+ `plugin version` and `changeset version → publish sync-version` both end in `plugin build`.
402
+
403
+ The refresh creates nothing: a catalog the repository does not carry is not written, and inside one
404
+ it carries, only this plugin's entry changes — the catalog's own fields, its formatting, its
405
+ indentation, and every other plugin's entry stay as they are. `--dry-run` reports the refresh as
406
+ planned. The build output and its JSON gain a `catalogs` list.
407
+
408
+ Neither generator requires a version on a Codex entry any more. `marketplace init --codex` used to
409
+ fail and `plugin init --vendor codex` used to skip the catalog, both on the belief that Codex keys
410
+ its install cache by the entry's version. It does not: the version comes from the plugin's own
411
+ manifest, and an entry that declares none installs normally (verified against codex-cli 0.147.0,
412
+ `.research/local-marketplaces`, E-CODEX-M15, E-CODEX-M16). The entry still carries the canonical
413
+ manifest's version when there is one, because that is this project's policy.
414
+ - d73685a: `marketplace init` now writes Cursor the catalog it actually reads, and every catalog an `owner`
415
+ object.
416
+
417
+ Cursor's plugins reference documents `.cursor-plugin/marketplace.json` at the repository root, close
418
+ to Claude Code's shape. This project's research had recorded the opposite, so `--cursor` produced a
419
+ `.cursor-plugin/marketplace-submission.json` and a `CURSOR_MARKETPLACE_SUBMISSION.md` handoff. Both
420
+ are gone, replaced by the catalog. Cursor also joins the default target set, and the
421
+ `skipped-default` status it carried no longer exists.
422
+
423
+ `owner` was emitted as a string, which Claude Code rejects: `claude plugin validate` reports
424
+ `owner: Invalid input: expected object, received string`. It is now an object carrying `name`, plus
425
+ `email` and `url` when the canonical manifest's `author` supplies them. The Claude catalog also
426
+ carries a `$schema` key for editor completion and validation.
427
+ - 620f2d0: `plugin build` now translates hooks per vendor instead of copying the canonical declaration through
428
+ unchanged. Cursor gets a derived `hooks.json` beside its manifest with camelCase event names, the
429
+ schema version it expects, and matcher groups flattened into its handler list; Claude Code, Codex,
430
+ and Copilot CLI read the canonical PascalCase file as authored.
431
+
432
+ A handler the target vendor cannot run — `http` on Cursor, anything but `command` on Codex, `agent`
433
+ on Copilot CLI — is dropped from that vendor's file and warned about, one warning per event and
434
+ handler type, and the build stays green (ADR-0011). A vendor left with no runnable hook at all gets
435
+ no derived file and no `hooks` field.
436
+ - d73685a: `plugin init --vendor <id>` now registers the plugin in the repository's local marketplace, writing
437
+ each selected vendor's catalog at the repository root — `.claude-plugin/marketplace.json`,
438
+ `.cursor-plugin/marketplace.json`, and the rest — so the plugin can be installed and tested before
439
+ it is published. `--no-marketplace` opts out.
440
+
441
+ The marketplace is named after the repository rather than the plugin, `<owner>-<repo>-local`, since
442
+ the catalog sits at the repository root and lists every plugin the repository develops. The entry's
443
+ `source` is the path from there to the plugin. Owner comes from the canonical manifest's author, the
444
+ package that ships it, or the account the repository lives under; without one there is no catalog,
445
+ because every runtime requires it.
446
+
447
+ Re-running `init` folds the entry into the catalogs already on disk: the marketplace name, the
448
+ owner, and every other plugin's entry stay as they are. The entry's `version` is derived from the
449
+ canonical manifest, never authored, and a version left on an entry whose manifest declares none is
450
+ removed (ADR-0010 §3). A Codex entry is written whether or not there is a version to derive:
451
+ Codex caches a local install under the version the plugin's own manifest carries, never the entry's.
452
+ - 37ae40f: Add a `marketplace` skill: generate the repository's own marketplace catalogs, then write the README install section.
453
+
454
+ `marketplace init` has shipped for a while with no skill in front of it, so nothing surfaced it to an agent. The skill picks targets with the user, runs the generation, verifies it, and offers the install documentation that goes with it.
455
+
456
+ The install commands were verified by running the CLIs, because the documentation is incomplete and a third-party README was the alternative source:
457
+
458
+ - **Claude Code, Codex, and Copilot CLI each install from a catalog the repository carries.** Each reads its own path, and all three read `.claude-plugin/marketplace.json`, so one file covers them when a repository wants fewer.
459
+ - **Codex's marketplace verbs exist but are undocumented.** `codex plugin marketplace add` and `codex plugin add` ship in codex-cli 0.147.0 and appear in no vendor page. Codex installs with `plugin add` where Copilot CLI uses `plugin install`.
460
+ - **Codex discovers a catalog by the filename `marketplace.json`** inside a supported directory. `.claude-plugin/` and `.agents/plugins/` are read; `.codex-plugin/`, `.plugin/`, `.github/plugin/`, and the repository root are not.
461
+ - **A shared catalog must carry `owner`.** Claude Code rejects one without it; Codex does not require it and tolerates extra fields, so the Claude shape is the portable one.
462
+ - **Cursor has no repository-local marketplace.** The `--cursor` output is a submission handoff, and `cursor-agent` has no plugin subcommand.
463
+
464
+ `references/runtimes.md` is the only source of install commands, and every entry carries an evidence ID from `.research/local-marketplaces/`. The skill also documents the Codex local-development loop, where an install is cached by plugin version and a source edit needs a reinstall and a new session.
465
+
466
+ `scripts/install-docs.mjs` derives the README section from the catalogs on disk, so the marketplace name, plugin names, and repository slug come from the repository. It emits JSON and writes nothing; the skill asks before editing the README.
467
+ - aad26dd: Declare plugin dependencies once, and let the build deliver them per vendor. A plugin says what it
468
+ needs under `extensions["org.cyberuni.universal-plugin"].dependencies` — an array of plugin names,
469
+ each optionally `@marketplace`-qualified or given as an object with a semver range or a commit sha.
470
+ Claude Code is the only runtime that reads a dependency, so its manifest carries the declaration and
471
+ the others are built without it, each drop named in a warning. The build stays green. A range written
472
+ into the string form is accepted by the runtime and then discarded, so the build warns once and names
473
+ the object form that is enforced (ADR-0013).
474
+ - f6bf784: Add `plugin install` and `plugin uninstall` — put the plugin under development into a runtime, instead of hand-writing a symlink.
475
+
476
+ Getting a working copy into a runtime meant a symlink per vendor, copy-pasted into every plugin repository's readme. Re-verifying that recipe against the shipped runtimes found both halves wrong: `~/.claude/plugins/local/` does not exist in Claude Code — the path that works is its skills directory, which adopts a plugin and loads it as `<name>@skills-dir` — and Cursor's `~/.cursor/plugins/local/` resolves each symlink and refuses a target outside itself. An author following those two lines got silence from both runtimes and no way to tell why.
477
+
478
+ `plugin install` installs into every vendor the canonical manifest already declares, `--vendor <id>` narrows it, and `--list` shows the resolved destinations without writing. Each vendor's local plugin directory now lives in the vendor registry alongside every other vendor path this tool knows, so a vendor moving its directory is one line here rather than a stale command in every downstream readme — and a machine with a runtime configured elsewhere can override it in `~/.agents/universal-plugin-vendors.json`.
479
+
480
+ The mode resolves per vendor, because a single default cannot serve both runtimes: it links where the vendor follows an out-of-tree symlink and copies where it does not, and the result row names the mode each vendor got. `--copy` forces a snapshot everywhere; `--link` forces a link and fails a vendor that will not load one, rather than quietly copying when a live link was asked for. Codex and Copilot CLI scan no local directory at all and report as `unsupported`, with their marketplace route named.
481
+
482
+ Re-running replaces this plugin's own earlier install rather than stacking; a destination another plugin owns is refused until `--force`. `plugin uninstall` applies the same ownership test, and reports a destination that was never installed rather than failing. Both refuse to run against a vendor whose derived manifest was never built, pointing at `plugin build`.
483
+
484
+ Recorded as ADR-0012, with the verified per-runtime facts and their confidence in `.research/local-marketplaces/`.
485
+ - 50a9c82: Record the version policy as ADR-0010, and give `doctor` the check it obliges.
486
+
487
+ The canonical `plugin.json` owns a plugin's version; every other version-carrying artifact — the per-vendor manifests, the repository-local marketplace catalogs, the `npx`/`upx` pins in `skills/**` — derives from it and is never authored by hand. Who picks the next value splits on `packagePath`: without one the author picks, through `plugin version <bump>`; with one the release picks, and `publish sync-version` carries the number from `package.json` into the manifest.
488
+
489
+ A marketplace entry's version is copied from the canonical manifest of the plugin its `source` resolves to. Where a runtime lets both the entry and the manifest carry one, the manifest wins — Claude Code documents that it overrides the entry silently — so a generated entry is never the number that decides anything, and never a number a human edits.
490
+
491
+ `doctor` gains `unreleased-content`. A runtime keys its plugin cache on the version, so content committed after the commit that set the current one never reaches a consumer who already installed the plugin, and neither side is told: the author sees a successful push, the consumer sees "already at the latest version". The check compares the shipped paths against that commit. It stays quiet on uncommitted work, on a plugin that declares `packagePath` — there the release picks the number — and on a tree with no git history. Alongside it, `doctor` now reads `packagePath` from `.agents/universal-plugin.json`, where the CLI reads it, so `version-drift` fires for the repositories that actually declare one.
492
+
493
+ ### Patch Changes
494
+
495
+ - d998e13: Resolve `--root` to an absolute directory, and stop re-joining a workspace-relative root onto a cwd already inside it
496
+
497
+ In a pnpm monorepo a package is named by its workspace-relative path, so `--root packages/pods`
498
+ run from inside `packages/pods` resolved to `<repo>/packages/pods/packages/pods` — a directory
499
+ that does not exist — and `plugin build` reported `No plugin.json found` against that doubled
500
+ path (#43). Every command taking `--root` now resolves it against the cwd and, when the re-joined
501
+ path is missing while the cwd already ends with the given path, uses the cwd — the package that
502
+ was named.
503
+
504
+ `--root` also resolves to an absolute path in every case now. A relative root previously flowed
505
+ through unresolved, so `No plugin.json found at ../empty` named a fragment rather than the
506
+ directory searched, and `plugin init --root .` derived the plugin name from `path.basename('.')`
507
+ instead of the directory's own name.
508
+
509
+ ## 0.4.0
510
+
511
+ ### Minor Changes
512
+
513
+ - 0d9136b: Replace the `plugin` gateway skill with four verb-shaped skills: `init`, `doctor`, `version`, and `remove-plugin`.
514
+
515
+ The gateway routed six operations behind one name, and no single name covers that set. `init` reads as first-time setup, which is wrong for deleting a manifest; `plugin` is a noun that says what the skill is about and never what it does. One description that has to trigger on "convert this to the open standard", "bump the version", and "delete the generated manifests" is a weaker match for each than three focused ones.
516
+
517
+ Each skill is now scoped by the object it touches, which is also what keeps them from competing for the same asks:
518
+
519
+ - **`init`** — the manifest's declaration: create, adopt, update. Runs five phases (survey, classify, confirm, apply, verify), where confirm is the gate the old gateway lacked: adoption turns files the user maintains into build output, and that needed approval it never asked for.
520
+ - **`doctor`** — read-only diagnosis. Reports what is declared, unbuilt, stale, hand-edited, drifting, or shadowing, and hands every repair to the skill that owns it.
521
+ - **`version`** — the released number, in both release models: changesets-decided and carried in by `publish sync-version`, or moved directly by `plugin version`.
522
+ - **`remove-plugin`** — the artifacts: derived manifests, a stale `.github/plugin/plugin.json`, a shadowing `.plugin/plugin.json`, or the whole plugin behind a confirmation.
523
+
524
+ Also in this change:
525
+
526
+ - `scripts/init.mjs` and `scripts/version.mjs` run their CLI verb from the copy shipped beside the skill, so neither a scaffold nor a release number needs a network fetch.
527
+ - `doctor` ships `scripts/doctor.mjs`: it composes `plugin build --dry-run --format json` with the filesystem facts build cannot see — missing and stale derived manifests, a shadowing `.plugin/plugin.json`, version drift between the two authored numbers — and emits one JSON object. It stays a thin composition so it folds into `plugin validate` when that command lands, rather than competing with it.
528
+ - Each skill carries a README.
529
+ - One reference per vendor, read only when that vendor is enabled, replacing the vendor columns the create reference carried inline.
530
+ - A frontmatter reference documenting `invocation-policy`, including the part that surprises people: the build rewrites the authored `SKILL.md` to carry the derived flags.
531
+ - The create reference no longer claims `plugin build` is unavailable — it has shipped, and the reference now names its flags and the warnings worth reading.
532
+ - The vendor references state plainly that the build does not translate hook event names across the PascalCase/camelCase divide, which it does not (tracked in #41).
533
+
534
+ ADR-0009 records the split and supersedes the single-gateway reach rule in `spec.md` and `plugin/version/`.
535
+ - 4e0e5ee: Emit TOON as the default output format
536
+
537
+ Every command's `--format` help named `toon` as its default, and the AXI output
538
+ contract (ADR-0003) requires it, but the implementation printed aligned ASCII
539
+ tables and padded field lists. Commands now encode their result with
540
+ `@toon-format/toon`, so `plugin build`, `plugin init`, `plugin version`,
541
+ `plugin bundle`, `config add`, `config get`, `governance list`,
542
+ `marketplace init`, and `publish sync-version` emit parseable TOON on stdout.
543
+
544
+ `--format json` is unchanged. `governance show` still prints the document body,
545
+ which is text rather than a record. Each default payload keeps its minimal row
546
+ schema and its pre-computed aggregate summary, so the counts a script matched
547
+ before are still there.
548
+
549
+ ### Patch Changes
550
+
551
+ - a7fa800: Document how a skill runs a CLI its own plugin ships.
552
+
553
+ The npx-and-upx page already named importing in-process as the only complete fix for the runner's cost, and put it at the top of the "choosing a runner" table. It did not say how a skill reaches that code when the skill file and the package both sit in a plugin cache.
554
+
555
+ It now records the launcher pattern: a script in the skill's own `scripts/` directory that resolves the package from `import.meta.url` and imports the bin, invoked as `node scripts/<name>.mjs`. Four requirements come with it, each with its own failure mode: resolve from the script rather than the working directory, keep `node` in front of a file that ships without an executable bit, publish to npm when the CLI has dependencies, and keep a pinned `npx` fallback that is regenerated at release.
556
+ - dda4bca: Ship the MIT license file in the package
557
+
558
+ `package.json` and `plugin.json` both declared `"license": "MIT"`, but no license
559
+ file existed, so the published tarball carried the declaration without the terms
560
+ and the readme's license link pointed at a file that was never there.
561
+
562
+ ## 0.3.1
563
+
564
+ ### Patch Changes
565
+
566
+ - b0da34d: Stop deriving `.cursor/commands/*.md` mirrors of skills
567
+
568
+ The build wrote a copy of every user-invocable skill body to
569
+ `<root>/.cursor/commands/<name>.md`. Cursor does not need it: a plugin's
570
+ `skills` path is loaded directly, and a user invokes a skill by typing `/` and
571
+ searching for it. Cursor also expresses explicit-only invocation natively with
572
+ `disable-model-invocation`, which the build already writes into SKILL.md — so the
573
+ mirror was a redundant second copy of the same content, dropped into the plugin's
574
+ own working tree.
575
+ - 13879cc: Derive universal-plugin's own vendor manifests instead of hand-maintaining them
576
+
577
+ The package shipped `.claude-plugin/`, `.cursor-plugin/`, and `.codex-plugin/`
578
+ manifests that were written by hand and never regenerated, because the canonical
579
+ `plugin.json` declared no `harnesses`. They had drifted to `version` `0.2.0` and
580
+ still carried the retired `vendors` and a `assets` path pointing at a directory
581
+ that does not exist — so every runtime reading a vendor manifest saw a stale
582
+ version. Declaring the four harnesses lets `universal-plugin plugin build`
583
+ produce them, and the regenerated files now track the canonical version.
584
+ - 7c026fb: Regenerate the vendor manifests during `changeset version`
585
+
586
+ The release chain synced the canonical `plugin.json` and stopped there —
587
+ `publish sync-version` writes exactly one row, so `.claude-plugin/`,
588
+ `.cursor-plugin/`, and `.codex-plugin/` kept whatever version they were last
589
+ committed with. The repo's own manifests had drifted a full minor behind as a
590
+ result. The root `version` script now runs `plugin:build` after the sync, so
591
+ every release derives the vendor manifests from the freshly synced version.
592
+
593
+ ## 0.3.0
594
+
595
+ ### Minor Changes
596
+
597
+ - e9a31ce: Add `universal-plugin marketplace init` for deterministic repository-local marketplace metadata.
598
+ - 8fb8297: `plugin build` no longer derives a manifest for `copilot-cli`. Copilot CLI searches
599
+ `.plugin/plugin.json` → `plugin.json` → `.github/plugin/plugin.json` → `.claude-plugin/plugin.json`
600
+ and takes the first match, so the canonical root `plugin.json` always shadowed the
601
+ `.github/plugin/plugin.json` we were emitting — that file was never read. Copilot CLI has consumed
602
+ Open Plugin Spec v1 manifests since v1.0.74, so the canonical manifest serves it directly. The
603
+ vendor is now reported with status `canonical`, and a `harnesses["copilot-cli"]` override warns that
604
+ it has no delivery path (the canonical schema is closed to vendor-only fields).
605
+
606
+ Delete any stale `.github/plugin/plugin.json` from a previous build; it was inert.
607
+ - 8dfffbd: Derive vendor slash-command artifacts from skill invocation policies.
608
+ - b50b9c8: The `plugin` skill now detects existing plugins on invocation. When a project has a vendor-specific
609
+ manifest (`.claude-plugin/`, `.cursor-plugin/`, …) or already ships public skills but has no
610
+ canonical root `plugin.json`, the gateway offers to adopt the open Agent Plugins Specification. The
611
+ lossless conversion procedure lives in the new `references/adopt.md`. Repo-private agent config
612
+ (`.claude/skills/`, `.agents/skills/`) is excluded from detection.
613
+ - ab6ff25: New `universal-plugin plugin version <major|minor|patch|premajor|preminor|prepatch|prerelease|x.y.z>`
614
+ moves a plugin's version. A version lives in up to five places, but only two of them are
615
+ **authored**: the canonical root `plugin.json` and, when `.agents/universal-plugin.json` declares a
616
+ `packagePath`, that `package.json`. The rest — the per-vendor manifests, the local marketplace
617
+ catalogs, and the `npx`/`upx` pins in `skills/**` — are **derived** by commands that already exist.
618
+ So the verb writes the authored pair and then calls `plugin build`'s own writer to re-derive, rather
619
+ than becoming a second writer for files `build` owns.
620
+
621
+ `--preid <id>` picks the prerelease identifier, `--force` allows a version that does not advance,
622
+ `--no-build` skips re-derivation, and `--dry-run` reports the plan without writing. Every guard —
623
+ missing manifest, a relative bump with no current version, an unknown bump argument, a
624
+ non-advancing target, a declared `packagePath` whose `package.json` is absent — fails loud and
625
+ leaves the tree untouched.
626
+
627
+ `publish sync-version` keeps the opposite direction (a changesets-decided number flowing
628
+ `package.json` → manifest) with its behavior unchanged, but now shares the new applier so the two
629
+ directions cannot drift apart.
630
+
631
+ The shipped `plugin` gateway skill gains a matching route — `references/version.md` — so an agent
632
+ asked to bump a plugin's version finds the verb instead of hand-editing a `version` field. Its
633
+ route table previously covered create / adopt / inspect / update / delete, none of which is moving
634
+ the version. The skill description now names the version triggers explicitly, and the reference
635
+ routes changesets repos to `publish sync-version` rather than to the new verb.
636
+ - 36d05fc: Shorten the bundled skill names by dropping the redundant `universal-plugin` half — the plugin
637
+ namespace already supplies it. `universal-plugin` → `plugin`, `publish-universal-plugin` →
638
+ `publish-plugin`, `upgrade-universal-plugin` → `upgrade-plugin`, `migrate-universal-plugin` →
639
+ `migrate-plugin`. Invocation becomes `/universal-plugin:plugin` instead of
640
+ `/universal-plugin:universal-plugin`. `adopt-upx` is unchanged.
641
+
642
+ **Breaking for name-pinned installs.** Installing the whole plugin is unaffected — the marketplace
643
+ entry resolves the package directory and discovers skills from `skills/`, so nothing there refers to
644
+ a skill by name. But a per-skill install pinned the old name, and that path is gone:
645
+
646
+ ```bash
647
+ # before
648
+ npx skills add cyberuni/universal-plugin --skill upgrade-universal-plugin
649
+ # after
650
+ npx skills add cyberuni/universal-plugin --skill upgrade-plugin
651
+ ```
652
+
653
+ Update the `skills` key and `source` path in your `skills-lock.json`, or re-run `skills add` with the
654
+ new name. No aliases are shipped for the old names.
655
+ - e2a57e1: Add `upx`, a local-first package runner, as a second lean bin.
656
+
657
+ `upx <pkg>@<range> [args…]` resolves the requested semver range against installed packages —
658
+ walking `node_modules` from the cwd up through its ancestors (nearest wins), then the global
659
+ `npm root -g` store — and spawns the matching binary directly, roughly 10× faster than `npx`
660
+ (which pays ~1s of registry resolution per call even when cached). On a miss it falls back to
661
+ `npx` with the spec exactly as given, printing a one-line stderr notice. It is a transparent
662
+ exec wrapper: the child owns stdout/stderr and its exit code; `upx` installs nothing and writes
663
+ nothing to `node_modules` or the global store. A dist-tag (`pkg@next`) goes straight to `npx`.
664
+
665
+ Also adds `plugin bundle --runner <npx|upx>`: omitting it preserves each skill reference's
666
+ existing runner word while re-pinning the version; `--runner upx` opts a release into emitting
667
+ `upx` references.
668
+
669
+ ### Patch Changes
670
+
671
+ - d28501c: Synchronize local Codex marketplace entry versions with canonical plugin manifests.
672
+ - df326ae: `plugin init --npm` now always wires the open-standard base — the canonical root `plugin.json` and
673
+ `skills/` — into `package.json` `files`, whatever `--vendor` targets are named. Previously the base
674
+ was tied to vendor selection, so a default `--npm` run wired `.claude-plugin/plugin.json` and
675
+ `skills/` but never the canonical manifest, and the published package shipped a Claude Code plugin
676
+ rather than a standard one. Vendor-derived manifests are added on top of the base, never in place
677
+ of it.
678
+ - 454267e: Restructure the `plugin` skill as a gateway. The Create, Inspect, Update, and Delete procedures
679
+ moved out of `SKILL.md` into `references/create.md`, `references/inspect.md`,
680
+ `references/update.md`, and `references/delete.md`. `SKILL.md` now carries only the trigger,
681
+ prerequisites, and a routing table, so an agent loads one operation's procedure instead of all four.
682
+
683
+ ## 0.2.1
684
+
685
+ ### Patch Changes
686
+
687
+ - 7c92d8e: Mark the CLI bin shim as executable so it runs directly after install.
688
+
689
+ ## 0.2.0
690
+
691
+ ### Minor Changes
692
+
693
+ - c6bc08a: Add `publish sync-version` command to sync the `version` field in `.plugin/plugin.json` from the npm package declared by a new `packagePath` field. Run `universal-plugin publish sync-version` after `changeset version` to keep the plugin manifest version in sync with the npm package. Also fixes the `build` command to strip `packagePath` from generated vendor manifests.
694
+ - 1100fa3: Add initial `universal-plugin` CLI with cross-vendor plugin management commands.
695
+
696
+ New commands:
697
+ - `prepare` — diffs the current vendor's installed plugins against the last snapshot and writes pending cross-vendor sync actions to state.
698
+ - `sync apply <actionId>` — executes a pending install, update, or remove action using the target vendor's registered CLI command (or emits a manual instruction when none is configured).
699
+ - `governance show <name>` / `governance list` — resolves and displays governance files by scope (global → project).
700
+ - `asset-store` — manages the local store of downloaded plugin assets.
701
+ - `self-update` — rewrites `universal-plugin` version pins in hook files when a newer version is detected.
702
+ - `clean` — removes the local asset store directory.
703
+
704
+ Supporting modules added: state file schema with tolerant reader and mutation helpers, vendor registry with bundled defaults and user-override support, source registry with store-path derivation for npm / GitHub / GitLab / URL sources.