universal-plugin 0.13.0 → 0.14.1

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.13.0",
3
+ "version": "0.14.1",
4
4
  "description": "Universal AI agent plugin build tool",
5
5
  "keywords": [
6
6
  "agent-plugin",
@@ -39,7 +39,7 @@
39
39
  "agents"
40
40
  ],
41
41
  "dependencies": {
42
- "@cyberuni/agent-harness": "^0.6.0",
42
+ "@cyberuni/agent-harness": "^0.7.0",
43
43
  "@repobuddy/upx": "^0.2.0",
44
44
  "@toon-format/toon": "^4.1.1",
45
45
  "commander": "^15.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.13.0",
4
+ "version": "0.14.1",
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.1","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.1`), 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.1","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
@@ -23,7 +23,7 @@ Resolve that path against this skill's own directory. It asks the project's inst
23
23
  (`pnpm exec universal-plugin`), else the CLI pinned to this skill's version (`npx`), about the
24
24
  current working directory; add `--root <path>` to diagnose elsewhere.
25
25
  Add `--marketplace-root <path>` (repeatable) to also check a **separately-cloned** shared marketplace
26
- repository (e.g. a local clone of `cyberuni/marketplace`) — see
26
+ repository (e.g. a local clone of `cyberuni/cyberplace`) — see
27
27
  [Catalogs are checked at the repository root](#catalogs-are-checked-at-the-repository-root).
28
28
  It never prompts and never writes, so it is safe to run unattended.
29
29
 
@@ -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,11 +105,11 @@ 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
 
112
- A **shared** marketplace repository (e.g. `cyberuni/marketplace`) is a repository of its own — a bad
112
+ A **shared** marketplace repository (e.g. `cyberuni/cyberplace`) is a repository of its own — a bad
113
113
  entry that reached it by another path (a hand-edited entry, a PR from a different tool, a curator
114
114
  edit) is invisible to a `doctor` run inside any plugin's own repo, because that run never sees the
115
115
  shared repository at all. Clone it separately and name the clone explicitly:
@@ -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.1`, 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.1","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.1`. 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.1","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
@@ -77,7 +77,7 @@ Copilot CLI. The reverse does not hold: Claude Code rejects the Codex catalog fo
77
77
  have published will not understand why nobody can install.
78
78
  - **Ask before editing the README**, and before `--force` replaces anything a user may have written
79
79
  by hand.
80
- - Listing a plugin in the shared `cyberuni/marketplace` repository is a different job: use
80
+ - Listing a plugin in the shared `cyberuni/cyberplace` repository is a different job: use
81
81
  `publish-plugin`.
82
82
 
83
83
  ## Related skills
@@ -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.1","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.1","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.1","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.1","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
@@ -12,7 +12,7 @@ for each vendor catalog that exists, then open one PR that updates all of them t
12
12
 
13
13
  The plugin being published and the marketplace it is going into are different repos, and the current
14
14
  working directory could be either. The skill checks the cwd's remote against the target marketplace
15
- repo (`cyberuni/marketplace` by default) before doing anything else:
15
+ repo (`cyberuni/cyberplace` by default) before doing anything else:
16
16
 
17
17
  - cwd is the plugin → the marketplace repo gets cloned or forked, as it always did.
18
18
  - cwd is already the marketplace → work happens in place; the plugin's metadata is read from wherever
@@ -30,6 +30,14 @@ nobody can install. The skill lists such a dependency in the same PR, or stops a
30
30
  published first. A dependency that names another marketplace only needs that marketplace in the
31
31
  catalog's `allowCrossMarketplaceDependenciesOn`, which the skill offers to add.
32
32
 
33
+ ## Some marketplaces take no pull requests
34
+
35
+ A curated directory, such as `anthropics/claude-plugins-official`, closes pull requests from
36
+ outsiders and takes new plugins through a form. When the user has only read access to the target,
37
+ the skill reads its workflows and Contributing section live, and, if it is curated, drafts the entry
38
+ in the catalog's own shape and hands over the submission link instead of opening a PR. It checks
39
+ each time rather than storing the catalog's rules, because those rules change.
40
+
33
41
  ## Why this is not the `marketplace` skill
34
42
 
35
43
  `marketplace` generates a repository's own local catalog — no submission, no shared listing, no PR.
@@ -5,9 +5,9 @@ description: Use this skill whenever the user wants to publish, release, submit,
5
5
 
6
6
  # Publish Universal Plugin
7
7
 
8
- Guides adding an already-packaged plugin to a marketplace repo by opening a pull request. Each vendor runtime may have its own marketplace manifest file inside the marketplace repo — update every one that exists.
8
+ Guides adding an already-packaged plugin to a marketplace repo by opening a pull request, or, for a curated marketplace that takes no pull requests, by drafting the submission. Each vendor runtime may have its own marketplace manifest file inside the marketplace repo — update every one that exists.
9
9
 
10
- **Default marketplace repo:** `cyberuni/marketplace` (adjust if the user targets a different one)
10
+ **Default marketplace repo:** `cyberuni/cyberplace` (adjust if the user targets a different one)
11
11
 
12
12
  Listing a plugin in a shared repository is not the only way to distribute it. A repository can carry
13
13
  its own catalog and let users add it directly as a marketplace. That is the `marketplace` skill; the
@@ -17,7 +17,7 @@ two compose, and neither replaces the other.
17
17
 
18
18
  Publishing has four steps:
19
19
 
20
- 0. **Locate** — work out which repo is which, and where the plugin and the marketplace each live
20
+ 0. **Locate** — work out which repo is which, where the plugin and the marketplace each live, and whether the marketplace takes PRs at all
21
21
  1. **Pre-flight** — validate the plugin is ready
22
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
@@ -34,7 +34,7 @@ is the common case.
34
34
 
35
35
  ### 0a. Identify the marketplace repo
36
36
 
37
- Default to `cyberuni/marketplace` unless the user names another one.
37
+ Default to `cyberuni/cyberplace` unless the user names another one.
38
38
 
39
39
  ### 0b. Identify which repo the cwd is
40
40
 
@@ -63,6 +63,36 @@ the user:
63
63
  Every pre-flight check and entry field in Steps 1–2 reads from the plugin location, not the cwd.
64
64
  Step 3 branches on whether the marketplace location is already the cwd.
65
65
 
66
+ ### 0c. Check how the marketplace takes submissions
67
+
68
+ Some marketplaces are curated directories that do not take plugins by pull request, for example
69
+ `anthropics/claude-plugins-official`. Check the target live every time; do not rely on what you
70
+ remember about a catalog, because its rules change.
71
+
72
+ ```bash
73
+ gh repo view <marketplace-repo> --json viewerPermission -q .viewerPermission
74
+ ```
75
+
76
+ If the result is `READ` (no write access):
77
+
78
+ 1. List the target's `.github/workflows/` and read any workflow that closes pull requests from
79
+ outsiders. Note what it lets through, if anything.
80
+ 2. Read the README's Contributing section (or `CONTRIBUTING.md`) for the submission route.
81
+
82
+ If submission is form-only, or a workflow closes outside pull requests automatically, **do not open
83
+ a PR**. Switch to drafting the submission:
84
+
85
+ - Run Step 1's pre-flight as usual.
86
+ - Resolve dependencies (2f) against the target's **live** catalog, read from its default branch. A
87
+ plain dependency the catalog does not list cannot be added through a form, so tell the user it
88
+ will not resolve there.
89
+ - Write the entry in the shape the catalog's existing entries use, not the shape in 2c. For example,
90
+ when existing entries pin `git-subdir` sources with `ref` and `sha`, use the plugin's release tag
91
+ and that tag's commit.
92
+ - Hand the user the drafted entry and the submission link the target names. Skip Step 3.
93
+
94
+ Otherwise (write access, or a fork-and-PR route the target accepts), continue to Step 1.
95
+
66
96
  ---
67
97
 
68
98
  ## Step 1: Pre-flight validation
@@ -279,15 +309,15 @@ Otherwise, the marketplace repo is elsewhere and needs a working copy. If the us
279
309
  (org member), work directly:
280
310
 
281
311
  ```bash
282
- gh repo clone cyberuni/marketplace
283
- cd marketplace
312
+ gh repo clone cyberuni/cyberplace
313
+ cd cyberplace
284
314
  ```
285
315
 
286
316
  If a fork is needed:
287
317
 
288
318
  ```bash
289
- gh repo fork cyberuni/marketplace --clone --remote
290
- cd marketplace
319
+ gh repo fork cyberuni/cyberplace --clone --remote
320
+ cd cyberplace
291
321
  git fetch upstream && git merge upstream/main
292
322
  ```
293
323
 
@@ -316,7 +346,7 @@ git push origin add-<plugin-name>
316
346
 
317
347
  ```bash
318
348
  gh pr create \
319
- --repo cyberuni/marketplace \
349
+ --repo cyberuni/cyberplace \
320
350
  --title "Add <plugin-name> v<version>" \
321
351
  --body "$(cat <<'EOF'
322
352
  ## Plugin
@@ -377,6 +407,7 @@ Return the PR URL to the user when done.
377
407
  | 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 |
378
408
  | Install fails resolving a dependency | 2f was skipped — list the plain dependency in this marketplace, or allow the named marketplace in `allowCrossMarketplaceDependenciesOn` |
379
409
  | `marketplace validate` fails after 2g | Fix the reported shape before opening the PR — do not open it while validation fails |
410
+ | PR closed automatically as soon as it opened | The target is curated — redo 0c and use its submission route instead of a PR |
380
411
  | 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 |
381
412
 
382
413
  ---
@@ -21,14 +21,14 @@
21
21
  },
