@skill-map/cli 0.57.0 → 0.59.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 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]="e6038423-ea97-5e66-b371-0916d382d819")}catch(e){}}();
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]="88ff98f5-2b47-5849-9567-922fc880f5bc")}catch(e){}}();
4
4
  import { existsSync as existsSync33 } from "fs";
5
5
  import { Builtins, Cli as Cli2 } from "clipanion";
6
6
 
@@ -250,7 +250,7 @@ function bucketByKind(kind, instance, bag) {
250
250
  // package.json
251
251
  var package_default = {
252
252
  name: "@skill-map/cli",
253
- version: "0.57.0",
253
+ version: "0.59.0",
254
254
  description: "skill-map reference implementation \u2014 kernel + CLI + adapters.",
255
255
  license: "MIT",
256
256
  type: "module",
@@ -1442,71 +1442,12 @@ var coreMarkdownProvider = {
1442
1442
  }
1443
1443
  };
1444
1444
 
1445
- // plugins/core/extractors/annotations/index.ts
1446
- var ID4 = "annotations";
1447
- var annotationsExtractor = {
1448
- id: ID4,
1449
- pluginId: CORE_PLUGIN_ID,
1450
- kind: "extractor",
1451
- description: "Turns the `supersedes` and `supersededBy` entries from a node's `.sm` sidecar into arrows between nodes in the graph. Example: `supersededBy: v1-skill.md` in a `.sm` sidecar draws an arrow to `v1-skill.md`.",
1452
- scope: "frontmatter",
1453
- extract(ctx) {
1454
- const sourcePath = ctx.node.path;
1455
- const seen = /* @__PURE__ */ new Set();
1456
- function emit(source, target, fieldPath) {
1457
- const key = `${source} ${target}`;
1458
- if (seen.has(key)) return;
1459
- seen.add(key);
1460
- ctx.emitSignal({
1461
- source,
1462
- scope: "sidecar",
1463
- fieldPath,
1464
- raw: target,
1465
- candidates: [
1466
- {
1467
- extractorId: ID4,
1468
- kind: "supersedes",
1469
- target,
1470
- confidence: 1,
1471
- rationale: "structured sidecar annotation"
1472
- }
1473
- ]
1474
- });
1475
- }
1476
- const ann = pickAnnotations(ctx.node);
1477
- if (ann) processBlock(ann, sourcePath, emit);
1478
- }
1479
- };
1480
- function processBlock(block, sourcePath, emit) {
1481
- const supersedes = stringArray(block["supersedes"]);
1482
- for (let i = 0; i < supersedes.length; i += 1) {
1483
- emit(sourcePath, supersedes[i], ["annotations", "supersedes", String(i)]);
1484
- }
1485
- const supersededBy = block["supersededBy"];
1486
- if (typeof supersededBy === "string" && supersededBy.length > 0) {
1487
- emit(supersededBy, sourcePath, ["annotations", "supersededBy"]);
1488
- }
1489
- }
1490
- function pickAnnotations(node) {
1491
- const sidecar = node.sidecar;
1492
- if (!sidecar || sidecar.present !== true) return null;
1493
- const ann = sidecar.annotations;
1494
- if (ann && typeof ann === "object" && !Array.isArray(ann)) {
1495
- return ann;
1496
- }
1497
- return null;
1498
- }
1499
- function stringArray(value) {
1500
- if (!Array.isArray(value)) return [];
1501
- return value.filter((v) => typeof v === "string" && v.length > 0);
1502
- }
1503
-
1504
1445
  // plugins/core/extractors/backtick-path/index.ts
1505
1446
  import { posix as pathPosix2 } from "path";
1506
- var ID5 = "backtick-path";
1447
+ var ID4 = "backtick-path";
1507
1448
  var PATH_RE = /(?<![\w/:.-])(?:\.{1,2}\/)?[\w][\w.-]*(?:\/[\w.-]+)*\.md\b(?![\w/])/g;
1508
1449
  var backtickPathExtractor = {
1509
- id: ID5,
1450
+ id: ID4,
1510
1451
  pluginId: CORE_PLUGIN_ID,
1511
1452
  kind: "extractor",
1512
1453
  description: "Turns relative .md paths written inside code spans and fenced blocks into arrows between nodes in the graph. Example: a backticked `references/rules.md` path draws an arrow to that file.",
@@ -1531,7 +1472,7 @@ var backtickPathExtractor = {
1531
1472
  raw: original,
1532
1473
  candidates: [
1533
1474
  {
1534
- extractorId: ID5,
1475
+ extractorId: ID4,
1535
1476
  kind: "points",
1536
1477
  target: resolved,
1537
1478
  // 0.85: a strong file signal with one degree of inference,
@@ -1560,7 +1501,7 @@ function resolveTarget(sourceDir, raw) {
1560
1501
  }
1561
1502
 
1562
1503
  // plugins/core/extractors/external-url-counter/index.ts
1563
- var ID6 = "external-url-counter";
1504
+ var ID5 = "external-url-counter";
1564
1505
  var count2 = {
1565
1506
  slot: "card.footer.left",
1566
1507
  icon: "pi-link",
@@ -1580,7 +1521,7 @@ var settings = {
1580
1521
  var URL_RE = /https?:\/\/[^\s<>"'`)\]]+/g;
1581
1522
  var TRAILING_PUNCT = /[.,;:!?]+$/;
1582
1523
  var externalUrlCounterExtractor = {
1583
- id: ID6,
1524
+ id: ID5,
1584
1525
  pluginId: CORE_PLUGIN_ID,
1585
1526
  kind: "extractor",
1586
1527
  description: "Counts the distinct external URLs in a node's body and shows the count on the card. Example: a body linking `https://example.com` and `https://docs.rs` shows a count of 2.",
@@ -1632,7 +1573,7 @@ var externalUrlCounterExtractor = {
1632
1573
  raw: original,
1633
1574
  candidates: [
1634
1575
  {
1635
- extractorId: ID6,
1576
+ extractorId: ID5,
1636
1577
  kind: "references",
1637
1578
  target: normalized.href,
1638
1579
  confidence: 0.3,
@@ -1674,11 +1615,11 @@ function normalizeUrl(raw) {
1674
1615
 
1675
1616
  // plugins/core/extractors/markdown-link/index.ts
1676
1617
  import { posix as pathPosix3 } from "path";
1677
- var ID7 = "markdown-link";
1618
+ var ID6 = "markdown-link";
1678
1619
  var LINK_RE = /(?<!!)\[([^\]]*)\]\(([^)\s]+)(?:\s+"[^"]*")?\)/g;
1679
1620
  var URL_SCHEME_RE = /^[a-z][a-z0-9+.-]*:/i;
1680
1621
  var markdownLinkExtractor = {
1681
- id: ID7,
1622
+ id: ID6,
1682
1623
  pluginId: CORE_PLUGIN_ID,
1683
1624
  kind: "extractor",
1684
1625
  description: "Turns markdown links (`[text](path)`) in a node's body into arrows between nodes in the graph. Example: `[the guide](docs/guide.md)` draws an arrow to `docs/guide.md`.",
@@ -1703,7 +1644,7 @@ var markdownLinkExtractor = {
1703
1644
  raw: match[0],
1704
1645
  candidates: [
1705
1646
  {
1706
- extractorId: ID7,
1647
+ extractorId: ID6,
1707
1648
  kind: "references",
1708
1649
  target: resolved,
1709
1650
  // 0.95: the `[text](path)` syntax is unambiguous (the spec's
@@ -1738,10 +1679,10 @@ function resolveTarget2(sourceDir, raw) {
1738
1679
  }
1739
1680
 
1740
1681
  // plugins/core/extractors/mcp-tools/index.ts
1741
- var ID8 = "mcp-tools";
1682
+ var ID7 = "mcp-tools";
1742
1683
  var MCP_PATTERN = /^mcp__([a-z0-9][a-z0-9_-]*)__[a-z0-9_-]+$/i;
1743
1684
  var mcpToolsExtractor = {
1744
- id: ID8,
1685
+ id: ID7,
1745
1686
  pluginId: CORE_PLUGIN_ID,
1746
1687
  kind: "extractor",
1747
1688
  description: "Turns `tools: [mcp__<server>__<tool>]` entries in a node's frontmatter into an MCP node per unique server and an arrow from the source to each one. Example: `tools: [mcp__github__create_pr]` adds an `mcp://github` node and an arrow to it.",
@@ -1772,7 +1713,7 @@ var mcpToolsExtractor = {
1772
1713
  raw: `mcp__${server}__*`,
1773
1714
  candidates: [
1774
1715
  {
1775
- extractorId: ID8,
1716
+ extractorId: ID7,
1776
1717
  kind: "references",
1777
1718
  target: mcpPath,
1778
1719
  confidence: 0.85,
@@ -1841,10 +1782,10 @@ var ANNOTATION_FIELD_UNKNOWN_TEXTS = {
1841
1782
  };
1842
1783
 
1843
1784
  // plugins/core/analyzers/annotation-field-unknown/index.ts
1844
- var ID9 = "annotation-field-unknown";
1785
+ var ID8 = "annotation-field-unknown";
1845
1786
  var RESERVED_ROOT_BLOCKS = /* @__PURE__ */ new Set(["identity", "annotations", "settings", "audit"]);
1846
1787
  var annotationFieldUnknownAnalyzer = {
1847
- id: ID9,
1788
+ id: ID8,
1848
1789
  pluginId: CORE_PLUGIN_ID,
1849
1790
  kind: "analyzer",
1850
1791
  description: "Flags typos or unrecognized keys in sidecars (`.sm`).",
@@ -1871,10 +1812,6 @@ var annotationFieldUnknownAnalyzer = {
1871
1812
  const rootKeys = indexRootContributions(contributions);
1872
1813
  const knownPluginIds = collectPluginIds(contributions);
1873
1814
  const issues = [];
1874
- const perNode = /* @__PURE__ */ new Map();
1875
- const bump2 = (nodePath) => {
1876
- perNode.set(nodePath, (perNode.get(nodePath) ?? 0) + 1);
1877
- };
1878
1815
  for (const node of ctx.nodes) {
1879
1816
  const root = sidecarRoots.get(node.path);
1880
1817
  if (!root) continue;
@@ -1883,7 +1820,7 @@ var annotationFieldUnknownAnalyzer = {
1883
1820
  for (const key of Object.keys(annotations)) {
1884
1821
  if (!knownAnnotationKeys.has(key)) {
1885
1822
  issues.push({
1886
- analyzerId: ID9,
1823
+ analyzerId: ID8,
1887
1824
  severity: "warn",
1888
1825
  nodeIds: [node.path],
1889
1826
  message: formatFinding({
@@ -1892,7 +1829,6 @@ var annotationFieldUnknownAnalyzer = {
1892
1829
  }),
1893
1830
  data: { surface: "annotations", key }
1894
1831
  });
1895
- bump2(node.path);
1896
1832
  }
1897
1833
  }
1898
1834
  }
@@ -1910,7 +1846,7 @@ var annotationFieldUnknownAnalyzer = {
1910
1846
  if (validator(value)) continue;
1911
1847
  const errors = (validator.errors ?? []).map((e) => `${e.instancePath || "(root)"} ${e.message ?? e.keyword}`).join("; ");
1912
1848
  issues.push({
1913
- analyzerId: ID9,
1849
+ analyzerId: ID8,
1914
1850
  severity: "warn",
1915
1851
  nodeIds: [node.path],
1916
1852
  message: formatFinding({
@@ -1921,12 +1857,11 @@ var annotationFieldUnknownAnalyzer = {
1921
1857
  }),
1922
1858
  data: { surface: "plugin-namespace", pluginId: key, key: contribKey }
1923
1859
  });
1924
- bump2(node.path);
1925
1860
  }
1926
1861
  continue;
1927
1862
  }
1928
1863
  issues.push({
1929
- analyzerId: ID9,
1864
+ analyzerId: ID8,
1930
1865
  severity: "warn",
1931
1866
  nodeIds: [node.path],
1932
1867
  message: formatFinding({
@@ -1935,10 +1870,8 @@ var annotationFieldUnknownAnalyzer = {
1935
1870
  }),
1936
1871
  data: { surface: "root", key }
1937
1872
  });
1938
- bump2(node.path);
1939
1873
  }
1940
1874
  }
1941
- void perNode;
1942
1875
  return issues;
1943
1876
  }
1944
1877
  };
@@ -2000,9 +1933,9 @@ var ANNOTATION_ORPHAN_TEXTS = {
2000
1933
  };
2001
1934
 
2002
1935
  // plugins/core/analyzers/annotation-orphan/index.ts
2003
- var ID10 = "annotation-orphan";
1936
+ var ID9 = "annotation-orphan";
2004
1937
  var annotationOrphanAnalyzer = {
2005
- id: ID10,
1938
+ id: ID9,
2006
1939
  pluginId: CORE_PLUGIN_ID,
2007
1940
  kind: "analyzer",
2008
1941
  description: "Flags sidecars (`.sm`) whose `.md` file no longer exists.",
@@ -2014,7 +1947,7 @@ var annotationOrphanAnalyzer = {
2014
1947
  for (const orphan of orphans) {
2015
1948
  const expectedMdRelative = orphan.relativePath.endsWith(".sm") ? `${orphan.relativePath.slice(0, -".sm".length)}.md` : `${orphan.relativePath}.md`;
2016
1949
  issues.push({
2017
- analyzerId: ID10,
1950
+ analyzerId: ID9,
2018
1951
  severity: "warn",
2019
1952
  nodeIds: [expectedMdRelative],
2020
1953
  message: formatFinding({
@@ -2057,7 +1990,7 @@ var ANNOTATION_STALE_TEXTS = {
2057
1990
  };
2058
1991
 
2059
1992
  // plugins/core/analyzers/annotation-stale/index.ts
2060
- var ID11 = "annotation-stale";
1993
+ var ID10 = "annotation-stale";
2061
1994
  var staleIcon = {
2062
1995
  slot: "card.footer.right",
2063
1996
  icon: "pi-clock",
@@ -2070,10 +2003,14 @@ var staleBadge = {
2070
2003
  priority: 20
2071
2004
  };
2072
2005
  var annotationStaleAnalyzer = {
2073
- id: ID11,
2006
+ id: ID10,
2074
2007
  pluginId: CORE_PLUGIN_ID,
2075
2008
  kind: "analyzer",
2076
2009
  description: "Marks sidecars (`.sm`) that are out of date with their `.md`.",
2010
+ // Ships experimental (disabled by default, Decision #128), gated as a
2011
+ // unit with the `core/node-bump` action that resolves the drift it
2012
+ // reports.
2013
+ stability: "experimental",
2077
2014
  mode: "deterministic",
2078
2015
  // The natural fix is to bump the node: refreshes the sidecar hashes,
2079
2016
  // increments `annotations.version`, and stamps the audit block. The
@@ -2086,7 +2023,7 @@ var annotationStaleAnalyzer = {
2086
2023
  const status = staleStatus(node.sidecar);
2087
2024
  if (status === null) continue;
2088
2025
  issues.push({
2089
- analyzerId: ID11,
2026
+ analyzerId: ID10,
2090
2027
  severity: "info",
2091
2028
  nodeIds: [node.path],
2092
2029
  message: formatFinding({ body: messageFor(status) }),
@@ -2132,9 +2069,9 @@ function tooltipFor(status) {
2132
2069
  }
2133
2070
 
2134
2071
  // plugins/core/analyzers/contribution-orphan/index.ts
2135
- var ID12 = "contribution-orphan";
2072
+ var ID11 = "contribution-orphan";
2136
2073
  var contributionOrphanAnalyzer = {
2137
- id: ID12,
2074
+ id: ID11,
2138
2075
  pluginId: CORE_PLUGIN_ID,
2139
2076
  kind: "analyzer",
2140
2077
  description: "Warns about plugin data referencing nodes renamed or deleted in the latest scan.",
@@ -2166,12 +2103,12 @@ var EXTRACTOR_COLLISION_TEXTS = {
2166
2103
  };
2167
2104
 
2168
2105
  // plugins/core/analyzers/extractor-collision/index.ts
2169
- var ID13 = "extractor-collision";
2106
+ var ID12 = "extractor-collision";
2170
2107
  function signalLines(signal) {
2171
2108
  return signal.range && typeof signal.range.line === "number" ? [signal.range.line] : void 0;
2172
2109
  }
2173
2110
  var extractorCollisionAnalyzer = {
2174
- id: ID13,
2111
+ id: ID12,
2175
2112
  pluginId: CORE_PLUGIN_ID,
2176
2113
  kind: "analyzer",
2177
2114
  description: "Reports when two extractors detect something at the same span of body text and the resolver drops one.",
@@ -2195,7 +2132,7 @@ function makeIssue(signal) {
2195
2132
  const loserRange = signal.range ? `${signal.range.start}-${signal.range.end}` : "unknown";
2196
2133
  const winnerRange = `${winner.range.start}-${winner.range.end}`;
2197
2134
  return {
2198
- analyzerId: ID13,
2135
+ analyzerId: ID12,
2199
2136
  severity: "warn",
2200
2137
  nodeIds: [signal.source],
2201
2138
  message: formatFinding({
@@ -2239,7 +2176,7 @@ var ISSUE_COUNTER_TEXTS = {
2239
2176
  };
2240
2177
 
2241
2178
  // plugins/core/analyzers/issue-counter/index.ts
2242
- var ID14 = "issue-counter";
2179
+ var ID13 = "issue-counter";
2243
2180
  var warnCount = {
2244
2181
  slot: "card.footer.right",
2245
2182
  icon: "pi-exclamation-triangle",
@@ -2275,7 +2212,7 @@ function emitTierChips(ctx, ref, severity, counts, singleTooltip, manyTooltip) {
2275
2212
  }
2276
2213
  }
2277
2214
  var issueCounterAnalyzer = {
2278
- id: ID14,
2215
+ id: ID13,
2279
2216
  pluginId: CORE_PLUGIN_ID,
2280
2217
  kind: "analyzer",
2281
2218
  description: "Emits one aggregate severity chip per node (error + warn counts) from the live issue accumulator.",
@@ -2338,7 +2275,7 @@ var LINK_COUNTER_TEXTS = {
2338
2275
  };
2339
2276
 
2340
2277
  // plugins/core/analyzers/link-counter/index.ts
2341
- var ID15 = "link-counter";
2278
+ var ID14 = "link-counter";
2342
2279
  var linksIn = {
2343
2280
  slot: "card.footer.left",
2344
2281
  icon: "pi-download",
@@ -2354,7 +2291,7 @@ var linksOut = {
2354
2291
  priority: 20
2355
2292
  };
2356
2293
  var linkCounterAnalyzer = {
2357
- id: ID15,
2294
+ id: ID14,
2358
2295
  pluginId: CORE_PLUGIN_ID,
2359
2296
  kind: "analyzer",
2360
2297
  description: "Counts incoming and outgoing links per node.",
@@ -2419,10 +2356,10 @@ var LINK_KIND_CONFLICT_TEXTS = {
2419
2356
  };
2420
2357
 
2421
2358
  // plugins/core/analyzers/link-kind-conflict/index.ts
2422
- var ID16 = "link-kind-conflict";
2359
+ var ID15 = "link-kind-conflict";
2423
2360
  var NON_CONFLICTING_KINDS = /* @__PURE__ */ new Set(["points"]);
2424
2361
  var linkKindConflictAnalyzer = {
2425
- id: ID16,
2362
+ id: ID15,
2426
2363
  pluginId: CORE_PLUGIN_ID,
2427
2364
  kind: "analyzer",
2428
2365
  description: "Flags conflicting arrow meanings between extractors (e.g. `references` vs `invokes`).",
@@ -2470,7 +2407,7 @@ var linkKindConflictAnalyzer = {
2470
2407
  const [source, target] = key.split("\0");
2471
2408
  const kindList = variants.map((v) => v.kind).join(" / ");
2472
2409
  issues.push({
2473
- analyzerId: ID16,
2410
+ analyzerId: ID15,
2474
2411
  severity: "warn",
2475
2412
  nodeIds: [source, target],
2476
2413
  message: formatFinding({
@@ -2509,9 +2446,9 @@ var LINK_SELF_LOOP_TEXTS = {
2509
2446
  };
2510
2447
 
2511
2448
  // plugins/core/analyzers/link-self-loop/index.ts
2512
- var ID17 = "link-self-loop";
2449
+ var ID16 = "link-self-loop";
2513
2450
  var linkSelfLoopAnalyzer = {
2514
- id: ID17,
2451
+ id: ID16,
2515
2452
  pluginId: CORE_PLUGIN_ID,
2516
2453
  kind: "analyzer",
2517
2454
  description: "Flags links whose source is also their own resolved target (e.g. a body heading like `# /deploy` inside the file that defines `/deploy`).",
@@ -2521,7 +2458,7 @@ var linkSelfLoopAnalyzer = {
2521
2458
  for (const link of ctx.links) {
2522
2459
  if (!isSelfLoop(link)) continue;
2523
2460
  issues.push({
2524
- analyzerId: ID17,
2461
+ analyzerId: ID16,
2525
2462
  severity: "warn",
2526
2463
  nodeIds: [link.source],
2527
2464
  message: formatFinding({
@@ -2553,9 +2490,9 @@ var NAME_COLLISION_TEXTS = {
2553
2490
  };
2554
2491
 
2555
2492
  // plugins/core/analyzers/name-collision/index.ts
2556
- var ID18 = "name-collision";
2493
+ var ID17 = "name-collision";
2557
2494
  var nameCollisionAnalyzer = {
2558
- id: ID18,
2495
+ id: ID17,
2559
2496
  pluginId: CORE_PLUGIN_ID,
2560
2497
  kind: "analyzer",
2561
2498
  mode: "deterministic",
@@ -2569,7 +2506,7 @@ var nameCollisionAnalyzer = {
2569
2506
  for (const [name, claims] of collisions) {
2570
2507
  const paths = claims.map((c) => c.path);
2571
2508
  issues.push({
2572
- analyzerId: ID18,
2509
+ analyzerId: ID17,
2573
2510
  severity: "error",
2574
2511
  nodeIds: paths,
2575
2512
  message: formatFinding({
@@ -2619,9 +2556,9 @@ var NAME_RESERVED_TEXTS = {
2619
2556
  };
2620
2557
 
2621
2558
  // plugins/core/analyzers/name-reserved/index.ts
2622
- var ID19 = "name-reserved";
2559
+ var ID18 = "name-reserved";
2623
2560
  var nameReservedAnalyzer = {
2624
- id: ID19,
2561
+ id: ID18,
2625
2562
  pluginId: CORE_PLUGIN_ID,
2626
2563
  kind: "analyzer",
2627
2564
  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.",
@@ -2639,7 +2576,7 @@ var nameReservedAnalyzer = {
2639
2576
  const node = byPath3.get(path);
2640
2577
  if (!node) continue;
2641
2578
  issues.push({
2642
- analyzerId: ID19,
2579
+ analyzerId: ID18,
2643
2580
  severity: "warn",
2644
2581
  nodeIds: [node.path],
2645
2582
  message: formatFinding({
@@ -2661,7 +2598,7 @@ var nameReservedAnalyzer = {
2661
2598
  adjust(link, { kind: "delta", value: -RESERVED_PENALTY });
2662
2599
  }
2663
2600
  issues.push({
2664
- analyzerId: ID19,
2601
+ analyzerId: ID18,
2665
2602
  severity: "warn",
2666
2603
  nodeIds: [link.source],
2667
2604
  message: formatFinding({
@@ -2688,26 +2625,32 @@ var nameReservedAnalyzer = {
2688
2625
  }
2689
2626
  };
2690
2627
 
2628
+ // plugins/core/stability.ts
2629
+ var STABILITY_VALUES = ["experimental", "stable", "deprecated"];
2630
+ function isStability(value) {
2631
+ return value === "experimental" || value === "stable" || value === "deprecated";
2632
+ }
2633
+ function readEffectiveStability(node) {
2634
+ const fromAnn = node.sidecar?.annotations?.["stability"];
2635
+ if (isStability(fromAnn)) return fromAnn;
2636
+ const legacy = readLegacyMetadataStability(node.frontmatter);
2637
+ return isStability(legacy) ? legacy : null;
2638
+ }
2639
+ function readLegacyMetadataStability(fm) {
2640
+ if (!fm) return void 0;
2641
+ const meta = fm["metadata"];
2642
+ if (!meta || typeof meta !== "object" || Array.isArray(meta)) return void 0;
2643
+ return meta["stability"];
2644
+ }
2645
+
2691
2646
  // plugins/core/analyzers/node-stability/text.ts
2692
2647
  var NODE_STABILITY_TEXTS = {
2693
- /** Issue body (`<what>; <why>`) for an experimental-marked node. */
2694
- experimental: "Marked experimental; API may change",
2695
2648
  /** Issue body (`<what>; <why>`) for a deprecated-marked node. */
2696
- deprecated: "Marked deprecated; avoid in new code",
2697
- /** Label of the inspector action button that sets the lifecycle stage. */
2698
- setLabel: "Set stability",
2699
- /** Prompt label for the enum-pick stability input. */
2700
- promptLabel: "Stability",
2701
- /** Prompt option label for the `experimental` stage. */
2702
- optionExperimental: "Experimental",
2703
- /** Prompt option label for the `stable` stage. */
2704
- optionStable: "Stable",
2705
- /** Prompt option label for the `deprecated` stage. */
2706
- optionDeprecated: "Deprecated"
2649
+ deprecated: "Marked deprecated; avoid using it"
2707
2650
  };
2708
2651
 
2709
2652
  // plugins/core/analyzers/node-stability/index.ts
2710
- var ID20 = "node-stability";
2653
+ var ID19 = "node-stability";
2711
2654
  var EXPERIMENTAL_TOOLTIP = "Experimental: API may change";
2712
2655
  var DEPRECATED_TOOLTIP = "Deprecated: avoid in new code";
2713
2656
  var experimental = {
@@ -2724,36 +2667,22 @@ var deprecated = {
2724
2667
  emitWhenEmpty: false,
2725
2668
  priority: 10
2726
2669
  };
2727
- var setStabilityButton = {
2728
- slot: "inspector.action.button",
2729
- priority: 15
2730
- };
2731
2670
  var nodeStabilityAnalyzer = {
2732
- id: ID20,
2671
+ id: ID19,
2733
2672
  pluginId: CORE_PLUGIN_ID,
2734
2673
  kind: "analyzer",
2735
- description: "Reports a node's stability stage (`experimental`, `deprecated`) on the card.",
2674
+ description: "Surfaces a node's stability stage on the card: `deprecated` as a chip plus a finding, `experimental` as a chip only; `stable` and unset stay silent.",
2736
2675
  mode: "deterministic",
2737
- ui: { experimental, deprecated, setStabilityButton },
2676
+ ui: { experimental, deprecated },
2738
2677
  evaluate(ctx) {
2739
2678
  const issues = [];
2740
2679
  for (const node of ctx.nodes) {
2741
- const stability = readStability(node);
2742
- if (node.sidecar?.present === true) {
2743
- emitSetStabilityButton(ctx, node.path, stability ?? "stable");
2744
- }
2680
+ const stability = readEffectiveStability(node);
2745
2681
  if (stability === "experimental") {
2746
2682
  ctx.emitContribution(node.path, experimental, {
2747
2683
  value: 0,
2748
2684
  tooltip: EXPERIMENTAL_TOOLTIP
2749
2685
  });
2750
- issues.push({
2751
- analyzerId: ID20,
2752
- severity: "info",
2753
- nodeIds: [node.path],
2754
- message: formatFinding({ body: tx(NODE_STABILITY_TEXTS.experimental) }),
2755
- data: { stability }
2756
- });
2757
2686
  } else if (stability === "deprecated") {
2758
2687
  ctx.emitContribution(node.path, deprecated, {
2759
2688
  value: 0,
@@ -2761,7 +2690,7 @@ var nodeStabilityAnalyzer = {
2761
2690
  severity: "warn"
2762
2691
  });
2763
2692
  issues.push({
2764
- analyzerId: ID20,
2693
+ analyzerId: ID19,
2765
2694
  severity: "warn",
2766
2695
  nodeIds: [node.path],
2767
2696
  message: formatFinding({ body: tx(NODE_STABILITY_TEXTS.deprecated) }),
@@ -2772,93 +2701,6 @@ var nodeStabilityAnalyzer = {
2772
2701
  return issues;
2773
2702
  }
2774
2703
  };
2775
- function readStability(node) {
2776
- const fromAnn = node.sidecar?.annotations?.["stability"];
2777
- if (isStability(fromAnn)) return fromAnn;
2778
- const legacy = readLegacyMetadataStability(node.frontmatter);
2779
- return isStability(legacy) ? legacy : null;
2780
- }
2781
- function readLegacyMetadataStability(fm) {
2782
- if (!fm) return void 0;
2783
- const meta = fm["metadata"];
2784
- if (!meta || typeof meta !== "object" || Array.isArray(meta)) return void 0;
2785
- return meta["stability"];
2786
- }
2787
- function isStability(value) {
2788
- return value === "experimental" || value === "deprecated" || value === "stable";
2789
- }
2790
- function emitSetStabilityButton(ctx, nodePath, current) {
2791
- ctx.emitContribution(nodePath, setStabilityButton, {
2792
- actionId: "core/node-set-stability",
2793
- label: NODE_STABILITY_TEXTS.setLabel,
2794
- icon: "pi-flag",
2795
- enabled: true,
2796
- prompt: {
2797
- inputType: "enum-pick",
2798
- paramKey: "stability",
2799
- label: NODE_STABILITY_TEXTS.promptLabel,
2800
- options: [
2801
- { value: "experimental", label: NODE_STABILITY_TEXTS.optionExperimental },
2802
- { value: "stable", label: NODE_STABILITY_TEXTS.optionStable },
2803
- { value: "deprecated", label: NODE_STABILITY_TEXTS.optionDeprecated }
2804
- ],
2805
- defaultValue: current
2806
- }
2807
- });
2808
- }
2809
-
2810
- // plugins/core/analyzers/node-superseded/text.ts
2811
- var NODE_SUPERSEDED_TEXTS = {
2812
- /**
2813
- * Diagnosis body (`<what>; <why>`). The shared `formatFinding` helper
2814
- * wraps it with the backtick subject (the superseding artifact); the
2815
- * superseded node is the finding's own node, so its path never appears.
2816
- */
2817
- message: "Superseded; a newer node supersedes this one"
2818
- };
2819
-
2820
- // plugins/core/analyzers/node-superseded/index.ts
2821
- var ID21 = "node-superseded";
2822
- var nodeSupersededAnalyzer = {
2823
- id: ID21,
2824
- pluginId: CORE_PLUGIN_ID,
2825
- kind: "analyzer",
2826
- description: "Marks nodes replaced by a newer one via `supersededBy`.",
2827
- // Part of the experimental supersession feature: ships disabled by
2828
- // default alongside the declarer (`core/supersede` button +
2829
- // `core/node-supersede` action). With the declarer off by default a
2830
- // user rarely produces `supersededBy` data, so surfacing it stays
2831
- // experimental too; the operator opts the whole family in together.
2832
- stability: "experimental",
2833
- mode: "deterministic",
2834
- evaluate(ctx) {
2835
- const issues = [];
2836
- for (const node of ctx.nodes) {
2837
- const supersededBy = pickSupersededBy(node);
2838
- if (supersededBy === null) continue;
2839
- issues.push({
2840
- analyzerId: ID21,
2841
- severity: "info",
2842
- nodeIds: [node.path],
2843
- message: formatFinding({
2844
- subject: supersededBy,
2845
- body: tx(NODE_SUPERSEDED_TEXTS.message)
2846
- }),
2847
- data: { supersededBy }
2848
- });
2849
- }
2850
- return issues;
2851
- }
2852
- };
2853
- function pickSupersededBy(node) {
2854
- const sidecar = node.sidecar;
2855
- if (!sidecar || sidecar.present !== true) return null;
2856
- const ann = sidecar.annotations;
2857
- if (!ann || typeof ann !== "object" || Array.isArray(ann)) return null;
2858
- const value = ann["supersededBy"];
2859
- if (typeof value !== "string" || value.length === 0) return null;
2860
- return value;
2861
- }
2862
2704
 
2863
2705
  // plugins/core/analyzers/reference-broken/index.ts
2864
2706
  import { resolve as resolve2 } from "path";
@@ -2890,7 +2732,6 @@ var REFERENCE_BROKEN_TEXTS = {
2890
2732
  references: "reference",
2891
2733
  mentions: "mention",
2892
2734
  invokes: "invocation",
2893
- supersedes: "supersession",
2894
2735
  points: "pointer"
2895
2736
  },
2896
2737
  kindLabelFallback: "{{kind}} link",
@@ -2901,9 +2742,9 @@ var REFERENCE_BROKEN_TEXTS = {
2901
2742
  };
2902
2743
 
2903
2744
  // plugins/core/analyzers/reference-broken/index.ts
2904
- var ID22 = "reference-broken";
2745
+ var ID20 = "reference-broken";
2905
2746
  var referenceBrokenAnalyzer = {
2906
- id: ID22,
2747
+ id: ID20,
2907
2748
  pluginId: CORE_PLUGIN_ID,
2908
2749
  kind: "analyzer",
2909
2750
  description: "Flags arrows pointing at a node not part of the current scan.",
@@ -2946,7 +2787,7 @@ function penalizeBrokenConfidence(adjust, link) {
2946
2787
  }
2947
2788
  function buildIssue(link) {
2948
2789
  return {
2949
- analyzerId: ID22,
2790
+ analyzerId: ID20,
2950
2791
  // `error`, not `warn`: a link whose target is not in the scan is a
2951
2792
  // structural defect the operator must notice, and the card chip
2952
2793
  // paints `danger` (red) to match. Per the chip-vs-issue policy in
@@ -3010,9 +2851,9 @@ var REFERENCE_REDUNDANT_TEXTS = {
3010
2851
  };
3011
2852
 
3012
2853
  // plugins/core/analyzers/reference-redundant/index.ts
3013
- var ID23 = "reference-redundant";
2854
+ var ID21 = "reference-redundant";
3014
2855
  var referenceRedundantAnalyzer = {
3015
- id: ID23,
2856
+ id: ID21,
3016
2857
  pluginId: CORE_PLUGIN_ID,
3017
2858
  kind: "analyzer",
3018
2859
  description: "Flags when one node references the same target through two or more different links (e.g. a markdown link plus a `references:` entry).",
@@ -3035,7 +2876,7 @@ var referenceRedundantAnalyzer = {
3035
2876
  const [source, resolvedTarget] = key.split("\0");
3036
2877
  const flat = flattenOccurrences(links);
3037
2878
  issues.push({
3038
- analyzerId: ID23,
2879
+ analyzerId: ID21,
3039
2880
  severity: "info",
3040
2881
  nodeIds: [source],
3041
2882
  message: formatFinding({
@@ -3380,9 +3221,9 @@ var SCHEMA_VIOLATION_TEXTS = {
3380
3221
  };
3381
3222
 
3382
3223
  // plugins/core/analyzers/schema-violation/index.ts
3383
- var ID24 = "schema-violation";
3224
+ var ID22 = "schema-violation";
3384
3225
  var schemaViolationAnalyzer = {
3385
- id: ID24,
3226
+ id: ID22,
3386
3227
  pluginId: CORE_PLUGIN_ID,
3387
3228
  kind: "analyzer",
3388
3229
  description: "Flags nodes or links that violate the project schemas.",
@@ -3434,7 +3275,7 @@ function collectNodeFindings(v, node, out) {
3434
3275
  const result = v.validate("node", toNodeForSchema(node));
3435
3276
  if (result.ok) return;
3436
3277
  out.push({
3437
- analyzerId: ID24,
3278
+ analyzerId: ID22,
3438
3279
  severity: "error",
3439
3280
  nodeIds: [node.path],
3440
3281
  message: formatFinding({
@@ -3463,7 +3304,7 @@ function collectFrontmatterBaseFindings(node, out, kernelFlagged) {
3463
3304
  if (isMissingStringField(fm, "description")) missing.push("description");
3464
3305
  if (missing.length === 0) return;
3465
3306
  out.push({
3466
- analyzerId: ID24,
3307
+ analyzerId: ID22,
3467
3308
  // `warn` (not `error`) so the default `sm scan` exit code stays
3468
3309
  // 0 even when nodes are missing frontmatter base fields. Strict
3469
3310
  // mode (`sm scan --strict`) still escalates to exit 1. Matches
@@ -3486,7 +3327,7 @@ function collectLinkFindings(v, link, out) {
3486
3327
  const result = v.validate("link", toLinkForSchema(link));
3487
3328
  if (result.ok) return;
3488
3329
  out.push({
3489
- analyzerId: ID24,
3330
+ analyzerId: ID22,
3490
3331
  severity: "error",
3491
3332
  nodeIds: [link.source],
3492
3333
  message: formatFinding({
@@ -3555,13 +3396,13 @@ var ASCII_FORMATTER_TEXTS = {
3555
3396
  };
3556
3397
 
3557
3398
  // plugins/core/formatters/ascii/index.ts
3558
- var ID25 = "ascii";
3399
+ var ID23 = "ascii";
3559
3400
  var KIND_ORDER = ["agent", "command", "skill", "markdown"];
3560
3401
  var asciiFormatter = {
3561
- id: ID25,
3402
+ id: ID23,
3562
3403
  pluginId: CORE_PLUGIN_ID,
3563
3404
  kind: "formatter",
3564
- formatId: ID25,
3405
+ formatId: ID23,
3565
3406
  description: "Renders the scan as plain text in three sections: nodes (grouped by kind), arrows, and issues. Used by `sm scan --format ascii`.",
3566
3407
  // ASCII tree formatter, header + per-kind sections + per-issue
3567
3408
  // section. Each section iterates and renders; splitting per section
@@ -3655,13 +3496,13 @@ function renderSection(out, kind, group) {
3655
3496
  }
3656
3497
 
3657
3498
  // plugins/core/formatters/json/index.ts
3658
- var ID26 = "json";
3499
+ var ID24 = "json";
3659
3500
  var jsonFormatter = {
3660
- id: ID26,
3501
+ id: ID24,
3661
3502
  pluginId: CORE_PLUGIN_ID,
3662
3503
  kind: "formatter",
3663
3504
  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`.",
3664
- formatId: ID26,
3505
+ formatId: ID24,
3665
3506
  format(ctx) {
3666
3507
  if (ctx.scanResult !== void 0) {
3667
3508
  return JSON.stringify(ctx.scanResult);
@@ -3808,22 +3649,28 @@ var BUMP_TEXTS = {
3808
3649
  };
3809
3650
 
3810
3651
  // plugins/core/actions/node-bump/index.ts
3811
- var ID27 = "node-bump";
3652
+ var ID25 = "node-bump";
3812
3653
  var bumpButton = {
3813
3654
  slot: "inspector.action.button",
3814
3655
  priority: 10
3815
3656
  };
3816
3657
  var nodeBumpAction = {
3817
- id: ID27,
3658
+ id: ID25,
3818
3659
  pluginId: CORE_PLUGIN_ID,
3819
3660
  kind: "action",
3820
3661
  description: "Marks a node as updated: bumps `annotations.version`, refreshes sidecar hashes, and records the timestamp.",
3662
+ // Ships experimental (disabled by default, Decision #128), gated as a
3663
+ // unit with the companion `core/annotation-stale` analyzer: a disabled
3664
+ // action projects no Bump button, so the button never appears without
3665
+ // the drift analyzer that motivates it.
3666
+ stability: "experimental",
3821
3667
  mode: "deterministic",
3822
3668
  ui: { bumpButton },
3823
3669
  project(ctx) {
3824
3670
  for (const node of ctx.nodes) {
3825
- if (node.sidecar?.present !== true) continue;
3826
- emitBumpButton(ctx, node.path, staleStatus2(node.sidecar) !== null);
3671
+ if (node.virtual === true) continue;
3672
+ const enabled = node.sidecar?.present !== true || staleStatus2(node.sidecar) !== null;
3673
+ emitBumpButton(ctx, node.path, enabled);
3827
3674
  }
3828
3675
  },
3829
3676
  // The runtime contract uses generic <TInput, TReport>; bump narrows
@@ -3892,15 +3739,39 @@ function pickCurrentVersion(overlay) {
3892
3739
  return typeof v === "number" && Number.isFinite(v) ? v : 0;
3893
3740
  }
3894
3741
 
3742
+ // plugins/core/actions/node-set-stability/text.ts
3743
+ var NODE_SET_STABILITY_TEXTS = {
3744
+ /** Label of the inspector action button that sets the lifecycle stage. */
3745
+ setLabel: "Set stability",
3746
+ /** Prompt label for the enum-pick stability input. */
3747
+ promptLabel: "Stability",
3748
+ /** Prompt option label for the `experimental` stage. */
3749
+ optionExperimental: "Experimental",
3750
+ /** Prompt option label for the `stable` stage. */
3751
+ optionStable: "Stable",
3752
+ /** Prompt option label for the `deprecated` stage. */
3753
+ optionDeprecated: "Deprecated"
3754
+ };
3755
+
3895
3756
  // plugins/core/actions/node-set-stability/index.ts
3896
- var STABILITY_VALUES = ["experimental", "stable", "deprecated"];
3897
- var ID28 = "node-set-stability";
3757
+ var ID26 = "node-set-stability";
3758
+ var setStabilityButton = {
3759
+ slot: "inspector.action.button",
3760
+ priority: 15
3761
+ };
3898
3762
  var nodeSetStabilityAction = {
3899
- id: ID28,
3763
+ id: ID26,
3900
3764
  pluginId: CORE_PLUGIN_ID,
3901
3765
  kind: "action",
3902
3766
  description: "Sets the lifecycle stage of the current node (writes `stability` to the sidecar).",
3903
3767
  mode: "deterministic",
3768
+ ui: { setStabilityButton },
3769
+ project(ctx) {
3770
+ for (const node of ctx.nodes) {
3771
+ if (node.virtual === true) continue;
3772
+ emitSetStabilityButton(ctx, node);
3773
+ }
3774
+ },
3904
3775
  // The runtime contract uses generic <TInput, TReport>; this narrows
3905
3776
  // both. The cast is the standard pattern for built-ins that want
3906
3777
  // typed local I/O while staying compatible with the open generic.
@@ -3909,6 +3780,27 @@ var nodeSetStabilityAction = {
3909
3780
  return invokeSetStability(input, ctx);
3910
3781
  }
3911
3782
  };
3783
+ function emitSetStabilityButton(ctx, node) {
3784
+ ctx.emitContribution(node.path, setStabilityButton, {
3785
+ actionId: "core/node-set-stability",
3786
+ label: NODE_SET_STABILITY_TEXTS.setLabel,
3787
+ icon: "pi-flag",
3788
+ enabled: true,
3789
+ prompt: {
3790
+ inputType: "enum-pick",
3791
+ paramKey: "stability",
3792
+ label: NODE_SET_STABILITY_TEXTS.promptLabel,
3793
+ options: [
3794
+ { value: "experimental", label: NODE_SET_STABILITY_TEXTS.optionExperimental },
3795
+ { value: "stable", label: NODE_SET_STABILITY_TEXTS.optionStable },
3796
+ { value: "deprecated", label: NODE_SET_STABILITY_TEXTS.optionDeprecated }
3797
+ ],
3798
+ // Pre-load the node's current stage so the picker opens on the active
3799
+ // value; `stable` when nothing is set yet.
3800
+ defaultValue: readEffectiveStability(node) ?? "stable"
3801
+ }
3802
+ });
3803
+ }
3912
3804
  function invokeSetStability(input, ctx) {
3913
3805
  const stability = input.stability;
3914
3806
  if (!STABILITY_VALUES.includes(stability)) {
@@ -3944,13 +3836,13 @@ var TAGS_TEXTS = {
3944
3836
  };
3945
3837
 
3946
3838
  // plugins/core/actions/node-set-tags/index.ts
3947
- var ID29 = "node-set-tags";
3839
+ var ID27 = "node-set-tags";
3948
3840
  var setTagsButton = {
3949
3841
  slot: "inspector.action.button",
3950
3842
  priority: 15
3951
3843
  };
3952
3844
  var nodeSetTagsAction = {
3953
- id: ID29,
3845
+ id: ID27,
3954
3846
  pluginId: CORE_PLUGIN_ID,
3955
3847
  kind: "action",
3956
3848
  description: "Sets the taxonomy tags of the current node (writes `tags` to the sidecar; whole-array replace).",
@@ -3958,7 +3850,7 @@ var nodeSetTagsAction = {
3958
3850
  ui: { setTagsButton },
3959
3851
  project(ctx) {
3960
3852
  for (const node of ctx.nodes) {
3961
- if (node.sidecar?.present !== true) continue;
3853
+ if (node.virtual === true) continue;
3962
3854
  emitSetTagsButton(ctx, node);
3963
3855
  }
3964
3856
  },
@@ -4014,107 +3906,6 @@ function invokeSetTags(input, ctx) {
4014
3906
  return { report, writes: [write] };
4015
3907
  }
4016
3908
 
4017
- // plugins/core/actions/node-supersede/text.ts
4018
- var SUPERSEDE_TEXTS = {
4019
- /** Label of the inspector action button that declares supersession. */
4020
- supersedeLabel: "Supersede",
4021
- /** Tooltip shown when the supersede button is disabled (already superseded). */
4022
- supersedeDisabledReason: "Already superseded.",
4023
- /** Tooltip shown when there is no other node to supersede this one. */
4024
- supersedeNoTargetsReason: "No other node to supersede this one.",
4025
- /** Prompt label for the target node-picker (enum-pick over the live node set). */
4026
- supersedePromptLabel: "Superseded by"
4027
- };
4028
-
4029
- // plugins/core/actions/node-supersede/index.ts
4030
- var ID30 = "node-supersede";
4031
- var supersedeButton = {
4032
- slot: "inspector.action.button",
4033
- priority: 10
4034
- };
4035
- var nodeSupersedeAction = {
4036
- id: ID30,
4037
- pluginId: CORE_PLUGIN_ID,
4038
- kind: "action",
4039
- description: "Declares the current node as superseded by another (writes `supersededBy` to the sidecar).",
4040
- // Ships disabled by default (the declarer feature is still settling its
4041
- // node-picker UX). The button self-projection gates as a unit with the
4042
- // invoke executor: an enabled button pointing at a disabled action
4043
- // would error on click, so the whole action stays experimental.
4044
- stability: "experimental",
4045
- mode: "deterministic",
4046
- ui: { supersedeButton },
4047
- project(ctx) {
4048
- const candidates = ctx.nodes.filter((n) => n.virtual !== true).map((n) => n.path);
4049
- for (const node of ctx.nodes) {
4050
- if (node.virtual === true) continue;
4051
- const options = candidates.filter((p) => p !== node.path).map((p) => ({ value: p, label: p }));
4052
- emitSupersedeButton(ctx, node, options);
4053
- }
4054
- },
4055
- // The runtime contract uses generic <TInput, TReport>; supersede
4056
- // narrows both. The cast is the standard pattern for built-ins that
4057
- // want typed local I/O while staying compatible with the open generic.
4058
- invoke(rawInput, ctx) {
4059
- const input = rawInput ?? {};
4060
- return invokeSupersede(input, ctx);
4061
- }
4062
- };
4063
- function emitSupersedeButton(ctx, node, options) {
4064
- const disabledReason = resolveDisabledReason(node, options.length);
4065
- ctx.emitContribution(node.path, supersedeButton, {
4066
- actionId: "core/node-supersede",
4067
- label: SUPERSEDE_TEXTS.supersedeLabel,
4068
- icon: "pi-arrow-right-arrow-left",
4069
- enabled: disabledReason === void 0,
4070
- ...disabledReason === void 0 ? {} : { disabledReason },
4071
- prompt: {
4072
- inputType: "enum-pick",
4073
- paramKey: "supersededBy",
4074
- label: SUPERSEDE_TEXTS.supersedePromptLabel,
4075
- options
4076
- }
4077
- });
4078
- }
4079
- function resolveDisabledReason(node, optionCount) {
4080
- if (alreadySuperseded(node)) return SUPERSEDE_TEXTS.supersedeDisabledReason;
4081
- if (optionCount === 0) return SUPERSEDE_TEXTS.supersedeNoTargetsReason;
4082
- return void 0;
4083
- }
4084
- function alreadySuperseded(node) {
4085
- const sidecar = node.sidecar;
4086
- if (!sidecar || sidecar.present !== true) return false;
4087
- const ann = sidecar.annotations;
4088
- if (!ann || typeof ann !== "object" || Array.isArray(ann)) return false;
4089
- const value = ann["supersededBy"];
4090
- return typeof value === "string" && value.length > 0;
4091
- }
4092
- function invokeSupersede(input, ctx) {
4093
- const supersededBy = input.supersededBy;
4094
- if (supersededBy === ctx.node.path) {
4095
- return { report: { ok: false, reason: "self" } };
4096
- }
4097
- const timestamp = ctx.now().toISOString();
4098
- const write = {
4099
- kind: "sidecar",
4100
- path: sidecarPathFor(ctx.nodeAbsolutePath),
4101
- changes: {
4102
- identity: {
4103
- path: ctx.node.path,
4104
- bodyHash: ctx.node.bodyHash,
4105
- frontmatterHash: ctx.node.frontmatterHash
4106
- },
4107
- annotations: { supersededBy },
4108
- audit: {
4109
- lastBumpedAt: timestamp,
4110
- lastBumpedBy: ctx.invoker
4111
- }
4112
- }
4113
- };
4114
- const report = { ok: true, supersededBy };
4115
- return { report, writes: [write] };
4116
- }
4117
-
4118
3909
  // kernel/update-check/index.ts
4119
3910
  var SEMVER_SHAPE_RE = /^[0-9]+\.[0-9]+\.[0-9]+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/;
4120
3911
  async function fetchLatestVersion(pkg, opts) {
@@ -4599,7 +4390,6 @@ var antigravityProvider2 = { ...antigravityProvider, pluginId: "antigravity", ve
4599
4390
  var openaiProvider2 = { ...openaiProvider, pluginId: "openai", version: VERSION };
4600
4391
  var agentSkillsProvider2 = { ...agentSkillsProvider, pluginId: "agent-skills", version: VERSION };
4601
4392
  var coreMarkdownProvider2 = { ...coreMarkdownProvider, pluginId: "core", version: VERSION };
4602
- var annotationsExtractor2 = { ...annotationsExtractor, pluginId: "core", version: VERSION };
4603
4393
  var backtickPathExtractor2 = { ...backtickPathExtractor, pluginId: "core", version: VERSION };
4604
4394
  var externalUrlCounterExtractor2 = { ...externalUrlCounterExtractor, pluginId: "core", version: VERSION };
4605
4395
  var markdownLinkExtractor2 = { ...markdownLinkExtractor, pluginId: "core", version: VERSION };
@@ -4616,7 +4406,6 @@ var linkSelfLoopAnalyzer2 = { ...linkSelfLoopAnalyzer, pluginId: "core", version
4616
4406
  var nameCollisionAnalyzer2 = { ...nameCollisionAnalyzer, pluginId: "core", version: VERSION };
4617
4407
  var nameReservedAnalyzer2 = { ...nameReservedAnalyzer, pluginId: "core", version: VERSION };
4618
4408
  var nodeStabilityAnalyzer2 = { ...nodeStabilityAnalyzer, pluginId: "core", version: VERSION };
4619
- var nodeSupersededAnalyzer2 = { ...nodeSupersededAnalyzer, pluginId: "core", version: VERSION };
4620
4409
  var referenceBrokenAnalyzer2 = { ...referenceBrokenAnalyzer, pluginId: "core", version: VERSION };
4621
4410
  var referenceRedundantAnalyzer2 = { ...referenceRedundantAnalyzer, pluginId: "core", version: VERSION };
4622
4411
  var schemaViolationAnalyzer2 = { ...schemaViolationAnalyzer, pluginId: "core", version: VERSION };
@@ -4625,7 +4414,6 @@ var jsonFormatter2 = { ...jsonFormatter, pluginId: "core", version: VERSION };
4625
4414
  var nodeBumpAction2 = { ...nodeBumpAction, pluginId: "core", version: VERSION };
4626
4415
  var nodeSetStabilityAction2 = { ...nodeSetStabilityAction, pluginId: "core", version: VERSION };
4627
4416
  var nodeSetTagsAction2 = { ...nodeSetTagsAction, pluginId: "core", version: VERSION };
4628
- var nodeSupersedeAction2 = { ...nodeSupersedeAction, pluginId: "core", version: VERSION };
4629
4417
  var updateCheckHook2 = { ...updateCheckHook, pluginId: "core", version: VERSION };
4630
4418
  var builtInPlugins = [
4631
4419
  {
@@ -4664,7 +4452,6 @@ var builtInPlugins = [
4664
4452
  description: "Core extensions shared across providers: parsers, extractors, analyzers, actions, hooks, formatters, and the universal `.md` fallback provider.",
4665
4453
  extensions: [
4666
4454
  coreMarkdownProvider2,
4667
- annotationsExtractor2,
4668
4455
  backtickPathExtractor2,
4669
4456
  externalUrlCounterExtractor2,
4670
4457
  markdownLinkExtractor2,
@@ -4681,7 +4468,6 @@ var builtInPlugins = [
4681
4468
  nameCollisionAnalyzer2,
4682
4469
  nameReservedAnalyzer2,
4683
4470
  nodeStabilityAnalyzer2,
4684
- nodeSupersededAnalyzer2,
4685
4471
  referenceBrokenAnalyzer2,
4686
4472
  referenceRedundantAnalyzer2,
4687
4473
  schemaViolationAnalyzer2,
@@ -4690,7 +4476,6 @@ var builtInPlugins = [
4690
4476
  nodeBumpAction2,
4691
4477
  nodeSetStabilityAction2,
4692
4478
  nodeSetTagsAction2,
4693
- nodeSupersedeAction2,
4694
4479
  updateCheckHook2
4695
4480
  ]
4696
4481
  }
@@ -7593,7 +7378,6 @@ var LINK_KIND_VALUES = Object.freeze([
7593
7378
  "invokes",
7594
7379
  "references",
7595
7380
  "mentions",
7596
- "supersedes",
7597
7381
  "points"
7598
7382
  ]);
7599
7383
  var SEVERITY_VALUES = Object.freeze([
@@ -10734,17 +10518,6 @@ var LOCKED_PLUGIN_IDS = /* @__PURE__ */ new Set([
10734
10518
  // silently invisible, a foot-gun the host product does not want to
10735
10519
  // expose. Lock it in the enabled state.
10736
10520
  "core/markdown",
10737
- // `core/annotations` turns the `supersedes` / `supersededBy` /
10738
- // `requires` / `related` / `conflictsWith` entries of the sidecar
10739
- // `annotations:` block into the arrows the graph draws between nodes.
10740
- // It does NOT own the rest of the block (`version`, `stability`,
10741
- // `tags`, `description`, those live on the node bundle directly and
10742
- // keep rendering with the plugin off). Disabling it produces a
10743
- // confusing "edges disappear but the sidecar metadata stays" split
10744
- // that no operator actually wants; the lock makes the asymmetry
10745
- // unreachable from CLI / BFF / UI. Re-evaluate if a third-party ever
10746
- // ships a competing supersession extractor.
10747
- "core/annotations",
10748
10521
  // `core/schema-violation` validates every scanned Node against
10749
10522
  // `node.schema.json` and every Link against `link.schema.json` (the
10750
10523
  // authoritative @skill-map/spec). Disabling it makes the system
@@ -15709,7 +15482,7 @@ function buildVirtualNode(extractor, emitted, emitter) {
15709
15482
  if (emitted.frontmatter) node.frontmatter = emitted.frontmatter;
15710
15483
  return node;
15711
15484
  }
15712
- var KNOWN_LINK_KINDS = ["invokes", "references", "mentions", "supersedes", "points"];
15485
+ var KNOWN_LINK_KINDS = ["invokes", "references", "mentions", "points"];
15713
15486
  function validateLink(extractor, link, emitter) {
15714
15487
  const knownKinds = KNOWN_LINK_KINDS;
15715
15488
  if (!knownKinds.includes(link.kind)) {
@@ -16150,26 +15923,24 @@ function validateIssue(analyzer, issue, emitter) {
16150
15923
  // kernel/orchestrator/cache.ts
16151
15924
  function indexPriorSnapshot(prior) {
16152
15925
  const priorNodesByPath = /* @__PURE__ */ new Map();
16153
- const priorNodePaths = /* @__PURE__ */ new Set();
16154
15926
  const priorLinksByOriginating = /* @__PURE__ */ new Map();
16155
15927
  const priorFrontmatterIssuesByNode = /* @__PURE__ */ new Map();
16156
15928
  if (!prior) {
16157
- return { priorNodesByPath, priorNodePaths, priorLinksByOriginating, priorFrontmatterIssuesByNode };
15929
+ return { priorNodesByPath, priorLinksByOriginating, priorFrontmatterIssuesByNode };
16158
15930
  }
16159
- indexPriorNodes(prior.nodes, priorNodesByPath, priorNodePaths);
16160
- indexPriorLinks(prior.links, priorNodePaths, priorLinksByOriginating);
15931
+ indexPriorNodes(prior.nodes, priorNodesByPath);
15932
+ indexPriorLinks(prior.links, priorLinksByOriginating);
16161
15933
  indexPriorFrontmatterIssues(prior.issues, priorFrontmatterIssuesByNode);
16162
- return { priorNodesByPath, priorNodePaths, priorLinksByOriginating, priorFrontmatterIssuesByNode };
15934
+ return { priorNodesByPath, priorLinksByOriginating, priorFrontmatterIssuesByNode };
16163
15935
  }
16164
- function indexPriorNodes(nodes, byPath3, paths) {
15936
+ function indexPriorNodes(nodes, byPath3) {
16165
15937
  for (const node of nodes) {
16166
15938
  byPath3.set(node.path, node);
16167
- paths.add(node.path);
16168
15939
  }
16169
15940
  }
16170
- function indexPriorLinks(links, priorNodePaths, byOriginating) {
15941
+ function indexPriorLinks(links, byOriginating) {
16171
15942
  for (const link of links) {
16172
- const key = originatingNodeOf(link, priorNodePaths);
15943
+ const key = link.source;
16173
15944
  const list = byOriginating.get(key);
16174
15945
  if (list) list.push(link);
16175
15946
  else byOriginating.set(key, [link]);
@@ -16185,12 +15956,6 @@ function indexPriorFrontmatterIssues(issues, byNode) {
16185
15956
  else byNode.set(path, [issue]);
16186
15957
  }
16187
15958
  }
16188
- function originatingNodeOf(link, priorNodePaths) {
16189
- if (link.kind === "supersedes" && !priorNodePaths.has(link.source)) {
16190
- return link.target;
16191
- }
16192
- return link.source;
16193
- }
16194
15959
  function computeCacheDecision(opts) {
16195
15960
  const applicableExtractors = opts.extractors.filter((ex) => {
16196
15961
  if (!matchesKindPrecondition(ex, opts.kind)) return false;
@@ -24409,8 +24174,8 @@ var ScanCommand = class extends SmCommand {
24409
24174
  details: `
24410
24175
  Walks the given roots with the built-in claude Provider, runs the
24411
24176
  frontmatter / slash / at-directive / external-url-counter
24412
- extractors per node, then the name-collision / broken-ref /
24413
- superseded analyzers over the full graph. Emits a ScanResult
24177
+ extractors per node, then the name-collision / broken-ref
24178
+ analyzers over the full graph. Emits a ScanResult
24414
24179
  conforming to scan-result.schema.json.
24415
24180
 
24416
24181
  The result is persisted into <cwd>/.skill-map/skill-map.db
@@ -31209,4 +30974,4 @@ function resolveBareDefault() {
31209
30974
  process.exit(ExitCode.Error);
31210
30975
  }
31211
30976
  //# sourceMappingURL=cli.js.map
31212
- //# debugId=e6038423-ea97-5e66-b371-0916d382d819
30977
+ //# debugId=88ff98f5-2b47-5849-9567-922fc880f5bc