universal-plugin 0.17.1 → 0.18.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/CHANGELOG.md +16 -0
- package/dist/cli.mjs +162 -10
- package/package.json +1 -1
- package/plugin.json +1 -1
- package/skills/adopt-upx/scripts/rewrite-upx.mjs +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 +16 -4
- package/skills/doctor-universal-plugin/scripts/doctor.mjs +225 -2
- package/skills/init-universal-plugin/SKILL.md +60 -1
- package/skills/init-universal-plugin/references/create.md +4 -1
- package/skills/init-universal-plugin/references/release-tools.md +272 -0
- package/skills/init-universal-plugin/scripts/init.mjs +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/update.mjs +1 -1
- package/skills/marketplace/scripts/validate.mjs +1 -1
- package/skills/version/README.md +5 -1
- package/skills/version/SKILL.md +126 -7
- package/skills/version/scripts/version.mjs +1 -1
|
@@ -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.18.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 update":"skills/marketplace/scripts/update.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";
|
|
@@ -51,6 +51,17 @@ const marketplaceRoots = argv.flatMap((arg, i) => arg === "--marketplace-root" ?
|
|
|
51
51
|
const findings = [];
|
|
52
52
|
/** semantic-release's version placeholder until its publish run stamps the real number. */
|
|
53
53
|
const UNSTAMPED_VERSION = "0.0.0-development";
|
|
54
|
+
/** The config files release-it reads, besides the `release-it` key of package.json. */
|
|
55
|
+
const RELEASE_IT_FILES = [
|
|
56
|
+
"json",
|
|
57
|
+
"yaml",
|
|
58
|
+
"yml",
|
|
59
|
+
"toml",
|
|
60
|
+
"js",
|
|
61
|
+
"cjs",
|
|
62
|
+
"mjs",
|
|
63
|
+
"ts"
|
|
64
|
+
].map((ext) => `.release-it.${ext}`);
|
|
54
65
|
const add = (code, severity, detail, repair) => findings.push({
|
|
55
66
|
code,
|
|
56
67
|
severity,
|
|
@@ -187,7 +198,7 @@ if (packagePath !== void 0 && !packageMissing) {
|
|
|
187
198
|
if (manifest.version !== void 0 && pkg.version !== UNSTAMPED_VERSION && pkg.version !== manifest.version) add("version-drift", "high", `plugin.json is ${manifest.version}, ${packagePath}/package.json is ${pkg.version}`, "/universal-plugin:version");
|
|
188
199
|
}
|
|
189
200
|
}
|
|
190
|
-
if (manifest.version !== void 0 && packagePath === null) {
|
|
201
|
+
if (manifest.version !== void 0 && packagePath === null && releaseTool() === null) {
|
|
191
202
|
const introduced = commitThatSetVersion(manifest.version);
|
|
192
203
|
if (introduced !== null) {
|
|
193
204
|
const files = (git("diff", "--name-only", `${introduced}..HEAD`, "--", ...shippedPaths()) ?? "").split("\n").filter(Boolean);
|
|
@@ -197,6 +208,10 @@ if (manifest.version !== void 0 && packagePath === null) {
|
|
|
197
208
|
}
|
|
198
209
|
}
|
|
199
210
|
}
|
|
211
|
+
for (const finding of changesetsReleaseFindings()) add(...finding);
|
|
212
|
+
for (const finding of releasePleaseReleaseFindings()) add(...finding);
|
|
213
|
+
for (const file of releaseItConfigsWithoutStamp()) add("release-it-no-stamp", "high", `${file} configures release-it, but no hook runs plugin version — the release is tagged with plugin.json and the vendor manifests still on the previous version`, "add \"hooks\": { \"after:bump\": \"universal-plugin plugin version ${version}\" } to the release-it config");
|
|
214
|
+
for (const finding of semanticReleaseFindings()) add(...finding);
|
|
200
215
|
const missingMarketplaceRoots = marketplaceRoots.filter((r) => !fs.existsSync(path.resolve(r)));
|
|
201
216
|
for (const r of missingMarketplaceRoots) add("marketplace-root-missing", "high", `--marketplace-root ${r} does not exist`, "clone the marketplace repository, or fix the path");
|
|
202
217
|
const existingMarketplaceRoots = marketplaceRoots.filter((r) => fs.existsSync(path.resolve(r)));
|
|
@@ -222,6 +237,214 @@ function invalidCatalogs(extraRoots) {
|
|
|
222
237
|
})) : [];
|
|
223
238
|
});
|
|
224
239
|
}
|
|
240
|
+
/** The release-config gaps of a non-npm plugin in a changesets repository: no `packagePath`, and a
|
|
241
|
+
* plugin-root package.json that is absent or private. An npm-shipped plugin is not checked here —
|
|
242
|
+
* `changeset publish` there publishes to npm whatever the private-package settings say. */
|
|
243
|
+
function changesetsReleaseFindings() {
|
|
244
|
+
if (packagePath !== null) return [];
|
|
245
|
+
const repoRoot = git("rev-parse", "--show-toplevel") ?? root;
|
|
246
|
+
const workspace = changesetsWorkspace(repoRoot);
|
|
247
|
+
if (workspace === void 0) return [];
|
|
248
|
+
const pkg = readJson(path.join(root, "package.json"));
|
|
249
|
+
const out = [];
|
|
250
|
+
if (pkg === null) out.push([
|
|
251
|
+
"changesets-no-package",
|
|
252
|
+
"high",
|
|
253
|
+
"the repository is released with changesets, but the plugin root has no package.json — changesets releases only a package, so changeset version and changeset publish fail",
|
|
254
|
+
"/universal-plugin:init-universal-plugin — it writes a private package.json (name, \"private\": true, version)"
|
|
255
|
+
]);
|
|
256
|
+
const setting = readJson(path.join(workspace, ".changeset", "config.json"))?.privatePackages;
|
|
257
|
+
if (!(typeof setting === "object" && setting !== null && setting.version !== false && setting.tag === true)) out.push([
|
|
258
|
+
"changesets-private-untagged",
|
|
259
|
+
"high",
|
|
260
|
+
".changeset/config.json does not set \"privatePackages\": { \"version\": true, \"tag\": true } — changeset publish creates no tag for a private package, so no release is made",
|
|
261
|
+
"set \"privatePackages\": { \"version\": true, \"tag\": true } in .changeset/config.json"
|
|
262
|
+
]);
|
|
263
|
+
for (const workflow of changesetsWorkflowsWithoutPublish(repoRoot)) out.push([
|
|
264
|
+
"changesets-no-publish-script",
|
|
265
|
+
"high",
|
|
266
|
+
`${workflow} runs changesets/action with no publish script — after the Version Packages PR merges it does nothing, so no tag or release is made`,
|
|
267
|
+
"add `publish-script: pnpm release` (changesets/action v1: `publish:`) to the changesets/action step, with a \"release\" script running changeset publish"
|
|
268
|
+
]);
|
|
269
|
+
return out;
|
|
270
|
+
}
|
|
271
|
+
/** The directory holding `.changeset/` for a non-npm plugin a changesets repository releases: the
|
|
272
|
+
* plugin root or the repository root, with a plugin-root package.json that is absent or private.
|
|
273
|
+
* `undefined` when changesets does not release this plugin as a non-npm one. */
|
|
274
|
+
function changesetsWorkspace(repoRoot) {
|
|
275
|
+
const workspace = [root, repoRoot].find((dir) => fs.existsSync(path.join(dir, ".changeset")));
|
|
276
|
+
if (workspace === void 0) return void 0;
|
|
277
|
+
const pkg = readJson(path.join(root, "package.json"));
|
|
278
|
+
return pkg !== null && pkg.private !== true ? void 0 : workspace;
|
|
279
|
+
}
|
|
280
|
+
/** The release tool that picks a non-npm plugin's next version, or `null` when the author picks it
|
|
281
|
+
* (ADR-0010 §6). Each tool moves the number at release time, from what accumulated since the last
|
|
282
|
+
* release: changesets from changeset files, release-please and semantic-release from commits,
|
|
283
|
+
* release-it from its prompt or increment argument. Config is looked for where each tool loads it:
|
|
284
|
+
* the plugin root and the repository root. */
|
|
285
|
+
function releaseTool() {
|
|
286
|
+
const repoRoot = git("rev-parse", "--show-toplevel") ?? root;
|
|
287
|
+
if (changesetsWorkspace(repoRoot) !== void 0) return "changesets";
|
|
288
|
+
const rpConfig = readJson(path.join(repoRoot, "release-please-config.json"));
|
|
289
|
+
if (rpConfig !== null && releasePleaseBumpsManifest(rpConfig, repoRoot)) return "release-please";
|
|
290
|
+
const dirs = [.../* @__PURE__ */ new Set([root, repoRoot])];
|
|
291
|
+
if (dirs.some((dir) => semanticReleaseConfig(dir) !== null)) return "semantic-release";
|
|
292
|
+
if (dirs.some((dir) => hasConfig(dir, RELEASE_IT_FILES, "release-it"))) return "release-it";
|
|
293
|
+
return null;
|
|
294
|
+
}
|
|
295
|
+
/** Whether `dir` holds one of the config files `files`, or a package.json carrying `key`. */
|
|
296
|
+
function hasConfig(dir, files, key) {
|
|
297
|
+
if (files.some((file) => fs.existsSync(path.join(dir, file)))) return true;
|
|
298
|
+
const pkg = readJson(path.join(dir, "package.json"));
|
|
299
|
+
return pkg !== null && typeof pkg === "object" && Object.hasOwn(pkg, key);
|
|
300
|
+
}
|
|
301
|
+
/** The release-please gap of a non-npm plugin: `release-please-config.json` bumps this plugin's
|
|
302
|
+
* plugin.json through `extra-files`, and no workflow runs `plugin version` to restamp the rest, or
|
|
303
|
+
* the restamp is pushed with the default `GITHUB_TOKEN` and so gets no checks. A plugin with `packagePath` is not checked: its number comes from the package, through
|
|
304
|
+
* `--from-package`. */
|
|
305
|
+
function releasePleaseReleaseFindings() {
|
|
306
|
+
if (packagePath !== null) return [];
|
|
307
|
+
const repoRoot = git("rev-parse", "--show-toplevel") ?? root;
|
|
308
|
+
const config = readJson(path.join(repoRoot, "release-please-config.json"));
|
|
309
|
+
if (config === null || !releasePleaseBumpsManifest(config, repoRoot)) return [];
|
|
310
|
+
if (!workflowsMention(repoRoot, /plugin version|version\.mjs/)) return [[
|
|
311
|
+
"release-please-no-restamp",
|
|
312
|
+
"high",
|
|
313
|
+
"release-please-config.json bumps plugin.json through extra-files, but no workflow runs plugin version — the release PR leaves the vendor manifests, catalogs, skill pins and compiled scripts on the old version",
|
|
314
|
+
"add a workflow step on the release PR branch that runs `universal-plugin plugin version --from-manifest` and pushes the stamped files (see the version skill)"
|
|
315
|
+
]];
|
|
316
|
+
return restampWorkflowsWithoutCi(repoRoot).map((workflow) => [
|
|
317
|
+
"release-please-restamp-no-ci",
|
|
318
|
+
"medium",
|
|
319
|
+
`${workflow} pushes the --from-manifest restamp with the default GITHUB_TOKEN — that push starts no workflow run, so the release PR's checks never run on its head commit and a required check blocks the merge`,
|
|
320
|
+
"mint a GitHub App token with actions/create-github-app-token and pass it to release-please-action and actions/checkout as `token:` (see the version skill)"
|
|
321
|
+
]);
|
|
322
|
+
}
|
|
323
|
+
/** Workflow files that restamp with `--from-manifest`, push, and leave the push on the default
|
|
324
|
+
* `GITHUB_TOKEN`, which starts no workflow run. Read as text, so it clears a file on any sign of
|
|
325
|
+
* another credential: a GitHub App token, a deploy key, or a `token:` input that is not the default
|
|
326
|
+
* token. A workflow dispatch does not clear it: its checks do not count toward a required check. */
|
|
327
|
+
function restampWorkflowsWithoutCi(repoRoot) {
|
|
328
|
+
const startsCi = /create-github-app-token|ssh-key:|token:\s*\$\{\{(?!\s*(?:secrets\.GITHUB_TOKEN|github\.token)\b)/;
|
|
329
|
+
return workflowFiles(repoRoot).filter(({ text }) => /--from-manifest/.test(text) && /git push/.test(text) && !startsCi.test(text)).map(({ file }) => file);
|
|
330
|
+
}
|
|
331
|
+
/** Whether a release-please config lists this plugin's plugin.json in `extra-files`. A package's own
|
|
332
|
+
* `extra-files` replaces the top-level default. A path is relative to the package path, or to the
|
|
333
|
+
* repository root with a leading `/`. */
|
|
334
|
+
function releasePleaseBumpsManifest(config, repoRoot) {
|
|
335
|
+
const target = path.join(root, "plugin.json");
|
|
336
|
+
const packages = config.packages ?? {};
|
|
337
|
+
return Object.entries(packages).some(([packageDir, options]) => {
|
|
338
|
+
const extra = options?.["extra-files"] ?? config["extra-files"];
|
|
339
|
+
if (!Array.isArray(extra)) return false;
|
|
340
|
+
return extra.some((entry) => {
|
|
341
|
+
const file = typeof entry === "string" ? entry : entry?.path;
|
|
342
|
+
if (typeof file !== "string") return false;
|
|
343
|
+
return (file.startsWith("/") ? path.join(repoRoot, file) : path.join(repoRoot, packageDir, file)) === target;
|
|
344
|
+
});
|
|
345
|
+
});
|
|
346
|
+
}
|
|
347
|
+
/** The semantic-release wiring gaps, for the config at the plugin root and at the repository root.
|
|
348
|
+
* Each config is read as text, so a JavaScript config is checked only for what it names. A config
|
|
349
|
+
* that `extends` a shareable config is skipped: the wiring may live in the shared one. */
|
|
350
|
+
function semanticReleaseFindings() {
|
|
351
|
+
const repoRoot = git("rev-parse", "--show-toplevel") ?? root;
|
|
352
|
+
return [.../* @__PURE__ */ new Set([root, repoRoot])].flatMap((dir) => {
|
|
353
|
+
const config = semanticReleaseConfig(dir);
|
|
354
|
+
if (config === null || /\bextends\b/.test(config.text)) return [];
|
|
355
|
+
const label = path.relative(root, path.join(dir, config.file)) || config.file;
|
|
356
|
+
const out = [];
|
|
357
|
+
if (!/\bprepareCmd\b['"]?\s*:\s*(?:[>|][-+]?\s*\n\s*)?[^,\n}]*(?:\bplugin\s+version\b|version\.mjs)/.test(config.text)) out.push([
|
|
358
|
+
"semantic-release-no-stamp",
|
|
359
|
+
"high",
|
|
360
|
+
`${label} configures semantic-release, but no @semantic-release/exec prepareCmd runs plugin version — the release is tagged with plugin.json, the vendor manifests and the catalogs still on the previous version`,
|
|
361
|
+
"add [\"@semantic-release/exec\", { \"prepareCmd\": \"universal-plugin plugin version ${nextRelease.version}\" }] before @semantic-release/git — /universal-plugin:init-universal-plugin wires it"
|
|
362
|
+
]);
|
|
363
|
+
const runsNpm = /@semantic-release\/npm(?![\w-])/.test(config.text) || !/\bplugins\b/.test(config.text);
|
|
364
|
+
if (packagePath === null && runsNpm) out.push([
|
|
365
|
+
"semantic-release-npm-unshipped",
|
|
366
|
+
"high",
|
|
367
|
+
`${label} runs @semantic-release/npm, but the plugin ships to no npm package — with no package.json the release fails (ENOPKG), and with one it still rewrites that version`,
|
|
368
|
+
"remove @semantic-release/npm from the plugins list (write the list out if the config relies on the defaults) — /universal-plugin:init-universal-plugin wires it"
|
|
369
|
+
]);
|
|
370
|
+
return out;
|
|
371
|
+
});
|
|
372
|
+
}
|
|
373
|
+
/** The semantic-release config semantic-release would read in `dir`, as text, or `null` when there
|
|
374
|
+
* is none. The search order is cosmiconfig 9's default for the module name `release`: the `release`
|
|
375
|
+
* key of package.json, then the files below. The first one found is the only one read. */
|
|
376
|
+
function semanticReleaseConfig(dir) {
|
|
377
|
+
const rc = [
|
|
378
|
+
"",
|
|
379
|
+
".json",
|
|
380
|
+
".yaml",
|
|
381
|
+
".yml",
|
|
382
|
+
".js",
|
|
383
|
+
".ts",
|
|
384
|
+
".cjs",
|
|
385
|
+
".mjs"
|
|
386
|
+
];
|
|
387
|
+
const files = [
|
|
388
|
+
...rc.map((ext) => `.releaserc${ext}`),
|
|
389
|
+
...rc.map((ext) => `.config/releaserc${ext}`),
|
|
390
|
+
...[
|
|
391
|
+
".js",
|
|
392
|
+
".ts",
|
|
393
|
+
".cjs",
|
|
394
|
+
".mjs"
|
|
395
|
+
].map((ext) => `release.config${ext}`)
|
|
396
|
+
];
|
|
397
|
+
const fromPackage = readJson(path.join(dir, "package.json"))?.release;
|
|
398
|
+
if (fromPackage !== void 0 && fromPackage !== null) return {
|
|
399
|
+
file: "package.json",
|
|
400
|
+
text: JSON.stringify(fromPackage, null, 2)
|
|
401
|
+
};
|
|
402
|
+
for (const file of files) {
|
|
403
|
+
const abs = path.join(dir, file);
|
|
404
|
+
if (fs.existsSync(abs) && fs.statSync(abs).isFile()) return {
|
|
405
|
+
file,
|
|
406
|
+
text: fs.readFileSync(abs, "utf8")
|
|
407
|
+
};
|
|
408
|
+
}
|
|
409
|
+
return null;
|
|
410
|
+
}
|
|
411
|
+
/** Whether any workflow file's text matches. */
|
|
412
|
+
function workflowsMention(repoRoot, pattern) {
|
|
413
|
+
return workflowFiles(repoRoot).some(({ text }) => pattern.test(text));
|
|
414
|
+
}
|
|
415
|
+
/** The workflow files under `.github/workflows`, each with its path from the repository root and its text. */
|
|
416
|
+
function workflowFiles(repoRoot) {
|
|
417
|
+
const dir = path.join(repoRoot, ".github", "workflows");
|
|
418
|
+
if (!fs.existsSync(dir)) return [];
|
|
419
|
+
return fs.readdirSync(dir).filter((file) => /\.ya?ml$/.test(file)).map((file) => ({
|
|
420
|
+
file: `.github/workflows/${file}`,
|
|
421
|
+
text: fs.readFileSync(path.join(dir, file), "utf8")
|
|
422
|
+
}));
|
|
423
|
+
}
|
|
424
|
+
/** Workflow files that run changesets/action and give it no publish command. Read as text: a step
|
|
425
|
+
* names it as `publish-script:` (v2) or `publish:` (v1). */
|
|
426
|
+
function changesetsWorkflowsWithoutPublish(repoRoot) {
|
|
427
|
+
const dir = path.join(repoRoot, ".github", "workflows");
|
|
428
|
+
if (!fs.existsSync(dir)) return [];
|
|
429
|
+
return fs.readdirSync(dir).filter((file) => /\.ya?ml$/.test(file)).filter((file) => {
|
|
430
|
+
const text = fs.readFileSync(path.join(dir, file), "utf8");
|
|
431
|
+
return /uses:\s*['"]?changesets\/action@/.test(text) && !/^\s*(publish-script|publish)\s*:/m.test(text);
|
|
432
|
+
}).map((file) => `.github/workflows/${file}`);
|
|
433
|
+
}
|
|
434
|
+
/** release-it configs, at the plugin root or the repository root, that never call `plugin version`.
|
|
435
|
+
* release-it reads `.release-it.{json,yaml,yml,toml,js,cjs,mjs,ts}` or the `release-it` key of
|
|
436
|
+
* package.json. Each is read as text, so the check is only that the stamp is named somewhere. */
|
|
437
|
+
function releaseItConfigsWithoutStamp() {
|
|
438
|
+
const repoRoot = git("rev-parse", "--show-toplevel") ?? root;
|
|
439
|
+
const stamps = (text) => /\bplugin\s+version\b/.test(text);
|
|
440
|
+
return [.../* @__PURE__ */ new Set([root, repoRoot])].flatMap((dir) => {
|
|
441
|
+
const label = (file) => path.relative(root, path.join(dir, file)) || file;
|
|
442
|
+
const found = RELEASE_IT_FILES.filter((file) => fs.existsSync(path.join(dir, file))).filter((file) => !stamps(fs.readFileSync(path.join(dir, file), "utf8"))).map(label);
|
|
443
|
+
const config = readJson(path.join(dir, "package.json"))?.["release-it"];
|
|
444
|
+
if (config !== void 0 && !stamps(JSON.stringify(config))) found.push(label("package.json"));
|
|
445
|
+
return found;
|
|
446
|
+
});
|
|
447
|
+
}
|
|
225
448
|
/** Runs git inside `root`, returning its stdout or `null` — a non-zero status, a missing git, and a
|
|
226
449
|
* directory outside any repository are all the same answer here: no history to read. */
|
|
227
450
|
function git(...args) {
|
|
@@ -70,6 +70,9 @@ covers moving one that sits in the wrong place.
|
|
|
70
70
|
|
|
71
71
|
Inventory both the canonical surface (root `plugin.json`, its `extensions` block, the component
|
|
72
72
|
directories it names) and every pre-existing vendor artifact listed in `references/detection.md`.
|
|
73
|
+
Note the release tool the repository uses, if any: `.changeset/` (changesets), `.releaserc*`,
|
|
74
|
+
`release.config.*`, or a `release` key in `package.json` (semantic-release), `.release-it.*` or a
|
|
75
|
+
`release-it` key in `package.json` (release-it), or `release-please-config.json` (release-please).
|
|
73
76
|
Read what you find. Write nothing yet.
|
|
74
77
|
|
|
75
78
|
## 2. Classify
|
|
@@ -126,9 +129,63 @@ plan, and ask before running init: it rewrites the user's root `package.json`. I
|
|
|
126
129
|
run init without `--npm` and wire `files` by hand. A custom `version` script is never rewritten;
|
|
127
130
|
init prints the line to append, so relay it and let the user place it.
|
|
128
131
|
|
|
132
|
+
A plugin that ships to **no** npm package in a changesets repository gets its own plan line.
|
|
133
|
+
Changesets releases only a package, so when the repository root carries `.changeset/` and the plugin
|
|
134
|
+
root has no `package.json`, `plugin init` writes a minimal private one: `name` from the plugin name,
|
|
135
|
+
`"private": true`, and `version` from the `plugin.json` it replaces (else `0.0.0`), with no `files`,
|
|
136
|
+
`main`, or `exports`. It also wires the root `version` script as above and adds
|
|
137
|
+
`"release": "changeset publish"`, which tags the release for changesets/action. Offer this in the
|
|
138
|
+
plan and show the file; if the user declines, add `--no-changesets` to the init call. Relay init's
|
|
139
|
+
notes: a plugin below the repository root must be a workspace package, and `.changeset/config.json`
|
|
140
|
+
needs `"privatePackages": { "version": true, "tag": true }` before `changeset publish` tags anything.
|
|
141
|
+
|
|
142
|
+
A plugin released with **semantic-release** gets the release wiring as a plan line too.
|
|
143
|
+
`plugin init` writes nothing for it, so the skill edits the config itself, once the user approves.
|
|
144
|
+
Add `@semantic-release/exec` with
|
|
145
|
+
`prepareCmd: "universal-plugin plugin version ${nextRelease.version}"`, and add
|
|
146
|
+
`@semantic-release/git` with the stamped files as `assets`. For a plugin that ships to no npm
|
|
147
|
+
package, also drop `@semantic-release/npm`: `npmPublish: false` is not enough, because the plugin
|
|
148
|
+
still edits `package.json`. Show the `plugins` list before and after, and edit the config file the
|
|
149
|
+
survey found, in its own format. [`references/release-tools.md`](./references/release-tools.md) has
|
|
150
|
+
the config, the plugin order, the full `assets` list, and the packages the release job must
|
|
151
|
+
install. If the user declines, leave the config alone.
|
|
152
|
+
|
|
153
|
+
A plugin released with **release-it** gets its wiring as a plan line as well. Add an `after:bump`
|
|
154
|
+
hook running `universal-plugin plugin version ${version}`, after any hook the user already has. For a
|
|
155
|
+
plugin that ships to no npm package, also set `"npm": false`, and run the hook through the pinned
|
|
156
|
+
`npx universal-plugin@0.18.0`. release-it then reads the current number from the latest git tag,
|
|
157
|
+
so when `git describe --tags` finds none, propose tagging the current commit with the version
|
|
158
|
+
`plugin.json` holds (`git tag v1.2.0`). Without that tag the first release starts from `0.0.0` and
|
|
159
|
+
fails. Create the tag only once the user approves, and leave pushing it to the user.
|
|
160
|
+
|
|
161
|
+
A plugin released with **release-please** gets its wiring as a plan line too. For a plugin that
|
|
162
|
+
ships to no npm package, write `release-please-config.json` with `release-type: simple` and an
|
|
163
|
+
`extra-files` entry bumping `plugin.json`. Put the version `plugin.json` holds in
|
|
164
|
+
`.release-please-manifest.json`, so the first release PR starts from it. The restamp runs in a
|
|
165
|
+
workflow step on the release PR and pushes with a GitHub App token, so the PR's checks run. Show that
|
|
166
|
+
step and the App setup, and hand both to the user.
|
|
167
|
+
|
|
168
|
+
[`references/release-tools.md`](./references/release-tools.md) has the configs for release-it and
|
|
169
|
+
release-please, the npm-shipped variants, and the tag and manifest checks. Show each file before and
|
|
170
|
+
after. If the user declines, leave the config alone.
|
|
171
|
+
|
|
172
|
+
When the survey found **no** release tool, ask the user how the plugin will be released before
|
|
173
|
+
running init. A new repository may simply not have set one up yet:
|
|
174
|
+
|
|
175
|
+
- **changesets.** Set up `.changeset/` first (`buddy-changesets:init-changesets` when it is
|
|
176
|
+
installed, else `npx @changesets/cli init`), then run init. It then finds `.changeset/` and writes
|
|
177
|
+
the private `package.json` above.
|
|
178
|
+
- **semantic-release.** Propose a new `.releaserc.json` carrying the wiring above, and write it once
|
|
179
|
+
the user approves. No `package.json` is needed.
|
|
180
|
+
- **release-it.** Propose a new `.release-it.json` carrying the wiring above, with the initial tag
|
|
181
|
+
for a plugin that ships to no npm package. Write it once the user approves.
|
|
182
|
+
- **release-please.** Propose `release-please-config.json` and `.release-please-manifest.json` as
|
|
183
|
+
above, and hand over the workflow step. Write them once the user approves.
|
|
184
|
+
- **None.** Run init as planned. The author picks each number with `version`.
|
|
185
|
+
|
|
129
186
|
## 4. Apply
|
|
130
187
|
|
|
131
|
-
Route by what Phase 2 found. Read exactly the reference for the work at hand — do not load all
|
|
188
|
+
Route by what Phase 2 found. Read exactly the reference for the work at hand — do not load them all.
|
|
132
189
|
|
|
133
190
|
| What Phase 2 found | Do this | Reference |
|
|
134
191
|
| --- | --- | --- |
|
|
@@ -227,6 +284,8 @@ This skill is not a formatter. If the project has one, run it over the written f
|
|
|
227
284
|
- **Offer adoption once.** If the user declines, or asked for something unrelated, drop it and do
|
|
228
285
|
what they asked.
|
|
229
286
|
- Plugin authoring only. Do not change CI workflows, repository settings, or unrelated project files.
|
|
287
|
+
The release tool's config is the one file outside the plugin this skill edits, and only once the
|
|
288
|
+
user approves it in Phase 3. The one git write is release-it's initial tag, on the same approval.
|
|
230
289
|
|
|
231
290
|
## Related skills
|
|
232
291
|
|
|
@@ -43,10 +43,13 @@ 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.18.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).
|
|
50
|
+
Without `--npm`, in a changesets repository with no `package.json` at the plugin root, init writes a
|
|
51
|
+
private `package.json` so changesets can release the plugin (SKILL.md Phase 3 offers it; pass
|
|
52
|
+
`--no-changesets` when the user declines).
|
|
50
53
|
|
|
51
54
|
`init` writes a minimal manifest — `$schema`, `name`, the vendor list, and the package `version`
|
|
52
55
|
under `--npm`. Fill in the Step 1
|
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
# Release tool wiring
|
|
2
|
+
|
|
3
|
+
Each release tool decides the release number in its own way. The plugin still needs that number
|
|
4
|
+
stamped into `plugin.json`, the vendor manifests, the catalogs, and the skill pins. The `version`
|
|
5
|
+
skill owns the stamp: `plugin version` with a number the tool hands it. This file covers the wiring
|
|
6
|
+
that makes a release tool call it.
|
|
7
|
+
|
|
8
|
+
`plugin init` writes the changesets wiring itself (SKILL.md Phase 3). It writes nothing for the
|
|
9
|
+
other tools. Their config takes several file formats, JavaScript modules among them, and it often
|
|
10
|
+
carries plugins the user added. Editing it is a judgment call, so the skill makes the edit and the
|
|
11
|
+
user approves it.
|
|
12
|
+
|
|
13
|
+
| Tool | Config the survey finds | Wiring |
|
|
14
|
+
| --- | --- | --- |
|
|
15
|
+
| changesets | `.changeset/` | `plugin init` writes it (SKILL.md Phase 3) |
|
|
16
|
+
| semantic-release | `.releaserc`, `.releaserc.{json,yaml,yml,js,cjs,mjs}`, `release.config.{js,cjs,mjs}`, or a `release` key in `package.json` | [below](#semantic-release) |
|
|
17
|
+
| release-it | `.release-it.{json,yaml,yml,toml,js,cjs,ts}`, or a `release-it` key in `package.json` | [below](#release-it) |
|
|
18
|
+
| release-please | `release-please-config.json`, `.release-please-manifest.json` | [below](#release-please) |
|
|
19
|
+
|
|
20
|
+
## semantic-release
|
|
21
|
+
|
|
22
|
+
semantic-release writes the version only during its own run. Two plugins carry the number into the
|
|
23
|
+
plugin:
|
|
24
|
+
|
|
25
|
+
- **`@semantic-release/exec`** runs the stamp in its `prepare` step:
|
|
26
|
+
`prepareCmd: "universal-plugin plugin version ${nextRelease.version}"`. semantic-release fills in
|
|
27
|
+
`${nextRelease.version}` with its lodash template. Add `--root <plugin-root>` when the plugin root
|
|
28
|
+
is not the repository root.
|
|
29
|
+
- **`@semantic-release/git`** commits the stamped files back. Copilot CLI and GitHub-hosted
|
|
30
|
+
marketplaces read `plugin.json` from the repository, not from a package, so without this commit
|
|
31
|
+
those channels never see the new number (ADR-0010 §2).
|
|
32
|
+
|
|
33
|
+
A `plugins` list replaces semantic-release's default list. It does not merge with it. The defaults
|
|
34
|
+
are `commit-analyzer`, `release-notes-generator`, `npm`, and `github`. A config with no `plugins`
|
|
35
|
+
key therefore gets the full list written out, minus whatever the case below drops.
|
|
36
|
+
|
|
37
|
+
Within each step, plugins run in list order. Put `exec` after `npm` and before `git`. That way `npm`
|
|
38
|
+
moves `package.json` first, `exec` stamps the plugin, and `git` commits both.
|
|
39
|
+
|
|
40
|
+
### A plugin that ships to no npm package
|
|
41
|
+
|
|
42
|
+
Drop `@semantic-release/npm` from the list. `npmPublish: false` does not cover this: the plugin
|
|
43
|
+
still sets `package.json` `version`, and it requires a `package.json` that a git-installed plugin
|
|
44
|
+
usually lacks. Without `npm`, semantic-release needs no `package.json` at all.
|
|
45
|
+
|
|
46
|
+
```json
|
|
47
|
+
{
|
|
48
|
+
"branches": ["main"],
|
|
49
|
+
"plugins": [
|
|
50
|
+
"@semantic-release/commit-analyzer",
|
|
51
|
+
"@semantic-release/release-notes-generator",
|
|
52
|
+
["@semantic-release/exec", {
|
|
53
|
+
"prepareCmd": "npx universal-plugin@0.18.0 plugin version ${nextRelease.version}"
|
|
54
|
+
}],
|
|
55
|
+
["@semantic-release/git", {
|
|
56
|
+
"assets": [
|
|
57
|
+
"plugin.json",
|
|
58
|
+
".claude-plugin/**",
|
|
59
|
+
".cursor-plugin/**",
|
|
60
|
+
".codex-plugin/**",
|
|
61
|
+
".agents/plugins/marketplace.json",
|
|
62
|
+
".github/plugin/**",
|
|
63
|
+
"com.github.copilot/**",
|
|
64
|
+
"skills/**",
|
|
65
|
+
".plugin/pins.json"
|
|
66
|
+
]
|
|
67
|
+
}],
|
|
68
|
+
"@semantic-release/github"
|
|
69
|
+
]
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
With no `package.json`, `universal-plugin` is not installed, so the command runs it through `npx`.
|
|
74
|
+
Pin it to the CLI version this skill ships with, as shown. The `upgrade-plugin` skill moves that pin
|
|
75
|
+
later.
|
|
76
|
+
Where the repository does install `universal-plugin` as a devDependency, use the bare
|
|
77
|
+
`universal-plugin` instead.
|
|
78
|
+
|
|
79
|
+
### A plugin that ships on npm
|
|
80
|
+
|
|
81
|
+
Keep `@semantic-release/npm` and add the other two after it:
|
|
82
|
+
|
|
83
|
+
```json
|
|
84
|
+
["@semantic-release/npm"],
|
|
85
|
+
["@semantic-release/exec", { "prepareCmd": "universal-plugin plugin version ${nextRelease.version}" }],
|
|
86
|
+
["@semantic-release/git", { "assets": ["package.json", "plugin.json", "..."] }]
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Setting `assets` replaces the git plugin's default list, which holds `package.json`,
|
|
90
|
+
`package-lock.json`, `npm-shrinkwrap.json`, and `CHANGELOG.md`. List again each of those the
|
|
91
|
+
repository needs, alongside the plugin files above.
|
|
92
|
+
|
|
93
|
+
### Assets
|
|
94
|
+
|
|
95
|
+
`plugin version` rewrites `plugin.json` and the skill pins, and then re-derives every vendor
|
|
96
|
+
manifest and repository catalog. Commit all of them, or the repository's files disagree with the
|
|
97
|
+
tag. The list above covers every place the CLI writes. A glob that matches nothing adds nothing, so
|
|
98
|
+
the whole list is safe to keep for a plugin that does not declare every vendor. Under a plugin root
|
|
99
|
+
below the repository root, prefix the plugin's own paths with that root. The catalogs
|
|
100
|
+
(`.claude-plugin/marketplace.json`, `.cursor-plugin/marketplace.json`,
|
|
101
|
+
`.agents/plugins/marketplace.json`, `.github/plugin/marketplace.json`) stay at the repository root.
|
|
102
|
+
Add the mcp file when the plugin declares one.
|
|
103
|
+
|
|
104
|
+
The git plugin's default commit message ends in `[skip ci]`, so the commit back does not start
|
|
105
|
+
another release.
|
|
106
|
+
|
|
107
|
+
### Applying it
|
|
108
|
+
|
|
109
|
+
1. Edit the config file the survey found, in its own format. For a JavaScript config, edit the
|
|
110
|
+
`plugins` array in place. If no config exists, write `.releaserc.json`.
|
|
111
|
+
2. Keep every plugin the user already lists, and keep their order relative to each other.
|
|
112
|
+
3. Show the before and after `plugins` list in the Phase 3 plan. Apply only once the user approves.
|
|
113
|
+
4. Name the packages the release job must install: `@semantic-release/exec` and
|
|
114
|
+
`@semantic-release/git`. The `--no-ci` local run, and the CI job that runs semantic-release, both
|
|
115
|
+
need them. Installing them is the user's step. Do not edit the CI workflow (SKILL.md Rules).
|
|
116
|
+
|
|
117
|
+
## release-it
|
|
118
|
+
|
|
119
|
+
release-it runs its `after:bump` hook after it settles the new number and before its release
|
|
120
|
+
commit and tag. That commit stages every tracked file the hook changed (`git add . --update`), so
|
|
121
|
+
the stamp ships in the tagged commit with no extra plugin. `${version}` in a hook is the new number.
|
|
122
|
+
|
|
123
|
+
### A plugin that ships to no npm package
|
|
124
|
+
|
|
125
|
+
Set `"npm": false`. release-it then ignores `package.json`, needs none, and reads the current version
|
|
126
|
+
from the latest git tag. Add the stamp as the `after:bump` hook:
|
|
127
|
+
|
|
128
|
+
```json
|
|
129
|
+
{
|
|
130
|
+
"npm": false,
|
|
131
|
+
"hooks": {
|
|
132
|
+
"after:bump": "npx universal-plugin@0.18.0 plugin version ${version}"
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
With no `package.json`, `universal-plugin` is not installed, so the hook runs it through `npx`. Pin
|
|
138
|
+
it to the CLI version this skill ships with, as shown. The `upgrade-plugin` skill moves that pin
|
|
139
|
+
later.
|
|
140
|
+
|
|
141
|
+
### A plugin that ships on npm
|
|
142
|
+
|
|
143
|
+
Keep release-it's npm plugin. It bumps `package.json`, and the hook then stamps the same number into
|
|
144
|
+
the plugin:
|
|
145
|
+
|
|
146
|
+
```json
|
|
147
|
+
{
|
|
148
|
+
"hooks": { "after:bump": "universal-plugin plugin version ${version}" }
|
|
149
|
+
}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
Use the bare `universal-plugin` when the repository installs it as a devDependency, as an
|
|
153
|
+
npm-shipped plugin usually does. Otherwise use the pinned `npx` form above. Here release-it reads
|
|
154
|
+
the current version from `package.json`, so the first release needs no tag.
|
|
155
|
+
|
|
156
|
+
Add `--root <plugin-root>` to the hook when release-it runs from a directory other than the plugin
|
|
157
|
+
root.
|
|
158
|
+
|
|
159
|
+
### The first release needs a tag
|
|
160
|
+
|
|
161
|
+
With `"npm": false`, release-it reads the current number from the latest tag, never from
|
|
162
|
+
`plugin.json`. With no tag it starts from `0.0.0`, proposes `0.0.1`, and the stamp refuses a number
|
|
163
|
+
that does not advance on the version `plugin.json` holds. The release then fails.
|
|
164
|
+
|
|
165
|
+
So, when the plugin ships to no npm package, check for a tag in the Phase 3 plan:
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
git describe --tags --abbrev=0
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
If that finds no tag, propose tagging the current commit with the version `plugin.json` holds, and
|
|
172
|
+
create the tag once the user approves:
|
|
173
|
+
|
|
174
|
+
```bash
|
|
175
|
+
git tag v1.2.0
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
- Use `v<version>` unless the repository already tags in another form. release-it names its next
|
|
179
|
+
tag after the latest one, so the first tag sets the form every later release keeps.
|
|
180
|
+
- A lightweight tag is enough. release-it finds it with `git describe --tags`.
|
|
181
|
+
- Tag the commit whose `plugin.json` holds that version, and only after the plugin's files are
|
|
182
|
+
committed. Do not move or replace an existing tag.
|
|
183
|
+
- The tag is local until pushed. A release that runs in CI needs it on the remote. Pushing it is the
|
|
184
|
+
user's step, so name `git push origin v1.2.0` and run it only if the user asks.
|
|
185
|
+
- If the user declines, say the first release fails until a tag on the current version exists.
|
|
186
|
+
|
|
187
|
+
### Applying it
|
|
188
|
+
|
|
189
|
+
1. Edit the config the survey found, in its own format: a `.release-it.*` file, or the `release-it`
|
|
190
|
+
key in `package.json`. If none exists, write `.release-it.json`.
|
|
191
|
+
2. Keep every key the user already set. If an `after:bump` hook already exists, keep its command and
|
|
192
|
+
run the stamp after it: a string becomes an array of both commands. Show the hooks before and
|
|
193
|
+
after in the Phase 3 plan. Apply only once the user approves.
|
|
194
|
+
3. For a plugin that ships to no npm package, set `"npm": false`, and handle the tag as above.
|
|
195
|
+
4. Commit the plugin's generated files (`plugin.json`, the vendor manifests, the catalogs,
|
|
196
|
+
`.plugin/pins.json`) before the first release. The release commit stages only tracked files, so
|
|
197
|
+
a stamped file git does not track yet stays out of the tagged commit.
|
|
198
|
+
5. Installing release-it is the user's step. Do not edit the CI workflow (SKILL.md Rules).
|
|
199
|
+
|
|
200
|
+
`doctor` reports `release-it-no-stamp` for a release-it config that never runs `plugin version`.
|
|
201
|
+
|
|
202
|
+
## release-please
|
|
203
|
+
|
|
204
|
+
release-please runs no command before its release commit. Its release PR moves the number in the
|
|
205
|
+
files it knows, and a workflow step on that PR then restamps the plugin. The wiring is two files the
|
|
206
|
+
skill writes, and one workflow step the user adds.
|
|
207
|
+
|
|
208
|
+
### A plugin that ships to no npm package
|
|
209
|
+
|
|
210
|
+
`release-type: simple` keeps the number in `.release-please-manifest.json`, and `extra-files` bumps
|
|
211
|
+
`plugin.json`. Write `release-please-config.json`:
|
|
212
|
+
|
|
213
|
+
```json
|
|
214
|
+
{
|
|
215
|
+
"packages": {
|
|
216
|
+
".": {
|
|
217
|
+
"release-type": "simple",
|
|
218
|
+
"extra-files": [{ "type": "json", "path": "plugin.json", "jsonpath": "$.version" }]
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
The restamp step runs `npx -y universal-plugin@0.18.0 plugin version --from-manifest`, which takes
|
|
225
|
+
the number `plugin.json` already holds. Pin it to the CLI version this skill ships with.
|
|
226
|
+
|
|
227
|
+
### A plugin that ships on npm
|
|
228
|
+
|
|
229
|
+
`release-type: node` bumps `package.json`. The restamp step runs
|
|
230
|
+
`universal-plugin plugin version --from-package` instead. Do not add `plugin.json` to `extra-files`
|
|
231
|
+
here: the package owns the number, and `--from-package` carries it into the plugin.
|
|
232
|
+
|
|
233
|
+
### The manifest holds the current version
|
|
234
|
+
|
|
235
|
+
release-please reads the last release from `.release-please-manifest.json`. A package with no entry
|
|
236
|
+
starts from a default version, not from the plugin's. Write the entry with the version `plugin.json`
|
|
237
|
+
holds, keyed by the package path:
|
|
238
|
+
|
|
239
|
+
```json
|
|
240
|
+
{ ".": "1.2.0" }
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
For a plugin below the repository root, use its path as the key in both files (`"packages/my-plugin"`),
|
|
244
|
+
and make `extra-files` paths relative to that package.
|
|
245
|
+
|
|
246
|
+
### The workflow step
|
|
247
|
+
|
|
248
|
+
The `version` skill's section *release-please with no `package.json`* has the workflow: a GitHub
|
|
249
|
+
App token minted for the run, the release-please action given that token, then a checkout of the
|
|
250
|
+
release PR branch with the same token, the restamp, and a commit pushed back. Show it in the plan and
|
|
251
|
+
hand it to the user. Do not write or edit the workflow (SKILL.md Rules). For an npm-shipped plugin,
|
|
252
|
+
the step runs `--from-package` in place of `--from-manifest`.
|
|
253
|
+
|
|
254
|
+
The token matters. A push made with the default `GITHUB_TOKEN` starts no workflow run, so the
|
|
255
|
+
release PR's checks never run on its head commit and a required check blocks the merge. Tell the
|
|
256
|
+
user the App setup the workflow needs: an App with Contents, Pull requests and Issues set to read and
|
|
257
|
+
write, installed on the repository, its client ID in the variable `RELEASE_APP_CLIENT_ID` and a
|
|
258
|
+
private key in the secret `RELEASE_APP_PRIVATE_KEY`. Do not offer a `workflow_dispatch` re-run of CI
|
|
259
|
+
instead: its checks do not count toward a required check.
|
|
260
|
+
|
|
261
|
+
### Applying it
|
|
262
|
+
|
|
263
|
+
1. If `release-please-config.json` exists, add `extra-files` to the plugin's package entry and keep
|
|
264
|
+
every other key. If it does not, write the config above.
|
|
265
|
+
2. Add the plugin's entry to `.release-please-manifest.json`, or write the file. Never lower or
|
|
266
|
+
replace an entry that already exists: that is the last released version.
|
|
267
|
+
3. Show both files before and after in the Phase 3 plan. Apply only once the user approves.
|
|
268
|
+
4. Hand over the workflow step and the App setup.
|
|
269
|
+
|
|
270
|
+
`doctor` reports `release-please-no-restamp` when `extra-files` bumps `plugin.json` and no workflow
|
|
271
|
+
runs `plugin version`, and `release-please-restamp-no-ci` when the restamp is pushed with the default
|
|
272
|
+
`GITHUB_TOKEN`.
|
|
@@ -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.18.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 update":"skills/marketplace/scripts/update.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.18.0","entry":"skills/marketplace/scripts/add.mjs","commands":{"marketplace add":"skills/marketplace/scripts/add.mjs","marketplace init":"skills/marketplace/scripts/marketplace.mjs","marketplace update":"skills/marketplace/scripts/update.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
|