universal-plugin 0.11.3 → 0.12.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.11.3",
3
+ "version": "0.12.0",
4
4
  "description": "Universal AI agent plugin build tool",
5
5
  "keywords": [
6
6
  "agent-plugin",
@@ -42,7 +42,7 @@
42
42
  "@cyberuni/agent-harness": "^0.3.0",
43
43
  "@repobuddy/upx": "^0.2.0",
44
44
  "@toon-format/toon": "^4.1.1",
45
- "commander": "^14.0.3",
45
+ "commander": "^15.0.0",
46
46
  "semver": "^7.8.1"
47
47
  },
48
48
  "devDependencies": {
@@ -53,7 +53,7 @@
53
53
  "tsdown": "^0.23.0",
54
54
  "tsx": "^4.22.3",
55
55
  "typescript": "^6.0.0",
56
- "vitest": "^4.1.7"
56
+ "vitest": "^5.0.0"
57
57
  },
58
58
  "engines": {
59
59
  "node": ">=22"
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.11.3",
4
+ "version": "0.12.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"
@@ -56,6 +56,7 @@ The command never prompts, so it is safe to run unattended.
56
56
  | `--dry-run` | Validate and report the plan, write nothing. Run this first when unsure what will change |
57
57
  | `--vendor <id>` | Build one vendor (`claude-code`, `cursor`, `codex`, `copilot-cli`), and refresh only its catalog |
58
58
  | `--verbose` | Print each field-level decision the derivation made |
59
+ | `--strict-dependencies` | Fail when a refreshed catalog cannot resolve a declared dependency. Use in CI |
59
60
  | `--format json` | The same result as JSON, for scripts |
60
61
 
61
62
  `--clean` also exists. It deletes derived manifests before rewriting them, so reach for it only
@@ -76,9 +77,14 @@ A catalog row reads `updated`, `unchanged`, or `planned` on `--dry-run`. A build
76
77
  catalog, and it keeps an entry's non-local source, such as an npm package, while it re-derives the
77
78
  version. To add a catalog or change a source, use `marketplace`.
78
79
 
80
+ The build also checks each declared dependency against the catalogs it refreshes. A bare dependency
81
+ the catalog does not list warns: offer the user both fixes the warning names, listing it with
82
+ `marketplace add` or qualifying it with the marketplace that lists it. A dependency whose entry
83
+ declares a `source` is listed in the catalog by the build itself.
84
+
79
85
  Read stderr too. The build drops what a vendor cannot represent and warns instead of failing: a hook
80
86
  handler type a vendor cannot run, a `harnesses.copilot-cli` override with no delivery path, an
81
- invalid catalog. Each warning names something that will not reach a runtime. Tell the user each
87
+ invalid catalog, a dependency the catalog cannot resolve. Each warning names something that will not reach a runtime. Tell the user each
82
88
  one; do not bury it in a summary.
83
89
 
84
90
  `built 0` with "nothing to build" is not success. The manifest declares no vendor, so hand it to
@@ -22,6 +22,14 @@ Every check and every entry field in Steps 1–2 reads from the plugin location
22
22
  from the cwd by assumption. Getting this wrong means the marketplace entry ends up pointing at the
23
23
  marketplace repo's own URL instead of the plugin's.
24
24
 
25
+ ## A plugin's dependencies go with it
26
+
27
+ A plain dependency (no marketplace named) resolves against the marketplace the plugin is installed
28
+ from, so publishing a plugin whose plain dependency the catalog does not list publishes something
29
+ nobody can install. The skill lists such a dependency in the same PR, or stops and asks for it to be
30
+ published first. A dependency that names another marketplace only needs that marketplace in the
31
+ catalog's `allowCrossMarketplaceDependenciesOn`, which the skill offers to add.
32
+
25
33
  ## Why this is not the `marketplace` skill
26
34
 
27
35
  `marketplace` generates a repository's own local catalog — no submission, no shared listing, no PR.
@@ -19,7 +19,7 @@ Publishing has four steps:
19
19
 
20
20
  0. **Locate** — work out which repo is which, and where the plugin and the marketplace each live
21
21
  1. **Pre-flight** — validate the plugin is ready
22
- 2. **Prepare entries** — build the entry for each vendor marketplace file that exists
22
+ 2. **Prepare entries** — build the entry for each vendor marketplace file that exists, and resolve the plugin's dependencies against the target marketplace
23
23
  3. **Submit PR** — one PR that updates all relevant marketplace files
24
24
 
25
25
  Work through each step in order. Do not skip pre-flight even if the user says the plugin is ready.
@@ -211,7 +211,39 @@ If the plugin is already listed (this is an update), find its existing entry, up
211
211
 
212
212
  Show all prepared entries to the user and ask them to confirm before proceeding.
213
213
 
214
- ### 2f. Validate the catalogs
214
+ ### 2f. Resolve the plugin's dependencies
215
+
216
+ Claude Code installs a plugin only when every dependency it declares resolves, so a catalog that lists
217
+ the plugin but not what it depends on publishes a plugin nobody can install. Read the declaration
218
+ Claude Code receives, from the **plugin location**: `dependencies` in `.claude-plugin/plugin.json`
219
+ (the built manifest), or, if that has not been built, the canonical one —
220
+ `extensions["org.cyberuni.universal-plugin"].harnesses["claude-code"].dependencies`, else
221
+ `extensions["org.cyberuni.universal-plugin"].dependencies` in `plugin.json`. No declaration means
222
+ nothing to do here.
223
+
224
+ Each entry is a string (`<plugin>` or `<plugin>@<marketplace>`, optionally with an `@^range` tail) or
225
+ an object (`{ "name", "marketplace"?, "version"?, ... }`). Sort each one:
226
+
227
+ - **Plain** — a bare `<plugin>`, or an object with no `marketplace`. Claude Code resolves it against
228
+ the marketplace the plugin is installed from, which is this one. If the target catalog
229
+ (`.claude-plugin/marketplace.json`) already lists that name, it is resolved. Otherwise it must be
230
+ listed in this same PR: locate the dependency's own repository or package (an object's `source`
231
+ field, when present, says where it is distributed from; otherwise ask the user), run Step 1's
232
+ pre-flight against it, and prepare its entries exactly as 2b–2e do for the main plugin — then
233
+ resolve *its* plain dependencies the same way. If a plain dependency cannot be listed (no
234
+ repository or package to read, pre-flight fails, the user declines), **stop**: tell the user to
235
+ publish that dependency to this marketplace first, and do not open the PR.
236
+ - **Names a marketplace** — `<plugin>@<marketplace>`, or an object with `marketplace`. Not held to
237
+ this catalog's listing, even when the marketplace it names is this one; do not add an entry for
238
+ it. When the named marketplace is **not** this catalog's `name`, Claude Code refuses the
239
+ dependency at install unless this catalog's top-level `allowCrossMarketplaceDependenciesOn` lists
240
+ that marketplace. If it does not, tell the user that installs from this marketplace need it, and
241
+ offer to add the marketplace name to that array in the same PR.
242
+
243
+ Report how each dependency was sorted and what was done about it, and include the dependency entries
244
+ in what you show the user to confirm.
245
+
246
+ ### 2g. Validate the catalogs
215
247
 
