@skill-map/cli 0.53.5 → 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/tutorial/sm-tutorial/SKILL.md +4 -2
- package/dist/cli/tutorial/sm-tutorial/references/_core.md +33 -7
- package/dist/cli/tutorial/sm-tutorial/references/_manifest.yml +1 -1
- package/dist/cli/tutorial/sm-tutorial/references/fixtures.md +0 -16
- package/dist/cli/tutorial/sm-tutorial/references/part-cli.md +8 -32
- package/dist/cli/tutorial/sm-tutorial/references/part-connect-harness.md +1 -16
- package/dist/cli/tutorial/sm-tutorial/references/part-fundamentals.md +4 -22
- package/dist/cli/tutorial/sm-tutorial/references/part-live-site.md +3 -3
- package/dist/cli/tutorial/sm-tutorial/references/part-maintain.md +17 -18
- package/dist/cli/tutorial/sm-tutorial/references/part-project-kickoff.md +0 -2
- package/dist/cli.js +459 -241
- 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-QLIHFXBC.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-MWDBZ2BE.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";
|
|
@@ -14839,6 +15016,13 @@ var HELP_TEXTS = {
|
|
|
14839
15016
|
* Tagline mirrors README.md "In a sentence", keep them in sync.
|
|
14840
15017
|
*/
|
|
14841
15018
|
compactHeader: "{{binary}} {{version}}: the missing map for Markdown-based generative-AI ecosystems",
|
|
15019
|
+
/**
|
|
15020
|
+
* Tutorial call-to-action rendered at the very top of the compact
|
|
15021
|
+
* overview, directly under the header and above USAGE, to point new
|
|
15022
|
+
* users at `sm tutorial`. `{{glyph}}` is a green `▶` when color is on,
|
|
15023
|
+
* a bare `▶` otherwise.
|
|
15024
|
+
*/
|
|
15025
|
+
compactTutorialCta: "{{glyph}} New to skill-map? Run `sm tutorial` for a hands-on, guided walkthrough.",
|
|
14842
15026
|
compactUsageHeading: "USAGE",
|
|
14843
15027
|
compactUsageLine: " sm <command> [options]",
|
|
14844
15028
|
compactExamplesHeading: "EXAMPLES",
|
|
@@ -14916,9 +15100,16 @@ var HelpCommand = class extends Command15 {
|
|
|
14916
15100
|
});
|
|
14917
15101
|
verbParts = Option14.Rest({ required: 0 });
|
|
14918
15102
|
format = Option14.String("--format", "human");
|
|
15103
|
+
// `HelpCommand` extends Clipanion's `Command` directly (see block
|
|
15104
|
+
// comment), so it does not inherit `SmCommand`'s `--no-color`. Declared
|
|
15105
|
+
// here because the human overview now emits a coloured tutorial glyph;
|
|
15106
|
+
// `ansiFor` still layers `NO_COLOR` / `FORCE_COLOR` / TTY on top.
|
|
15107
|
+
noColor = Option14.Boolean("--no-color", false, {
|
|
15108
|
+
description: "Disable ANSI color codes."
|
|
15109
|
+
});
|
|
14919
15110
|
async execute() {
|
|
14920
15111
|
const stderr = this.context.stderr;
|
|
14921
|
-
const ansi = ansiFor({ isTTY: stderr.isTTY === true, noColorFlag:
|
|
15112
|
+
const ansi = ansiFor({ isTTY: stderr.isTTY === true, noColorFlag: this.noColor });
|
|
14922
15113
|
const errGlyph = ansi.red("\u2715");
|
|
14923
15114
|
const format = normalizeFormat(this.format);
|
|
14924
15115
|
if (!format) {
|
|
@@ -14954,7 +15145,9 @@ var HelpCommand = class extends Command15 {
|
|
|
14954
15145
|
return ExitCode.NotFound;
|
|
14955
15146
|
}
|
|
14956
15147
|
if (format === "human") {
|
|
14957
|
-
this.context.stdout
|
|
15148
|
+
const stdout = this.context.stdout;
|
|
15149
|
+
const stdoutAnsi = ansiFor({ isTTY: stdout.isTTY === true, noColorFlag: this.noColor });
|
|
15150
|
+
this.context.stdout.write(renderCompactOverview(verbs, stdoutAnsi));
|
|
14958
15151
|
return ExitCode.Ok;
|
|
14959
15152
|
}
|
|
14960
15153
|
const doc = {
|
|
@@ -15255,10 +15448,12 @@ function truncate2(text, width) {
|
|
|
15255
15448
|
function padRight(value, width) {
|
|
15256
15449
|
return value.length >= width ? value : value + " ".repeat(width - value.length);
|
|
15257
15450
|
}
|
|
15258
|
-
function renderCompactOverview(verbs) {
|
|
15451
|
+
function renderCompactOverview(verbs, ansi) {
|
|
15259
15452
|
const lines = [];
|
|
15260
15453
|
lines.push(tx(HELP_TEXTS.compactHeader, { binary: BINARY_LABEL, version: VERSION }));
|
|
15261
15454
|
lines.push("");
|
|
15455
|
+
lines.push(tx(HELP_TEXTS.compactTutorialCta, { glyph: ansi.green("\u25B6") }));
|
|
15456
|
+
lines.push("");
|
|
15262
15457
|
lines.push(HELP_TEXTS.compactUsageHeading);
|
|
15263
15458
|
lines.push(HELP_TEXTS.compactUsageLine);
|
|
15264
15459
|
lines.push("");
|
|
@@ -15303,9 +15498,17 @@ function renderCompactOverview(verbs) {
|
|
|
15303
15498
|
}
|
|
15304
15499
|
var RootHelpCommand = class extends Command15 {
|
|
15305
15500
|
static paths = [["-h"], ["--help"]];
|
|
15501
|
+
// Mirrors `HelpCommand.noColor`: this command extends Clipanion's
|
|
15502
|
+
// `Command` directly, so the flag is declared here to gate the
|
|
15503
|
+
// coloured tutorial glyph in the overview.
|
|
15504
|
+
noColor = Option14.Boolean("--no-color", false, {
|
|
15505
|
+
description: "Disable ANSI color codes."
|
|
15506
|
+
});
|
|
15306
15507
|
async execute() {
|
|
15307
15508
|
const verbs = buildVerbCatalog(this.cli);
|
|
15308
|
-
this.context.stdout
|
|
15509
|
+
const stdout = this.context.stdout;
|
|
15510
|
+
const ansi = ansiFor({ isTTY: stdout.isTTY === true, noColorFlag: this.noColor });
|
|
15511
|
+
this.context.stdout.write(renderCompactOverview(verbs, ansi));
|
|
15309
15512
|
return ExitCode.Ok;
|
|
15310
15513
|
}
|
|
15311
15514
|
};
|
|
@@ -15797,8 +16000,9 @@ function buildVirtualNode(extractor, emitted, emitter) {
|
|
|
15797
16000
|
if (emitted.frontmatter) node.frontmatter = emitted.frontmatter;
|
|
15798
16001
|
return node;
|
|
15799
16002
|
}
|
|
16003
|
+
var KNOWN_LINK_KINDS = ["invokes", "references", "mentions", "supersedes", "points"];
|
|
15800
16004
|
function validateLink(extractor, link, emitter) {
|
|
15801
|
-
const knownKinds =
|
|
16005
|
+
const knownKinds = KNOWN_LINK_KINDS;
|
|
15802
16006
|
if (!knownKinds.includes(link.kind)) {
|
|
15803
16007
|
const qualifiedId2 = `${extractor.pluginId}/${extractor.id}`;
|
|
15804
16008
|
emitter.emit(
|
|
@@ -15833,7 +16037,6 @@ function validateLink(extractor, link, emitter) {
|
|
|
15833
16037
|
const confidence = c ?? ConfidenceTier.MEDIUM;
|
|
15834
16038
|
return { ...link, confidence };
|
|
15835
16039
|
}
|
|
15836
|
-
var KNOWN_LINK_KINDS = ["invokes", "references", "mentions", "supersedes"];
|
|
15837
16040
|
function validateSignal(extractor, signal, emitter) {
|
|
15838
16041
|
const qualifiedId2 = qualifiedExtensionId(extractor.pluginId, extractor.id);
|
|
15839
16042
|
if (!Array.isArray(signal.candidates) || signal.candidates.length === 0) {
|
|
@@ -20443,6 +20646,13 @@ var PLUGINS_TEXTS = {
|
|
|
20443
20646
|
* the visible output stay in sync.
|
|
20444
20647
|
*/
|
|
20445
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}})",
|
|
20446
20656
|
listTipShow: "\nTip: `sm plugins show <id>` for kinds, versions, and per-extension status.\n",
|
|
20447
20657
|
/** Show command, built-in header (no version row, no path). */
|
|
20448
20658
|
detailHeaderBuiltIn: " {{glyph}} {{id}} {{source}} {{count}} extension{{plural}}\n",
|
|
@@ -20598,9 +20808,14 @@ function extensionRowFromBuiltIn(ext, plugin, resolveEnabled) {
|
|
|
20598
20808
|
enabled: resolveEnabled(qualifiedExtensionId(plugin.id, ext.id)),
|
|
20599
20809
|
description: ext.description ?? ""
|
|
20600
20810
|
};
|
|
20811
|
+
if (ext.stability !== void 0) row.stability = ext.stability;
|
|
20601
20812
|
if (ext.entry !== void 0) row.entry = ext.entry;
|
|
20602
20813
|
return row;
|
|
20603
20814
|
}
|
|
20815
|
+
function withStabilityTag(name, stability) {
|
|
20816
|
+
if (!stability || stability === "stable") return name;
|
|
20817
|
+
return name + tx(PLUGINS_TEXTS.stabilityTag, { stability: sanitizeForTerminal(stability) });
|
|
20818
|
+
}
|
|
20604
20819
|
function omitModule(key, value) {
|
|
20605
20820
|
if (key !== "module") return value;
|
|
20606
20821
|
if (value === null || typeof value !== "object") return value;
|
|
@@ -20687,9 +20902,10 @@ function renderListHuman(builtIns2, plugins, resolveEnabled, ansi) {
|
|
|
20687
20902
|
return lines.join("\n") + "\n" + PLUGINS_TEXTS.listTipShow;
|
|
20688
20903
|
}
|
|
20689
20904
|
function builtInToListRow(b) {
|
|
20690
|
-
const names = b.extensions.map(
|
|
20691
|
-
|
|
20692
|
-
|
|
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
|
+
});
|
|
20693
20909
|
return {
|
|
20694
20910
|
id: b.id,
|
|
20695
20911
|
enabled: b.enabled,
|
|
@@ -20702,7 +20918,7 @@ function pluginToListRow(p, resolveEnabled) {
|
|
|
20702
20918
|
const extensions = p.extensions ?? [];
|
|
20703
20919
|
const enabled = isLoaded ? extensions.length === 0 || extensions.some((e) => resolveEnabled(qualifiedExtensionId(p.id, e.id))) : false;
|
|
20704
20920
|
const names = extensions.map((e) => {
|
|
20705
|
-
const safeId = sanitizeForTerminal(e.id);
|
|
20921
|
+
const safeId = withStabilityTag(sanitizeForTerminal(e.id), e.stability);
|
|
20706
20922
|
return resolveEnabled(qualifiedExtensionId(p.id, e.id)) ? safeId : `${PLUGINS_TEXTS.rowGlyphOff} ${safeId}`;
|
|
20707
20923
|
});
|
|
20708
20924
|
const reason = p.status === "enabled" ? void 0 : sanitizeForTerminal(p.reason ?? "") || void 0;
|
|
@@ -20882,7 +21098,7 @@ function renderBuiltInDetail(b, ansi) {
|
|
|
20882
21098
|
const items = sorted.map((ext) => ({
|
|
20883
21099
|
glyph: ext.enabled ? ansi.green(PLUGINS_TEXTS.rowGlyphOk) : ansi.red(PLUGINS_TEXTS.rowGlyphOff),
|
|
20884
21100
|
kind: ext.kind,
|
|
20885
|
-
name: `${b.id}/${ext.id}
|
|
21101
|
+
name: withStabilityTag(`${b.id}/${ext.id}`, ext.stability)
|
|
20886
21102
|
}));
|
|
20887
21103
|
return tx(PLUGINS_TEXTS.detailHeaderBuiltIn, {
|
|
20888
21104
|
glyph,
|
|
@@ -20961,7 +21177,7 @@ function collectPluginExtensionItems(match, ansi) {
|
|
|
20961
21177
|
// status header above (✕ on the row).
|
|
20962
21178
|
glyph: ansi.green(PLUGINS_TEXTS.rowGlyphOk),
|
|
20963
21179
|
kind: sanitizeForTerminal(ext.kind),
|
|
20964
|
-
name: `${safePluginId}/${safeExtId}`,
|
|
21180
|
+
name: withStabilityTag(`${safePluginId}/${safeExtId}`, ext.stability),
|
|
20965
21181
|
version: sanitizeForTerminal(ext.version)
|
|
20966
21182
|
};
|
|
20967
21183
|
});
|
|
@@ -20995,6 +21211,7 @@ function renderBuiltInExtensionDetail(pluginId, ext, ansi) {
|
|
|
20995
21211
|
source: ansi.dim(PLUGINS_TEXTS.sourceBuiltIn)
|
|
20996
21212
|
});
|
|
20997
21213
|
const meta = { kind: ext.kind };
|
|
21214
|
+
if (ext.stability && ext.stability !== "stable") meta.stability = ext.stability;
|
|
20998
21215
|
if (ext.description) meta.description = ext.description;
|
|
20999
21216
|
if (ext.entry !== void 0) meta.entry = ext.entry;
|
|
21000
21217
|
return header + "\n" + renderExtensionFields(meta);
|
|
@@ -21012,7 +21229,7 @@ function renderUserExtensionDetail(pluginId, ext, ansi) {
|
|
|
21012
21229
|
version: ext.version,
|
|
21013
21230
|
entry: ext.entryPath
|
|
21014
21231
|
};
|
|
21015
|
-
if (
|
|
21232
|
+
if (ext.stability && ext.stability !== "stable") input.stability = ext.stability;
|
|
21016
21233
|
if (meta.description !== void 0) input.description = meta.description;
|
|
21017
21234
|
if (meta.preconditions !== void 0) input.preconditions = meta.preconditions;
|
|
21018
21235
|
return header + "\n" + renderExtensionFields(input);
|
|
@@ -21022,7 +21239,6 @@ function readInstanceMeta(instance) {
|
|
|
21022
21239
|
const obj = instance;
|
|
21023
21240
|
const out = {};
|
|
21024
21241
|
if (typeof obj["description"] === "string") out.description = obj["description"];
|
|
21025
|
-
if (typeof obj["stability"] === "string") out.stability = obj["stability"];
|
|
21026
21242
|
if (Array.isArray(obj["preconditions"])) {
|
|
21027
21243
|
out.preconditions = obj["preconditions"].filter(
|
|
21028
21244
|
(p) => typeof p === "string"
|
|
@@ -25711,6 +25927,7 @@ function buildBuiltInItems(resolveEnabled) {
|
|
|
25711
25927
|
version: ext.version,
|
|
25712
25928
|
enabled: resolveEnabled(qualified),
|
|
25713
25929
|
...ext.description ? { description: ext.description } : {},
|
|
25930
|
+
...ext.stability ? { stability: ext.stability } : {},
|
|
25714
25931
|
...extLocked ? { locked: true } : {}
|
|
25715
25932
|
};
|
|
25716
25933
|
});
|
|
@@ -25766,6 +25983,7 @@ function projectExtensionRows(plugin, resolveEnabled, pluginLocked) {
|
|
|
25766
25983
|
version: ext.version,
|
|
25767
25984
|
enabled: resolveEnabled(qualified),
|
|
25768
25985
|
...description ? { description } : {},
|
|
25986
|
+
...ext.stability ? { stability: ext.stability } : {},
|
|
25769
25987
|
...extLocked ? { locked: true } : {}
|
|
25770
25988
|
};
|
|
25771
25989
|
});
|
|
@@ -30251,4 +30469,4 @@ function resolveBareDefault() {
|
|
|
30251
30469
|
process.exit(ExitCode.Error);
|
|
30252
30470
|
}
|
|
30253
30471
|
//# sourceMappingURL=cli.js.map
|
|
30254
|
-
//# debugId=
|
|
30472
|
+
//# debugId=3118bb11-aad2-50b2-b70d-ed15c2f72a97
|