@skill-map/cli 0.53.6 → 0.54.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.js +429 -237
- package/dist/index.js +5 -5
- package/dist/kernel/index.d.ts +30 -3
- package/dist/kernel/index.js +5 -5
- package/dist/migrations/001_initial.sql +1 -1
- package/dist/ui/{chunk-7OJPO3XD.js → chunk-BUNPMGDX.js} +16 -15
- package/dist/ui/{chunk-NBXEOYS4.js → chunk-CXTU4HQV.js} +1 -1
- package/dist/ui/chunk-DSNBKMYU.js +2 -0
- package/dist/ui/chunk-MVRQGDZJ.js +123 -0
- package/dist/ui/index.html +2 -2
- package/dist/ui/{main-O4DGYJ62.js → main-HP3MOLI2.js} +3 -3
- package/dist/ui/{styles-L6FZYH7X.css → styles-4SNVM34O.css} +1 -1
- package/migrations/001_initial.sql +1 -1
- package/package.json +2 -2
- package/dist/ui/chunk-HWQTV6ZL.js +0 -2
- package/dist/ui/chunk-PRP3JSUU.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]="3118bb11-aad2-50b2-b70d-ed15c2f72a97")}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.54.0",
|
|
250
250
|
description: "skill-map reference implementation \u2014 kernel + CLI + adapters.",
|
|
251
251
|
license: "MIT",
|
|
252
252
|
type: "module",
|
|
@@ -796,6 +796,16 @@ function stripCodeBlocks(input) {
|
|
|
796
796
|
const fenceless = stripFences(input);
|
|
797
797
|
return stripInline(fenceless);
|
|
798
798
|
}
|
|
799
|
+
function extractCodeRegions(input) {
|
|
800
|
+
if (!input) return input;
|
|
801
|
+
const stripped = stripCodeBlocks(input);
|
|
802
|
+
let out = "";
|
|
803
|
+
for (let i = 0; i < input.length; i++) {
|
|
804
|
+
const ch = input[i];
|
|
805
|
+
out += ch === stripped[i] ? ch === "\n" ? "\n" : " " : ch;
|
|
806
|
+
}
|
|
807
|
+
return out;
|
|
808
|
+
}
|
|
799
809
|
function stripFences(input) {
|
|
800
810
|
const out = [];
|
|
801
811
|
const lines = input.split("\n");
|
|
@@ -1005,6 +1015,44 @@ var slashCommandExtractor = {
|
|
|
1005
1015
|
}
|
|
1006
1016
|
};
|
|
1007
1017
|
|
|
1018
|
+
// plugins/claude/extractors/tools-counter/index.ts
|
|
1019
|
+
var ID3 = "tools-counter";
|
|
1020
|
+
var count = {
|
|
1021
|
+
slot: "card.footer.left",
|
|
1022
|
+
icon: "pi-wrench",
|
|
1023
|
+
label: "tools",
|
|
1024
|
+
emitWhenEmpty: false,
|
|
1025
|
+
priority: 40
|
|
1026
|
+
};
|
|
1027
|
+
var TOOLTIP_MAX = 255;
|
|
1028
|
+
var toolsCounterExtractor = {
|
|
1029
|
+
id: ID3,
|
|
1030
|
+
pluginId: CLAUDE_PLUGIN_ID,
|
|
1031
|
+
kind: "extractor",
|
|
1032
|
+
description: "Counts the tools an agent declares in its frontmatter and shows the count on the agent card.",
|
|
1033
|
+
scope: "frontmatter",
|
|
1034
|
+
precondition: { kind: ["claude/agent"] },
|
|
1035
|
+
ui: { count },
|
|
1036
|
+
extract(ctx) {
|
|
1037
|
+
const raw = ctx.frontmatter["tools"];
|
|
1038
|
+
if (!Array.isArray(raw)) return;
|
|
1039
|
+
const names = [];
|
|
1040
|
+
for (const t of raw) {
|
|
1041
|
+
if (typeof t === "string" && t.length > 0) names.push(t);
|
|
1042
|
+
}
|
|
1043
|
+
if (names.length === 0) return;
|
|
1044
|
+
ctx.emitContribution(count, {
|
|
1045
|
+
value: names.length,
|
|
1046
|
+
tooltip: buildTooltip(names)
|
|
1047
|
+
});
|
|
1048
|
+
}
|
|
1049
|
+
};
|
|
1050
|
+
function buildTooltip(names) {
|
|
1051
|
+
const joined = names.join(" \xB7 ");
|
|
1052
|
+
if (joined.length <= TOOLTIP_MAX) return joined;
|
|
1053
|
+
return `${joined.slice(0, TOOLTIP_MAX - 1)}\u2026`;
|
|
1054
|
+
}
|
|
1055
|
+
|
|
1008
1056
|
// plugins/antigravity/providers/antigravity/index.ts
|
|
1009
1057
|
var antigravityProvider = {
|
|
1010
1058
|
id: "antigravity",
|
|
@@ -1391,9 +1439,9 @@ var coreMarkdownProvider = {
|
|
|
1391
1439
|
};
|
|
1392
1440
|
|
|
1393
1441
|
// plugins/core/extractors/annotations/index.ts
|
|
1394
|
-
var
|
|
1442
|
+
var ID4 = "annotations";
|
|
1395
1443
|
var annotationsExtractor = {
|
|
1396
|
-
id:
|
|
1444
|
+
id: ID4,
|
|
1397
1445
|
pluginId: CORE_PLUGIN_ID,
|
|
1398
1446
|
kind: "extractor",
|
|
1399
1447
|
description: "Turns the `supersedes` and `supersededBy` entries from a node's `.sm` sidecar into arrows between nodes in the graph.",
|
|
@@ -1412,7 +1460,7 @@ var annotationsExtractor = {
|
|
|
1412
1460
|
raw: target,
|
|
1413
1461
|
candidates: [
|
|
1414
1462
|
{
|
|
1415
|
-
extractorId:
|
|
1463
|
+
extractorId: ID4,
|
|
1416
1464
|
kind: "supersedes",
|
|
1417
1465
|
target,
|
|
1418
1466
|
confidence: 1,
|
|
@@ -1449,9 +1497,67 @@ function stringArray(value) {
|
|
|
1449
1497
|
return value.filter((v) => typeof v === "string" && v.length > 0);
|
|
1450
1498
|
}
|
|
1451
1499
|
|
|
1500
|
+
// plugins/core/extractors/backtick-path/index.ts
|
|
1501
|
+
import { posix as pathPosix2 } from "path";
|
|
1502
|
+
var ID5 = "backtick-path";
|
|
1503
|
+
var PATH_RE = /(?<![\w/:.-])(?:\.{1,2}\/)?[\w.-]+(?:\/[\w.-]+)+\.md\b(?![\w/])/g;
|
|
1504
|
+
var backtickPathExtractor = {
|
|
1505
|
+
id: ID5,
|
|
1506
|
+
pluginId: CORE_PLUGIN_ID,
|
|
1507
|
+
kind: "extractor",
|
|
1508
|
+
description: "Turns relative .md paths written inside code spans and fenced blocks into arrows between nodes in the graph.",
|
|
1509
|
+
scope: "body",
|
|
1510
|
+
extract(ctx) {
|
|
1511
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1512
|
+
const body = extractCodeRegions(ctx.body);
|
|
1513
|
+
const lineStarts = computeLineStarts(body);
|
|
1514
|
+
const sourceDir = pathPosix2.dirname(ctx.node.path);
|
|
1515
|
+
for (const match of body.matchAll(PATH_RE)) {
|
|
1516
|
+
const original = match[0];
|
|
1517
|
+
const resolved = resolveTarget(sourceDir, original);
|
|
1518
|
+
if (resolved === null) continue;
|
|
1519
|
+
if (seen.has(resolved)) continue;
|
|
1520
|
+
seen.add(resolved);
|
|
1521
|
+
const offset = match.index ?? 0;
|
|
1522
|
+
const line = lineFor(lineStarts, offset);
|
|
1523
|
+
ctx.emitSignal({
|
|
1524
|
+
source: ctx.node.path,
|
|
1525
|
+
scope: "body",
|
|
1526
|
+
range: { start: offset, end: offset + original.length, line },
|
|
1527
|
+
raw: original,
|
|
1528
|
+
candidates: [
|
|
1529
|
+
{
|
|
1530
|
+
extractorId: ID5,
|
|
1531
|
+
kind: "points",
|
|
1532
|
+
target: resolved,
|
|
1533
|
+
// 0.85: a strong file signal with one degree of inference,
|
|
1534
|
+
// the author wrote a path inside a code region rather than
|
|
1535
|
+
// an explicit `[text](path)` link. Whether the path resolves
|
|
1536
|
+
// to a real node is a separate concern (`core/reference-broken`
|
|
1537
|
+
// flags unresolved targets), not a confidence question.
|
|
1538
|
+
confidence: 0.85,
|
|
1539
|
+
rationale: "relative .md path inside a code region",
|
|
1540
|
+
trigger: {
|
|
1541
|
+
originalTrigger: original,
|
|
1542
|
+
normalizedTrigger: resolved
|
|
1543
|
+
}
|
|
1544
|
+
}
|
|
1545
|
+
]
|
|
1546
|
+
});
|
|
1547
|
+
}
|
|
1548
|
+
}
|
|
1549
|
+
};
|
|
1550
|
+
function resolveTarget(sourceDir, raw) {
|
|
1551
|
+
const trimmed = raw.trim();
|
|
1552
|
+
if (trimmed.length === 0) return null;
|
|
1553
|
+
if (trimmed.startsWith("/")) return null;
|
|
1554
|
+
const joined = sourceDir === "." ? trimmed : `${sourceDir}/${trimmed}`;
|
|
1555
|
+
return pathPosix2.normalize(joined);
|
|
1556
|
+
}
|
|
1557
|
+
|
|
1452
1558
|
// plugins/core/extractors/external-url-counter/index.ts
|
|
1453
|
-
var
|
|
1454
|
-
var
|
|
1559
|
+
var ID6 = "external-url-counter";
|
|
1560
|
+
var count2 = {
|
|
1455
1561
|
slot: "card.footer.left",
|
|
1456
1562
|
icon: "pi-link",
|
|
1457
1563
|
label: "urls",
|
|
@@ -1461,7 +1567,7 @@ var count = {
|
|
|
1461
1567
|
var URL_RE = /https?:\/\/[^\s<>"'`)\]]+/g;
|
|
1462
1568
|
var TRAILING_PUNCT = /[.,;:!?]+$/;
|
|
1463
1569
|
var externalUrlCounterExtractor = {
|
|
1464
|
-
id:
|
|
1570
|
+
id: ID6,
|
|
1465
1571
|
pluginId: CORE_PLUGIN_ID,
|
|
1466
1572
|
kind: "extractor",
|
|
1467
1573
|
description: "Counts the distinct external URLs in a node's body and shows the count on the card.",
|
|
@@ -1482,7 +1588,7 @@ var externalUrlCounterExtractor = {
|
|
|
1482
1588
|
* inherited from the footer `.sm-gnode__stat` styles cloned by
|
|
1483
1589
|
* the `NodeCounter` renderer.
|
|
1484
1590
|
*/
|
|
1485
|
-
ui: { count },
|
|
1591
|
+
ui: { count: count2 },
|
|
1486
1592
|
extract(ctx) {
|
|
1487
1593
|
const seen = /* @__PURE__ */ new Set();
|
|
1488
1594
|
const body = stripCodeBlocks(ctx.body);
|
|
@@ -1503,7 +1609,7 @@ var externalUrlCounterExtractor = {
|
|
|
1503
1609
|
raw: original,
|
|
1504
1610
|
candidates: [
|
|
1505
1611
|
{
|
|
1506
|
-
extractorId:
|
|
1612
|
+
extractorId: ID6,
|
|
1507
1613
|
kind: "references",
|
|
1508
1614
|
target: normalized,
|
|
1509
1615
|
confidence: 0.3,
|
|
@@ -1517,7 +1623,7 @@ var externalUrlCounterExtractor = {
|
|
|
1517
1623
|
});
|
|
1518
1624
|
}
|
|
1519
1625
|
if (seen.size > 0) {
|
|
1520
|
-
ctx.emitContribution(
|
|
1626
|
+
ctx.emitContribution(count2, { value: seen.size });
|
|
1521
1627
|
}
|
|
1522
1628
|
}
|
|
1523
1629
|
};
|
|
@@ -1536,12 +1642,12 @@ function normalizeUrl(raw) {
|
|
|
1536
1642
|
}
|
|
1537
1643
|
|
|
1538
1644
|
// plugins/core/extractors/markdown-link/index.ts
|
|
1539
|
-
import { posix as
|
|
1540
|
-
var
|
|
1645
|
+
import { posix as pathPosix3 } from "path";
|
|
1646
|
+
var ID7 = "markdown-link";
|
|
1541
1647
|
var LINK_RE = /(?<!!)\[([^\]]*)\]\(([^)\s]+)(?:\s+"[^"]*")?\)/g;
|
|
1542
1648
|
var URL_SCHEME_RE = /^[a-z][a-z0-9+.-]*:/i;
|
|
1543
1649
|
var markdownLinkExtractor = {
|
|
1544
|
-
id:
|
|
1650
|
+
id: ID7,
|
|
1545
1651
|
pluginId: CORE_PLUGIN_ID,
|
|
1546
1652
|
kind: "extractor",
|
|
1547
1653
|
description: "Turns markdown links (`[text](path)`) in a node's body into arrows between nodes in the graph.",
|
|
@@ -1550,10 +1656,10 @@ var markdownLinkExtractor = {
|
|
|
1550
1656
|
const seen = /* @__PURE__ */ new Set();
|
|
1551
1657
|
const body = stripCodeBlocks(ctx.body);
|
|
1552
1658
|
const lineStarts = computeLineStarts(body);
|
|
1553
|
-
const sourceDir =
|
|
1659
|
+
const sourceDir = pathPosix3.dirname(ctx.node.path);
|
|
1554
1660
|
for (const match of body.matchAll(LINK_RE)) {
|
|
1555
1661
|
const original = match[2];
|
|
1556
|
-
const resolved =
|
|
1662
|
+
const resolved = resolveTarget2(sourceDir, original);
|
|
1557
1663
|
if (resolved === null) continue;
|
|
1558
1664
|
if (seen.has(resolved)) continue;
|
|
1559
1665
|
seen.add(resolved);
|
|
@@ -1566,7 +1672,7 @@ var markdownLinkExtractor = {
|
|
|
1566
1672
|
raw: match[0],
|
|
1567
1673
|
candidates: [
|
|
1568
1674
|
{
|
|
1569
|
-
extractorId:
|
|
1675
|
+
extractorId: ID7,
|
|
1570
1676
|
kind: "references",
|
|
1571
1677
|
target: resolved,
|
|
1572
1678
|
// 1.0: the `[text](path)` syntax is unambiguous. Markdown
|
|
@@ -1587,7 +1693,7 @@ var markdownLinkExtractor = {
|
|
|
1587
1693
|
}
|
|
1588
1694
|
}
|
|
1589
1695
|
};
|
|
1590
|
-
function
|
|
1696
|
+
function resolveTarget2(sourceDir, raw) {
|
|
1591
1697
|
const noFragment = raw.split("#", 1)[0];
|
|
1592
1698
|
const noQuery = noFragment.split("?", 1)[0];
|
|
1593
1699
|
const trimmed = noQuery.trim();
|
|
@@ -1595,17 +1701,21 @@ function resolveTarget(sourceDir, raw) {
|
|
|
1595
1701
|
if (URL_SCHEME_RE.test(trimmed)) return null;
|
|
1596
1702
|
if (trimmed.startsWith("/")) return null;
|
|
1597
1703
|
const joined = sourceDir === "." ? trimmed : `${sourceDir}/${trimmed}`;
|
|
1598
|
-
return
|
|
1704
|
+
return pathPosix3.normalize(joined);
|
|
1599
1705
|
}
|
|
1600
1706
|
|
|
1601
1707
|
// plugins/core/extractors/mcp-tools/index.ts
|
|
1602
|
-
var
|
|
1708
|
+
var ID8 = "mcp-tools";
|
|
1603
1709
|
var MCP_PATTERN = /^mcp__([a-z0-9][a-z0-9_-]*)__[a-z0-9_-]+$/i;
|
|
1604
1710
|
var mcpToolsExtractor = {
|
|
1605
|
-
id:
|
|
1711
|
+
id: ID8,
|
|
1606
1712
|
pluginId: CORE_PLUGIN_ID,
|
|
1607
1713
|
kind: "extractor",
|
|
1608
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.",
|
|
1715
|
+
// Claude-convention pattern only; per-vendor flavours and the
|
|
1716
|
+
// config-side MCP declaration (Phase 5b) are still pending, so the
|
|
1717
|
+
// extractor ships flagged as experimental in list / show / Settings.
|
|
1718
|
+
stability: "experimental",
|
|
1609
1719
|
scope: "frontmatter",
|
|
1610
1720
|
extract(ctx) {
|
|
1611
1721
|
const raw = ctx.frontmatter["tools"];
|
|
@@ -1629,7 +1739,7 @@ var mcpToolsExtractor = {
|
|
|
1629
1739
|
raw: `mcp__${server}__*`,
|
|
1630
1740
|
candidates: [
|
|
1631
1741
|
{
|
|
1632
|
-
extractorId:
|
|
1742
|
+
extractorId: ID8,
|
|
1633
1743
|
kind: "references",
|
|
1634
1744
|
target: mcpPath,
|
|
1635
1745
|
confidence: 0.85,
|
|
@@ -1659,44 +1769,6 @@ function collectMcpServers(tools) {
|
|
|
1659
1769
|
return out;
|
|
1660
1770
|
}
|
|
1661
1771
|
|
|
1662
|
-
// plugins/core/extractors/tools-counter/index.ts
|
|
1663
|
-
var ID7 = "tools-counter";
|
|
1664
|
-
var count2 = {
|
|
1665
|
-
slot: "card.footer.left",
|
|
1666
|
-
icon: "pi-wrench",
|
|
1667
|
-
label: "tools",
|
|
1668
|
-
emitWhenEmpty: false,
|
|
1669
|
-
priority: 40
|
|
1670
|
-
};
|
|
1671
|
-
var TOOLTIP_MAX = 255;
|
|
1672
|
-
var toolsCounterExtractor = {
|
|
1673
|
-
id: ID7,
|
|
1674
|
-
pluginId: CORE_PLUGIN_ID,
|
|
1675
|
-
kind: "extractor",
|
|
1676
|
-
description: "Counts the tools an agent declares in its frontmatter and shows the count on the agent card.",
|
|
1677
|
-
scope: "frontmatter",
|
|
1678
|
-
precondition: { kind: ["claude/agent"] },
|
|
1679
|
-
ui: { count: count2 },
|
|
1680
|
-
extract(ctx) {
|
|
1681
|
-
const raw = ctx.frontmatter["tools"];
|
|
1682
|
-
if (!Array.isArray(raw)) return;
|
|
1683
|
-
const names = [];
|
|
1684
|
-
for (const t of raw) {
|
|
1685
|
-
if (typeof t === "string" && t.length > 0) names.push(t);
|
|
1686
|
-
}
|
|
1687
|
-
if (names.length === 0) return;
|
|
1688
|
-
ctx.emitContribution(count2, {
|
|
1689
|
-
value: names.length,
|
|
1690
|
-
tooltip: buildTooltip(names)
|
|
1691
|
-
});
|
|
1692
|
-
}
|
|
1693
|
-
};
|
|
1694
|
-
function buildTooltip(names) {
|
|
1695
|
-
const joined = names.join(" \xB7 ");
|
|
1696
|
-
if (joined.length <= TOOLTIP_MAX) return joined;
|
|
1697
|
-
return `${joined.slice(0, TOOLTIP_MAX - 1)}\u2026`;
|
|
1698
|
-
}
|
|
1699
|
-
|
|
1700
1772
|
// plugins/core/analyzers/annotation-field-unknown/index.ts
|
|
1701
1773
|
import { readFileSync } from "fs";
|
|
1702
1774
|
import { dirname, resolve } from "path";
|
|
@@ -1712,12 +1784,14 @@ function applyAjvFormats(ajv) {
|
|
|
1712
1784
|
|
|
1713
1785
|
// plugins/core/analyzers/annotation-field-unknown/text.ts
|
|
1714
1786
|
var ANNOTATION_FIELD_UNKNOWN_TEXTS = {
|
|
1787
|
+
// Compact finding grammar: the affected node is the finding's own
|
|
1788
|
+
// node, so its path never appears in the message.
|
|
1715
1789
|
/** Key inside `annotations:` is not in the curated catalog. */
|
|
1716
|
-
unknownAnnotationKey: "
|
|
1790
|
+
unknownAnnotationKey: "Unknown sidecar key '{{key}}'; not in the annotations catalog.",
|
|
1717
1791
|
/** Top-level key is neither reserved, nor a registered plugin namespace, nor a registered root key. */
|
|
1718
|
-
unknownRootKey: "
|
|
1792
|
+
unknownRootKey: "Unknown sidecar top-level key '{{key}}'; not a reserved block, a plugin namespace, or a root contribution.",
|
|
1719
1793
|
/** Value under a registered plugin namespace fails the contributed schema. */
|
|
1720
|
-
pluginNamespaceInvalid: "
|
|
1794
|
+
pluginNamespaceInvalid: "Sidecar block '{{pluginId}}.{{key}}' fails the schema from plugin '{{pluginId}}': {{errors}}.",
|
|
1721
1795
|
// Tooltips for the per-node view-contribution badges. Singular vs
|
|
1722
1796
|
// plural keeps the count grammar correct without a sub-template.
|
|
1723
1797
|
alertTooltipSingle: "This node has 1 unknown field in its sidecar. Open the inspector for details.",
|
|
@@ -1725,10 +1799,10 @@ var ANNOTATION_FIELD_UNKNOWN_TEXTS = {
|
|
|
1725
1799
|
};
|
|
1726
1800
|
|
|
1727
1801
|
// plugins/core/analyzers/annotation-field-unknown/index.ts
|
|
1728
|
-
var
|
|
1802
|
+
var ID9 = "annotation-field-unknown";
|
|
1729
1803
|
var RESERVED_ROOT_BLOCKS = /* @__PURE__ */ new Set(["identity", "annotations", "settings", "audit"]);
|
|
1730
1804
|
var annotationFieldUnknownAnalyzer = {
|
|
1731
|
-
id:
|
|
1805
|
+
id: ID9,
|
|
1732
1806
|
pluginId: CORE_PLUGIN_ID,
|
|
1733
1807
|
kind: "analyzer",
|
|
1734
1808
|
description: "Flags typos or unrecognized keys in sidecars (`.sm`).",
|
|
@@ -1767,7 +1841,7 @@ var annotationFieldUnknownAnalyzer = {
|
|
|
1767
1841
|
for (const key of Object.keys(annotations)) {
|
|
1768
1842
|
if (!knownAnnotationKeys.has(key)) {
|
|
1769
1843
|
issues.push({
|
|
1770
|
-
analyzerId:
|
|
1844
|
+
analyzerId: ID9,
|
|
1771
1845
|
severity: "warn",
|
|
1772
1846
|
nodeIds: [node.path],
|
|
1773
1847
|
message: tx(ANNOTATION_FIELD_UNKNOWN_TEXTS.unknownAnnotationKey, {
|
|
@@ -1794,7 +1868,7 @@ var annotationFieldUnknownAnalyzer = {
|
|
|
1794
1868
|
if (validator(value)) continue;
|
|
1795
1869
|
const errors = (validator.errors ?? []).map((e) => `${e.instancePath || "(root)"} ${e.message ?? e.keyword}`).join("; ");
|
|
1796
1870
|
issues.push({
|
|
1797
|
-
analyzerId:
|
|
1871
|
+
analyzerId: ID9,
|
|
1798
1872
|
severity: "warn",
|
|
1799
1873
|
nodeIds: [node.path],
|
|
1800
1874
|
message: tx(ANNOTATION_FIELD_UNKNOWN_TEXTS.pluginNamespaceInvalid, {
|
|
@@ -1810,7 +1884,7 @@ var annotationFieldUnknownAnalyzer = {
|
|
|
1810
1884
|
continue;
|
|
1811
1885
|
}
|
|
1812
1886
|
issues.push({
|
|
1813
|
-
analyzerId:
|
|
1887
|
+
analyzerId: ID9,
|
|
1814
1888
|
severity: "warn",
|
|
1815
1889
|
nodeIds: [node.path],
|
|
1816
1890
|
message: tx(ANNOTATION_FIELD_UNKNOWN_TEXTS.unknownRootKey, {
|
|
@@ -1871,14 +1945,19 @@ function collectPluginIds(contributions) {
|
|
|
1871
1945
|
|
|
1872
1946
|
// plugins/core/analyzers/annotation-orphan/text.ts
|
|
1873
1947
|
var ANNOTATION_ORPHAN_TEXTS = {
|
|
1874
|
-
/**
|
|
1875
|
-
|
|
1948
|
+
/**
|
|
1949
|
+
* Compact finding grammar: line 1 = the orphan sidecar file, line 2
|
|
1950
|
+
* = the diagnosis. The expected markdown path IS the finding's
|
|
1951
|
+
* `nodeIds[0]` (the issue files under the path the sidecar points
|
|
1952
|
+
* at), so it never appears in the message.
|
|
1953
|
+
*/
|
|
1954
|
+
message: "{{sidecarPath}}:\nOrphan sidecar; no matching markdown node."
|
|
1876
1955
|
};
|
|
1877
1956
|
|
|
1878
1957
|
// plugins/core/analyzers/annotation-orphan/index.ts
|
|
1879
|
-
var
|
|
1958
|
+
var ID10 = "annotation-orphan";
|
|
1880
1959
|
var annotationOrphanAnalyzer = {
|
|
1881
|
-
id:
|
|
1960
|
+
id: ID10,
|
|
1882
1961
|
pluginId: CORE_PLUGIN_ID,
|
|
1883
1962
|
kind: "analyzer",
|
|
1884
1963
|
description: "Flags sidecars (`.sm`) whose `.md` file no longer exists.",
|
|
@@ -1890,7 +1969,7 @@ var annotationOrphanAnalyzer = {
|
|
|
1890
1969
|
for (const orphan of orphans) {
|
|
1891
1970
|
const expectedMdRelative = orphan.relativePath.endsWith(".sm") ? `${orphan.relativePath.slice(0, -".sm".length)}.md` : `${orphan.relativePath}.md`;
|
|
1892
1971
|
issues.push({
|
|
1893
|
-
analyzerId:
|
|
1972
|
+
analyzerId: ID10,
|
|
1894
1973
|
severity: "warn",
|
|
1895
1974
|
nodeIds: [expectedMdRelative],
|
|
1896
1975
|
message: tx(ANNOTATION_ORPHAN_TEXTS.message, {
|
|
@@ -1909,12 +1988,14 @@ var annotationOrphanAnalyzer = {
|
|
|
1909
1988
|
|
|
1910
1989
|
// plugins/core/analyzers/annotation-stale/text.ts
|
|
1911
1990
|
var ANNOTATION_STALE_TEXTS = {
|
|
1991
|
+
// Compact finding grammar: the affected node is the finding's own
|
|
1992
|
+
// node, so its path never appears in the message.
|
|
1912
1993
|
/** body changed since last bump */
|
|
1913
|
-
bodyDrift: "
|
|
1994
|
+
bodyDrift: "Sidecar `.sm` is stale: body changed since last bump.",
|
|
1914
1995
|
/** frontmatter changed since last bump */
|
|
1915
|
-
frontmatterDrift: "
|
|
1996
|
+
frontmatterDrift: "Sidecar `.sm` is stale: frontmatter changed since last bump.",
|
|
1916
1997
|
/** both body and frontmatter changed */
|
|
1917
|
-
bothDrift: "
|
|
1998
|
+
bothDrift: "Sidecar `.sm` is stale: body and frontmatter changed since last bump.",
|
|
1918
1999
|
// Tooltips for the `card.footer.right` clock chip emitted alongside
|
|
1919
2000
|
// the issue. Lists only the drifted face(s), in-sync faces are
|
|
1920
2001
|
// omitted so the operator immediately sees what's modified without
|
|
@@ -1931,7 +2012,7 @@ var ANNOTATION_STALE_TEXTS = {
|
|
|
1931
2012
|
};
|
|
1932
2013
|
|
|
1933
2014
|
// plugins/core/analyzers/annotation-stale/index.ts
|
|
1934
|
-
var
|
|
2015
|
+
var ID11 = "annotation-stale";
|
|
1935
2016
|
var staleIcon = {
|
|
1936
2017
|
slot: "card.footer.right",
|
|
1937
2018
|
icon: "pi-clock",
|
|
@@ -1948,7 +2029,7 @@ var bumpButton = {
|
|
|
1948
2029
|
priority: 10
|
|
1949
2030
|
};
|
|
1950
2031
|
var annotationStaleAnalyzer = {
|
|
1951
|
-
id:
|
|
2032
|
+
id: ID11,
|
|
1952
2033
|
pluginId: CORE_PLUGIN_ID,
|
|
1953
2034
|
kind: "analyzer",
|
|
1954
2035
|
description: "Marks sidecars (`.sm`) that are out of date with their `.md`.",
|
|
@@ -1966,7 +2047,7 @@ var annotationStaleAnalyzer = {
|
|
|
1966
2047
|
}
|
|
1967
2048
|
if (status === null) continue;
|
|
1968
2049
|
issues.push({
|
|
1969
|
-
analyzerId:
|
|
2050
|
+
analyzerId: ID11,
|
|
1970
2051
|
severity: "info",
|
|
1971
2052
|
nodeIds: [node.path],
|
|
1972
2053
|
message: messageFor(status, node.path),
|
|
@@ -2020,9 +2101,9 @@ function tooltipFor(status) {
|
|
|
2020
2101
|
}
|
|
2021
2102
|
|
|
2022
2103
|
// plugins/core/analyzers/contribution-orphan/index.ts
|
|
2023
|
-
var
|
|
2104
|
+
var ID12 = "contribution-orphan";
|
|
2024
2105
|
var contributionOrphanAnalyzer = {
|
|
2025
|
-
id:
|
|
2106
|
+
id: ID12,
|
|
2026
2107
|
pluginId: CORE_PLUGIN_ID,
|
|
2027
2108
|
kind: "analyzer",
|
|
2028
2109
|
description: "Warns about plugin data referencing nodes renamed or deleted in the latest scan.",
|
|
@@ -2041,7 +2122,7 @@ var ISSUE_COUNTER_TEXTS = {
|
|
|
2041
2122
|
};
|
|
2042
2123
|
|
|
2043
2124
|
// plugins/core/analyzers/issue-counter/index.ts
|
|
2044
|
-
var
|
|
2125
|
+
var ID13 = "issue-counter";
|
|
2045
2126
|
var warnCount = {
|
|
2046
2127
|
slot: "card.footer.right",
|
|
2047
2128
|
icon: "pi-exclamation-triangle",
|
|
@@ -2077,7 +2158,7 @@ function emitTierChips(ctx, ref, severity, counts, singleTooltip, manyTooltip) {
|
|
|
2077
2158
|
}
|
|
2078
2159
|
}
|
|
2079
2160
|
var issueCounterAnalyzer = {
|
|
2080
|
-
id:
|
|
2161
|
+
id: ID13,
|
|
2081
2162
|
pluginId: CORE_PLUGIN_ID,
|
|
2082
2163
|
kind: "analyzer",
|
|
2083
2164
|
description: "Emits one aggregate severity chip per node (error + warn counts) from the live issue accumulator.",
|
|
@@ -2112,15 +2193,16 @@ var issueCounterAnalyzer = {
|
|
|
2112
2193
|
var JOB_FILE_ORPHAN_TEXTS = {
|
|
2113
2194
|
/**
|
|
2114
2195
|
* `<path>.md` lives under `.skill-map/jobs/` but no `state_jobs.filePath`
|
|
2115
|
-
* row references it.
|
|
2196
|
+
* row references it. Compact finding grammar: the file IS the
|
|
2197
|
+
* finding's own node, so its path never appears in the message.
|
|
2116
2198
|
*/
|
|
2117
|
-
message: "Orphan job file
|
|
2199
|
+
message: "Orphan job file; not referenced by any job. Run `sm job prune --orphan-files` to remove it."
|
|
2118
2200
|
};
|
|
2119
2201
|
|
|
2120
2202
|
// plugins/core/analyzers/job-file-orphan/index.ts
|
|
2121
|
-
var
|
|
2203
|
+
var ID14 = "job-file-orphan";
|
|
2122
2204
|
var jobFileOrphanAnalyzer = {
|
|
2123
|
-
id:
|
|
2205
|
+
id: ID14,
|
|
2124
2206
|
pluginId: CORE_PLUGIN_ID,
|
|
2125
2207
|
kind: "analyzer",
|
|
2126
2208
|
description: "Flags leftover job result files (no live job references them). Clean up via `sm job prune --orphan-files`.",
|
|
@@ -2131,7 +2213,7 @@ var jobFileOrphanAnalyzer = {
|
|
|
2131
2213
|
const issues = [];
|
|
2132
2214
|
for (const filePath of orphans) {
|
|
2133
2215
|
issues.push({
|
|
2134
|
-
analyzerId:
|
|
2216
|
+
analyzerId: ID14,
|
|
2135
2217
|
severity: "warn",
|
|
2136
2218
|
nodeIds: [filePath],
|
|
2137
2219
|
message: tx(JOB_FILE_ORPHAN_TEXTS.message, { filePath }),
|
|
@@ -2144,14 +2226,19 @@ var jobFileOrphanAnalyzer = {
|
|
|
2144
2226
|
|
|
2145
2227
|
// plugins/core/analyzers/link-conflict/text.ts
|
|
2146
2228
|
var LINK_CONFLICT_TEXTS = {
|
|
2147
|
-
/**
|
|
2148
|
-
|
|
2229
|
+
/**
|
|
2230
|
+
* Compact finding grammar: line 1 = the disputed target, line 2 =
|
|
2231
|
+
* the short diagnosis. The source is the finding's own node, so it
|
|
2232
|
+
* never appears in the message.
|
|
2233
|
+
*/
|
|
2234
|
+
message: "{{target}}:\nDetectors disagree on link kind ({{kindList}})."
|
|
2149
2235
|
};
|
|
2150
2236
|
|
|
2151
2237
|
// plugins/core/analyzers/link-conflict/index.ts
|
|
2152
|
-
var
|
|
2238
|
+
var ID15 = "link-conflict";
|
|
2239
|
+
var NON_CONFLICTING_KINDS = /* @__PURE__ */ new Set(["points"]);
|
|
2153
2240
|
var linkConflictAnalyzer = {
|
|
2154
|
-
id:
|
|
2241
|
+
id: ID15,
|
|
2155
2242
|
pluginId: "core",
|
|
2156
2243
|
kind: "analyzer",
|
|
2157
2244
|
description: "Flags conflicting arrow meanings between extractors (e.g. `references` vs `invokes`).",
|
|
@@ -2163,6 +2250,7 @@ var linkConflictAnalyzer = {
|
|
|
2163
2250
|
evaluate(ctx) {
|
|
2164
2251
|
const groups = /* @__PURE__ */ new Map();
|
|
2165
2252
|
for (const link of ctx.links) {
|
|
2253
|
+
if (NON_CONFLICTING_KINDS.has(link.kind)) continue;
|
|
2166
2254
|
const key = `${link.source}\0${link.target}`;
|
|
2167
2255
|
const bucket = groups.get(key);
|
|
2168
2256
|
if (bucket) bucket.push(link);
|
|
@@ -2198,7 +2286,7 @@ var linkConflictAnalyzer = {
|
|
|
2198
2286
|
const [source, target] = key.split("\0");
|
|
2199
2287
|
const kindList = variants.map((v) => v.kind).join(" / ");
|
|
2200
2288
|
issues.push({
|
|
2201
|
-
analyzerId:
|
|
2289
|
+
analyzerId: ID15,
|
|
2202
2290
|
severity: "warn",
|
|
2203
2291
|
nodeIds: [source, target],
|
|
2204
2292
|
message: tx(LINK_CONFLICT_TEXTS.message, {
|
|
@@ -2265,7 +2353,7 @@ function resolveLinkTargetToPath(link, nameIndex) {
|
|
|
2265
2353
|
}
|
|
2266
2354
|
|
|
2267
2355
|
// plugins/core/analyzers/link-counter/index.ts
|
|
2268
|
-
var
|
|
2356
|
+
var ID16 = "link-counter";
|
|
2269
2357
|
var linksIn = {
|
|
2270
2358
|
slot: "card.footer.left",
|
|
2271
2359
|
icon: "pi-download",
|
|
@@ -2281,7 +2369,7 @@ var linksOut = {
|
|
|
2281
2369
|
priority: 20
|
|
2282
2370
|
};
|
|
2283
2371
|
var linkCounterAnalyzer = {
|
|
2284
|
-
id:
|
|
2372
|
+
id: ID16,
|
|
2285
2373
|
pluginId: CORE_PLUGIN_ID,
|
|
2286
2374
|
kind: "analyzer",
|
|
2287
2375
|
description: "Counts incoming and outgoing links per node.",
|
|
@@ -2328,6 +2416,27 @@ function formatBreakdown(byKind, direction) {
|
|
|
2328
2416
|
return [direction, ...lines].join("\n");
|
|
2329
2417
|
}
|
|
2330
2418
|
|
|
2419
|
+
// kernel/util/link-lines.ts
|
|
2420
|
+
function linkLines(link) {
|
|
2421
|
+
const lines = /* @__PURE__ */ new Set();
|
|
2422
|
+
for (const occ of link.occurrences ?? []) {
|
|
2423
|
+
const line = occ.location?.line;
|
|
2424
|
+
if (typeof line === "number") lines.add(line);
|
|
2425
|
+
}
|
|
2426
|
+
if (lines.size === 0) {
|
|
2427
|
+
const line = link.location?.line;
|
|
2428
|
+
if (typeof line === "number") lines.add(line);
|
|
2429
|
+
}
|
|
2430
|
+
return [...lines].sort((a, b) => a - b);
|
|
2431
|
+
}
|
|
2432
|
+
function linkWhere(link, texts) {
|
|
2433
|
+
const lines = linkLines(link);
|
|
2434
|
+
if (lines.length === 0) return "";
|
|
2435
|
+
return tx(lines.length === 1 ? texts.single : texts.plural, {
|
|
2436
|
+
lines: lines.join(", ")
|
|
2437
|
+
});
|
|
2438
|
+
}
|
|
2439
|
+
|
|
2331
2440
|
// plugins/core/analyzers/link-self-loop/text.ts
|
|
2332
2441
|
var LINK_SELF_LOOP_TEXTS = {
|
|
2333
2442
|
/**
|
|
@@ -2338,13 +2447,17 @@ var LINK_SELF_LOOP_TEXTS = {
|
|
|
2338
2447
|
* the operator's intent; UI consumers MAY hide it by default and
|
|
2339
2448
|
* surface a count.
|
|
2340
2449
|
*/
|
|
2341
|
-
message: "
|
|
2450
|
+
message: "`{{trigger}}`:\nSelf-reference ({{kind}}{{where}}); typically the file's own heading or label. Remove the token or ignore deliberately.",
|
|
2451
|
+
/** Location suffix inside the kind parens, one detection site. */
|
|
2452
|
+
whereSingle: ", line {{lines}}",
|
|
2453
|
+
/** Location suffix inside the kind parens, several detection sites. */
|
|
2454
|
+
wherePlural: ", lines {{lines}}"
|
|
2342
2455
|
};
|
|
2343
2456
|
|
|
2344
2457
|
// plugins/core/analyzers/link-self-loop/index.ts
|
|
2345
|
-
var
|
|
2458
|
+
var ID17 = "link-self-loop";
|
|
2346
2459
|
var linkSelfLoopAnalyzer = {
|
|
2347
|
-
id:
|
|
2460
|
+
id: ID17,
|
|
2348
2461
|
pluginId: CORE_PLUGIN_ID,
|
|
2349
2462
|
kind: "analyzer",
|
|
2350
2463
|
description: "Flags links whose source is also their own resolved target (e.g. a body heading like `# /deploy` inside the file that defines `/deploy`).",
|
|
@@ -2355,13 +2468,16 @@ var linkSelfLoopAnalyzer = {
|
|
|
2355
2468
|
for (const link of ctx.links) {
|
|
2356
2469
|
if (!isSelfLoop(link)) continue;
|
|
2357
2470
|
issues.push({
|
|
2358
|
-
analyzerId:
|
|
2471
|
+
analyzerId: ID17,
|
|
2359
2472
|
severity: "warn",
|
|
2360
2473
|
nodeIds: [link.source],
|
|
2361
2474
|
message: tx(LINK_SELF_LOOP_TEXTS.message, {
|
|
2362
|
-
source: link.source,
|
|
2363
2475
|
trigger: link.trigger?.originalTrigger ?? link.target,
|
|
2364
|
-
kind: link.kind
|
|
2476
|
+
kind: link.kind,
|
|
2477
|
+
where: linkWhere(link, {
|
|
2478
|
+
single: LINK_SELF_LOOP_TEXTS.whereSingle,
|
|
2479
|
+
plural: LINK_SELF_LOOP_TEXTS.wherePlural
|
|
2480
|
+
})
|
|
2365
2481
|
}),
|
|
2366
2482
|
data: {
|
|
2367
2483
|
target: link.target,
|
|
@@ -2384,7 +2500,7 @@ function isSelfLoop(link) {
|
|
|
2384
2500
|
}
|
|
2385
2501
|
|
|
2386
2502
|
// kernel/orchestrator/node-identifiers.ts
|
|
2387
|
-
import { posix as
|
|
2503
|
+
import { posix as pathPosix4 } from "path";
|
|
2388
2504
|
function deriveNodeIdentifiers(node, kindDescriptor) {
|
|
2389
2505
|
const sources = kindDescriptor?.identifiers;
|
|
2390
2506
|
if (!sources || sources.length === 0) return [];
|
|
@@ -2408,16 +2524,16 @@ function readFrontmatterName(node) {
|
|
|
2408
2524
|
return raw.length > 0 ? raw : null;
|
|
2409
2525
|
}
|
|
2410
2526
|
function readFilenameBasename(node) {
|
|
2411
|
-
const base =
|
|
2527
|
+
const base = pathPosix4.basename(node.path);
|
|
2412
2528
|
if (!base) return null;
|
|
2413
|
-
const ext =
|
|
2529
|
+
const ext = pathPosix4.extname(base);
|
|
2414
2530
|
const stem = ext ? base.slice(0, -ext.length) : base;
|
|
2415
2531
|
return stem.length > 0 ? stem : null;
|
|
2416
2532
|
}
|
|
2417
2533
|
function readDirname(node) {
|
|
2418
|
-
const dir =
|
|
2534
|
+
const dir = pathPosix4.dirname(node.path);
|
|
2419
2535
|
if (!dir || dir === "." || dir === "/") return null;
|
|
2420
|
-
const base =
|
|
2536
|
+
const base = pathPosix4.basename(dir);
|
|
2421
2537
|
return base.length > 0 ? base : null;
|
|
2422
2538
|
}
|
|
2423
2539
|
|
|
@@ -2492,7 +2608,7 @@ var NAME_RESERVED_TEXTS = {
|
|
|
2492
2608
|
* a runtime built-in. Same wording skill-map shipped before the
|
|
2493
2609
|
* source-side link finding landed.
|
|
2494
2610
|
*/
|
|
2495
|
-
message: "
|
|
2611
|
+
message: "Built-in {{provider}} {{kind}}:\nShadowed by this file; the runtime uses its built-in instead. Rename the file or its `frontmatter.name`.",
|
|
2496
2612
|
/**
|
|
2497
2613
|
* Source-side message: emitted on the node that AUTHORED a link
|
|
2498
2614
|
* whose target resolves to a reserved name. Explains WHY the link's
|
|
@@ -2500,13 +2616,17 @@ var NAME_RESERVED_TEXTS = {
|
|
|
2500
2616
|
* the kernel saw the target match a runtime built-in and downgraded
|
|
2501
2617
|
* the edge so the operator notices.
|
|
2502
2618
|
*/
|
|
2503
|
-
linkMessage: "
|
|
2619
|
+
linkMessage: "{{target}}:\nResolves to a {{provider}} built-in ({{reservedKind}} `{{reservedPath}}`){{where}}; edge downgraded to confidence {{confidence}}. Rename the target file or its `frontmatter.name`.",
|
|
2620
|
+
/** Location suffix after the built-in parens, one detection site. */
|
|
2621
|
+
whereSingle: " (line {{lines}})",
|
|
2622
|
+
/** Location suffix after the built-in parens, several detection sites. */
|
|
2623
|
+
wherePlural: " (lines {{lines}})"
|
|
2504
2624
|
};
|
|
2505
2625
|
|
|
2506
2626
|
// plugins/core/analyzers/name-reserved/index.ts
|
|
2507
|
-
var
|
|
2627
|
+
var ID18 = "name-reserved";
|
|
2508
2628
|
var nameReservedAnalyzer = {
|
|
2509
|
-
id:
|
|
2629
|
+
id: ID18,
|
|
2510
2630
|
pluginId: CORE_PLUGIN_ID,
|
|
2511
2631
|
kind: "analyzer",
|
|
2512
2632
|
description: "Flags two kinds of reserved-name collision: a file whose name shadows a built-in command of the active runtime, and a link that resolves to one of those reserved names.",
|
|
@@ -2522,7 +2642,7 @@ var nameReservedAnalyzer = {
|
|
|
2522
2642
|
const node = byPath3.get(path);
|
|
2523
2643
|
if (!node) continue;
|
|
2524
2644
|
issues.push({
|
|
2525
|
-
analyzerId:
|
|
2645
|
+
analyzerId: ID18,
|
|
2526
2646
|
severity: "warn",
|
|
2527
2647
|
nodeIds: [node.path],
|
|
2528
2648
|
message: tx(NAME_RESERVED_TEXTS.message, {
|
|
@@ -2538,16 +2658,16 @@ var nameReservedAnalyzer = {
|
|
|
2538
2658
|
const reservedNode = findReservedNodeForLink(link, reserved, byPath3);
|
|
2539
2659
|
if (!reservedNode) continue;
|
|
2540
2660
|
issues.push({
|
|
2541
|
-
analyzerId:
|
|
2661
|
+
analyzerId: ID18,
|
|
2542
2662
|
severity: "warn",
|
|
2543
2663
|
nodeIds: [link.source],
|
|
2544
2664
|
message: tx(NAME_RESERVED_TEXTS.linkMessage, {
|
|
2545
|
-
kind: link.kind,
|
|
2546
2665
|
target: link.target,
|
|
2547
2666
|
provider: reservedNode.provider,
|
|
2548
2667
|
reservedKind: reservedNode.kind,
|
|
2549
2668
|
reservedPath: reservedNode.path,
|
|
2550
|
-
confidence: RESERVED_TARGET_CONFIDENCE.toFixed(2)
|
|
2669
|
+
confidence: RESERVED_TARGET_CONFIDENCE.toFixed(2),
|
|
2670
|
+
where: linkWhereSuffix(link)
|
|
2551
2671
|
}),
|
|
2552
2672
|
data: {
|
|
2553
2673
|
target: link.target,
|
|
@@ -2562,6 +2682,12 @@ var nameReservedAnalyzer = {
|
|
|
2562
2682
|
return issues;
|
|
2563
2683
|
}
|
|
2564
2684
|
};
|
|
2685
|
+
function linkWhereSuffix(link) {
|
|
2686
|
+
return linkWhere(link, {
|
|
2687
|
+
single: NAME_RESERVED_TEXTS.whereSingle,
|
|
2688
|
+
plural: NAME_RESERVED_TEXTS.wherePlural
|
|
2689
|
+
});
|
|
2690
|
+
}
|
|
2565
2691
|
function findReservedNodeForLink(link, reserved, byPath3) {
|
|
2566
2692
|
if (reserved.has(link.target)) {
|
|
2567
2693
|
const node = byPath3.get(link.target);
|
|
@@ -2613,7 +2739,7 @@ var NODE_STABILITY_TEXTS = {
|
|
|
2613
2739
|
};
|
|
2614
2740
|
|
|
2615
2741
|
// plugins/core/analyzers/node-stability/index.ts
|
|
2616
|
-
var
|
|
2742
|
+
var ID19 = "node-stability";
|
|
2617
2743
|
var EXPERIMENTAL_TOOLTIP = "Experimental: API may change";
|
|
2618
2744
|
var DEPRECATED_TOOLTIP = "Deprecated: avoid in new code";
|
|
2619
2745
|
var experimental = {
|
|
@@ -2635,7 +2761,7 @@ var setStabilityButton = {
|
|
|
2635
2761
|
priority: 15
|
|
2636
2762
|
};
|
|
2637
2763
|
var nodeStabilityAnalyzer = {
|
|
2638
|
-
id:
|
|
2764
|
+
id: ID19,
|
|
2639
2765
|
pluginId: CORE_PLUGIN_ID,
|
|
2640
2766
|
kind: "analyzer",
|
|
2641
2767
|
description: "Reports a node's stability stage (`experimental`, `deprecated`) on the card.",
|
|
@@ -2654,7 +2780,7 @@ var nodeStabilityAnalyzer = {
|
|
|
2654
2780
|
tooltip: EXPERIMENTAL_TOOLTIP
|
|
2655
2781
|
});
|
|
2656
2782
|
issues.push({
|
|
2657
|
-
analyzerId:
|
|
2783
|
+
analyzerId: ID19,
|
|
2658
2784
|
severity: "info",
|
|
2659
2785
|
nodeIds: [node.path],
|
|
2660
2786
|
message: `Node '${node.path}' is marked experimental: API may change.`,
|
|
@@ -2667,7 +2793,7 @@ var nodeStabilityAnalyzer = {
|
|
|
2667
2793
|
severity: "warn"
|
|
2668
2794
|
});
|
|
2669
2795
|
issues.push({
|
|
2670
|
-
analyzerId:
|
|
2796
|
+
analyzerId: ID19,
|
|
2671
2797
|
severity: "warn",
|
|
2672
2798
|
nodeIds: [node.path],
|
|
2673
2799
|
message: `Node '${node.path}' is marked deprecated: avoid in new code.`,
|
|
@@ -2715,14 +2841,18 @@ function emitSetStabilityButton(ctx, nodePath, current) {
|
|
|
2715
2841
|
|
|
2716
2842
|
// plugins/core/analyzers/node-superseded/text.ts
|
|
2717
2843
|
var NODE_SUPERSEDED_TEXTS = {
|
|
2718
|
-
/**
|
|
2719
|
-
|
|
2844
|
+
/**
|
|
2845
|
+
* Compact finding grammar: line 1 = the superseding artifact, line
|
|
2846
|
+
* 2 = what it means. The superseded node is the finding's own node,
|
|
2847
|
+
* so its path never appears in the message.
|
|
2848
|
+
*/
|
|
2849
|
+
message: "{{supersededBy}}:\nSupersedes this node."
|
|
2720
2850
|
};
|
|
2721
2851
|
|
|
2722
2852
|
// plugins/core/analyzers/node-superseded/index.ts
|
|
2723
|
-
var
|
|
2853
|
+
var ID20 = "node-superseded";
|
|
2724
2854
|
var nodeSupersededAnalyzer = {
|
|
2725
|
-
id:
|
|
2855
|
+
id: ID20,
|
|
2726
2856
|
pluginId: CORE_PLUGIN_ID,
|
|
2727
2857
|
kind: "analyzer",
|
|
2728
2858
|
description: "Marks nodes replaced by a newer one via `supersededBy`.",
|
|
@@ -2733,7 +2863,7 @@ var nodeSupersededAnalyzer = {
|
|
|
2733
2863
|
const supersededBy = pickSupersededBy(node);
|
|
2734
2864
|
if (supersededBy === null) continue;
|
|
2735
2865
|
issues.push({
|
|
2736
|
-
analyzerId:
|
|
2866
|
+
analyzerId: ID20,
|
|
2737
2867
|
severity: "info",
|
|
2738
2868
|
nodeIds: [node.path],
|
|
2739
2869
|
message: tx(NODE_SUPERSEDED_TEXTS.message, {
|
|
@@ -2757,12 +2887,34 @@ function pickSupersededBy(node) {
|
|
|
2757
2887
|
}
|
|
2758
2888
|
|
|
2759
2889
|
// plugins/core/analyzers/reference-broken/index.ts
|
|
2760
|
-
import { posix as
|
|
2890
|
+
import { posix as pathPosix5, resolve as resolve3 } from "path";
|
|
2761
2891
|
|
|
2762
2892
|
// plugins/core/analyzers/reference-broken/text.ts
|
|
2763
2893
|
var REFERENCE_BROKEN_TEXTS = {
|
|
2764
|
-
/**
|
|
2765
|
-
|
|
2894
|
+
/**
|
|
2895
|
+
* Compact finding grammar: line 1 = the unresolved target, line 2 =
|
|
2896
|
+
* the short diagnosis plus WHERE the reference sits (`{{where}}` is
|
|
2897
|
+
* the pre-rendered location suffix below, or empty when the link
|
|
2898
|
+
* carries no line info). The source is the finding's own node, so it
|
|
2899
|
+
* never appears in the message.
|
|
2900
|
+
*/
|
|
2901
|
+
message: "{{target}}:\nBroken {{kindLabel}}{{where}}.",
|
|
2902
|
+
/** Location suffix, one detection site. */
|
|
2903
|
+
whereSingle: " (line {{lines}})",
|
|
2904
|
+
/** Location suffix, several detection sites. */
|
|
2905
|
+
wherePlural: " (lines {{lines}})",
|
|
2906
|
+
/**
|
|
2907
|
+
* Human noun per link kind for the message above. Fallback for an
|
|
2908
|
+
* off-catalog kind: `<kind> link` (composed in the analyzer).
|
|
2909
|
+
*/
|
|
2910
|
+
kindLabels: {
|
|
2911
|
+
references: "reference",
|
|
2912
|
+
mentions: "mention",
|
|
2913
|
+
invokes: "invocation",
|
|
2914
|
+
supersedes: "supersession",
|
|
2915
|
+
points: "pointer"
|
|
2916
|
+
},
|
|
2917
|
+
kindLabelFallback: "{{kind}} link",
|
|
2766
2918
|
// Tooltips for the per-node view-contribution badges. Singular vs
|
|
2767
2919
|
// plural keeps the count grammar correct without a sub-template.
|
|
2768
2920
|
alertTooltipSingle: "This node has a broken reference. Open the inspector for details.",
|
|
@@ -2776,9 +2928,9 @@ var REFERENCE_BROKEN_TEXTS = {
|
|
|
2776
2928
|
};
|
|
2777
2929
|
|
|
2778
2930
|
// plugins/core/analyzers/reference-broken/index.ts
|
|
2779
|
-
var
|
|
2931
|
+
var ID21 = "reference-broken";
|
|
2780
2932
|
var referenceBrokenAnalyzer = {
|
|
2781
|
-
id:
|
|
2933
|
+
id: ID21,
|
|
2782
2934
|
pluginId: CORE_PLUGIN_ID,
|
|
2783
2935
|
kind: "analyzer",
|
|
2784
2936
|
description: "Flags arrows pointing at a node not part of the current scan.",
|
|
@@ -2815,7 +2967,7 @@ function buildIssue(link, hintCandidates = []) {
|
|
|
2815
2967
|
trigger: link.trigger?.normalizedTrigger ?? null
|
|
2816
2968
|
};
|
|
2817
2969
|
const issue = {
|
|
2818
|
-
analyzerId:
|
|
2970
|
+
analyzerId: ID21,
|
|
2819
2971
|
// `error`, not `warn`: a link whose target is not in the scan is a
|
|
2820
2972
|
// structural defect the operator must notice, and the card chip
|
|
2821
2973
|
// paints `danger` (red) to match. Per the chip-vs-issue policy in
|
|
@@ -2825,33 +2977,37 @@ function buildIssue(link, hintCandidates = []) {
|
|
|
2825
2977
|
severity: "error",
|
|
2826
2978
|
nodeIds: [link.source],
|
|
2827
2979
|
message: tx(REFERENCE_BROKEN_TEXTS.message, {
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2980
|
+
target: link.target,
|
|
2981
|
+
kindLabel: REFERENCE_BROKEN_TEXTS.kindLabels[link.kind] ?? tx(REFERENCE_BROKEN_TEXTS.kindLabelFallback, { kind: link.kind }),
|
|
2982
|
+
where: linkWhere(link, {
|
|
2983
|
+
single: REFERENCE_BROKEN_TEXTS.whereSingle,
|
|
2984
|
+
plural: REFERENCE_BROKEN_TEXTS.wherePlural
|
|
2985
|
+
})
|
|
2831
2986
|
}),
|
|
2832
2987
|
data
|
|
2833
2988
|
};
|
|
2834
|
-
if (hintCandidates.length > 0)
|
|
2835
|
-
const suggestedName = (link.trigger?.normalizedTrigger ?? "").replace(/^[/@]/, "").trim();
|
|
2836
|
-
const candidatePaths = hintCandidates.map((n) => n.path);
|
|
2837
|
-
data["hint"] = {
|
|
2838
|
-
kind: "missing-frontmatter-name",
|
|
2839
|
-
suggestedName,
|
|
2840
|
-
candidates: candidatePaths
|
|
2841
|
-
};
|
|
2842
|
-
issue.fix = {
|
|
2843
|
-
summary: candidatePaths.length === 1 ? tx(REFERENCE_BROKEN_TEXTS.hintSummarySingle, {
|
|
2844
|
-
name: suggestedName,
|
|
2845
|
-
candidate: candidatePaths[0]
|
|
2846
|
-
}) : tx(REFERENCE_BROKEN_TEXTS.hintSummaryMany, {
|
|
2847
|
-
name: suggestedName,
|
|
2848
|
-
candidates: candidatePaths.join(", ")
|
|
2849
|
-
}),
|
|
2850
|
-
autofixable: false
|
|
2851
|
-
};
|
|
2852
|
-
}
|
|
2989
|
+
if (hintCandidates.length > 0) attachHint(issue, data, link, hintCandidates);
|
|
2853
2990
|
return issue;
|
|
2854
2991
|
}
|
|
2992
|
+
function attachHint(issue, data, link, hintCandidates) {
|
|
2993
|
+
const suggestedName = (link.trigger?.normalizedTrigger ?? "").replace(/^[/@]/, "").trim();
|
|
2994
|
+
const candidatePaths = hintCandidates.map((n) => n.path);
|
|
2995
|
+
data["hint"] = {
|
|
2996
|
+
kind: "missing-frontmatter-name",
|
|
2997
|
+
suggestedName,
|
|
2998
|
+
candidates: candidatePaths
|
|
2999
|
+
};
|
|
3000
|
+
issue.fix = {
|
|
3001
|
+
summary: candidatePaths.length === 1 ? tx(REFERENCE_BROKEN_TEXTS.hintSummarySingle, {
|
|
3002
|
+
name: suggestedName,
|
|
3003
|
+
candidate: candidatePaths[0]
|
|
3004
|
+
}) : tx(REFERENCE_BROKEN_TEXTS.hintSummaryMany, {
|
|
3005
|
+
name: suggestedName,
|
|
3006
|
+
candidates: candidatePaths.join(", ")
|
|
3007
|
+
}),
|
|
3008
|
+
autofixable: false
|
|
3009
|
+
};
|
|
3010
|
+
}
|
|
2855
3011
|
function resolvesViaReferencePaths(link, refIndex) {
|
|
2856
3012
|
if (!isPathStyleLink(link)) return false;
|
|
2857
3013
|
return refIndex.paths.has(resolve3(refIndex.cwd, link.target));
|
|
@@ -2870,8 +3026,8 @@ function indexByNormalizedName(nodes) {
|
|
|
2870
3026
|
return out;
|
|
2871
3027
|
}
|
|
2872
3028
|
function basenameWithoutExt(path) {
|
|
2873
|
-
const base =
|
|
2874
|
-
const ext =
|
|
3029
|
+
const base = pathPosix5.basename(path);
|
|
3030
|
+
const ext = pathPosix5.extname(base);
|
|
2875
3031
|
return ext ? base.slice(0, -ext.length) : base;
|
|
2876
3032
|
}
|
|
2877
3033
|
function indexByBasenameWithoutName(nodes) {
|
|
@@ -2917,25 +3073,29 @@ function isPathStyleLink(link) {
|
|
|
2917
3073
|
// plugins/core/analyzers/reference-redundant/text.ts
|
|
2918
3074
|
var REFERENCE_REDUNDANT_TEXTS = {
|
|
2919
3075
|
/**
|
|
2920
|
-
*
|
|
2921
|
-
*
|
|
2922
|
-
*
|
|
2923
|
-
*
|
|
2924
|
-
*
|
|
3076
|
+
* Compact finding grammar (subject first, `\n` renders as a line
|
|
3077
|
+
* break in the inspector and flattens to a space in `sm check`):
|
|
3078
|
+
*
|
|
3079
|
+
* <resolvedTarget>:
|
|
3080
|
+
* Duplicate reference (2): `references/x.md` (124, 145).
|
|
3081
|
+
*
|
|
3082
|
+
* Occurrences are grouped BY TRIGGER: each distinct trigger text
|
|
3083
|
+
* appears once with its line numbers collapsed into one paren list.
|
|
3084
|
+
* The source node is the finding's own node, so it never appears.
|
|
2925
3085
|
*/
|
|
2926
|
-
message: "
|
|
2927
|
-
/** Inline separator between
|
|
3086
|
+
message: "{{resolvedTarget}}:\nDuplicate reference ({{count}}): {{occurrences}}.",
|
|
3087
|
+
/** Inline separator between trigger groups in the message. */
|
|
2928
3088
|
occurrenceSeparator: ", ",
|
|
2929
|
-
/** Per-
|
|
2930
|
-
occurrence: "`{{trigger}}` ({{
|
|
2931
|
-
/**
|
|
2932
|
-
|
|
3089
|
+
/** Per-trigger formatting: the trigger once, its lines grouped. */
|
|
3090
|
+
occurrence: "`{{trigger}}` ({{lines}})",
|
|
3091
|
+
/** Placeholder for an occurrence whose extractor recorded no line. */
|
|
3092
|
+
lineUnknown: "?"
|
|
2933
3093
|
};
|
|
2934
3094
|
|
|
2935
3095
|
// plugins/core/analyzers/reference-redundant/index.ts
|
|
2936
|
-
var
|
|
3096
|
+
var ID22 = "reference-redundant";
|
|
2937
3097
|
var referenceRedundantAnalyzer = {
|
|
2938
|
-
id:
|
|
3098
|
+
id: ID22,
|
|
2939
3099
|
pluginId: CORE_PLUGIN_ID,
|
|
2940
3100
|
kind: "analyzer",
|
|
2941
3101
|
description: "Flags when one node references the same target through two or more different links (e.g. a markdown link plus a `references:` entry).",
|
|
@@ -2961,14 +3121,13 @@ var referenceRedundantAnalyzer = {
|
|
|
2961
3121
|
const [source, resolvedTarget] = key.split("\0");
|
|
2962
3122
|
const flat = flattenOccurrences(links);
|
|
2963
3123
|
issues.push({
|
|
2964
|
-
analyzerId:
|
|
2965
|
-
severity: "
|
|
3124
|
+
analyzerId: ID22,
|
|
3125
|
+
severity: "info",
|
|
2966
3126
|
nodeIds: [source],
|
|
2967
3127
|
message: tx(REFERENCE_REDUNDANT_TEXTS.message, {
|
|
2968
|
-
source,
|
|
2969
3128
|
resolvedTarget,
|
|
2970
3129
|
count: flat.length,
|
|
2971
|
-
occurrences: flat
|
|
3130
|
+
occurrences: formatGroupedOccurrences(flat)
|
|
2972
3131
|
}),
|
|
2973
3132
|
data: {
|
|
2974
3133
|
target: resolvedTarget,
|
|
@@ -3015,11 +3174,19 @@ function flattenOccurrences(links) {
|
|
|
3015
3174
|
});
|
|
3016
3175
|
return out;
|
|
3017
3176
|
}
|
|
3018
|
-
function
|
|
3019
|
-
|
|
3020
|
-
|
|
3021
|
-
|
|
3022
|
-
|
|
3177
|
+
function formatGroupedOccurrences(occurrences) {
|
|
3178
|
+
const byTrigger = /* @__PURE__ */ new Map();
|
|
3179
|
+
for (const occ of occurrences) {
|
|
3180
|
+
const bucket = byTrigger.get(occ.originalTrigger);
|
|
3181
|
+
if (bucket) bucket.push(occ);
|
|
3182
|
+
else byTrigger.set(occ.originalTrigger, [occ]);
|
|
3183
|
+
}
|
|
3184
|
+
return [...byTrigger.entries()].map(
|
|
3185
|
+
([trigger, occs]) => tx(REFERENCE_REDUNDANT_TEXTS.occurrence, {
|
|
3186
|
+
trigger,
|
|
3187
|
+
lines: occs.map((o) => o.line === null ? REFERENCE_REDUNDANT_TEXTS.lineUnknown : String(o.line)).join(", ")
|
|
3188
|
+
})
|
|
3189
|
+
).join(REFERENCE_REDUNDANT_TEXTS.occurrenceSeparator);
|
|
3023
3190
|
}
|
|
3024
3191
|
function buildNameIndex2(nodes) {
|
|
3025
3192
|
const out = /* @__PURE__ */ new Map();
|
|
@@ -3311,12 +3478,14 @@ function existsSyncSafe(path) {
|
|
|
3311
3478
|
|
|
3312
3479
|
// plugins/core/analyzers/schema-violation/text.ts
|
|
3313
3480
|
var SCHEMA_VIOLATION_TEXTS = {
|
|
3314
|
-
|
|
3315
|
-
|
|
3316
|
-
/** `
|
|
3317
|
-
|
|
3318
|
-
/**
|
|
3319
|
-
|
|
3481
|
+
// Compact finding grammar: the affected node (or the link's source)
|
|
3482
|
+
// is the finding's own node, so its path never appears.
|
|
3483
|
+
/** `Schema validation failed: <errors>` */
|
|
3484
|
+
nodeFailure: "Schema validation failed: {{errors}}",
|
|
3485
|
+
/** `<target>:\nLink failed schema validation: <errors>` */
|
|
3486
|
+
linkFailure: "{{target}}:\nLink failed schema validation: {{errors}}",
|
|
3487
|
+
/** `Missing required frontmatter: <missing>.` */
|
|
3488
|
+
frontmatterBaseFailure: "Missing required frontmatter: {{missing}}.",
|
|
3320
3489
|
/** Singular tooltip on the alert / chip when a node has exactly one validation failure. */
|
|
3321
3490
|
alertTooltipSingle: "Frontmatter or schema validation failed.",
|
|
3322
3491
|
/** Plural tooltip; `{{count}}` capped at 99 in the chip badge but the tooltip text shows the raw count. */
|
|
@@ -3324,9 +3493,9 @@ var SCHEMA_VIOLATION_TEXTS = {
|
|
|
3324
3493
|
};
|
|
3325
3494
|
|
|
3326
3495
|
// plugins/core/analyzers/schema-violation/index.ts
|
|
3327
|
-
var
|
|
3496
|
+
var ID23 = "schema-violation";
|
|
3328
3497
|
var schemaViolationAnalyzer = {
|
|
3329
|
-
id:
|
|
3498
|
+
id: ID23,
|
|
3330
3499
|
pluginId: CORE_PLUGIN_ID,
|
|
3331
3500
|
kind: "analyzer",
|
|
3332
3501
|
description: "Flags nodes or links that violate the project schemas.",
|
|
@@ -3377,7 +3546,7 @@ function collectNodeFindings(v, node, out) {
|
|
|
3377
3546
|
const result = v.validate("node", toNodeForSchema(node));
|
|
3378
3547
|
if (result.ok) return;
|
|
3379
3548
|
out.push({
|
|
3380
|
-
analyzerId:
|
|
3549
|
+
analyzerId: ID23,
|
|
3381
3550
|
severity: "error",
|
|
3382
3551
|
nodeIds: [node.path],
|
|
3383
3552
|
message: tx(SCHEMA_VIOLATION_TEXTS.nodeFailure, {
|
|
@@ -3396,7 +3565,7 @@ function collectFrontmatterBaseFindings(node, out) {
|
|
|
3396
3565
|
if (isMissingStringField(fm, "description")) missing.push("description");
|
|
3397
3566
|
if (missing.length === 0) return;
|
|
3398
3567
|
out.push({
|
|
3399
|
-
analyzerId:
|
|
3568
|
+
analyzerId: ID23,
|
|
3400
3569
|
// `warn` (not `error`) so the default `sm scan` exit code stays
|
|
3401
3570
|
// 0 even when nodes are missing frontmatter base fields. Strict
|
|
3402
3571
|
// mode (`sm scan --strict`) still escalates to exit 1. Matches
|
|
@@ -3418,7 +3587,7 @@ function collectLinkFindings(v, link, out) {
|
|
|
3418
3587
|
const result = v.validate("link", toLinkForSchema(link));
|
|
3419
3588
|
if (result.ok) return;
|
|
3420
3589
|
out.push({
|
|
3421
|
-
analyzerId:
|
|
3590
|
+
analyzerId: ID23,
|
|
3422
3591
|
severity: "error",
|
|
3423
3592
|
nodeIds: [link.source],
|
|
3424
3593
|
message: tx(SCHEMA_VIOLATION_TEXTS.linkFailure, {
|
|
@@ -3473,7 +3642,7 @@ var SIGNAL_COLLISION_TEXTS = {
|
|
|
3473
3642
|
* the same paragraph, the markdown-link wins and the at-directive
|
|
3474
3643
|
* silently disappears without this warning).
|
|
3475
3644
|
*/
|
|
3476
|
-
message: "{{
|
|
3645
|
+
message: "`{{loserRaw}}`:\nOverlap collision: {{loserExtractor}} (at {{loserRange}}) lost to {{winnerExtractor}} (at {{winnerRange}}) by {{reason}}; only the winning edge persists.",
|
|
3477
3646
|
/**
|
|
3478
3647
|
* Same warn but for the rare case the resolver rejected a Signal
|
|
3479
3648
|
* because the operator disabled its extractor via
|
|
@@ -3482,20 +3651,20 @@ var SIGNAL_COLLISION_TEXTS = {
|
|
|
3482
3651
|
* resolver; documented now so the analyzer stays forward-compatible
|
|
3483
3652
|
* with the upcoming filter pass.
|
|
3484
3653
|
*/
|
|
3485
|
-
messageExtractorDisabled: "
|
|
3654
|
+
messageExtractorDisabled: "`{{loserRaw}}`:\nDropped: extension `{{extractorId}}` is disabled. Re-enable it in Settings or via `sm plugins enable`.",
|
|
3486
3655
|
/**
|
|
3487
3656
|
* Same warn but for the future confidence floor case. Phase 4+ stub:
|
|
3488
3657
|
* today the resolver materialises every winning candidate regardless
|
|
3489
3658
|
* of confidence, so this template is unreachable; documented for
|
|
3490
3659
|
* forward compatibility.
|
|
3491
3660
|
*/
|
|
3492
|
-
messageBelowFloor: "
|
|
3661
|
+
messageBelowFloor: "`{{loserRaw}}`:\nDropped: confidence {{confidence}} is below the threshold {{threshold}}."
|
|
3493
3662
|
};
|
|
3494
3663
|
|
|
3495
3664
|
// plugins/core/analyzers/signal-collision/index.ts
|
|
3496
|
-
var
|
|
3665
|
+
var ID24 = "signal-collision";
|
|
3497
3666
|
var signalCollisionAnalyzer = {
|
|
3498
|
-
id:
|
|
3667
|
+
id: ID24,
|
|
3499
3668
|
pluginId: CORE_PLUGIN_ID,
|
|
3500
3669
|
kind: "analyzer",
|
|
3501
3670
|
description: "Reports when two extractors fight over the same span of body text, or when a candidate link is dropped (extractor disabled, confidence too low) before it reaches the graph.",
|
|
@@ -3520,7 +3689,7 @@ function makeIssue(signal) {
|
|
|
3520
3689
|
const loserRange = signal.range ? `${signal.range.start}-${signal.range.end}` : "unknown";
|
|
3521
3690
|
const winnerRange = `${winner.range.start}-${winner.range.end}`;
|
|
3522
3691
|
return {
|
|
3523
|
-
analyzerId:
|
|
3692
|
+
analyzerId: ID24,
|
|
3524
3693
|
severity: "warn",
|
|
3525
3694
|
nodeIds: [signal.source],
|
|
3526
3695
|
message: tx(SIGNAL_COLLISION_TEXTS.message, {
|
|
@@ -3553,7 +3722,7 @@ function makeIssue(signal) {
|
|
|
3553
3722
|
if (resolution.extractorDisabled) {
|
|
3554
3723
|
const loserRange = signal.range ? `${signal.range.start}-${signal.range.end}` : "unknown";
|
|
3555
3724
|
return {
|
|
3556
|
-
analyzerId:
|
|
3725
|
+
analyzerId: ID24,
|
|
3557
3726
|
severity: "warn",
|
|
3558
3727
|
nodeIds: [signal.source],
|
|
3559
3728
|
message: tx(SIGNAL_COLLISION_TEXTS.messageExtractorDisabled, {
|
|
@@ -3572,7 +3741,7 @@ function makeIssue(signal) {
|
|
|
3572
3741
|
const loserRange = signal.range ? `${signal.range.start}-${signal.range.end}` : "unknown";
|
|
3573
3742
|
const topCandidate = signal.candidates[0];
|
|
3574
3743
|
return {
|
|
3575
|
-
analyzerId:
|
|
3744
|
+
analyzerId: ID24,
|
|
3576
3745
|
severity: "warn",
|
|
3577
3746
|
nodeIds: [signal.source],
|
|
3578
3747
|
message: tx(SIGNAL_COLLISION_TEXTS.messageBelowFloor, {
|
|
@@ -3604,13 +3773,13 @@ var SUPERSEDE_TEXTS = {
|
|
|
3604
3773
|
};
|
|
3605
3774
|
|
|
3606
3775
|
// plugins/core/analyzers/supersede/index.ts
|
|
3607
|
-
var
|
|
3776
|
+
var ID25 = "supersede";
|
|
3608
3777
|
var supersedeButton = {
|
|
3609
3778
|
slot: "inspector.action.button",
|
|
3610
3779
|
priority: 10
|
|
3611
3780
|
};
|
|
3612
3781
|
var supersedeAnalyzer = {
|
|
3613
|
-
id:
|
|
3782
|
+
id: ID25,
|
|
3614
3783
|
pluginId: CORE_PLUGIN_ID,
|
|
3615
3784
|
kind: "analyzer",
|
|
3616
3785
|
description: 'Projects the inspector "Supersede" button (declares a node replaced by another).',
|
|
@@ -3665,13 +3834,13 @@ var TAGS_TEXTS = {
|
|
|
3665
3834
|
};
|
|
3666
3835
|
|
|
3667
3836
|
// plugins/core/analyzers/tags/index.ts
|
|
3668
|
-
var
|
|
3837
|
+
var ID26 = "tags";
|
|
3669
3838
|
var setTagsButton = {
|
|
3670
3839
|
slot: "inspector.action.button",
|
|
3671
3840
|
priority: 15
|
|
3672
3841
|
};
|
|
3673
3842
|
var tagsAnalyzer = {
|
|
3674
|
-
id:
|
|
3843
|
+
id: ID26,
|
|
3675
3844
|
pluginId: CORE_PLUGIN_ID,
|
|
3676
3845
|
kind: "analyzer",
|
|
3677
3846
|
description: `Projects the inspector "Edit tags" button (edits a node's taxonomy tags).`,
|
|
@@ -3714,18 +3883,18 @@ var TRIGGER_COLLISION_TEXTS = {
|
|
|
3714
3883
|
* cause part. Used for the advertiser-ambiguous-only, invocation-
|
|
3715
3884
|
* ambiguous-only, and cross-kind-only branches.
|
|
3716
3885
|
*/
|
|
3717
|
-
messageOnePart: '
|
|
3886
|
+
messageOnePart: '"{{normalized}}":\nTrigger collision: {{part}}.',
|
|
3718
3887
|
/**
|
|
3719
3888
|
* Top-level message when `analyzeTriggerBucket` accumulated two cause
|
|
3720
3889
|
* parts (advertiser-ambiguous AND invocation-ambiguous fire together).
|
|
3721
3890
|
* The joiner lives inside the template so future locales can adapt it
|
|
3722
3891
|
* (e.g. `'; y '` in Spanish) without touching the rule code.
|
|
3723
3892
|
*/
|
|
3724
|
-
messageTwoParts: '
|
|
3725
|
-
/** `<n>
|
|
3726
|
-
partAdvertisers: "{{count}}
|
|
3727
|
-
/** `<n>
|
|
3728
|
-
partInvocations: "{{count}}
|
|
3893
|
+
messageTwoParts: '"{{normalized}}":\nTrigger collision: {{first}}; and {{second}}.',
|
|
3894
|
+
/** `<n> advertisers: <list>` part, fires on the advertiser-ambiguous branch. */
|
|
3895
|
+
partAdvertisers: "{{count}} advertisers: {{paths}}",
|
|
3896
|
+
/** `<n> invocation forms: <list>` part, fires on the invocation-ambiguous branch. */
|
|
3897
|
+
partInvocations: "{{count}} invocation forms: {{forms}}",
|
|
3729
3898
|
/** Singular cross-kind cause: `non-canonical invocation <form> against advertiser <path>`. */
|
|
3730
3899
|
partNonCanonicalSingular: "non-canonical invocation {{forms}} against advertiser {{advertiser}}",
|
|
3731
3900
|
/** Plural cross-kind cause: `non-canonical invocations <forms> against advertiser <path>`. */
|
|
@@ -3733,14 +3902,14 @@ var TRIGGER_COLLISION_TEXTS = {
|
|
|
3733
3902
|
};
|
|
3734
3903
|
|
|
3735
3904
|
// plugins/core/analyzers/trigger-collision/index.ts
|
|
3736
|
-
var
|
|
3905
|
+
var ID27 = "trigger-collision";
|
|
3737
3906
|
var ADVERTISING_KINDS = /* @__PURE__ */ new Set([
|
|
3738
3907
|
"command",
|
|
3739
3908
|
"skill",
|
|
3740
3909
|
"agent"
|
|
3741
3910
|
]);
|
|
3742
3911
|
var triggerCollisionAnalyzer = {
|
|
3743
|
-
id:
|
|
3912
|
+
id: ID27,
|
|
3744
3913
|
pluginId: CORE_PLUGIN_ID,
|
|
3745
3914
|
kind: "analyzer",
|
|
3746
3915
|
mode: "deterministic",
|
|
@@ -3838,7 +4007,7 @@ function analyzeTriggerBucket(normalized, claims) {
|
|
|
3838
4007
|
part: parts[0]
|
|
3839
4008
|
});
|
|
3840
4009
|
return {
|
|
3841
|
-
analyzerId:
|
|
4010
|
+
analyzerId: ID27,
|
|
3842
4011
|
severity: "error",
|
|
3843
4012
|
nodeIds,
|
|
3844
4013
|
message,
|
|
@@ -3878,13 +4047,13 @@ var ASCII_FORMATTER_TEXTS = {
|
|
|
3878
4047
|
};
|
|
3879
4048
|
|
|
3880
4049
|
// plugins/core/formatters/ascii/index.ts
|
|
3881
|
-
var
|
|
4050
|
+
var ID28 = "ascii";
|
|
3882
4051
|
var KIND_ORDER = ["agent", "command", "skill", "markdown"];
|
|
3883
4052
|
var asciiFormatter = {
|
|
3884
|
-
id:
|
|
4053
|
+
id: ID28,
|
|
3885
4054
|
pluginId: CORE_PLUGIN_ID,
|
|
3886
4055
|
kind: "formatter",
|
|
3887
|
-
formatId:
|
|
4056
|
+
formatId: ID28,
|
|
3888
4057
|
description: "Renders the scan as plain text in three sections: nodes (grouped by kind), arrows, and issues. Used by `sm scan --format ascii`.",
|
|
3889
4058
|
// ASCII tree formatter, header + per-kind sections + per-issue
|
|
3890
4059
|
// section. Each section iterates and renders; splitting per section
|
|
@@ -3978,13 +4147,13 @@ function renderSection(out, kind, group) {
|
|
|
3978
4147
|
}
|
|
3979
4148
|
|
|
3980
4149
|
// plugins/core/formatters/json/index.ts
|
|
3981
|
-
var
|
|
4150
|
+
var ID29 = "json";
|
|
3982
4151
|
var jsonFormatter = {
|
|
3983
|
-
id:
|
|
4152
|
+
id: ID29,
|
|
3984
4153
|
pluginId: CORE_PLUGIN_ID,
|
|
3985
4154
|
kind: "formatter",
|
|
3986
4155
|
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`.",
|
|
3987
|
-
formatId:
|
|
4156
|
+
formatId: ID29,
|
|
3988
4157
|
format(ctx) {
|
|
3989
4158
|
if (ctx.scanResult !== void 0) {
|
|
3990
4159
|
return JSON.stringify(ctx.scanResult);
|
|
@@ -4123,9 +4292,9 @@ function resolveSpecRoot2() {
|
|
|
4123
4292
|
}
|
|
4124
4293
|
|
|
4125
4294
|
// plugins/core/actions/node-bump/index.ts
|
|
4126
|
-
var
|
|
4295
|
+
var ID30 = "node-bump";
|
|
4127
4296
|
var nodeBumpAction = {
|
|
4128
|
-
id:
|
|
4297
|
+
id: ID30,
|
|
4129
4298
|
pluginId: CORE_PLUGIN_ID,
|
|
4130
4299
|
kind: "action",
|
|
4131
4300
|
description: "Marks a node as updated: bumps `annotations.version`, refreshes sidecar hashes, and records the timestamp.",
|
|
@@ -4184,9 +4353,9 @@ function pickCurrentVersion(overlay) {
|
|
|
4184
4353
|
|
|
4185
4354
|
// plugins/core/actions/node-set-stability/index.ts
|
|
4186
4355
|
var STABILITY_VALUES = ["experimental", "stable", "deprecated"];
|
|
4187
|
-
var
|
|
4356
|
+
var ID31 = "node-set-stability";
|
|
4188
4357
|
var nodeSetStabilityAction = {
|
|
4189
|
-
id:
|
|
4358
|
+
id: ID31,
|
|
4190
4359
|
pluginId: CORE_PLUGIN_ID,
|
|
4191
4360
|
kind: "action",
|
|
4192
4361
|
description: "Sets the lifecycle stage of the current node (writes `stability` to the sidecar).",
|
|
@@ -4226,9 +4395,9 @@ function invokeSetStability(input, ctx) {
|
|
|
4226
4395
|
}
|
|
4227
4396
|
|
|
4228
4397
|
// plugins/core/actions/node-set-tags/index.ts
|
|
4229
|
-
var
|
|
4398
|
+
var ID32 = "node-set-tags";
|
|
4230
4399
|
var nodeSetTagsAction = {
|
|
4231
|
-
id:
|
|
4400
|
+
id: ID32,
|
|
4232
4401
|
pluginId: CORE_PLUGIN_ID,
|
|
4233
4402
|
kind: "action",
|
|
4234
4403
|
description: "Sets the taxonomy tags of the current node (writes `tags` to the sidecar; whole-array replace).",
|
|
@@ -4265,9 +4434,9 @@ function invokeSetTags(input, ctx) {
|
|
|
4265
4434
|
}
|
|
4266
4435
|
|
|
4267
4436
|
// plugins/core/actions/node-supersede/index.ts
|
|
4268
|
-
var
|
|
4437
|
+
var ID33 = "node-supersede";
|
|
4269
4438
|
var nodeSupersedeAction = {
|
|
4270
|
-
id:
|
|
4439
|
+
id: ID33,
|
|
4271
4440
|
pluginId: CORE_PLUGIN_ID,
|
|
4272
4441
|
kind: "action",
|
|
4273
4442
|
description: "Declares the current node as superseded by another (writes `supersededBy` to the sidecar).",
|
|
@@ -4785,15 +4954,16 @@ var updateCheckHook = {
|
|
|
4785
4954
|
var claudeProvider2 = { ...claudeProvider, pluginId: "claude", version: VERSION };
|
|
4786
4955
|
var atDirectiveExtractor2 = { ...atDirectiveExtractor, pluginId: "claude", version: VERSION };
|
|
4787
4956
|
var slashCommandExtractor2 = { ...slashCommandExtractor, pluginId: "claude", version: VERSION };
|
|
4957
|
+
var toolsCounterExtractor2 = { ...toolsCounterExtractor, pluginId: "claude", version: VERSION };
|
|
4788
4958
|
var antigravityProvider2 = { ...antigravityProvider, pluginId: "antigravity", version: VERSION };
|
|
4789
4959
|
var openaiProvider2 = { ...openaiProvider, pluginId: "openai", version: VERSION };
|
|
4790
4960
|
var agentSkillsProvider2 = { ...agentSkillsProvider, pluginId: "agent-skills", version: VERSION };
|
|
4791
4961
|
var coreMarkdownProvider2 = { ...coreMarkdownProvider, pluginId: "core", version: VERSION };
|
|
4792
4962
|
var annotationsExtractor2 = { ...annotationsExtractor, pluginId: "core", version: VERSION };
|
|
4963
|
+
var backtickPathExtractor2 = { ...backtickPathExtractor, pluginId: "core", version: VERSION };
|
|
4793
4964
|
var externalUrlCounterExtractor2 = { ...externalUrlCounterExtractor, pluginId: "core", version: VERSION };
|
|
4794
4965
|
var markdownLinkExtractor2 = { ...markdownLinkExtractor, pluginId: "core", version: VERSION };
|
|
4795
4966
|
var mcpToolsExtractor2 = { ...mcpToolsExtractor, pluginId: "core", version: VERSION };
|
|
4796
|
-
var toolsCounterExtractor2 = { ...toolsCounterExtractor, pluginId: "core", version: VERSION };
|
|
4797
4967
|
var annotationFieldUnknownAnalyzer2 = { ...annotationFieldUnknownAnalyzer, pluginId: "core", version: VERSION };
|
|
4798
4968
|
var annotationOrphanAnalyzer2 = { ...annotationOrphanAnalyzer, pluginId: "core", version: VERSION };
|
|
4799
4969
|
var annotationStaleAnalyzer2 = { ...annotationStaleAnalyzer, pluginId: "core", version: VERSION };
|
|
@@ -4827,7 +4997,8 @@ var builtInPlugins = [
|
|
|
4827
4997
|
extensions: [
|
|
4828
4998
|
claudeProvider2,
|
|
4829
4999
|
atDirectiveExtractor2,
|
|
4830
|
-
slashCommandExtractor2
|
|
5000
|
+
slashCommandExtractor2,
|
|
5001
|
+
toolsCounterExtractor2
|
|
4831
5002
|
]
|
|
4832
5003
|
},
|
|
4833
5004
|
{
|
|
@@ -4857,10 +5028,10 @@ var builtInPlugins = [
|
|
|
4857
5028
|
extensions: [
|
|
4858
5029
|
coreMarkdownProvider2,
|
|
4859
5030
|
annotationsExtractor2,
|
|
5031
|
+
backtickPathExtractor2,
|
|
4860
5032
|
externalUrlCounterExtractor2,
|
|
4861
5033
|
markdownLinkExtractor2,
|
|
4862
5034
|
mcpToolsExtractor2,
|
|
4863
|
-
toolsCounterExtractor2,
|
|
4864
5035
|
annotationFieldUnknownAnalyzer2,
|
|
4865
5036
|
annotationOrphanAnalyzer2,
|
|
4866
5037
|
annotationStaleAnalyzer2,
|
|
@@ -7784,7 +7955,8 @@ var LINK_KIND_VALUES = Object.freeze([
|
|
|
7784
7955
|
"invokes",
|
|
7785
7956
|
"references",
|
|
7786
7957
|
"mentions",
|
|
7787
|
-
"supersedes"
|
|
7958
|
+
"supersedes",
|
|
7959
|
+
"points"
|
|
7788
7960
|
]);
|
|
7789
7961
|
var SEVERITY_VALUES = Object.freeze([
|
|
7790
7962
|
"error",
|
|
@@ -10802,11 +10974,13 @@ var PluginLoader = class {
|
|
|
10802
10974
|
if (kind === "provider" && discoveredKinds) {
|
|
10803
10975
|
instance["kinds"] = discoveredKinds;
|
|
10804
10976
|
}
|
|
10977
|
+
const stability = exported["stability"];
|
|
10805
10978
|
return { ok: true, extension: {
|
|
10806
10979
|
kind,
|
|
10807
10980
|
id: pathId2,
|
|
10808
10981
|
pluginId,
|
|
10809
10982
|
version: exported["version"],
|
|
10983
|
+
...stability !== void 0 ? { stability } : {},
|
|
10810
10984
|
entryPath: abs,
|
|
10811
10985
|
module: mod,
|
|
10812
10986
|
instance
|
|
@@ -11796,7 +11970,7 @@ function renderHuman(issues, ansi) {
|
|
|
11796
11970
|
tx(CHECK_TEXTS.issueRow, {
|
|
11797
11971
|
glyph: severityGlyph(row.severity, ansi),
|
|
11798
11972
|
analyzerId: ansi.dim(row.analyzerId.padEnd(analyzerWidth)),
|
|
11799
|
-
message: trimRedundantPath(row.message, row.primary)
|
|
11973
|
+
message: flattenMessage(trimRedundantPath(row.message, row.primary))
|
|
11800
11974
|
})
|
|
11801
11975
|
);
|
|
11802
11976
|
}
|
|
@@ -11850,6 +12024,9 @@ function trimRedundantPath(message, primary) {
|
|
|
11850
12024
|
if (!message.includes(needle)) return message;
|
|
11851
12025
|
return message.replace(needle, "");
|
|
11852
12026
|
}
|
|
12027
|
+
function flattenMessage(message) {
|
|
12028
|
+
return message.replace(/\n+/g, " ");
|
|
12029
|
+
}
|
|
11853
12030
|
|
|
11854
12031
|
// cli/commands/config.ts
|
|
11855
12032
|
import { existsSync as existsSync16 } from "fs";
|
|
@@ -15823,8 +16000,9 @@ function buildVirtualNode(extractor, emitted, emitter) {
|
|
|
15823
16000
|
if (emitted.frontmatter) node.frontmatter = emitted.frontmatter;
|
|
15824
16001
|
return node;
|
|
15825
16002
|
}
|
|
16003
|
+
var KNOWN_LINK_KINDS = ["invokes", "references", "mentions", "supersedes", "points"];
|
|
15826
16004
|
function validateLink(extractor, link, emitter) {
|
|
15827
|
-
const knownKinds =
|
|
16005
|
+
const knownKinds = KNOWN_LINK_KINDS;
|
|
15828
16006
|
if (!knownKinds.includes(link.kind)) {
|
|
15829
16007
|
const qualifiedId2 = `${extractor.pluginId}/${extractor.id}`;
|
|
15830
16008
|
emitter.emit(
|
|
@@ -15859,7 +16037,6 @@ function validateLink(extractor, link, emitter) {
|
|
|
15859
16037
|
const confidence = c ?? ConfidenceTier.MEDIUM;
|
|
15860
16038
|
return { ...link, confidence };
|
|
15861
16039
|
}
|
|
15862
|
-
var KNOWN_LINK_KINDS = ["invokes", "references", "mentions", "supersedes"];
|
|
15863
16040
|
function validateSignal(extractor, signal, emitter) {
|
|
15864
16041
|
const qualifiedId2 = qualifiedExtensionId(extractor.pluginId, extractor.id);
|
|
15865
16042
|
if (!Array.isArray(signal.candidates) || signal.candidates.length === 0) {
|
|
@@ -20469,6 +20646,13 @@ var PLUGINS_TEXTS = {
|
|
|
20469
20646
|
* the visible output stay in sync.
|
|
20470
20647
|
*/
|
|
20471
20648
|
pluginSubIndent: " ",
|
|
20649
|
+
/**
|
|
20650
|
+
* Lifecycle tag appended to an extension name in list / show rows
|
|
20651
|
+
* when the manifest declares a non-default `stability` (anything but
|
|
20652
|
+
* `stable`). Inherits the surrounding line's color; `stable`
|
|
20653
|
+
* (declared or defaulted) renders no tag.
|
|
20654
|
+
*/
|
|
20655
|
+
stabilityTag: " ({{stability}})",
|
|
20472
20656
|
listTipShow: "\nTip: `sm plugins show <id>` for kinds, versions, and per-extension status.\n",
|
|
20473
20657
|
/** Show command, built-in header (no version row, no path). */
|
|
20474
20658
|
detailHeaderBuiltIn: " {{glyph}} {{id}} {{source}} {{count}} extension{{plural}}\n",
|
|
@@ -20624,9 +20808,14 @@ function extensionRowFromBuiltIn(ext, plugin, resolveEnabled) {
|
|
|
20624
20808
|
enabled: resolveEnabled(qualifiedExtensionId(plugin.id, ext.id)),
|
|
20625
20809
|
description: ext.description ?? ""
|
|
20626
20810
|
};
|
|
20811
|
+
if (ext.stability !== void 0) row.stability = ext.stability;
|
|
20627
20812
|
if (ext.entry !== void 0) row.entry = ext.entry;
|
|
20628
20813
|
return row;
|
|
20629
20814
|
}
|
|
20815
|
+
function withStabilityTag(name, stability) {
|
|
20816
|
+
if (!stability || stability === "stable") return name;
|
|
20817
|
+
return name + tx(PLUGINS_TEXTS.stabilityTag, { stability: sanitizeForTerminal(stability) });
|
|
20818
|
+
}
|
|
20630
20819
|
function omitModule(key, value) {
|
|
20631
20820
|
if (key !== "module") return value;
|
|
20632
20821
|
if (value === null || typeof value !== "object") return value;
|
|
@@ -20713,9 +20902,10 @@ function renderListHuman(builtIns2, plugins, resolveEnabled, ansi) {
|
|
|
20713
20902
|
return lines.join("\n") + "\n" + PLUGINS_TEXTS.listTipShow;
|
|
20714
20903
|
}
|
|
20715
20904
|
function builtInToListRow(b) {
|
|
20716
|
-
const names = b.extensions.map(
|
|
20717
|
-
|
|
20718
|
-
|
|
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
|
+
});
|
|
20719
20909
|
return {
|
|
20720
20910
|
id: b.id,
|
|
20721
20911
|
enabled: b.enabled,
|
|
@@ -20728,7 +20918,7 @@ function pluginToListRow(p, resolveEnabled) {
|
|
|
20728
20918
|
const extensions = p.extensions ?? [];
|
|
20729
20919
|
const enabled = isLoaded ? extensions.length === 0 || extensions.some((e) => resolveEnabled(qualifiedExtensionId(p.id, e.id))) : false;
|
|
20730
20920
|
const names = extensions.map((e) => {
|
|
20731
|
-
const safeId = sanitizeForTerminal(e.id);
|
|
20921
|
+
const safeId = withStabilityTag(sanitizeForTerminal(e.id), e.stability);
|
|
20732
20922
|
return resolveEnabled(qualifiedExtensionId(p.id, e.id)) ? safeId : `${PLUGINS_TEXTS.rowGlyphOff} ${safeId}`;
|
|
20733
20923
|
});
|
|
20734
20924
|
const reason = p.status === "enabled" ? void 0 : sanitizeForTerminal(p.reason ?? "") || void 0;
|
|
@@ -20908,7 +21098,7 @@ function renderBuiltInDetail(b, ansi) {
|
|
|
20908
21098
|
const items = sorted.map((ext) => ({
|
|
20909
21099
|
glyph: ext.enabled ? ansi.green(PLUGINS_TEXTS.rowGlyphOk) : ansi.red(PLUGINS_TEXTS.rowGlyphOff),
|
|
20910
21100
|
kind: ext.kind,
|
|
20911
|
-
name: `${b.id}/${ext.id}
|
|
21101
|
+
name: withStabilityTag(`${b.id}/${ext.id}`, ext.stability)
|
|
20912
21102
|
}));
|
|
20913
21103
|
return tx(PLUGINS_TEXTS.detailHeaderBuiltIn, {
|
|
20914
21104
|
glyph,
|
|
@@ -20987,7 +21177,7 @@ function collectPluginExtensionItems(match, ansi) {
|
|
|
20987
21177
|
// status header above (✕ on the row).
|
|
20988
21178
|
glyph: ansi.green(PLUGINS_TEXTS.rowGlyphOk),
|
|
20989
21179
|
kind: sanitizeForTerminal(ext.kind),
|
|
20990
|
-
name: `${safePluginId}/${safeExtId}`,
|
|
21180
|
+
name: withStabilityTag(`${safePluginId}/${safeExtId}`, ext.stability),
|
|
20991
21181
|
version: sanitizeForTerminal(ext.version)
|
|
20992
21182
|
};
|
|
20993
21183
|
});
|
|
@@ -21021,6 +21211,7 @@ function renderBuiltInExtensionDetail(pluginId, ext, ansi) {
|
|
|
21021
21211
|
source: ansi.dim(PLUGINS_TEXTS.sourceBuiltIn)
|
|
21022
21212
|
});
|
|
21023
21213
|
const meta = { kind: ext.kind };
|
|
21214
|
+
if (ext.stability && ext.stability !== "stable") meta.stability = ext.stability;
|
|
21024
21215
|
if (ext.description) meta.description = ext.description;
|
|
21025
21216
|
if (ext.entry !== void 0) meta.entry = ext.entry;
|
|
21026
21217
|
return header + "\n" + renderExtensionFields(meta);
|
|
@@ -21038,7 +21229,7 @@ function renderUserExtensionDetail(pluginId, ext, ansi) {
|
|
|
21038
21229
|
version: ext.version,
|
|
21039
21230
|
entry: ext.entryPath
|
|
21040
21231
|
};
|
|
21041
|
-
if (
|
|
21232
|
+
if (ext.stability && ext.stability !== "stable") input.stability = ext.stability;
|
|
21042
21233
|
if (meta.description !== void 0) input.description = meta.description;
|
|
21043
21234
|
if (meta.preconditions !== void 0) input.preconditions = meta.preconditions;
|
|
21044
21235
|
return header + "\n" + renderExtensionFields(input);
|
|
@@ -21048,7 +21239,6 @@ function readInstanceMeta(instance) {
|
|
|
21048
21239
|
const obj = instance;
|
|
21049
21240
|
const out = {};
|
|
21050
21241
|
if (typeof obj["description"] === "string") out.description = obj["description"];
|
|
21051
|
-
if (typeof obj["stability"] === "string") out.stability = obj["stability"];
|
|
21052
21242
|
if (Array.isArray(obj["preconditions"])) {
|
|
21053
21243
|
out.preconditions = obj["preconditions"].filter(
|
|
21054
21244
|
(p) => typeof p === "string"
|
|
@@ -25737,6 +25927,7 @@ function buildBuiltInItems(resolveEnabled) {
|
|
|
25737
25927
|
version: ext.version,
|
|
25738
25928
|
enabled: resolveEnabled(qualified),
|
|
25739
25929
|
...ext.description ? { description: ext.description } : {},
|
|
25930
|
+
...ext.stability ? { stability: ext.stability } : {},
|
|
25740
25931
|
...extLocked ? { locked: true } : {}
|
|
25741
25932
|
};
|
|
25742
25933
|
});
|
|
@@ -25792,6 +25983,7 @@ function projectExtensionRows(plugin, resolveEnabled, pluginLocked) {
|
|
|
25792
25983
|
version: ext.version,
|
|
25793
25984
|
enabled: resolveEnabled(qualified),
|
|
25794
25985
|
...description ? { description } : {},
|
|
25986
|
+
...ext.stability ? { stability: ext.stability } : {},
|
|
25795
25987
|
...extLocked ? { locked: true } : {}
|
|
25796
25988
|
};
|
|
25797
25989
|
});
|
|
@@ -30277,4 +30469,4 @@ function resolveBareDefault() {
|
|
|
30277
30469
|
process.exit(ExitCode.Error);
|
|
30278
30470
|
}
|
|
30279
30471
|
//# sourceMappingURL=cli.js.map
|
|
30280
|
-
//# debugId=
|
|
30472
|
+
//# debugId=3118bb11-aad2-50b2-b70d-ed15c2f72a97
|