universal-plugin 0.16.3 → 0.17.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/.cursor-plugin/plugin.json +1 -1
- package/CHANGELOG.md +24 -0
- package/agents/agentskills-specialist.md +6 -11
- package/com.github.copilot/agents/agentskills-specialist.agent.md +6 -11
- package/dist/cli.mjs +669 -407
- package/package.json +6 -6
- package/plugin.json +5 -1
- package/readme.md +2 -2
- package/references/plugin-design.md +19 -33
- package/references/slash-invocation.md +2 -2
- package/skills/adopt-upx/scripts/rewrite-upx.mjs +1 -1
- package/skills/build-plugin/SKILL.md +2 -3
- package/skills/build-plugin/scripts/build.mjs +1 -1
- package/skills/doctor-universal-plugin/README.md +1 -1
- package/skills/doctor-universal-plugin/SKILL.md +3 -3
- package/skills/doctor-universal-plugin/scripts/doctor.mjs +1 -1
- package/skills/init-universal-plugin/README.md +1 -1
- package/skills/init-universal-plugin/SKILL.md +2 -2
- package/skills/init-universal-plugin/references/create.md +7 -7
- package/skills/init-universal-plugin/references/detection.md +1 -1
- package/skills/init-universal-plugin/references/frontmatter.md +1 -1
- package/skills/init-universal-plugin/references/standard.md +3 -3
- package/skills/init-universal-plugin/references/vendors/copilot-cli.md +3 -0
- package/skills/init-universal-plugin/scripts/init.mjs +1 -1
- package/skills/marketplace/README.md +9 -2
- package/skills/marketplace/SKILL.md +15 -10
- package/skills/marketplace/references/add.md +3 -1
- package/skills/marketplace/references/update.md +75 -0
- package/skills/marketplace/references/validate.md +1 -1
- package/skills/marketplace/scripts/add.mjs +1 -1
- package/skills/marketplace/scripts/install-docs.mjs +1 -1
- package/skills/marketplace/scripts/marketplace.mjs +1 -1
- package/skills/marketplace/scripts/update.mjs +52 -0
- package/skills/marketplace/scripts/validate.mjs +1 -1
- package/skills/migrate-plugin/SKILL.md +1 -2
- package/skills/publish-plugin/SKILL.md +15 -6
- package/skills/version/README.md +2 -2
- package/skills/version/SKILL.md +4 -4
- package/skills/version/scripts/version.mjs +1 -1
package/dist/cli.mjs
CHANGED
|
@@ -5581,6 +5581,29 @@ function refreshCatalogEntry(target, plugin, existing) {
|
|
|
5581
5581
|
})
|
|
5582
5582
|
};
|
|
5583
5583
|
}
|
|
5584
|
+
/** A source in the shape a target's catalog states it, once `adaptSource` has settled which source
|
|
5585
|
+
* that is. Only Codex differs: it tags a repository path `local`. */
|
|
5586
|
+
function catalogEntrySource(target, source) {
|
|
5587
|
+
return target === "codex" ? codexSource(source) : source;
|
|
5588
|
+
}
|
|
5589
|
+
/** The entry a catalog lists under a name, or `undefined` when it lists none. */
|
|
5590
|
+
function findCatalogEntry(content, catalogPath, name) {
|
|
5591
|
+
const catalog = parseCatalog(content, catalogPath);
|
|
5592
|
+
return (Array.isArray(catalog.plugins) ? catalog.plugins : []).find((entry) => typeof entry === "object" && entry !== null && entry.name === name);
|
|
5593
|
+
}
|
|
5594
|
+
/** Puts an edited entry back where the entry of the same name sat. The catalog's top level and every
|
|
5595
|
+
* other entry stay exactly as they were. */
|
|
5596
|
+
function replaceCatalogEntry(content, catalogPath, entry) {
|
|
5597
|
+
const catalog = parseCatalog(content, catalogPath);
|
|
5598
|
+
const entries = Array.isArray(catalog.plugins) ? [...catalog.plugins] : [];
|
|
5599
|
+
const index = entries.findIndex((candidate) => typeof candidate === "object" && candidate !== null && candidate.name === entry.name);
|
|
5600
|
+
if (index === -1) throw new Error(`error: "${String(entry.name)}" is not listed in ${catalogPath}`);
|
|
5601
|
+
entries[index] = entry;
|
|
5602
|
+
return json({
|
|
5603
|
+
...catalog,
|
|
5604
|
+
plugins: entries
|
|
5605
|
+
});
|
|
5606
|
+
}
|
|
5584
5607
|
/** Whether two catalogs say the same thing. Key order and whitespace do not change a catalog's
|
|
5585
5608
|
* meaning — the repository formats its own JSON — so a refresh compares this rather than bytes and
|
|
5586
5609
|
* leaves a file it agrees with alone. Array order does count. */
|
|
@@ -8964,7 +8987,7 @@ const NEXT_STEP$1 = "→ review and commit the pinned skills\n";
|
|
|
8964
8987
|
function bundleCommand() {
|
|
8965
8988
|
const cmd = new Command("bundle").description("Deprecated: use `plugin version`, which stamps the skill pins");
|
|
8966
8989
|
cmd.option("--dry-run", "Resolve and report pins without writing them").option("--full", "Show every pins row without truncation").option("--format <format>", "Output format: json or toon (default: toon)").option("--runner <runner>", "Runner word to emit on rewritten refs: npx or upx (default: preserve each ref's runner)").addOption(ROOT_OPTION).addHelpText("after", "\nExample:\n $ universal-plugin plugin bundle --dry-run --full\n").action((opts) => {
|
|
8967
|
-
process.stderr.write("warn: plugin bundle is deprecated and will be removed in
|
|
8990
|
+
process.stderr.write("warn: plugin bundle is deprecated since 0.14.0 and will be removed in a later release — use plugin version, which stamps the skill pins\n");
|
|
8968
8991
|
try {
|
|
8969
8992
|
const runner = opts.runner;
|
|
8970
8993
|
if (runner !== void 0 && runner !== "npx" && runner !== "upx") throw new Error(`error: unknown --runner value "${runner}" (expected npx or upx)`);
|
|
@@ -9442,386 +9465,121 @@ function initCommand$1(deps = { fs: realInitFs }) {
|
|
|
9442
9465
|
return cmd;
|
|
9443
9466
|
}
|
|
9444
9467
|
//#endregion
|
|
9445
|
-
//#region ../../node_modules/.pnpm/cyber-agentkit@
|
|
9468
|
+
//#region ../../node_modules/.pnpm/cyber-agentkit@2.0.0/node_modules/cyber-agentkit/dist/reference-where-CVmGFOwR.js
|
|
9446
9469
|
var __commonJSMin = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod), cb = null), mod.exports);
|
|
9447
9470
|
var __require = /* #__PURE__ */ (() => createRequire(import.meta.url))();
|
|
9448
|
-
|
|
9449
|
-
|
|
9450
|
-
|
|
9451
|
-
|
|
9452
|
-
|
|
9453
|
-
|
|
9454
|
-
|
|
9455
|
-
|
|
9456
|
-
|
|
9457
|
-
|
|
9458
|
-
|
|
9459
|
-
|
|
9460
|
-
|
|
9461
|
-
|
|
9462
|
-
|
|
9463
|
-
|
|
9464
|
-
|
|
9465
|
-
|
|
9466
|
-
|
|
9467
|
-
|
|
9468
|
-
const configDir = win32.join(env.APPDATA || win32.join(homedir, "AppData", "Roaming"), "Code");
|
|
9469
|
-
return {
|
|
9470
|
-
configDir,
|
|
9471
|
-
path: win32.join(configDir, "agentPlugins")
|
|
9472
|
-
};
|
|
9471
|
+
var require_identity = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
9472
|
+
const ALIAS = Symbol.for("yaml.alias");
|
|
9473
|
+
const DOC = Symbol.for("yaml.document");
|
|
9474
|
+
const MAP = Symbol.for("yaml.map");
|
|
9475
|
+
const PAIR = Symbol.for("yaml.pair");
|
|
9476
|
+
const SCALAR = Symbol.for("yaml.scalar");
|
|
9477
|
+
const SEQ = Symbol.for("yaml.seq");
|
|
9478
|
+
const NODE_TYPE = Symbol.for("yaml.node.type");
|
|
9479
|
+
const isAlias = (node) => !!node && typeof node === "object" && node[NODE_TYPE] === ALIAS;
|
|
9480
|
+
const isDocument = (node) => !!node && typeof node === "object" && node[NODE_TYPE] === DOC;
|
|
9481
|
+
const isMap = (node) => !!node && typeof node === "object" && node[NODE_TYPE] === MAP;
|
|
9482
|
+
const isPair = (node) => !!node && typeof node === "object" && node[NODE_TYPE] === PAIR;
|
|
9483
|
+
const isScalar = (node) => !!node && typeof node === "object" && node[NODE_TYPE] === SCALAR;
|
|
9484
|
+
const isSeq = (node) => !!node && typeof node === "object" && node[NODE_TYPE] === SEQ;
|
|
9485
|
+
function isCollection(node) {
|
|
9486
|
+
if (node && typeof node === "object") switch (node[NODE_TYPE]) {
|
|
9487
|
+
case MAP:
|
|
9488
|
+
case SEQ: return true;
|
|
9489
|
+
}
|
|
9490
|
+
return false;
|
|
9473
9491
|
}
|
|
9474
|
-
|
|
9475
|
-
|
|
9476
|
-
|
|
9477
|
-
|
|
9478
|
-
|
|
9479
|
-
|
|
9480
|
-
|
|
9481
|
-
|
|
9482
|
-
|
|
9483
|
-
|
|
9484
|
-
|
|
9485
|
-
|
|
9486
|
-
|
|
9487
|
-
|
|
9488
|
-
|
|
9489
|
-
|
|
9490
|
-
|
|
9491
|
-
|
|
9492
|
-
|
|
9493
|
-
|
|
9494
|
-
|
|
9495
|
-
|
|
9496
|
-
|
|
9497
|
-
|
|
9498
|
-
|
|
9499
|
-
|
|
9500
|
-
|
|
9501
|
-
|
|
9502
|
-
|
|
9503
|
-
|
|
9504
|
-
|
|
9505
|
-
|
|
9506
|
-
|
|
9507
|
-
|
|
9508
|
-
|
|
9509
|
-
|
|
9510
|
-
|
|
9511
|
-
|
|
9512
|
-
|
|
9513
|
-
|
|
9514
|
-
|
|
9515
|
-
|
|
9516
|
-
|
|
9517
|
-
|
|
9518
|
-
|
|
9519
|
-
|
|
9520
|
-
|
|
9521
|
-
|
|
9522
|
-
|
|
9523
|
-
|
|
9524
|
-
|
|
9525
|
-
|
|
9526
|
-
|
|
9527
|
-
|
|
9528
|
-
|
|
9529
|
-
|
|
9530
|
-
|
|
9531
|
-
|
|
9532
|
-
|
|
9533
|
-
|
|
9534
|
-
|
|
9535
|
-
|
|
9536
|
-
|
|
9537
|
-
|
|
9538
|
-
|
|
9539
|
-
|
|
9540
|
-
|
|
9541
|
-
|
|
9542
|
-
|
|
9543
|
-
|
|
9544
|
-
|
|
9545
|
-
|
|
9546
|
-
|
|
9547
|
-
|
|
9548
|
-
|
|
9549
|
-
|
|
9550
|
-
|
|
9551
|
-
|
|
9552
|
-
|
|
9553
|
-
|
|
9554
|
-
|
|
9555
|
-
|
|
9556
|
-
|
|
9557
|
-
{
|
|
9558
|
-
|
|
9559
|
-
|
|
9560
|
-
|
|
9561
|
-
|
|
9562
|
-
|
|
9563
|
-
|
|
9564
|
-
|
|
9565
|
-
path: join(configDir, "config.json"),
|
|
9566
|
-
description: "Application state, including installedPlugins",
|
|
9567
|
-
research: "E-COPILOT-P9"
|
|
9568
|
-
},
|
|
9569
|
-
{
|
|
9570
|
-
kind: "enabled-record",
|
|
9571
|
-
path: join(configDir, "settings.json"),
|
|
9572
|
-
description: "User settings (JSON with comments); enabledPlugins maps plugin specs to a boolean",
|
|
9573
|
-
research: "E-COPILOT-P4"
|
|
9574
|
-
}
|
|
9575
|
-
]
|
|
9576
|
-
};
|
|
9577
|
-
},
|
|
9578
|
-
opencode: (environment) => {
|
|
9579
|
-
const configDir = join(xdgConfig(environment), "opencode");
|
|
9580
|
-
return {
|
|
9581
|
-
harness: "opencode",
|
|
9582
|
-
configDir,
|
|
9583
|
-
locations: [{
|
|
9584
|
-
kind: "local-plugins",
|
|
9585
|
-
path: join(configDir, "plugins"),
|
|
9586
|
-
description: "JS/TS plugin modules loaded at startup; npm plugins are named in the plugin config array",
|
|
9587
|
-
research: "E-OC-P2"
|
|
9588
|
-
}]
|
|
9589
|
-
};
|
|
9590
|
-
},
|
|
9591
|
-
kilo: (environment) => {
|
|
9592
|
-
const configDir = join(xdgConfig(environment), "kilo");
|
|
9593
|
-
return {
|
|
9594
|
-
harness: "kilo",
|
|
9595
|
-
configDir,
|
|
9596
|
-
locations: [{
|
|
9597
|
-
kind: "local-plugins",
|
|
9598
|
-
path: join(configDir, "plugin"),
|
|
9599
|
-
description: "JS/TS plugin modules loaded at startup; npm plugins are named in the plugin config array",
|
|
9600
|
-
research: "E-KILO-P2"
|
|
9601
|
-
}]
|
|
9602
|
-
};
|
|
9603
|
-
},
|
|
9604
|
-
"gemini-cli": ({ env, homedir }) => {
|
|
9605
|
-
const configDir = join(env.GEMINI_CLI_HOME || homedir, ".gemini");
|
|
9606
|
-
const extensions = join(configDir, "extensions");
|
|
9607
|
-
return {
|
|
9608
|
-
harness: "gemini-cli",
|
|
9609
|
-
configDir,
|
|
9610
|
-
locations: [{
|
|
9611
|
-
kind: "installed-plugins",
|
|
9612
|
-
path: extensions,
|
|
9613
|
-
description: "Installed extensions, one folder each with a gemini-extension.json manifest",
|
|
9614
|
-
research: "E-GEM-P1"
|
|
9615
|
-
}, {
|
|
9616
|
-
kind: "enabled-record",
|
|
9617
|
-
path: join(extensions, "extension-enablement.json"),
|
|
9618
|
-
description: "Per-extension path-glob overrides that enable or disable it by folder, not a boolean",
|
|
9619
|
-
research: "E-GEM-P3"
|
|
9620
|
-
}]
|
|
9621
|
-
};
|
|
9622
|
-
},
|
|
9623
|
-
"qwen-code": ({ env, homedir }) => {
|
|
9624
|
-
const configDir = env.QWEN_HOME || join(homedir, ".qwen");
|
|
9625
|
-
const extensions = join(configDir, "extensions");
|
|
9626
|
-
return {
|
|
9627
|
-
harness: "qwen-code",
|
|
9628
|
-
configDir,
|
|
9629
|
-
locations: [{
|
|
9630
|
-
kind: "installed-plugins",
|
|
9631
|
-
path: extensions,
|
|
9632
|
-
description: "Installed extensions, one folder each with a qwen-extension.json manifest",
|
|
9633
|
-
research: "E-QWEN-P1"
|
|
9634
|
-
}, {
|
|
9635
|
-
kind: "enabled-record",
|
|
9636
|
-
path: join(extensions, "extension-enablement.json"),
|
|
9637
|
-
description: "Extension enable/disable state, inherited from Gemini CLI's format",
|
|
9638
|
-
research: "E-QWEN-P2"
|
|
9639
|
-
}]
|
|
9640
|
-
};
|
|
9641
|
-
},
|
|
9642
|
-
"vscode-copilot": (environment) => {
|
|
9643
|
-
const { configDir, path } = vscodeAgentPlugins(environment);
|
|
9644
|
-
return {
|
|
9645
|
-
harness: "vscode-copilot",
|
|
9646
|
-
configDir,
|
|
9647
|
-
locations: [{
|
|
9648
|
-
kind: "installed-plugins",
|
|
9649
|
-
path,
|
|
9650
|
-
description: "Installed agent plugins as <host>/<org>/<repo>/",
|
|
9651
|
-
research: "E-VSC-P3"
|
|
9652
|
-
}]
|
|
9653
|
-
};
|
|
9654
|
-
},
|
|
9655
|
-
cline: ({ homedir }) => {
|
|
9656
|
-
const configDir = join(homedir, ".cline");
|
|
9657
|
-
return {
|
|
9658
|
-
harness: "cline",
|
|
9659
|
-
configDir,
|
|
9660
|
-
locations: [{
|
|
9661
|
-
kind: "installed-plugins",
|
|
9662
|
-
path: join(configDir, "plugins", "_installed"),
|
|
9663
|
-
description: "Installed plugins, grouped by source: npm, git, remote, or local",
|
|
9664
|
-
research: "E-CLINE-P3"
|
|
9665
|
-
}]
|
|
9666
|
-
};
|
|
9667
|
-
},
|
|
9668
|
-
crush: ({ env, homedir }) => {
|
|
9669
|
-
return {
|
|
9670
|
-
harness: "crush",
|
|
9671
|
-
configDir: env.CRUSH_GLOBAL_CONFIG || join(env.XDG_CONFIG_HOME || join(homedir, ".config"), "crush"),
|
|
9672
|
-
locations: []
|
|
9673
|
-
};
|
|
9674
|
-
},
|
|
9675
|
-
openhands: ({ env, homedir }) => {
|
|
9676
|
-
const configDir = env.OH_PERSISTENCE_DIR || env.OPENHANDS_PERSISTENCE_DIR || join(homedir, ".openhands");
|
|
9677
|
-
const installed = join(configDir, "plugins", "installed");
|
|
9678
|
-
return {
|
|
9679
|
-
harness: "openhands",
|
|
9680
|
-
configDir,
|
|
9681
|
-
locations: [{
|
|
9682
|
-
kind: "installed-plugins",
|
|
9683
|
-
path: installed,
|
|
9684
|
-
description: "Installed plugins, one folder each",
|
|
9685
|
-
research: "E-OH-P3"
|
|
9686
|
-
}, {
|
|
9687
|
-
kind: "enabled-record",
|
|
9688
|
-
path: join(installed, ".installed.json"),
|
|
9689
|
-
description: "Install metadata keyed by plugin name, each with enabled: <bool>",
|
|
9690
|
-
research: "E-OH-P4"
|
|
9691
|
-
}]
|
|
9692
|
-
};
|
|
9693
|
-
},
|
|
9694
|
-
augment: ({ homedir }) => {
|
|
9695
|
-
const configDir = join(homedir, ".augment");
|
|
9696
|
-
return {
|
|
9697
|
-
harness: "augment",
|
|
9698
|
-
configDir,
|
|
9699
|
-
locations: [{
|
|
9700
|
-
kind: "marketplaces",
|
|
9701
|
-
path: join(configDir, "plugins", "marketplaces"),
|
|
9702
|
-
description: "Marketplace checkouts",
|
|
9703
|
-
research: "E-AUG-P2"
|
|
9704
|
-
}, {
|
|
9705
|
-
kind: "enabled-record",
|
|
9706
|
-
path: join(configDir, "settings.json"),
|
|
9707
|
-
description: "User settings; enabledPlugins maps plugin@marketplace to a boolean",
|
|
9708
|
-
research: "E-AUG-P4"
|
|
9709
|
-
}]
|
|
9710
|
-
};
|
|
9711
|
-
}
|
|
9712
|
-
};
|
|
9713
|
-
var require_identity = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
9714
|
-
const ALIAS = Symbol.for("yaml.alias");
|
|
9715
|
-
const DOC = Symbol.for("yaml.document");
|
|
9716
|
-
const MAP = Symbol.for("yaml.map");
|
|
9717
|
-
const PAIR = Symbol.for("yaml.pair");
|
|
9718
|
-
const SCALAR = Symbol.for("yaml.scalar");
|
|
9719
|
-
const SEQ = Symbol.for("yaml.seq");
|
|
9720
|
-
const NODE_TYPE = Symbol.for("yaml.node.type");
|
|
9721
|
-
const isAlias = (node) => !!node && typeof node === "object" && node[NODE_TYPE] === ALIAS;
|
|
9722
|
-
const isDocument = (node) => !!node && typeof node === "object" && node[NODE_TYPE] === DOC;
|
|
9723
|
-
const isMap = (node) => !!node && typeof node === "object" && node[NODE_TYPE] === MAP;
|
|
9724
|
-
const isPair = (node) => !!node && typeof node === "object" && node[NODE_TYPE] === PAIR;
|
|
9725
|
-
const isScalar = (node) => !!node && typeof node === "object" && node[NODE_TYPE] === SCALAR;
|
|
9726
|
-
const isSeq = (node) => !!node && typeof node === "object" && node[NODE_TYPE] === SEQ;
|
|
9727
|
-
function isCollection(node) {
|
|
9728
|
-
if (node && typeof node === "object") switch (node[NODE_TYPE]) {
|
|
9729
|
-
case MAP:
|
|
9730
|
-
case SEQ: return true;
|
|
9731
|
-
}
|
|
9732
|
-
return false;
|
|
9733
|
-
}
|
|
9734
|
-
function isNode(node) {
|
|
9735
|
-
if (node && typeof node === "object") switch (node[NODE_TYPE]) {
|
|
9736
|
-
case ALIAS:
|
|
9737
|
-
case MAP:
|
|
9738
|
-
case SCALAR:
|
|
9739
|
-
case SEQ: return true;
|
|
9740
|
-
}
|
|
9741
|
-
return false;
|
|
9742
|
-
}
|
|
9743
|
-
const hasAnchor = (node) => (isScalar(node) || isCollection(node)) && !!node.anchor;
|
|
9744
|
-
exports.ALIAS = ALIAS;
|
|
9745
|
-
exports.DOC = DOC;
|
|
9746
|
-
exports.MAP = MAP;
|
|
9747
|
-
exports.NODE_TYPE = NODE_TYPE;
|
|
9748
|
-
exports.PAIR = PAIR;
|
|
9749
|
-
exports.SCALAR = SCALAR;
|
|
9750
|
-
exports.SEQ = SEQ;
|
|
9751
|
-
exports.hasAnchor = hasAnchor;
|
|
9752
|
-
exports.isAlias = isAlias;
|
|
9753
|
-
exports.isCollection = isCollection;
|
|
9754
|
-
exports.isDocument = isDocument;
|
|
9755
|
-
exports.isMap = isMap;
|
|
9756
|
-
exports.isNode = isNode;
|
|
9757
|
-
exports.isPair = isPair;
|
|
9758
|
-
exports.isScalar = isScalar;
|
|
9759
|
-
exports.isSeq = isSeq;
|
|
9760
|
-
}));
|
|
9761
|
-
var require_visit = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
9762
|
-
var identity = require_identity();
|
|
9763
|
-
const BREAK = Symbol("break visit");
|
|
9764
|
-
const SKIP = Symbol("skip children");
|
|
9765
|
-
const REMOVE = Symbol("remove node");
|
|
9766
|
-
/**
|
|
9767
|
-
* Apply a visitor to an AST node or document.
|
|
9768
|
-
*
|
|
9769
|
-
* Walks through the tree (depth-first) starting from `node`, calling a
|
|
9770
|
-
* `visitor` function with three arguments:
|
|
9771
|
-
* - `key`: For sequence values and map `Pair`, the node's index in the
|
|
9772
|
-
* collection. Within a `Pair`, `'key'` or `'value'`, correspondingly.
|
|
9773
|
-
* `null` for the root node.
|
|
9774
|
-
* - `node`: The current node.
|
|
9775
|
-
* - `path`: The ancestry of the current node.
|
|
9776
|
-
*
|
|
9777
|
-
* The return value of the visitor may be used to control the traversal:
|
|
9778
|
-
* - `undefined` (default): Do nothing and continue
|
|
9779
|
-
* - `visit.SKIP`: Do not visit the children of this node, continue with next
|
|
9780
|
-
* sibling
|
|
9781
|
-
* - `visit.BREAK`: Terminate traversal completely
|
|
9782
|
-
* - `visit.REMOVE`: Remove the current node, then continue with the next one
|
|
9783
|
-
* - `Node`: Replace the current node, then continue by visiting it
|
|
9784
|
-
* - `number`: While iterating the items of a sequence or map, set the index
|
|
9785
|
-
* of the next step. This is useful especially if the index of the current
|
|
9786
|
-
* node has changed.
|
|
9787
|
-
*
|
|
9788
|
-
* If `visitor` is a single function, it will be called with all values
|
|
9789
|
-
* encountered in the tree, including e.g. `null` values. Alternatively,
|
|
9790
|
-
* separate visitor functions may be defined for each `Map`, `Pair`, `Seq`,
|
|
9791
|
-
* `Alias` and `Scalar` node. To define the same visitor function for more than
|
|
9792
|
-
* one node type, use the `Collection` (map and seq), `Value` (map, seq & scalar)
|
|
9793
|
-
* and `Node` (alias, map, seq & scalar) targets. Of all these, only the most
|
|
9794
|
-
* specific defined one will be used for each node.
|
|
9795
|
-
*/
|
|
9796
|
-
function visit(node, visitor) {
|
|
9797
|
-
const visitor_ = initVisitor(visitor);
|
|
9798
|
-
if (identity.isDocument(node)) {
|
|
9799
|
-
if (visit_(null, node.contents, visitor_, Object.freeze([node])) === REMOVE) node.contents = null;
|
|
9800
|
-
} else visit_(null, node, visitor_, Object.freeze([]));
|
|
9801
|
-
}
|
|
9802
|
-
/** Terminate visit traversal completely */
|
|
9803
|
-
visit.BREAK = BREAK;
|
|
9804
|
-
/** Do not visit the children of the current node */
|
|
9805
|
-
visit.SKIP = SKIP;
|
|
9806
|
-
/** Remove the current node */
|
|
9807
|
-
visit.REMOVE = REMOVE;
|
|
9808
|
-
function visit_(key, node, visitor, path) {
|
|
9809
|
-
const ctrl = callVisitor(key, node, visitor, path);
|
|
9810
|
-
if (identity.isNode(ctrl) || identity.isPair(ctrl)) {
|
|
9811
|
-
replaceNode(key, path, ctrl);
|
|
9812
|
-
return visit_(key, ctrl, visitor, path);
|
|
9813
|
-
}
|
|
9814
|
-
if (typeof ctrl !== "symbol") {
|
|
9815
|
-
if (identity.isCollection(node)) {
|
|
9816
|
-
path = Object.freeze(path.concat(node));
|
|
9817
|
-
for (let i = 0; i < node.items.length; ++i) {
|
|
9818
|
-
const ci = visit_(i, node.items[i], visitor, path);
|
|
9819
|
-
if (typeof ci === "number") i = ci - 1;
|
|
9820
|
-
else if (ci === BREAK) return BREAK;
|
|
9821
|
-
else if (ci === REMOVE) {
|
|
9822
|
-
node.items.splice(i, 1);
|
|
9823
|
-
i -= 1;
|
|
9824
|
-
}
|
|
9492
|
+
function isNode(node) {
|
|
9493
|
+
if (node && typeof node === "object") switch (node[NODE_TYPE]) {
|
|
9494
|
+
case ALIAS:
|
|
9495
|
+
case MAP:
|
|
9496
|
+
case SCALAR:
|
|
9497
|
+
case SEQ: return true;
|
|
9498
|
+
}
|
|
9499
|
+
return false;
|
|
9500
|
+
}
|
|
9501
|
+
const hasAnchor = (node) => (isScalar(node) || isCollection(node)) && !!node.anchor;
|
|
9502
|
+
exports.ALIAS = ALIAS;
|
|
9503
|
+
exports.DOC = DOC;
|
|
9504
|
+
exports.MAP = MAP;
|
|
9505
|
+
exports.NODE_TYPE = NODE_TYPE;
|
|
9506
|
+
exports.PAIR = PAIR;
|
|
9507
|
+
exports.SCALAR = SCALAR;
|
|
9508
|
+
exports.SEQ = SEQ;
|
|
9509
|
+
exports.hasAnchor = hasAnchor;
|
|
9510
|
+
exports.isAlias = isAlias;
|
|
9511
|
+
exports.isCollection = isCollection;
|
|
9512
|
+
exports.isDocument = isDocument;
|
|
9513
|
+
exports.isMap = isMap;
|
|
9514
|
+
exports.isNode = isNode;
|
|
9515
|
+
exports.isPair = isPair;
|
|
9516
|
+
exports.isScalar = isScalar;
|
|
9517
|
+
exports.isSeq = isSeq;
|
|
9518
|
+
}));
|
|
9519
|
+
var require_visit = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
9520
|
+
var identity = require_identity();
|
|
9521
|
+
const BREAK = Symbol("break visit");
|
|
9522
|
+
const SKIP = Symbol("skip children");
|
|
9523
|
+
const REMOVE = Symbol("remove node");
|
|
9524
|
+
/**
|
|
9525
|
+
* Apply a visitor to an AST node or document.
|
|
9526
|
+
*
|
|
9527
|
+
* Walks through the tree (depth-first) starting from `node`, calling a
|
|
9528
|
+
* `visitor` function with three arguments:
|
|
9529
|
+
* - `key`: For sequence values and map `Pair`, the node's index in the
|
|
9530
|
+
* collection. Within a `Pair`, `'key'` or `'value'`, correspondingly.
|
|
9531
|
+
* `null` for the root node.
|
|
9532
|
+
* - `node`: The current node.
|
|
9533
|
+
* - `path`: The ancestry of the current node.
|
|
9534
|
+
*
|
|
9535
|
+
* The return value of the visitor may be used to control the traversal:
|
|
9536
|
+
* - `undefined` (default): Do nothing and continue
|
|
9537
|
+
* - `visit.SKIP`: Do not visit the children of this node, continue with next
|
|
9538
|
+
* sibling
|
|
9539
|
+
* - `visit.BREAK`: Terminate traversal completely
|
|
9540
|
+
* - `visit.REMOVE`: Remove the current node, then continue with the next one
|
|
9541
|
+
* - `Node`: Replace the current node, then continue by visiting it
|
|
9542
|
+
* - `number`: While iterating the items of a sequence or map, set the index
|
|
9543
|
+
* of the next step. This is useful especially if the index of the current
|
|
9544
|
+
* node has changed.
|
|
9545
|
+
*
|
|
9546
|
+
* If `visitor` is a single function, it will be called with all values
|
|
9547
|
+
* encountered in the tree, including e.g. `null` values. Alternatively,
|
|
9548
|
+
* separate visitor functions may be defined for each `Map`, `Pair`, `Seq`,
|
|
9549
|
+
* `Alias` and `Scalar` node. To define the same visitor function for more than
|
|
9550
|
+
* one node type, use the `Collection` (map and seq), `Value` (map, seq & scalar)
|
|
9551
|
+
* and `Node` (alias, map, seq & scalar) targets. Of all these, only the most
|
|
9552
|
+
* specific defined one will be used for each node.
|
|
9553
|
+
*/
|
|
9554
|
+
function visit(node, visitor) {
|
|
9555
|
+
const visitor_ = initVisitor(visitor);
|
|
9556
|
+
if (identity.isDocument(node)) {
|
|
9557
|
+
if (visit_(null, node.contents, visitor_, Object.freeze([node])) === REMOVE) node.contents = null;
|
|
9558
|
+
} else visit_(null, node, visitor_, Object.freeze([]));
|
|
9559
|
+
}
|
|
9560
|
+
/** Terminate visit traversal completely */
|
|
9561
|
+
visit.BREAK = BREAK;
|
|
9562
|
+
/** Do not visit the children of the current node */
|
|
9563
|
+
visit.SKIP = SKIP;
|
|
9564
|
+
/** Remove the current node */
|
|
9565
|
+
visit.REMOVE = REMOVE;
|
|
9566
|
+
function visit_(key, node, visitor, path) {
|
|
9567
|
+
const ctrl = callVisitor(key, node, visitor, path);
|
|
9568
|
+
if (identity.isNode(ctrl) || identity.isPair(ctrl)) {
|
|
9569
|
+
replaceNode(key, path, ctrl);
|
|
9570
|
+
return visit_(key, ctrl, visitor, path);
|
|
9571
|
+
}
|
|
9572
|
+
if (typeof ctrl !== "symbol") {
|
|
9573
|
+
if (identity.isCollection(node)) {
|
|
9574
|
+
path = Object.freeze(path.concat(node));
|
|
9575
|
+
for (let i = 0; i < node.items.length; ++i) {
|
|
9576
|
+
const ci = visit_(i, node.items[i], visitor, path);
|
|
9577
|
+
if (typeof ci === "number") i = ci - 1;
|
|
9578
|
+
else if (ci === BREAK) return BREAK;
|
|
9579
|
+
else if (ci === REMOVE) {
|
|
9580
|
+
node.items.splice(i, 1);
|
|
9581
|
+
i -= 1;
|
|
9582
|
+
}
|
|
9825
9583
|
}
|
|
9826
9584
|
} else if (identity.isPair(node)) {
|
|
9827
9585
|
path = Object.freeze(path.concat(node));
|
|
@@ -16221,27 +15979,292 @@ var require_public_api = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
16221
15979
|
exports.visit = visit.visit;
|
|
16222
15980
|
exports.visitAsync = visit.visitAsync;
|
|
16223
15981
|
})))();
|
|
16224
|
-
|
|
16225
|
-
|
|
16226
|
-
|
|
16227
|
-
|
|
16228
|
-
|
|
16229
|
-
|
|
16230
|
-
|
|
16231
|
-
|
|
16232
|
-
|
|
16233
|
-
|
|
16234
|
-
|
|
16235
|
-
|
|
16236
|
-
|
|
16237
|
-
|
|
16238
|
-
|
|
16239
|
-
|
|
16240
|
-
|
|
16241
|
-
|
|
16242
|
-
|
|
16243
|
-
|
|
16244
|
-
|
|
15982
|
+
function resolveHarnessEnvironment(environment = {}) {
|
|
15983
|
+
return {
|
|
15984
|
+
env: environment.env ?? process.env,
|
|
15985
|
+
homedir: environment.homedir ?? homedir(),
|
|
15986
|
+
cwd: environment.cwd ?? process.cwd(),
|
|
15987
|
+
platform: environment.platform ?? process.platform
|
|
15988
|
+
};
|
|
15989
|
+
}
|
|
15990
|
+
/**
|
|
15991
|
+
* Where a harness keeps plugins at the user level. Paths are computed, not checked: a location may
|
|
15992
|
+
* not exist until the first plugin is installed.
|
|
15993
|
+
*/
|
|
15994
|
+
function pluginStorage(harness, environment = {}) {
|
|
15995
|
+
return storages[harness](resolveHarnessEnvironment(environment));
|
|
15996
|
+
}
|
|
15997
|
+
/** `$XDG_CONFIG_HOME`, else `~/.config`, as the `xdg-basedir` package resolves it. */
|
|
15998
|
+
const xdgConfig = ({ env, homedir }) => env.XDG_CONFIG_HOME || join(homedir, ".config");
|
|
15999
|
+
/** The agent plugin folder of the stable VS Code build, per OS (E-VSC-P3). */
|
|
16000
|
+
function vscodeAgentPlugins({ env, homedir, platform }) {
|
|
16001
|
+
if (platform === "win32") {
|
|
16002
|
+
const configDir = win32.join(env.APPDATA || win32.join(homedir, "AppData", "Roaming"), "Code");
|
|
16003
|
+
return {
|
|
16004
|
+
configDir,
|
|
16005
|
+
path: win32.join(configDir, "agentPlugins")
|
|
16006
|
+
};
|
|
16007
|
+
}
|
|
16008
|
+
const configDir = platform === "darwin" ? join(homedir, "Library", "Application Support", "Code") : join(homedir, ".config", "Code");
|
|
16009
|
+
return {
|
|
16010
|
+
configDir,
|
|
16011
|
+
path: join(configDir, "agentPlugins")
|
|
16012
|
+
};
|
|
16013
|
+
}
|
|
16014
|
+
const storages = {
|
|
16015
|
+
"claude-code": ({ env, homedir }) => {
|
|
16016
|
+
const configDir = env.CLAUDE_CONFIG_DIR || join(homedir, ".claude");
|
|
16017
|
+
const plugins = join(configDir, "plugins");
|
|
16018
|
+
return {
|
|
16019
|
+
harness: "claude-code",
|
|
16020
|
+
configDir,
|
|
16021
|
+
locations: [
|
|
16022
|
+
{
|
|
16023
|
+
kind: "plugin-cache",
|
|
16024
|
+
path: join(plugins, "cache"),
|
|
16025
|
+
description: "Installed plugins as <marketplace>/<plugin>/<version>/",
|
|
16026
|
+
research: "E-CC-P1"
|
|
16027
|
+
},
|
|
16028
|
+
{
|
|
16029
|
+
kind: "marketplaces",
|
|
16030
|
+
path: join(plugins, "marketplaces"),
|
|
16031
|
+
description: "Marketplace checkouts",
|
|
16032
|
+
research: "E-CC-P1"
|
|
16033
|
+
},
|
|
16034
|
+
{
|
|
16035
|
+
kind: "install-record",
|
|
16036
|
+
path: join(plugins, "installed_plugins.json"),
|
|
16037
|
+
description: "Installs keyed by plugin@marketplace, each with scope, installPath, and version",
|
|
16038
|
+
research: "E-CC-P2"
|
|
16039
|
+
},
|
|
16040
|
+
{
|
|
16041
|
+
kind: "enabled-record",
|
|
16042
|
+
path: join(configDir, "settings.json"),
|
|
16043
|
+
description: "User settings; enabledPlugins maps plugin@marketplace to a boolean",
|
|
16044
|
+
research: "E-CC-P3"
|
|
16045
|
+
}
|
|
16046
|
+
]
|
|
16047
|
+
};
|
|
16048
|
+
},
|
|
16049
|
+
cursor: ({ homedir }) => {
|
|
16050
|
+
const configDir = join(homedir, ".cursor");
|
|
16051
|
+
return {
|
|
16052
|
+
harness: "cursor",
|
|
16053
|
+
configDir,
|
|
16054
|
+
locations: [{
|
|
16055
|
+
kind: "local-plugins",
|
|
16056
|
+
path: join(configDir, "plugins", "local"),
|
|
16057
|
+
description: "Plugins under development, one folder each",
|
|
16058
|
+
research: "E-CUR-P2"
|
|
16059
|
+
}, {
|
|
16060
|
+
kind: "marketplaces",
|
|
16061
|
+
path: join(configDir, "plugins", "marketplaces"),
|
|
16062
|
+
description: "Marketplace checkouts",
|
|
16063
|
+
research: "E-CUR-P3"
|
|
16064
|
+
}]
|
|
16065
|
+
};
|
|
16066
|
+
},
|
|
16067
|
+
codex: ({ env, homedir }) => {
|
|
16068
|
+
const configDir = env.CODEX_HOME || join(homedir, ".codex");
|
|
16069
|
+
return {
|
|
16070
|
+
harness: "codex",
|
|
16071
|
+
configDir,
|
|
16072
|
+
locations: [{
|
|
16073
|
+
kind: "plugin-cache",
|
|
16074
|
+
path: join(configDir, "plugins", "cache"),
|
|
16075
|
+
description: "Installed plugins as <marketplace>/<plugin>/<version>/",
|
|
16076
|
+
research: "E-CODEX-P3"
|
|
16077
|
+
}, {
|
|
16078
|
+
kind: "enabled-record",
|
|
16079
|
+
path: join(configDir, "config.toml"),
|
|
16080
|
+
description: "User config; [plugins.\"<plugin>@<marketplace>\"] tables carry enabled = <bool>",
|
|
16081
|
+
research: "E-CODEX-P2"
|
|
16082
|
+
}]
|
|
16083
|
+
};
|
|
16084
|
+
},
|
|
16085
|
+
"copilot-cli": ({ env, homedir }) => {
|
|
16086
|
+
const configDir = env.COPILOT_HOME || join(homedir, ".copilot");
|
|
16087
|
+
return {
|
|
16088
|
+
harness: "copilot-cli",
|
|
16089
|
+
configDir,
|
|
16090
|
+
locations: [
|
|
16091
|
+
{
|
|
16092
|
+
kind: "installed-plugins",
|
|
16093
|
+
path: join(configDir, "installed-plugins"),
|
|
16094
|
+
description: "Installed plugins as <marketplace>/<plugin>/, or _direct/<source-id>/ for direct installs",
|
|
16095
|
+
research: "E-COPILOT-P9"
|
|
16096
|
+
},
|
|
16097
|
+
{
|
|
16098
|
+
kind: "install-record",
|
|
16099
|
+
path: join(configDir, "config.json"),
|
|
16100
|
+
description: "Application state, including installedPlugins",
|
|
16101
|
+
research: "E-COPILOT-P9"
|
|
16102
|
+
},
|
|
16103
|
+
{
|
|
16104
|
+
kind: "enabled-record",
|
|
16105
|
+
path: join(configDir, "settings.json"),
|
|
16106
|
+
description: "User settings (JSON with comments); enabledPlugins maps plugin specs to a boolean",
|
|
16107
|
+
research: "E-COPILOT-P4"
|
|
16108
|
+
}
|
|
16109
|
+
]
|
|
16110
|
+
};
|
|
16111
|
+
},
|
|
16112
|
+
opencode: (environment) => {
|
|
16113
|
+
const configDir = join(xdgConfig(environment), "opencode");
|
|
16114
|
+
return {
|
|
16115
|
+
harness: "opencode",
|
|
16116
|
+
configDir,
|
|
16117
|
+
locations: [{
|
|
16118
|
+
kind: "local-plugins",
|
|
16119
|
+
path: join(configDir, "plugins"),
|
|
16120
|
+
description: "JS/TS plugin modules loaded at startup; npm plugins are named in the plugin config array",
|
|
16121
|
+
research: "E-OC-P2"
|
|
16122
|
+
}]
|
|
16123
|
+
};
|
|
16124
|
+
},
|
|
16125
|
+
kilo: (environment) => {
|
|
16126
|
+
const configDir = join(xdgConfig(environment), "kilo");
|
|
16127
|
+
return {
|
|
16128
|
+
harness: "kilo",
|
|
16129
|
+
configDir,
|
|
16130
|
+
locations: [{
|
|
16131
|
+
kind: "local-plugins",
|
|
16132
|
+
path: join(configDir, "plugin"),
|
|
16133
|
+
description: "JS/TS plugin modules loaded at startup; npm plugins are named in the plugin config array",
|
|
16134
|
+
research: "E-KILO-P2"
|
|
16135
|
+
}]
|
|
16136
|
+
};
|
|
16137
|
+
},
|
|
16138
|
+
"gemini-cli": ({ env, homedir }) => {
|
|
16139
|
+
const configDir = join(env.GEMINI_CLI_HOME || homedir, ".gemini");
|
|
16140
|
+
const extensions = join(configDir, "extensions");
|
|
16141
|
+
return {
|
|
16142
|
+
harness: "gemini-cli",
|
|
16143
|
+
configDir,
|
|
16144
|
+
locations: [{
|
|
16145
|
+
kind: "installed-plugins",
|
|
16146
|
+
path: extensions,
|
|
16147
|
+
description: "Installed extensions, one folder each with a gemini-extension.json manifest",
|
|
16148
|
+
research: "E-GEM-P1"
|
|
16149
|
+
}, {
|
|
16150
|
+
kind: "enabled-record",
|
|
16151
|
+
path: join(extensions, "extension-enablement.json"),
|
|
16152
|
+
description: "Per-extension path-glob overrides that enable or disable it by folder, not a boolean",
|
|
16153
|
+
research: "E-GEM-P3"
|
|
16154
|
+
}]
|
|
16155
|
+
};
|
|
16156
|
+
},
|
|
16157
|
+
"qwen-code": ({ env, homedir }) => {
|
|
16158
|
+
const configDir = env.QWEN_HOME || join(homedir, ".qwen");
|
|
16159
|
+
const extensions = join(configDir, "extensions");
|
|
16160
|
+
return {
|
|
16161
|
+
harness: "qwen-code",
|
|
16162
|
+
configDir,
|
|
16163
|
+
locations: [{
|
|
16164
|
+
kind: "installed-plugins",
|
|
16165
|
+
path: extensions,
|
|
16166
|
+
description: "Installed extensions, one folder each with a qwen-extension.json manifest",
|
|
16167
|
+
research: "E-QWEN-P1"
|
|
16168
|
+
}, {
|
|
16169
|
+
kind: "enabled-record",
|
|
16170
|
+
path: join(extensions, "extension-enablement.json"),
|
|
16171
|
+
description: "Extension enable/disable state, inherited from Gemini CLI's format",
|
|
16172
|
+
research: "E-QWEN-P2"
|
|
16173
|
+
}]
|
|
16174
|
+
};
|
|
16175
|
+
},
|
|
16176
|
+
"vscode-copilot": (environment) => {
|
|
16177
|
+
const { configDir, path } = vscodeAgentPlugins(environment);
|
|
16178
|
+
return {
|
|
16179
|
+
harness: "vscode-copilot",
|
|
16180
|
+
configDir,
|
|
16181
|
+
locations: [{
|
|
16182
|
+
kind: "installed-plugins",
|
|
16183
|
+
path,
|
|
16184
|
+
description: "Installed agent plugins as <host>/<org>/<repo>/",
|
|
16185
|
+
research: "E-VSC-P3"
|
|
16186
|
+
}]
|
|
16187
|
+
};
|
|
16188
|
+
},
|
|
16189
|
+
cline: ({ homedir }) => {
|
|
16190
|
+
const configDir = join(homedir, ".cline");
|
|
16191
|
+
return {
|
|
16192
|
+
harness: "cline",
|
|
16193
|
+
configDir,
|
|
16194
|
+
locations: [{
|
|
16195
|
+
kind: "installed-plugins",
|
|
16196
|
+
path: join(configDir, "plugins", "_installed"),
|
|
16197
|
+
description: "Installed plugins, grouped by source: npm, git, remote, or local",
|
|
16198
|
+
research: "E-CLINE-P3"
|
|
16199
|
+
}]
|
|
16200
|
+
};
|
|
16201
|
+
},
|
|
16202
|
+
crush: ({ env, homedir }) => {
|
|
16203
|
+
return {
|
|
16204
|
+
harness: "crush",
|
|
16205
|
+
configDir: env.CRUSH_GLOBAL_CONFIG || join(env.XDG_CONFIG_HOME || join(homedir, ".config"), "crush"),
|
|
16206
|
+
locations: []
|
|
16207
|
+
};
|
|
16208
|
+
},
|
|
16209
|
+
openhands: ({ env, homedir }) => {
|
|
16210
|
+
const configDir = env.OH_PERSISTENCE_DIR || env.OPENHANDS_PERSISTENCE_DIR || join(homedir, ".openhands");
|
|
16211
|
+
const installed = join(configDir, "plugins", "installed");
|
|
16212
|
+
return {
|
|
16213
|
+
harness: "openhands",
|
|
16214
|
+
configDir,
|
|
16215
|
+
locations: [{
|
|
16216
|
+
kind: "installed-plugins",
|
|
16217
|
+
path: installed,
|
|
16218
|
+
description: "Installed plugins, one folder each",
|
|
16219
|
+
research: "E-OH-P3"
|
|
16220
|
+
}, {
|
|
16221
|
+
kind: "enabled-record",
|
|
16222
|
+
path: join(installed, ".installed.json"),
|
|
16223
|
+
description: "Install metadata keyed by plugin name, each with enabled: <bool>",
|
|
16224
|
+
research: "E-OH-P4"
|
|
16225
|
+
}]
|
|
16226
|
+
};
|
|
16227
|
+
},
|
|
16228
|
+
augment: ({ homedir }) => {
|
|
16229
|
+
const configDir = join(homedir, ".augment");
|
|
16230
|
+
return {
|
|
16231
|
+
harness: "augment",
|
|
16232
|
+
configDir,
|
|
16233
|
+
locations: [{
|
|
16234
|
+
kind: "marketplaces",
|
|
16235
|
+
path: join(configDir, "plugins", "marketplaces"),
|
|
16236
|
+
description: "Marketplace checkouts",
|
|
16237
|
+
research: "E-AUG-P2"
|
|
16238
|
+
}, {
|
|
16239
|
+
kind: "enabled-record",
|
|
16240
|
+
path: join(configDir, "settings.json"),
|
|
16241
|
+
description: "User settings; enabledPlugins maps plugin@marketplace to a boolean",
|
|
16242
|
+
research: "E-AUG-P4"
|
|
16243
|
+
}]
|
|
16244
|
+
};
|
|
16245
|
+
}
|
|
16246
|
+
};
|
|
16247
|
+
//#endregion
|
|
16248
|
+
//#region ../../node_modules/.pnpm/cyber-agentkit@2.0.0/node_modules/cyber-agentkit/dist/index.js
|
|
16249
|
+
const harnessIds = [
|
|
16250
|
+
"claude-code",
|
|
16251
|
+
"cursor",
|
|
16252
|
+
"codex",
|
|
16253
|
+
"copilot-cli",
|
|
16254
|
+
"opencode",
|
|
16255
|
+
"kilo",
|
|
16256
|
+
"gemini-cli",
|
|
16257
|
+
"qwen-code",
|
|
16258
|
+
"vscode-copilot",
|
|
16259
|
+
"cline",
|
|
16260
|
+
"crush",
|
|
16261
|
+
"openhands",
|
|
16262
|
+
"augment"
|
|
16263
|
+
];
|
|
16264
|
+
//#endregion
|
|
16265
|
+
//#region src/vendor-registry/vendor-registry.ts
|
|
16266
|
+
function lookupVendor(registry, vendorId) {
|
|
16267
|
+
return registry[vendorId] ?? null;
|
|
16245
16268
|
}
|
|
16246
16269
|
function mergeRegistries(base, override) {
|
|
16247
16270
|
const result = { ...base };
|
|
@@ -16929,6 +16952,19 @@ function marketplaceSpec(value) {
|
|
|
16929
16952
|
};
|
|
16930
16953
|
}
|
|
16931
16954
|
const SHA = /^[a-f0-9]{40}$/;
|
|
16955
|
+
/** Whether a source is one of the git-backed forms, the only ones a `ref` or `sha` can pin. */
|
|
16956
|
+
function isGitSource(source) {
|
|
16957
|
+
if (typeof source !== "object" || source === null || Array.isArray(source)) return false;
|
|
16958
|
+
return [
|
|
16959
|
+
"url",
|
|
16960
|
+
"github",
|
|
16961
|
+
"git-subdir"
|
|
16962
|
+
].includes(source.source);
|
|
16963
|
+
}
|
|
16964
|
+
/** The schema requires the full hash, so a short one is refused at input rather than at load. */
|
|
16965
|
+
function assertCommitSha(sha) {
|
|
16966
|
+
if (!SHA.test(sha)) throw new Error(`error: --sha "${sha}" must be a full 40-character commit hash`);
|
|
16967
|
+
}
|
|
16932
16968
|
/** A subdirectory as `git-subdir` states it: no leading `./`, no trailing slash. */
|
|
16933
16969
|
function normalizeSubdir(subdir) {
|
|
16934
16970
|
const path = subdir.trim().replace(/\\/g, "/").replace(/^\.\/?/, "").replace(/\/+$/, "");
|
|
@@ -16966,12 +17002,8 @@ function withSubdir(spec, subdir) {
|
|
|
16966
17002
|
function withPin(spec, ref, sha) {
|
|
16967
17003
|
if (ref === void 0 && sha === void 0) return spec;
|
|
16968
17004
|
const source = spec.source;
|
|
16969
|
-
if (
|
|
16970
|
-
|
|
16971
|
-
"github",
|
|
16972
|
-
"git-subdir"
|
|
16973
|
-
].includes(source.source)) throw new Error(`error: --ref and --sha apply to a git source, not to a ${spec.kind} one`);
|
|
16974
|
-
if (sha !== void 0 && !SHA.test(sha)) throw new Error(`error: --sha "${sha}" must be a full 40-character commit hash`);
|
|
17005
|
+
if (!isGitSource(source)) throw new Error(`error: --ref and --sha apply to a git source, not to a ${spec.kind} one`);
|
|
17006
|
+
if (sha !== void 0) assertCommitSha(sha);
|
|
16975
17007
|
return {
|
|
16976
17008
|
...spec,
|
|
16977
17009
|
source: {
|
|
@@ -17391,6 +17423,194 @@ function parseAndCheck(content, check) {
|
|
|
17391
17423
|
return check(parsed);
|
|
17392
17424
|
}
|
|
17393
17425
|
//#endregion
|
|
17426
|
+
//#region src/marketplace/update.ts
|
|
17427
|
+
/** The fields `update` sets by flag: the ones `add` writes, plus `category`, which a curator sets by
|
|
17428
|
+
* hand and `add --force` has no way to keep. */
|
|
17429
|
+
const UPDATE_FIELDS = [...ENTRY_METADATA_FIELDS, "category"];
|
|
17430
|
+
const PINS = ["ref", "sha"];
|
|
17431
|
+
/** The field flags a Codex entry carries. Its catalog states a plugin by name, source, version, and
|
|
17432
|
+
* category, so a description or a license set there would be a field no generator writes. */
|
|
17433
|
+
const CODEX_FIELDS = ["version", "category"];
|
|
17434
|
+
/** Reads the flags into one change, refusing a request that contradicts itself or changes nothing. */
|
|
17435
|
+
function readChange(opts) {
|
|
17436
|
+
const unset = [...new Set(opts.unset ?? [])];
|
|
17437
|
+
for (const field of unset) if (field === "name" || field === "source") throw new Error(`error: --unset cannot remove "${field}"; every entry needs one`);
|
|
17438
|
+
const metadata = {};
|
|
17439
|
+
for (const [field, value] of Object.entries(opts.metadata ?? {})) if (value !== void 0) metadata[field] = value;
|
|
17440
|
+
const set = [
|
|
17441
|
+
...Object.keys(metadata),
|
|
17442
|
+
...opts.ref === void 0 ? [] : ["ref"],
|
|
17443
|
+
...opts.sha === void 0 ? [] : ["sha"]
|
|
17444
|
+
];
|
|
17445
|
+
const both = set.filter((field) => unset.includes(field));
|
|
17446
|
+
if (both.length > 0) throw new Error(`error: "${both[0]}" is both set and unset`);
|
|
17447
|
+
if (opts.sha !== void 0) assertCommitSha(opts.sha);
|
|
17448
|
+
let source;
|
|
17449
|
+
if (opts.source !== void 0) {
|
|
17450
|
+
const parsed = parsePluginSpec(opts.source, {
|
|
17451
|
+
kind: opts.kind,
|
|
17452
|
+
subdir: opts.subdir,
|
|
17453
|
+
ref: opts.ref,
|
|
17454
|
+
sha: opts.sha
|
|
17455
|
+
});
|
|
17456
|
+
if (parsed.kind === "marketplace" || parsed.source === void 0) throw new Error("error: --source names where the plugin lives, not <plugin>@<marketplace>; copy an entry with marketplace add");
|
|
17457
|
+
source = parsed.source;
|
|
17458
|
+
} else if (opts.kind !== void 0 || opts.subdir !== void 0) throw new Error("error: a source kind and --subdir shape --source; pass --source as well");
|
|
17459
|
+
if (source === void 0 && opts.ref === void 0 && opts.sha === void 0 && set.length === 0 && unset.length === 0) throw new Error("error: nothing to change; pass --source, --ref, --sha, a field flag, or --unset");
|
|
17460
|
+
return {
|
|
17461
|
+
source,
|
|
17462
|
+
ref: opts.ref,
|
|
17463
|
+
sha: opts.sha,
|
|
17464
|
+
metadata,
|
|
17465
|
+
unset
|
|
17466
|
+
};
|
|
17467
|
+
}
|
|
17468
|
+
function pinsOf(source) {
|
|
17469
|
+
const pins = {};
|
|
17470
|
+
for (const pin of PINS) if (typeof source[pin] === "string") pins[pin] = source[pin];
|
|
17471
|
+
return pins;
|
|
17472
|
+
}
|
|
17473
|
+
/** The entry as it reads after the change, for one target. Every field the change does not name is
|
|
17474
|
+
* kept as it stands, and so is the key order. A new source this runtime cannot install leaves the
|
|
17475
|
+
* entry as it is, and the reason says why. */
|
|
17476
|
+
function changeEntry(target, catalogPath, entry, change) {
|
|
17477
|
+
const next = { ...entry };
|
|
17478
|
+
const pinned = change.ref !== void 0 || change.sha !== void 0;
|
|
17479
|
+
if (change.source !== void 0) {
|
|
17480
|
+
const adapted = adaptSource(target, !pinned && isGitSource(change.source) && isGitSource(entry.source) ? {
|
|
17481
|
+
...change.source,
|
|
17482
|
+
...pinsOf(entry.source)
|
|
17483
|
+
} : change.source);
|
|
17484
|
+
if ("omitted" in adapted) return { omitted: adapted.omitted };
|
|
17485
|
+
next.source = catalogEntrySource(target, adapted.source);
|
|
17486
|
+
} else if (pinned) {
|
|
17487
|
+
if (!isGitSource(entry.source)) {
|
|
17488
|
+
const kind = typeof entry.source === "string" || typeof entry.source === "object" && entry.source !== null ? sourceKindOf(entry.source) : "missing";
|
|
17489
|
+
throw new Error(`error: "${String(entry.name)}" in ${catalogPath} has a ${kind} source; --ref and --sha apply to a git source`);
|
|
17490
|
+
}
|
|
17491
|
+
next.source = {
|
|
17492
|
+
...entry.source,
|
|
17493
|
+
...change.ref === void 0 ? {} : { ref: change.ref },
|
|
17494
|
+
...change.sha === void 0 ? {} : { sha: change.sha }
|
|
17495
|
+
};
|
|
17496
|
+
}
|
|
17497
|
+
for (const [field, value] of Object.entries(change.metadata)) {
|
|
17498
|
+
if (target === "codex" && !CODEX_FIELDS.includes(field)) continue;
|
|
17499
|
+
next[field] = value;
|
|
17500
|
+
}
|
|
17501
|
+
for (const field of change.unset) if (PINS.includes(field)) {
|
|
17502
|
+
if (isGitSource(next.source)) {
|
|
17503
|
+
const { [field]: _removed, ...rest } = next.source;
|
|
17504
|
+
next.source = rest;
|
|
17505
|
+
}
|
|
17506
|
+
} else delete next[field];
|
|
17507
|
+
return { entry: next };
|
|
17508
|
+
}
|
|
17509
|
+
/** Reads the catalogs as they would be once `writes` landed, so validation sees the result before
|
|
17510
|
+
* anything is written. */
|
|
17511
|
+
function overlay(fs, writes) {
|
|
17512
|
+
return {
|
|
17513
|
+
...fs,
|
|
17514
|
+
exists: (file) => writes.has(file) || fs.exists(file),
|
|
17515
|
+
read: (file) => writes.get(file) ?? fs.read(file)
|
|
17516
|
+
};
|
|
17517
|
+
}
|
|
17518
|
+
function issueKey(file, issue) {
|
|
17519
|
+
return `${file}\0${issue.path}\0${issue.message}`;
|
|
17520
|
+
}
|
|
17521
|
+
/** Changes one entry already listed in this repository's catalogs, in place.
|
|
17522
|
+
*
|
|
17523
|
+
* `marketplace add --force` replaces an entry with what it can derive, which drops anything it
|
|
17524
|
+
* cannot: a `category`, an `author`, a field a curator wrote by hand. This keeps every field the
|
|
17525
|
+
* request does not name, and changes only the ones it does — the source, a pin, one field.
|
|
17526
|
+
*
|
|
17527
|
+
* The result is validated before anything is written. An update that would leave a catalog with a
|
|
17528
|
+
* problem it did not have before stops; problems that were already there are `validate`'s to report.
|
|
17529
|
+
* Nothing is fetched and nothing is published. */
|
|
17530
|
+
function updateMarketplaceEntry(rootInput, name, opts = {}, fs = realMarketplaceFs) {
|
|
17531
|
+
const root = path$1.resolve(rootInput);
|
|
17532
|
+
assertMarketplaceName(name, "plugin name");
|
|
17533
|
+
const change = readChange(opts);
|
|
17534
|
+
const targets = selectedTargets(opts.targets);
|
|
17535
|
+
const planned = targets.map((target) => {
|
|
17536
|
+
const catalogPath = TARGET_CATALOG_PATHS[target];
|
|
17537
|
+
const file = path$1.join(root, catalogPath);
|
|
17538
|
+
if (!fs.exists(file)) return {
|
|
17539
|
+
target,
|
|
17540
|
+
catalogPath,
|
|
17541
|
+
file,
|
|
17542
|
+
skipped: `no catalog at ${catalogPath}`
|
|
17543
|
+
};
|
|
17544
|
+
const existing = fs.read(file);
|
|
17545
|
+
const entry = findCatalogEntry(existing, catalogPath, name);
|
|
17546
|
+
if (entry === void 0) return {
|
|
17547
|
+
target,
|
|
17548
|
+
catalogPath,
|
|
17549
|
+
file,
|
|
17550
|
+
existing,
|
|
17551
|
+
skipped: `"${name}" is not listed in ${catalogPath}`
|
|
17552
|
+
};
|
|
17553
|
+
const changed = changeEntry(target, catalogPath, entry, change);
|
|
17554
|
+
if ("omitted" in changed) return {
|
|
17555
|
+
target,
|
|
17556
|
+
catalogPath,
|
|
17557
|
+
file,
|
|
17558
|
+
existing,
|
|
17559
|
+
source: entry.source,
|
|
17560
|
+
skipped: `${changed.omitted}; "${name}" keeps its current source in ${catalogPath}`
|
|
17561
|
+
};
|
|
17562
|
+
return {
|
|
17563
|
+
target,
|
|
17564
|
+
catalogPath,
|
|
17565
|
+
file,
|
|
17566
|
+
existing,
|
|
17567
|
+
source: changed.entry.source,
|
|
17568
|
+
content: replaceCatalogEntry(existing, catalogPath, changed.entry)
|
|
17569
|
+
};
|
|
17570
|
+
});
|
|
17571
|
+
if (!planned.some((entry) => entry.source !== void 0)) throw new Error(`error: "${name}" is not listed in any selected catalog; list it with marketplace add`);
|
|
17572
|
+
const claude = planned.find((entry) => entry.target === "claude");
|
|
17573
|
+
if (claude?.content !== void 0 && !sameCatalogContent(claude.existing, claude.content)) for (const entry of planned) {
|
|
17574
|
+
if (entry.existing !== void 0 || entry.target !== "copilot" && entry.target !== "cursor") continue;
|
|
17575
|
+
if (!adaptCatalogContent(entry.target, claude.content).omitted.some((item) => item.name === name)) continue;
|
|
17576
|
+
entry.content = deriveSharedCatalog(entry.target, claude.content);
|
|
17577
|
+
entry.skipped = `${entry.skipped}, and ${entry.target} reads the Claude one, where "${name}" now has a source it cannot install; wrote ${entry.catalogPath} without it`;
|
|
17578
|
+
}
|
|
17579
|
+
const changed = planned.filter((entry) => entry.content !== void 0 && (entry.existing === void 0 || !sameCatalogContent(entry.existing, entry.content)));
|
|
17580
|
+
const writes = new Map(changed.map((entry) => [entry.file, entry.content]));
|
|
17581
|
+
const before = validateMarketplace(root, { targets }, fs);
|
|
17582
|
+
const after = validateMarketplace(root, { targets }, overlay(fs, writes));
|
|
17583
|
+
const known = new Set(before.flatMap((row) => row.issues.map((issue) => issueKey(row.path, issue))));
|
|
17584
|
+
const introduced = after.map((row) => ({
|
|
17585
|
+
path: row.path,
|
|
17586
|
+
issues: row.issues.filter((issue) => !known.has(issueKey(row.path, issue)))
|
|
17587
|
+
})).filter((row) => row.issues.length > 0);
|
|
17588
|
+
if (introduced.length > 0) throw new Error(introduced.map((row) => formatCatalogIssues(row.path, row.issues)).join("\n"));
|
|
17589
|
+
const results = planned.map((entry) => {
|
|
17590
|
+
const row = {
|
|
17591
|
+
target: entry.target,
|
|
17592
|
+
entry: name,
|
|
17593
|
+
source: entry.source === void 0 ? "-" : describeSource(entry.source),
|
|
17594
|
+
path: entry.catalogPath
|
|
17595
|
+
};
|
|
17596
|
+
if (entry.skipped !== void 0) return {
|
|
17597
|
+
...row,
|
|
17598
|
+
status: "skipped",
|
|
17599
|
+
reason: entry.skipped
|
|
17600
|
+
};
|
|
17601
|
+
if (!changed.includes(entry)) return {
|
|
17602
|
+
...row,
|
|
17603
|
+
status: "unchanged"
|
|
17604
|
+
};
|
|
17605
|
+
return {
|
|
17606
|
+
...row,
|
|
17607
|
+
status: opts.dryRun ? "planned" : "updated"
|
|
17608
|
+
};
|
|
17609
|
+
});
|
|
17610
|
+
if (!opts.dryRun) for (const [file, content] of writes) fs.writeAtomically(file, content);
|
|
17611
|
+
return results;
|
|
17612
|
+
}
|
|
17613
|
+
//#endregion
|
|
17394
17614
|
//#region src/marketplace/cli.ts
|
|
17395
17615
|
function targetsFromOptions(opts) {
|
|
17396
17616
|
const targets = [
|
|
@@ -17460,6 +17680,48 @@ function addCommand() {
|
|
|
17460
17680
|
}
|
|
17461
17681
|
});
|
|
17462
17682
|
}
|
|
17683
|
+
function updateMetadataFromOptions(opts) {
|
|
17684
|
+
const metadata = { ...metadataFromOptions(opts) };
|
|
17685
|
+
for (const field of UPDATE_FIELDS) {
|
|
17686
|
+
const value = opts[field];
|
|
17687
|
+
if (!(field in metadata) && typeof value === "string") metadata[field] = value;
|
|
17688
|
+
}
|
|
17689
|
+
return metadata;
|
|
17690
|
+
}
|
|
17691
|
+
function updateCommand() {
|
|
17692
|
+
return new Command("update").description("Change one entry already listed in this repository's marketplace catalogs, keeping the rest").argument("<name>", "The entry to change, as the catalogs list it").option("--claude", "Update the Claude marketplace catalog").option("--codex", "Update the Codex marketplace catalog").option("--copilot", "Update the Copilot marketplace catalog").option("--cursor", "Update the Cursor marketplace catalog").option("--source <spec>", "New source, read the way marketplace add reads its spec").option("--path", "Read --source as a repository-relative path").option("--npm", "Read --source as an npm package name").option("--github", "Read --source as an owner/repo GitHub repository").option("--url", "Read --source as a git or https URL").option("--subdir <path>", "The plugin's directory inside the --source repository, for a monorepo").option("--ref <ref>", "Branch or tag to pin the git source to").option("--sha <sha>", "Commit to pin the git source to (full 40-character hash)").option("--description <text>", "Entry description").option("--version <version>", "Entry version").option("--homepage <url>", "Entry homepage").option("--repository <url>", "Entry repository URL").option("--license <id>", "Entry license").option("--keywords <list>", "Entry keywords, comma-separated").option("--category <name>", "Entry category").option("--unset <field>", "Remove a field from the entry; ref and sha remove a pin (repeatable)", (value, previous = []) => [...previous, value]).option("--dry-run", "Preview the change without writing it").option("--format <format>", "Output format: toon or json (default: toon)").addOption(ROOT_OPTION).addHelpText("after", "\nExamples:\n $ universal-plugin marketplace update aced --source https://github.com/cyberuni/cyber-sdd.git --subdir plugins/aced\n $ universal-plugin marketplace update aced --ref v1.3.0 --unset sha\n $ universal-plugin marketplace update repobuddy --category productivity --dry-run\n").action((name, opts) => {
|
|
17693
|
+
try {
|
|
17694
|
+
if (opts.format !== void 0 && opts.format !== "toon" && opts.format !== "json") throw new Error("error: --format must be \"toon\" or \"json\"");
|
|
17695
|
+
const results = updateMarketplaceEntry(resolveRoot(opts.root), name, {
|
|
17696
|
+
targets: targetsFromOptions(opts),
|
|
17697
|
+
source: opts.source,
|
|
17698
|
+
kind: kindFromOptions(opts),
|
|
17699
|
+
subdir: opts.subdir,
|
|
17700
|
+
ref: opts.ref,
|
|
17701
|
+
sha: opts.sha,
|
|
17702
|
+
metadata: updateMetadataFromOptions(opts),
|
|
17703
|
+
unset: opts.unset,
|
|
17704
|
+
dryRun: opts.dryRun
|
|
17705
|
+
});
|
|
17706
|
+
output(results, {
|
|
17707
|
+
targets: results.map((row) => ({
|
|
17708
|
+
target: row.target,
|
|
17709
|
+
status: row.status,
|
|
17710
|
+
entry: row.entry,
|
|
17711
|
+
source: row.source,
|
|
17712
|
+
path: row.path,
|
|
17713
|
+
reason: row.reason ?? "-"
|
|
17714
|
+
})),
|
|
17715
|
+
summary: `${results.filter((row) => row.status === "skipped").length} skipped of ${results.length}`
|
|
17716
|
+
});
|
|
17717
|
+
for (const row of results.filter((row) => row.status === "skipped")) process.stderr.write(`skipped ${row.target}: ${row.reason}\n`);
|
|
17718
|
+
process.stderr.write(`${opts.dryRun ? "Planned" : "Wrote"} repository metadata only; no marketplace publication, registration, installation, authentication, or provisioning occurred.\n`);
|
|
17719
|
+
} catch (err) {
|
|
17720
|
+
process.stderr.write(`${err instanceof Error ? err.message : String(err)}\n`);
|
|
17721
|
+
process.exitCode = 1;
|
|
17722
|
+
}
|
|
17723
|
+
});
|
|
17724
|
+
}
|
|
17463
17725
|
function initCommand() {
|
|
17464
17726
|
return new Command("init").description("Generate local marketplace metadata without publishing or provisioning").option("--claude", "Generate the Claude marketplace catalog").option("--codex", "Generate the Codex marketplace catalog").option("--copilot", "Generate the Copilot marketplace catalog").option("--cursor", "Generate the Cursor marketplace catalog").option("--plugin-scan-dir <dir>", "Directory beneath --root to scan for root-level plugin.json files (repeatable)", (value, previous = []) => [...previous, value]).option("--name <name>", "Override the marketplace name").option("--owner <name>", "Override the marketplace owner").option("--dry-run", "Preview artifacts without writing them").option("--force", "Replace differing artifacts for selected targets").option("--format <format>", "Output format: toon or json (default: toon)").addOption(new Option("--json").hideHelp()).addOption(ROOT_OPTION).addHelpText("after", "\nExample:\n $ universal-plugin marketplace init --root .\n").action((opts) => {
|
|
17465
17727
|
try {
|
|
@@ -17521,7 +17783,7 @@ function validateCommand$1() {
|
|
|
17521
17783
|
});
|
|
17522
17784
|
}
|
|
17523
17785
|
function marketplaceCommand() {
|
|
17524
|
-
return new Command("marketplace").description("Generate repository-local marketplace metadata").addCommand(addCommand()).addCommand(initCommand()).addCommand(validateCommand$1());
|
|
17786
|
+
return new Command("marketplace").description("Generate repository-local marketplace metadata").addCommand(addCommand()).addCommand(initCommand()).addCommand(updateCommand()).addCommand(validateCommand$1());
|
|
17525
17787
|
}
|
|
17526
17788
|
//#endregion
|
|
17527
17789
|
//#region src/prepare/installed-plugins.ts
|
|
@@ -18041,7 +18303,7 @@ function stringField(value, key) {
|
|
|
18041
18303
|
function publishCommand() {
|
|
18042
18304
|
const cmd = new Command("publish").description("Prepare plugin for publishing").helpCommand(false);
|
|
18043
18305
|
cmd.command("sync-version").description("Deprecated: use `plugin version --from-package`").option("--no-build", "Skip re-deriving the vendor manifests").option("--format <format>", "Output format: json or toon (default: toon)").addOption(ROOT_OPTION).action((opts) => {
|
|
18044
|
-
process.stderr.write("warn: publish sync-version is deprecated and will be removed in
|
|
18306
|
+
process.stderr.write("warn: publish sync-version is deprecated since 0.14.0 and will be removed in a later release — use plugin version --from-package\n");
|
|
18045
18307
|
runVersion(void 0, {
|
|
18046
18308
|
...opts,
|
|
18047
18309
|
fromPackage: true
|