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