216
248
  Before moving to Step 3, run the validator against the marketplace repo's working copy (the same
217
249
  checkout the entries were just written into):
@@ -221,7 +253,11 @@ npx universal-plugin marketplace validate --root .
221
253
  ```
222
254
 
223
255
  This is the same check `marketplace init`/`build` rely on — it catches an entry shape no runtime can
224
- load (a bad `source`, a missing required key) before it reaches a PR. Fix any reported issue and
256
+ load (a bad `source`, a missing required key) before it reaches a PR. In the Claude catalog it also
257
+ reports a plain dependency the catalog does not list and a dependency on a marketplace missing from
258
+ `allowCrossMarketplaceDependenciesOn`, as far as it can see them offline (an entry's own
259
+ `dependencies`, and plugins at `./` paths) — so it does not replace 2f for a plugin listed from npm
260
+ or git. Fix any reported issue and
225
261
  re-run before continuing. Do not open the PR while validation fails.
226
262
 
227
263
  ---
@@ -266,7 +302,7 @@ git checkout -b add-<plugin-name>
266
302
 
267
303
  ### 3c. Edit all detected marketplace files
268
304
 
269
- For each vendor marketplace file detected in Step 2a, append the plugin entry to its `plugins` array. Preserve formatting and all existing entries exactly. Stage all changed files together.
305
+ For each vendor marketplace file detected in Step 2a, append the plugin entry — and the entry of each dependency 2f listed — to its `plugins` array, and add any `allowCrossMarketplaceDependenciesOn` change the user accepted in 2f. Preserve formatting and all existing entries exactly. Stage all changed files together.
270
306
 
271
307
  ### 3d. Commit and push
272
308
 
@@ -319,6 +355,8 @@ gh pr create \
319
355
  - [ ] Semver version string
320
356
  - [ ] SPDX license identifier
321
357
  - [ ] Entry appended to each detected marketplace file
358
+ - [ ] Every plain dependency is listed in this marketplace (here or already)
359
+ - [ ] Every marketplace a dependency names is in `allowCrossMarketplaceDependenciesOn`, or noted as not needed
322
360
  EOF
323
361
  )"
324
362
  ```
