universal-plugin 0.2.1 → 0.3.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 +15 -0
- package/.codex-plugin/plugin.json +14 -0
- package/.cursor-plugin/plugin.json +14 -0
- package/agents/agentskills-specialist.md +132 -0
- package/bin/upx.mjs +6 -0
- package/dist/cli.mjs +1330 -255
- package/dist/run.mjs +271 -0
- package/governances/plugin-design.md +22 -17
- package/governances/slash-invocation.md +30 -0
- package/package.json +14 -5
- package/plugin.json +18 -0
- package/readme.md +37 -3
- package/skills/adopt-upx/README.md +38 -0
- package/skills/adopt-upx/SKILL.md +120 -0
- package/skills/adopt-upx/scripts/rewrite-upx.mjs +168 -0
- package/skills/migrate-plugin/SKILL.md +106 -0
- package/skills/migrate-plugin/evals/evals.json +11 -0
- package/skills/migrate-plugin/evals/trigger-queries.json +35 -0
- package/skills/plugin/README.md +37 -0
- package/skills/plugin/SKILL.md +105 -0
- package/skills/plugin/assets/templates/agent.md +7 -0
- package/skills/plugin/assets/templates/command.md +9 -0
- package/skills/plugin/assets/templates/hooks.json +9 -0
- package/skills/plugin/assets/templates/plugin.json +19 -0
- package/skills/plugin/assets/templates/setup-command.md +15 -0
- package/skills/plugin/assets/templates/skill.md +15 -0
- package/skills/plugin/references/adopt.md +114 -0
- package/skills/plugin/references/create.md +163 -0
- package/skills/plugin/references/delete.md +23 -0
- package/skills/plugin/references/inspect.md +21 -0
- package/skills/plugin/references/update.md +26 -0
- package/skills/plugin/references/version.md +97 -0
- package/skills/publish-plugin/SKILL.md +246 -0
- package/skills/publish-plugin/evals/evals.json +23 -0
- package/skills/publish-plugin/references/vendor-requirements.md +38 -0
- package/skills/upgrade-plugin/README.md +23 -0
- package/skills/upgrade-plugin/SKILL.md +86 -0
- package/LICENSE +0 -21
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: adopt-upx
|
|
3
|
+
description: Use this skill when the user wants to make their skills use upx — the fast local-first package runner shipped by universal-plugin. Trigger on phrases like "make my skills use upx", "adopt the upx runner", "speed up npx calls", "switch to upx", or "rewrite npx pins to upx". Rewrites `npx <pkg>@<version>` references to a caret range on `upx` (`^<major>`, or `^0.<minor>` for a 0.x pin) across one skill, a named set, or every skill in the project.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Adopt upx
|
|
7
|
+
|
|
8
|
+
Rewrites `npx <pkg>@<version>` references inside `SKILL.md` files to a caret range on `upx` — the
|
|
9
|
+
fast local-first runner shipped by `universal-plugin` (see the package
|
|
10
|
+
[`readme.md`](../../readme.md#upx--the-fast-package-runner) for the `upx` contract).
|
|
11
|
+
|
|
12
|
+
## When to use
|
|
13
|
+
|
|
14
|
+
The user wants their project's skills to shell out via `upx` instead of `npx`, for the ~10× speed
|
|
15
|
+
win on repeated calls. This is an opt-in migration, not a default — see Tradeoff below before
|
|
16
|
+
running it broadly.
|
|
17
|
+
|
|
18
|
+
## Prerequisites
|
|
19
|
+
|
|
20
|
+
Install the runner:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npm i -g universal-plugin
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
This puts the `upx` bin on PATH. Verify:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
upx --help
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
If `upx` isn't found after install, stop and fix PATH before rewriting anything — a rewritten
|
|
33
|
+
skill with no `upx` on PATH breaks for that user (see Tradeoff).
|
|
34
|
+
|
|
35
|
+
## Rewrite rule
|
|
36
|
+
|
|
37
|
+
`npx <pkg>@<version>` → `upx <pkg>@^<major>` — a caret range on the major version, not the exact
|
|
38
|
+
pin. That's the point: one global `upx` install then satisfies every skill's call to that CLI at
|
|
39
|
+
that major, instead of `npx` re-resolving+spawning per exact version every time.
|
|
40
|
+
|
|
41
|
+
**`0.x` versions are special.** Under semver a `0.x` minor bump is a breaking change, so `^0`
|
|
42
|
+
(= `>=0.0.0 <1.0.0`) is far too loose — it would match across incompatible `0.x` lines. A `0.x` pin
|
|
43
|
+
is rewritten to `upx <pkg>@^0.<minor>` instead (e.g. `pkg@0.2.3` → `upx pkg@^0.2`, matching only the
|
|
44
|
+
`0.2.x` line). `^<major>` applies only to `>=1.0.0`.
|
|
45
|
+
|
|
46
|
+
Left alone (never rewritten):
|
|
47
|
+
|
|
48
|
+
- **Non-semver placeholders** — `npx universal-plugin@<version>` (angle-bracket doc placeholders
|
|
49
|
+
aren't real pins)
|
|
50
|
+
- **Dist-tags** — `npx pkg@next`, `npx pkg@latest` (not a range `upx` can match against an
|
|
51
|
+
installed version; these already go straight to `npx` inside `upx` itself on a miss)
|
|
52
|
+
- **Already-`upx` references** — nothing to do
|
|
53
|
+
- **Any skill marked `pin-exempt: true`** in its frontmatter — its version strings are
|
|
54
|
+
documentation/illustration, not real invocations. This mirrors how `plugin bundle` treats
|
|
55
|
+
pin-exempt skills; `upgrade-plugin` is a live example.
|
|
56
|
+
|
|
57
|
+
## Choose scope
|
|
58
|
+
|
|
59
|
+
Ask the user (or infer from their request) which of the three scopes applies:
|
|
60
|
+
|
|
61
|
+
| Scope | How to invoke |
|
|
62
|
+
|---|---|
|
|
63
|
+
| **A specific skill** | Pass its path: `skills/my-skill` (dir) or `skills/my-skill/SKILL.md` |
|
|
64
|
+
| **A named set** | Pass multiple paths and/or a glob: `skills/a skills/b "skills/foo-*"` |
|
|
65
|
+
| **All skills in the project** | Pass `--all` — walks the whole project for every `SKILL.md`, skipping `node_modules`, `.git`, `dist`, `build`, `.turbo` |
|
|
66
|
+
|
|
67
|
+
## Run the rewrite
|
|
68
|
+
|
|
69
|
+
The mechanism is `scripts/rewrite-upx.mjs` in this skill directory — run it directly, don't
|
|
70
|
+
hand-edit files:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
# One skill
|
|
74
|
+
node "<this skill's dir>/scripts/rewrite-upx.mjs" skills/my-skill
|
|
75
|
+
|
|
76
|
+
# A named set (paths and/or globs)
|
|
77
|
+
node "<this skill's dir>/scripts/rewrite-upx.mjs" skills/my-skill skills/other-skill "skills/team-*"
|
|
78
|
+
|
|
79
|
+
# Every skill in the project
|
|
80
|
+
node "<this skill's dir>/scripts/rewrite-upx.mjs" --all
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Preview without writing:
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
node "<this skill's dir>/scripts/rewrite-upx.mjs" --all --dry-run
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
The script reports, per file, how many references it rewrote and which skills it skipped as
|
|
90
|
+
pin-exempt, plus a final tally. It is **idempotent** — re-running over already-rewritten files is
|
|
91
|
+
a no-op (there's no `npx` left to match), so it's safe to run again after adding new skills.
|
|
92
|
+
|
|
93
|
+
## Tradeoff — say this out loud to the user
|
|
94
|
+
|
|
95
|
+
A skill rewritten to `upx` now depends on the `upx` bin being on that environment's PATH.
|
|
96
|
+
`npx` always ships with npm — every Node environment has it. `upx` does not — it only exists after
|
|
97
|
+
`npm i -g universal-plugin`. So this is a deliberate opt-in for environments where
|
|
98
|
+
`universal-plugin` is installed globally, not a safe-by-default swap.
|
|
99
|
+
|
|
100
|
+
Mitigating factor: `upx` itself falls back to plain `npx` on a miss (no local/global install
|
|
101
|
+
satisfies the range) — but that fallback only fires if the `upx` bin is present to run in the
|
|
102
|
+
first place. If `upx` isn't on PATH at all, the shell fails to find the command before `upx`'s own
|
|
103
|
+
fallback logic ever gets a chance to run.
|
|
104
|
+
|
|
105
|
+
## Verify
|
|
106
|
+
|
|
107
|
+
1. Re-run the script over the same scope — it should report `0 file(s) rewritten` (idempotent).
|
|
108
|
+
2. Spot-check a rewritten skill: the pin should read `upx <pkg>@^<major>` (or `upx <pkg>@^0.<minor>`
|
|
109
|
+
for a 0.x package), not a concrete version.
|
|
110
|
+
3. Confirm any pin-exempt skills (e.g. `upgrade-plugin`) were skipped, not rewritten.
|
|
111
|
+
4. If the project has a skill validator (`validate-skill` / `improve-skill`), run it over each
|
|
112
|
+
touched skill to confirm the rewrite didn't break frontmatter or Markdown structure.
|
|
113
|
+
|
|
114
|
+
## Commit
|
|
115
|
+
|
|
116
|
+
Follow project commit discipline — one commit for this rewrite:
|
|
117
|
+
|
|
118
|
+
```text
|
|
119
|
+
chore(skills): adopt upx runner for <scope>
|
|
120
|
+
```
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Rewrites `npx <pkg>@<version>` references inside SKILL.md files to the fast local-first
|
|
3
|
+
// `upx <pkg>@^<major>` form. See ../SKILL.md for the full contract; this is the mechanism.
|
|
4
|
+
//
|
|
5
|
+
// Usage:
|
|
6
|
+
// node rewrite-upx.mjs --all # every SKILL.md under cwd
|
|
7
|
+
// node rewrite-upx.mjs skills/my-skill # one skill (dir or SKILL.md path)
|
|
8
|
+
// node rewrite-upx.mjs skills/a skills/b/SKILL.md skills/c-* # a named set (paths + globs)
|
|
9
|
+
// node rewrite-upx.mjs --all --dry-run # report only, write nothing
|
|
10
|
+
//
|
|
11
|
+
// Rewrite rule: `npx <pkg>@<concrete-semver>` -> `upx <pkg>@^<major>` (caret on the major, so
|
|
12
|
+
// one global `upx` install serves many pinned callers). A `0.x` pin instead becomes
|
|
13
|
+
// `upx <pkg>@^0.<minor>` — under semver a `0.x` minor bump is breaking, so `^0` would be far too
|
|
14
|
+
// loose. Left alone:
|
|
15
|
+
// - `@<placeholder>` (non-semver, e.g. `@<version>`) — not a real pin
|
|
16
|
+
// - dist-tags (e.g. `@next`, `@latest`) — upx can't range-match these, they go to npx anyway
|
|
17
|
+
// - any occurrence already using `upx` — nothing to rewrite
|
|
18
|
+
// - any SKILL.md whose frontmatter declares `pin-exempt: true` — its versions are illustration
|
|
19
|
+
// (the same convention the plugin bundler uses)
|
|
20
|
+
//
|
|
21
|
+
// Idempotent: a second run finds no more `npx <pkg>@<semver>` occurrences to rewrite.
|
|
22
|
+
|
|
23
|
+
import { readdirSync, readFileSync, statSync, writeFileSync } from 'node:fs'
|
|
24
|
+
import { join, resolve } from 'node:path'
|
|
25
|
+
|
|
26
|
+
const SKIP_DIRS = new Set(['node_modules', '.git', 'dist', 'build', '.turbo'])
|
|
27
|
+
|
|
28
|
+
const FRONTMATTER_PATTERN = /^---\r?\n([\s\S]*?)\r?\n---/
|
|
29
|
+
const PIN_EXEMPT_PATTERN = /(^|\n)\s*pin-exempt:\s*true\s*(\n|$)/
|
|
30
|
+
|
|
31
|
+
// Matches `npx <pkg>@<version>` — mirrors the pattern `plugin bundle` uses for pin rewriting,
|
|
32
|
+
// but only for the `npx` runner word (upx refs are already fast, nothing to do). The package
|
|
33
|
+
// class includes `@` and `/` so a scoped package (`@acme/cli@1.2.3`) matches; greedy matching
|
|
34
|
+
// backtracks to the LAST `@`, which separates the version.
|
|
35
|
+
const NPX_REF_PATTERN = /\bnpx(\s+(?:--yes\s+|-y\s+)?)([@a-z0-9/._-]+)@([^\s`'")]+)/g
|
|
36
|
+
|
|
37
|
+
const SEMVER_PATTERN = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/
|
|
38
|
+
|
|
39
|
+
function isPinExempt(content) {
|
|
40
|
+
const match = FRONTMATTER_PATTERN.exec(content)
|
|
41
|
+
if (!match) return false
|
|
42
|
+
return PIN_EXEMPT_PATTERN.test(match[1])
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// `>=1.0.0` → `^<major>` (any release in that major). A `0.x` version is special: under semver a
|
|
46
|
+
// `0.x` minor bump is a breaking change, so `^0` (= `>=0.0.0 <1.0.0`) is far too loose — pin the
|
|
47
|
+
// minor instead with `^0.<minor>` (= that `0.<minor>.x` line only).
|
|
48
|
+
function caretRange(version) {
|
|
49
|
+
const [major, minor] = version.split('.')
|
|
50
|
+
return major === '0' ? `^0.${minor}` : `^${major}`
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function rewriteContent(content) {
|
|
54
|
+
let changed = 0
|
|
55
|
+
const next = content.replace(NPX_REF_PATTERN, (whole, ws, pkg, version) => {
|
|
56
|
+
if (!SEMVER_PATTERN.test(version)) return whole // placeholder or dist-tag — leave alone
|
|
57
|
+
changed++
|
|
58
|
+
return `upx${ws}${pkg}@${caretRange(version)}`
|
|
59
|
+
})
|
|
60
|
+
return { next, changed }
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function findSkillFiles(root) {
|
|
64
|
+
const out = []
|
|
65
|
+
const st = statSync(root, { throwIfNoEntry: false })
|
|
66
|
+
if (!st) return out
|
|
67
|
+
if (st.isFile()) {
|
|
68
|
+
if (root.endsWith('SKILL.md')) out.push(root)
|
|
69
|
+
return out
|
|
70
|
+
}
|
|
71
|
+
if (st.isDirectory()) {
|
|
72
|
+
const direct = join(root, 'SKILL.md')
|
|
73
|
+
if (statSync(direct, { throwIfNoEntry: false })?.isFile()) {
|
|
74
|
+
out.push(direct)
|
|
75
|
+
return out // a skill dir given directly — don't also recurse into it
|
|
76
|
+
}
|
|
77
|
+
for (const entry of readdirSync(root, { withFileTypes: true })) {
|
|
78
|
+
if (entry.isDirectory()) {
|
|
79
|
+
if (SKIP_DIRS.has(entry.name)) continue
|
|
80
|
+
out.push(...findSkillFiles(join(root, entry.name)))
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return out
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Minimal glob: only `*` within a single path segment (no `**`). Enough for named-set patterns
|
|
88
|
+
// like `skills/foo-*` or `skills/*/SKILL.md`.
|
|
89
|
+
function expandGlob(pattern) {
|
|
90
|
+
if (!pattern.includes('*')) return null
|
|
91
|
+
const segments = pattern.split('/')
|
|
92
|
+
let bases = ['.']
|
|
93
|
+
for (const seg of segments) {
|
|
94
|
+
if (!seg.includes('*')) {
|
|
95
|
+
bases = bases.map((b) => join(b, seg))
|
|
96
|
+
continue
|
|
97
|
+
}
|
|
98
|
+
const re = new RegExp('^' + seg.split('*').map(escapeRegExp).join('.*') + '$')
|
|
99
|
+
const next = []
|
|
100
|
+
for (const b of bases) {
|
|
101
|
+
const st = statSync(b, { throwIfNoEntry: false })
|
|
102
|
+
if (!st?.isDirectory()) continue
|
|
103
|
+
for (const entry of readdirSync(b)) {
|
|
104
|
+
if (re.test(entry)) next.push(join(b, entry))
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
bases = next
|
|
108
|
+
}
|
|
109
|
+
return bases
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function escapeRegExp(value) {
|
|
113
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function resolveTargets(args) {
|
|
117
|
+
const all = args.includes('--all')
|
|
118
|
+
const dryRun = args.includes('--dry-run')
|
|
119
|
+
const positional = args.filter((a) => a !== '--all' && a !== '--dry-run')
|
|
120
|
+
|
|
121
|
+
if (all) return { files: findSkillFiles('.'), dryRun }
|
|
122
|
+
|
|
123
|
+
const files = []
|
|
124
|
+
for (const arg of positional) {
|
|
125
|
+
const globbed = expandGlob(arg)
|
|
126
|
+
if (globbed) {
|
|
127
|
+
for (const g of globbed) files.push(...findSkillFiles(g))
|
|
128
|
+
} else {
|
|
129
|
+
files.push(...findSkillFiles(arg))
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return { files: [...new Set(files)], dryRun }
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function main() {
|
|
136
|
+
const args = process.argv.slice(2)
|
|
137
|
+
if (args.length === 0) {
|
|
138
|
+
console.error('usage: rewrite-upx.mjs (--all | <path-or-glob>...) [--dry-run]')
|
|
139
|
+
process.exit(1)
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const { files, dryRun } = resolveTargets(args)
|
|
143
|
+
if (files.length === 0) {
|
|
144
|
+
console.error('no SKILL.md files matched — nothing to do')
|
|
145
|
+
process.exit(0)
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
let touched = 0
|
|
149
|
+
let skippedExempt = 0
|
|
150
|
+
for (const file of files) {
|
|
151
|
+
const abs = resolve(file)
|
|
152
|
+
const content = readFileSync(abs, 'utf8')
|
|
153
|
+
if (isPinExempt(content)) {
|
|
154
|
+
skippedExempt++
|
|
155
|
+
console.log(`skip (pin-exempt): ${file}`)
|
|
156
|
+
continue
|
|
157
|
+
}
|
|
158
|
+
const { next, changed } = rewriteContent(content)
|
|
159
|
+
if (changed === 0) continue
|
|
160
|
+
touched++
|
|
161
|
+
console.log(`${dryRun ? '[dry-run] ' : ''}rewrite (${changed}): ${file}`)
|
|
162
|
+
if (!dryRun) writeFileSync(abs, next, 'utf8')
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
console.log(`\n${touched} file(s) rewritten, ${skippedExempt} skipped (pin-exempt), ${files.length} scanned.`)
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
main()
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: migrate-plugin
|
|
3
|
+
description: "Move a repository-root universal agent plugin into its npm package so the package distributes its manifest, vendor manifests, skills, and agents. Use this skill when packaging an existing plugin for npm, relocating a top-level plugin into a package, or fixing a package that omits plugin assets, even if the user says only 'ship this plugin through npm' or 'move the plugin into the package.'"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Migrate Universal Plugin to npm
|
|
7
|
+
|
|
8
|
+
## Scope
|
|
9
|
+
|
|
10
|
+
Move one existing universal plugin from a repository root into its owning npm
|
|
11
|
+
package. The package becomes the plugin root and must contain every runtime
|
|
12
|
+
artifact it needs after installation.
|
|
13
|
+
|
|
14
|
+
This skill does not create a plugin from scratch, publish a package, or move
|
|
15
|
+
project-local agent configuration unrelated to the plugin.
|
|
16
|
+
|
|
17
|
+
## 1. Inspect and plan
|
|
18
|
+
|
|
19
|
+
Identify the destination package directory and read its `package.json`.
|
|
20
|
+
Before changing manifest fields or component compatibility behavior, consult the
|
|
21
|
+
[Agent Plugins Specification](https://github.com/agentplugins/agent-plugins-spec)
|
|
22
|
+
and its versioned specification: it is the canonical reference for the current
|
|
23
|
+
standard. Keep an existing schema version pinned unless the user explicitly
|
|
24
|
+
requests a standards upgrade.
|
|
25
|
+
Inventory these root-level plugin assets when they exist:
|
|
26
|
+
|
|
27
|
+
- `plugin.json`
|
|
28
|
+
- vendor manifest directories for Claude Code, Cursor, Codex, and Copilot CLI
|
|
29
|
+
- `skills/`, `agents/`, `commands/`, `hooks/`, `rules/`, `output-styles/`
|
|
30
|
+
- `.mcp.json`, `.lsp.json`, and plugin-owned `assets/`
|
|
31
|
+
|
|
32
|
+
Leave project configuration in place unless it is required solely to maintain
|
|
33
|
+
the moved plugin. In particular, do not move `.agents/skills/`, plans, or a
|
|
34
|
+
marketplace catalog such as `.claude/marketplace.json`.
|
|
35
|
+
|
|
36
|
+
Before modifying files, report the exact source-to-destination mapping and any
|
|
37
|
+
destination collisions. Ask for confirmation if a destination contains a
|
|
38
|
+
different file that would be overwritten.
|
|
39
|
+
|
|
40
|
+
## 2. Move the plugin root
|
|
41
|
+
|
|
42
|
+
Move each inventoried asset under the package directory, preserving its path.
|
|
43
|
+
A package receives these relative paths:
|
|
44
|
+
|
|
45
|
+
```text
|
|
46
|
+
the canonical manifest
|
|
47
|
+
vendor manifests
|
|
48
|
+
skills
|
|
49
|
+
agents
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
The source root must no longer retain duplicate distributable plugin assets.
|
|
53
|
+
Do not move a project-local skill merely because it is under `.agents/skills/`.
|
|
54
|
+
|
|
55
|
+
## 3. Configure npm packaging
|
|
56
|
+
|
|
57
|
+
Add every moved plugin artifact to the destination package's `package.json`
|
|
58
|
+
`files` allowlist. At minimum, include the canonical manifest, each present
|
|
59
|
+
vendor manifest directory, and every present component directory. A typical
|
|
60
|
+
configuration is:
|
|
61
|
+
|
|
62
|
+
```json
|
|
63
|
+
{
|
|
64
|
+
"files": [
|
|
65
|
+
"bin",
|
|
66
|
+
"dist",
|
|
67
|
+
"plugin.json",
|
|
68
|
+
".claude-plugin",
|
|
69
|
+
".cursor-plugin",
|
|
70
|
+
".codex-plugin",
|
|
71
|
+
"skills",
|
|
72
|
+
"agents"
|
|
73
|
+
]
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Retain existing package entries such as `bin`, `dist`, and `governances`.
|
|
78
|
+
Never replace the allowlist wholesale.
|
|
79
|
+
|
|
80
|
+
## 4. Preserve release synchronization
|
|
81
|
+
|
|
82
|
+
If the repository runs `universal-plugin publish sync-version`, move its
|
|
83
|
+
plugin-specific configuration beside the new `plugin.json` and change
|
|
84
|
+
`packagePath` to `"."`. Update the root release script to run the command from
|
|
85
|
+
the destination package, for example:
|
|
86
|
+
|
|
87
|
+
```sh
|
|
88
|
+
pnpm exec universal-plugin publish sync-version --root .
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Update any checked-in skill lockfile that records an absolute source path for a
|
|
92
|
+
moved skill. Do not modify unrelated agent configuration.
|
|
93
|
+
|
|
94
|
+
## 5. Verify the result
|
|
95
|
+
|
|
96
|
+
1. Run the package's focused tests and typecheck/lint commands.
|
|
97
|
+
2. Run `npm pack --dry-run` from the destination package. Confirm it lists
|
|
98
|
+
`plugin.json`, every required vendor manifest, `skills/`, and `agents/`.
|
|
99
|
+
3. If the manifest declares build targets, run `universal-plugin plugin build`
|
|
100
|
+
from the destination package and confirm generated paths stay inside it.
|
|
101
|
+
4. Search the repository for stale references to the old top-level asset paths.
|
|
102
|
+
5. Review the diff to confirm no project-local `.agents` content or marketplace
|
|
103
|
+
catalog was included in the package.
|
|
104
|
+
|
|
105
|
+
Report the package path, files added to the npm tarball, checks run, and any
|
|
106
|
+
intentionally retained root-local files.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"skill_name": "migrate-plugin",
|
|
3
|
+
"evals": [
|
|
4
|
+
{
|
|
5
|
+
"id": 1,
|
|
6
|
+
"prompt": "Move the top-level universal plugin into packages/universal-plugin so npm distributes it.",
|
|
7
|
+
"expected_output": "Inventories and relocates only distributable plugin assets, adds them to package.json files, updates version synchronization, verifies npm pack --dry-run, and preserves project-local .agents content.",
|
|
8
|
+
"files": []
|
|
9
|
+
}
|
|
10
|
+
]
|
|
11
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"skill_name": "migrate-plugin",
|
|
3
|
+
"trigger_queries": [
|
|
4
|
+
{
|
|
5
|
+
"id": 1,
|
|
6
|
+
"query": "Move our root plugin.json and skills into packages/my-plugin so npm ships them.",
|
|
7
|
+
"should_trigger": true,
|
|
8
|
+
"split": "train"
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
"id": 2,
|
|
12
|
+
"query": "Our npm package publishes the CLI but not its Claude and Codex plugin assets. Fix the package layout.",
|
|
13
|
+
"should_trigger": true,
|
|
14
|
+
"split": "train"
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"id": 3,
|
|
18
|
+
"query": "Ship this universal agent plugin through npm instead of from the monorepo root.",
|
|
19
|
+
"should_trigger": true,
|
|
20
|
+
"split": "val"
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"id": 4,
|
|
24
|
+
"query": "Upgrade all npx universal-plugin pins to version 0.3.0.",
|
|
25
|
+
"should_trigger": false,
|
|
26
|
+
"split": "train"
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"id": 5,
|
|
30
|
+
"query": "Create a new universal plugin from scratch for Claude Code and Cursor.",
|
|
31
|
+
"should_trigger": false,
|
|
32
|
+
"split": "val"
|
|
33
|
+
}
|
|
34
|
+
]
|
|
35
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# plugin skill
|
|
2
|
+
|
|
3
|
+
A skill for creating, inspecting, updating, and deleting universal AI coding agent plugins that target multiple runtimes from a single source of truth.
|
|
4
|
+
|
|
5
|
+
## Supported runtimes
|
|
6
|
+
|
|
7
|
+
| Vendor | Manifest path |
|
|
8
|
+
| ----------- | ---------------------------- |
|
|
9
|
+
| Claude Code | `.claude-plugin/plugin.json` |
|
|
10
|
+
| Cursor | `.cursor-plugin/plugin.json` |
|
|
11
|
+
| Codex | `.codex-plugin/plugin.json` |
|
|
12
|
+
| Copilot CLI | root `plugin.json` (the canonical manifest; nothing derived) |
|
|
13
|
+
|
|
14
|
+
Universal minimum (no vendor manifest needed): `skills/<name>/SKILL.md` or `.mcp.json`. The canonical source of truth is root `plugin.json`.
|
|
15
|
+
|
|
16
|
+
## Operations
|
|
17
|
+
|
|
18
|
+
`SKILL.md` is a gateway: it detects what the project already contains, then routes to one operation
|
|
19
|
+
reference and only that one gets read.
|
|
20
|
+
|
|
21
|
+
| Operation | Reference | What it covers |
|
|
22
|
+
| --------- | --------- | -------------- |
|
|
23
|
+
| Create | [`references/create.md`](./references/create.md) | scaffold a new plugin with chosen vendors and components |
|
|
24
|
+
| Adopt | [`references/adopt.md`](./references/adopt.md) | put an existing vendor-specific plugin, or already-shipped skills, onto the open standard |
|
|
25
|
+
| Inspect | [`references/inspect.md`](./references/inspect.md) | show build status for each declared vendor |
|
|
26
|
+
| Update | [`references/update.md`](./references/update.md) | add/remove vendors or components |
|
|
27
|
+
| Delete | [`references/delete.md`](./references/delete.md) | remove generated manifests or the whole plugin |
|
|
28
|
+
|
|
29
|
+
On invocation the gateway checks for existing vendor manifests and publicly-shipped skills, and
|
|
30
|
+
offers adoption when it finds either without a canonical `plugin.json`. Repo-private agent config
|
|
31
|
+
(`.claude/skills/`, `.agents/skills/`) is deliberately excluded — it is not something to package.
|
|
32
|
+
|
|
33
|
+
## References
|
|
34
|
+
|
|
35
|
+
- [Spec](https://github.com/cyberuni/universal-plugin/blob/main/packages/universal-plugin/.agents/spec/spec.md)
|
|
36
|
+
- [Schema](https://raw.githubusercontent.com/cyberuni/universal-plugin/refs/heads/main/schema/v1.json)
|
|
37
|
+
- [Examples](https://github.com/cyberuni/universal-plugin/tree/main/examples)
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: plugin
|
|
3
|
+
description: Use this skill when creating, inspecting, updating, versioning, or deleting a universal agent plugin that targets multiple AI coding agent runtimes — Claude Code, Cursor, Codex, GitHub Copilot CLI. Also use it to convert a vendor-specific plugin, or a project that already ships skills, onto the open Agent Plugins Specification, or to move a plugin's version — for asks like "make my Claude Code plugin work in Cursor", "convert this to the open plugin standard", "turn these skills into a plugin", "bump my plugin's version", "release a new version of this plugin", or "set the plugin version to 1.0.0".
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Universal Plugin
|
|
7
|
+
|
|
8
|
+
Gateway skill. Identify which operation the user wants, load that operation's reference, and follow
|
|
9
|
+
it.
|
|
10
|
+
|
|
11
|
+
## When to use
|
|
12
|
+
|
|
13
|
+
When the user wants to create, inspect, update, version, or delete a plugin targeting Claude Code,
|
|
14
|
+
Cursor, Codex, and/or GitHub Copilot CLI from a single source of truth.
|
|
15
|
+
|
|
16
|
+
## Prerequisites
|
|
17
|
+
|
|
18
|
+
Load governance before starting any operation:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npx universal-plugin governance show plugin-design
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Until the CLI is available, read `governances/plugin-design.md` from this plugin's installation
|
|
25
|
+
directory. It is the authoritative source for component selection rules and anti-patterns.
|
|
26
|
+
|
|
27
|
+
## Step 0 — Detect what is already here
|
|
28
|
+
|
|
29
|
+
Run this before routing. What the project already contains often changes which operation is
|
|
30
|
+
actually right — a "create a plugin" request in a repo that already ships skills is an *adopt*, not
|
|
31
|
+
a create.
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
ls -d .claude-plugin .cursor-plugin .codex-plugin .github/plugin .plugin 2>/dev/null
|
|
35
|
+
test -f plugin.json && head -20 plugin.json
|
|
36
|
+
find . -name SKILL.md -not -path '*/node_modules/*' -not -path './.git/*'
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Read the signals:
|
|
40
|
+
|
|
41
|
+
| What you find | What it means | Do this |
|
|
42
|
+
|---------------|---------------|---------|
|
|
43
|
+
| Root `plugin.json` with `$schema` on `agent-plugins.org` **and** an `extensions` object | Already on the open standard | Nothing to offer — route normally |
|
|
44
|
+
| A vendor manifest (`.claude-plugin/`, `.cursor-plugin/`, `.codex-plugin/`, `.github/plugin/`) with **no** canonical root `plugin.json` | A vendor-specific plugin | **Offer to adopt** |
|
|
45
|
+
| Root `plugin.json` with no `$schema`/`extensions` | Legacy single-vendor manifest | **Offer to adopt** |
|
|
46
|
+
| Public skills (see below) and no plugin manifest at all | Skills shipped without a plugin | **Offer to adopt** |
|
|
47
|
+
| None of the above | Greenfield | Route normally |
|
|
48
|
+
|
|
49
|
+
### Which skills count as public
|
|
50
|
+
|
|
51
|
+
Only offer on skills the project **distributes**. Repo-local agent configuration is not a plugin,
|
|
52
|
+
and offering to package it is wrong.
|
|
53
|
+
|
|
54
|
+
| Location | Public? |
|
|
55
|
+
|----------|---------|
|
|
56
|
+
| `skills/<name>/SKILL.md` at the repo root | Yes |
|
|
57
|
+
| `<package>/skills/<name>/SKILL.md` where `package.json` `files` ships it | Yes |
|
|
58
|
+
| `.claude/skills/`, `.agents/skills/`, `.cursor/rules/` | **No** — repo-private tooling |
|
|
59
|
+
|
|
60
|
+
If the only skills are in private locations, say nothing about adoption.
|
|
61
|
+
|
|
62
|
+
### Making the offer
|
|
63
|
+
|
|
64
|
+
State what you found, what adoption would give them, and let them decline:
|
|
65
|
+
|
|
66
|
+
> This repo has a Claude Code plugin manifest but no canonical `plugin.json`. I can convert it to
|
|
67
|
+
> the open Agent Plugins Specification, which would let one manifest drive Cursor, Codex, and
|
|
68
|
+
> Copilot CLI too — Claude Code keeps working exactly as it does now. Want me to?
|
|
69
|
+
|
|
70
|
+
Offer once. If the user declines, or their request is already a specific unrelated operation
|
|
71
|
+
(deleting manifests, inspecting status), drop it and do what they asked.
|
|
72
|
+
|
|
73
|
+
## Route
|
|
74
|
+
|
|
75
|
+
Read exactly the reference for the operation at hand — do not load all six.
|
|
76
|
+
|
|
77
|
+
| The user wants to… | Reference |
|
|
78
|
+
|--------------------|-----------|
|
|
79
|
+
| Scaffold a new plugin, add vendors/components to a fresh one, or build vendor manifests | [`references/create.md`](./references/create.md) |
|
|
80
|
+
| Put an existing vendor-specific plugin, or already-shipped skills, onto the open standard | [`references/adopt.md`](./references/adopt.md) |
|
|
81
|
+
| See what a plugin declares and which vendor manifests are built or stale | [`references/inspect.md`](./references/inspect.md) |
|
|
82
|
+
| Add or remove a vendor, or add or remove a component, on an existing plugin | [`references/update.md`](./references/update.md) |
|
|
83
|
+
| Bump or set the plugin's version, or cut a release of it | [`references/version.md`](./references/version.md) |
|
|
84
|
+
| Remove generated manifests, or remove the whole plugin | [`references/delete.md`](./references/delete.md) |
|
|
85
|
+
|
|
86
|
+
If the request spans more than one operation (for example "add Codex and rebuild"), load each
|
|
87
|
+
reference in turn as you reach that part of the work.
|
|
88
|
+
|
|
89
|
+
If the operation is unclear, ask which the user means rather than guessing.
|
|
90
|
+
|
|
91
|
+
## Related skills
|
|
92
|
+
|
|
93
|
+
| Task | Skill |
|
|
94
|
+
|------|-------|
|
|
95
|
+
| Move a repo-root plugin into its npm package | `migrate-plugin` |
|
|
96
|
+
| Publish a packaged plugin to the marketplace | `publish-plugin` |
|
|
97
|
+
| Bump the pinned `universal-plugin@<version>` the project *calls* (not the plugin's own version) | `upgrade-plugin` |
|
|
98
|
+
| Rewrite `npx` pins to the `upx` runner | `adopt-upx` |
|
|
99
|
+
|
|
100
|
+
## References
|
|
101
|
+
|
|
102
|
+
- Governance: `npx cyberplace governance show plugin-design`
|
|
103
|
+
- Spec: https://github.com/cyberuni/universal-plugin/blob/main/packages/universal-plugin/.agents/spec/spec.md
|
|
104
|
+
- Schema: https://raw.githubusercontent.com/cyberuni/universal-plugin/refs/heads/main/schema/v1.json
|
|
105
|
+
- Examples: https://github.com/cyberuni/universal-plugin/tree/main/examples
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
|
|
3
|
+
"name": "<plugin-name>",
|
|
4
|
+
"version": "1.0.0",
|
|
5
|
+
"description": "<description>",
|
|
6
|
+
"author": { "name": "<author>" },
|
|
7
|
+
"extensions": {
|
|
8
|
+
"org.cyberuni.universal-plugin": {
|
|
9
|
+
"vendors": ["claude-code", "cursor", "codex", "copilot-cli"],
|
|
10
|
+
"skills": "./skills/",
|
|
11
|
+
"harnesses": {
|
|
12
|
+
"claude-code": {},
|
|
13
|
+
"cursor": {},
|
|
14
|
+
"codex": {},
|
|
15
|
+
"copilot-cli": {}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Post-install setup — merge always-on plugin guidance into project AGENTS.md
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Plugin Setup
|
|
6
|
+
|
|
7
|
+
Run once after installing the plugin.
|
|
8
|
+
|
|
9
|
+
## Instructions
|
|
10
|
+
|
|
11
|
+
1. Read all `.mdc` files under this plugin's `rules/` directory
|
|
12
|
+
2. Strip YAML frontmatter from each file
|
|
13
|
+
3. Append the remaining content as a new `## <plugin-name>` section in the project's `AGENTS.md`
|
|
14
|
+
4. Confirm the merge completed
|
|
15
|
+
5. The `rules/*.mdc` files are now redundant. Delete them if desired.
|