@inerrata-corporation/errata 2.0.0-dev.88 → 2.0.0-dev.89

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.
@@ -17212,6 +17212,9 @@ var DRIFT_VALUES = new Set(Object.values(DRIFT_KIND));
17212
17212
  init_src();
17213
17213
  init_src();
17214
17214
 
17215
+ // ../../packages/local-graph/src/tools.ts
17216
+ init_src();
17217
+
17215
17218
  // ../../packages/local-graph/src/principle-sync.ts
17216
17219
  init_src2();
17217
17220
 
package/errata.mjs CHANGED
@@ -919,6 +919,20 @@ function normalizeToolName(raw2) {
919
919
  function operatingSystemCanonicalId(name2) {
920
920
  return genericCanonicalId("OperatingSystem", { name: name2.trim().toLowerCase() });
921
921
  }
922
+ function osNameForPlatform(platform) {
923
+ switch (platform) {
924
+ case "win32":
925
+ return OS_NAME.windows;
926
+ case "darwin":
927
+ return OS_NAME.macos;
928
+ case "linux":
929
+ return OS_NAME.linux;
930
+ case "android":
931
+ return OS_NAME.android;
932
+ default:
933
+ return null;
934
+ }
935
+ }
922
936
  function packageCanonicalId(p) {
923
937
  const eco = p.ecosystem.toLowerCase();
924
938
  const name2 = eco === "npm" ? p.name.toLowerCase() : p.name;
@@ -939,7 +953,7 @@ function parsePackageRef(ref) {
939
953
  const slug2 = (version2 ? `${name2}@${version2}` : name2).toLowerCase();
940
954
  return { name: name2, version: version2, slug: slug2 };
941
955
  }
942
- var DESIGN_PROBLEM_PREFIX, DESIGN_PROBLEM_ID_LENGTH, DIAGNOSTIC_PROBLEM_PREFIX, DIAGNOSTIC_HASH_LENGTH, TRIAGE_PREFIX, TRIAGE_ID_LENGTH, SAFE_TOOL_NAME;
956
+ var DESIGN_PROBLEM_PREFIX, DESIGN_PROBLEM_ID_LENGTH, DIAGNOSTIC_PROBLEM_PREFIX, DIAGNOSTIC_HASH_LENGTH, TRIAGE_PREFIX, TRIAGE_ID_LENGTH, SAFE_TOOL_NAME, OS_NAME;
943
957
  var init_identity = __esm({
944
958
  "../../packages/shared/src/identity.ts"() {
945
959
  "use strict";
@@ -953,6 +967,12 @@ var init_identity = __esm({
953
967
  TRIAGE_PREFIX = "dtri_";
954
968
  TRIAGE_ID_LENGTH = 56;
955
969
  SAFE_TOOL_NAME = /^[a-z0-9][a-z0-9._+-]{0,63}$/;
970
+ OS_NAME = {
971
+ windows: "Windows",
972
+ macos: "macOS",
973
+ linux: "Linux",
974
+ android: "Android"
975
+ };
956
976
  }
957
977
  });
958
978
 
@@ -15894,6 +15914,7 @@ __export(src_exports, {
15894
15914
  MAX_NODES_PER_PAYLOAD: () => MAX_NODES_PER_PAYLOAD,
15895
15915
  MAX_SIDECAR_SYMBOLS: () => MAX_SIDECAR_SYMBOLS,
15896
15916
  MAX_SYMBOL_SUMMARY_CHARS: () => MAX_SYMBOL_SUMMARY_CHARS,
15917
+ OS_NAME: () => OS_NAME,
15897
15918
  PAGERANK_EXCLUSIONS: () => PAGERANK_EXCLUSIONS,
15898
15919
  PROBLEM_RESOLUTION: () => PROBLEM_RESOLUTION,
15899
15920
  PROJECT_ONLY_EDGE_TYPES: () => PROJECT_ONLY_EDGE_TYPES,
@@ -15951,6 +15972,7 @@ __export(src_exports, {
15951
15972
  normalizeToolName: () => normalizeToolName,
15952
15973
  npmPurl: () => npmPurl,
15953
15974
  operatingSystemCanonicalId: () => operatingSystemCanonicalId,
15975
+ osNameForPlatform: () => osNameForPlatform,
15954
15976
  packageCanonicalId: () => packageCanonicalId,
15955
15977
  pagerankEdgeTypes: () => pagerankEdgeTypes,
15956
15978
  parsePackageLockJson: () => parsePackageLockJson,
@@ -20352,6 +20374,100 @@ var init_problem_dedup = __esm({
20352
20374
  }
20353
20375
  });
20354
20376
 
20377
+ // ../../packages/local-graph/src/tools.ts
20378
+ function toolNodeId(name2) {
20379
+ return `tool:${name2}`;
20380
+ }
20381
+ function osNodeId(name2) {
20382
+ return `os:${name2.toLowerCase()}`;
20383
+ }
20384
+ function resolveOsNode(store, osName, ts) {
20385
+ const id = osNodeId(osName);
20386
+ const existing = store.getNode(id);
20387
+ if (existing) return existing;
20388
+ const node2 = {
20389
+ id,
20390
+ label: "OperatingSystem",
20391
+ description: osName,
20392
+ extractionConfidence: 1,
20393
+ extractionSource: "daemon-extracted",
20394
+ embedding: [],
20395
+ cumulativeSurprise: 0,
20396
+ peakSurprise: 0,
20397
+ cumulativeHits: 0,
20398
+ lastUpdatedAt: ts,
20399
+ createdAt: ts,
20400
+ memoryTier: "short-term",
20401
+ pageRank: 0,
20402
+ isLandmark: false,
20403
+ community: null,
20404
+ stability: "stable",
20405
+ attrs: { name: osName, canonicalId: operatingSystemCanonicalId(osName), public: true }
20406
+ };
20407
+ store.mergeNode(node2);
20408
+ return node2;
20409
+ }
20410
+ function stampObservedOs(store, nodeId, osName, ts) {
20411
+ if (!osName || !store.getNode(nodeId)) return false;
20412
+ const os2 = resolveOsNode(store, osName, ts);
20413
+ const already = store.outEdges(nodeId, ["OCCURS_ON"]).some((e) => e.to === os2.id);
20414
+ if (already) return true;
20415
+ store.mergeEdge({
20416
+ id: `edge_${digest({ from: nodeId, type: "OCCURS_ON", to: os2.id })}`.slice(0, 24),
20417
+ from: nodeId,
20418
+ to: os2.id,
20419
+ type: "OCCURS_ON",
20420
+ confidence: 1,
20421
+ // observed, not inferred — we ran on this platform
20422
+ extractionSource: "daemon-extracted",
20423
+ createdAt: ts,
20424
+ lastSeenAt: ts,
20425
+ navSuccesses: 0,
20426
+ navFailures: 0,
20427
+ attrs: { observed: true }
20428
+ });
20429
+ return true;
20430
+ }
20431
+ function rankToolsForHandles(store, limit = 5) {
20432
+ const scored = store.findNodesByLabel("Tool").map((node2) => ({
20433
+ node: node2,
20434
+ concerns: store.inEdges(node2.id, ["CONCERNS"]).length,
20435
+ hits: node2.cumulativeHits ?? 0
20436
+ }));
20437
+ scored.sort((a, b) => b.concerns - a.concerns || b.hits - a.hits);
20438
+ return scored.slice(0, Math.max(0, limit)).map((s) => s.node);
20439
+ }
20440
+ function toolPriorsFor(store, toolName, ctx, limit = 4) {
20441
+ const tool = store.getNode(toolNodeId(toolName));
20442
+ if (!tool) return [];
20443
+ const pkgs = ctx.workspacePackageIds ?? /* @__PURE__ */ new Set();
20444
+ const fits = [];
20445
+ for (const e of store.inEdges(tool.id, ["CONCERNS"])) {
20446
+ const node2 = store.getNode(e.from);
20447
+ if (!node2) continue;
20448
+ if (node2.attrs["resolvedAs"] === "false_positive") continue;
20449
+ const observedOn = store.outEdges(node2.id, ["OCCURS_ON"]).map((oe) => store.getNode(oe.to)?.description).filter((d) => !!d);
20450
+ const osMismatch = observedOn.length > 0 && !!ctx.os && !observedOn.includes(ctx.os);
20451
+ const deps = store.outEdges(node2.id, ["DEPENDS_ON"]).map((de) => de.to);
20452
+ const stackHits = [];
20453
+ const stackMisses = [];
20454
+ for (const d of deps) {
20455
+ const name2 = String(store.getNode(d)?.attrs["name"] ?? d);
20456
+ (pkgs.has(d) ? stackHits : stackMisses).push(name2);
20457
+ }
20458
+ fits.push({ node: node2, observedOn, osMismatch, stackHits, stackMisses });
20459
+ }
20460
+ const rank = (f) => (f.osMismatch ? 0 : 2) + (f.stackHits.length > 0 ? 1 : 0);
20461
+ fits.sort((a, b) => rank(b) - rank(a) || (b.node.cumulativeHits ?? 0) - (a.node.cumulativeHits ?? 0));
20462
+ return fits.slice(0, Math.max(0, limit));
20463
+ }
20464
+ var init_tools = __esm({
20465
+ "../../packages/local-graph/src/tools.ts"() {
20466
+ "use strict";
20467
+ init_src();
20468
+ }
20469
+ });
20470
+
20355
20471
  // ../../packages/local-graph/src/principle-sync.ts
20356
20472
  function asStrings(v) {
20357
20473
  return Array.isArray(v) ? v : [];
@@ -20514,6 +20630,7 @@ __export(src_exports2, {
20514
20630
  mergeDuplicateProblems: () => mergeDuplicateProblems,
20515
20631
  mintPatternNode: () => mintPatternNode,
20516
20632
  openGraphStore: () => openGraphStore,
20633
+ osNodeId: () => osNodeId,
20517
20634
  parseAbstractionFences: () => parseAbstractionFences,
20518
20635
  parseSemver: () => parseSemver,
20519
20636
  parseTriageFences: () => parseTriageFences,
@@ -20522,6 +20639,7 @@ __export(src_exports2, {
20522
20639
  priorsForFile: () => priorsForFile,
20523
20640
  propagateFactChange: () => propagateFactChange,
20524
20641
  propagateVersionChange: () => propagateVersionChange,
20642
+ rankToolsForHandles: () => rankToolsForHandles,
20525
20643
  recordAnchorHint: () => recordAnchorHint,
20526
20644
  recordClaim: () => recordClaim,
20527
20645
  recordMisreadPrior: () => recordMisreadPrior,
@@ -20531,13 +20649,17 @@ __export(src_exports2, {
20531
20649
  resolveDesignProblemById: () => resolveDesignProblemById,
20532
20650
  resolveDesignProblemByStatement: () => resolveDesignProblemByStatement,
20533
20651
  resolveDesignProblems: () => resolveDesignProblems,
20652
+ resolveOsNode: () => resolveOsNode,
20534
20653
  retractDesignProblemById: () => retractDesignProblemById,
20535
20654
  retractDesignProblemByStatement: () => retractDesignProblemByStatement,
20536
20655
  revisitContradictedPrinciples: () => revisitContradictedPrinciples,
20537
20656
  revisitStaleRoutes: () => revisitStaleRoutes,
20538
20657
  solutionForProblem: () => solutionForProblem,
20539
20658
  splittingAxis: () => splittingAxis,
20659
+ stampObservedOs: () => stampObservedOs,
20540
20660
  staticConductance: () => staticConductance,
20661
+ toolNodeId: () => toolNodeId,
20662
+ toolPriorsFor: () => toolPriorsFor,
20541
20663
  triageOf: () => triageOf,
20542
20664
  walk: () => walk
20543
20665
  });
@@ -20560,6 +20682,7 @@ var init_src4 = __esm({
20560
20682
  init_triage2();
20561
20683
  init_problem_dedup();
20562
20684
  init_problem_package_link();
20685
+ init_tools();
20563
20686
  init_principle_sync();
20564
20687
  }
20565
20688
  });
@@ -20628,7 +20751,7 @@ function buildSnapshot(opts) {
20628
20751
  };
20629
20752
  const langNodes = opts.store.findNodesByLabel("Language");
20630
20753
  const pkgNodes = opts.store.findNodesByLabel("Package");
20631
- const toolNodes = opts.store.findNodesByLabel("Tool").sort((a, b) => (b.cumulativeHits ?? 0) - (a.cumulativeHits ?? 0)).slice(0, 5);
20754
+ const toolNodes = rankToolsForHandles(opts.store, 5);
20632
20755
  const profileContext = {
20633
20756
  languages: opts.profile.languages.map((name2) => ({ name: name2, node: matchNode(langNodes, name2) })),
20634
20757
  packages: opts.profile.stack.map((name2) => ({ name: name2, node: matchNode(pkgNodes, pkgBase(name2)) })),
@@ -45185,8 +45308,8 @@ var init_tldr_tools_generated = __esm({
45185
45308
  });
45186
45309
 
45187
45310
  // src/tool-index.ts
45188
- function toolNodeId(name2) {
45189
- return `tool:${name2}`;
45311
+ function currentOsName() {
45312
+ return osNameForPlatform(process.platform);
45190
45313
  }
45191
45314
  function extractExecutables(command) {
45192
45315
  const out2 = [];
@@ -45211,8 +45334,10 @@ function extractExecutables(command) {
45211
45334
  }
45212
45335
  function observeCommandTools(store, command, ts) {
45213
45336
  const result = { minted: [], reinforced: [] };
45337
+ const osName = currentOsName();
45214
45338
  for (const name2 of extractExecutables(command)) {
45215
45339
  if (!PUBLIC_TOOLS.has(name2)) continue;
45340
+ if (PLUMBING.has(name2)) continue;
45216
45341
  const id = toolNodeId(name2);
45217
45342
  const existing = store.getNode(id);
45218
45343
  if (existing) {
@@ -45245,17 +45370,60 @@ function observeCommandTools(store, command, ts) {
45245
45370
  attrs: { name: name2, canonicalId: toolCanonicalId(name2), public: true }
45246
45371
  });
45247
45372
  result.minted.push(name2);
45373
+ if (osName) {
45374
+ const os2 = resolveOsNode(store, osName, ts);
45375
+ store.mergeEdge({
45376
+ id: `edge_${digest({ from: id, type: "RUNS_ON", to: os2.id })}`.slice(0, 24),
45377
+ from: id,
45378
+ to: os2.id,
45379
+ type: "RUNS_ON",
45380
+ confidence: 1,
45381
+ // observed
45382
+ extractionSource: "daemon-extracted",
45383
+ createdAt: ts,
45384
+ lastSeenAt: ts,
45385
+ navSuccesses: 0,
45386
+ navFailures: 0,
45387
+ attrs: { observed: true }
45388
+ });
45389
+ }
45248
45390
  }
45249
45391
  }
45250
45392
  return result;
45251
45393
  }
45252
- var PUBLIC_TOOLS, PASSTHROUGH, SEGMENT_SPLIT;
45394
+ var PUBLIC_TOOLS, PLUMBING, PASSTHROUGH, SEGMENT_SPLIT;
45253
45395
  var init_tool_index = __esm({
45254
45396
  "src/tool-index.ts"() {
45255
45397
  "use strict";
45256
45398
  init_src();
45399
+ init_src();
45400
+ init_src4();
45257
45401
  init_tldr_tools_generated();
45258
45402
  PUBLIC_TOOLS = new Set(TLDR_TOOL_NAMES);
45403
+ PLUMBING = /* @__PURE__ */ new Set([
45404
+ "cd",
45405
+ "pwd",
45406
+ "ls",
45407
+ "dir",
45408
+ "echo",
45409
+ "clear",
45410
+ "cls",
45411
+ "exit",
45412
+ "true",
45413
+ "false",
45414
+ "which",
45415
+ "where",
45416
+ "alias",
45417
+ "unalias",
45418
+ "history",
45419
+ "set",
45420
+ "unset",
45421
+ "export",
45422
+ "source",
45423
+ "sleep",
45424
+ "time",
45425
+ "type"
45426
+ ]);
45259
45427
  PASSTHROUGH = /* @__PURE__ */ new Set(["sudo", "npx", "pnpx", "bunx", "uvx", "time", "nohup", "xargs", "watch"]);
45260
45428
  SEGMENT_SPLIT = /\|\|?|&&|;|\r?\n/;
45261
45429
  }
@@ -45357,7 +45525,8 @@ __export(webui_exports, {
45357
45525
  decideContextInject: () => decideContextInject,
45358
45526
  fileUriToFsPath: () => fileUriToFsPath,
45359
45527
  findFileByPath: () => findFileByPath,
45360
- recallForFile: () => recallForFile
45528
+ recallForFile: () => recallForFile,
45529
+ recallForTool: () => recallForTool
45361
45530
  });
45362
45531
  import { join as join12 } from "node:path";
45363
45532
  function fileUriToFsPath(raw2) {
@@ -45410,6 +45579,35 @@ function recallForFile(store, relPath) {
45410
45579
  ${lines.join("\n")}
45411
45580
  ` + buildFileRecallInstruction();
45412
45581
  }
45582
+ function workspacePackageIds(store) {
45583
+ const hit = wsPackagesCache.get(store);
45584
+ const now = Date.now();
45585
+ if (hit && now - hit.at < WS_PACKAGES_TTL_MS) return hit.ids;
45586
+ const ids = new Set(store.findNodesByLabel("Package").map((n) => n.id));
45587
+ wsPackagesCache.set(store, { at: now, ids });
45588
+ return ids;
45589
+ }
45590
+ function recallForTool(store, command, ctx) {
45591
+ const lines = [];
45592
+ const seen = /* @__PURE__ */ new Set();
45593
+ for (const name2 of extractExecutables(command)) {
45594
+ if (seen.has(name2)) continue;
45595
+ seen.add(name2);
45596
+ for (const fit of toolPriorsFor(store, name2, ctx, 3)) {
45597
+ const where = fit.osMismatch ? ` \`[${fit.observedOn.join("/")}]\`` : "";
45598
+ const stack = fit.stackHits.length > 0 ? ` \`[${fit.stackHits.join(", ")}]\`` : "";
45599
+ lines.push(
45600
+ `- \`${name2}\`${where}${stack} ${recallLine(
45601
+ fit.node,
45602
+ fit.node.label === "Problem" ? `${TAG_EXAMPLE.fix(fit.node.id)} if you resolved it \xB7 ${TAG_EXAMPLE.prior(fit.node.id)} to cite` : `cite with ${TAG_EXAMPLE.prior(fit.node.id)}`
45603
+ ).slice(2)}`
45604
+ );
45605
+ }
45606
+ }
45607
+ if (lines.length === 0) return null;
45608
+ return `errata \u2014 ${lines.length} prior(s) about the tool(s) you're about to run (a \`[platform]\` tag means it was seen on a DIFFERENT OS than this one \u2014 judge it):
45609
+ ${lines.join("\n")}`;
45610
+ }
45413
45611
  function decideContextInject(args2) {
45414
45612
  const { event, source, sessionId, block, lastInjectedHash } = args2;
45415
45613
  if (!block) return null;
@@ -45581,6 +45779,15 @@ function buildWebUi(deps) {
45581
45779
  }
45582
45780
  return c.json({ ok: true, materialized });
45583
45781
  }
45782
+ if (tool === "Bash" && typeof input["command"] === "string") {
45783
+ try {
45784
+ recallCtx = recallForTool(deps.store, input["command"], {
45785
+ os: currentOsName(),
45786
+ workspacePackageIds: workspacePackageIds(deps.store)
45787
+ });
45788
+ } catch {
45789
+ }
45790
+ }
45584
45791
  }
45585
45792
  const filePath = extractWorkingFile(tool, input);
45586
45793
  let rel = null;
@@ -45672,6 +45879,11 @@ function buildWebUi(deps) {
45672
45879
  }
45673
45880
  return c.body(null, 204);
45674
45881
  }
45882
+ if (event === "PreToolUse" && recallCtx) {
45883
+ return c.json({
45884
+ hookSpecificOutput: { hookEventName: "PreToolUse", additionalContext: recallCtx }
45885
+ });
45886
+ }
45675
45887
  return c.json({ ok: true, event, tool, recognizedFile: filePath ?? null });
45676
45888
  });
45677
45889
  app.post("/api/turn", async (c) => {
@@ -45918,7 +46130,7 @@ function proposalToIngest(p, profile, daemonVersion) {
45918
46130
  payloadDigest: p.id
45919
46131
  };
45920
46132
  }
45921
- var META_LABELS;
46133
+ var wsPackagesCache, WS_PACKAGES_TTL_MS, META_LABELS;
45922
46134
  var init_webui = __esm({
45923
46135
  "src/webui.ts"() {
45924
46136
  "use strict";
@@ -45930,6 +46142,8 @@ var init_webui = __esm({
45930
46142
  init_vfile();
45931
46143
  init_tool_index();
45932
46144
  init_outbox();
46145
+ wsPackagesCache = /* @__PURE__ */ new WeakMap();
46146
+ WS_PACKAGES_TTL_MS = 6e4;
45933
46147
  META_LABELS = /* @__PURE__ */ new Set([
45934
46148
  "Pattern",
45935
46149
  "Technique",
@@ -48977,6 +49191,8 @@ function subagentTranscripts(mainTranscriptPath, sessionId) {
48977
49191
  init_src();
48978
49192
  init_src2();
48979
49193
  init_agent_signals();
49194
+ init_tool_index();
49195
+ init_src4();
48980
49196
  import { readFileSync as readFileSync9, writeFileSync as writeFileSync9 } from "node:fs";
48981
49197
  var NEG = /n['']t|\b(?:not|never|no|none|neither|nor|unrelated|irrelevant|would|might|could|if)\b/i;
48982
49198
  var CITE_GROUP_RE = /\(((?:[^()\n]|\([^()\n]*\)){1,200})\)/g;
@@ -49304,6 +49520,7 @@ function mintPriorEdge(store, source, target, sentence, touched, ts) {
49304
49520
  navFailures: 0,
49305
49521
  attrs: { provisional: true, priorTag: true, primingProvenance: true, corroborated }
49306
49522
  });
49523
+ if (type === "CONCERNS") stampObservedOs(store, source.id, currentOsName(), ts);
49307
49524
  return true;
49308
49525
  }
49309
49526
  function harvestInlineTags(store, text, opts) {
@@ -51015,7 +51232,7 @@ function startLoopLagMonitor(thresholdMs = 1e3) {
51015
51232
  }
51016
51233
 
51017
51234
  // src/engine.ts
51018
- var DAEMON_VERSION = true ? "2.0.0-dev.88" : "2.0.0-alpha.0";
51235
+ var DAEMON_VERSION = true ? "2.0.0-dev.89" : "2.0.0-alpha.0";
51019
51236
  var IGNORED_PATH = /[\\/](?:\.git|node_modules|\.errata|\.claude|\.codex|\.cursor|\.turbo|\.next|dist|coverage|test-results|playwright-report|__pycache__)(?:[\\/]|$)/;
51020
51237
  var IGNORED_NOISE = /castalia\.db|eventlog\.sqlite|turn-cursors/;
51021
51238
  var GIT_OP_MUTE_MS = 4e3;
@@ -56070,7 +56287,7 @@ async function installClaudeHooks(port) {
56070
56287
  }
56071
56288
  const matcher = "Read|Edit|Write|Grep|Glob|NotebookEdit|Bash";
56072
56289
  const postMatcher = `${matcher}|ToolSearch|mcp__errata__.*`;
56073
- const preCmd = `${hookCurlCommand(port)} ${ERRATA_TAG}`;
56290
+ const preCmd = `${hookRelayCommand(port, "/api/hook")} ${ERRATA_TAG}`;
56074
56291
  const postCmd = `${hookRelayCommand(port, "/api/hook")} ${ERRATA_TAG}`;
56075
56292
  settings.hooks ??= {};
56076
56293
  const dropErrata = (list) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inerrata-corporation/errata",
3
- "version": "2.0.0-dev.88",
3
+ "version": "2.0.0-dev.89",
4
4
  "description": "errata - local-first observation engine for AI coding agents",
5
5
  "type": "module",
6
6
  "bin": {
package/pass-worker.mjs CHANGED
@@ -25748,6 +25748,18 @@ function foldDuplicateProblem(store2, dup, survivor, ts) {
25748
25748
  store2.closeNode(dup.id, ts);
25749
25749
  }
25750
25750
 
25751
+ // ../../packages/local-graph/src/tools.ts
25752
+ init_src();
25753
+ function rankToolsForHandles(store2, limit = 5) {
25754
+ const scored = store2.findNodesByLabel("Tool").map((node) => ({
25755
+ node,
25756
+ concerns: store2.inEdges(node.id, ["CONCERNS"]).length,
25757
+ hits: node.cumulativeHits ?? 0
25758
+ }));
25759
+ scored.sort((a, b) => b.concerns - a.concerns || b.hits - a.hits);
25760
+ return scored.slice(0, Math.max(0, limit)).map((s) => s.node);
25761
+ }
25762
+
25751
25763
  // ../../packages/local-graph/src/principle-sync.ts
25752
25764
  init_src2();
25753
25765
 
@@ -26055,7 +26067,7 @@ function buildSnapshot(opts) {
26055
26067
  };
26056
26068
  const langNodes = opts.store.findNodesByLabel("Language");
26057
26069
  const pkgNodes = opts.store.findNodesByLabel("Package");
26058
- const toolNodes = opts.store.findNodesByLabel("Tool").sort((a, b) => (b.cumulativeHits ?? 0) - (a.cumulativeHits ?? 0)).slice(0, 5);
26070
+ const toolNodes = rankToolsForHandles(opts.store, 5);
26059
26071
  const profileContext = {
26060
26072
  languages: opts.profile.languages.map((name2) => ({ name: name2, node: matchNode(langNodes, name2) })),
26061
26073
  packages: opts.profile.stack.map((name2) => ({ name: name2, node: matchNode(pkgNodes, pkgBase(name2)) })),