@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.
- package/README.md +1 -1
- package/dist/cli/tutorial/sm-master/SKILL.md +12 -14
- package/dist/cli/tutorial/sm-master/references/fixture-templates.md +10 -9
- package/dist/cli/tutorial/sm-master/references/tour-plugins.md +3 -3
- package/dist/cli/tutorial/sm-tutorial/SKILL.md +109 -46
- package/dist/cli.js +2559 -913
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +357 -71
- package/dist/index.js.map +1 -1
- package/dist/kernel/index.d.ts +266 -10
- package/dist/kernel/index.js +357 -71
- package/dist/kernel/index.js.map +1 -1
- package/dist/migrations/001_initial.sql +26 -0
- package/dist/ui/chunk-DGXHJVQN.js +317 -0
- package/dist/ui/{chunk-TKV6TXTI.js → chunk-GX2V3PSZ.js} +1 -1
- package/dist/ui/{chunk-P25ABCQU.js → chunk-O2N4CRRW.js} +4 -4
- package/dist/ui/{chunk-FQOZBFJ5.js → chunk-S2NIJM7Z.js} +2 -2
- package/dist/ui/{chunk-KJQEO6P3.js → chunk-VFYNKTSB.js} +1 -1
- package/dist/ui/index.html +1 -1
- package/dist/ui/{main-MNZ7YAUE.js → main-YSELA4XD.js} +2 -2
- package/migrations/001_initial.sql +26 -0
- package/package.json +3 -3
- package/dist/ui/chunk-L3OLNVKI.js +0 -317
package/dist/kernel/index.js
CHANGED
|
@@ -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
|
|
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.
|
|
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.
|
|
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
|
-
|
|
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))
|
|
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
|
|
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/
|
|
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
|
|
1735
|
-
|
|
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
|
|
1751
|
-
if (indexes.byPath.has(link.target)) return
|
|
1752
|
-
return
|
|
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
|
|
1827
|
+
function resolveByName(link, indexes, ctx) {
|
|
1755
1828
|
const stripped = stripTriggerSigil(link.trigger?.normalizedTrigger);
|
|
1756
|
-
if (stripped === null) return
|
|
1829
|
+
if (stripped === null) return "none";
|
|
1757
1830
|
const candidates = indexes.byName.get(stripped);
|
|
1758
|
-
if (!candidates?.length) return
|
|
1831
|
+
if (!candidates?.length) return "none";
|
|
1759
1832
|
const allowedKinds = lookupAllowedKinds(link, indexes, ctx);
|
|
1760
|
-
if (!allowedKinds?.length) return
|
|
1761
|
-
|
|
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
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
const
|
|
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(
|
|
1854
|
+
bucket.push(entry);
|
|
1785
1855
|
} else {
|
|
1786
|
-
byName.set(
|
|
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
|
|
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
|
-
|
|
2246
|
+
resolve8(here, "../../config/defaults/skillmapignore"),
|
|
2016
2247
|
// src/kernel/scan/ → src/config/defaults/
|
|
2017
|
-
|
|
2248
|
+
resolve8(here, "../config/defaults/skillmapignore"),
|
|
2018
2249
|
// dist/cli.js → dist/config/defaults/ (siblings)
|
|
2019
|
-
|
|
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
|
|
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(
|
|
2520
|
+
readFileSync8(resolve9(specRoot, "schemas/annotations.schema.json"), "utf8")
|
|
2290
2521
|
);
|
|
2291
2522
|
const sidecarSchema = JSON.parse(
|
|
2292
|
-
readFileSync8(
|
|
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
|
|
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
|
-
|
|
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:
|
|
3145
|
+
activeProvider: activeProviderId
|
|
2906
3146
|
});
|
|
2907
|
-
const
|
|
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(
|
|
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
|
|
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
|
-
|
|
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 :
|
|
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
|
|
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) =>
|
|
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) => {
|