@skill-map/cli 0.56.0 → 0.57.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.
@@ -1,6 +1,6 @@
1
1
  // kernel/i18n/registry.texts.ts
2
2
 
3
- !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="bed984e8-cc93-51f3-94cd-c0789fe21577")}catch(e){}}();
3
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="12d40092-5030-5aa9-ba9b-939af94ed740")}catch(e){}}();
4
4
  var REGISTRY_TEXTS = {
5
5
  duplicateExtension: "Extension already registered: {{kind}}:{{qualifiedId}}",
6
6
  unknownKind: "Unknown extension kind: {{kind}}",
@@ -102,7 +102,7 @@ import { Tiktoken as Tiktoken2 } from "js-tiktoken/lite";
102
102
  // package.json
103
103
  var package_default = {
104
104
  name: "@skill-map/cli",
105
- version: "0.56.0",
105
+ version: "0.57.0",
106
106
  description: "skill-map reference implementation \u2014 kernel + CLI + adapters.",
107
107
  license: "MIT",
108
108
  type: "module",
@@ -1269,8 +1269,49 @@ function runActionProjections(actions, nodes, links, emitter) {
1269
1269
  return { contributions, contributionErrors };
1270
1270
  }
1271
1271
 
1272
+ // kernel/orchestrator/confidence-score.ts
1273
+ function foldConfidence(base, ops) {
1274
+ let running = base;
1275
+ for (const op of ops) {
1276
+ if (op.kind === "set") running = op.value;
1277
+ }
1278
+ for (const op of ops) {
1279
+ if (op.kind === "delta") running += op.value;
1280
+ }
1281
+ for (const op of ops) {
1282
+ if (op.kind === "floor") running = Math.max(running, op.value);
1283
+ }
1284
+ for (const op of ops) {
1285
+ if (op.kind === "ceil") running = Math.min(running, op.value);
1286
+ }
1287
+ return clamp01(running);
1288
+ }
1289
+ function clamp01(n) {
1290
+ if (n < 0) return 0;
1291
+ if (n > 1) return 1;
1292
+ return n;
1293
+ }
1294
+ function applyConfidenceAdjustments(adjustments) {
1295
+ if (adjustments.length === 0) return;
1296
+ const byLink = /* @__PURE__ */ new Map();
1297
+ for (const adj of adjustments) {
1298
+ const bucket = byLink.get(adj.link);
1299
+ if (bucket) bucket.push(adj);
1300
+ else byLink.set(adj.link, [adj]);
1301
+ }
1302
+ for (const [link, adjs] of byLink) {
1303
+ const ops = [...adjs].sort(compareAdjustments).map((a) => a.op);
1304
+ link.confidence = foldConfidence(link.confidence, ops);
1305
+ }
1306
+ }
1307
+ function compareAdjustments(a, b) {
1308
+ if (a.pluginId !== b.pluginId) return a.pluginId < b.pluginId ? -1 : 1;
1309
+ if (a.extensionId !== b.extensionId) return a.extensionId < b.extensionId ? -1 : 1;
1310
+ return 0;
1311
+ }
1312
+
1272
1313
  // kernel/orchestrator/analyzers.ts
1273
- async function runAnalyzers(analyzers, nodes, internalLinks, orphanSidecars, sidecarRoots, annotationContributions, viewContributions, orphanJobFiles, referenceablePaths, cwd, registeredActionIds, emitter, hookDispatcher, reservedNodePaths, brokenLinks, signals, seedIssues = []) {
1314
+ async function runAnalyzers(analyzers, nodes, internalLinks, orphanSidecars, sidecarRoots, annotationContributions, viewContributions, referenceablePaths, cwd, registeredActionIds, emitter, hookDispatcher, reservedNodePaths, brokenLinks, nameCollisions, signals, seedIssues = []) {
1274
1315
  const issues = [...seedIssues];
1275
1316
  const contributions = [];
1276
1317
  const contributionErrors = [];
@@ -1281,7 +1322,16 @@ async function runAnalyzers(analyzers, nodes, internalLinks, orphanSidecars, sid
1281
1322
  expectedMdPath: o.expectedMdPath
1282
1323
  }));
1283
1324
  const scheduled = orderAnalyzersByPhase(analyzers);
1325
+ const scoreAdjustments = [];
1326
+ const scorableLinks = new Set(internalLinks);
1327
+ let scoresFolded = false;
1328
+ const foldScores = () => {
1329
+ if (scoresFolded) return;
1330
+ scoresFolded = true;
1331
+ applyConfidenceAdjustments(scoreAdjustments);
1332
+ };
1284
1333
  for (const analyzer of scheduled) {
1334
+ if (analyzer.phase !== "score") foldScores();
1285
1335
  const qualifiedId = qualifiedExtensionId(analyzer.pluginId, analyzer.id);
1286
1336
  const declaredContributions = readDeclaredContributionRefs(analyzer);
1287
1337
  const emitContribution = (nodePath, ref, payload) => {
@@ -1344,6 +1394,16 @@ async function runAnalyzers(analyzers, nodes, internalLinks, orphanSidecars, sid
1344
1394
  emittedAt: Date.now()
1345
1395
  });
1346
1396
  };
1397
+ const adjustConfidence = analyzer.phase === "score" ? (link, op) => {
1398
+ if (scorableLinks.has(link)) {
1399
+ scoreAdjustments.push({
1400
+ link,
1401
+ pluginId: analyzer.pluginId,
1402
+ extensionId: analyzer.id,
1403
+ op
1404
+ });
1405
+ }
1406
+ } : void 0;
1347
1407
  const emitted = await analyzer.evaluate({
1348
1408
  nodes,
1349
1409
  links: internalLinks,
@@ -1355,7 +1415,6 @@ async function runAnalyzers(analyzers, nodes, internalLinks, orphanSidecars, sid
1355
1415
  sidecarRoots,
1356
1416
  annotationContributions,
1357
1417
  viewContributions,
1358
- orphanJobFiles,
1359
1418
  // `issues` is the live accumulator, mutated by `issues.push(...)`
1360
1419
  // below as each analyzer's emission lands. Late-phase analyzers
1361
1420
  // (`core/issue-counter`) read it to compute cross-analyzer
@@ -1365,7 +1424,9 @@ async function runAnalyzers(analyzers, nodes, internalLinks, orphanSidecars, sid
1365
1424
  ...cwd ? { cwd } : {},
1366
1425
  ...reservedNodePaths ? { reservedNodePaths } : {},
1367
1426
  ...brokenLinks ? { brokenLinks } : {},
1427
+ ...nameCollisions && nameCollisions.size > 0 ? { nameCollisions } : {},
1368
1428
  ...signals && signals.length > 0 ? { signals } : {},
1429
+ ...adjustConfidence ? { adjustConfidence } : {},
1369
1430
  emitContribution
1370
1431
  });
1371
1432
  for (const issue of emitted) {
@@ -1376,13 +1437,16 @@ async function runAnalyzers(analyzers, nodes, internalLinks, orphanSidecars, sid
1376
1437
  emitter.emit(evt);
1377
1438
  await hookDispatcher.dispatch("analyzer.completed", evt);
1378
1439
  }
1379
- return { issues, contributions, contributionErrors };
1440
+ foldScores();
1441
+ return { issues, contributions, contributionErrors, linkScores: scoreAdjustments };
1380
1442
  }
1381
1443
  function orderAnalyzersByPhase(analyzers) {
1382
1444
  return analyzers.slice().sort((a, b) => phaseRank(a) - phaseRank(b));
1383
1445
  }
1384
1446
  function phaseRank(a) {
1385
- return a.phase === "aggregate" ? 1 : 0;
1447
+ if (a.phase === "score") return 0;
1448
+ if (a.phase === "aggregate") return 2;
1449
+ return 1;
1386
1450
  }
1387
1451
  function validateIssue(analyzer, issue, emitter) {
1388
1452
  const severity = issue.severity;
@@ -1405,6 +1469,13 @@ function validateIssue(analyzer, issue, emitter) {
1405
1469
  return { ...issue, analyzerId: issue.analyzerId || analyzer.id };
1406
1470
  }
1407
1471
 
1472
+ // kernel/orchestrator/frontmatter-issue-ids.ts
1473
+ var FRONTMATTER_ISSUE_ANALYZERS = /* @__PURE__ */ new Set([
1474
+ "frontmatter-invalid",
1475
+ "frontmatter-malformed",
1476
+ "frontmatter-parse-error"
1477
+ ]);
1478
+
1408
1479
  // kernel/orchestrator/cache.ts
1409
1480
  function indexPriorSnapshot(prior) {
1410
1481
  const priorNodesByPath = /* @__PURE__ */ new Map();
@@ -1433,17 +1504,6 @@ function indexPriorLinks(links, priorNodePaths, byOriginating) {
1433
1504
  else byOriginating.set(key, [link]);
1434
1505
  }
1435
1506
  }
1436
- var FRONTMATTER_ISSUE_ANALYZERS = /* @__PURE__ */ new Set([
1437
- "frontmatter-invalid",
1438
- "frontmatter-malformed",
1439
- // Audit L1: parser parse-error is emitted by
1440
- // `buildFreshNodeAndValidateFrontmatter` from `raw.parseIssues`. The
1441
- // raw.parseIssues only flows through the non-cache path; a cached
1442
- // node skips the rebuild, so the prior issue MUST survive the
1443
- // incremental scan or the warning silently disappears on a clean
1444
- // re-scan of an unchanged file.
1445
- "frontmatter-parse-error"
1446
- ]);
1447
1507
  function indexPriorFrontmatterIssues(issues, byNode) {
1448
1508
  for (const issue of issues) {
1449
1509
  if (!FRONTMATTER_ISSUE_ANALYZERS.has(issue.analyzerId)) continue;
@@ -1641,15 +1701,47 @@ function readDirname(node) {
1641
1701
  const base = pathPosix.basename(dir);
1642
1702
  return base.length > 0 ? base : null;
1643
1703
  }
1704
+ function collectNameCollisions(nodes, kindRegistry) {
1705
+ const byName = indexNameClaims(nodes, kindRegistry);
1706
+ const collisions = /* @__PURE__ */ new Map();
1707
+ for (const [name, claims] of byName) {
1708
+ const distinct = dedupeClaimsByPath(claims);
1709
+ if (distinct.length >= 2) collisions.set(name, distinct);
1710
+ }
1711
+ return collisions;
1712
+ }
1713
+ function indexNameClaims(nodes, kindRegistry) {
1714
+ const byName = /* @__PURE__ */ new Map();
1715
+ for (const node of nodes) {
1716
+ const name = resolvableName(node, kindRegistry);
1717
+ if (name === null) continue;
1718
+ const bucket = byName.get(name) ?? [];
1719
+ bucket.push({ path: node.path, kind: node.kind });
1720
+ byName.set(name, bucket);
1721
+ }
1722
+ return byName;
1723
+ }
1724
+ function resolvableName(node, kindRegistry) {
1725
+ const descriptor = kindRegistry.get(`${node.provider}/${node.kind}`);
1726
+ if (!descriptor?.identifiers?.includes("frontmatter.name")) return null;
1727
+ const raw = node.frontmatter?.["name"];
1728
+ if (typeof raw !== "string" || raw.length === 0) return null;
1729
+ const normalised = normalizeTrigger(raw);
1730
+ return normalised.length > 0 ? normalised : null;
1731
+ }
1732
+ function dedupeClaimsByPath(claims) {
1733
+ return [...new Map(claims.map((c) => [c.path, c])).values()].sort(
1734
+ (a, b) => a.path.localeCompare(b.path)
1735
+ );
1736
+ }
1644
1737
 
1645
1738
  // kernel/orchestrator/lift-resolved-link-confidence.ts
1646
- var RESERVED_TARGET_CONFIDENCE = 0.1;
1647
- var BROKEN_TARGET_CONFIDENCE = 0.5;
1648
1739
  function liftResolvedLinkConfidence(links, nodes, ctx) {
1649
- if (!links.some((l) => l.confidence < 1)) return;
1740
+ if (links.length === 0) return;
1650
1741
  const indexes = buildIndexes(nodes, ctx);
1651
1742
  for (const link of links) {
1652
- if (link.confidence < 1) applyResolution(link, indexes, ctx);
1743
+ link.confidence = 1;
1744
+ applyResolution(link, indexes, ctx);
1653
1745
  }
1654
1746
  }
1655
1747
  function collectBrokenLinks(links, nodes, ctx) {
@@ -1663,15 +1755,8 @@ function collectBrokenLinks(links, nodes, ctx) {
1663
1755
  }
1664
1756
  function applyResolution(link, indexes, ctx) {
1665
1757
  const resolution = resolve5(link, indexes, ctx);
1666
- if (resolution === "none") {
1667
- if (isGenuinelyBroken(link, indexes)) {
1668
- link.confidence = Math.min(link.confidence, BROKEN_TARGET_CONFIDENCE);
1669
- }
1670
- return;
1671
- }
1758
+ if (resolution === "none") return;
1672
1759
  link.resolvedTarget = resolution;
1673
- if (indexes.nodeByPath.get(resolution)?.virtual) return;
1674
- link.confidence = ctx.reservedNodePaths.has(resolution) ? RESERVED_TARGET_CONFIDENCE : 1;
1675
1760
  }
1676
1761
  function buildIndexes(nodes, ctx) {
1677
1762
  const byPath2 = /* @__PURE__ */ new Set();
@@ -3143,6 +3228,7 @@ async function runScanInternal(_kernel, options) {
3143
3228
  const postWalkCtx = buildPostWalkTransformCtx(exts.providers, walked.nodes, activeProviderId);
3144
3229
  walked.internalLinks = applyPostWalkTransforms(walked.internalLinks, walked.nodes, postWalkCtx);
3145
3230
  const brokenLinks = collectBrokenLinks(walked.internalLinks, walked.nodes, postWalkCtx);
3231
+ const nameCollisions = collectNameCollisions(walked.nodes, postWalkCtx.kindRegistry);
3146
3232
  recomputeLinkCounts(walked.nodes, walked.internalLinks);
3147
3233
  recomputeExternalRefsCount(walked.nodes, walked.externalLinks, walked.cachedPaths);
3148
3234
  await dispatchExtractorCompleted(exts.extractors, emitter, hookDispatcher);
@@ -3157,7 +3243,6 @@ async function runScanInternal(_kernel, options) {
3157
3243
  walked.sidecarRoots,
3158
3244
  options.annotationContributions ?? [],
3159
3245
  options.viewContributions ?? [],
3160
- options.orphanJobFiles ?? [],
3161
3246
  options.referenceablePaths,
3162
3247
  options.cwd,
3163
3248
  registeredActionIds,
@@ -3165,6 +3250,7 @@ async function runScanInternal(_kernel, options) {
3165
3250
  hookDispatcher,
3166
3251
  postWalkCtx.reservedNodePaths,
3167
3252
  brokenLinks,
3253
+ nameCollisions,
3168
3254
  walked.signals,
3169
3255
  // Seed the accumulator with orchestrator-emitted frontmatter
3170
3256
  // issues so the aggregate phase (`core/issue-counter`) counts
@@ -3187,7 +3273,7 @@ async function runScanInternal(_kernel, options) {
3187
3273
  const scanCompletedEvent = makeEvent("scan.completed", { stats });
3188
3274
  emitter.emit(scanCompletedEvent);
3189
3275
  await hookDispatcher.dispatch("scan.completed", scanCompletedEvent);
3190
- return buildScanReturn(walked, issues, renameOps, stats, options, setup);
3276
+ return buildScanReturn(walked, issues, renameOps, stats, options, setup, analyzerResult.linkScores);
3191
3277
  }
3192
3278
  function buildPostWalkTransformCtx(providers, nodes, activeProvider) {
3193
3279
  const { kindRegistry, providerResolution, reservedNamesByProviderKind } = buildProviderIndexes(providers);
@@ -3315,7 +3401,7 @@ function buildScanStats(walked, issues, start) {
3315
3401
  durationMs: Date.now() - start
3316
3402
  };
3317
3403
  }
3318
- function buildScanReturn(walked, issues, renameOps, stats, options, setup) {
3404
+ function buildScanReturn(walked, issues, renameOps, stats, options, setup, linkScores) {
3319
3405
  return {
3320
3406
  result: {
3321
3407
  schemaVersion: 1,
@@ -3337,6 +3423,7 @@ function buildScanReturn(walked, issues, renameOps, stats, options, setup) {
3337
3423
  enrichments: walked.enrichments,
3338
3424
  contributions: walked.contributions,
3339
3425
  contributionErrors: walked.contributionErrors,
3426
+ linkScores,
3340
3427
  freshlyRunTuples: walked.freshlyRunTuples
3341
3428
  };
3342
3429
  }
@@ -3766,4 +3853,4 @@ export {
3766
3853
  runScanWithRenames
3767
3854
  };
3768
3855
  //# sourceMappingURL=index.js.map
3769
- //# debugId=bed984e8-cc93-51f3-94cd-c0789fe21577
3856
+ //# debugId=12d40092-5030-5aa9-ba9b-939af94ed740
@@ -472,6 +472,51 @@ CREATE TABLE scan_contribution_errors (
472
472
  CREATE INDEX ix_scan_contribution_errors_plugin_id ON scan_contribution_errors(plugin_id);
473
473
  CREATE INDEX ix_scan_contribution_errors_node_path ON scan_contribution_errors(node_path);
474
474
 
475
+ -- scan_link_scores: per-op confidence-attribution audit trail. One row
476
+ -- per attributed `ctx.adjustConfidence(link, op)` call buffered by a
477
+ -- `score`-phase analyzer during the scan (the kernel's own built-in
478
+ -- `core/name-reserved` / `core/reference-broken` detectors dogfood the
479
+ -- API, applying penalty deltas on top of the kernel's 1.0 baseline). Lets
480
+ -- an operator answer "why is this link at 0.3?" by listing the plugin /
481
+ -- extension / op that moved it, with the FOLDED final value denormalised
482
+ -- onto every row (`result_confidence` mirrors `scan_links.confidence`).
483
+ --
484
+ -- The link is identified by its structural identity fields
485
+ -- (`source_path`, `target`, `kind`, `normalized_trigger`), the same key
486
+ -- `scan_links` dedups on; `normalized_trigger` is NULL for path-style
487
+ -- links that carry no trigger. `op_kind` is the algebra bucket
488
+ -- (`set` / `delta` / `ceil` / `floor`) and `op_value` its operand.
489
+ --
490
+ -- Belongs to the `scan_*` family. Plain REPLACE-ALL per scan (delete
491
+ -- all, then insert), the same posture as `scan_issues` and
492
+ -- `scan_contribution_errors` — NOT the sweep model `scan_contributions`
493
+ -- uses. A score adjustment is a transient scan finding re-derived in
494
+ -- full on every analyzer pass, so there is no cached-node row to
495
+ -- preserve and no compound PK (multiple ops can land on one link). Index
496
+ -- on `source_path` for the per-node "why this link?" lookup + the rename
497
+ -- heuristic-adjacent reads.
498
+ CREATE TABLE scan_link_scores (
499
+ plugin_id TEXT NOT NULL,
500
+ extension_id TEXT NOT NULL,
501
+ source_path TEXT NOT NULL,
502
+ target TEXT NOT NULL,
503
+ kind TEXT NOT NULL,
504
+ -- NULL for path-style links that carry no trigger (the structural
505
+ -- identity key mirrors `scan_links`'s dedup tuple).
506
+ normalized_trigger TEXT,
507
+ -- Confidence-algebra bucket: `set` / `delta` / `ceil` / `floor`. Kept
508
+ -- open at the SQL layer (no CHECK) so the op catalog can evolve as a
509
+ -- kernel + spec change without a DDL migration.
510
+ op_kind TEXT NOT NULL,
511
+ op_value REAL NOT NULL,
512
+ -- Denormalised FOLDED final `link.confidence` after every op for this
513
+ -- link was applied. Equal across all rows for one link; carried per
514
+ -- row so the audit read needs no join back to `scan_links`.
515
+ result_confidence REAL NOT NULL,
516
+ emitted_at INTEGER NOT NULL
517
+ );
518
+ CREATE INDEX ix_scan_link_scores_source_path ON scan_link_scores(source_path);
519
+
475
520
  -- scan_node_tags: tag system. One row per (node_path, tag) pair.
476
521
  -- Projected at persist time from `sidecar.annotations.tags`. Tags are
477
522
  -- a skill-map concept (no vendor carries `tags` in frontmatter), so the