universal-plugin 0.16.3 → 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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "universal-plugin",
3
- "version": "0.16.3",
3
+ "version": "0.17.0",
4
4
  "description": "Universal AI agent plugin build tool",
5
5
  "keywords": [
6
6
  "agent-plugin",
@@ -41,17 +41,17 @@
41
41
  ],
42
42
  "dependencies": {
43
43
  "@repobuddy/upx": "^0.2.0",
44
- "@toon-format/toon": "^4.1.1",
45
- "commander": "^15.0.0",
46
- "cyber-agentkit": "^1.0.0",
47
- "rolldown": "^1.2.11",
48
- "semver": "^7.8.1"
44
+ "rolldown": "^1.2.11"
49
45
  },
50
46
  "devDependencies": {
47
+ "@toon-format/toon": "^4.1.1",
51
48
  "@types/node": "^24.10.1",
52
49
  "@types/semver": "^7.7.1",
53
50
  "ajv": "^8.20.0",
51
+ "commander": "^15.0.0",
52
+ "cyber-agentkit": "^2.0.0",
54
53
  "knip": "^6.14.1",
54
+ "semver": "^7.8.1",
55
55
  "tsdown": "^0.23.0",
56
56
  "tsx": "^4.22.3",
57
57
  "typescript": "^6.0.0",
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.16.3",
4
+ "version": "0.17.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"
@@ -44,6 +44,10 @@
44
44
  "source": "src/skill-scripts/run-cli.ts",
45
45
  "command": "marketplace init"
46
46
  },