22
22
  {
23
23
  "id": 4,
24
- "prompt": "My plugin 'foo' lives at packages/foo/plugin.json inside a monorepo (the repo root only has a marketplace.json catalog, no plugin.json). Publish it to cyberuni/marketplace.",
24
+ "prompt": "My plugin 'foo' lives at packages/foo/plugin.json inside a monorepo (the repo root only has a marketplace.json catalog, no plugin.json). Publish it to cyberuni/cyberplace.",
25
25
  "expected_output": "Determines the plugin is not at the repo root and has no npm packagePath, so decides source type git-subdir rather than a root-clone url. Writes { \"source\": \"git-subdir\", \"url\": \"<clone-url>.git\", \"path\": \"packages/foo\" } in the marketplace entry. Runs marketplace validate against the marketplace working copy before opening the PR, and does not proceed if it fails.",
26
26
  "files": []
27
27
  },
28
28
  {
29
29
  "id": 5,
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
- "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.",
30
+ "prompt": "I'm a maintainer of cyberuni/cyberplace 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
+ "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/cyberplace again. The prepared entry's source/repository URL points at db-migrate's repo, not at cyberuni/cyberplace.",
32
32
  "files": []
33
33
  },
34
34
  {
@@ -36,6 +36,12 @@
36
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
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
38
  "files": []
39
+ },
40
+ {
41
+ "id": 7,
42
+ "prompt": "Publish cyber-asana (in ~/code/cyber-asana, a monorepo with the plugin at packages/cyber-asana, released as tag cyber-asana@1.2.0) to anthropics/claude-plugins-official. Its plugin.json declares the plain dependency \"cyber-agent-harness\".",
43
+ "expected_output": "Before preparing a PR, runs `gh repo view anthropics/claude-plugins-official --json viewerPermission`, sees READ, then reads the target's .github/workflows/ for a workflow that closes outside PRs and its README's Contributing section. Concludes the catalog is curated (outside PRs are closed automatically; new plugins go through a submission form), so it does not clone, fork, branch, push, or open a PR. Runs pre-flight, resolves cyber-agent-harness against the target's live catalog and tells the user it will not resolve there, and drafts the entry in the shape the catalog's existing entries use (e.g. a git-subdir source pinned with the release tag as ref and that tag's commit as sha). Hands the user the draft and the submission form link the target names. Does not rely on remembered facts about that catalog.",
44
+ "files": []
39
45
  }
40
46
  ]
41
47
  }
@@ -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.1` 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.1","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