@skill-map/cli 0.54.0 → 0.55.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/dist/cli/tutorial/sm-tutorial/SKILL.md +22 -24
- package/dist/cli/tutorial/sm-tutorial/references/_core.md +8 -7
- package/dist/cli/tutorial/sm-tutorial/references/_manifest.yml +21 -42
- package/dist/cli/tutorial/sm-tutorial/references/fixtures.md +15 -7
- package/dist/cli/tutorial/sm-tutorial/references/part-authoring.md +2 -2
- package/dist/cli/tutorial/sm-tutorial/references/part-cli.md +1 -1
- package/dist/cli/tutorial/sm-tutorial/references/part-connect-harness.md +9 -10
- package/dist/cli/tutorial/sm-tutorial/references/part-daily-loop.md +563 -0
- package/dist/cli/tutorial/sm-tutorial/references/part-mcp.md +5 -1
- package/dist/cli/tutorial/sm-tutorial/references/part-plugins.md +7 -7
- package/dist/cli/tutorial/sm-tutorial/references/part-project-kickoff.md +24 -12
- package/dist/cli/tutorial/sm-tutorial/references/part-settings.md +2 -2
- package/dist/cli.js +594 -485
- package/dist/index.js +127 -13
- package/dist/kernel/index.d.ts +187 -94
- package/dist/kernel/index.js +127 -13
- package/dist/migrations/001_initial.sql +5 -0
- package/dist/ui/chunk-CN6IOM67.js +2 -0
- package/dist/ui/chunk-HPKRDGLH.js +123 -0
- package/dist/ui/{chunk-CXTU4HQV.js → chunk-LREXXX7T.js} +1 -1
- package/dist/ui/{chunk-BUNPMGDX.js → chunk-RGB5FBZL.js} +28 -28
- package/dist/ui/{chunk-4CXAL43H.js → chunk-XAM6VKXM.js} +1 -1
- package/dist/ui/index.html +2 -2
- package/dist/ui/{main-HP3MOLI2.js → main-7YXBWYHE.js} +3 -3
- package/dist/ui/{styles-4SNVM34O.css → styles-HRJG67XW.css} +1 -1
- package/migrations/001_initial.sql +5 -0
- package/package.json +2 -2
- package/dist/cli/tutorial/sm-tutorial/references/part-live-site.md +0 -155
- package/dist/cli/tutorial/sm-tutorial/references/part-maintain.md +0 -284
- package/dist/cli/tutorial/sm-tutorial/references/part-run-harness.md +0 -181
- package/dist/ui/chunk-DSNBKMYU.js +0 -2
- package/dist/ui/chunk-MVRQGDZJ.js +0 -123
package/dist/cli.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// cli/entry.ts
|
|
2
2
|
|
|
3
|
-
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="
|
|
3
|
+
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="e21852cd-d92e-5bdf-abc7-02fffaa89502")}catch(e){}}();
|
|
4
4
|
import { existsSync as existsSync33 } from "fs";
|
|
5
5
|
import { Builtins, Cli as Cli2 } from "clipanion";
|
|
6
6
|
|
|
@@ -246,7 +246,7 @@ function bucketByKind(kind, instance, bag) {
|
|
|
246
246
|
// package.json
|
|
247
247
|
var package_default = {
|
|
248
248
|
name: "@skill-map/cli",
|
|
249
|
-
version: "0.
|
|
249
|
+
version: "0.55.0",
|
|
250
250
|
description: "skill-map reference implementation \u2014 kernel + CLI + adapters.",
|
|
251
251
|
license: "MIT",
|
|
252
252
|
type: "module",
|
|
@@ -883,7 +883,7 @@ var atDirectiveExtractor = {
|
|
|
883
883
|
id: ID,
|
|
884
884
|
pluginId: CLAUDE_PLUGIN_ID,
|
|
885
885
|
kind: "extractor",
|
|
886
|
-
description: "Detects `@<token>` directives in a node's body using Claude Code rules.
|
|
886
|
+
description: "Detects `@<token>` directives in a node's body using Claude Code rules, choosing the link kind by token shape. Example: a bare handle `@team` becomes a `mentions` link, while a file-flavoured token `@docs/api.md` becomes a `references` link.",
|
|
887
887
|
scope: "body",
|
|
888
888
|
precondition: { provider: ["claude"] },
|
|
889
889
|
// eslint-disable-next-line complexity
|
|
@@ -971,7 +971,7 @@ var slashCommandExtractor = {
|
|
|
971
971
|
id: ID2,
|
|
972
972
|
pluginId: CLAUDE_PLUGIN_ID,
|
|
973
973
|
kind: "extractor",
|
|
974
|
-
description: "Turns `/command` invocations in a node's body into arrows that point at the resolved slash command or skill, using Claude Code routing rules.",
|
|
974
|
+
description: "Turns `/command` invocations in a node's body into arrows that point at the resolved slash command or skill, using Claude Code routing rules. Example: `/deploy` in the body draws an arrow to the `deploy` command.",
|
|
975
975
|
scope: "body",
|
|
976
976
|
precondition: { provider: ["claude"] },
|
|
977
977
|
extract(ctx) {
|
|
@@ -1029,7 +1029,7 @@ var toolsCounterExtractor = {
|
|
|
1029
1029
|
id: ID3,
|
|
1030
1030
|
pluginId: CLAUDE_PLUGIN_ID,
|
|
1031
1031
|
kind: "extractor",
|
|
1032
|
-
description: "Counts the tools an agent declares in its frontmatter and shows the count on the agent card.",
|
|
1032
|
+
description: "Counts the tools an agent declares in its frontmatter and shows the count on the agent card. Example: an agent with `tools: [Bash, Read, Grep]` shows a count of 3.",
|
|
1033
1033
|
scope: "frontmatter",
|
|
1034
1034
|
precondition: { kind: ["claude/agent"] },
|
|
1035
1035
|
ui: { count },
|
|
@@ -1444,7 +1444,7 @@ var annotationsExtractor = {
|
|
|
1444
1444
|
id: ID4,
|
|
1445
1445
|
pluginId: CORE_PLUGIN_ID,
|
|
1446
1446
|
kind: "extractor",
|
|
1447
|
-
description: "Turns the `supersedes` and `supersededBy` entries from a node's `.sm` sidecar into arrows between nodes in the graph.",
|
|
1447
|
+
description: "Turns the `supersedes` and `supersededBy` entries from a node's `.sm` sidecar into arrows between nodes in the graph. Example: `supersededBy: v1-skill.md` in a `.sm` sidecar draws an arrow to `v1-skill.md`.",
|
|
1448
1448
|
scope: "frontmatter",
|
|
1449
1449
|
extract(ctx) {
|
|
1450
1450
|
const sourcePath = ctx.node.path;
|
|
@@ -1500,12 +1500,12 @@ function stringArray(value) {
|
|
|
1500
1500
|
// plugins/core/extractors/backtick-path/index.ts
|
|
1501
1501
|
import { posix as pathPosix2 } from "path";
|
|
1502
1502
|
var ID5 = "backtick-path";
|
|
1503
|
-
var PATH_RE = /(?<![\w/:.-])(?:\.{1,2}\/)?[\w.-]
|
|
1503
|
+
var PATH_RE = /(?<![\w/:.-])(?:\.{1,2}\/)?[\w][\w.-]*(?:\/[\w.-]+)*\.md\b(?![\w/])/g;
|
|
1504
1504
|
var backtickPathExtractor = {
|
|
1505
1505
|
id: ID5,
|
|
1506
1506
|
pluginId: CORE_PLUGIN_ID,
|
|
1507
1507
|
kind: "extractor",
|
|
1508
|
-
description: "Turns relative .md paths written inside code spans and fenced blocks into arrows between nodes in the graph.",
|
|
1508
|
+
description: "Turns relative .md paths written inside code spans and fenced blocks into arrows between nodes in the graph. Example: a backticked `references/rules.md` path draws an arrow to that file.",
|
|
1509
1509
|
scope: "body",
|
|
1510
1510
|
extract(ctx) {
|
|
1511
1511
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -1570,7 +1570,7 @@ var externalUrlCounterExtractor = {
|
|
|
1570
1570
|
id: ID6,
|
|
1571
1571
|
pluginId: CORE_PLUGIN_ID,
|
|
1572
1572
|
kind: "extractor",
|
|
1573
|
-
description: "Counts the distinct external URLs in a node's body and shows the count on the card.",
|
|
1573
|
+
description: "Counts the distinct external URLs in a node's body and shows the count on the card. Example: a body linking `https://example.com` and `https://docs.rs` shows a count of 2.",
|
|
1574
1574
|
scope: "body",
|
|
1575
1575
|
/**
|
|
1576
1576
|
* Phase 6 / View contribution system, surface the distinct-URL
|
|
@@ -1650,7 +1650,7 @@ var markdownLinkExtractor = {
|
|
|
1650
1650
|
id: ID7,
|
|
1651
1651
|
pluginId: CORE_PLUGIN_ID,
|
|
1652
1652
|
kind: "extractor",
|
|
1653
|
-
description: "Turns markdown links (`[text](path)`) in a node's body into arrows between nodes in the graph.",
|
|
1653
|
+
description: "Turns markdown links (`[text](path)`) in a node's body into arrows between nodes in the graph. Example: `[the guide](docs/guide.md)` draws an arrow to `docs/guide.md`.",
|
|
1654
1654
|
scope: "body",
|
|
1655
1655
|
extract(ctx) {
|
|
1656
1656
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -1675,13 +1675,15 @@ var markdownLinkExtractor = {
|
|
|
1675
1675
|
extractorId: ID7,
|
|
1676
1676
|
kind: "references",
|
|
1677
1677
|
target: resolved,
|
|
1678
|
-
//
|
|
1679
|
-
//
|
|
1680
|
-
//
|
|
1681
|
-
//
|
|
1682
|
-
//
|
|
1683
|
-
//
|
|
1684
|
-
|
|
1678
|
+
// 0.95: the `[text](path)` syntax is unambiguous (the spec's
|
|
1679
|
+
// "unambiguous syntax" tier), but NOT 1.0. `1.0` is reserved
|
|
1680
|
+
// for structured input and is earned post-walk by the
|
|
1681
|
+
// confidence-lift transform when `target` resolves to a real
|
|
1682
|
+
// node; an unresolved (broken) target is downgraded to the
|
|
1683
|
+
// broken floor (0.5) by the same transform. Emitting 1.0 here
|
|
1684
|
+
// would short-circuit the lift and make a broken link
|
|
1685
|
+
// indistinguishable from a resolved one.
|
|
1686
|
+
confidence: 0.95,
|
|
1685
1687
|
rationale: "unambiguous markdown link syntax",
|
|
1686
1688
|
trigger: {
|
|
1687
1689
|
originalTrigger: original,
|
|
@@ -1711,7 +1713,7 @@ var mcpToolsExtractor = {
|
|
|
1711
1713
|
id: ID8,
|
|
1712
1714
|
pluginId: CORE_PLUGIN_ID,
|
|
1713
1715
|
kind: "extractor",
|
|
1714
|
-
description: "Turns `tools: [mcp__<server>__<tool>]` entries in a node's frontmatter into an MCP node per unique server and an arrow from the source to each one.",
|
|
1716
|
+
description: "Turns `tools: [mcp__<server>__<tool>]` entries in a node's frontmatter into an MCP node per unique server and an arrow from the source to each one. Example: `tools: [mcp__github__create_pr]` adds an `mcp://github` node and an arrow to it.",
|
|
1715
1717
|
// Claude-convention pattern only; per-vendor flavours and the
|
|
1716
1718
|
// config-side MCP declaration (Phase 5b) are still pending, so the
|
|
1717
1719
|
// extractor ships flagged as experimental in list / show / Settings.
|
|
@@ -2004,11 +2006,7 @@ var ANNOTATION_STALE_TEXTS = {
|
|
|
2004
2006
|
// a literal placeholder the operator substitutes.
|
|
2005
2007
|
bodyTooltip: "Sidecar drift since last bump:\n \u2022 body\nRun `sm bump <path>` to refresh.",
|
|
2006
2008
|
frontmatterTooltip: "Sidecar drift since last bump:\n \u2022 frontmatter\nRun `sm bump <path>` to refresh.",
|
|
2007
|
-
bothTooltip: "Sidecar drift since last bump:\n \u2022 body\n \u2022 frontmatter\nRun `sm bump <path>` to refresh."
|
|
2008
|
-
/** Label of the inspector action button that dispatches a bump. */
|
|
2009
|
-
bumpLabel: "Bump",
|
|
2010
|
-
/** Tooltip shown when the bump button is disabled (the node is fresh, no drift). */
|
|
2011
|
-
bumpDisabledReason: "No drift to bump."
|
|
2009
|
+
bothTooltip: "Sidecar drift since last bump:\n \u2022 body\n \u2022 frontmatter\nRun `sm bump <path>` to refresh."
|
|
2012
2010
|
};
|
|
2013
2011
|
|
|
2014
2012
|
// plugins/core/analyzers/annotation-stale/index.ts
|
|
@@ -2024,10 +2022,6 @@ var staleBadge = {
|
|
|
2024
2022
|
emitWhenEmpty: false,
|
|
2025
2023
|
priority: 20
|
|
2026
2024
|
};
|
|
2027
|
-
var bumpButton = {
|
|
2028
|
-
slot: "inspector.action.button",
|
|
2029
|
-
priority: 10
|
|
2030
|
-
};
|
|
2031
2025
|
var annotationStaleAnalyzer = {
|
|
2032
2026
|
id: ID11,
|
|
2033
2027
|
pluginId: CORE_PLUGIN_ID,
|
|
@@ -2036,15 +2030,13 @@ var annotationStaleAnalyzer = {
|
|
|
2036
2030
|
mode: "deterministic",
|
|
2037
2031
|
// The natural fix is to bump the node: refreshes the sidecar hashes,
|
|
2038
2032
|
// increments `annotations.version`, and stamps the audit block. The
|
|
2039
|
-
// inspector surfaces `core/node-bump`
|
|
2040
|
-
|
|
2033
|
+
// inspector surfaces that affordance via the `core/node-bump` action's
|
|
2034
|
+
// own scan-time `project()` self-projection, not from this analyzer.
|
|
2035
|
+
ui: { staleIcon, staleBadge },
|
|
2041
2036
|
evaluate(ctx) {
|
|
2042
2037
|
const issues = [];
|
|
2043
2038
|
for (const node of ctx.nodes) {
|
|
2044
2039
|
const status = staleStatus(node.sidecar);
|
|
2045
|
-
if (node.sidecar?.present === true) {
|
|
2046
|
-
emitBumpButton(ctx, node.path, status !== null);
|
|
2047
|
-
}
|
|
2048
2040
|
if (status === null) continue;
|
|
2049
2041
|
issues.push({
|
|
2050
2042
|
analyzerId: ID11,
|
|
@@ -2080,15 +2072,6 @@ function messageFor(status, path) {
|
|
|
2080
2072
|
return tx(ANNOTATION_STALE_TEXTS.bothDrift, { path });
|
|
2081
2073
|
}
|
|
2082
2074
|
}
|
|
2083
|
-
function emitBumpButton(ctx, nodePath, enabled) {
|
|
2084
|
-
ctx.emitContribution(nodePath, bumpButton, {
|
|
2085
|
-
actionId: "core/node-bump",
|
|
2086
|
-
label: ANNOTATION_STALE_TEXTS.bumpLabel,
|
|
2087
|
-
icon: "pi-arrow-up-right",
|
|
2088
|
-
enabled,
|
|
2089
|
-
...enabled ? {} : { disabledReason: ANNOTATION_STALE_TEXTS.bumpDisabledReason }
|
|
2090
|
-
});
|
|
2091
|
-
}
|
|
2092
2075
|
function tooltipFor(status) {
|
|
2093
2076
|
switch (status) {
|
|
2094
2077
|
case "stale-body":
|
|
@@ -2539,16 +2522,25 @@ function readDirname(node) {
|
|
|
2539
2522
|
|
|
2540
2523
|
// kernel/orchestrator/lift-resolved-link-confidence.ts
|
|
2541
2524
|
var RESERVED_TARGET_CONFIDENCE = 0.1;
|
|
2525
|
+
var BROKEN_TARGET_CONFIDENCE = 0.5;
|
|
2542
2526
|
function liftResolvedLinkConfidence(links, nodes, ctx) {
|
|
2543
2527
|
if (!links.some((l) => l.confidence < 1)) return;
|
|
2544
2528
|
const indexes = buildIndexes(nodes, ctx);
|
|
2545
2529
|
for (const link of links) {
|
|
2546
|
-
if (link.confidence
|
|
2547
|
-
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
|
|
2530
|
+
if (link.confidence < 1) applyResolution(link, indexes, ctx);
|
|
2531
|
+
}
|
|
2532
|
+
}
|
|
2533
|
+
function applyResolution(link, indexes, ctx) {
|
|
2534
|
+
const resolution = resolve2(link, indexes, ctx);
|
|
2535
|
+
if (resolution === "none") {
|
|
2536
|
+
if (isGenuinelyBroken(link, indexes)) {
|
|
2537
|
+
link.confidence = Math.min(link.confidence, BROKEN_TARGET_CONFIDENCE);
|
|
2538
|
+
}
|
|
2539
|
+
return;
|
|
2551
2540
|
}
|
|
2541
|
+
link.resolvedTarget = resolution;
|
|
2542
|
+
if (indexes.nodeByPath.get(resolution)?.virtual) return;
|
|
2543
|
+
link.confidence = ctx.reservedNodePaths.has(resolution) ? RESERVED_TARGET_CONFIDENCE : 1;
|
|
2552
2544
|
}
|
|
2553
2545
|
function buildIndexes(nodes, ctx) {
|
|
2554
2546
|
const byPath3 = /* @__PURE__ */ new Set();
|
|
@@ -2565,6 +2557,12 @@ function resolve2(link, indexes, ctx) {
|
|
|
2565
2557
|
if (indexes.byPath.has(link.target)) return link.target;
|
|
2566
2558
|
return resolveByName(link, indexes, ctx);
|
|
2567
2559
|
}
|
|
2560
|
+
function isGenuinelyBroken(link, indexes) {
|
|
2561
|
+
if (indexes.byPath.has(link.target)) return false;
|
|
2562
|
+
const stripped = stripTriggerSigil(link.trigger?.normalizedTrigger);
|
|
2563
|
+
if (stripped !== null && indexes.byName.has(stripped)) return false;
|
|
2564
|
+
return true;
|
|
2565
|
+
}
|
|
2568
2566
|
function resolveByName(link, indexes, ctx) {
|
|
2569
2567
|
const stripped = stripTriggerSigil(link.trigger?.normalizedTrigger);
|
|
2570
2568
|
if (stripped === null) return "none";
|
|
@@ -2856,6 +2854,12 @@ var nodeSupersededAnalyzer = {
|
|
|
2856
2854
|
pluginId: CORE_PLUGIN_ID,
|
|
2857
2855
|
kind: "analyzer",
|
|
2858
2856
|
description: "Marks nodes replaced by a newer one via `supersededBy`.",
|
|
2857
|
+
// Part of the experimental supersession feature: ships disabled by
|
|
2858
|
+
// default alongside the declarer (`core/supersede` button +
|
|
2859
|
+
// `core/node-supersede` action). With the declarer off by default a
|
|
2860
|
+
// user rarely produces `supersededBy` data, so surfacing it stays
|
|
2861
|
+
// experimental too; the operator opts the whole family in together.
|
|
2862
|
+
stability: "experimental",
|
|
2859
2863
|
mode: "deterministic",
|
|
2860
2864
|
evaluate(ctx) {
|
|
2861
2865
|
const issues = [];
|
|
@@ -3760,122 +3764,6 @@ function makeIssue(signal) {
|
|
|
3760
3764
|
return null;
|
|
3761
3765
|
}
|
|
3762
3766
|
|
|
3763
|
-
// plugins/core/analyzers/supersede/text.ts
|
|
3764
|
-
var SUPERSEDE_TEXTS = {
|
|
3765
|
-
/** Label of the inspector action button that declares supersession. */
|
|
3766
|
-
supersedeLabel: "Supersede",
|
|
3767
|
-
/** Tooltip shown when the supersede button is disabled (already superseded). */
|
|
3768
|
-
supersedeDisabledReason: "Already superseded.",
|
|
3769
|
-
/** Tooltip shown when there is no other node to supersede this one. */
|
|
3770
|
-
supersedeNoTargetsReason: "No other node to supersede this one.",
|
|
3771
|
-
/** Prompt label for the target node-picker (enum-pick over the live node set). */
|
|
3772
|
-
supersedePromptLabel: "Superseded by"
|
|
3773
|
-
};
|
|
3774
|
-
|
|
3775
|
-
// plugins/core/analyzers/supersede/index.ts
|
|
3776
|
-
var ID25 = "supersede";
|
|
3777
|
-
var supersedeButton = {
|
|
3778
|
-
slot: "inspector.action.button",
|
|
3779
|
-
priority: 10
|
|
3780
|
-
};
|
|
3781
|
-
var supersedeAnalyzer = {
|
|
3782
|
-
id: ID25,
|
|
3783
|
-
pluginId: CORE_PLUGIN_ID,
|
|
3784
|
-
kind: "analyzer",
|
|
3785
|
-
description: 'Projects the inspector "Supersede" button (declares a node replaced by another).',
|
|
3786
|
-
mode: "deterministic",
|
|
3787
|
-
ui: { supersedeButton },
|
|
3788
|
-
evaluate(ctx) {
|
|
3789
|
-
const candidates = ctx.nodes.filter((n) => n.virtual !== true).map((n) => n.path);
|
|
3790
|
-
for (const node of ctx.nodes) {
|
|
3791
|
-
if (node.virtual === true) continue;
|
|
3792
|
-
const options = candidates.filter((p) => p !== node.path).map((p) => ({ value: p, label: p }));
|
|
3793
|
-
emitSupersedeButton(ctx, node, options);
|
|
3794
|
-
}
|
|
3795
|
-
return [];
|
|
3796
|
-
}
|
|
3797
|
-
};
|
|
3798
|
-
function emitSupersedeButton(ctx, node, options) {
|
|
3799
|
-
const disabledReason = resolveDisabledReason(node, options.length);
|
|
3800
|
-
ctx.emitContribution(node.path, supersedeButton, {
|
|
3801
|
-
actionId: "core/node-supersede",
|
|
3802
|
-
label: SUPERSEDE_TEXTS.supersedeLabel,
|
|
3803
|
-
icon: "pi-arrow-right-arrow-left",
|
|
3804
|
-
enabled: disabledReason === void 0,
|
|
3805
|
-
...disabledReason === void 0 ? {} : { disabledReason },
|
|
3806
|
-
prompt: {
|
|
3807
|
-
inputType: "enum-pick",
|
|
3808
|
-
paramKey: "supersededBy",
|
|
3809
|
-
label: SUPERSEDE_TEXTS.supersedePromptLabel,
|
|
3810
|
-
options
|
|
3811
|
-
}
|
|
3812
|
-
});
|
|
3813
|
-
}
|
|
3814
|
-
function resolveDisabledReason(node, optionCount) {
|
|
3815
|
-
if (alreadySuperseded(node)) return SUPERSEDE_TEXTS.supersedeDisabledReason;
|
|
3816
|
-
if (optionCount === 0) return SUPERSEDE_TEXTS.supersedeNoTargetsReason;
|
|
3817
|
-
return void 0;
|
|
3818
|
-
}
|
|
3819
|
-
function alreadySuperseded(node) {
|
|
3820
|
-
const sidecar = node.sidecar;
|
|
3821
|
-
if (!sidecar || sidecar.present !== true) return false;
|
|
3822
|
-
const ann = sidecar.annotations;
|
|
3823
|
-
if (!ann || typeof ann !== "object" || Array.isArray(ann)) return false;
|
|
3824
|
-
const value = ann["supersededBy"];
|
|
3825
|
-
return typeof value === "string" && value.length > 0;
|
|
3826
|
-
}
|
|
3827
|
-
|
|
3828
|
-
// plugins/core/analyzers/tags/text.ts
|
|
3829
|
-
var TAGS_TEXTS = {
|
|
3830
|
-
/** Label of the inspector action button that edits the node's tags. */
|
|
3831
|
-
editLabel: "Edit tags",
|
|
3832
|
-
/** Prompt label for the string-list tags input. */
|
|
3833
|
-
promptLabel: "Tags"
|
|
3834
|
-
};
|
|
3835
|
-
|
|
3836
|
-
// plugins/core/analyzers/tags/index.ts
|
|
3837
|
-
var ID26 = "tags";
|
|
3838
|
-
var setTagsButton = {
|
|
3839
|
-
slot: "inspector.action.button",
|
|
3840
|
-
priority: 15
|
|
3841
|
-
};
|
|
3842
|
-
var tagsAnalyzer = {
|
|
3843
|
-
id: ID26,
|
|
3844
|
-
pluginId: CORE_PLUGIN_ID,
|
|
3845
|
-
kind: "analyzer",
|
|
3846
|
-
description: `Projects the inspector "Edit tags" button (edits a node's taxonomy tags).`,
|
|
3847
|
-
mode: "deterministic",
|
|
3848
|
-
ui: { setTagsButton },
|
|
3849
|
-
evaluate(ctx) {
|
|
3850
|
-
for (const node of ctx.nodes) {
|
|
3851
|
-
if (node.sidecar?.present !== true) continue;
|
|
3852
|
-
emitSetTagsButton(ctx, node);
|
|
3853
|
-
}
|
|
3854
|
-
return [];
|
|
3855
|
-
}
|
|
3856
|
-
};
|
|
3857
|
-
function emitSetTagsButton(ctx, node) {
|
|
3858
|
-
ctx.emitContribution(node.path, setTagsButton, {
|
|
3859
|
-
actionId: "core/node-set-tags",
|
|
3860
|
-
label: TAGS_TEXTS.editLabel,
|
|
3861
|
-
icon: "pi-tags",
|
|
3862
|
-
enabled: true,
|
|
3863
|
-
prompt: {
|
|
3864
|
-
inputType: "string-list",
|
|
3865
|
-
paramKey: "tags",
|
|
3866
|
-
label: TAGS_TEXTS.promptLabel,
|
|
3867
|
-
defaultValue: currentTags(node)
|
|
3868
|
-
}
|
|
3869
|
-
});
|
|
3870
|
-
}
|
|
3871
|
-
function currentTags(node) {
|
|
3872
|
-
const ann = node.sidecar?.annotations;
|
|
3873
|
-
if (!ann || typeof ann !== "object" || Array.isArray(ann)) return [];
|
|
3874
|
-
const value = ann["tags"];
|
|
3875
|
-
if (!Array.isArray(value)) return [];
|
|
3876
|
-
return value.filter((t) => typeof t === "string");
|
|
3877
|
-
}
|
|
3878
|
-
|
|
3879
3767
|
// plugins/core/analyzers/trigger-collision/text.ts
|
|
3880
3768
|
var TRIGGER_COLLISION_TEXTS = {
|
|
3881
3769
|
/**
|
|
@@ -3902,14 +3790,14 @@ var TRIGGER_COLLISION_TEXTS = {
|
|
|
3902
3790
|
};
|
|
3903
3791
|
|
|
3904
3792
|
// plugins/core/analyzers/trigger-collision/index.ts
|
|
3905
|
-
var
|
|
3793
|
+
var ID25 = "trigger-collision";
|
|
3906
3794
|
var ADVERTISING_KINDS = /* @__PURE__ */ new Set([
|
|
3907
3795
|
"command",
|
|
3908
3796
|
"skill",
|
|
3909
3797
|
"agent"
|
|
3910
3798
|
]);
|
|
3911
3799
|
var triggerCollisionAnalyzer = {
|
|
3912
|
-
id:
|
|
3800
|
+
id: ID25,
|
|
3913
3801
|
pluginId: CORE_PLUGIN_ID,
|
|
3914
3802
|
kind: "analyzer",
|
|
3915
3803
|
mode: "deterministic",
|
|
@@ -4007,7 +3895,7 @@ function analyzeTriggerBucket(normalized, claims) {
|
|
|
4007
3895
|
part: parts[0]
|
|
4008
3896
|
});
|
|
4009
3897
|
return {
|
|
4010
|
-
analyzerId:
|
|
3898
|
+
analyzerId: ID25,
|
|
4011
3899
|
severity: "error",
|
|
4012
3900
|
nodeIds,
|
|
4013
3901
|
message,
|
|
@@ -4047,13 +3935,13 @@ var ASCII_FORMATTER_TEXTS = {
|
|
|
4047
3935
|
};
|
|
4048
3936
|
|
|
4049
3937
|
// plugins/core/formatters/ascii/index.ts
|
|
4050
|
-
var
|
|
3938
|
+
var ID26 = "ascii";
|
|
4051
3939
|
var KIND_ORDER = ["agent", "command", "skill", "markdown"];
|
|
4052
3940
|
var asciiFormatter = {
|
|
4053
|
-
id:
|
|
3941
|
+
id: ID26,
|
|
4054
3942
|
pluginId: CORE_PLUGIN_ID,
|
|
4055
3943
|
kind: "formatter",
|
|
4056
|
-
formatId:
|
|
3944
|
+
formatId: ID26,
|
|
4057
3945
|
description: "Renders the scan as plain text in three sections: nodes (grouped by kind), arrows, and issues. Used by `sm scan --format ascii`.",
|
|
4058
3946
|
// ASCII tree formatter, header + per-kind sections + per-issue
|
|
4059
3947
|
// section. Each section iterates and renders; splitting per section
|
|
@@ -4147,13 +4035,13 @@ function renderSection(out, kind, group) {
|
|
|
4147
4035
|
}
|
|
4148
4036
|
|
|
4149
4037
|
// plugins/core/formatters/json/index.ts
|
|
4150
|
-
var
|
|
4038
|
+
var ID27 = "json";
|
|
4151
4039
|
var jsonFormatter = {
|
|
4152
|
-
id:
|
|
4040
|
+
id: ID27,
|
|
4153
4041
|
pluginId: CORE_PLUGIN_ID,
|
|
4154
4042
|
kind: "formatter",
|
|
4155
4043
|
description: "Renders the persisted scan as JSON (conforms to `scan-result.schema.json`). Used by `sm graph --format json` and `GET /api/graph?format=json`.",
|
|
4156
|
-
formatId:
|
|
4044
|
+
formatId: ID27,
|
|
4157
4045
|
format(ctx) {
|
|
4158
4046
|
if (ctx.scanResult !== void 0) {
|
|
4159
4047
|
return JSON.stringify(ctx.scanResult);
|
|
@@ -4291,14 +4179,33 @@ function resolveSpecRoot2() {
|
|
|
4291
4179
|
}
|
|
4292
4180
|
}
|
|
4293
4181
|
|
|
4182
|
+
// plugins/core/actions/node-bump/text.ts
|
|
4183
|
+
var BUMP_TEXTS = {
|
|
4184
|
+
/** Label of the inspector action button that dispatches a bump. */
|
|
4185
|
+
bumpLabel: "Bump",
|
|
4186
|
+
/** Tooltip shown when the bump button is disabled (the node is fresh, no drift). */
|
|
4187
|
+
bumpDisabledReason: "No drift to bump."
|
|
4188
|
+
};
|
|
4189
|
+
|
|
4294
4190
|
// plugins/core/actions/node-bump/index.ts
|
|
4295
|
-
var
|
|
4191
|
+
var ID28 = "node-bump";
|
|
4192
|
+
var bumpButton = {
|
|
4193
|
+
slot: "inspector.action.button",
|
|
4194
|
+
priority: 10
|
|
4195
|
+
};
|
|
4296
4196
|
var nodeBumpAction = {
|
|
4297
|
-
id:
|
|
4197
|
+
id: ID28,
|
|
4298
4198
|
pluginId: CORE_PLUGIN_ID,
|
|
4299
4199
|
kind: "action",
|
|
4300
4200
|
description: "Marks a node as updated: bumps `annotations.version`, refreshes sidecar hashes, and records the timestamp.",
|
|
4301
4201
|
mode: "deterministic",
|
|
4202
|
+
ui: { bumpButton },
|
|
4203
|
+
project(ctx) {
|
|
4204
|
+
for (const node of ctx.nodes) {
|
|
4205
|
+
if (node.sidecar?.present !== true) continue;
|
|
4206
|
+
emitBumpButton(ctx, node.path, staleStatus2(node.sidecar) !== null);
|
|
4207
|
+
}
|
|
4208
|
+
},
|
|
4302
4209
|
// The runtime contract uses generic <TInput, TReport>; bump narrows
|
|
4303
4210
|
// both. The cast is the standard pattern for built-ins that want
|
|
4304
4211
|
// typed local I/O while staying compatible with the open generic.
|
|
@@ -4307,6 +4214,20 @@ var nodeBumpAction = {
|
|
|
4307
4214
|
return invokeBump(input, ctx);
|
|
4308
4215
|
}
|
|
4309
4216
|
};
|
|
4217
|
+
function emitBumpButton(ctx, nodePath, enabled) {
|
|
4218
|
+
ctx.emitContribution(nodePath, bumpButton, {
|
|
4219
|
+
actionId: "core/node-bump",
|
|
4220
|
+
label: BUMP_TEXTS.bumpLabel,
|
|
4221
|
+
icon: "pi-arrow-up-right",
|
|
4222
|
+
enabled,
|
|
4223
|
+
...enabled ? {} : { disabledReason: BUMP_TEXTS.bumpDisabledReason }
|
|
4224
|
+
});
|
|
4225
|
+
}
|
|
4226
|
+
function staleStatus2(overlay) {
|
|
4227
|
+
const status = overlay?.status;
|
|
4228
|
+
if (status === void 0 || status === null || status === "fresh") return null;
|
|
4229
|
+
return status;
|
|
4230
|
+
}
|
|
4310
4231
|
function invokeBump(input, ctx) {
|
|
4311
4232
|
const overlay = ctx.node.sidecar ?? null;
|
|
4312
4233
|
const isFresh = overlay?.present === true && overlay.status === "fresh";
|
|
@@ -4353,9 +4274,9 @@ function pickCurrentVersion(overlay) {
|
|
|
4353
4274
|
|
|
4354
4275
|
// plugins/core/actions/node-set-stability/index.ts
|
|
4355
4276
|
var STABILITY_VALUES = ["experimental", "stable", "deprecated"];
|
|
4356
|
-
var
|
|
4277
|
+
var ID29 = "node-set-stability";
|
|
4357
4278
|
var nodeSetStabilityAction = {
|
|
4358
|
-
id:
|
|
4279
|
+
id: ID29,
|
|
4359
4280
|
pluginId: CORE_PLUGIN_ID,
|
|
4360
4281
|
kind: "action",
|
|
4361
4282
|
description: "Sets the lifecycle stage of the current node (writes `stability` to the sidecar).",
|
|
@@ -4394,14 +4315,33 @@ function invokeSetStability(input, ctx) {
|
|
|
4394
4315
|
return { report, writes: [write] };
|
|
4395
4316
|
}
|
|
4396
4317
|
|
|
4318
|
+
// plugins/core/actions/node-set-tags/text.ts
|
|
4319
|
+
var TAGS_TEXTS = {
|
|
4320
|
+
/** Label of the inspector action button that edits the node's tags. */
|
|
4321
|
+
editLabel: "Edit tags",
|
|
4322
|
+
/** Prompt label for the string-list tags input. */
|
|
4323
|
+
promptLabel: "Tags"
|
|
4324
|
+
};
|
|
4325
|
+
|
|
4397
4326
|
// plugins/core/actions/node-set-tags/index.ts
|
|
4398
|
-
var
|
|
4327
|
+
var ID30 = "node-set-tags";
|
|
4328
|
+
var setTagsButton = {
|
|
4329
|
+
slot: "inspector.action.button",
|
|
4330
|
+
priority: 15
|
|
4331
|
+
};
|
|
4399
4332
|
var nodeSetTagsAction = {
|
|
4400
|
-
id:
|
|
4333
|
+
id: ID30,
|
|
4401
4334
|
pluginId: CORE_PLUGIN_ID,
|
|
4402
4335
|
kind: "action",
|
|
4403
4336
|
description: "Sets the taxonomy tags of the current node (writes `tags` to the sidecar; whole-array replace).",
|
|
4404
4337
|
mode: "deterministic",
|
|
4338
|
+
ui: { setTagsButton },
|
|
4339
|
+
project(ctx) {
|
|
4340
|
+
for (const node of ctx.nodes) {
|
|
4341
|
+
if (node.sidecar?.present !== true) continue;
|
|
4342
|
+
emitSetTagsButton(ctx, node);
|
|
4343
|
+
}
|
|
4344
|
+
},
|
|
4405
4345
|
// The runtime contract uses generic <TInput, TReport>; this narrows
|
|
4406
4346
|
// both. The cast is the standard pattern for built-ins that want
|
|
4407
4347
|
// typed local I/O while staying compatible with the open generic.
|
|
@@ -4410,6 +4350,27 @@ var nodeSetTagsAction = {
|
|
|
4410
4350
|
return invokeSetTags(input, ctx);
|
|
4411
4351
|
}
|
|
4412
4352
|
};
|
|
4353
|
+
function emitSetTagsButton(ctx, node) {
|
|
4354
|
+
ctx.emitContribution(node.path, setTagsButton, {
|
|
4355
|
+
actionId: "core/node-set-tags",
|
|
4356
|
+
label: TAGS_TEXTS.editLabel,
|
|
4357
|
+
icon: "pi-tags",
|
|
4358
|
+
enabled: true,
|
|
4359
|
+
prompt: {
|
|
4360
|
+
inputType: "string-list",
|
|
4361
|
+
paramKey: "tags",
|
|
4362
|
+
label: TAGS_TEXTS.promptLabel,
|
|
4363
|
+
defaultValue: currentTags(node)
|
|
4364
|
+
}
|
|
4365
|
+
});
|
|
4366
|
+
}
|
|
4367
|
+
function currentTags(node) {
|
|
4368
|
+
const ann = node.sidecar?.annotations;
|
|
4369
|
+
if (!ann || typeof ann !== "object" || Array.isArray(ann)) return [];
|
|
4370
|
+
const value = ann["tags"];
|
|
4371
|
+
if (!Array.isArray(value)) return [];
|
|
4372
|
+
return value.filter((t) => typeof t === "string");
|
|
4373
|
+
}
|
|
4413
4374
|
function invokeSetTags(input, ctx) {
|
|
4414
4375
|
const tags = Array.isArray(input.tags) ? input.tags : [];
|
|
4415
4376
|
const timestamp = ctx.now().toISOString();
|
|
@@ -4433,14 +4394,44 @@ function invokeSetTags(input, ctx) {
|
|
|
4433
4394
|
return { report, writes: [write] };
|
|
4434
4395
|
}
|
|
4435
4396
|
|
|
4397
|
+
// plugins/core/actions/node-supersede/text.ts
|
|
4398
|
+
var SUPERSEDE_TEXTS = {
|
|
4399
|
+
/** Label of the inspector action button that declares supersession. */
|
|
4400
|
+
supersedeLabel: "Supersede",
|
|
4401
|
+
/** Tooltip shown when the supersede button is disabled (already superseded). */
|
|
4402
|
+
supersedeDisabledReason: "Already superseded.",
|
|
4403
|
+
/** Tooltip shown when there is no other node to supersede this one. */
|
|
4404
|
+
supersedeNoTargetsReason: "No other node to supersede this one.",
|
|
4405
|
+
/** Prompt label for the target node-picker (enum-pick over the live node set). */
|
|
4406
|
+
supersedePromptLabel: "Superseded by"
|
|
4407
|
+
};
|
|
4408
|
+
|
|
4436
4409
|
// plugins/core/actions/node-supersede/index.ts
|
|
4437
|
-
var
|
|
4410
|
+
var ID31 = "node-supersede";
|
|
4411
|
+
var supersedeButton = {
|
|
4412
|
+
slot: "inspector.action.button",
|
|
4413
|
+
priority: 10
|
|
4414
|
+
};
|
|
4438
4415
|
var nodeSupersedeAction = {
|
|
4439
|
-
id:
|
|
4416
|
+
id: ID31,
|
|
4440
4417
|
pluginId: CORE_PLUGIN_ID,
|
|
4441
4418
|
kind: "action",
|
|
4442
4419
|
description: "Declares the current node as superseded by another (writes `supersededBy` to the sidecar).",
|
|
4420
|
+
// Ships disabled by default (the declarer feature is still settling its
|
|
4421
|
+
// node-picker UX). The button self-projection gates as a unit with the
|
|
4422
|
+
// invoke executor: an enabled button pointing at a disabled action
|
|
4423
|
+
// would error on click, so the whole action stays experimental.
|
|
4424
|
+
stability: "experimental",
|
|
4443
4425
|
mode: "deterministic",
|
|
4426
|
+
ui: { supersedeButton },
|
|
4427
|
+
project(ctx) {
|
|
4428
|
+
const candidates = ctx.nodes.filter((n) => n.virtual !== true).map((n) => n.path);
|
|
4429
|
+
for (const node of ctx.nodes) {
|
|
4430
|
+
if (node.virtual === true) continue;
|
|
4431
|
+
const options = candidates.filter((p) => p !== node.path).map((p) => ({ value: p, label: p }));
|
|
4432
|
+
emitSupersedeButton(ctx, node, options);
|
|
4433
|
+
}
|
|
4434
|
+
},
|
|
4444
4435
|
// The runtime contract uses generic <TInput, TReport>; supersede
|
|
4445
4436
|
// narrows both. The cast is the standard pattern for built-ins that
|
|
4446
4437
|
// want typed local I/O while staying compatible with the open generic.
|
|
@@ -4449,6 +4440,35 @@ var nodeSupersedeAction = {
|
|
|
4449
4440
|
return invokeSupersede(input, ctx);
|
|
4450
4441
|
}
|
|
4451
4442
|
};
|
|
4443
|
+
function emitSupersedeButton(ctx, node, options) {
|
|
4444
|
+
const disabledReason = resolveDisabledReason(node, options.length);
|
|
4445
|
+
ctx.emitContribution(node.path, supersedeButton, {
|
|
4446
|
+
actionId: "core/node-supersede",
|
|
4447
|
+
label: SUPERSEDE_TEXTS.supersedeLabel,
|
|
4448
|
+
icon: "pi-arrow-right-arrow-left",
|
|
4449
|
+
enabled: disabledReason === void 0,
|
|
4450
|
+
...disabledReason === void 0 ? {} : { disabledReason },
|
|
4451
|
+
prompt: {
|
|
4452
|
+
inputType: "enum-pick",
|
|
4453
|
+
paramKey: "supersededBy",
|
|
4454
|
+
label: SUPERSEDE_TEXTS.supersedePromptLabel,
|
|
4455
|
+
options
|
|
4456
|
+
}
|
|
4457
|
+
});
|
|
4458
|
+
}
|
|
4459
|
+
function resolveDisabledReason(node, optionCount) {
|
|
4460
|
+
if (alreadySuperseded(node)) return SUPERSEDE_TEXTS.supersedeDisabledReason;
|
|
4461
|
+
if (optionCount === 0) return SUPERSEDE_TEXTS.supersedeNoTargetsReason;
|
|
4462
|
+
return void 0;
|
|
4463
|
+
}
|
|
4464
|
+
function alreadySuperseded(node) {
|
|
4465
|
+
const sidecar = node.sidecar;
|
|
4466
|
+
if (!sidecar || sidecar.present !== true) return false;
|
|
4467
|
+
const ann = sidecar.annotations;
|
|
4468
|
+
if (!ann || typeof ann !== "object" || Array.isArray(ann)) return false;
|
|
4469
|
+
const value = ann["supersededBy"];
|
|
4470
|
+
return typeof value === "string" && value.length > 0;
|
|
4471
|
+
}
|
|
4452
4472
|
function invokeSupersede(input, ctx) {
|
|
4453
4473
|
const supersededBy = input.supersededBy;
|
|
4454
4474
|
if (supersededBy === ctx.node.path) {
|
|
@@ -4980,8 +5000,6 @@ var referenceBrokenAnalyzer2 = { ...referenceBrokenAnalyzer, pluginId: "core", v
|
|
|
4980
5000
|
var referenceRedundantAnalyzer2 = { ...referenceRedundantAnalyzer, pluginId: "core", version: VERSION };
|
|
4981
5001
|
var schemaViolationAnalyzer2 = { ...schemaViolationAnalyzer, pluginId: "core", version: VERSION };
|
|
4982
5002
|
var signalCollisionAnalyzer2 = { ...signalCollisionAnalyzer, pluginId: "core", version: VERSION };
|
|
4983
|
-
var supersedeAnalyzer2 = { ...supersedeAnalyzer, pluginId: "core", version: VERSION };
|
|
4984
|
-
var tagsAnalyzer2 = { ...tagsAnalyzer, pluginId: "core", version: VERSION };
|
|
4985
5003
|
var triggerCollisionAnalyzer2 = { ...triggerCollisionAnalyzer, pluginId: "core", version: VERSION };
|
|
4986
5004
|
var asciiFormatter2 = { ...asciiFormatter, pluginId: "core", version: VERSION };
|
|
4987
5005
|
var jsonFormatter2 = { ...jsonFormatter, pluginId: "core", version: VERSION };
|
|
@@ -5048,8 +5066,6 @@ var builtInPlugins = [
|
|
|
5048
5066
|
referenceRedundantAnalyzer2,
|
|
5049
5067
|
schemaViolationAnalyzer2,
|
|
5050
5068
|
signalCollisionAnalyzer2,
|
|
5051
|
-
supersedeAnalyzer2,
|
|
5052
|
-
tagsAnalyzer2,
|
|
5053
5069
|
triggerCollisionAnalyzer2,
|
|
5054
5070
|
asciiFormatter2,
|
|
5055
5071
|
jsonFormatter2,
|
|
@@ -6458,7 +6474,7 @@ function resolveSpecRoot3() {
|
|
|
6458
6474
|
}
|
|
6459
6475
|
|
|
6460
6476
|
// cli/i18n/bump.texts.ts
|
|
6461
|
-
var
|
|
6477
|
+
var BUMP_TEXTS2 = {
|
|
6462
6478
|
// --- argument validation --------------------------------------------------
|
|
6463
6479
|
/**
|
|
6464
6480
|
* §3.1b two-line block. Mutex between the positional <node.path> and
|
|
@@ -8149,6 +8165,7 @@ function rowToNode(row) {
|
|
|
8149
8165
|
const parsed = JSON.parse(row.externalRefsJson);
|
|
8150
8166
|
if (Array.isArray(parsed) && parsed.length > 0) node.externalRefs = parsed;
|
|
8151
8167
|
}
|
|
8168
|
+
if (row.modifiedAtMs !== null) node.modifiedAtMs = row.modifiedAtMs;
|
|
8152
8169
|
return node;
|
|
8153
8170
|
}
|
|
8154
8171
|
function rowToLink(row) {
|
|
@@ -8665,7 +8682,10 @@ function nodeToRow(node, scannedAt) {
|
|
|
8665
8682
|
// the column stays sparse for nodes whose bodies have no http(s)
|
|
8666
8683
|
// URLs at all. Round-tripped by `rowToNode` on load.
|
|
8667
8684
|
externalRefsJson: node.externalRefs && node.externalRefs.length > 0 ? JSON.stringify(node.externalRefs) : null,
|
|
8668
|
-
scannedAt
|
|
8685
|
+
scannedAt,
|
|
8686
|
+
// File mtime (Unix ms) from the walker; NULL for virtual / derived
|
|
8687
|
+
// nodes that carry no backing file. Round-tripped by `rowToNode`.
|
|
8688
|
+
modifiedAtMs: node.modifiedAtMs ?? null
|
|
8669
8689
|
};
|
|
8670
8690
|
}
|
|
8671
8691
|
function projectAnnotationColumns(node) {
|
|
@@ -9666,10 +9686,10 @@ var BumpCommand = class extends SmCommand {
|
|
|
9666
9686
|
);
|
|
9667
9687
|
if (!persisted) {
|
|
9668
9688
|
this.printer.error(
|
|
9669
|
-
tx(
|
|
9689
|
+
tx(BUMP_TEXTS2.nodeNotFound, {
|
|
9670
9690
|
glyph: ansi.red("\u2715"),
|
|
9671
9691
|
nodePath: this.nodePath ?? "<pending>",
|
|
9672
|
-
hint: ansi.dim(
|
|
9692
|
+
hint: ansi.dim(BUMP_TEXTS2.nodeNotFoundHint)
|
|
9673
9693
|
})
|
|
9674
9694
|
);
|
|
9675
9695
|
return ExitCode.NotFound;
|
|
@@ -9689,27 +9709,27 @@ var BumpCommand = class extends SmCommand {
|
|
|
9689
9709
|
const errGlyph = ansi.red("\u2715");
|
|
9690
9710
|
if (this.pending && this.nodePath !== void 0) {
|
|
9691
9711
|
this.printer.error(
|
|
9692
|
-
tx(
|
|
9712
|
+
tx(BUMP_TEXTS2.nodeAndPendingMutex, {
|
|
9693
9713
|
glyph: errGlyph,
|
|
9694
|
-
hint: ansi.dim(
|
|
9714
|
+
hint: ansi.dim(BUMP_TEXTS2.nodeAndPendingMutexHint)
|
|
9695
9715
|
})
|
|
9696
9716
|
);
|
|
9697
9717
|
return ExitCode.Error;
|
|
9698
9718
|
}
|
|
9699
9719
|
if (!this.pending && this.nodePath === void 0) {
|
|
9700
9720
|
this.printer.error(
|
|
9701
|
-
tx(
|
|
9721
|
+
tx(BUMP_TEXTS2.noTargetSpecified, {
|
|
9702
9722
|
glyph: errGlyph,
|
|
9703
|
-
hint: ansi.dim(
|
|
9723
|
+
hint: ansi.dim(BUMP_TEXTS2.noTargetSpecifiedHint)
|
|
9704
9724
|
})
|
|
9705
9725
|
);
|
|
9706
9726
|
return ExitCode.Error;
|
|
9707
9727
|
}
|
|
9708
9728
|
if (this.staged && !this.pending) {
|
|
9709
9729
|
this.printer.error(
|
|
9710
|
-
tx(
|
|
9730
|
+
tx(BUMP_TEXTS2.stagedRequiresPending, {
|
|
9711
9731
|
glyph: errGlyph,
|
|
9712
|
-
hint: ansi.dim(
|
|
9732
|
+
hint: ansi.dim(BUMP_TEXTS2.stagedRequiresPendingHint)
|
|
9713
9733
|
})
|
|
9714
9734
|
);
|
|
9715
9735
|
return ExitCode.Error;
|
|
@@ -9768,10 +9788,10 @@ var BumpCommand = class extends SmCommand {
|
|
|
9768
9788
|
const node = nodes.find((n) => n.path === this.nodePath);
|
|
9769
9789
|
if (!node) {
|
|
9770
9790
|
this.printer.error(
|
|
9771
|
-
tx(
|
|
9791
|
+
tx(BUMP_TEXTS2.nodeNotFound, {
|
|
9772
9792
|
glyph: ansi.red("\u2715"),
|
|
9773
9793
|
nodePath: this.nodePath,
|
|
9774
|
-
hint: ansi.dim(
|
|
9794
|
+
hint: ansi.dim(BUMP_TEXTS2.nodeNotFoundHint)
|
|
9775
9795
|
})
|
|
9776
9796
|
);
|
|
9777
9797
|
return ExitCode.NotFound;
|
|
@@ -9793,9 +9813,9 @@ var BumpCommand = class extends SmCommand {
|
|
|
9793
9813
|
const errGlyph = ansi.red("\u2715");
|
|
9794
9814
|
if (item.status === "error") {
|
|
9795
9815
|
this.printer.error(
|
|
9796
|
-
tx(
|
|
9816
|
+
tx(BUMP_TEXTS2.bumpFailed, {
|
|
9797
9817
|
glyph: errGlyph,
|
|
9798
|
-
message: tx(
|
|
9818
|
+
message: tx(BUMP_TEXTS2.resolveAbsPathFailed, {
|
|
9799
9819
|
nodePath: node.path,
|
|
9800
9820
|
message: item.message
|
|
9801
9821
|
})
|
|
@@ -9805,10 +9825,10 @@ var BumpCommand = class extends SmCommand {
|
|
|
9805
9825
|
}
|
|
9806
9826
|
if (item.status === "refused") {
|
|
9807
9827
|
this.printer.error(
|
|
9808
|
-
tx(
|
|
9828
|
+
tx(BUMP_TEXTS2.refusedFresh, {
|
|
9809
9829
|
glyph: errGlyph,
|
|
9810
9830
|
nodePath: node.path,
|
|
9811
|
-
hint: ansi.dim(
|
|
9831
|
+
hint: ansi.dim(BUMP_TEXTS2.refusedFreshHint)
|
|
9812
9832
|
})
|
|
9813
9833
|
);
|
|
9814
9834
|
return ExitCode.Error;
|
|
@@ -9835,9 +9855,9 @@ var BumpCommand = class extends SmCommand {
|
|
|
9835
9855
|
if (applied.error !== void 0) {
|
|
9836
9856
|
if (applied.error instanceof EConsentRequiredError) throw applied.error;
|
|
9837
9857
|
this.printer.error(
|
|
9838
|
-
tx(
|
|
9858
|
+
tx(BUMP_TEXTS2.bumpFailed, {
|
|
9839
9859
|
glyph: ansi.red("\u2715"),
|
|
9840
|
-
message: tx(
|
|
9860
|
+
message: tx(BUMP_TEXTS2.storeFailedDetail, {
|
|
9841
9861
|
path: applied.sidecarPath ?? sidecarPathFor(item.absPath),
|
|
9842
9862
|
message: formatErrorMessage(applied.error)
|
|
9843
9863
|
})
|
|
@@ -9854,11 +9874,11 @@ var BumpCommand = class extends SmCommand {
|
|
|
9854
9874
|
const version = item.report.version ?? 1;
|
|
9855
9875
|
if (item.report.createdSidecar === true) {
|
|
9856
9876
|
this.printer.data(
|
|
9857
|
-
tx(
|
|
9877
|
+
tx(BUMP_TEXTS2.bumpedCreated, { glyph: okGlyph, sidecarPath, nodePath: node.path, version })
|
|
9858
9878
|
);
|
|
9859
9879
|
} else {
|
|
9860
9880
|
this.printer.data(
|
|
9861
|
-
tx(
|
|
9881
|
+
tx(BUMP_TEXTS2.bumped, { glyph: okGlyph, nodePath: node.path, version })
|
|
9862
9882
|
);
|
|
9863
9883
|
}
|
|
9864
9884
|
return ExitCode.Ok;
|
|
@@ -9870,7 +9890,7 @@ var BumpCommand = class extends SmCommand {
|
|
|
9870
9890
|
const stale = nodes.filter((n) => n.sidecar?.present === true && n.sidecar.status !== null && n.sidecar.status !== "fresh").sort((a, b) => a.path.localeCompare(b.path));
|
|
9871
9891
|
if (stale.length === 0) return this.#renderEmptyPending();
|
|
9872
9892
|
if (!this.json) {
|
|
9873
|
-
this.printer.info(tx(
|
|
9893
|
+
this.printer.info(tx(BUMP_TEXTS2.pendingBanner, { count: stale.length }));
|
|
9874
9894
|
}
|
|
9875
9895
|
const plan = computeBumpPlan(stale, { cwd, force: this.force });
|
|
9876
9896
|
const outcomes = await this.#executePending(plan, cwd, ansi);
|
|
@@ -9888,19 +9908,19 @@ var BumpCommand = class extends SmCommand {
|
|
|
9888
9908
|
const gitOk = ensureGitForStaged(cwd);
|
|
9889
9909
|
if (gitOk === "no-repo") {
|
|
9890
9910
|
this.printer.error(
|
|
9891
|
-
tx(
|
|
9911
|
+
tx(BUMP_TEXTS2.notInGitRepo, {
|
|
9892
9912
|
glyph: errGlyph,
|
|
9893
9913
|
cwd,
|
|
9894
|
-
hint: ansi.dim(
|
|
9914
|
+
hint: ansi.dim(BUMP_TEXTS2.notInGitRepoHint)
|
|
9895
9915
|
})
|
|
9896
9916
|
);
|
|
9897
9917
|
return ExitCode.NotFound;
|
|
9898
9918
|
}
|
|
9899
9919
|
if (gitOk === "no-binary") {
|
|
9900
9920
|
this.printer.error(
|
|
9901
|
-
tx(
|
|
9921
|
+
tx(BUMP_TEXTS2.gitBinaryMissing, {
|
|
9902
9922
|
glyph: errGlyph,
|
|
9903
|
-
hint: ansi.dim(
|
|
9923
|
+
hint: ansi.dim(BUMP_TEXTS2.gitBinaryMissingHint)
|
|
9904
9924
|
})
|
|
9905
9925
|
);
|
|
9906
9926
|
return ExitCode.Error;
|
|
@@ -9938,7 +9958,7 @@ var BumpCommand = class extends SmCommand {
|
|
|
9938
9958
|
return {
|
|
9939
9959
|
nodePath: item.nodePath,
|
|
9940
9960
|
status: "error",
|
|
9941
|
-
message: tx(
|
|
9961
|
+
message: tx(BUMP_TEXTS2.storeFailedDetail, {
|
|
9942
9962
|
path: applied.sidecarPath ?? sidecarPathFor(item.absPath),
|
|
9943
9963
|
message: formatErrorMessage(applied.error)
|
|
9944
9964
|
})
|
|
@@ -9958,11 +9978,11 @@ var BumpCommand = class extends SmCommand {
|
|
|
9958
9978
|
const addErr = stageSidecar(cwd, sidecarPath);
|
|
9959
9979
|
if (addErr === null || this.json) return;
|
|
9960
9980
|
this.printer.warn(
|
|
9961
|
-
tx(
|
|
9981
|
+
tx(BUMP_TEXTS2.gitAddFailed, {
|
|
9962
9982
|
glyph: ansi.yellow("\u26A0"),
|
|
9963
9983
|
path: sidecarPath,
|
|
9964
9984
|
message: addErr,
|
|
9965
|
-
hint: ansi.dim(tx(
|
|
9985
|
+
hint: ansi.dim(tx(BUMP_TEXTS2.gitAddFailedHint, { path: sidecarPath }))
|
|
9966
9986
|
})
|
|
9967
9987
|
);
|
|
9968
9988
|
}
|
|
@@ -9982,7 +10002,7 @@ var BumpCommand = class extends SmCommand {
|
|
|
9982
10002
|
this.printer.data(JSON.stringify(empty) + "\n");
|
|
9983
10003
|
return ExitCode.Ok;
|
|
9984
10004
|
}
|
|
9985
|
-
this.printer.data(
|
|
10005
|
+
this.printer.data(BUMP_TEXTS2.pendingNone);
|
|
9986
10006
|
return ExitCode.Ok;
|
|
9987
10007
|
}
|
|
9988
10008
|
// Complexity is from per-status rendering (4 status values) plus
|
|
@@ -10013,24 +10033,24 @@ var BumpCommand = class extends SmCommand {
|
|
|
10013
10033
|
for (const o of outcomes) {
|
|
10014
10034
|
if (o.status === "bumped") {
|
|
10015
10035
|
this.printer.data(
|
|
10016
|
-
tx(
|
|
10036
|
+
tx(BUMP_TEXTS2.bumpedItem, {
|
|
10017
10037
|
nodePath: o.nodePath,
|
|
10018
10038
|
version: o.version ?? 0,
|
|
10019
10039
|
createdSuffix: o.createdSidecar === true ? " (new sidecar)" : ""
|
|
10020
10040
|
})
|
|
10021
10041
|
);
|
|
10022
10042
|
} else if (o.status === "refused") {
|
|
10023
|
-
this.printer.data(tx(
|
|
10043
|
+
this.printer.data(tx(BUMP_TEXTS2.refusedItem, { nodePath: o.nodePath }));
|
|
10024
10044
|
} else if (o.status === "skipped") {
|
|
10025
10045
|
this.printer.data(
|
|
10026
|
-
tx(
|
|
10046
|
+
tx(BUMP_TEXTS2.skippedItem, {
|
|
10027
10047
|
nodePath: o.nodePath,
|
|
10028
10048
|
reason: o.reason ?? "unknown"
|
|
10029
10049
|
})
|
|
10030
10050
|
);
|
|
10031
10051
|
} else {
|
|
10032
10052
|
this.printer.data(
|
|
10033
|
-
tx(
|
|
10053
|
+
tx(BUMP_TEXTS2.errorItem, {
|
|
10034
10054
|
nodePath: o.nodePath,
|
|
10035
10055
|
message: o.message ?? ""
|
|
10036
10056
|
})
|
|
@@ -10038,7 +10058,7 @@ var BumpCommand = class extends SmCommand {
|
|
|
10038
10058
|
}
|
|
10039
10059
|
}
|
|
10040
10060
|
this.printer.info(
|
|
10041
|
-
tx(
|
|
10061
|
+
tx(BUMP_TEXTS2.pendingSummary, {
|
|
10042
10062
|
bumped: counts.bumped,
|
|
10043
10063
|
refused: counts.refused,
|
|
10044
10064
|
skipped: counts.skipped,
|
|
@@ -11091,29 +11111,39 @@ function isPluginLocked(idOrQualified) {
|
|
|
11091
11111
|
}
|
|
11092
11112
|
|
|
11093
11113
|
// kernel/config/plugin-resolver.ts
|
|
11094
|
-
|
|
11114
|
+
var SHIPS_DISABLED = /* @__PURE__ */ new Set([
|
|
11115
|
+
"experimental",
|
|
11116
|
+
"deprecated"
|
|
11117
|
+
]);
|
|
11118
|
+
function installedDefaultEnabled(stability) {
|
|
11119
|
+
return stability === void 0 || !SHIPS_DISABLED.has(stability);
|
|
11120
|
+
}
|
|
11121
|
+
function resolvePluginEnabled(pluginId, cfg, dbOverrides, installedDefault = true) {
|
|
11095
11122
|
if (isPluginLocked(pluginId)) return true;
|
|
11096
11123
|
if (dbOverrides.has(pluginId)) return dbOverrides.get(pluginId) === true;
|
|
11097
11124
|
const settingsEntry = cfg.plugins[pluginId];
|
|
11098
11125
|
if (settingsEntry?.enabled !== void 0) return settingsEntry.enabled;
|
|
11099
|
-
return
|
|
11126
|
+
return installedDefault;
|
|
11100
11127
|
}
|
|
11101
11128
|
function makeEnabledResolver(cfg, dbOverrides) {
|
|
11102
|
-
return (pluginId) => resolvePluginEnabled(pluginId, cfg, dbOverrides);
|
|
11129
|
+
return (pluginId, installedDefault) => resolvePluginEnabled(pluginId, cfg, dbOverrides, installedDefault);
|
|
11103
11130
|
}
|
|
11104
11131
|
|
|
11105
11132
|
// core/runtime/plugin-runtime/resolver.ts
|
|
11106
|
-
function defaultResolveEnabled(_id) {
|
|
11107
|
-
return
|
|
11133
|
+
function defaultResolveEnabled(_id, installedDefault = true) {
|
|
11134
|
+
return installedDefault;
|
|
11108
11135
|
}
|
|
11109
11136
|
function isBuiltInExtensionEnabled(plugin, ext, resolveEnabled) {
|
|
11110
|
-
return isPluginEntryEnabled(plugin, ext.id, resolveEnabled);
|
|
11137
|
+
return isPluginEntryEnabled(plugin, ext.id, resolveEnabled, ext.stability);
|
|
11111
11138
|
}
|
|
11112
|
-
function isPluginEntryEnabled(plugin, extId, resolveEnabled) {
|
|
11113
|
-
return resolveEnabled(qualifiedExtensionId(plugin.id, extId));
|
|
11139
|
+
function isPluginEntryEnabled(plugin, extId, resolveEnabled, stability) {
|
|
11140
|
+
return resolveEnabled(qualifiedExtensionId(plugin.id, extId), installedDefaultEnabled(stability));
|
|
11114
11141
|
}
|
|
11115
11142
|
function isPluginExtensionEnabled(ext, resolveEnabled) {
|
|
11116
|
-
return resolveEnabled(
|
|
11143
|
+
return resolveEnabled(
|
|
11144
|
+
qualifiedExtensionId(ext.pluginId, ext.id),
|
|
11145
|
+
installedDefaultEnabled(ext.stability)
|
|
11146
|
+
);
|
|
11117
11147
|
}
|
|
11118
11148
|
async function buildEnabledResolver(ctx) {
|
|
11119
11149
|
const { effective: cfg } = loadConfig({ ...ctx });
|
|
@@ -11311,11 +11341,11 @@ async function* walkContent(roots, options) {
|
|
|
11311
11341
|
const extensions = options.extensions;
|
|
11312
11342
|
const sizeLimit = buildSizeLimit(options);
|
|
11313
11343
|
for (const root of roots) {
|
|
11314
|
-
for await (const
|
|
11315
|
-
const relPath = relative2(root,
|
|
11344
|
+
for await (const entry of walkRoot(root, root, filter, extensions, sizeLimit)) {
|
|
11345
|
+
const relPath = relative2(root, entry.full).split(sep3).join("/");
|
|
11316
11346
|
let raw;
|
|
11317
11347
|
try {
|
|
11318
|
-
raw = await readFile(
|
|
11348
|
+
raw = await readFile(entry.full, "utf8");
|
|
11319
11349
|
} catch {
|
|
11320
11350
|
continue;
|
|
11321
11351
|
}
|
|
@@ -11325,6 +11355,9 @@ async function* walkContent(roots, options) {
|
|
|
11325
11355
|
body: parsed.body,
|
|
11326
11356
|
frontmatterRaw: parsed.frontmatterRaw,
|
|
11327
11357
|
frontmatter: parsed.frontmatter,
|
|
11358
|
+
// File mtime from the TOCTOU `lstat` (zero extra syscalls).
|
|
11359
|
+
// Threaded onto the persisted `Node` as `modifiedAtMs`.
|
|
11360
|
+
modifiedAtMs: entry.modifiedAtMs,
|
|
11328
11361
|
// Audit L1: forward parser diagnostics (e.g. malformed YAML)
|
|
11329
11362
|
// through the IRawNode surface so the orchestrator can
|
|
11330
11363
|
// convert them into warn-level kernel `Issue` rows. Omitted
|
|
@@ -11365,7 +11398,7 @@ async function* walkRoot(root, current, filter, extensions, sizeLimit) {
|
|
|
11365
11398
|
sizeLimit.onOversizedFile?.({ path: rel, bytes: s.size });
|
|
11366
11399
|
continue;
|
|
11367
11400
|
}
|
|
11368
|
-
yield full;
|
|
11401
|
+
yield { full, modifiedAtMs: Math.round(s.mtimeMs) };
|
|
11369
11402
|
} catch {
|
|
11370
11403
|
}
|
|
11371
11404
|
}
|
|
@@ -11447,8 +11480,8 @@ function bucketLoaded(loaded, runtime, pluginOrder) {
|
|
|
11447
11480
|
extractor: runtime.extensions.extractors,
|
|
11448
11481
|
analyzer: runtime.extensions.analyzers,
|
|
11449
11482
|
formatter: runtime.extensions.formatters,
|
|
11450
|
-
hook: runtime.extensions.hooks
|
|
11451
|
-
|
|
11483
|
+
hook: runtime.extensions.hooks,
|
|
11484
|
+
action: runtime.extensions.actions
|
|
11452
11485
|
});
|
|
11453
11486
|
runtime.manifests.push({
|
|
11454
11487
|
id: ext.id,
|
|
@@ -11563,7 +11596,7 @@ async function loadPluginRuntime(opts = {}) {
|
|
|
11563
11596
|
const loader = createPluginLoader(loaderOpts);
|
|
11564
11597
|
const discovered = await loader.discoverAndLoadAll();
|
|
11565
11598
|
const runtime = {
|
|
11566
|
-
extensions: { providers: [], extractors: [], analyzers: [], formatters: [], hooks: [] },
|
|
11599
|
+
extensions: { providers: [], extractors: [], analyzers: [], formatters: [], hooks: [], actions: [] },
|
|
11567
11600
|
annotationContributions: [],
|
|
11568
11601
|
viewContributions: [],
|
|
11569
11602
|
manifests: [],
|
|
@@ -11618,7 +11651,7 @@ function enforceRootExclusivity(catalog) {
|
|
|
11618
11651
|
}
|
|
11619
11652
|
function emptyPluginRuntime() {
|
|
11620
11653
|
const runtime = {
|
|
11621
|
-
extensions: { providers: [], extractors: [], analyzers: [], formatters: [], hooks: [] },
|
|
11654
|
+
extensions: { providers: [], extractors: [], analyzers: [], formatters: [], hooks: [], actions: [] },
|
|
11622
11655
|
annotationContributions: [],
|
|
11623
11656
|
viewContributions: [],
|
|
11624
11657
|
manifests: [],
|
|
@@ -11636,23 +11669,26 @@ function emptyPluginRuntime() {
|
|
|
11636
11669
|
function collectRegisteredContributionKeys(composed) {
|
|
11637
11670
|
const keys = /* @__PURE__ */ new Set();
|
|
11638
11671
|
if (!composed) return keys;
|
|
11639
|
-
for (const ext of [...composed.extractors, ...composed.analyzers]) {
|
|
11640
|
-
|
|
11641
|
-
if (typeof raw !== "object" || raw === null) continue;
|
|
11642
|
-
for (const [contributionId, value] of Object.entries(raw)) {
|
|
11643
|
-
if (typeof value !== "object" || value === null) continue;
|
|
11644
|
-
keys.add(`${ext.pluginId}/${ext.id}/${contributionId}`);
|
|
11645
|
-
}
|
|
11672
|
+
for (const ext of [...composed.extractors, ...composed.analyzers, ...composed.actions ?? []]) {
|
|
11673
|
+
addContributionKeysForExtension(ext, keys);
|
|
11646
11674
|
}
|
|
11647
11675
|
return keys;
|
|
11648
11676
|
}
|
|
11677
|
+
function addContributionKeysForExtension(ext, keys) {
|
|
11678
|
+
const raw = ext.ui;
|
|
11679
|
+
if (typeof raw !== "object" || raw === null) return;
|
|
11680
|
+
for (const [contributionId, value] of Object.entries(raw)) {
|
|
11681
|
+
if (typeof value !== "object" || value === null) continue;
|
|
11682
|
+
keys.add(`${ext.pluginId}/${ext.id}/${contributionId}`);
|
|
11683
|
+
}
|
|
11684
|
+
}
|
|
11649
11685
|
function filterBuiltInManifests(manifests, resolveEnabled) {
|
|
11650
11686
|
const pluginById = /* @__PURE__ */ new Map();
|
|
11651
11687
|
for (const plugin of builtInPlugins) pluginById.set(plugin.id, plugin);
|
|
11652
11688
|
return manifests.filter((m) => {
|
|
11653
11689
|
const plugin = pluginById.get(m.pluginId);
|
|
11654
11690
|
if (!plugin) return true;
|
|
11655
|
-
return isPluginEntryEnabled(plugin, m.id, resolveEnabled);
|
|
11691
|
+
return isPluginEntryEnabled(plugin, m.id, resolveEnabled, m.stability);
|
|
11656
11692
|
});
|
|
11657
11693
|
}
|
|
11658
11694
|
|
|
@@ -11663,9 +11699,10 @@ function composeScanExtensions(opts) {
|
|
|
11663
11699
|
const extractors = [];
|
|
11664
11700
|
const analyzers = [];
|
|
11665
11701
|
const hooks = [];
|
|
11702
|
+
const actions = [];
|
|
11666
11703
|
if (!opts.noBuiltIns) {
|
|
11667
11704
|
accumulateBuiltInScanExtensions(
|
|
11668
|
-
{ providers, extractors, analyzers, hooks },
|
|
11705
|
+
{ providers, extractors, analyzers, hooks, actions },
|
|
11669
11706
|
resolveEnabled
|
|
11670
11707
|
);
|
|
11671
11708
|
}
|
|
@@ -11681,6 +11718,9 @@ function composeScanExtensions(opts) {
|
|
|
11681
11718
|
for (const ext of opts.pluginRuntime.extensions.hooks) {
|
|
11682
11719
|
if (isPluginExtensionEnabled(ext, resolveEnabled)) hooks.push(ext);
|
|
11683
11720
|
}
|
|
11721
|
+
for (const ext of opts.pluginRuntime.extensions.actions) {
|
|
11722
|
+
if (isPluginExtensionEnabled(ext, resolveEnabled)) actions.push(ext);
|
|
11723
|
+
}
|
|
11684
11724
|
const finalProviders = opts.killSwitches?.providers === true ? [] : providers;
|
|
11685
11725
|
const finalExtractors = opts.killSwitches?.extractors === true ? [] : extractors;
|
|
11686
11726
|
const finalAnalyzers = opts.killSwitches?.analyzers === true ? [] : analyzers;
|
|
@@ -11691,7 +11731,8 @@ function composeScanExtensions(opts) {
|
|
|
11691
11731
|
providers: finalProviders,
|
|
11692
11732
|
extractors: finalExtractors,
|
|
11693
11733
|
analyzers: finalAnalyzers,
|
|
11694
|
-
hooks
|
|
11734
|
+
hooks,
|
|
11735
|
+
actions
|
|
11695
11736
|
};
|
|
11696
11737
|
}
|
|
11697
11738
|
function accumulateBuiltInScanExtensions(buckets, resolveEnabled) {
|
|
@@ -11712,6 +11753,7 @@ function accumulateBuiltInScanExtensions(buckets, resolveEnabled) {
|
|
|
11712
11753
|
buckets.hooks.push(ext);
|
|
11713
11754
|
break;
|
|
11714
11755
|
case "action":
|
|
11756
|
+
buckets.actions.push(ext);
|
|
11715
11757
|
break;
|
|
11716
11758
|
case "formatter":
|
|
11717
11759
|
break;
|
|
@@ -16155,12 +16197,87 @@ function recomputeExternalRefsCount(nodes, externalLinks, cachedPaths) {
|
|
|
16155
16197
|
});
|
|
16156
16198
|
source.externalRefs = refs;
|
|
16157
16199
|
}
|
|
16158
|
-
}
|
|
16159
|
-
var EXTERNAL_URL_SCHEME_RE = /^[a-z][a-z0-9+\-.]+:/i;
|
|
16160
|
-
var VIRTUAL_NODE_SCHEME_RE = /^mcp:\/\//i;
|
|
16161
|
-
function isExternalUrlLink(link) {
|
|
16162
|
-
if (VIRTUAL_NODE_SCHEME_RE.test(link.target)) return false;
|
|
16163
|
-
return EXTERNAL_URL_SCHEME_RE.test(link.target);
|
|
16200
|
+
}
|
|
16201
|
+
var EXTERNAL_URL_SCHEME_RE = /^[a-z][a-z0-9+\-.]+:/i;
|
|
16202
|
+
var VIRTUAL_NODE_SCHEME_RE = /^mcp:\/\//i;
|
|
16203
|
+
function isExternalUrlLink(link) {
|
|
16204
|
+
if (VIRTUAL_NODE_SCHEME_RE.test(link.target)) return false;
|
|
16205
|
+
return EXTERNAL_URL_SCHEME_RE.test(link.target);
|
|
16206
|
+
}
|
|
16207
|
+
|
|
16208
|
+
// kernel/orchestrator/action-projections.ts
|
|
16209
|
+
function runActionProjections(actions, nodes, links, emitter) {
|
|
16210
|
+
const contributions = [];
|
|
16211
|
+
const contributionErrors = [];
|
|
16212
|
+
const validators = loadSchemaValidators();
|
|
16213
|
+
for (const action of actions) {
|
|
16214
|
+
if (typeof action.project !== "function") continue;
|
|
16215
|
+
const qualifiedId2 = qualifiedExtensionId(action.pluginId, action.id);
|
|
16216
|
+
const declaredContributions = readDeclaredContributionRefs(action);
|
|
16217
|
+
const emitContribution = (nodePath, ref, payload) => {
|
|
16218
|
+
const declared = typeof ref === "object" && ref !== null ? declaredContributions.get(ref) : void 0;
|
|
16219
|
+
if (!declared) {
|
|
16220
|
+
const message = tx(ORCHESTRATOR_TEXTS.extensionErrorContributionUndeclaredRef, {
|
|
16221
|
+
extractorId: qualifiedId2,
|
|
16222
|
+
nodePath
|
|
16223
|
+
});
|
|
16224
|
+
emitExtensionError(emitter, qualifiedId2, nodePath, {
|
|
16225
|
+
phase: "emitContribution",
|
|
16226
|
+
reason: "undeclared-contribution-ref",
|
|
16227
|
+
message
|
|
16228
|
+
});
|
|
16229
|
+
contributionErrors.push({
|
|
16230
|
+
pluginId: action.pluginId,
|
|
16231
|
+
extensionId: action.id,
|
|
16232
|
+
nodePath,
|
|
16233
|
+
reason: "undeclared-contribution-ref",
|
|
16234
|
+
message,
|
|
16235
|
+
emittedAt: Date.now()
|
|
16236
|
+
});
|
|
16237
|
+
return;
|
|
16238
|
+
}
|
|
16239
|
+
const result = validators.validateContributionPayload(declared.slot, payload);
|
|
16240
|
+
if (!result.ok) {
|
|
16241
|
+
const message = tx(ORCHESTRATOR_TEXTS.extensionErrorContributionPayloadInvalid, {
|
|
16242
|
+
extractorId: qualifiedId2,
|
|
16243
|
+
contributionId: declared.id,
|
|
16244
|
+
nodePath,
|
|
16245
|
+
slot: declared.slot,
|
|
16246
|
+
errors: result.errors
|
|
16247
|
+
});
|
|
16248
|
+
emitExtensionError(emitter, qualifiedId2, nodePath, {
|
|
16249
|
+
phase: "emitContribution",
|
|
16250
|
+
contributionId: declared.id,
|
|
16251
|
+
slot: declared.slot,
|
|
16252
|
+
reason: result.errors,
|
|
16253
|
+
message
|
|
16254
|
+
});
|
|
16255
|
+
contributionErrors.push({
|
|
16256
|
+
pluginId: action.pluginId,
|
|
16257
|
+
extensionId: action.id,
|
|
16258
|
+
nodePath,
|
|
16259
|
+
reason: result.errors,
|
|
16260
|
+
message,
|
|
16261
|
+
contributionId: declared.id,
|
|
16262
|
+
slot: declared.slot,
|
|
16263
|
+
emittedAt: Date.now()
|
|
16264
|
+
});
|
|
16265
|
+
return;
|
|
16266
|
+
}
|
|
16267
|
+
contributions.push({
|
|
16268
|
+
pluginId: action.pluginId,
|
|
16269
|
+
extensionId: action.id,
|
|
16270
|
+
nodePath,
|
|
16271
|
+
contributionId: declared.id,
|
|
16272
|
+
slot: declared.slot,
|
|
16273
|
+
payload,
|
|
16274
|
+
emittedAt: Date.now()
|
|
16275
|
+
});
|
|
16276
|
+
};
|
|
16277
|
+
const ctx = { nodes, links, emitContribution };
|
|
16278
|
+
action.project(ctx);
|
|
16279
|
+
}
|
|
16280
|
+
return { contributions, contributionErrors };
|
|
16164
16281
|
}
|
|
16165
16282
|
|
|
16166
16283
|
// kernel/orchestrator/analyzers.ts
|
|
@@ -16952,6 +17069,7 @@ function buildNode(args2) {
|
|
|
16952
17069
|
externalRefsCount: 0,
|
|
16953
17070
|
frontmatter: args2.frontmatter
|
|
16954
17071
|
};
|
|
17072
|
+
if (args2.modifiedAtMs !== void 0) node.modifiedAtMs = args2.modifiedAtMs;
|
|
16955
17073
|
if (args2.encoder) {
|
|
16956
17074
|
node.tokens = countTokens(args2.encoder, args2.frontmatterRaw, args2.body);
|
|
16957
17075
|
}
|
|
@@ -17067,7 +17185,10 @@ function buildFreshNodeAndValidateFrontmatter(opts) {
|
|
|
17067
17185
|
frontmatter: opts.raw.frontmatter,
|
|
17068
17186
|
bodyHash: opts.bodyHash,
|
|
17069
17187
|
frontmatterHash: opts.frontmatterHash,
|
|
17070
|
-
encoder: opts.encoder
|
|
17188
|
+
encoder: opts.encoder,
|
|
17189
|
+
// Thread the walker's mtime through; `buildNode` only attaches it
|
|
17190
|
+
// when present, so virtual / walk()-without-stat sources stay absent.
|
|
17191
|
+
modifiedAtMs: opts.raw.modifiedAtMs
|
|
17071
17192
|
});
|
|
17072
17193
|
const frontmatterIssues = [];
|
|
17073
17194
|
if (opts.raw.parseIssues && opts.raw.parseIssues.length > 0) {
|
|
@@ -17501,6 +17622,13 @@ async function runScanInternal(_kernel, options) {
|
|
|
17501
17622
|
walked.frontmatterIssues
|
|
17502
17623
|
);
|
|
17503
17624
|
mergeAnalyzerEmissions(walked, analyzerResult, exts.analyzers);
|
|
17625
|
+
const projectionResult = runActionProjections(
|
|
17626
|
+
exts.actions ?? [],
|
|
17627
|
+
walked.nodes,
|
|
17628
|
+
walked.internalLinks,
|
|
17629
|
+
emitter
|
|
17630
|
+
);
|
|
17631
|
+
mergeActionProjections(walked, projectionResult, exts.actions);
|
|
17504
17632
|
const issues = analyzerResult.issues;
|
|
17505
17633
|
const silenced = options.ignoreFilter ? (path) => options.ignoreFilter.ignores(path) : void 0;
|
|
17506
17634
|
const renameOps = prior ? detectRenamesAndOrphans(prior, walked.nodes, issues, silenced) : [];
|
|
@@ -17609,6 +17737,16 @@ function mergeAnalyzerEmissions(walked, analyzerResult, analyzers) {
|
|
|
17609
17737
|
}
|
|
17610
17738
|
}
|
|
17611
17739
|
}
|
|
17740
|
+
function mergeActionProjections(walked, projectionResult, actions) {
|
|
17741
|
+
for (const c of projectionResult.contributions) walked.contributions.push(c);
|
|
17742
|
+
for (const e of projectionResult.contributionErrors) walked.contributionErrors.push(e);
|
|
17743
|
+
for (const action of actions ?? []) {
|
|
17744
|
+
if (action.ui === void 0 || typeof action.project !== "function") continue;
|
|
17745
|
+
for (const node of walked.nodes) {
|
|
17746
|
+
walked.freshlyRunTuples.add(`${action.pluginId}\0${action.id}\0${node.path}`);
|
|
17747
|
+
}
|
|
17748
|
+
}
|
|
17749
|
+
}
|
|
17612
17750
|
function buildScanStats(walked, issues, start) {
|
|
17613
17751
|
return {
|
|
17614
17752
|
// `filesSkipped` is "files walked but not classified by any
|
|
@@ -20513,6 +20651,17 @@ var PLUGINS_TEXTS = {
|
|
|
20513
20651
|
qualifiedIdNotFoundHint: "Run `sm plugins list` to see what each plugin ships.",
|
|
20514
20652
|
qualifiedIdUnknownPlugin: "{{glyph}} Qualified extension id references unknown plugin: {{pluginId}}\n {{hint}}\n",
|
|
20515
20653
|
qualifiedIdUnknownPluginHint: "Run `sm plugins list` for known plugin ids.",
|
|
20654
|
+
// --- verb-shape redirects (show is extension-only; list is plugin-only) ---
|
|
20655
|
+
// `sm plugins show` takes a qualified `<plugin>/<ext>` id and renders a
|
|
20656
|
+
// single extension. A bare plugin id is the wrong granularity, redirect
|
|
20657
|
+
// to `sm plugins list <id>`, which renders the whole plugin.
|
|
20658
|
+
showBareId: '{{glyph}} `sm plugins show` needs a qualified `<plugin>/<ext>` id; "{{id}}" is a plugin.\n {{hint}}\n',
|
|
20659
|
+
showBareIdHint: "Run `sm plugins list {{id}}` for the plugin and its extensions, then `sm plugins show {{id}}/<ext>` for one.",
|
|
20660
|
+
// `sm plugins list <id>` takes a bare plugin id. A qualified
|
|
20661
|
+
// `<plugin>/<ext>` id targets a single extension, redirect to
|
|
20662
|
+
// `sm plugins show`.
|
|
20663
|
+
listQualifiedId: "{{glyph}} `sm plugins list` takes a plugin id, not a qualified `<plugin>/<ext>` id: {{id}}\n {{hint}}\n",
|
|
20664
|
+
listQualifiedIdHint: "Run `sm plugins show {{id}}` for that extension, or `sm plugins list {{pluginId}}` for the whole plugin.",
|
|
20516
20665
|
// Spec § A.10, `applicableKinds` filter on Extractors. When an extractor
|
|
20517
20666
|
// declares a kind that no installed Provider emits, the load succeeds
|
|
20518
20667
|
// (the Provider may arrive later) but `sm plugins doctor` surfaces a
|
|
@@ -20653,7 +20802,7 @@ var PLUGINS_TEXTS = {
|
|
|
20653
20802
|
* (declared or defaulted) renders no tag.
|
|
20654
20803
|
*/
|
|
20655
20804
|
stabilityTag: " ({{stability}})",
|
|
20656
|
-
listTipShow: "\nTip: `sm plugins
|
|
20805
|
+
listTipShow: "\nTip: `sm plugins list <id>` for a plugin's extensions (kinds, versions, per-extension status), `sm plugins show <plugin>/<ext>` for one extension.\n",
|
|
20657
20806
|
/** Show command, built-in header (no version row, no path). */
|
|
20658
20807
|
detailHeaderBuiltIn: " {{glyph}} {{id}} {{source}} {{count}} extension{{plural}}\n",
|
|
20659
20808
|
/**
|
|
@@ -20805,7 +20954,7 @@ function extensionRowFromBuiltIn(ext, plugin, resolveEnabled) {
|
|
|
20805
20954
|
id: ext.id,
|
|
20806
20955
|
kind: ext.kind,
|
|
20807
20956
|
version: ext.version,
|
|
20808
|
-
enabled: resolveEnabled(qualifiedExtensionId(plugin.id, ext.id)),
|
|
20957
|
+
enabled: resolveEnabled(qualifiedExtensionId(plugin.id, ext.id), installedDefaultEnabled(ext.stability)),
|
|
20809
20958
|
description: ext.description ?? ""
|
|
20810
20959
|
};
|
|
20811
20960
|
if (ext.stability !== void 0) row.stability = ext.stability;
|
|
@@ -20822,6 +20971,43 @@ function omitModule(key, value) {
|
|
|
20822
20971
|
const tag = value[Symbol.toStringTag];
|
|
20823
20972
|
return tag === "Module" ? void 0 : value;
|
|
20824
20973
|
}
|
|
20974
|
+
function pluginCatalogue(plugins) {
|
|
20975
|
+
const out = [];
|
|
20976
|
+
for (const plugin of builtInPlugins) {
|
|
20977
|
+
out.push({ id: plugin.id, extensionIds: plugin.extensions.map((e) => e.id) });
|
|
20978
|
+
}
|
|
20979
|
+
for (const p of plugins) {
|
|
20980
|
+
out.push({ id: p.id, extensionIds: p.extensions?.map((e) => e.id) ?? [] });
|
|
20981
|
+
}
|
|
20982
|
+
return out;
|
|
20983
|
+
}
|
|
20984
|
+
function parseQualifiedExtensionId(id, catalogue) {
|
|
20985
|
+
const [pluginId, extId, ...rest] = id.split("/");
|
|
20986
|
+
if (!pluginId || !extId || rest.length > 0) return { ok: false, reason: "malformed" };
|
|
20987
|
+
const plugin = catalogue.find((p) => p.id === pluginId);
|
|
20988
|
+
if (!plugin) return { ok: false, reason: "unknown-plugin", pluginId };
|
|
20989
|
+
if (!plugin.extensionIds.includes(extId)) {
|
|
20990
|
+
return { ok: false, reason: "unknown-extension", pluginId, extId };
|
|
20991
|
+
}
|
|
20992
|
+
return { ok: true, pluginId, extId };
|
|
20993
|
+
}
|
|
20994
|
+
function renderQualifiedIdError(result, rawId, ansi) {
|
|
20995
|
+
const glyph = ansi.red(PLUGINS_TEXTS.rowGlyphOff);
|
|
20996
|
+
if (result.reason === "unknown-extension") {
|
|
20997
|
+
return tx(PLUGINS_TEXTS.qualifiedIdNotFound, {
|
|
20998
|
+
glyph,
|
|
20999
|
+
id: sanitizeForTerminal(rawId),
|
|
21000
|
+
pluginId: sanitizeForTerminal(result.pluginId ?? ""),
|
|
21001
|
+
extId: sanitizeForTerminal(result.extId ?? ""),
|
|
21002
|
+
hint: ansi.dim(PLUGINS_TEXTS.qualifiedIdNotFoundHint)
|
|
21003
|
+
});
|
|
21004
|
+
}
|
|
21005
|
+
return tx(PLUGINS_TEXTS.qualifiedIdUnknownPlugin, {
|
|
21006
|
+
glyph,
|
|
21007
|
+
pluginId: sanitizeForTerminal(result.reason === "unknown-plugin" ? result.pluginId ?? rawId : rawId),
|
|
21008
|
+
hint: ansi.dim(PLUGINS_TEXTS.qualifiedIdUnknownPluginHint)
|
|
21009
|
+
});
|
|
21010
|
+
}
|
|
20825
21011
|
function wrapText(text, maxWidth) {
|
|
20826
21012
|
const words = text.split(/\s+/).filter((w) => w.length > 0);
|
|
20827
21013
|
if (words.length === 0) return [];
|
|
@@ -20845,14 +21031,24 @@ var PluginsListCommand = class extends SmCommand {
|
|
|
20845
21031
|
static paths = [["plugins", "list"]];
|
|
20846
21032
|
static usage = Command22.Usage({
|
|
20847
21033
|
category: "Plugins",
|
|
20848
|
-
description: "List discovered plugins
|
|
20849
|
-
details:
|
|
21034
|
+
description: "List discovered plugins, or one plugin's extensions.",
|
|
21035
|
+
details: `
|
|
21036
|
+
No id: scans <cwd>/.skill-map/plugins (or --plugin-dir <path>) and
|
|
21037
|
+
lists every plugin (built-in + user) with status, one row each.
|
|
21038
|
+
With a bare plugin id: renders that plugin's manifest and its
|
|
21039
|
+
extensions (kind / version / per-extension status). A qualified
|
|
21040
|
+
\`<plugin>/<ext>\` id is rejected with a redirect to \`sm plugins show\`.
|
|
21041
|
+
`
|
|
20850
21042
|
});
|
|
21043
|
+
id = Option21.String({ required: false });
|
|
20851
21044
|
pluginDir = Option21.String("--plugin-dir", { required: false });
|
|
20852
21045
|
async run() {
|
|
20853
21046
|
const plugins = await loadAll({ pluginDir: this.pluginDir });
|
|
20854
21047
|
const resolveEnabled = await buildResolver();
|
|
20855
21048
|
const builtIns2 = builtInRows(resolveEnabled);
|
|
21049
|
+
if (this.id !== void 0) {
|
|
21050
|
+
return this.renderPluginDetailById(this.id, builtIns2, plugins);
|
|
21051
|
+
}
|
|
20856
21052
|
if (this.json) {
|
|
20857
21053
|
this.printer.data(
|
|
20858
21054
|
JSON.stringify({ builtIns: builtIns2, plugins }, omitModule, 2) + "\n"
|
|
@@ -20864,24 +21060,68 @@ var PluginsListCommand = class extends SmCommand {
|
|
|
20864
21060
|
return ExitCode.Ok;
|
|
20865
21061
|
}
|
|
20866
21062
|
const ansi = this.ansiFor("stdout");
|
|
20867
|
-
this.printer.data(
|
|
21063
|
+
this.printer.data(renderIndexHuman(builtIns2, plugins, resolveEnabled, ansi));
|
|
21064
|
+
return ExitCode.Ok;
|
|
21065
|
+
}
|
|
21066
|
+
/**
|
|
21067
|
+
* `sm plugins list <id>`, render one plugin's full detail. A qualified
|
|
21068
|
+
* `<plugin>/<ext>` id is the wrong granularity for `list` (it targets a
|
|
21069
|
+
* single extension), redirect to `sm plugins show`. A bare id that
|
|
21070
|
+
* matches no plugin is a NotFound.
|
|
21071
|
+
*/
|
|
21072
|
+
renderPluginDetailById(id, builtIns2, plugins) {
|
|
21073
|
+
const stderrAnsi = this.ansiFor("stderr");
|
|
21074
|
+
if (id.includes("/")) {
|
|
21075
|
+
const pluginId = id.split("/")[0] ?? id;
|
|
21076
|
+
this.printer.error(
|
|
21077
|
+
tx(PLUGINS_TEXTS.listQualifiedId, {
|
|
21078
|
+
glyph: stderrAnsi.red(PLUGINS_TEXTS.rowGlyphOff),
|
|
21079
|
+
id: sanitizeForTerminal(id),
|
|
21080
|
+
hint: stderrAnsi.dim(
|
|
21081
|
+
tx(PLUGINS_TEXTS.listQualifiedIdHint, {
|
|
21082
|
+
id: sanitizeForTerminal(id),
|
|
21083
|
+
pluginId: sanitizeForTerminal(pluginId)
|
|
21084
|
+
})
|
|
21085
|
+
)
|
|
21086
|
+
})
|
|
21087
|
+
);
|
|
21088
|
+
return ExitCode.Error;
|
|
21089
|
+
}
|
|
21090
|
+
const builtIn = builtIns2.find((b) => b.id === id);
|
|
21091
|
+
const match = plugins.find((p) => p.id === id);
|
|
21092
|
+
if (!builtIn && !match) {
|
|
21093
|
+
this.printer.error(
|
|
21094
|
+
tx(PLUGINS_TEXTS.pluginNotFound, {
|
|
21095
|
+
glyph: stderrAnsi.red(PLUGINS_TEXTS.rowGlyphOff),
|
|
21096
|
+
id: sanitizeForTerminal(id),
|
|
21097
|
+
hint: stderrAnsi.dim(PLUGINS_TEXTS.pluginNotFoundHint)
|
|
21098
|
+
})
|
|
21099
|
+
);
|
|
21100
|
+
return ExitCode.NotFound;
|
|
21101
|
+
}
|
|
21102
|
+
if (this.json) {
|
|
21103
|
+
const payload = builtIn ?? match;
|
|
21104
|
+
this.printer.data(JSON.stringify(payload, omitModule, 2) + "\n");
|
|
21105
|
+
return ExitCode.Ok;
|
|
21106
|
+
}
|
|
21107
|
+
const ansi = this.ansiFor("stdout");
|
|
21108
|
+
const text = builtIn ? renderBuiltInDetail(builtIn, ansi) : renderPluginDetail(match, ansi);
|
|
21109
|
+
this.printer.data(text);
|
|
20868
21110
|
return ExitCode.Ok;
|
|
20869
21111
|
}
|
|
20870
21112
|
};
|
|
20871
|
-
function
|
|
21113
|
+
function renderIndexHuman(builtIns2, plugins, resolveEnabled, ansi) {
|
|
20872
21114
|
const rows = [
|
|
20873
|
-
...builtIns2.map(
|
|
20874
|
-
...plugins.map((p) =>
|
|
21115
|
+
...builtIns2.map(builtInToIndexRow),
|
|
21116
|
+
...plugins.map((p) => pluginToIndexRow(p, resolveEnabled))
|
|
20875
21117
|
];
|
|
20876
21118
|
const idWidth = Math.max(...rows.map((r) => r.id.length));
|
|
20877
|
-
const countWidth = Math.max(
|
|
20878
|
-
...rows.map((r) => String(r.names.length).length)
|
|
20879
|
-
);
|
|
21119
|
+
const countWidth = Math.max(...rows.map((r) => String(r.extCount).length));
|
|
20880
21120
|
const lines = [];
|
|
20881
21121
|
for (const row of rows) {
|
|
20882
21122
|
const glyph = row.enabled ? ansi.green(PLUGINS_TEXTS.rowGlyphOk) : ansi.red(PLUGINS_TEXTS.rowGlyphOff);
|
|
20883
21123
|
const idCol = row.id.padEnd(idWidth);
|
|
20884
|
-
const countCol = String(row.
|
|
21124
|
+
const countCol = String(row.extCount).padStart(countWidth);
|
|
20885
21125
|
lines.push(
|
|
20886
21126
|
tx(PLUGINS_TEXTS.pluginRow, {
|
|
20887
21127
|
glyph,
|
|
@@ -20890,196 +21130,34 @@ function renderListHuman(builtIns2, plugins, resolveEnabled, ansi) {
|
|
|
20890
21130
|
source: ansi.dim(row.source)
|
|
20891
21131
|
})
|
|
20892
21132
|
);
|
|
20893
|
-
const indent = PLUGINS_TEXTS.pluginSubIndent;
|
|
20894
21133
|
if (row.reason) {
|
|
20895
|
-
lines.push(`${
|
|
20896
|
-
} else if (row.names.length > 0) {
|
|
20897
|
-
for (const wrapped of wrapNames(row.names, indent, 76)) {
|
|
20898
|
-
lines.push(`${indent}${ansi.dim(wrapped)}`);
|
|
20899
|
-
}
|
|
21134
|
+
lines.push(`${PLUGINS_TEXTS.pluginSubIndent}${ansi.dim(row.reason)}`);
|
|
20900
21135
|
}
|
|
20901
21136
|
}
|
|
20902
21137
|
return lines.join("\n") + "\n" + PLUGINS_TEXTS.listTipShow;
|
|
20903
21138
|
}
|
|
20904
|
-
function
|
|
20905
|
-
const names = b.extensions.map((e) => {
|
|
20906
|
-
const name = withStabilityTag(e.id, e.stability);
|
|
20907
|
-
return e.enabled ? name : `${PLUGINS_TEXTS.rowGlyphOff} ${name}`;
|
|
20908
|
-
});
|
|
21139
|
+
function builtInToIndexRow(b) {
|
|
20909
21140
|
return {
|
|
20910
21141
|
id: b.id,
|
|
20911
21142
|
enabled: b.enabled,
|
|
20912
21143
|
source: PLUGINS_TEXTS.sourceBuiltIn,
|
|
20913
|
-
|
|
21144
|
+
extCount: b.extensions.length
|
|
20914
21145
|
};
|
|
20915
21146
|
}
|
|
20916
|
-
function
|
|
21147
|
+
function pluginToIndexRow(p, resolveEnabled) {
|
|
20917
21148
|
const isLoaded = p.status === "enabled";
|
|
20918
21149
|
const extensions = p.extensions ?? [];
|
|
20919
|
-
const
|
|
20920
|
-
const
|
|
20921
|
-
const safeId = withStabilityTag(sanitizeForTerminal(e.id), e.stability);
|
|
20922
|
-
return resolveEnabled(qualifiedExtensionId(p.id, e.id)) ? safeId : `${PLUGINS_TEXTS.rowGlyphOff} ${safeId}`;
|
|
20923
|
-
});
|
|
21150
|
+
const extEnabled = (e) => resolveEnabled(qualifiedExtensionId(p.id, e.id), installedDefaultEnabled(e.stability));
|
|
21151
|
+
const enabled = isLoaded ? extensions.length === 0 || extensions.some((e) => extEnabled(e)) : false;
|
|
20924
21152
|
const reason = p.status === "enabled" ? void 0 : sanitizeForTerminal(p.reason ?? "") || void 0;
|
|
20925
21153
|
return {
|
|
20926
21154
|
id: sanitizeForTerminal(p.id),
|
|
20927
21155
|
enabled,
|
|
20928
21156
|
source: PLUGINS_TEXTS.sourceUser,
|
|
20929
|
-
|
|
21157
|
+
extCount: extensions.length,
|
|
20930
21158
|
reason
|
|
20931
21159
|
};
|
|
20932
21160
|
}
|
|
20933
|
-
function wrapNames(names, indent, maxWidth) {
|
|
20934
|
-
const out = [];
|
|
20935
|
-
const sep8 = ", ";
|
|
20936
|
-
let current = "";
|
|
20937
|
-
for (const name of names) {
|
|
20938
|
-
const candidate = current === "" ? name : `${current}${sep8}${name}`;
|
|
20939
|
-
if (indent.length + candidate.length > maxWidth && current !== "") {
|
|
20940
|
-
out.push(`${current},`);
|
|
20941
|
-
current = name;
|
|
20942
|
-
} else {
|
|
20943
|
-
current = candidate;
|
|
20944
|
-
}
|
|
20945
|
-
}
|
|
20946
|
-
if (current !== "") out.push(current);
|
|
20947
|
-
return out;
|
|
20948
|
-
}
|
|
20949
|
-
|
|
20950
|
-
// cli/commands/plugins/show.ts
|
|
20951
|
-
import { Command as Command23, Option as Option22 } from "clipanion";
|
|
20952
|
-
var PluginsShowCommand = class extends SmCommand {
|
|
20953
|
-
static paths = [["plugins", "show"]];
|
|
20954
|
-
static usage = Command23.Usage({
|
|
20955
|
-
category: "Plugins",
|
|
20956
|
-
description: "Show a single plugin's manifest + loaded extensions.",
|
|
20957
|
-
details: `
|
|
20958
|
-
Accepts a plugin id (\`core\`, \`claude\`, \`my-plugin\`)
|
|
20959
|
-
or a qualified extension id (\`core/<ext-id>\`,
|
|
20960
|
-
\`<plugin>/<ext-id>\`). When given a qualified id, validates the
|
|
20961
|
-
extension exists and renders a single-extension detail block.
|
|
20962
|
-
The bare form renders the parent plugin's detail with per-extension
|
|
20963
|
-
status. The same id shapes \`sm plugins enable\` and
|
|
20964
|
-
\`sm plugins disable\` accept resolve cleanly here too.
|
|
20965
|
-
`
|
|
20966
|
-
});
|
|
20967
|
-
id = Option22.String({ required: true });
|
|
20968
|
-
pluginDir = Option22.String("--plugin-dir", { required: false });
|
|
20969
|
-
async run() {
|
|
20970
|
-
const plugins = await loadAll({ pluginDir: this.pluginDir });
|
|
20971
|
-
const resolveEnabled = await buildResolver();
|
|
20972
|
-
const builtIns2 = builtInRows(resolveEnabled);
|
|
20973
|
-
const stderrAnsi = this.ansiFor("stderr");
|
|
20974
|
-
const lookupResult = resolveShowLookupId(this.id, builtIns2, plugins, stderrAnsi);
|
|
20975
|
-
if ("error" in lookupResult) {
|
|
20976
|
-
this.printer.error(lookupResult.error);
|
|
20977
|
-
return ExitCode.NotFound;
|
|
20978
|
-
}
|
|
20979
|
-
const { pluginId, extId } = lookupResult;
|
|
20980
|
-
const builtIn = builtIns2.find((b) => b.id === pluginId);
|
|
20981
|
-
const match = plugins.find((p) => p.id === pluginId);
|
|
20982
|
-
if (!builtIn && !match) {
|
|
20983
|
-
this.printer.error(
|
|
20984
|
-
tx(PLUGINS_TEXTS.pluginNotFound, {
|
|
20985
|
-
glyph: stderrAnsi.red("\u2715"),
|
|
20986
|
-
id: sanitizeForTerminal(this.id),
|
|
20987
|
-
hint: stderrAnsi.dim(PLUGINS_TEXTS.pluginNotFoundHint)
|
|
20988
|
-
})
|
|
20989
|
-
);
|
|
20990
|
-
return ExitCode.NotFound;
|
|
20991
|
-
}
|
|
20992
|
-
if (extId !== void 0) {
|
|
20993
|
-
return this.renderExtensionDetail({ extId, pluginId, builtIn, match });
|
|
20994
|
-
}
|
|
20995
|
-
if (this.json) {
|
|
20996
|
-
const payload = builtIn ?? match;
|
|
20997
|
-
this.printer.data(JSON.stringify(payload, omitModule, 2) + "\n");
|
|
20998
|
-
return ExitCode.Ok;
|
|
20999
|
-
}
|
|
21000
|
-
const ansi = this.ansiFor("stdout");
|
|
21001
|
-
const text = builtIn ? renderBuiltInDetail(builtIn, ansi) : renderPluginDetail(match, ansi);
|
|
21002
|
-
this.printer.data(text);
|
|
21003
|
-
return ExitCode.Ok;
|
|
21004
|
-
}
|
|
21005
|
-
/**
|
|
21006
|
-
* Render the single-extension detail block, the path taken when the
|
|
21007
|
-
* user supplies a qualified `<plugin>/<ext>` id. `--json` emits the
|
|
21008
|
-
* single extension row (no surrounding plugin envelope) so tooling
|
|
21009
|
-
* can pipe straight into `jq`; human mode renders a focused header
|
|
21010
|
-
* plus a Kind / Version / Stability / Description / Preconditions /
|
|
21011
|
-
* Entry field block.
|
|
21012
|
-
*/
|
|
21013
|
-
renderExtensionDetail(args2) {
|
|
21014
|
-
const { extId, pluginId, builtIn, match } = args2;
|
|
21015
|
-
const ansi = this.ansiFor("stdout");
|
|
21016
|
-
if (builtIn) {
|
|
21017
|
-
const ext = builtIn.extensions.find((e) => e.id === extId);
|
|
21018
|
-
if (!ext) return ExitCode.NotFound;
|
|
21019
|
-
if (this.json) {
|
|
21020
|
-
this.printer.data(JSON.stringify({ pluginId, ...ext }, omitModule, 2) + "\n");
|
|
21021
|
-
return ExitCode.Ok;
|
|
21022
|
-
}
|
|
21023
|
-
this.printer.data(renderBuiltInExtensionDetail(pluginId, ext, ansi));
|
|
21024
|
-
return ExitCode.Ok;
|
|
21025
|
-
}
|
|
21026
|
-
const userExt = match?.extensions?.find((e) => e.id === extId);
|
|
21027
|
-
if (!userExt) return ExitCode.NotFound;
|
|
21028
|
-
if (this.json) {
|
|
21029
|
-
this.printer.data(JSON.stringify(userExt, omitModule, 2) + "\n");
|
|
21030
|
-
return ExitCode.Ok;
|
|
21031
|
-
}
|
|
21032
|
-
this.printer.data(renderUserExtensionDetail(pluginId, userExt, ansi));
|
|
21033
|
-
return ExitCode.Ok;
|
|
21034
|
-
}
|
|
21035
|
-
};
|
|
21036
|
-
function resolveShowLookupId(id, builtIns2, plugins, ansi) {
|
|
21037
|
-
if (!id.includes("/")) return { pluginId: id };
|
|
21038
|
-
const parsed = parseQualifiedId(id);
|
|
21039
|
-
if ("error" in parsed) return { error: malformedQualifiedError(id, ansi) };
|
|
21040
|
-
const { pluginId, extId } = parsed;
|
|
21041
|
-
const knownExts = collectKnownExtensions(pluginId, builtIns2, plugins);
|
|
21042
|
-
if (knownExts === null) return { error: unknownPluginError(pluginId, ansi) };
|
|
21043
|
-
if (!knownExts.includes(extId)) {
|
|
21044
|
-
return { error: unknownExtensionError(id, pluginId, extId, ansi) };
|
|
21045
|
-
}
|
|
21046
|
-
return { pluginId, extId };
|
|
21047
|
-
}
|
|
21048
|
-
function parseQualifiedId(id) {
|
|
21049
|
-
const [pluginId, extId, ...rest] = id.split("/");
|
|
21050
|
-
if (!pluginId || !extId || rest.length > 0) return { error: true };
|
|
21051
|
-
return { pluginId, extId };
|
|
21052
|
-
}
|
|
21053
|
-
function collectKnownExtensions(pluginId, builtIns2, plugins) {
|
|
21054
|
-
const builtIn = builtIns2.find((b) => b.id === pluginId);
|
|
21055
|
-
if (builtIn) return builtIn.extensions.map((e) => e.id);
|
|
21056
|
-
const userPlugin = plugins.find((p) => p.id === pluginId);
|
|
21057
|
-
if (userPlugin) return userPlugin.extensions?.map((e) => e.id) ?? [];
|
|
21058
|
-
return null;
|
|
21059
|
-
}
|
|
21060
|
-
function malformedQualifiedError(id, ansi) {
|
|
21061
|
-
return tx(PLUGINS_TEXTS.qualifiedIdUnknownPlugin, {
|
|
21062
|
-
glyph: ansi.red("\u2715"),
|
|
21063
|
-
pluginId: sanitizeForTerminal(id),
|
|
21064
|
-
hint: ansi.dim(PLUGINS_TEXTS.qualifiedIdUnknownPluginHint)
|
|
21065
|
-
});
|
|
21066
|
-
}
|
|
21067
|
-
function unknownPluginError(pluginId, ansi) {
|
|
21068
|
-
return tx(PLUGINS_TEXTS.qualifiedIdUnknownPlugin, {
|
|
21069
|
-
glyph: ansi.red("\u2715"),
|
|
21070
|
-
pluginId: sanitizeForTerminal(pluginId),
|
|
21071
|
-
hint: ansi.dim(PLUGINS_TEXTS.qualifiedIdUnknownPluginHint)
|
|
21072
|
-
});
|
|
21073
|
-
}
|
|
21074
|
-
function unknownExtensionError(id, pluginId, extId, ansi) {
|
|
21075
|
-
return tx(PLUGINS_TEXTS.qualifiedIdNotFound, {
|
|
21076
|
-
glyph: ansi.red("\u2715"),
|
|
21077
|
-
id: sanitizeForTerminal(id),
|
|
21078
|
-
pluginId: sanitizeForTerminal(pluginId),
|
|
21079
|
-
extId: sanitizeForTerminal(extId),
|
|
21080
|
-
hint: ansi.dim(PLUGINS_TEXTS.qualifiedIdNotFoundHint)
|
|
21081
|
-
});
|
|
21082
|
-
}
|
|
21083
21161
|
function kindIndex(kind) {
|
|
21084
21162
|
const idx = EXTENSION_KINDS.indexOf(kind);
|
|
21085
21163
|
return idx === -1 ? EXTENSION_KINDS.length : idx;
|
|
@@ -21203,6 +21281,83 @@ function renderExtensionItems(items) {
|
|
|
21203
21281
|
}
|
|
21204
21282
|
return out.join("");
|
|
21205
21283
|
}
|
|
21284
|
+
|
|
21285
|
+
// cli/commands/plugins/show.ts
|
|
21286
|
+
import { Command as Command23, Option as Option22 } from "clipanion";
|
|
21287
|
+
var PluginsShowCommand = class extends SmCommand {
|
|
21288
|
+
static paths = [["plugins", "show"]];
|
|
21289
|
+
static usage = Command23.Usage({
|
|
21290
|
+
category: "Plugins",
|
|
21291
|
+
description: "Show a single extension's detail.",
|
|
21292
|
+
details: `
|
|
21293
|
+
Accepts a qualified extension id (\`core/<ext-id>\`,
|
|
21294
|
+
\`<plugin>/<ext-id>\`) and renders a single-extension detail block
|
|
21295
|
+
(Kind / Version / Stability / Description / Preconditions / Entry).
|
|
21296
|
+
A bare plugin id is rejected with a redirect to
|
|
21297
|
+
\`sm plugins list <id>\`, which renders the whole plugin. The same
|
|
21298
|
+
qualified id shape \`sm plugins enable\` and \`sm plugins disable\`
|
|
21299
|
+
accept resolves cleanly here too.
|
|
21300
|
+
`
|
|
21301
|
+
});
|
|
21302
|
+
id = Option22.String({ required: true });
|
|
21303
|
+
pluginDir = Option22.String("--plugin-dir", { required: false });
|
|
21304
|
+
async run() {
|
|
21305
|
+
const plugins = await loadAll({ pluginDir: this.pluginDir });
|
|
21306
|
+
const resolveEnabled = await buildResolver();
|
|
21307
|
+
const builtIns2 = builtInRows(resolveEnabled);
|
|
21308
|
+
const stderrAnsi = this.ansiFor("stderr");
|
|
21309
|
+
if (!this.id.includes("/")) {
|
|
21310
|
+
this.printer.error(
|
|
21311
|
+
tx(PLUGINS_TEXTS.showBareId, {
|
|
21312
|
+
glyph: stderrAnsi.red(PLUGINS_TEXTS.rowGlyphOff),
|
|
21313
|
+
id: sanitizeForTerminal(this.id),
|
|
21314
|
+
hint: stderrAnsi.dim(
|
|
21315
|
+
tx(PLUGINS_TEXTS.showBareIdHint, { id: sanitizeForTerminal(this.id) })
|
|
21316
|
+
)
|
|
21317
|
+
})
|
|
21318
|
+
);
|
|
21319
|
+
return ExitCode.Error;
|
|
21320
|
+
}
|
|
21321
|
+
const parsed = parseQualifiedExtensionId(this.id, pluginCatalogue(plugins));
|
|
21322
|
+
if (!parsed.ok) {
|
|
21323
|
+
this.printer.error(renderQualifiedIdError(parsed, this.id, stderrAnsi));
|
|
21324
|
+
return ExitCode.NotFound;
|
|
21325
|
+
}
|
|
21326
|
+
const { pluginId, extId } = parsed;
|
|
21327
|
+
const builtIn = builtIns2.find((b) => b.id === pluginId);
|
|
21328
|
+
const match = plugins.find((p) => p.id === pluginId);
|
|
21329
|
+
return this.renderExtensionDetail({ extId, pluginId, builtIn, match });
|
|
21330
|
+
}
|
|
21331
|
+
/**
|
|
21332
|
+
* Render the single-extension detail block. `--json` emits the single
|
|
21333
|
+
* extension row (no surrounding plugin envelope) so tooling can pipe
|
|
21334
|
+
* straight into `jq`; human mode renders a focused header plus a
|
|
21335
|
+
* Kind / Version / Stability / Description / Preconditions / Entry
|
|
21336
|
+
* field block.
|
|
21337
|
+
*/
|
|
21338
|
+
renderExtensionDetail(args2) {
|
|
21339
|
+
const { extId, pluginId, builtIn, match } = args2;
|
|
21340
|
+
const ansi = this.ansiFor("stdout");
|
|
21341
|
+
if (builtIn) {
|
|
21342
|
+
const ext = builtIn.extensions.find((e) => e.id === extId);
|
|
21343
|
+
if (!ext) return ExitCode.NotFound;
|
|
21344
|
+
if (this.json) {
|
|
21345
|
+
this.printer.data(JSON.stringify({ pluginId, ...ext }, omitModule, 2) + "\n");
|
|
21346
|
+
return ExitCode.Ok;
|
|
21347
|
+
}
|
|
21348
|
+
this.printer.data(renderBuiltInExtensionDetail(pluginId, ext, ansi));
|
|
21349
|
+
return ExitCode.Ok;
|
|
21350
|
+
}
|
|
21351
|
+
const userExt = match?.extensions?.find((e) => e.id === extId);
|
|
21352
|
+
if (!userExt) return ExitCode.NotFound;
|
|
21353
|
+
if (this.json) {
|
|
21354
|
+
this.printer.data(JSON.stringify(userExt, omitModule, 2) + "\n");
|
|
21355
|
+
return ExitCode.Ok;
|
|
21356
|
+
}
|
|
21357
|
+
this.printer.data(renderUserExtensionDetail(pluginId, userExt, ansi));
|
|
21358
|
+
return ExitCode.Ok;
|
|
21359
|
+
}
|
|
21360
|
+
};
|
|
21206
21361
|
function renderBuiltInExtensionDetail(pluginId, ext, ansi) {
|
|
21207
21362
|
const glyph = ext.enabled ? ansi.green(PLUGINS_TEXTS.rowGlyphOk) : ansi.red(PLUGINS_TEXTS.rowGlyphOff);
|
|
21208
21363
|
const header = tx(PLUGINS_TEXTS.detailHeaderExtensionBuiltIn, {
|
|
@@ -22039,61 +22194,15 @@ var PluginsDisableCommand = class extends TogglePluginsBase {
|
|
|
22039
22194
|
return this.toggle(false);
|
|
22040
22195
|
}
|
|
22041
22196
|
};
|
|
22042
|
-
function pluginCatalogue(plugins) {
|
|
22043
|
-
const out = [];
|
|
22044
|
-
for (const plugin of builtInPlugins) {
|
|
22045
|
-
out.push({
|
|
22046
|
-
id: plugin.id,
|
|
22047
|
-
extensionIds: plugin.extensions.map((e) => e.id)
|
|
22048
|
-
});
|
|
22049
|
-
}
|
|
22050
|
-
for (const p of plugins) {
|
|
22051
|
-
out.push({
|
|
22052
|
-
id: p.id,
|
|
22053
|
-
extensionIds: p.extensions?.map((e) => e.id) ?? []
|
|
22054
|
-
});
|
|
22055
|
-
}
|
|
22056
|
-
return out;
|
|
22057
|
-
}
|
|
22058
22197
|
function resolveToggleTarget(id, catalogue, ansi) {
|
|
22059
22198
|
return id.includes("/") ? resolveQualifiedToggle(id, catalogue, ansi) : resolveBareToggle(id, catalogue);
|
|
22060
22199
|
}
|
|
22061
22200
|
function resolveQualifiedToggle(id, catalogue, ansi) {
|
|
22062
|
-
const
|
|
22063
|
-
|
|
22064
|
-
if (!pluginId || !extId || rest.length > 0) {
|
|
22065
|
-
return {
|
|
22066
|
-
error: tx(PLUGINS_TEXTS.qualifiedIdUnknownPlugin, {
|
|
22067
|
-
glyph: errGlyph,
|
|
22068
|
-
pluginId: sanitizeForTerminal(id),
|
|
22069
|
-
hint: ansi.dim(PLUGINS_TEXTS.qualifiedIdUnknownPluginHint)
|
|
22070
|
-
})
|
|
22071
|
-
};
|
|
22072
|
-
}
|
|
22073
|
-
const plugin = catalogue.find((b) => b.id === pluginId);
|
|
22074
|
-
if (!plugin) {
|
|
22075
|
-
return {
|
|
22076
|
-
error: tx(PLUGINS_TEXTS.qualifiedIdUnknownPlugin, {
|
|
22077
|
-
glyph: errGlyph,
|
|
22078
|
-
pluginId: sanitizeForTerminal(pluginId),
|
|
22079
|
-
hint: ansi.dim(PLUGINS_TEXTS.qualifiedIdUnknownPluginHint)
|
|
22080
|
-
})
|
|
22081
|
-
};
|
|
22082
|
-
}
|
|
22083
|
-
if (!plugin.extensionIds.includes(extId)) {
|
|
22084
|
-
return {
|
|
22085
|
-
error: tx(PLUGINS_TEXTS.qualifiedIdNotFound, {
|
|
22086
|
-
glyph: errGlyph,
|
|
22087
|
-
id: sanitizeForTerminal(id),
|
|
22088
|
-
pluginId: sanitizeForTerminal(pluginId),
|
|
22089
|
-
extId: sanitizeForTerminal(extId),
|
|
22090
|
-
hint: ansi.dim(PLUGINS_TEXTS.qualifiedIdNotFoundHint)
|
|
22091
|
-
})
|
|
22092
|
-
};
|
|
22093
|
-
}
|
|
22201
|
+
const parsed = parseQualifiedExtensionId(id, catalogue);
|
|
22202
|
+
if (!parsed.ok) return { error: renderQualifiedIdError(parsed, id, ansi) };
|
|
22094
22203
|
return {
|
|
22095
22204
|
origin: "qualified",
|
|
22096
|
-
keys: [qualifiedExtensionId(pluginId, extId)]
|
|
22205
|
+
keys: [qualifiedExtensionId(parsed.pluginId, parsed.extId)]
|
|
22097
22206
|
};
|
|
22098
22207
|
}
|
|
22099
22208
|
function resolveBareToggle(id, catalogue) {
|
|
@@ -22473,7 +22582,7 @@ Generated by \`sm plugins create ${kind} ${pluginId}\`. Edit \`${mainFileRel}\`
|
|
|
22473
22582
|
|
|
22474
22583
|
## Verbs
|
|
22475
22584
|
|
|
22476
|
-
- \`sm plugins
|
|
22585
|
+
- \`sm plugins list ${pluginId}\`: manifest + extensions + load status
|
|
22477
22586
|
- \`sm plugins doctor\`: full plugin diagnostic
|
|
22478
22587
|
- \`sm scan\`: re-emit contributions / re-run analysis
|
|
22479
22588
|
|
|
@@ -25925,7 +26034,7 @@ function buildBuiltInItems(resolveEnabled) {
|
|
|
25925
26034
|
id: ext.id,
|
|
25926
26035
|
kind: ext.kind,
|
|
25927
26036
|
version: ext.version,
|
|
25928
|
-
enabled: resolveEnabled(qualified),
|
|
26037
|
+
enabled: resolveEnabled(qualified, installedDefaultEnabled(ext.stability)),
|
|
25929
26038
|
...ext.description ? { description: ext.description } : {},
|
|
25930
26039
|
...ext.stability ? { stability: ext.stability } : {},
|
|
25931
26040
|
...extLocked ? { locked: true } : {}
|
|
@@ -25981,7 +26090,7 @@ function projectExtensionRows(plugin, resolveEnabled, pluginLocked) {
|
|
|
25981
26090
|
id: ext.id,
|
|
25982
26091
|
kind: ext.kind,
|
|
25983
26092
|
version: ext.version,
|
|
25984
|
-
enabled: resolveEnabled(qualified),
|
|
26093
|
+
enabled: resolveEnabled(qualified, installedDefaultEnabled(ext.stability)),
|
|
25985
26094
|
...description ? { description } : {},
|
|
25986
26095
|
...ext.stability ? { stability: ext.stability } : {},
|
|
25987
26096
|
...extLocked ? { locked: true } : {}
|
|
@@ -30469,4 +30578,4 @@ function resolveBareDefault() {
|
|
|
30469
30578
|
process.exit(ExitCode.Error);
|
|
30470
30579
|
}
|
|
30471
30580
|
//# sourceMappingURL=cli.js.map
|
|
30472
|
-
//# debugId=
|
|
30581
|
+
//# debugId=e21852cd-d92e-5bdf-abc7-02fffaa89502
|