@skill-map/cli 0.35.0 → 0.37.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.
@@ -94,14 +94,14 @@ var Registry = class {
94
94
 
95
95
  // kernel/orchestrator/index.ts
96
96
  import { existsSync as existsSync11, statSync as statSync4 } from "fs";
97
- import { isAbsolute as isAbsolute4, resolve as resolve10 } from "path";
97
+ import { isAbsolute as isAbsolute4, resolve as resolve11 } from "path";
98
98
  import { Tiktoken as Tiktoken2 } from "js-tiktoken/lite";
99
99
  import cl100k_base from "js-tiktoken/ranks/cl100k_base";
100
100
 
101
101
  // package.json
102
102
  var package_default = {
103
103
  name: "@skill-map/cli",
104
- version: "0.35.0",
104
+ version: "0.37.0",
105
105
  description: "skill-map reference implementation \u2014 kernel + CLI + adapters.",
106
106
  license: "MIT",
107
107
  type: "module",
@@ -197,7 +197,7 @@ var package_default = {
197
197
  eslint: "10.2.1",
198
198
  "eslint-plugin-import-x": "4.16.2",
199
199
  tsup: "8.5.1",
200
- tsx: "4.21.0",
200
+ tsx: "4.22.3",
201
201
  typescript: "5.9.3",
202
202
  "typescript-eslint": "8.59.1"
203
203
  },
@@ -1051,7 +1051,13 @@ function loadConfigForScope(opts) {
1051
1051
  // core/config/active-provider.ts
1052
1052
  var DETECTION_RULES = [
1053
1053
  { providerId: "claude", marker: ".claude" },
1054
- { providerId: "gemini", marker: ".gemini" },
1054
+ // `gemini` retired 2026-05-22: Google replaced the Gemini CLI with the
1055
+ // Antigravity CLI (released 2026-05-19; Gemini CLI sunsets 2026-06-18).
1056
+ // Antigravity adopted the open-standard `.agents/` instead of a
1057
+ // vendor-specific directory, so detection of a Google CLI project
1058
+ // falls through to the universal `agent-skills` lens (`.agents/`
1059
+ // already classifies via that neutral provider). The lens can still
1060
+ // be set manually via `sm config set activeProvider antigravity`.
1055
1061
  { providerId: "openai", marker: ".codex" },
1056
1062
  { providerId: "openai", marker: "AGENTS.md" },
1057
1063
  { providerId: "cursor", marker: ".cursor" }
@@ -1390,6 +1396,20 @@ function dedupeLinks(links) {
1390
1396
  if (link.confidence > existing.confidence) {
1391
1397
  existing.confidence = link.confidence;
1392
1398
  }
1399
+ if (link.occurrences && link.occurrences.length > 0) {
1400
+ const existingOccurrences = existing.occurrences ?? [];
1401
+ const occKey = (o) => `${o.extractor}\0${o.originalTrigger}\0${o.location?.line ?? -1}`;
1402
+ const occSeen = new Set(existingOccurrences.map(occKey));
1403
+ const merged = [...existingOccurrences];
1404
+ for (const occ of link.occurrences) {
1405
+ const k = occKey(occ);
1406
+ if (!occSeen.has(k)) {
1407
+ occSeen.add(k);
1408
+ merged.push(occ);
1409
+ }
1410
+ }
1411
+ existing.occurrences = merged;
1412
+ }
1393
1413
  continue;
1394
1414
  }
1395
1415
  out.set(key, link);
@@ -1413,12 +1433,23 @@ function recomputeLinkCounts(nodes, links) {
1413
1433
  function recomputeExternalRefsCount(nodes, externalLinks, cachedPaths) {
1414
1434
  const byPath2 = /* @__PURE__ */ new Map();
1415
1435
  for (const node of nodes) {
1416
- if (!cachedPaths.has(node.path)) node.externalRefsCount = 0;
1436
+ if (!cachedPaths.has(node.path)) {
1437
+ node.externalRefsCount = 0;
1438
+ delete node.externalRefs;
1439
+ }
1417
1440
  byPath2.set(node.path, node);
1418
1441
  }
1419
1442
  for (const link of externalLinks) {
1420
1443
  const source = byPath2.get(link.source);
1421
- if (source && !cachedPaths.has(source.path)) source.externalRefsCount += 1;
1444
+ if (!source || cachedPaths.has(source.path)) continue;
1445
+ source.externalRefsCount += 1;
1446
+ const refs = source.externalRefs ?? [];
1447
+ refs.push({
1448
+ url: link.target,
1449
+ ...link.location?.line !== void 0 ? { line: link.location.line } : {},
1450
+ ...link.trigger?.originalTrigger ? { originalTrigger: link.trigger.originalTrigger } : {}
1451
+ });
1452
+ source.externalRefs = refs;
1422
1453
  }
1423
1454
  }
1424
1455
  var EXTERNAL_URL_SCHEME_RE = /^[a-z][a-z0-9+\-.]+:/i;
@@ -1429,7 +1460,7 @@ function isExternalUrlLink(link) {
1429
1460
  }
1430
1461
 
1431
1462
  // kernel/orchestrator/analyzers.ts
1432
- async function runAnalyzers(analyzers, nodes, internalLinks, orphanSidecars, sidecarRoots, annotationContributions, viewContributions, orphanJobFiles, referenceablePaths, cwd, registeredActionIds, emitter, hookDispatcher) {
1463
+ async function runAnalyzers(analyzers, nodes, internalLinks, orphanSidecars, sidecarRoots, annotationContributions, viewContributions, orphanJobFiles, referenceablePaths, cwd, registeredActionIds, emitter, hookDispatcher, reservedNodePaths, signals) {
1433
1464
  const issues = [];
1434
1465
  const contributions = [];
1435
1466
  const validators = loadSchemaValidators();
@@ -1493,6 +1524,8 @@ async function runAnalyzers(analyzers, nodes, internalLinks, orphanSidecars, sid
1493
1524
  orphanJobFiles,
1494
1525
  ...referenceablePaths ? { referenceablePaths } : {},
1495
1526
  ...cwd ? { cwd } : {},
1527
+ ...reservedNodePaths ? { reservedNodePaths } : {},
1528
+ ...signals && signals.length > 0 ? { signals } : {},
1496
1529
  emitContribution
1497
1530
  });
1498
1531
  for (const issue of emitted) {
@@ -1713,7 +1746,7 @@ function classifyLinkSource(source, shortIdToQualified, cachedQualifiedIds, appl
1713
1746
  return "obsolete";
1714
1747
  }
1715
1748
 
1716
- // kernel/orchestrator/lift-resolved-link-confidence.ts
1749
+ // kernel/orchestrator/node-identifiers.ts
1717
1750
  import { posix as pathPosix } from "path";
1718
1751
 
1719
1752
  // kernel/trigger-normalize.ts
@@ -1726,14 +1759,54 @@ function normalizeTrigger(source) {
1726
1759
  return out.trim();
1727
1760
  }
1728
1761
 
1762
+ // kernel/orchestrator/node-identifiers.ts
1763
+ function deriveNodeIdentifiers(node, kindDescriptor) {
1764
+ const sources = kindDescriptor?.identifiers;
1765
+ if (!sources || sources.length === 0) return [];
1766
+ const out = [];
1767
+ for (const source of sources) {
1768
+ const raw = readIdentifier(source, node);
1769
+ if (!raw) continue;
1770
+ const normalised = normalizeTrigger(raw);
1771
+ if (normalised) out.push(normalised);
1772
+ }
1773
+ return out;
1774
+ }
1775
+ function readIdentifier(source, node) {
1776
+ if (source === "frontmatter.name") return readFrontmatterName(node);
1777
+ if (source === "filename-basename") return readFilenameBasename(node);
1778
+ return readDirname(node);
1779
+ }
1780
+ function readFrontmatterName(node) {
1781
+ const raw = node.frontmatter?.["name"];
1782
+ if (typeof raw !== "string") return null;
1783
+ return raw.length > 0 ? raw : null;
1784
+ }
1785
+ function readFilenameBasename(node) {
1786
+ const base = pathPosix.basename(node.path);
1787
+ if (!base) return null;
1788
+ const ext = pathPosix.extname(base);
1789
+ const stem = ext ? base.slice(0, -ext.length) : base;
1790
+ return stem.length > 0 ? stem : null;
1791
+ }
1792
+ function readDirname(node) {
1793
+ const dir = pathPosix.dirname(node.path);
1794
+ if (!dir || dir === "." || dir === "/") return null;
1795
+ const base = pathPosix.basename(dir);
1796
+ return base.length > 0 ? base : null;
1797
+ }
1798
+
1729
1799
  // kernel/orchestrator/lift-resolved-link-confidence.ts
1800
+ var RESERVED_TARGET_CONFIDENCE = 0.1;
1730
1801
  function liftResolvedLinkConfidence(links, nodes, ctx) {
1731
1802
  if (!links.some((l) => l.confidence < 1)) return;
1732
1803
  const indexes = buildIndexes(nodes, ctx);
1733
1804
  for (const link of links) {
1734
- if (link.confidence < 1 && resolves(link, indexes, ctx)) {
1735
- link.confidence = 1;
1736
- }
1805
+ if (link.confidence >= 1) continue;
1806
+ const resolution = resolve7(link, indexes, ctx);
1807
+ if (resolution === "none") continue;
1808
+ link.confidence = ctx.reservedNodePaths.has(resolution) ? RESERVED_TARGET_CONFIDENCE : 1;
1809
+ link.resolvedTarget = resolution;
1737
1810
  }
1738
1811
  }
1739
1812
  function buildIndexes(nodes, ctx) {
@@ -1747,18 +1820,19 @@ function buildIndexes(nodes, ctx) {
1747
1820
  }
1748
1821
  return { byPath: byPath2, byName, nodeByPath };
1749
1822
  }
1750
- function resolves(link, indexes, ctx) {
1751
- if (indexes.byPath.has(link.target)) return true;
1752
- return resolvesByName(link, indexes, ctx);
1823
+ function resolve7(link, indexes, ctx) {
1824
+ if (indexes.byPath.has(link.target)) return link.target;
1825
+ return resolveByName(link, indexes, ctx);
1753
1826
  }
1754
- function resolvesByName(link, indexes, ctx) {
1827
+ function resolveByName(link, indexes, ctx) {
1755
1828
  const stripped = stripTriggerSigil(link.trigger?.normalizedTrigger);
1756
- if (stripped === null) return false;
1829
+ if (stripped === null) return "none";
1757
1830
  const candidates = indexes.byName.get(stripped);
1758
- if (!candidates?.length) return false;
1831
+ if (!candidates?.length) return "none";
1759
1832
  const allowedKinds = lookupAllowedKinds(link, indexes, ctx);
1760
- if (!allowedKinds?.length) return false;
1761
- return candidates.some((c) => allowedKinds.includes(c.kind));
1833
+ if (!allowedKinds?.length) return "none";
1834
+ const winner = candidates.find((c) => allowedKinds.includes(c.kind));
1835
+ return winner ? winner.path : "none";
1762
1836
  }
1763
1837
  function lookupAllowedKinds(link, indexes, ctx) {
1764
1838
  const sourceNode = indexes.nodeByPath.get(link.source);
@@ -1772,44 +1846,17 @@ function stripTriggerSigil(normalized) {
1772
1846
  }
1773
1847
  function indexNode(node, ctx, byName) {
1774
1848
  const kindDescriptor = ctx.kindRegistry.get(kindKey(node));
1775
- const sources = kindDescriptor?.identifiers;
1776
- if (!sources || sources.length === 0) return;
1777
- for (const source of sources) {
1778
- const raw = deriveIdentifier(source, node);
1779
- if (!raw) continue;
1780
- const normalized = normalizeTrigger(raw);
1781
- if (!normalized) continue;
1782
- const bucket = byName.get(normalized);
1849
+ const normalised = deriveNodeIdentifiers(node, kindDescriptor);
1850
+ for (const name of normalised) {
1851
+ const entry = { kind: node.kind, path: node.path };
1852
+ const bucket = byName.get(name);
1783
1853
  if (bucket) {
1784
- bucket.push({ kind: node.kind });
1854
+ bucket.push(entry);
1785
1855
  } else {
1786
- byName.set(normalized, [{ kind: node.kind }]);
1856
+ byName.set(name, [entry]);
1787
1857
  }
1788
1858
  }
1789
1859
  }
1790
- function deriveIdentifier(source, node) {
1791
- if (source === "frontmatter.name") return readFrontmatterName(node);
1792
- if (source === "filename-basename") return readFilenameBasename(node);
1793
- return readDirname(node);
1794
- }
1795
- function readFrontmatterName(node) {
1796
- const raw = node.frontmatter?.["name"];
1797
- if (typeof raw !== "string") return null;
1798
- return raw.length > 0 ? raw : null;
1799
- }
1800
- function readFilenameBasename(node) {
1801
- const base = pathPosix.basename(node.path);
1802
- if (!base) return null;
1803
- const ext = pathPosix.extname(base);
1804
- const stem = ext ? base.slice(0, -ext.length) : base;
1805
- return stem.length > 0 ? stem : null;
1806
- }
1807
- function readDirname(node) {
1808
- const dir = pathPosix.dirname(node.path);
1809
- if (!dir || dir === "." || dir === "/") return null;
1810
- const base = pathPosix.basename(dir);
1811
- return base.length > 0 ? base : null;
1812
- }
1813
1860
  function kindKey(node) {
1814
1861
  return `${node.provider}/${node.kind}`;
1815
1862
  }
@@ -1840,6 +1887,190 @@ function applyPostWalkTransforms(links, nodes, ctx, transforms = POST_WALK_TRANS
1840
1887
  return current;
1841
1888
  }
1842
1889
 
1890
+ // kernel/orchestrator/resolver.ts
1891
+ function resolveSignals(opts) {
1892
+ const kindPriority = opts.activeProvider?.resolverRules?.kindPriority ?? [];
1893
+ const extractorRank = buildExtractorRank(opts.extractorOrder);
1894
+ for (const signal of opts.signals) {
1895
+ signal.resolution = pickIntraWinner(signal, kindPriority, extractorRank);
1896
+ }
1897
+ const bySource = /* @__PURE__ */ new Map();
1898
+ for (const signal of opts.signals) {
1899
+ if (signal.resolution?.outcome !== "materialised") continue;
1900
+ const bucket = bySource.get(signal.source) ?? [];
1901
+ bucket.push(signal);
1902
+ bySource.set(signal.source, bucket);
1903
+ }
1904
+ for (const [, signals] of bySource) {
1905
+ const clusters = buildOverlapClusters(signals);
1906
+ for (const cluster of clusters) {
1907
+ if (cluster.length < 2) continue;
1908
+ if (everyCandidateIsExternalUrl(cluster)) continue;
1909
+ resolveCluster(cluster, kindPriority, extractorRank);
1910
+ }
1911
+ }
1912
+ const links = [];
1913
+ for (const signal of opts.signals) {
1914
+ if (signal.resolution?.outcome !== "materialised") continue;
1915
+ const winnerIndex = signal.resolution.winnerIndex ?? 0;
1916
+ const winner = signal.candidates[winnerIndex];
1917
+ if (!winner) continue;
1918
+ links.push(materialise(signal, winner));
1919
+ }
1920
+ return { links, resolvedSignals: [...opts.signals] };
1921
+ }
1922
+ function buildExtractorRank(order) {
1923
+ const rank = /* @__PURE__ */ new Map();
1924
+ for (let i = 0; i < order.length; i += 1) rank.set(order[i], i);
1925
+ return rank;
1926
+ }
1927
+ function pickIntraWinner(signal, kindPriority, extractorRank) {
1928
+ let bestIndex = 0;
1929
+ for (let i = 1; i < signal.candidates.length; i += 1) {
1930
+ if (compareCandidates(signal.candidates[i], signal.candidates[bestIndex], kindPriority, extractorRank) < 0) {
1931
+ bestIndex = i;
1932
+ }
1933
+ }
1934
+ return { outcome: "materialised", winnerIndex: bestIndex };
1935
+ }
1936
+ function compareCandidates(a, b, kindPriority, extractorRank) {
1937
+ const kindCmp = compareKindPriority(a.kind, b.kind, kindPriority);
1938
+ if (kindCmp !== 0) return kindCmp;
1939
+ if (a.confidence !== b.confidence) return b.confidence - a.confidence;
1940
+ const aRank = extractorRank.get(a.extractorId) ?? Number.MAX_SAFE_INTEGER;
1941
+ const bRank = extractorRank.get(b.extractorId) ?? Number.MAX_SAFE_INTEGER;
1942
+ return aRank - bRank;
1943
+ }
1944
+ function compareKindPriority(aKind, bKind, kindPriority) {
1945
+ if (kindPriority.length === 0) return 0;
1946
+ const aIdx = kindPriority.indexOf(aKind);
1947
+ const bIdx = kindPriority.indexOf(bKind);
1948
+ const aEff = aIdx === -1 ? Number.MAX_SAFE_INTEGER : aIdx;
1949
+ const bEff = bIdx === -1 ? Number.MAX_SAFE_INTEGER : bIdx;
1950
+ return aEff - bEff;
1951
+ }
1952
+ function buildOverlapClusters(signals) {
1953
+ const bodySignals = signals.filter((s) => s.scope === "body" && s.range);
1954
+ const others = signals.filter((s) => !(s.scope === "body" && s.range));
1955
+ const parent = bodySignals.map((_, i) => i);
1956
+ const find = (i) => {
1957
+ while (parent[i] !== i) {
1958
+ parent[i] = parent[parent[i]];
1959
+ i = parent[i];
1960
+ }
1961
+ return i;
1962
+ };
1963
+ const union = (a, b) => {
1964
+ const ra = find(a);
1965
+ const rb = find(b);
1966
+ if (ra !== rb) parent[ra] = rb;
1967
+ };
1968
+ for (let i = 0; i < bodySignals.length; i += 1) {
1969
+ for (let j = i + 1; j < bodySignals.length; j += 1) {
1970
+ if (rangesOverlap(bodySignals[i].range, bodySignals[j].range)) {
1971
+ union(i, j);
1972
+ }
1973
+ }
1974
+ }
1975
+ const byRoot = /* @__PURE__ */ new Map();
1976
+ for (let i = 0; i < bodySignals.length; i += 1) {
1977
+ const root = find(i);
1978
+ const bucket = byRoot.get(root) ?? [];
1979
+ bucket.push(bodySignals[i]);
1980
+ byRoot.set(root, bucket);
1981
+ }
1982
+ return [...byRoot.values(), ...others.map((s) => [s])];
1983
+ }
1984
+ function rangesOverlap(a, b) {
1985
+ return a.end > b.start && b.end > a.start;
1986
+ }
1987
+ function everyCandidateIsExternalUrl(cluster) {
1988
+ for (const signal of cluster) {
1989
+ const winnerIndex = signal.resolution?.winnerIndex ?? 0;
1990
+ const winner = signal.candidates[winnerIndex];
1991
+ if (!winner) return false;
1992
+ if (!isExternalUrl(winner.target)) return false;
1993
+ }
1994
+ return true;
1995
+ }
1996
+ function isExternalUrl(target) {
1997
+ return target.startsWith("http://") || target.startsWith("https://");
1998
+ }
1999
+ function resolveCluster(cluster, kindPriority, extractorRank) {
2000
+ let winnerIdx = 0;
2001
+ for (let i = 1; i < cluster.length; i += 1) {
2002
+ const result = compareClusterMembers(cluster[i], cluster[winnerIdx], kindPriority, extractorRank);
2003
+ if (result.winner === "challenger") winnerIdx = i;
2004
+ }
2005
+ const winner = cluster[winnerIdx];
2006
+ const winnerCandidate = winner.candidates[winner.resolution?.winnerIndex ?? 0];
2007
+ for (let i = 0; i < cluster.length; i += 1) {
2008
+ if (i === winnerIdx) continue;
2009
+ const loser = cluster[i];
2010
+ loser.resolution = {
2011
+ outcome: "rejected",
2012
+ rejectedBy: {
2013
+ source: winner.source,
2014
+ range: winner.range,
2015
+ extractorId: winnerCandidate.extractorId,
2016
+ reason: whyLost(loser, winner, kindPriority, extractorRank)
2017
+ }
2018
+ };
2019
+ }
2020
+ }
2021
+ function compareClusterMembers(challenger, champion, kindPriority, extractorRank) {
2022
+ const cWinner = challenger.candidates[challenger.resolution?.winnerIndex ?? 0];
2023
+ const xWinner = champion.candidates[champion.resolution?.winnerIndex ?? 0];
2024
+ const kindCmp = compareKindPriority(cWinner.kind, xWinner.kind, kindPriority);
2025
+ if (kindCmp < 0) return { winner: "challenger", reason: "kind-priority" };
2026
+ if (kindCmp > 0) return { winner: "champion", reason: "kind-priority" };
2027
+ if (cWinner.confidence !== xWinner.confidence) {
2028
+ return cWinner.confidence > xWinner.confidence ? { winner: "challenger", reason: "higher-confidence" } : { winner: "champion", reason: "higher-confidence" };
2029
+ }
2030
+ const cLen = rangeLength(challenger.range);
2031
+ const xLen = rangeLength(champion.range);
2032
+ if (cLen !== xLen) {
2033
+ return cLen > xLen ? { winner: "challenger", reason: "longer-range" } : { winner: "champion", reason: "longer-range" };
2034
+ }
2035
+ const cRank = extractorRank.get(cWinner.extractorId) ?? Number.MAX_SAFE_INTEGER;
2036
+ const xRank = extractorRank.get(xWinner.extractorId) ?? Number.MAX_SAFE_INTEGER;
2037
+ if (cRank !== xRank) {
2038
+ return cRank < xRank ? { winner: "challenger", reason: "earlier-declaration" } : { winner: "champion", reason: "earlier-declaration" };
2039
+ }
2040
+ return { winner: "tie", reason: "earlier-declaration" };
2041
+ }
2042
+ function rangeLength(range) {
2043
+ if (!range) return 0;
2044
+ return range.end - range.start;
2045
+ }
2046
+ function whyLost(loser, winner, kindPriority, extractorRank) {
2047
+ return compareClusterMembers(winner, loser, kindPriority, extractorRank).reason;
2048
+ }
2049
+ function materialise(signal, winner) {
2050
+ const link = {
2051
+ source: signal.source,
2052
+ target: winner.target,
2053
+ kind: winner.kind,
2054
+ confidence: winner.confidence,
2055
+ sources: [winner.extractorId],
2056
+ raw: signal.raw
2057
+ };
2058
+ if (winner.trigger) link.trigger = winner.trigger;
2059
+ if (signal.range) {
2060
+ link.location = { line: signal.range.line ?? 1, offset: signal.range.start };
2061
+ }
2062
+ const occurrenceTrigger = winner.trigger?.originalTrigger ?? signal.raw;
2063
+ const occurrenceLocation = signal.range ? { line: signal.range.line ?? 1 } : null;
2064
+ link.occurrences = [
2065
+ {
2066
+ extractor: winner.extractorId,
2067
+ originalTrigger: occurrenceTrigger,
2068
+ location: occurrenceLocation
2069
+ }
2070
+ ];
2071
+ return link;
2072
+ }
2073
+
1843
2074
  // kernel/orchestrator/renames.ts
1844
2075
  function findHighConfidenceRenames(opts) {
1845
2076
  const ops = [];
@@ -1978,7 +2209,7 @@ import { join as join7, relative as relative2, sep } from "path";
1978
2209
 
1979
2210
  // kernel/scan/ignore.ts
1980
2211
  import { existsSync as existsSync6, readFileSync as readFileSync7 } from "fs";
1981
- import { dirname as dirname4, resolve as resolve7 } from "path";
2212
+ import { dirname as dirname4, resolve as resolve8 } from "path";
1982
2213
  import { fileURLToPath } from "url";
1983
2214
  import ignoreFactory from "ignore";
1984
2215
  function buildIgnoreFilter(opts = {}) {
@@ -2012,11 +2243,11 @@ function loadDefaultsText() {
2012
2243
  function readDefaultsFromDisk() {
2013
2244
  const here = dirname4(fileURLToPath(import.meta.url));
2014
2245
  const candidates = [
2015
- resolve7(here, "../../config/defaults/skillmapignore"),
2246
+ resolve8(here, "../../config/defaults/skillmapignore"),
2016
2247
  // src/kernel/scan/ → src/config/defaults/
2017
- resolve7(here, "../config/defaults/skillmapignore"),
2248
+ resolve8(here, "../config/defaults/skillmapignore"),
2018
2249
  // dist/cli.js → dist/config/defaults/ (siblings)
2019
- resolve7(here, "config/defaults/skillmapignore")
2250
+ resolve8(here, "config/defaults/skillmapignore")
2020
2251
  ];
2021
2252
  for (const candidate of candidates) {
2022
2253
  if (existsSync6(candidate)) {
@@ -2207,7 +2438,7 @@ function resolveProviderWalk(provider) {
2207
2438
 
2208
2439
  // kernel/sidecar/parse.ts
2209
2440
  import { existsSync as existsSync7, readFileSync as readFileSync8 } from "fs";
2210
- import { dirname as dirname5, resolve as resolve8 } from "path";
2441
+ import { dirname as dirname5, resolve as resolve9 } from "path";
2211
2442
  import { createRequire as createRequire3 } from "module";
2212
2443
  import { Ajv2020 as Ajv20204 } from "ajv/dist/2020.js";
2213
2444
  import yaml2 from "js-yaml";
@@ -2286,10 +2517,10 @@ function getSidecarValidator() {
2286
2517
  applyAjvFormats(ajv);
2287
2518
  const specRoot = resolveSpecRoot2();
2288
2519
  const annotationsSchema = JSON.parse(
2289
- readFileSync8(resolve8(specRoot, "schemas/annotations.schema.json"), "utf8")
2520
+ readFileSync8(resolve9(specRoot, "schemas/annotations.schema.json"), "utf8")
2290
2521
  );
2291
2522
  const sidecarSchema = JSON.parse(
2292
- readFileSync8(resolve8(specRoot, "schemas/sidecar.schema.json"), "utf8")
2523
+ readFileSync8(resolve9(specRoot, "schemas/sidecar.schema.json"), "utf8")
2293
2524
  );
2294
2525
  ajv.addSchema(annotationsSchema);
2295
2526
  cachedSidecarValidator = ajv.compile(sidecarSchema);
@@ -2360,7 +2591,7 @@ function safeIsFile(path) {
2360
2591
 
2361
2592
  // kernel/sidecar/store.ts
2362
2593
  import { existsSync as existsSync9, readFileSync as readFileSync9 } from "fs";
2363
- import { dirname as dirname6, resolve as resolve9 } from "path";
2594
+ import { dirname as dirname6, resolve as resolve10 } from "path";
2364
2595
  import { createRequire as createRequire4 } from "module";
2365
2596
  import { Ajv2020 as Ajv20205 } from "ajv/dist/2020.js";
2366
2597
  import yaml3 from "js-yaml";
@@ -2612,7 +2843,12 @@ async function walkAndExtract(opts) {
2612
2843
  const walkOptions = opts.ignoreFilter ? { ignoreFilter: opts.ignoreFilter } : {};
2613
2844
  let filesWalked = 0;
2614
2845
  let index = 0;
2615
- for (const provider of opts.providers) {
2846
+ const activeProviders = opts.providers.filter((provider) => {
2847
+ if (!provider.gatedByActiveLens) return true;
2848
+ if (opts.activeProvider === null) return true;
2849
+ return provider.id === opts.activeProvider;
2850
+ });
2851
+ for (const provider of activeProviders) {
2616
2852
  for await (const raw of resolveProviderWalk(provider)(opts.roots, walkOptions)) {
2617
2853
  filesWalked += 1;
2618
2854
  if (claimedPaths.has(raw.path)) continue;
@@ -2633,7 +2869,8 @@ async function walkAndExtract(opts) {
2633
2869
  contributions: accum.contributionsBuffer,
2634
2870
  freshlyRunTuples: accum.freshlyRunTuples,
2635
2871
  orphanSidecars,
2636
- sidecarRoots: accum.sidecarRoots
2872
+ sidecarRoots: accum.sidecarRoots,
2873
+ signals: accum.signals
2637
2874
  };
2638
2875
  }
2639
2876
  function createWalkAccumulators() {
@@ -2641,6 +2878,7 @@ function createWalkAccumulators() {
2641
2878
  nodes: [],
2642
2879
  internalLinks: [],
2643
2880
  externalLinks: [],
2881
+ signals: [],
2644
2882
  cachedPaths: /* @__PURE__ */ new Set(),
2645
2883
  frontmatterIssues: [],
2646
2884
  enrichmentBuffer: /* @__PURE__ */ new Map(),
@@ -2786,6 +3024,7 @@ function recordFreshlyRunTuples(extractors, nodePath, accum) {
2786
3024
  function mergeExtractResult(extractResult, accum) {
2787
3025
  for (const link of extractResult.internalLinks) accum.internalLinks.push(link);
2788
3026
  for (const link of extractResult.externalLinks) accum.externalLinks.push(link);
3027
+ for (const signal of extractResult.signals) accum.signals.push(signal);
2789
3028
  for (const enr of extractResult.enrichments) {
2790
3029
  accum.enrichmentBuffer.set(`${enr.nodePath}\0${enr.extractorId}`, enr);
2791
3030
  }
@@ -2888,6 +3127,7 @@ async function runScanInternal(_kernel, options) {
2888
3127
  const scanStartedEvent = makeEvent("scan.started", { roots: options.roots });
2889
3128
  emitter.emit(scanStartedEvent);
2890
3129
  await hookDispatcher.dispatch("scan.started", scanStartedEvent);
3130
+ const activeProviderId = resolveActiveProviderOption(options.activeProvider, options.roots);
2891
3131
  const walked = await walkAndExtract({
2892
3132
  providers: exts.providers,
2893
3133
  extractors: exts.extractors,
@@ -2902,9 +3142,20 @@ async function runScanInternal(_kernel, options) {
2902
3142
  priorExtractorRuns: setup.priorExtractorRuns,
2903
3143
  providerFrontmatter: setup.providerFrontmatter,
2904
3144
  pluginStores: options.pluginStores,
2905
- activeProvider: resolveActiveProviderOption(options.activeProvider, options.roots)
3145
+ activeProvider: activeProviderId
2906
3146
  });
2907
- const postWalkCtx = buildPostWalkTransformCtx(_kernel);
3147
+ const activeProvider = activeProviderId ? exts.providers.find((p) => p.id === activeProviderId) ?? null : null;
3148
+ const resolved = resolveSignals({
3149
+ signals: walked.signals,
3150
+ activeProvider,
3151
+ extractorOrder: exts.extractors.map((e) => e.id)
3152
+ });
3153
+ for (const link of resolved.links) {
3154
+ if (isExternalUrlLink(link)) walked.externalLinks.push(link);
3155
+ else walked.internalLinks.push(link);
3156
+ }
3157
+ walked.signals = resolved.resolvedSignals;
3158
+ const postWalkCtx = buildPostWalkTransformCtx(exts.providers, walked.nodes);
2908
3159
  walked.internalLinks = applyPostWalkTransforms(walked.internalLinks, walked.nodes, postWalkCtx);
2909
3160
  recomputeLinkCounts(walked.nodes, walked.internalLinks);
2910
3161
  recomputeExternalRefsCount(walked.nodes, walked.externalLinks, walked.cachedPaths);
@@ -2925,7 +3176,9 @@ async function runScanInternal(_kernel, options) {
2925
3176
  options.cwd,
2926
3177
  registeredActionIds,
2927
3178
  emitter,
2928
- hookDispatcher
3179
+ hookDispatcher,
3180
+ postWalkCtx.reservedNodePaths,
3181
+ walked.signals
2929
3182
  );
2930
3183
  mergeAnalyzerEmissions(walked, analyzerResult, exts.analyzers);
2931
3184
  const issues = analyzerResult.issues;
@@ -2938,10 +3191,19 @@ async function runScanInternal(_kernel, options) {
2938
3191
  await hookDispatcher.dispatch("scan.completed", scanCompletedEvent);
2939
3192
  return buildScanReturn(walked, issues, renameOps, stats, options, setup);
2940
3193
  }
2941
- function buildPostWalkTransformCtx(kernel) {
3194
+ function buildPostWalkTransformCtx(providers, nodes) {
3195
+ const { kindRegistry, providerResolution, reservedNamesByProviderKind } = buildProviderIndexes(providers);
3196
+ const reservedNodePaths = buildReservedNodePaths(
3197
+ nodes,
3198
+ kindRegistry,
3199
+ reservedNamesByProviderKind
3200
+ );
3201
+ return { kindRegistry, providerResolution, reservedNodePaths };
3202
+ }
3203
+ function buildProviderIndexes(providers) {
2942
3204
  const kindRegistry = /* @__PURE__ */ new Map();
2943
3205
  const providerResolution = /* @__PURE__ */ new Map();
2944
- const providers = kernel.registry.all("provider");
3206
+ const reservedNamesByProviderKind = /* @__PURE__ */ new Map();
2945
3207
  for (const provider of providers) {
2946
3208
  if (provider.kinds) {
2947
3209
  for (const [kindName, descriptor] of Object.entries(provider.kinds)) {
@@ -2951,8 +3213,32 @@ function buildPostWalkTransformCtx(kernel) {
2951
3213
  if (provider.resolution) {
2952
3214
  providerResolution.set(provider.id, provider.resolution);
2953
3215
  }
3216
+ if (provider.reservedNames) {
3217
+ indexReservedNames(provider, reservedNamesByProviderKind);
3218
+ }
3219
+ }
3220
+ return { kindRegistry, providerResolution, reservedNamesByProviderKind };
3221
+ }
3222
+ function indexReservedNames(provider, out) {
3223
+ for (const [kindName, list] of Object.entries(provider.reservedNames ?? {})) {
3224
+ const normalised = new Set(list.map((raw) => normalizeTrigger(raw)).filter(Boolean));
3225
+ if (normalised.size > 0) {
3226
+ out.set(`${provider.id}/${kindName}`, normalised);
3227
+ }
2954
3228
  }
2955
- return { kindRegistry, providerResolution };
3229
+ }
3230
+ function buildReservedNodePaths(nodes, kindRegistry, reservedNamesByProviderKind) {
3231
+ const out = /* @__PURE__ */ new Set();
3232
+ for (const node of nodes) {
3233
+ const key = `${node.provider}/${node.kind}`;
3234
+ const reservedSet = reservedNamesByProviderKind.get(key);
3235
+ if (!reservedSet || reservedSet.size === 0) continue;
3236
+ const ids = deriveNodeIdentifiers(node, kindRegistry.get(key));
3237
+ if (ids.some((id) => reservedSet.has(id))) {
3238
+ out.add(node.path);
3239
+ }
3240
+ }
3241
+ return out;
2956
3242
  }
2957
3243
  function buildScanSetup(options) {
2958
3244
  const start = Date.now();
@@ -3045,7 +3331,7 @@ function validateRoots(roots) {
3045
3331
  function resolveActiveProviderOption(optionValue, roots) {
3046
3332
  if (optionValue !== void 0) return optionValue;
3047
3333
  for (const root of roots) {
3048
- const absRoot = isAbsolute4(root) ? root : resolve10(root);
3334
+ const absRoot = isAbsolute4(root) ? root : resolve11(root);
3049
3335
  if (!existsSync11(absRoot)) continue;
3050
3336
  const detected = resolveActiveProvider(absRoot).resolved;
3051
3337
  if (detected !== null) return detected;
@@ -3054,10 +3340,10 @@ function resolveActiveProviderOption(optionValue, roots) {
3054
3340
  }
3055
3341
 
3056
3342
  // kernel/scan/watcher.ts
3057
- import { resolve as resolve11, relative as relative4, sep as sep3 } from "path";
3343
+ import { resolve as resolve12, relative as relative4, sep as sep3 } from "path";
3058
3344
  import chokidar from "chokidar";
3059
3345
  function createChokidarWatcher(opts) {
3060
- const absRoots = opts.roots.map((r) => resolve11(opts.cwd, r));
3346
+ const absRoots = opts.roots.map((r) => resolve12(opts.cwd, r));
3061
3347
  const ignoreFilterOpt = opts.ignoreFilter;
3062
3348
  const getFilter = ignoreFilterOpt === void 0 ? void 0 : typeof ignoreFilterOpt === "function" ? ignoreFilterOpt : () => ignoreFilterOpt;
3063
3349
  const ignored = getFilter ? (path) => {