@skill-map/cli 0.32.0 → 0.33.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/tutorial/sm-tutorial/SKILL.md +27 -7
- package/dist/cli.js +851 -318
- package/dist/cli.js.map +1 -1
- package/dist/index.js +206 -15
- package/dist/index.js.map +1 -1
- package/dist/kernel/index.d.ts +198 -3
- package/dist/kernel/index.js +206 -15
- package/dist/kernel/index.js.map +1 -1
- package/dist/migrations/001_initial.sql +2 -2
- package/dist/ui/chunk-2QZDJSJN.js +1 -0
- package/dist/ui/chunk-5CFY2K3Y.js +135 -0
- package/dist/ui/{chunk-YQIWQVJ6.js → chunk-L3OLNVKI.js} +9 -9
- package/dist/ui/chunk-OKFHCQNJ.js +123 -0
- package/dist/ui/{chunk-47OZB7LR.js → chunk-TKV6TXTI.js} +1 -1
- package/dist/ui/{chunk-WJLIYGWJ.js → chunk-UK5YFHL3.js} +1 -1
- package/dist/ui/{chunk-FEPH4VNB.js → chunk-UMCC32EJ.js} +3 -3
- package/dist/ui/{chunk-VDQLDTTR.js → chunk-YZ7KCL3G.js} +1 -1
- package/dist/ui/index.html +1 -1
- package/dist/ui/main-H7FURBYT.js +2 -0
- package/migrations/001_initial.sql +2 -2
- package/package.json +3 -2
- package/dist/ui/chunk-BCQZKYOD.js +0 -1
- package/dist/ui/chunk-LS2NXZQZ.js +0 -135
- package/dist/ui/chunk-WCE7MTK5.js +0 -123
- package/dist/ui/main-LJIHL73M.js +0 -2
package/dist/index.js
CHANGED
|
@@ -100,7 +100,7 @@ import cl100k_base from "js-tiktoken/ranks/cl100k_base";
|
|
|
100
100
|
// package.json
|
|
101
101
|
var package_default = {
|
|
102
102
|
name: "@skill-map/cli",
|
|
103
|
-
version: "0.
|
|
103
|
+
version: "0.33.0",
|
|
104
104
|
description: "skill-map reference implementation \u2014 kernel + CLI + adapters.",
|
|
105
105
|
license: "MIT",
|
|
106
106
|
type: "module",
|
|
@@ -181,6 +181,7 @@ var package_default = {
|
|
|
181
181
|
"js-yaml": "4.1.1",
|
|
182
182
|
kysely: "0.28.17",
|
|
183
183
|
semver: "7.7.4",
|
|
184
|
+
"smol-toml": "1.6.1",
|
|
184
185
|
typanion: "3.14.0",
|
|
185
186
|
ws: "8.20.0"
|
|
186
187
|
},
|
|
@@ -692,12 +693,22 @@ var ORCHESTRATOR_TEXTS = {
|
|
|
692
693
|
runScanRootMissing: "runScan: root path '{{root}}' does not exist or is not a directory"
|
|
693
694
|
};
|
|
694
695
|
|
|
696
|
+
// kernel/types.ts
|
|
697
|
+
var ConfidenceTier = Object.freeze({
|
|
698
|
+
HIGH: 0.9,
|
|
699
|
+
MEDIUM: 0.6,
|
|
700
|
+
LOW: 0.3
|
|
701
|
+
});
|
|
702
|
+
|
|
695
703
|
// kernel/orchestrator/extractors.ts
|
|
696
704
|
async function runExtractorsForNode(opts) {
|
|
697
705
|
const internalLinks = [];
|
|
698
706
|
const externalLinks = [];
|
|
699
707
|
const enrichmentBuffer = /* @__PURE__ */ new Map();
|
|
700
708
|
const contributions = [];
|
|
709
|
+
const signals = [];
|
|
710
|
+
const virtualNodes = [];
|
|
711
|
+
const virtualNodePaths = /* @__PURE__ */ new Set();
|
|
701
712
|
const validators = loadSchemaValidators();
|
|
702
713
|
for (const extractor of opts.extractors) {
|
|
703
714
|
const qualifiedId = qualifiedExtensionId(extractor.pluginId, extractor.id);
|
|
@@ -769,6 +780,18 @@ async function runExtractorsForNode(opts) {
|
|
|
769
780
|
emittedAt: Date.now()
|
|
770
781
|
});
|
|
771
782
|
};
|
|
783
|
+
const emitSignal = (signal) => {
|
|
784
|
+
const validated = validateSignal(extractor, signal, opts.emitter);
|
|
785
|
+
if (!validated) return;
|
|
786
|
+
signals.push(validated);
|
|
787
|
+
};
|
|
788
|
+
const emitNode = (emitted) => {
|
|
789
|
+
if (virtualNodePaths.has(emitted.path)) return;
|
|
790
|
+
const node = buildVirtualNode(extractor, emitted, opts.emitter);
|
|
791
|
+
if (!node) return;
|
|
792
|
+
virtualNodePaths.add(node.path);
|
|
793
|
+
virtualNodes.push(node);
|
|
794
|
+
};
|
|
772
795
|
const store = opts.pluginStores?.get(extractor.pluginId);
|
|
773
796
|
const ctx = buildExtractorContext(
|
|
774
797
|
extractor,
|
|
@@ -778,6 +801,8 @@ async function runExtractorsForNode(opts) {
|
|
|
778
801
|
emitLink,
|
|
779
802
|
enrichNode,
|
|
780
803
|
emitContribution,
|
|
804
|
+
emitSignal,
|
|
805
|
+
emitNode,
|
|
781
806
|
store
|
|
782
807
|
);
|
|
783
808
|
await extractor.extract(ctx);
|
|
@@ -786,7 +811,9 @@ async function runExtractorsForNode(opts) {
|
|
|
786
811
|
internalLinks,
|
|
787
812
|
externalLinks,
|
|
788
813
|
enrichments: Array.from(enrichmentBuffer.values()),
|
|
789
|
-
contributions
|
|
814
|
+
contributions,
|
|
815
|
+
signals,
|
|
816
|
+
virtualNodes
|
|
790
817
|
};
|
|
791
818
|
}
|
|
792
819
|
function readDeclaredContributions(extension) {
|
|
@@ -811,7 +838,7 @@ function emitExtensionError(emitter, qualifiedId, nodePath, data) {
|
|
|
811
838
|
})
|
|
812
839
|
);
|
|
813
840
|
}
|
|
814
|
-
function buildExtractorContext(extractor, node, body, frontmatter, emitLink, enrichNode, emitContribution, store) {
|
|
841
|
+
function buildExtractorContext(extractor, node, body, frontmatter, emitLink, enrichNode, emitContribution, emitSignal, emitNode, store) {
|
|
815
842
|
const scope = extractor.scope ?? "both";
|
|
816
843
|
const settings = extractor.resolvedSettings ?? {};
|
|
817
844
|
return {
|
|
@@ -822,9 +849,62 @@ function buildExtractorContext(extractor, node, body, frontmatter, emitLink, enr
|
|
|
822
849
|
emitLink,
|
|
823
850
|
enrichNode,
|
|
824
851
|
emitContribution,
|
|
852
|
+
emitSignal,
|
|
853
|
+
emitNode,
|
|
825
854
|
...store !== void 0 ? { store } : {}
|
|
826
855
|
};
|
|
827
856
|
}
|
|
857
|
+
var VIRTUAL_NODE_PLACEHOLDER_HASH = "0".repeat(64);
|
|
858
|
+
function buildVirtualNode(extractor, emitted, emitter) {
|
|
859
|
+
const qualifiedId = qualifiedExtensionId(extractor.pluginId, extractor.id);
|
|
860
|
+
if (typeof emitted.path !== "string" || emitted.path.length === 0) {
|
|
861
|
+
emitter.emit(
|
|
862
|
+
makeEvent("extension.error", {
|
|
863
|
+
kind: "virtual-node-missing-path",
|
|
864
|
+
extensionId: qualifiedId,
|
|
865
|
+
message: `Extractor ${qualifiedId} emitted a virtual node with no path; dropped.`
|
|
866
|
+
})
|
|
867
|
+
);
|
|
868
|
+
return null;
|
|
869
|
+
}
|
|
870
|
+
if (typeof emitted.kind !== "string" || emitted.kind.length === 0) {
|
|
871
|
+
emitter.emit(
|
|
872
|
+
makeEvent("extension.error", {
|
|
873
|
+
kind: "virtual-node-missing-kind",
|
|
874
|
+
extensionId: qualifiedId,
|
|
875
|
+
virtualPath: emitted.path,
|
|
876
|
+
message: `Extractor ${qualifiedId} emitted a virtual node at '${emitted.path}' with no kind; dropped.`
|
|
877
|
+
})
|
|
878
|
+
);
|
|
879
|
+
return null;
|
|
880
|
+
}
|
|
881
|
+
if (!Array.isArray(emitted.derivedFrom) || emitted.derivedFrom.length === 0) {
|
|
882
|
+
emitter.emit(
|
|
883
|
+
makeEvent("extension.error", {
|
|
884
|
+
kind: "virtual-node-missing-derived-from",
|
|
885
|
+
extensionId: qualifiedId,
|
|
886
|
+
virtualPath: emitted.path,
|
|
887
|
+
message: `Extractor ${qualifiedId} emitted a virtual node at '${emitted.path}' with empty derivedFrom; dropped.`
|
|
888
|
+
})
|
|
889
|
+
);
|
|
890
|
+
return null;
|
|
891
|
+
}
|
|
892
|
+
const node = {
|
|
893
|
+
path: emitted.path,
|
|
894
|
+
kind: emitted.kind,
|
|
895
|
+
provider: emitted.provider,
|
|
896
|
+
bodyHash: VIRTUAL_NODE_PLACEHOLDER_HASH,
|
|
897
|
+
frontmatterHash: VIRTUAL_NODE_PLACEHOLDER_HASH,
|
|
898
|
+
bytes: { frontmatter: 0, body: 0, total: 0 },
|
|
899
|
+
linksOutCount: 0,
|
|
900
|
+
linksInCount: 0,
|
|
901
|
+
externalRefsCount: 0,
|
|
902
|
+
virtual: true,
|
|
903
|
+
derivedFrom: [...emitted.derivedFrom]
|
|
904
|
+
};
|
|
905
|
+
if (emitted.frontmatter) node.frontmatter = emitted.frontmatter;
|
|
906
|
+
return node;
|
|
907
|
+
}
|
|
828
908
|
function validateLink(extractor, link, emitter) {
|
|
829
909
|
const knownKinds = ["invokes", "references", "mentions", "supersedes"];
|
|
830
910
|
if (!knownKinds.includes(link.kind)) {
|
|
@@ -845,9 +925,68 @@ function validateLink(extractor, link, emitter) {
|
|
|
845
925
|
);
|
|
846
926
|
return null;
|
|
847
927
|
}
|
|
848
|
-
const
|
|
928
|
+
const c = link.confidence;
|
|
929
|
+
if (c !== void 0 && (typeof c !== "number" || !Number.isFinite(c) || c < 0 || c > 1)) {
|
|
930
|
+
const qualifiedId = `${extractor.pluginId}/${extractor.id}`;
|
|
931
|
+
emitter.emit(
|
|
932
|
+
makeEvent("extension.error", {
|
|
933
|
+
kind: "link-confidence-out-of-range",
|
|
934
|
+
extensionId: qualifiedId,
|
|
935
|
+
confidence: c,
|
|
936
|
+
message: `Extractor ${qualifiedId} emitted a Link with confidence ${String(c)} outside [0..1]; dropped.`
|
|
937
|
+
})
|
|
938
|
+
);
|
|
939
|
+
return null;
|
|
940
|
+
}
|
|
941
|
+
const confidence = c ?? ConfidenceTier.MEDIUM;
|
|
849
942
|
return { ...link, confidence };
|
|
850
943
|
}
|
|
944
|
+
var KNOWN_LINK_KINDS = ["invokes", "references", "mentions", "supersedes"];
|
|
945
|
+
function validateSignal(extractor, signal, emitter) {
|
|
946
|
+
const qualifiedId = qualifiedExtensionId(extractor.pluginId, extractor.id);
|
|
947
|
+
if (!Array.isArray(signal.candidates) || signal.candidates.length === 0) {
|
|
948
|
+
emitter.emit(
|
|
949
|
+
makeEvent("extension.error", {
|
|
950
|
+
kind: "signal-no-candidates",
|
|
951
|
+
extensionId: qualifiedId,
|
|
952
|
+
signal: { source: signal.source, scope: signal.scope },
|
|
953
|
+
message: `Extractor ${qualifiedId} emitted a Signal with no candidates; dropped.`
|
|
954
|
+
})
|
|
955
|
+
);
|
|
956
|
+
return null;
|
|
957
|
+
}
|
|
958
|
+
for (const candidate of signal.candidates) {
|
|
959
|
+
if (!isValidSignalCandidate(qualifiedId, candidate, emitter)) return null;
|
|
960
|
+
}
|
|
961
|
+
return signal;
|
|
962
|
+
}
|
|
963
|
+
function isValidSignalCandidate(qualifiedId, candidate, emitter) {
|
|
964
|
+
if (!KNOWN_LINK_KINDS.includes(candidate.kind)) {
|
|
965
|
+
emitter.emit(
|
|
966
|
+
makeEvent("extension.error", {
|
|
967
|
+
kind: "signal-candidate-kind-not-declared",
|
|
968
|
+
extensionId: qualifiedId,
|
|
969
|
+
candidateKind: candidate.kind,
|
|
970
|
+
declaredKinds: KNOWN_LINK_KINDS,
|
|
971
|
+
message: `Extractor ${qualifiedId} emitted a Signal candidate with off-enum kind '${String(candidate.kind)}'; dropped.`
|
|
972
|
+
})
|
|
973
|
+
);
|
|
974
|
+
return false;
|
|
975
|
+
}
|
|
976
|
+
const c = candidate.confidence;
|
|
977
|
+
if (typeof c !== "number" || !Number.isFinite(c) || c < 0 || c > 1) {
|
|
978
|
+
emitter.emit(
|
|
979
|
+
makeEvent("extension.error", {
|
|
980
|
+
kind: "signal-candidate-confidence-out-of-range",
|
|
981
|
+
extensionId: qualifiedId,
|
|
982
|
+
confidence: candidate.confidence,
|
|
983
|
+
message: `Extractor ${qualifiedId} emitted a Signal candidate with confidence ${String(c)} outside [0..1]; dropped.`
|
|
984
|
+
})
|
|
985
|
+
);
|
|
986
|
+
return false;
|
|
987
|
+
}
|
|
988
|
+
return true;
|
|
989
|
+
}
|
|
851
990
|
function dedupeLinks(links) {
|
|
852
991
|
const out = /* @__PURE__ */ new Map();
|
|
853
992
|
for (const link of links) {
|
|
@@ -894,7 +1033,9 @@ function recomputeExternalRefsCount(nodes, externalLinks, cachedPaths) {
|
|
|
894
1033
|
}
|
|
895
1034
|
}
|
|
896
1035
|
var EXTERNAL_URL_SCHEME_RE = /^[a-z][a-z0-9+\-.]+:/i;
|
|
1036
|
+
var VIRTUAL_NODE_SCHEME_RE = /^mcp:\/\//i;
|
|
897
1037
|
function isExternalUrlLink(link) {
|
|
1038
|
+
if (VIRTUAL_NODE_SCHEME_RE.test(link.target)) return false;
|
|
898
1039
|
return EXTERNAL_URL_SCHEME_RE.test(link.target);
|
|
899
1040
|
}
|
|
900
1041
|
|
|
@@ -1053,13 +1194,9 @@ function originatingNodeOf(link, priorNodePaths) {
|
|
|
1053
1194
|
}
|
|
1054
1195
|
function computeCacheDecision(opts) {
|
|
1055
1196
|
const applicableExtractors = opts.extractors.filter((ex) => {
|
|
1056
|
-
|
|
1057
|
-
if (!
|
|
1058
|
-
return
|
|
1059
|
-
const slashIdx = qualified.indexOf("/");
|
|
1060
|
-
const kindOnly = slashIdx === -1 ? qualified : qualified.slice(slashIdx + 1);
|
|
1061
|
-
return kindOnly === opts.kind;
|
|
1062
|
-
});
|
|
1197
|
+
if (!matchesKindPrecondition(ex, opts.kind)) return false;
|
|
1198
|
+
if (!matchesProviderPrecondition(ex, opts.provider)) return false;
|
|
1199
|
+
return true;
|
|
1063
1200
|
});
|
|
1064
1201
|
const applicableQualifiedIds = new Set(
|
|
1065
1202
|
applicableExtractors.map((ex) => qualifiedExtensionId(ex.pluginId, ex.id))
|
|
@@ -1073,6 +1210,20 @@ function computeCacheDecision(opts) {
|
|
|
1073
1210
|
fullCacheHit: opts.nodeHashCacheEligible && split.missingExtractors.length === 0
|
|
1074
1211
|
};
|
|
1075
1212
|
}
|
|
1213
|
+
function matchesKindPrecondition(ex, kind) {
|
|
1214
|
+
const kinds = ex.precondition?.kind;
|
|
1215
|
+
if (!kinds || kinds.length === 0) return true;
|
|
1216
|
+
return kinds.some((qualified) => {
|
|
1217
|
+
const slashIdx = qualified.indexOf("/");
|
|
1218
|
+
const kindOnly = slashIdx === -1 ? qualified : qualified.slice(slashIdx + 1);
|
|
1219
|
+
return kindOnly === kind;
|
|
1220
|
+
});
|
|
1221
|
+
}
|
|
1222
|
+
function matchesProviderPrecondition(ex, provider) {
|
|
1223
|
+
const providers = ex.precondition?.provider;
|
|
1224
|
+
if (!providers || providers.length === 0) return true;
|
|
1225
|
+
return providers.includes(provider);
|
|
1226
|
+
}
|
|
1076
1227
|
function splitLegacy(applicableExtractors, applicableQualifiedIds, nodeHashCacheEligible) {
|
|
1077
1228
|
const cachedQualifiedIds = /* @__PURE__ */ new Set();
|
|
1078
1229
|
const missingExtractors = [];
|
|
@@ -1182,7 +1333,7 @@ function findHighConfidenceRenames(opts) {
|
|
|
1182
1333
|
if (opts.claimedNew.has(toPath)) continue;
|
|
1183
1334
|
const toNode = opts.currentByPath.get(toPath);
|
|
1184
1335
|
if (toNode.bodyHash === fromNode.bodyHash) {
|
|
1185
|
-
ops.push({ from: fromPath, to: toPath, confidence:
|
|
1336
|
+
ops.push({ from: fromPath, to: toPath, confidence: ConfidenceTier.HIGH });
|
|
1186
1337
|
opts.claimedDeleted.add(fromPath);
|
|
1187
1338
|
opts.claimedNew.add(toPath);
|
|
1188
1339
|
break;
|
|
@@ -1217,13 +1368,13 @@ function claimSingletonRenames(opts) {
|
|
|
1217
1368
|
const remaining = candidates.filter((p) => !opts.claimedDeleted.has(p));
|
|
1218
1369
|
if (remaining.length === 1) {
|
|
1219
1370
|
const fromPath = remaining[0];
|
|
1220
|
-
ops.push({ from: fromPath, to: toPath, confidence:
|
|
1371
|
+
ops.push({ from: fromPath, to: toPath, confidence: ConfidenceTier.MEDIUM });
|
|
1221
1372
|
opts.issues.push({
|
|
1222
1373
|
analyzerId: "auto-rename-medium",
|
|
1223
1374
|
severity: "warn",
|
|
1224
1375
|
nodeIds: [toPath],
|
|
1225
1376
|
message: `Auto-rename (medium confidence): ${fromPath} \u2192 ${toPath}`,
|
|
1226
|
-
data: { from: fromPath, to: toPath, confidence:
|
|
1377
|
+
data: { from: fromPath, to: toPath, confidence: ConfidenceTier.MEDIUM }
|
|
1227
1378
|
});
|
|
1228
1379
|
opts.claimedDeleted.add(fromPath);
|
|
1229
1380
|
opts.claimedNew.add(toPath);
|
|
@@ -1427,10 +1578,45 @@ var plainParser = {
|
|
|
1427
1578
|
}
|
|
1428
1579
|
};
|
|
1429
1580
|
|
|
1581
|
+
// plugins/core/parsers/toml/index.ts
|
|
1582
|
+
import { parse as parseToml } from "smol-toml";
|
|
1583
|
+
var tomlParser = {
|
|
1584
|
+
id: "toml",
|
|
1585
|
+
parse(raw, _path) {
|
|
1586
|
+
let parsed = {};
|
|
1587
|
+
const issues = [];
|
|
1588
|
+
try {
|
|
1589
|
+
const doc = parseToml(raw);
|
|
1590
|
+
if (doc && typeof doc === "object" && !Array.isArray(doc)) {
|
|
1591
|
+
parsed = stripPrototypePollution(doc);
|
|
1592
|
+
}
|
|
1593
|
+
} catch (err) {
|
|
1594
|
+
issues.push({
|
|
1595
|
+
code: "frontmatter-parse-error",
|
|
1596
|
+
message: sanitiseParseErrorMessage2(err)
|
|
1597
|
+
});
|
|
1598
|
+
}
|
|
1599
|
+
const out = {
|
|
1600
|
+
frontmatterRaw: raw,
|
|
1601
|
+
frontmatter: parsed,
|
|
1602
|
+
body: ""
|
|
1603
|
+
};
|
|
1604
|
+
if (issues.length > 0) {
|
|
1605
|
+
return { ...out, issues };
|
|
1606
|
+
}
|
|
1607
|
+
return out;
|
|
1608
|
+
}
|
|
1609
|
+
};
|
|
1610
|
+
function sanitiseParseErrorMessage2(err) {
|
|
1611
|
+
const raw = err instanceof Error ? err.message : String(err);
|
|
1612
|
+
return raw.replace(/[-]+/g, " ").replace(/\s+/g, " ").trim();
|
|
1613
|
+
}
|
|
1614
|
+
|
|
1430
1615
|
// kernel/scan/parsers/index.ts
|
|
1431
1616
|
var REGISTRY = /* @__PURE__ */ new Map([
|
|
1432
1617
|
[frontmatterYamlParser.id, frontmatterYamlParser],
|
|
1433
|
-
[plainParser.id, plainParser]
|
|
1618
|
+
[plainParser.id, plainParser],
|
|
1619
|
+
[tomlParser.id, tomlParser]
|
|
1434
1620
|
]);
|
|
1435
1621
|
var FROZEN_IDS = new Set(REGISTRY.keys());
|
|
1436
1622
|
function getParser(id) {
|
|
@@ -2043,6 +2229,7 @@ async function processRawNode(raw, provider, wctx, accum, claimedPaths, nextInde
|
|
|
2043
2229
|
const cacheDecision = computeCacheDecision({
|
|
2044
2230
|
extractors: wctx.opts.extractors,
|
|
2045
2231
|
kind,
|
|
2232
|
+
provider: provider.id,
|
|
2046
2233
|
nodePath: raw.path,
|
|
2047
2234
|
bodyHash,
|
|
2048
2235
|
sidecarAnnotationsHash,
|
|
@@ -2145,6 +2332,10 @@ function mergeExtractResult(extractResult, accum) {
|
|
|
2145
2332
|
accum.enrichmentBuffer.set(`${enr.nodePath}\0${enr.extractorId}`, enr);
|
|
2146
2333
|
}
|
|
2147
2334
|
for (const c of extractResult.contributions) accum.contributionsBuffer.push(c);
|
|
2335
|
+
for (const vn of extractResult.virtualNodes) {
|
|
2336
|
+
if (accum.nodes.some((n) => n.path === vn.path)) continue;
|
|
2337
|
+
accum.nodes.push(vn);
|
|
2338
|
+
}
|
|
2148
2339
|
}
|
|
2149
2340
|
function isPartialCacheHit(ctx) {
|
|
2150
2341
|
return ctx.nodeHashCacheEligible && ctx.cacheDecision.cachedQualifiedIds.size > 0 && ctx.priorNode !== void 0;
|