@@ -337,7 +375,8 @@ Return the PR URL to the user when done.
337
375
  | Name conflict in marketplace | Check existing entries in each marketplace file first |
338
376
  | Plugin loads but skills missing | Add `skills` array to the Claude Code marketplace entry |
339
377
  | Entry installs nothing for a monorepo plugin | `source` was `url`/root-clone instead of `git-subdir` — redo 2b/2c with the plugin's actual repo-relative path |
340
- | `marketplace validate` fails after 2f | Fix the reported shape before opening the PR — do not open it while validation fails |
378
+ | Install fails resolving a dependency | 2f was skipped — list the plain dependency in this marketplace, or allow the named marketplace in `allowCrossMarketplaceDependenciesOn` |
379
+ | `marketplace validate` fails after 2g | Fix the reported shape before opening the PR — do not open it while validation fails |
341
380
  | Entry's `repository`/`source.url` points at the marketplace repo | Step 0 role detection was skipped or overridden wrongly — re-check which repo the cwd is |
342
381
 
343
382
  ---
@@ -30,6 +30,12 @@
30
30
  "prompt": "I'm a maintainer of cyberuni/marketplace and I already have it checked out here. I want to add a plugin called 'db-migrate' that lives at github.com/someuser/db-migrate. Add it.",
31
31
  "expected_output": "Detects the cwd is the marketplace repo itself, not the plugin, so it reads the plugin's metadata from the given URL (cloning it to a scratch location) instead of the cwd, then works directly in the existing checkout (fetch/merge, branch, edit, commit, push, PR) rather than cloning or forking cyberuni/marketplace again. The prepared entry's source/repository URL points at db-migrate's repo, not at cyberuni/marketplace.",
32
32
  "files": []
33
+ },
34
+ {
35
+ "id": 6,
36
+ "prompt": "Publish buddy-agent-harness (in ~/code/buddy-agent-harness) to the cyberplace marketplace. Its plugin.json declares dependencies [\"agent-harness\", { \"name\": \"cyber-asana\", \"marketplace\": \"cyberuni\" }]. cyberplace's .claude-plugin/marketplace.json does not list agent-harness and has no allowCrossMarketplaceDependenciesOn.",
37
+ "expected_output": "Reads the plugin's dependencies before submitting. Treats \"agent-harness\" as a plain dependency resolved against cyberplace: since cyberplace does not list it, prepares agent-harness's entry in the same PR from its own repository/package (after pre-flight), or stops and tells the user to publish agent-harness first — never opens a PR listing buddy-agent-harness without it. Treats cyber-asana@cyberuni as a named-marketplace dependency: adds no entry for it, says installs from cyberplace need \"cyberuni\" in allowCrossMarketplaceDependenciesOn, and offers to add it.",
38
+ "files": []
33
39
  }
34
40
  ]
35
41
  }