universal-plugin 0.11.2 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/.cursor-plugin/plugin.json +1 -1
- package/dist/cli.mjs +3309 -3166
- package/package.json +3 -3
- package/plugin.json +1 -1
- package/readme.md +1 -1
- package/skills/build-plugin/SKILL.md +7 -1
- package/skills/doctor-universal-plugin/SKILL.md +5 -4
- package/skills/doctor-universal-plugin/scripts/doctor.mjs +10 -1
- package/skills/publish-plugin/README.md +8 -0
- package/skills/publish-plugin/SKILL.md +44 -5
- package/skills/publish-plugin/evals/evals.json +6 -0
- package/skills/version/README.md +1 -1
- package/skills/version/SKILL.md +7 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "universal-plugin",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.0",
|
|
4
4
|
"description": "Universal AI agent plugin build tool",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agent-plugin",
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
"@cyberuni/agent-harness": "^0.3.0",
|
|
43
43
|
"@repobuddy/upx": "^0.2.0",
|
|
44
44
|
"@toon-format/toon": "^4.1.1",
|
|
45
|
-
"commander": "^
|
|
45
|
+
"commander": "^15.0.0",
|
|
46
46
|
"semver": "^7.8.1"
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
"tsdown": "^0.23.0",
|
|
54
54
|
"tsx": "^4.22.3",
|
|
55
55
|
"typescript": "^6.0.0",
|
|
56
|
-
"vitest": "^
|
|
56
|
+
"vitest": "^5.0.0"
|
|
57
57
|
},
|
|
58
58
|
"engines": {
|
|
59
59
|
"node": ">=22"
|
package/plugin.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
|
|
3
3
|
"name": "universal-plugin",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.12.0",
|
|
5
5
|
"description": "Research and design toolkit for building universal AI coding agent plugins that work across Claude Code, Cursor, Codex, and GitHub Copilot CLI.",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "unional"
|
package/readme.md
CHANGED
|
@@ -69,7 +69,7 @@ npx universal-plugin sync apply <action-id>
|
|
|
69
69
|
### publish
|
|
70
70
|
|
|
71
71
|
```sh
|
|
72
|
-
npx universal-plugin publish sync-version # copy packagePath/package.json version into plugin.json
|
|
72
|
+
npx universal-plugin publish sync-version # copy packagePath/package.json version into plugin.json, then rebuild
|
|
73
73
|
```
|
|
74
74
|
|
|
75
75
|
This writes the canonical `plugin.json` only. Run `plugin build` afterwards, or the vendor manifests
|
|
@@ -56,6 +56,7 @@ The command never prompts, so it is safe to run unattended.
|
|
|
56
56
|
| `--dry-run` | Validate and report the plan, write nothing. Run this first when unsure what will change |
|
|
57
57
|
| `--vendor <id>` | Build one vendor (`claude-code`, `cursor`, `codex`, `copilot-cli`), and refresh only its catalog |
|
|
58
58
|
| `--verbose` | Print each field-level decision the derivation made |
|
|
59
|
+
| `--strict-dependencies` | Fail when a refreshed catalog cannot resolve a declared dependency. Use in CI |
|
|
59
60
|
| `--format json` | The same result as JSON, for scripts |
|
|
60
61
|
|
|
61
62
|
`--clean` also exists. It deletes derived manifests before rewriting them, so reach for it only
|
|
@@ -76,9 +77,14 @@ A catalog row reads `updated`, `unchanged`, or `planned` on `--dry-run`. A build
|
|
|
76
77
|
catalog, and it keeps an entry's non-local source, such as an npm package, while it re-derives the
|
|
77
78
|
version. To add a catalog or change a source, use `marketplace`.
|
|
78
79
|
|
|
80
|
+
The build also checks each declared dependency against the catalogs it refreshes. A bare dependency
|
|
81
|
+
the catalog does not list warns: offer the user both fixes the warning names, listing it with
|
|
82
|
+
`marketplace add` or qualifying it with the marketplace that lists it. A dependency whose entry
|
|
83
|
+
declares a `source` is listed in the catalog by the build itself.
|
|
84
|
+
|
|
79
85
|
Read stderr too. The build drops what a vendor cannot represent and warns instead of failing: a hook
|
|
80
86
|
handler type a vendor cannot run, a `harnesses.copilot-cli` override with no delivery path, an
|
|
81
|
-
invalid catalog. Each warning names something that will not reach a runtime. Tell the user each
|
|
87
|
+
invalid catalog, a dependency the catalog cannot resolve. Each warning names something that will not reach a runtime. Tell the user each
|
|
82
88
|
one; do not bury it in a summary.
|
|
83
89
|
|
|
84
90
|
`built 0` with "nothing to build" is not success. The manifest declares no vendor, so hand it to
|
|
@@ -73,8 +73,8 @@ Each `code` below is what the script emits.
|
|
|
73
73
|
| `no-manifest` | no root `plugin.json` — this is not a plugin yet | `/universal-plugin:init-universal-plugin` |
|
|
74
74
|
| `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 |
|
|
75
75
|
| `vendor-only` | a vendor manifest with no canonical manifest above it | `/universal-plugin:init-universal-plugin`, adopt route |
|
|
76
|
-
| `unbuilt` | a declared vendor whose output path holds no file — that runtime sees no plugin |
|
|
77
|
-
| `stale` | a derived manifest older than `plugin.json` |
|
|
76
|
+
| `unbuilt` | a declared vendor whose output path holds no file — that runtime sees no plugin | `/universal-plugin:build-plugin` |
|
|
77
|
+
| `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` |
|
|
78
78
|
| `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 |
|
|
79
79
|
| `unknown-vendor` | a `vendors` entry no build target matches; reported as `skipped` plus a warning | fix the id in `plugin.json` |
|
|
80
80
|
| `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,7 +82,7 @@ Each `code` below is what the script emits.
|
|
|
82
82
|
| `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 |
|
|
83
83
|
| `version-drift` | the `packagePath` `package.json` and the canonical manifest carry different versions | `/universal-plugin:version` |
|
|
84
84
|
| `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` |
|
|
85
|
-
| `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 |
|
|
85
|
+
| `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` |
|
|
86
86
|
| `stale-github-plugin` | a leftover `.github/plugin/plugin.json` from an older build — shadowed by root and no longer generated | `/universal-plugin:remove-plugin` |
|
|
87
87
|
| `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` |
|
|
88
88
|
| `no-vendors` | no vendor is declared, so the build writes nothing and no runtime reads the plugin. On a repository still on the pre-0.6 layout 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 on the pre-0.6 layout, else update route |
|
|
@@ -126,7 +126,7 @@ the diff:
|
|
|
126
126
|
```bash
|
|
127
127
|
git status --short # must be clean first, or the diff proves nothing
|
|
128
128
|
npx universal-plugin plugin build
|
|
129
|
-
git diff -- .claude-plugin .cursor-plugin .codex-plugin
|
|
129
|
+
git diff -- .claude-plugin .cursor-plugin .codex-plugin com.github.copilot
|
|
130
130
|
```
|
|
131
131
|
|
|
132
132
|
An empty diff means the derived manifests match what the canonical manifest says. Any hunk is drift —
|
|
@@ -180,6 +180,7 @@ is meant to ship — content that is still being worked on is not a finding to a
|
|
|
180
180
|
| Task | Skill |
|
|
181
181
|
|------|-------|
|
|
182
182
|
| Create, adopt, or change what the plugin declares | `init-universal-plugin` |
|
|
183
|
+
| Rebuild the derived manifests (`unbuilt`, `stale`, `copilot-root-components`) | `build-plugin` |
|
|
183
184
|
| Move the plugin's version | `version` |
|
|
184
185
|
| Remove derived manifests, or the plugin itself | `remove-plugin` |
|
|
185
186
|
| Generate the repository's own marketplace catalogs | `marketplace` |
|
|
@@ -30,6 +30,15 @@ const readJson = (file) => {
|
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
32
|
const mtime = (file) => (fs.existsSync(file) ? fs.statSync(file).mtimeMs : null)
|
|
33
|
+
// A derived directory (copilot-cli's com.github.copilot/) is as fresh as the newest file in it. The
|
|
34
|
+
// directory's own mtime moves only when an entry is added, removed or renamed, so a rebuild that
|
|
35
|
+
// rewrites its files in place leaves it as old as the first build (issue #144).
|
|
36
|
+
const contentMtime = (abs) => {
|
|
37
|
+
const stat = fs.statSync(abs)
|
|
38
|
+
if (!stat.isDirectory()) return stat.mtimeMs
|
|
39
|
+
const files = fs.readdirSync(abs).map((entry) => contentMtime(path.join(abs, entry)))
|
|
40
|
+
return files.length === 0 ? stat.mtimeMs : Math.max(...files)
|
|
41
|
+
}
|
|
33
42
|
|
|
34
43
|
const VENDOR_MANIFESTS = ['.claude-plugin/plugin.json', '.cursor-plugin/plugin.json', '.codex-plugin/plugin.json']
|
|
35
44
|
|
|
@@ -207,7 +216,7 @@ if (build === null) {
|
|
|
207
216
|
const abs = path.join(root, row.path)
|
|
208
217
|
const exists = fs.existsSync(abs)
|
|
209
218
|
// `canonical` means the vendor reads root plugin.json; no derived file is expected.
|
|
210
|
-
const stale = row.status === 'built' && exists && manifestMtime !== null &&
|
|
219
|
+
const stale = row.status === 'built' && exists && manifestMtime !== null && contentMtime(abs) < manifestMtime
|
|
211
220
|
vendors.push({ vendor: row.vendor, path: row.path, status: row.status, exists, stale })
|
|
212
221
|
|
|
213
222
|
if (row.status === 'built' && !exists) {
|
|
@@ -22,6 +22,14 @@ Every check and every entry field in Steps 1–2 reads from the plugin location
|
|
|
22
22
|
from the cwd by assumption. Getting this wrong means the marketplace entry ends up pointing at the
|
|
23
23
|
marketplace repo's own URL instead of the plugin's.
|
|
24
24
|
|
|
25
|
+
## A plugin's dependencies go with it
|
|
26
|
+
|
|
27
|
+
A plain dependency (no marketplace named) resolves against the marketplace the plugin is installed
|
|
28
|
+
from, so publishing a plugin whose plain dependency the catalog does not list publishes something
|
|
29
|
+
nobody can install. The skill lists such a dependency in the same PR, or stops and asks for it to be
|
|
30
|
+
published first. A dependency that names another marketplace only needs that marketplace in the
|
|
31
|
+
catalog's `allowCrossMarketplaceDependenciesOn`, which the skill offers to add.
|
|
32
|
+
|
|
25
33
|
## Why this is not the `marketplace` skill
|
|
26
34
|
|
|
27
35
|
`marketplace` generates a repository's own local catalog — no submission, no shared listing, no PR.
|
|
@@ -19,7 +19,7 @@ Publishing has four steps:
|
|
|
19
19
|
|
|
20
20
|
0. **Locate** — work out which repo is which, and where the plugin and the marketplace each live
|
|
21
21
|
1. **Pre-flight** — validate the plugin is ready
|
|
22
|
-
2. **Prepare entries** — build the entry for each vendor marketplace file that exists
|
|
22
|
+
2. **Prepare entries** — build the entry for each vendor marketplace file that exists, and resolve the plugin's dependencies against the target marketplace
|
|
23
23
|
3. **Submit PR** — one PR that updates all relevant marketplace files
|
|
24
24
|
|
|
25
25
|
Work through each step in order. Do not skip pre-flight even if the user says the plugin is ready.
|
|
@@ -211,7 +211,39 @@ If the plugin is already listed (this is an update), find its existing entry, up
|
|
|
211
211
|
|
|
212
212
|
Show all prepared entries to the user and ask them to confirm before proceeding.
|
|
213
213
|
|
|
214
|
-
### 2f.
|
|
214
|
+
### 2f. Resolve the plugin's dependencies
|
|
215
|
+
|
|
216
|
+
Claude Code installs a plugin only when every dependency it declares resolves, so a catalog that lists
|
|
217
|
+
the plugin but not what it depends on publishes a plugin nobody can install. Read the declaration
|
|
218
|
+
Claude Code receives, from the **plugin location**: `dependencies` in `.claude-plugin/plugin.json`
|
|
219
|
+
(the built manifest), or, if that has not been built, the canonical one —
|
|
220
|
+
`extensions["org.cyberuni.universal-plugin"].harnesses["claude-code"].dependencies`, else
|
|
221
|
+
`extensions["org.cyberuni.universal-plugin"].dependencies` in `plugin.json`. No declaration means
|
|
222
|
+
nothing to do here.
|
|
223
|
+
|
|
224
|
+
Each entry is a string (`<plugin>` or `<plugin>@<marketplace>`, optionally with an `@^range` tail) or
|
|
225
|
+
an object (`{ "name", "marketplace"?, "version"?, ... }`). Sort each one:
|
|
226
|
+
|
|
227
|
+
- **Plain** — a bare `<plugin>`, or an object with no `marketplace`. Claude Code resolves it against
|
|
228
|
+
the marketplace the plugin is installed from, which is this one. If the target catalog
|
|
229
|
+
(`.claude-plugin/marketplace.json`) already lists that name, it is resolved. Otherwise it must be
|
|
230
|
+
listed in this same PR: locate the dependency's own repository or package (an object's `source`
|
|
231
|
+
field, when present, says where it is distributed from; otherwise ask the user), run Step 1's
|
|
232
|
+
pre-flight against it, and prepare its entries exactly as 2b–2e do for the main plugin — then
|
|
233
|
+
resolve *its* plain dependencies the same way. If a plain dependency cannot be listed (no
|
|
234
|
+
repository or package to read, pre-flight fails, the user declines), **stop**: tell the user to
|
|
235
|
+
publish that dependency to this marketplace first, and do not open the PR.
|
|
236
|
+
- **Names a marketplace** — `<plugin>@<marketplace>`, or an object with `marketplace`. Not held to
|
|
237
|
+
this catalog's listing, even when the marketplace it names is this one; do not add an entry for
|
|
238
|
+
it. When the named marketplace is **not** this catalog's `name`, Claude Code refuses the
|
|
239
|
+
dependency at install unless this catalog's top-level `allowCrossMarketplaceDependenciesOn` lists
|
|
240
|
+
that marketplace. If it does not, tell the user that installs from this marketplace need it, and
|
|
241
|
+
offer to add the marketplace name to that array in the same PR.
|
|
242
|
+
|
|
243
|
+
Report how each dependency was sorted and what was done about it, and include the dependency entries
|
|
244
|
+
in what you show the user to confirm.
|
|
245
|
+
|
|
246
|
+
### 2g. Validate the catalogs
|
|
215
247
|
|
|
216
248
|
Before moving to Step 3, run the validator against the marketplace repo's working copy (the same
|
|
217
249
|
checkout the entries were just written into):
|
|
@@ -221,7 +253,11 @@ npx universal-plugin marketplace validate --root .
|
|
|
221
253
|
```
|
|
222
254
|
|
|
223
255
|
This is the same check `marketplace init`/`build` rely on — it catches an entry shape no runtime can
|
|
224
|
-
load (a bad `source`, a missing required key) before it reaches a PR.
|
|
256
|
+
load (a bad `source`, a missing required key) before it reaches a PR. In the Claude catalog it also
|
|
257
|
+
reports a plain dependency the catalog does not list and a dependency on a marketplace missing from
|
|
258
|
+
`allowCrossMarketplaceDependenciesOn`, as far as it can see them offline (an entry's own
|
|
259
|
+
`dependencies`, and plugins at `./` paths) — so it does not replace 2f for a plugin listed from npm
|
|
260
|
+
or git. Fix any reported issue and
|
|
225
261
|
re-run before continuing. Do not open the PR while validation fails.
|
|
226
262
|
|
|
227
263
|
---
|
|
@@ -266,7 +302,7 @@ git checkout -b add-<plugin-name>
|
|
|
266
302
|
|
|
267
303
|
### 3c. Edit all detected marketplace files
|
|
268
304
|
|
|
269
|
-
For each vendor marketplace file detected in Step 2a, append the plugin entry to its `plugins` array. Preserve formatting and all existing entries exactly. Stage all changed files together.
|
|
305
|
+
For each vendor marketplace file detected in Step 2a, append the plugin entry — and the entry of each dependency 2f listed — to its `plugins` array, and add any `allowCrossMarketplaceDependenciesOn` change the user accepted in 2f. Preserve formatting and all existing entries exactly. Stage all changed files together.
|
|
270
306
|
|
|
271
307
|
### 3d. Commit and push
|
|
272
308
|
|
|
@@ -319,6 +355,8 @@ gh pr create \
|
|
|
319
355
|
- [ ] Semver version string
|
|
320
356
|
- [ ] SPDX license identifier
|
|
321
357
|
- [ ] Entry appended to each detected marketplace file
|
|
358
|
+
- [ ] Every plain dependency is listed in this marketplace (here or already)
|
|
359
|
+
- [ ] Every marketplace a dependency names is in `allowCrossMarketplaceDependenciesOn`, or noted as not needed
|
|
322
360
|
EOF
|
|
323
361
|
)"
|
|
324
362
|
```
|
|
@@ -337,7 +375,8 @@ Return the PR URL to the user when done.
|
|
|
337
375
|
| Name conflict in marketplace | Check existing entries in each marketplace file first |
|
|
338
376
|
| Plugin loads but skills missing | Add `skills` array to the Claude Code marketplace entry |
|
|
339
377
|
| Entry installs nothing for a monorepo plugin | `source` was `url`/root-clone instead of `git-subdir` — redo 2b/2c with the plugin's actual repo-relative path |
|
|
340
|
-
|
|
|
378
|
+
| Install fails resolving a dependency | 2f was skipped — list the plain dependency in this marketplace, or allow the named marketplace in `allowCrossMarketplaceDependenciesOn` |
|
|
379
|
+
| `marketplace validate` fails after 2g | Fix the reported shape before opening the PR — do not open it while validation fails |
|
|
341
380
|
| Entry's `repository`/`source.url` points at the marketplace repo | Step 0 role detection was skipped or overridden wrongly — re-check which repo the cwd is |
|
|
342
381
|
|
|
343
382
|
---
|
|
@@ -30,6 +30,12 @@
|
|
|
30
30
|
"prompt": "I'm a maintainer of cyberuni/marketplace and I already have it checked out here. I want to add a plugin called 'db-migrate' that lives at github.com/someuser/db-migrate. Add it.",
|
|
31
31
|
"expected_output": "Detects the cwd is the marketplace repo itself, not the plugin, so it reads the plugin's metadata from the given URL (cloning it to a scratch location) instead of the cwd, then works directly in the existing checkout (fetch/merge, branch, edit, commit, push, PR) rather than cloning or forking cyberuni/marketplace again. The prepared entry's source/repository URL points at db-migrate's repo, not at cyberuni/marketplace.",
|
|
32
32
|
"files": []
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"id": 6,
|
|
36
|
+
"prompt": "Publish buddy-agent-harness (in ~/code/buddy-agent-harness) to the cyberplace marketplace. Its plugin.json declares dependencies [\"agent-harness\", { \"name\": \"cyber-asana\", \"marketplace\": \"cyberuni\" }]. cyberplace's .claude-plugin/marketplace.json does not list agent-harness and has no allowCrossMarketplaceDependenciesOn.",
|
|
37
|
+
"expected_output": "Reads the plugin's dependencies before submitting. Treats \"agent-harness\" as a plain dependency resolved against cyberplace: since cyberplace does not list it, prepares agent-harness's entry in the same PR from its own repository/package (after pre-flight), or stops and tells the user to publish agent-harness first — never opens a PR listing buddy-agent-harness without it. Treats cyber-asana@cyberuni as a named-marketplace dependency: adds no entry for it, says installs from cyberplace need \"cyberuni\" in allowCrossMarketplaceDependenciesOn, and offers to add it.",
|
|
38
|
+
"files": []
|
|
33
39
|
}
|
|
34
40
|
]
|
|
35
41
|
}
|
package/skills/version/README.md
CHANGED
|
@@ -18,7 +18,7 @@ The first question the skill asks is whether the repository uses changesets.
|
|
|
18
18
|
|
|
19
19
|
- **With changesets** — the number is decided by the release, not by this skill. Add a changeset, let
|
|
20
20
|
the release run, and `publish sync-version` carries the released number into the canonical
|
|
21
|
-
manifest.
|
|
21
|
+
manifest and re-derives the vendor manifests. With `--no-build`, `plugin build` is the next step.
|
|
22
22
|
- **Without** — `plugin version <bump>` is the whole step. `scripts/version.mjs` runs it from the CLI
|
|
23
23
|
shipped beside the skill, so nothing is downloaded.
|
|
24
24
|
|
package/skills/version/SKILL.md
CHANGED
|
@@ -22,12 +22,17 @@ test -d .changeset && echo "changesets"
|
|
|
22
22
|
|
|
23
23
|
**If it does**, the version number is decided by changesets, not by you. Add a changeset and let the
|
|
24
24
|
release run — the repo's `version` script should already call `publish sync-version`, which carries
|
|
25
|
-
the released number from `package.json` into the canonical manifest
|
|
25
|
+
the released number from `package.json` into the canonical manifest and re-derives the vendor
|
|
26
|
+
manifests, the same way `plugin version` does:
|
|
26
27
|
|
|
27
28
|
```bash
|
|
28
29
|
npx universal-plugin publish sync-version
|
|
29
30
|
```
|
|
30
31
|
|
|
32
|
+
If the script passes `--no-build`, it must run `plugin build` next (`/universal-plugin:build-plugin`);
|
|
33
|
+
otherwise the vendor manifests and `com.github.copilot/` keep the old version, and a consumer's
|
|
34
|
+
plugin cache never re-extracts.
|
|
35
|
+
|
|
31
36
|
Do **not** run `plugin version` in a changesets repo — it would decide a number changesets is about
|
|
32
37
|
to decide again.
|
|
33
38
|
|
|
@@ -109,6 +114,7 @@ Every guard resolves before the first write, so a failed run leaves the tree unt
|
|
|
109
114
|
| Task | Skill |
|
|
110
115
|
|------|-------|
|
|
111
116
|
| Create, adopt, or change what the plugin declares | `init-universal-plugin` |
|
|
117
|
+
| Re-derive the vendor manifests by hand | `build-plugin` |
|
|
112
118
|
| Check whether the two authored versions agree | `doctor` |
|
|
113
119
|
| Add a changeset for the change being released | `add-changeset` |
|
|
114
120
|
| Refresh the repository's own marketplace catalogs after a bump | `marketplace` |
|