47
+ "skills/marketplace/scripts/update.mjs": {
48
+ "source": "src/skill-scripts/run-cli.ts",
49
+ "command": "marketplace update"
50
+ },
47
51
  "skills/marketplace/scripts/validate.mjs": {
48
52
  "source": "src/skill-scripts/run-cli.ts",
49
53
  "command": "marketplace validate"
package/readme.md CHANGED
@@ -110,7 +110,7 @@ TOON by default; pass `--format json` for JSON.
110
110
  ### Reference documents
111
111
 
112
112
  This package ships its own documents (`plugin-design`, `slash-invocation`, `universal-plugin`) under
113
- `references/`. Read one with `npx cyber-agentkit reference show <name>` in any
113
+ `references/`. Read one with `npx cyber-agentkit reference load <name>` in any
114
114
  project that depends on `universal-plugin`, or, from a skill, with the `reference` skill in the
115
115
  `cyber-agentkit` plugin.
116
116
 
@@ -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.16.3","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.17.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 update":"skills/marketplace/scripts/update.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
@@ -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.16.3`), 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.17.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.16.3","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.17.0","entry":"skills/build-plugin/scripts/build.mjs","commands":{"marketplace add":"skills/marketplace/scripts/add.mjs","marketplace init":"skills/marketplace/scripts/marketplace.mjs","marketplace update":"skills/marketplace/scripts/update.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
@@ -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.16.3`, pinned. This check matters most where the release tool picks the
175
+ `npx universal-plugin@0.17.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
@@ -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.16.3","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.17.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 update":"skills/marketplace/scripts/update.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.16.3`. Add `--npm` when an npm package ships the plugin,
46
+ the pinned `npx universal-plugin@0.17.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).
@@ -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.16.3","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.17.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 update":"skills/marketplace/scripts/update.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
@@ -3,7 +3,7 @@
3
3
  Run a repository's own plugin marketplace: generate the catalogs the runtimes read, list plugins
4
4
  that live elsewhere, and check that what is on disk is what each runtime will load.
5
5
 
6
- ## A gateway over three routes
6
+ ## A gateway over four routes
7
7
 
8
8
  `SKILL.md` holds no procedure. It classifies the request and loads one reference:
9
9
 
@@ -11,7 +11,8 @@ that live elsewhere, and check that what is on disk is what each runtime will lo
11
11
  | --- | --- | --- |
12
12
  | `init` | The repository holds the plugins. Derive a catalog from `plugins/`, then offer the README install section. | `references/init.md` |
13
13
  | `add` | The plugin lives elsewhere — an npm package, a GitHub repo, or `<plugin>@<marketplace>`. | `references/add.md` |
14
- | `validate` | Check the catalogs against the schema each runtime loads. Both other routes end here. | `references/validate.md` |
14
+ | `update` | An entry is already listed. Change its source, a pin, or one field, and keep the rest. | `references/update.md` |
15
+ | `validate` | Check the catalogs against the schema each runtime loads. Every other route ends here. | `references/validate.md` |
15
16
 
16
17
  The split exists because the two writing routes answer different questions and share almost no
17
18
  steps. A single document had to hedge every instruction with "unless the plugin is not in this
@@ -22,6 +23,11 @@ discovery could never have produced them — and keeps a non-local source on a p
22
23
  discover, so a plugin shipped through npm is not rewritten to a repository path holding gitignored
23
24
  build output.
24
25
 
26
+ `update` exists because the other writing routes cannot change one entry safely. `add --force`
27
+ replaces the entry with what `add` derives and drops what it cannot, such as `category` and
28
+ `author`, and the skill forbids patching a catalog by hand. `update` changes only the fields it is
29
+ given and validates every catalog before it writes.
30
+
25
31
  ## Support is uneven, and the skill says so
26
32
 
27
33
  | Runtime | Reality |
@@ -62,5 +68,6 @@ document.
62
68
  - [Research: local marketplaces](https://github.com/cyberuni/universal-plugin/blob/main/.research/local-marketplaces/conclusion.md)
63
69
  - [`marketplace add` spec](https://github.com/cyberuni/universal-plugin/blob/main/packages/universal-plugin/.agents/spec/marketplace/add/README.md)
64
70
  - [`marketplace init` spec](https://github.com/cyberuni/universal-plugin/blob/main/packages/universal-plugin/.agents/spec/marketplace/init/README.md)
71
+ - [`marketplace update` spec](https://github.com/cyberuni/universal-plugin/blob/main/packages/universal-plugin/.agents/spec/marketplace/update/README.md)
65
72
  - [`marketplace validate` spec](https://github.com/cyberuni/universal-plugin/blob/main/packages/universal-plugin/.agents/spec/marketplace/validate/README.md)
66
73
  - [Official Claude Code marketplace schema](https://json.schemastore.org/claude-code-marketplace.json)
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: marketplace
3
- description: Use this skill to run a repository's own plugin marketplace — generate the catalogs Claude Code, Codex, GitHub Copilot CLI, and Cursor read, list a plugin that lives elsewhere (an npm package, a GitHub repo, or `<plugin>@<marketplace>`), check every catalog against the schema its runtime loads, and write the README install section. Trigger on "set up a local marketplace", "let users install this from my repo", "generate marketplace catalogs", "add a plugin to the marketplace", "list this npm package in my marketplace", "make this repo installable", "add install instructions to the README", or "check my marketplace catalogs".
4
- argument-hint: '[init|add|validate] [--claude] [--codex] [--copilot] [--cursor] [--dry-run] [--force]'
3
+ description: Use this skill to run a repository's own plugin marketplace — generate the catalogs Claude Code, Codex, GitHub Copilot CLI, and Cursor read, list a plugin that lives elsewhere (an npm package, a GitHub repo, or `<plugin>@<marketplace>`), change one listed entry in place, check every catalog against the schema its runtime loads, and write the README install section. Trigger on "set up a local marketplace", "let users install this from my repo", "generate marketplace catalogs", "add a plugin to the marketplace", "list this npm package in my marketplace", "switch this entry to a url source", "bump the ref on this entry", "change the category of a marketplace entry", "make this repo installable", "add install instructions to the README", or "check my marketplace catalogs".
4
+ argument-hint: '[init|add|update|validate] [--claude] [--codex] [--copilot] [--cursor] [--dry-run] [--force]'
5
5
  ---
6
6
 
7
7
  # marketplace
@@ -18,23 +18,26 @@ route names. Read only the one you need.
18
18
  | --- | --- | --- |
19
19
  | `init` | The repository **holds** the plugins. Derive a catalog from what is on disk, then offer the README install section. | `references/init.md` |
20
20
  | `add` | The plugin **lives elsewhere** — an npm package, a GitHub repository, or an entry another marketplace already publishes. | `references/add.md` |
21
+ | `update` | An entry is **already listed** and needs a new source, a moved pin, or one field changed. Keeps every other field. | `references/update.md` |
21
22
  | `validate` | Check the catalogs the repository already carries against the schema each runtime loads. | `references/validate.md` |
22
23
 
23
24
  `init` and `add` are not alternatives. One repository can be both a plugin's home and a curated
24
25
  list, and the two commands compose: a regeneration keeps the entries `add` wrote, because discovery
25
26
  could never have produced them.
26
27
 
27
- Both routes end in `validate`. A catalog the runtime rejects is worse than no catalog — it is found,
28
+ All three writing routes end in `validate`. A catalog the runtime rejects is worse than no catalog — it is found,
28
29
  read, and refused at install time, in someone else's terminal.
29
30
 
30
31
  ## Intake
31
32
 
32
33
  **Name the route and go.** "Set up a local marketplace", "make this repo installable", "generate the
33
- catalogs" → `init`. "Add repobuddy to the marketplace", "list this npm package" → `add`. "Check the
34
- catalogs" → `validate`. Load that reference and follow it; do not ask.
34
+ catalogs" → `init`. "Add repobuddy to the marketplace", "list this npm package" → `add`. "Switch
35
+ aced to a url source", "bump the ref", "change its category" → `update`. "Check the catalogs" →
36
+ `validate`. Load that reference and follow it; do not ask.
35
37
 
36
38
  **Ask only when the invocation is bare.** One question: does the repository hold the plugins it is
37
- listing, or is it listing plugins that live somewhere else? Offer `init`, `add`, and `validate`.
39
+ listing, or is it listing plugins that live somewhere else? Offer `init`, `add`, `update`, and
40
+ `validate`.
38
41
 
39
42
  Discovery settles the question faster than the user can:
40
43
 
@@ -44,7 +47,7 @@ ls .claude-plugin/marketplace.json .agents/plugins/marketplace.json 2>/dev/null
44
47
  ```
45
48
 
46
49
  Plugins under `plugins/` and no catalog yet is `init`. A catalog already there and nothing new on
47
- disk is usually `add`.
50
+ disk is usually `add`, or `update` when the user names an entry the catalog already lists.
48
51
 
49
52
  ## Where each runtime looks
50
53
 
@@ -69,7 +72,8 @@ their own catalog before the Claude one, which shields them. State per runtime w
69
72
  is worse than no install section, and that file is the only source of them. Widely-copied README
70
73
  snippets are not sources. The trap that lives there: Codex installs with `plugin add` where
71
74
  Copilot CLI uses `plugin install`.
72
- - **Never hand-author or hand-patch a catalog.** Generate it, then validate it. A catalog written by
75
+ - **Never hand-author or hand-patch a catalog.** Generate it, then validate it. To change an entry
76
+ that is already listed, use `update`, not `add --force`, which drops the fields it cannot derive. A catalog written by
73
77
  copying fields out of `package.json` carries `owner` as a string and `repository` as an object,
74
78
  and Claude Code refuses it for either one.
75
79
  - **Name every catalog `marketplace.json`.** Codex discovers a catalog by that filename inside a
@@ -81,8 +85,8 @@ their own catalog before the Claude one, which shields them. State per runtime w
81
85
  have published will not understand why nobody can install.
82
86
  - **Ask before editing the README**, and before `--force` replaces anything a user may have written
83
87
  by hand.
84
- - Listing a plugin in the shared `cyberuni/cyberplace` repository is a different job: use
85
- `publish-plugin`.
88
+ - Listing a plugin in the shared `cyberuni/cyberplace` repository, or changing its entry there, is a
89
+ different job: use `publish-plugin`.
86
90
 
87
91
  ## Related skills
88
92
 
@@ -97,6 +101,7 @@ their own catalog before the Claude one, which shields them. State per runtime w
97
101
 
98
102
  - `references/init.md` — derive the catalogs from the plugins this repository holds
99
103
  - `references/add.md` — list a plugin that lives elsewhere
104
+ - `references/update.md` — change one listed entry in place
100
105
  - `references/validate.md` — check the catalogs against the schema each runtime loads
101
106
  - `references/runtimes.md` — per-runtime install commands and their sources
102
107
  - [Research conclusion](https://github.com/cyberuni/universal-plugin/blob/main/.research/local-marketplaces/conclusion.md)
@@ -107,7 +107,9 @@ fallback. Run `--dry-run` first and show the plan, including the skips. The comm
107
107
  | `skipped` | that runtime cannot resolve this source; the reason says which |
108
108
 
109
109
  An entry already listed **differently** stops the run and asks for `--force`. Read what would change
110
- before passing it: someone wrote that entry, and `--force` is what discards their version.
110
+ before passing it: someone wrote that entry, and `--force` is what discards their version. To change
111
+ a listed entry rather than replace it, use `update` (`references/update.md`), which keeps every field
112
+ it is not asked about.
111
113
 
112
114
  The catalog is created if the repository has none, named and owned the same way `init` names it —
113
115
  from the root `plugin.json` author, with `--marketplace-name` and `--owner` to override. A
@@ -0,0 +1,75 @@
1
+ # Route: update
2
+
3
+ Change one entry the catalogs already list, and keep everything else about it. This is the route
4
+ for an entry that is listed and wrong or stale: a new source, a moved pin, one field.
5
+
6
+ `add --force` is not a substitute. It replaces the entry with what `add` can derive, so it needs
7
+ `--owner` and the other `add` inputs again, and it drops what it cannot derive: `category`,
8
+ `author`, any field a curator wrote by hand. Use `update` whenever the entry already exists.
9
+
10
+ An entry that is not listed yet is `add`'s (`references/add.md`). A plugin this repository holds is
11
+ re-derived by `init` or `plugin build`; reach for `update` there only for a field neither derives,
12
+ such as `category`.
13
+
14
+ ## 1. Work out the change
15
+
16
+ Name the entry by the name the catalogs list it under, then say what changes:
17
+
18
+ | The user wants | Flags |
19
+ | --- | --- |
20
+ | Move the entry to another source, such as the `github` shorthand to an https `url` | `--source <spec>` |
21
+ | Bump or change a pin | `--ref <branch-or-tag>`, `--sha <commit>` |
22
+ | Change one field | `--description`, `--version`, `--homepage`, `--repository`, `--license`, `--keywords`, `--category` |
23
+ | Remove a field or a pin | `--unset <field>`, repeatable; `--unset ref`, `--unset sha` |
24
+
25
+ `--source` is read exactly the way `add` reads its spec, so the same collisions apply: write
26
+ `./plugins/alpha` or pass `--path` for a directory, and `--npm`, `--github`, `--url`, and `--subdir`
27
+ shape it the same way. A `<plugin>@<marketplace>` spec is refused; copying an entry is `add`'s job.
28
+
29
+ Two pin rules to state to the user before running:
30
+
31
+ - **A new git source keeps the old pin** unless `--ref` or `--sha` comes with it. Switching how a
32
+ repository is reached does not move which commit installs.
33
+ - **`--ref` alone keeps an existing `sha`.** A sha pinned for the old ref then names a commit the
34
+ new one has moved past. When bumping a ref, pass `--unset sha` too, or pass the new `--sha`.
35
+
36
+ ## 2. Preview, then write
37
+
38
+ ```bash
39
+ node scripts/update.mjs repobuddy --source https://github.com/cyberuni/repobuddy.git --dry-run
40
+ ```
41
+
42
+ Resolve that path against this skill's own directory; `npx universal-plugin marketplace update` is
43
+ the fallback. Run `--dry-run` first and show the plan. The command never prompts.
44
+
45
+ | Status | Means |
46
+ | --- | --- |
47
+ | `updated` | the entry changed |
48
+ | `unchanged` | already says exactly this |
49
+ | `planned` | `--dry-run` only |
50
+ | `skipped` | that catalog is missing, does not list the entry, or its runtime cannot install the new source; the reason says which |
51
+
52
+ With no target flags all four catalogs are selected, so a `skipped` row for a catalog that never
53
+ listed the entry is normal. Report every skip with its reason anyway. Two deserve a sentence each:
54
+
55
+ - **A runtime that cannot install the new source keeps its old entry.** Moving an entry to `npm`
56
+ leaves Copilot CLI and Cursor on the source they had. Say so; the user may want those entries
57
+ removed, which is a hand decision this skill does not make.
58
+ - **A shield catalog may appear.** Copilot CLI and Cursor read the Claude catalog when they have none
59
+ of their own. If the new source would break them there, their own catalog is written without the
60
+ entry, as `add` does. Tell the user the file appeared and why.
61
+
62
+ The Codex catalog takes only `version` and `category` of the field flags, because that is all its
63
+ entries carry. A description changed everywhere else is not missing from Codex by mistake.
64
+
65
+ ## 3. Validate
66
+
67
+ The command checks every catalog it plans to write, with the same checks as `validate`, before it
68
+ writes anything. An update that would introduce an issue stops and writes nothing; fix the input and
69
+ rerun. An issue the catalogs already had does not stop it.
70
+
71
+ So the write is safe, but the repository may still carry older issues. Follow
72
+ `references/validate.md` and report its result, not just the update's.
73
+
74
+ Then state plainly that nothing was published: the change sits in the repository until it is pushed
75
+ and a user refreshes the marketplace.
@@ -35,7 +35,7 @@ the fix is to run `init` or `add` so the runtime gets a catalog of its own.
35
35
 
36
36
  Fix an issue in the source it comes from, then regenerate. An entry's fields are derived, so an
37
37
  npm-style `repository` object belongs fixed in the plugin's `plugin.json` (for a discovered plugin)
38
- or passed as `--repository <url>` (for an added one).
38
+ or set with `update <name> --repository <url>` (for an added one, `references/update.md`).
39
39
 
40
40
  The top-level `name` and `owner` live in the catalog itself, and `owner` must be an object —
41
41
  `{ "name": "…" }`, never the `"Name <email>"` string `package.json` uses.
@@ -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.16.3","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.17.0","entry":"skills/marketplace/scripts/add.mjs","commands":{"marketplace add":"skills/marketplace/scripts/add.mjs","marketplace init":"skills/marketplace/scripts/marketplace.mjs","marketplace update":"skills/marketplace/scripts/update.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.16.3","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.17.0","entry":"skills/marketplace/scripts/install-docs.mjs","commands":{"marketplace add":"skills/marketplace/scripts/add.mjs","marketplace init":"skills/marketplace/scripts/marketplace.mjs","marketplace update":"skills/marketplace/scripts/update.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.16.3","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.17.0","entry":"skills/marketplace/scripts/marketplace.mjs","commands":{"marketplace add":"skills/marketplace/scripts/add.mjs","marketplace init":"skills/marketplace/scripts/marketplace.mjs","marketplace update":"skills/marketplace/scripts/update.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
@@ -0,0 +1,52 @@
1
+ #!/usr/bin/env node
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.17.0","entry":"skills/marketplace/scripts/update.mjs","commands":{"marketplace add":"skills/marketplace/scripts/add.mjs","marketplace init":"skills/marketplace/scripts/marketplace.mjs","marketplace update":"skills/marketplace/scripts/update.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
+ import { spawnSync } from "node:child_process";
5
+ //#region src/compile/scripts.ts
6
+ /** The global the header assigns the script data to. Framework-neutral: a script's own code, or the
7
+ * library it inlines, reads it; universal-plugin depends on neither. */
8
+ const SCRIPT_GLOBAL = "__SKILL_SCRIPT__";
9
+ //#endregion
10
+ //#region src/skill-scripts/cli-runner.ts
11
+ /** The data `plugin build` embedded in this compiled script. */
12
+ function skillScript() {
13
+ const data = globalThis[SCRIPT_GLOBAL];
14
+ if (data === void 0) throw new Error("this script runs only as compiled by `plugin build`");
15
+ return data;
16
+ }
17
+ /** Runs the universal-plugin CLI. A skill may be copied away from its package, so it never reaches
18
+ * for a CLI beside it: the project's installed CLI first, then the one pinned to this script's
19
+ * version, which `plugin version` stamps. */
20
+ function runCli(args, options = {}) {
21
+ const { bin, package: pkg, version } = skillScript();
22
+ const name = bin ?? "universal-plugin";
23
+ if (spawnSync("pnpm", [
24
+ "exec",
25
+ name,
26
+ "--version"
27
+ ], { encoding: "utf8" }).status === 0) return spawnSync("pnpm", [
28
+ "exec",
29
+ name,
30
+ ...args
31
+ ], {
32
+ encoding: "utf8",
33
+ ...options
34
+ });
35
+ const pinned = `${pkg ?? "universal-plugin"}@${version ?? "latest"}`;
36
+ return spawnSync("npx", [pinned, ...args], {
37
+ encoding: "utf8",
38
+ ...options
39
+ });
40
+ }
41
+ //#endregion
42
+ //#region src/skill-scripts/run-cli.ts
43
+ const script = skillScript();
44
+ const command = Object.entries(script.commands).find(([, entry]) => entry === script.entry)?.[0];
45
+ if (command === void 0) {
46
+ process.stderr.write(`${script.entry} declares no command in the scripts map\n`);
47
+ process.exit(1);
48
+ }
49
+ const result = runCli([...command.split(" "), ...process.argv.slice(2)], { stdio: "inherit" });
50
+ process.exit(result.status ?? 1);
51
+ //#endregion
52
+ export {};
@@ -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.16.3","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.17.0","entry":"skills/marketplace/scripts/validate.mjs","commands":{"marketplace add":"skills/marketplace/scripts/add.mjs","marketplace init":"skills/marketplace/scripts/marketplace.mjs","marketplace update":"skills/marketplace/scripts/update.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
@@ -239,6 +239,14 @@ The `source` field supports the same shapes as Claude Code (`url`, `github`, `gi
239
239
 
240
240
  If the plugin is already listed (this is an update), find its existing entry, update changed fields, and preserve any curator-added fields not in the standard shape. Do not overwrite `publishedAt` if present — add `"updatedAt": "<today>"` instead.
241
241
 
242
+ For a change `marketplace update` covers (a new source, a moved `ref` or `sha` pin, or a field such as `description`, `version`, or `category`), run it in the marketplace checkout rather than editing the catalogs by hand. It keeps every field it is not given, curator fields included, and validates each catalog before writing:
243
+
244
+ ```bash
245
+ npx universal-plugin marketplace update <plugin-name> --source <spec> --dry-run --root .
246
+ ```
247
+
248
+ Drop `--dry-run` once the plan reads right. `updatedAt` and any other field it has no flag for are still set by hand.
249
+
242
250
  Show all prepared entries to the user and ask them to confirm before proceeding.
243
251
 
244
252
  ### 2f. Resolve the plugin's dependencies
@@ -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.16.3` pinned to this skill's version.
77
+ (`pnpm exec universal-plugin`), else `npx universal-plugin@0.17.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
 
@@ -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.16.3","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.17.0","entry":"skills/version/scripts/version.mjs","commands":{"marketplace add":"skills/marketplace/scripts/add.mjs","marketplace init":"skills/marketplace/scripts/marketplace.mjs","marketplace update":"skills/marketplace/scripts/update.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