@skill-map/cli 0.36.0 → 0.38.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.
Files changed (34) hide show
  1. package/dist/cli/tutorial/sm-tutorial/SKILL.md +100 -13
  2. package/dist/cli.js +2684 -988
  3. package/dist/cli.js.map +1 -1
  4. package/dist/conformance/index.d.ts +4 -4
  5. package/dist/conformance/index.js +48 -2
  6. package/dist/conformance/index.js.map +1 -1
  7. package/dist/index.d.ts +1 -1
  8. package/dist/index.js +256 -25
  9. package/dist/index.js.map +1 -1
  10. package/dist/kernel/index.d.ts +232 -17
  11. package/dist/kernel/index.js +256 -25
  12. package/dist/kernel/index.js.map +1 -1
  13. package/dist/migrations/001_initial.sql +26 -0
  14. package/dist/ui/chunk-47MG5XH2.js +317 -0
  15. package/dist/ui/{chunk-YZ7KCL3G.js → chunk-4CDTW64C.js} +1 -1
  16. package/dist/ui/chunk-4XEJUDPL.js +123 -0
  17. package/dist/ui/{chunk-2QZDJSJN.js → chunk-5AZ5S6JB.js} +1 -1
  18. package/dist/ui/{chunk-TKV6TXTI.js → chunk-AAR3Y55J.js} +3 -3
  19. package/dist/ui/chunk-CR3AANNX.js +3 -0
  20. package/dist/ui/{chunk-UMCC32EJ.js → chunk-G5CKBDBB.js} +1 -1
  21. package/dist/ui/{chunk-5CFY2K3Y.js → chunk-KKOZFBXQ.js} +1 -1
  22. package/dist/ui/{chunk-UK5YFHL3.js → chunk-NTM2J2WO.js} +5 -5
  23. package/dist/ui/{chunk-LTQTJU54.js → chunk-O5N7UH37.js} +13 -13
  24. package/dist/ui/{chunk-FQOZBFJ5.js → chunk-QZM2G474.js} +2 -2
  25. package/dist/ui/chunk-Z4LANJFK.js +1 -0
  26. package/dist/ui/index.html +6 -9
  27. package/dist/ui/main-EO5QNLE4.js +2 -0
  28. package/migrations/001_initial.sql +26 -0
  29. package/package.json +4 -4
  30. package/dist/ui/chunk-5JBW2LUN.js +0 -2
  31. package/dist/ui/chunk-GQ5YNA5Q.js +0 -123
  32. package/dist/ui/chunk-KJQEO6P3.js +0 -1
  33. package/dist/ui/chunk-L3OLNVKI.js +0 -317
  34. package/dist/ui/main-MGFSWAOX.js +0 -2
package/dist/index.js CHANGED
@@ -43,7 +43,7 @@ var DuplicateExtensionError = class extends Error {
43
43
  }
44
44
  };
