universal-plugin 0.13.0 → 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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "universal-plugin",
3
- "version": "0.13.0",
3
+ "version": "0.14.0",
4
4
  "description": "Research and design toolkit for building universal AI coding agent plugins that work across Claude Code, Cursor, Codex, and GitHub Copilot CLI.",
5
5
  "author": {
6
6
  "name": "unional"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "universal-plugin",
3
- "version": "0.13.0",
3
+ "version": "0.14.0",
4
4
  "description": "Research and design toolkit for building universal AI coding agent plugins that work across Claude Code, Cursor, Codex, and GitHub Copilot CLI.",
5
5
  "author": {
6
6
  "name": "unional"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "universal-plugin",
3
- "version": "0.13.0",
3
+ "version": "0.14.0",
4
4
  "description": "Research and design toolkit for building universal AI coding agent plugins that work across Claude Code, Cursor, Codex, and GitHub Copilot CLI.",
5
5
  "author": {
6
6
  "name": "unional"
package/dist/cli.mjs CHANGED
@@ -6098,7 +6098,7 @@ function schemaRuleViolations(manifest, warnings) {
6098
6098
  const INLINE_LINK = /!?\[[^\]\n]*\]\(\s*<?([^)\s>]+)>?(?:\s+["'(][^)]*)?\)/g;
6099
6099
  /** Reference definitions, `[label]: target`. */
6100
6100
  const REFERENCE_DEFINITION = /^\s{0,3}\[[^\]\n]+\]:\s*<?(\S+?)>?(?:\s|$)/;
6101
- const FENCE = /^\s{0,3}(`{3,}|~{3,})/;
6101
+ const FENCE$1 = /^\s{0,3}(`{3,}|~{3,})/;
6102
6102
  /** The relative links in `content` whose target resolves outside the skill folder. `fileInSkill` is
6103
6103
  * the file's path relative to the skill folder, `/`-separated (`SKILL.md`, `references/a.md`).
6104
6104
  * Fenced code is skipped: a link there is an example, not one the agent follows. */
@@ -6109,7 +6109,7 @@ function escapingLinks(content, fileInSkill) {
6109
6109
  const lines = content.split(/\r?\n/);
6110
6110
  for (let i = 0; i < lines.length; i++) {
6111
6111
  const line = lines[i] ?? "";
6112
- const marker = line.match(FENCE)?.[1];
6112
+ const marker = line.match(FENCE$1)?.[1];
6113
6113
  if (marker !== void 0) {
6114
6114
  if (fence === null) fence = marker[0];
6115
6115
  else if (marker[0] === fence) fence = null;
@@ -6141,6 +6141,38 @@ function leavesSkill(fileDir, target) {
6141
6141
  return false;
6142
6142
  }
6143
6143
  //#endregion
6144
+ //#region src/build/skill-references.ts
6145
+ /** The folder name pnpm gives a skill: `pnpm-<package>-<skill>`, with `/` in the package as `+`. */
6146
+ function pnpmSkillName(packageName, skill) {
6147
+ return `pnpm-${packageName.replace(/\//g, "+")}-${skill}`;
6148
+ }
6149
+ const FENCE = /^\s{0,3}(`{3,}|~{3,})/;
6150
+ /** `/plugin:skill`, bare or alone in an inline code span. A span that holds more (`/p:s --flag`) is a
6151
+ * command example and stays as written. */
6152
+ const REFERENCE = /(`?)(?<![\w/.:@-])\/([a-z0-9][a-z0-9-]*):([a-z0-9][a-z0-9-]*)(?![\w:/-])(`?)/g;
6153
+ const ALREADY = " (pnpm install: `";
6154
+ /** `content` with the pnpm name added after each reference this package can resolve:
6155
+ * `/<plugin>:<skill>` (pnpm install: `pnpm-<package>-<skill>`). A reference that already carries
6156
+ * it, one to another plugin or an unknown skill, and anything inside fenced code is left alone, so
6157
+ * a rebuild changes nothing. Fences are skipped whole: the added text would break a command. */
6158
+ function addPnpmNames(content, target) {
6159
+ let fence = null;
6160
+ return content.split(/(\r?\n)/).map((line) => {
6161
+ const marker = line.match(FENCE)?.[1];
6162
+ if (marker !== void 0) {
6163
+ if (fence === null) fence = marker[0];
6164
+ else if (marker[0] === fence) fence = null;
6165
+ return line;
6166
+ }
6167
+ if (fence !== null) return line;
6168
+ return line.replace(REFERENCE, (match, open, plugin, skill, close, offset) => {
6169
+ if (open !== close || plugin !== target.plugin || !target.skills.has(skill)) return match;
6170
+ if (line.startsWith(ALREADY, offset + match.length)) return match;
6171
+ return `${open === "" ? `\`/${plugin}:${skill}\`` : match}${ALREADY}${pnpmSkillName(target.packageName, skill)}\`)`;
6172
+ });
6173
+ }).join("");
6174
+ }
6175
+ //#endregion
6144
6176
  //#region src/build/build.ts
6145
6177
  /** Where each vendor reads its manifest, relative to the project root. Shared with
6146
6178
  * `plugin init --npm`, which wires exactly these paths into `package.json` `files`. */
@@ -6338,6 +6370,7 @@ function buildPlugin(root, opts = {}) {
6338
6370
  warnings.push(...validateDependencies(declaredDependencies).warnings);
6339
6371
  const skills = readSkills(root, manifest, warnings);
6340
6372
  warnings.push(...skillLinkWarnings(root, skills));
6373
+ writePnpmNames(root, manifest, skills, opts, written);
6341
6374
  const canonicalHooks = readCanonicalHooks(root, componentConfig["hooks"], warnings);
6342
6375
  const declaredMcp = readCanonicalMcpServers(root, componentConfig["mcpServers"], warnings);
6343
6376
  const mcp = declaredMcp ? stripPinMarkers(declaredMcp.servers) : null;
@@ -6577,6 +6610,35 @@ function skillLinkWarnings(root, skills) {
6577
6610
  }
6578
6611
  return warnings;
6579
6612
  }
6613
+ /** Adds the pnpm name beside each `/<plugin>:<skill>` reference to a skill this package ships, in every
6614
+ * Markdown file under a skill. The name comes from the package's own `package.json`; with none, the
6615
+ * references stay as written. A reference to another plugin cannot be resolved here, and is left
6616
+ * without a warning because it is usually a legitimate one. */
6617
+ function writePnpmNames(root, manifest, skills, opts, written) {
6618
+ const packageName = readPackageName(root);
6619
+ if (!packageName || typeof manifest.name !== "string") return;
6620
+ const target = {
6621
+ plugin: manifest.name,
6622
+ packageName,
6623
+ skills: new Set(skills.map((s) => s.name))
6624
+ };
6625
+ for (const skill of skills) for (const file of listFilesRecursive(path$1.dirname(skill.path)).filter((f) => f.endsWith(".md"))) {
6626
+ const before = fs$1.readFileSync(file, "utf8");
6627
+ const after = addPnpmNames(before, target);
6628
+ if (after === before) continue;
6629
+ if (!opts.dryRun) fs$1.writeFileSync(file, after);
6630
+ written.push(file);
6631
+ if (file === skill.path) skill.content = after;
6632
+ }
6633
+ }
6634
+ function readPackageName(root) {
6635
+ try {
6636
+ const name = JSON.parse(fs$1.readFileSync(path$1.join(root, "package.json"), "utf8")).name;
6637
+ return typeof name === "string" && name !== "" ? name : void 0;
6638
+ } catch {
6639
+ return;
6640
+ }
6641
+ }
6580
6642
  function listSkillFiles(dir) {
6581
6643
  return fs$1.readdirSync(dir, { withFileTypes: true }).flatMap((entry) => {
6582
6644
  const entryPath = path$1.join(dir, entry.name);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "universal-plugin",
3
- "version": "0.13.0",
3
+ "version": "0.14.0",
4
4
  "description": "Universal AI agent plugin build tool",
5
5
  "keywords": [
6
6
  "agent-plugin",
package/plugin.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
3
3
  "name": "universal-plugin",
4
- "version": "0.13.0",
4
+ "version": "0.14.0",
5
5
  "description": "Research and design toolkit for building universal AI coding agent plugins that work across Claude Code, Cursor, Codex, and GitHub Copilot CLI.",
6
6
  "author": {
7
7
  "name": "unional"
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  // Compiled by `universal-plugin plugin build` from src/skill-scripts/rewrite-upx.ts. Edit the source, not this file.
3
- globalThis.__SKILL_SCRIPT__ = {"package":"universal-plugin","bin":"universal-plugin","version":"0.13.0","entry":"skills/adopt-upx/scripts/rewrite-upx.mjs","commands":{"marketplace add":"skills/marketplace/scripts/add.mjs","marketplace init":"skills/marketplace/scripts/marketplace.mjs","marketplace validate":"skills/marketplace/scripts/validate.mjs","plugin build":"skills/build-plugin/scripts/build.mjs","plugin init":"skills/init-universal-plugin/scripts/init.mjs","plugin version":"skills/version/scripts/version.mjs"}};
3
+ globalThis.__SKILL_SCRIPT__ = {"package":"universal-plugin","bin":"universal-plugin","version":"0.14.0","entry":"skills/adopt-upx/scripts/rewrite-upx.mjs","commands":{"marketplace add":"skills/marketplace/scripts/add.mjs","marketplace init":"skills/marketplace/scripts/marketplace.mjs","marketplace validate":"skills/marketplace/scripts/validate.mjs","plugin build":"skills/build-plugin/scripts/build.mjs","plugin init":"skills/init-universal-plugin/scripts/init.mjs","plugin version":"skills/version/scripts/version.mjs"}};
4
4
  import { readFileSync, readdirSync, statSync, writeFileSync } from "node:fs";
5
5
  import { join, resolve } from "node:path";
6
6
  //#region src/skill-scripts/rewrite-upx.ts
@@ -22,7 +22,7 @@ rather than reported as success.
22
22
  ## Install
23
23
 
24
24
  Ships with the `universal-plugin` plugin. It is invoked in Claude Code as
25
- `/universal-plugin:build-plugin`.
25
+ `/universal-plugin:build-plugin` (pnpm install: `pnpm-universal-plugin-build-plugin`).
26
26
 
27
27
  ## References
28
28
 
@@ -47,7 +47,7 @@ node scripts/build.mjs --root <plugin-root>
47
47
 
48
48
  Resolve `scripts/build.mjs` against this skill's own directory. It runs the CLI the project installed
49
49
  (`pnpm exec universal-plugin`), else the CLI pinned to the version this skill shipped with
50
- (`npx universal-plugin@0.13.0`), so it works in a skill that was linked or copied on its own. `--root` defaults to the working directory and
50
+ (`npx universal-plugin@0.14.0`), so it works in a skill that was linked or copied on its own. `--root` defaults to the working directory and
51
51
  must name the directory that holds the canonical `plugin.json`.
52
52
 
53
53
  The command never prompts, so it is safe to run unattended.
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  // Compiled by `universal-plugin plugin build` from src/skill-scripts/run-cli.ts. Edit the source, not this file.
3
- globalThis.__SKILL_SCRIPT__ = {"package":"universal-plugin","bin":"universal-plugin","version":"0.13.0","entry":"skills/build-plugin/scripts/build.mjs","commands":{"marketplace add":"skills/marketplace/scripts/add.mjs","marketplace init":"skills/marketplace/scripts/marketplace.mjs","marketplace validate":"skills/marketplace/scripts/validate.mjs","plugin build":"skills/build-plugin/scripts/build.mjs","plugin init":"skills/init-universal-plugin/scripts/init.mjs","plugin version":"skills/version/scripts/version.mjs"}};
3
+ globalThis.__SKILL_SCRIPT__ = {"package":"universal-plugin","bin":"universal-plugin","version":"0.14.0","entry":"skills/build-plugin/scripts/build.mjs","commands":{"marketplace add":"skills/marketplace/scripts/add.mjs","marketplace init":"skills/marketplace/scripts/marketplace.mjs","marketplace validate":"skills/marketplace/scripts/validate.mjs","plugin build":"skills/build-plugin/scripts/build.mjs","plugin init":"skills/init-universal-plugin/scripts/init.mjs","plugin version":"skills/version/scripts/version.mjs"}};
4
4
  import { spawnSync } from "node:child_process";
5
5
  //#region src/compile/scripts.ts
6
6
  /** The global the header assigns the script data to. Framework-neutral: a script's own code, or the
@@ -71,32 +71,32 @@ Each `code` below is what the script emits.
71
71
 
72
72
  | Finding | What it means | Repair |
73
73
  | --- | --- | --- |
74
- | `no-manifest` | no root `plugin.json` — this is not a plugin yet | `/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`, adopt route |
76
- | `vendor-only` | a vendor manifest with no canonical manifest above it | `/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` |
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` |
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`) |
79
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 |
80
80
  | `unknown-vendor` | a `vendors` entry no build target matches; reported as `skipped` plus a warning | fix the id in `plugin.json` |
81
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 |
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`, 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` |
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
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
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`, update route — move them to a vendor that has a derived manifest, or drop them |
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 |
87
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 |
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` (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` |
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` |
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` |
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` |
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` |
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`, 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 |
95
95
  | `package-path-missing` | `packagePath` names a directory with no readable `package.json` | fix `packagePath`, or create the package |
96
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 |
97
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 |
98
98
  | `unparsable-manifest` | root `plugin.json` is not valid JSON | fix the syntax error |
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` |
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`) |
100
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 |
101
101
 
102
102
  ## Catalogs are checked at the repository root
@@ -105,7 +105,7 @@ The marketplace catalogs sit above the plugin in a monorepo, so the catalog chec
105
105
  repository root rather than `--root`. It reports only a catalog that would be **refused**: a missing
106
106
  one is not a fault, and nothing here has an opinion on which catalogs a repository ought to carry.
107
107
 
108
- 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
109
109
  entry's fields are derived from the plugin's `plugin.json`, and the catalog's own `name` and `owner`
110
110
  are authored in the catalog — which half is at fault decides where the repair goes.
111
111
 
@@ -157,7 +157,7 @@ holding `0.0.0-development` is reported as `unstamped`, not as `version-drift`.
157
157
 
158
158
  Files diverge when someone ran `npm version`, or when a release tool (changesets, release-please,
159
159
  semantic-release) moved `package.json` and nothing stamped the number on. All of it is
160
- `/universal-plugin:version`'s to fix — never patch one file by hand to match another.
160
+ `/universal-plugin:version` (pnpm install: `pnpm-universal-plugin-version`)'s to fix — never patch one file by hand to match another.
161
161
 
162
162
  ### Offer the check to CI
163
163
 
@@ -172,7 +172,7 @@ it does not, offer to add it — ask first, because both are the user's files:
172
172
  semantic-release bot opens.
173
173
 
174
174
  Use the locked `universal-plugin` from the repository's devDependencies when it has one; otherwise
175
- `npx universal-plugin@0.13.0`, pinned. This check matters most where the release tool picks the
175
+ `npx universal-plugin@0.14.0`, pinned. This check matters most where the release tool picks the
176
176
  number, because nothing else runs between that bump and publish.
177
177
 
178
178
  ## Unreleased content
@@ -191,7 +191,7 @@ Two cases are deliberately silent. A plugin that declares `packagePath` is skipp
191
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
192
192
  normal state of a branch. A tree with no git history is skipped rather than guessed at.
193
193
 
194
- 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
195
195
  is meant to ship — content that is still being worked on is not a finding to act on.
196
196
 
197
197
  ## Rules
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  // Compiled by `universal-plugin plugin build` from src/skill-scripts/doctor.ts. Edit the source, not this file.
3
- globalThis.__SKILL_SCRIPT__ = {"package":"universal-plugin","bin":"universal-plugin","version":"0.13.0","entry":"skills/doctor-universal-plugin/scripts/doctor.mjs","commands":{"marketplace add":"skills/marketplace/scripts/add.mjs","marketplace init":"skills/marketplace/scripts/marketplace.mjs","marketplace validate":"skills/marketplace/scripts/validate.mjs","plugin build":"skills/build-plugin/scripts/build.mjs","plugin init":"skills/init-universal-plugin/scripts/init.mjs","plugin version":"skills/version/scripts/version.mjs"}};
3
+ globalThis.__SKILL_SCRIPT__ = {"package":"universal-plugin","bin":"universal-plugin","version":"0.14.0","entry":"skills/doctor-universal-plugin/scripts/doctor.mjs","commands":{"marketplace add":"skills/marketplace/scripts/add.mjs","marketplace init":"skills/marketplace/scripts/marketplace.mjs","marketplace validate":"skills/marketplace/scripts/validate.mjs","plugin build":"skills/build-plugin/scripts/build.mjs","plugin init":"skills/init-universal-plugin/scripts/init.mjs","plugin version":"skills/version/scripts/version.mjs"}};
4
4
  import { spawnSync } from "node:child_process";
5
5
  import * as fs from "node:fs";
6
6
  import * as path from "node:path";
@@ -43,7 +43,7 @@ node scripts/init.mjs --name <plugin-name> --vendor claude-code --vendor cursor
43
43
  ```
44
44
 
45
45
  Resolve `scripts/init.mjs` against this skill's directory; it runs the project's installed CLI, else
46
- the pinned `npx universal-plugin@0.13.0`. Add `--npm` when an npm package ships the plugin,
46
+ the pinned `npx universal-plugin@0.14.0`. Add `--npm` when an npm package ships the plugin,
47
47
  which also wires that `package.json`'s `files` to carry the derived manifests, copies its `version`
48
48
  into the manifest, and, in a changesets repository, wires the root `version` script to run
49
49
  `plugin version --from-package` (SKILL.md Phase 3 asks before that rewrite).
@@ -122,4 +122,4 @@ rejected by Cursor's own scan.
122
122
  ## Next
123
123
 
124
124
  Shipping it on npm → `migrate-plugin`. Listing it in a marketplace → `publish-plugin`. Releasing a
125
- number → `/universal-plugin:version`.
125
+ number → `/universal-plugin:version` (pnpm install: `pnpm-universal-plugin-version`).
@@ -86,7 +86,7 @@ what only that component does; the `plugin-design` reference is the authority on
86
86
 
87
87
  - **Never hand-edit a derived manifest.** `plugin build` owns `.claude-plugin/plugin.json` and its
88
88
  siblings; an edit there survives until the next build and no longer.
89
- - **Never hand-edit a `version` field.** That move belongs to `/universal-plugin:version`.
89
+ - **Never hand-edit a `version` field.** That move belongs to `/universal-plugin:version` (pnpm install: `pnpm-universal-plugin-version`).
90
90
  - **The canonical schema is closed.** A vendor-only field cannot be added at the top level; it goes
91
91
  under that vendor's `harnesses` entry or nowhere.
92
92
  - Root `plugin.json` is not a build artifact. It is both the source of truth and the file Copilot CLI
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  // Compiled by `universal-plugin plugin build` from src/skill-scripts/run-cli.ts. Edit the source, not this file.
3
- globalThis.__SKILL_SCRIPT__ = {"package":"universal-plugin","bin":"universal-plugin","version":"0.13.0","entry":"skills/init-universal-plugin/scripts/init.mjs","commands":{"marketplace add":"skills/marketplace/scripts/add.mjs","marketplace init":"skills/marketplace/scripts/marketplace.mjs","marketplace validate":"skills/marketplace/scripts/validate.mjs","plugin build":"skills/build-plugin/scripts/build.mjs","plugin init":"skills/init-universal-plugin/scripts/init.mjs","plugin version":"skills/version/scripts/version.mjs"}};
3
+ globalThis.__SKILL_SCRIPT__ = {"package":"universal-plugin","bin":"universal-plugin","version":"0.14.0","entry":"skills/init-universal-plugin/scripts/init.mjs","commands":{"marketplace add":"skills/marketplace/scripts/add.mjs","marketplace init":"skills/marketplace/scripts/marketplace.mjs","marketplace validate":"skills/marketplace/scripts/validate.mjs","plugin build":"skills/build-plugin/scripts/build.mjs","plugin init":"skills/init-universal-plugin/scripts/init.mjs","plugin version":"skills/version/scripts/version.mjs"}};
4
4
  import { spawnSync } from "node:child_process";
5
5
  //#region src/compile/scripts.ts
6
6
  /** The global the header assigns the script data to. Framework-neutral: a script's own code, or the
@@ -127,5 +127,5 @@ with the current source, so neither `codex plugin remove` nor a version bump is
127
127
  the cache when a session starts, so the session you are in keeps the old copy — start a new one.
128
128
 
129
129
  The catalog entry's version is derived from the canonical manifest, so a version move updates both
130
- (`/universal-plugin:version` owns that). Codex itself does not read the entry's version; keeping it
130
+ (`/universal-plugin:version` (pnpm install: `pnpm-universal-plugin-version`) owns that). Codex itself does not read the entry's version; keeping it
131
131
  true is this project's policy, so the catalog never states a version the plugin does not have.
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  // Compiled by `universal-plugin plugin build` from src/skill-scripts/run-cli.ts. Edit the source, not this file.
3
- globalThis.__SKILL_SCRIPT__ = {"package":"universal-plugin","bin":"universal-plugin","version":"0.13.0","entry":"skills/marketplace/scripts/add.mjs","commands":{"marketplace add":"skills/marketplace/scripts/add.mjs","marketplace init":"skills/marketplace/scripts/marketplace.mjs","marketplace validate":"skills/marketplace/scripts/validate.mjs","plugin build":"skills/build-plugin/scripts/build.mjs","plugin init":"skills/init-universal-plugin/scripts/init.mjs","plugin version":"skills/version/scripts/version.mjs"}};
3
+ globalThis.__SKILL_SCRIPT__ = {"package":"universal-plugin","bin":"universal-plugin","version":"0.14.0","entry":"skills/marketplace/scripts/add.mjs","commands":{"marketplace add":"skills/marketplace/scripts/add.mjs","marketplace init":"skills/marketplace/scripts/marketplace.mjs","marketplace validate":"skills/marketplace/scripts/validate.mjs","plugin build":"skills/build-plugin/scripts/build.mjs","plugin init":"skills/init-universal-plugin/scripts/init.mjs","plugin version":"skills/version/scripts/version.mjs"}};
4
4
  import { spawnSync } from "node:child_process";
5
5
  //#region src/compile/scripts.ts
6
6
  /** The global the header assigns the script data to. Framework-neutral: a script's own code, or the
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  // Compiled by `universal-plugin plugin build` from src/skill-scripts/install-docs.ts. Edit the source, not this file.
3
- globalThis.__SKILL_SCRIPT__ = {"package":"universal-plugin","bin":"universal-plugin","version":"0.13.0","entry":"skills/marketplace/scripts/install-docs.mjs","commands":{"marketplace add":"skills/marketplace/scripts/add.mjs","marketplace init":"skills/marketplace/scripts/marketplace.mjs","marketplace validate":"skills/marketplace/scripts/validate.mjs","plugin build":"skills/build-plugin/scripts/build.mjs","plugin init":"skills/init-universal-plugin/scripts/init.mjs","plugin version":"skills/version/scripts/version.mjs"}};
3
+ globalThis.__SKILL_SCRIPT__ = {"package":"universal-plugin","bin":"universal-plugin","version":"0.14.0","entry":"skills/marketplace/scripts/install-docs.mjs","commands":{"marketplace add":"skills/marketplace/scripts/add.mjs","marketplace init":"skills/marketplace/scripts/marketplace.mjs","marketplace validate":"skills/marketplace/scripts/validate.mjs","plugin build":"skills/build-plugin/scripts/build.mjs","plugin init":"skills/init-universal-plugin/scripts/init.mjs","plugin version":"skills/version/scripts/version.mjs"}};
4
4
  import { execFileSync } from "node:child_process";
5
5
  import * as fs from "node:fs";
6
6
  import * as path from "node:path";
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  // Compiled by `universal-plugin plugin build` from src/skill-scripts/run-cli.ts. Edit the source, not this file.
3
- globalThis.__SKILL_SCRIPT__ = {"package":"universal-plugin","bin":"universal-plugin","version":"0.13.0","entry":"skills/marketplace/scripts/marketplace.mjs","commands":{"marketplace add":"skills/marketplace/scripts/add.mjs","marketplace init":"skills/marketplace/scripts/marketplace.mjs","marketplace validate":"skills/marketplace/scripts/validate.mjs","plugin build":"skills/build-plugin/scripts/build.mjs","plugin init":"skills/init-universal-plugin/scripts/init.mjs","plugin version":"skills/version/scripts/version.mjs"}};
3
+ globalThis.__SKILL_SCRIPT__ = {"package":"universal-plugin","bin":"universal-plugin","version":"0.14.0","entry":"skills/marketplace/scripts/marketplace.mjs","commands":{"marketplace add":"skills/marketplace/scripts/add.mjs","marketplace init":"skills/marketplace/scripts/marketplace.mjs","marketplace validate":"skills/marketplace/scripts/validate.mjs","plugin build":"skills/build-plugin/scripts/build.mjs","plugin init":"skills/init-universal-plugin/scripts/init.mjs","plugin version":"skills/version/scripts/version.mjs"}};
4
4
  import { spawnSync } from "node:child_process";
5
5
  //#region src/compile/scripts.ts
6
6
  /** The global the header assigns the script data to. Framework-neutral: a script's own code, or the
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  // Compiled by `universal-plugin plugin build` from src/skill-scripts/run-cli.ts. Edit the source, not this file.
3
- globalThis.__SKILL_SCRIPT__ = {"package":"universal-plugin","bin":"universal-plugin","version":"0.13.0","entry":"skills/marketplace/scripts/validate.mjs","commands":{"marketplace add":"skills/marketplace/scripts/add.mjs","marketplace init":"skills/marketplace/scripts/marketplace.mjs","marketplace validate":"skills/marketplace/scripts/validate.mjs","plugin build":"skills/build-plugin/scripts/build.mjs","plugin init":"skills/init-universal-plugin/scripts/init.mjs","plugin version":"skills/version/scripts/version.mjs"}};
3
+ globalThis.__SKILL_SCRIPT__ = {"package":"universal-plugin","bin":"universal-plugin","version":"0.14.0","entry":"skills/marketplace/scripts/validate.mjs","commands":{"marketplace add":"skills/marketplace/scripts/add.mjs","marketplace init":"skills/marketplace/scripts/marketplace.mjs","marketplace validate":"skills/marketplace/scripts/validate.mjs","plugin build":"skills/build-plugin/scripts/build.mjs","plugin init":"skills/init-universal-plugin/scripts/init.mjs","plugin version":"skills/version/scripts/version.mjs"}};
4
4
  import { spawnSync } from "node:child_process";
5
5
  //#region src/compile/scripts.ts
6
6
  /** The global the header assigns the script data to. Framework-neutral: a script's own code, or the
@@ -49,7 +49,7 @@ Copilot CLI's search order is `.plugin/plugin.json` → `plugin.json` → `.gith
49
49
 
50
50
  Removing a vendor is a manifest edit first and a deletion second — deleting only the file leaves the
51
51
  vendor declared, and the next build writes it straight back. That edit belongs to
52
- `/universal-plugin:init-universal-plugin`'s update route; come back here for the file.
52
+ `/universal-plugin:init-universal-plugin` (pnpm install: `pnpm-universal-plugin-init-universal-plugin`)'s update route; come back here for the file.
53
53
 
54
54
  ## Remove the whole plugin
55
55
 
@@ -74,7 +74,7 @@ node scripts/version.mjs --from-package
74
74
  ```
75
75
 
76
76
  Resolve that path against this skill's own directory; it runs the project's installed CLI
77
- (`pnpm exec universal-plugin`), else `npx universal-plugin@0.13.0` pinned to this skill's version.
77
+ (`pnpm exec universal-plugin`), else `npx universal-plugin@0.14.0` pinned to this skill's version.
78
78
  `universal-plugin plugin version` on the `PATH` is the fallback. The command never prompts, so it is safe to run unattended once the
79
79
  source is decided.
80
80
 
@@ -123,7 +123,7 @@ Every guard resolves before the first write, so a failed run leaves the tree unt
123
123
 
124
124
  | Message names | What it means | Do this |
125
125
  |---|---|---|
126
- | a missing `plugin.json` | not at a plugin root, or the plugin was never scaffolded | `cd` to the plugin root, or run `/universal-plugin:init-universal-plugin` |
126
+ | a missing `plugin.json` | not at a plugin root, or the plugin was never scaffolded | `cd` to the plugin root, or run `/universal-plugin:init-universal-plugin` (pnpm install: `pnpm-universal-plugin-init-universal-plugin`) |
127
127
  | no version to bump from | the manifest has never carried a `version` | pass an explicit version (`plugin version 0.1.0`) to set the first one |
128
128
  | an unknown version or release type | the argument is neither a release type nor valid semver | use one of the values in the table above |
129
129
  | a target that does not advance | the requested version is not greater than the current one | pick a higher version, or pass `--force` if the user genuinely wants to move backward |
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  // Compiled by `universal-plugin plugin build` from src/skill-scripts/run-cli.ts. Edit the source, not this file.
3
- globalThis.__SKILL_SCRIPT__ = {"package":"universal-plugin","bin":"universal-plugin","version":"0.13.0","entry":"skills/version/scripts/version.mjs","commands":{"marketplace add":"skills/marketplace/scripts/add.mjs","marketplace init":"skills/marketplace/scripts/marketplace.mjs","marketplace validate":"skills/marketplace/scripts/validate.mjs","plugin build":"skills/build-plugin/scripts/build.mjs","plugin init":"skills/init-universal-plugin/scripts/init.mjs","plugin version":"skills/version/scripts/version.mjs"}};
3
+ globalThis.__SKILL_SCRIPT__ = {"package":"universal-plugin","bin":"universal-plugin","version":"0.14.0","entry":"skills/version/scripts/version.mjs","commands":{"marketplace add":"skills/marketplace/scripts/add.mjs","marketplace init":"skills/marketplace/scripts/marketplace.mjs","marketplace validate":"skills/marketplace/scripts/validate.mjs","plugin build":"skills/build-plugin/scripts/build.mjs","plugin init":"skills/init-universal-plugin/scripts/init.mjs","plugin version":"skills/version/scripts/version.mjs"}};
4
4
  import { spawnSync } from "node:child_process";
5
5
  //#region src/compile/scripts.ts
6
6
  /** The global the header assigns the script data to. Framework-neutral: a script's own code, or the