45
45
  var Registry = class {
46
- /** kind → qualifiedId → Extension. */
46
+ /** kind → qualifiedId → IExtension. */
47
47
  #byKind;
48
48
  constructor() {
49
49
  this.#byKind = new Map(
@@ -101,7 +101,7 @@ import cl100k_base from "js-tiktoken/ranks/cl100k_base";
101
101
  // package.json
102
102
  var package_default = {
103
103
  name: "@skill-map/cli",
104
- version: "0.36.0",
104
+ version: "0.38.0",
105
105
  description: "skill-map reference implementation \u2014 kernel + CLI + adapters.",
106
106
  license: "MIT",
107
107
  type: "module",
@@ -184,7 +184,7 @@ var package_default = {
184
184
  semver: "7.7.4",
185
185
  "smol-toml": "1.6.1",
186
186
  typanion: "3.14.0",
187
- ws: "8.20.0"
187
+ ws: "8.21.0"
188
188
  },
189
189
  devDependencies: {
190
190
  "@eslint/js": "10.0.1",
@@ -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
  },
@@ -700,7 +700,7 @@ import { join as join6 } from "path";
700
700
 
701
701
  // core/config/helper.ts
702
702
  import { homedir as osHomedir } from "os";
703
- import { isAbsolute as isAbsolute2, join as join5, resolve as resolve6 } from "path";
703
+ import { isAbsolute as isAbsolute2, join as join5, resolve as resolve6, sep } from "path";
704
704
 
705
705
  // kernel/config/loader.ts
706
706
  import { existsSync as existsSync3, readFileSync as readFileSync5 } from "fs";
@@ -1396,6 +1396,20 @@ function dedupeLinks(links) {
1396
1396
  if (link.confidence > existing.confidence) {
1397
1397
  existing.confidence = link.confidence;
1398
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
+ }
1399
1413
  continue;
1400
1414
  }
1401
1415
  out.set(key, link);
@@ -1419,12 +1433,23 @@ function recomputeLinkCounts(nodes, links) {
1419
1433
  function recomputeExternalRefsCount(nodes, externalLinks, cachedPaths) {
1420
1434
  const byPath2 = /* @__PURE__ */ new Map();
1421
1435
  for (const node of nodes) {
1422
- if (!cachedPaths.has(node.path)) node.externalRefsCount = 0;
1436
+ if (!cachedPaths.has(node.path)) {
1437
+ node.externalRefsCount = 0;
1438
+ delete node.externalRefs;
1439
+ }
1423
1440
  byPath2.set(node.path, node);
1424
1441
  }
1425
1442
  for (const link of externalLinks) {
1426
1443
  const source = byPath2.get(link.source);
1427
- 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;
1428
1453
  }
1429
1454
  }
1430
1455
  var EXTERNAL_URL_SCHEME_RE = /^[a-z][a-z0-9+\-.]+:/i;
@@ -1435,7 +1460,7 @@ function isExternalUrlLink(link) {
1435
1460
  }
1436
1461
 
1437
1462
  // kernel/orchestrator/analyzers.ts
1438
- async function runAnalyzers(analyzers, nodes, internalLinks, orphanSidecars, sidecarRoots, annotationContributions, viewContributions, orphanJobFiles, referenceablePaths, cwd, registeredActionIds, emitter, hookDispatcher, reservedNodePaths) {
1463
+ async function runAnalyzers(analyzers, nodes, internalLinks, orphanSidecars, sidecarRoots, annotationContributions, viewContributions, orphanJobFiles, referenceablePaths, cwd, registeredActionIds, emitter, hookDispatcher, reservedNodePaths, signals) {
1439
1464
  const issues = [];
1440
1465
  const contributions = [];
1441
1466
  const validators = loadSchemaValidators();
@@ -1500,6 +1525,7 @@ async function runAnalyzers(analyzers, nodes, internalLinks, orphanSidecars, sid
1500
1525
  ...referenceablePaths ? { referenceablePaths } : {},
1501
1526
  ...cwd ? { cwd } : {},
1502
1527
  ...reservedNodePaths ? { reservedNodePaths } : {},
1528
+ ...signals && signals.length > 0 ? { signals } : {},
1503
1529
  emitContribution
1504
1530
  });
1505
1531
  for (const issue of emitted) {
@@ -1780,6 +1806,7 @@ function liftResolvedLinkConfidence(links, nodes, ctx) {
1780
1806
  const resolution = resolve7(link, indexes, ctx);
1781
1807
  if (resolution === "none") continue;
1782
1808
  link.confidence = ctx.reservedNodePaths.has(resolution) ? RESERVED_TARGET_CONFIDENCE : 1;
1809
+ link.resolvedTarget = resolution;
1783
1810
  }
1784
1811
  }
1785
1812
  function buildIndexes(nodes, ctx) {
@@ -1860,6 +1887,190 @@ function applyPostWalkTransforms(links, nodes, ctx, transforms = POST_WALK_TRANS
1860
1887
  return current;
1861
1888
  }
1862
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
+
1863
2074
  // kernel/orchestrator/renames.ts
1864
2075
  function findHighConfidenceRenames(opts) {
1865
2076
  const ops = [];
@@ -1994,7 +2205,7 @@ function detectRenamesAndOrphans(prior, current, issues, silenced) {
1994
2205
 
1995
2206
  // kernel/scan/walk-content.ts
1996
2207
  import { readFile, readdir, lstat } from "fs/promises";
1997
- import { join as join7, relative as relative2, sep } from "path";
2208
+ import { join as join7, relative as relative2, sep as sep2 } from "path";
1998
2209
 
1999
2210
  // kernel/scan/ignore.ts
2000
2211
  import { existsSync as existsSync6, readFileSync as readFileSync7 } from "fs";
@@ -2151,7 +2362,7 @@ async function* walkContent(roots, options) {
2151
2362
  const extensions = options.extensions;
2152
2363
  for (const root of roots) {
2153
2364
  for await (const file of walkRoot(root, root, filter, extensions)) {
2154
- const relPath = relative2(root, file).split(sep).join("/");
2365
+ const relPath = relative2(root, file).split(sep2).join("/");
2155
2366
  let raw;
2156
2367
  try {
2157
2368
  raw = await readFile(file, "utf8");
@@ -2183,7 +2394,7 @@ async function* walkRoot(root, current, filter, extensions) {
2183
2394
  for (const entry of entries) {
2184
2395
  const name = entry.name;
2185
2396
  const full = join7(current, name);
2186
- const rel = relative2(root, full).split(sep).join("/");
2397
+ const rel = relative2(root, full).split(sep2).join("/");
2187
2398
  if (filter.ignores(rel)) continue;
2188
2399
  if (entry.isSymbolicLink()) continue;
2189
2400
  if (entry.isDirectory()) {
@@ -2339,7 +2550,7 @@ function computeDriftStatus(args) {
2339
2550
 
2340
2551
  // kernel/sidecar/discover-orphans.ts
2341
2552
  import { existsSync as existsSync8, readdirSync as readdirSync3, statSync as statSync3 } from "fs";
2342
- import { join as join8, relative as relative3, sep as sep2 } from "path";
2553
+ import { join as join8, relative as relative3, sep as sep3 } from "path";
2343
2554
  function discoverOrphanSidecars(roots, shouldSkip) {
2344
2555
  const out = [];
2345
2556
  for (const root of roots) {
@@ -2356,7 +2567,7 @@ function walk(root, current, shouldSkip, out) {
2356
2567
  }
2357
2568
  for (const entry of entries) {
2358
2569
  const full = join8(current, entry.name);
2359
- const rel = relative3(root, full).split(sep2).join("/");
2570
+ const rel = relative3(root, full).split(sep3).join("/");
2360
2571
  if (shouldSkip(rel)) continue;
2361
2572
  if (entry.isSymbolicLink()) continue;
2362
2573
  if (entry.isDirectory()) {
@@ -2632,7 +2843,12 @@ async function walkAndExtract(opts) {
2632
2843
  const walkOptions = opts.ignoreFilter ? { ignoreFilter: opts.ignoreFilter } : {};
2633
2844
  let filesWalked = 0;
2634
2845
  let index = 0;
2635
- 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) {
2636
2852
  for await (const raw of resolveProviderWalk(provider)(opts.roots, walkOptions)) {
2637
2853
  filesWalked += 1;
2638
2854
  if (claimedPaths.has(raw.path)) continue;
@@ -2653,7 +2869,8 @@ async function walkAndExtract(opts) {
2653
2869
  contributions: accum.contributionsBuffer,
2654
2870
  freshlyRunTuples: accum.freshlyRunTuples,
2655
2871
  orphanSidecars,
2656
- sidecarRoots: accum.sidecarRoots
2872
+ sidecarRoots: accum.sidecarRoots,
2873
+ signals: accum.signals
2657
2874
  };
2658
2875
  }
2659
2876
  function createWalkAccumulators() {
@@ -2661,6 +2878,7 @@ function createWalkAccumulators() {
2661
2878
  nodes: [],
2662
2879
  internalLinks: [],
2663
2880
  externalLinks: [],
2881
+ signals: [],
2664
2882
  cachedPaths: /* @__PURE__ */ new Set(),
2665
2883
  frontmatterIssues: [],
2666
2884
  enrichmentBuffer: /* @__PURE__ */ new Map(),
@@ -2806,6 +3024,7 @@ function recordFreshlyRunTuples(extractors, nodePath, accum) {
2806
3024
  function mergeExtractResult(extractResult, accum) {
2807
3025
  for (const link of extractResult.internalLinks) accum.internalLinks.push(link);
2808
3026
  for (const link of extractResult.externalLinks) accum.externalLinks.push(link);
3027
+ for (const signal of extractResult.signals) accum.signals.push(signal);
2809
3028
  for (const enr of extractResult.enrichments) {
2810
3029
  accum.enrichmentBuffer.set(`${enr.nodePath}\0${enr.extractorId}`, enr);
2811
3030
  }
@@ -2908,6 +3127,7 @@ async function runScanInternal(_kernel, options) {
2908
3127
  const scanStartedEvent = makeEvent("scan.started", { roots: options.roots });
2909
3128
  emitter.emit(scanStartedEvent);
2910
3129
  await hookDispatcher.dispatch("scan.started", scanStartedEvent);
3130
+ const activeProviderId = resolveActiveProviderOption(options.activeProvider, options.roots);
2911
3131
  const walked = await walkAndExtract({
2912
3132
  providers: exts.providers,
2913
3133
  extractors: exts.extractors,
@@ -2922,9 +3142,20 @@ async function runScanInternal(_kernel, options) {
2922
3142
  priorExtractorRuns: setup.priorExtractorRuns,
2923
3143
  providerFrontmatter: setup.providerFrontmatter,
2924
3144
  pluginStores: options.pluginStores,
2925
- activeProvider: resolveActiveProviderOption(options.activeProvider, options.roots)
3145
+ activeProvider: activeProviderId
3146
+ });
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)
2926
3152
  });
2927
- const postWalkCtx = buildPostWalkTransformCtx(_kernel, walked.nodes);
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);
2928
3159
  walked.internalLinks = applyPostWalkTransforms(walked.internalLinks, walked.nodes, postWalkCtx);
2929
3160
  recomputeLinkCounts(walked.nodes, walked.internalLinks);
2930
3161
  recomputeExternalRefsCount(walked.nodes, walked.externalLinks, walked.cachedPaths);
@@ -2946,7 +3177,8 @@ async function runScanInternal(_kernel, options) {
2946
3177
  registeredActionIds,
2947
3178
  emitter,
2948
3179
  hookDispatcher,
2949
- postWalkCtx.reservedNodePaths
3180
+ postWalkCtx.reservedNodePaths,
3181
+ walked.signals
2950
3182
  );
2951
3183
  mergeAnalyzerEmissions(walked, analyzerResult, exts.analyzers);
2952
3184
  const issues = analyzerResult.issues;
@@ -2959,8 +3191,8 @@ async function runScanInternal(_kernel, options) {
2959
3191
  await hookDispatcher.dispatch("scan.completed", scanCompletedEvent);
2960
3192
  return buildScanReturn(walked, issues, renameOps, stats, options, setup);
2961
3193
  }
2962
- function buildPostWalkTransformCtx(kernel, nodes) {
2963
- const { kindRegistry, providerResolution, reservedNamesByProviderKind } = buildProviderIndexes(kernel);
3194
+ function buildPostWalkTransformCtx(providers, nodes) {
3195
+ const { kindRegistry, providerResolution, reservedNamesByProviderKind } = buildProviderIndexes(providers);
2964
3196
  const reservedNodePaths = buildReservedNodePaths(
2965
3197
  nodes,
2966
3198
  kindRegistry,
@@ -2968,11 +3200,10 @@ function buildPostWalkTransformCtx(kernel, nodes) {
2968
3200
  );
2969
3201
  return { kindRegistry, providerResolution, reservedNodePaths };
2970
3202
  }
2971
- function buildProviderIndexes(kernel) {
3203
+ function buildProviderIndexes(providers) {
2972
3204
  const kindRegistry = /* @__PURE__ */ new Map();
2973
3205
  const providerResolution = /* @__PURE__ */ new Map();
2974
3206
  const reservedNamesByProviderKind = /* @__PURE__ */ new Map();
2975
- const providers = kernel.registry.all("provider");
2976
3207
  for (const provider of providers) {
2977
3208
  if (provider.kinds) {
2978
3209
  for (const [kindName, descriptor] of Object.entries(provider.kinds)) {
@@ -3109,7 +3340,7 @@ function resolveActiveProviderOption(optionValue, roots) {
3109
3340
  }
3110
3341
 
3111
3342
  // kernel/scan/watcher.ts
3112
- import { resolve as resolve12, relative as relative4, sep as sep3 } from "path";
3343
+ import { resolve as resolve12, relative as relative4, sep as sep4 } from "path";
3113
3344
  import chokidar from "chokidar";
3114
3345
  function createChokidarWatcher(opts) {
3115
3346
  const absRoots = opts.roots.map((r) => resolve12(opts.cwd, r));
@@ -3207,8 +3438,8 @@ function relativePathFromRoots2(absolute, absRoots) {
3207
3438
  for (const root of absRoots) {
3208
3439
  const rel = relative4(root, absolute);
3209
3440
  if (rel === "" || rel === ".") return "";
3210
- if (!rel.startsWith("..") && !rel.startsWith(`..${sep3}`)) {
3211
- return rel.split(sep3).join("/");
3441
+ if (!rel.startsWith("..") && !rel.startsWith(`..${sep4}`)) {
3442
+ return rel.split(sep4).join("/");
3212
3443
  }
3213
3444
  }
3214
3445
  return null;