@inerrata-corporation/errata 2.0.0-dev.87 → 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,
@@ -17359,8 +17381,9 @@ function addDependency(store, opts) {
17359
17381
  return edge2;
17360
17382
  }
17361
17383
  function markRevisit(store, node2, reason, ts) {
17384
+ const fresh = store.getNode(node2.id) ?? node2;
17362
17385
  store.updateNode(node2.id, {
17363
- attrs: { ...node2.attrs, revisit: true, revisitReason: reason, revisitSinceTs: ts },
17386
+ attrs: { ...fresh.attrs, revisit: true, revisitReason: reason, revisitSinceTs: ts },
17364
17387
  lastUpdatedAt: ts
17365
17388
  });
17366
17389
  }
@@ -18456,6 +18479,77 @@ var init_design_problem = __esm({
18456
18479
  }
18457
18480
  });
18458
18481
 
18482
+ // ../../packages/local-graph/src/anchor-backfill.ts
18483
+ function isLegacyAnchor(attrs) {
18484
+ return attrs?.["captureTime"] === true && attrs["anchorProvenance"] === void 0;
18485
+ }
18486
+ function backfillLegacyAnchors(store, ts) {
18487
+ const report = {
18488
+ demotedEdges: 0,
18489
+ demotedProblems: 0,
18490
+ labeledEdges: 0,
18491
+ suspects: []
18492
+ };
18493
+ for (const p of store.findNodesByLabel("Problem")) {
18494
+ const legacy = store.outEdges(p.id, ["ANCHORED_AT"]).filter((e) => isLegacyAnchor(e.attrs));
18495
+ if (legacy.length === 0) continue;
18496
+ const resolved = p.attrs["resolvedAt"] !== void 0;
18497
+ try {
18498
+ if (!resolved) {
18499
+ for (const e of legacy) {
18500
+ const file2 = store.getNode(e.to);
18501
+ const path2 = String(file2?.attrs["relPath"] ?? file2?.description ?? "");
18502
+ if (path2) recordAnchorHint(store, p.id, path2, "legacy", ts);
18503
+ store.deleteEdge(e.id);
18504
+ report.demotedEdges++;
18505
+ }
18506
+ report.demotedProblems++;
18507
+ continue;
18508
+ }
18509
+ for (const e of legacy) {
18510
+ store.mergeEdge({ ...e, attrs: { ...e.attrs, anchorProvenance: "legacy" }, lastSeenAt: ts });
18511
+ report.labeledEdges++;
18512
+ }
18513
+ for (const se of store.outEdges(p.id, ["SOLVED_BY"])) {
18514
+ const sol = store.getNode(se.to);
18515
+ if (!sol || !sol.description.startsWith(AUTO_MINT_PREFIX)) continue;
18516
+ const guessedAnchor = sol.description.slice(AUTO_MINT_PREFIX.length);
18517
+ store.updateNode(sol.id, {
18518
+ attrs: { ...sol.attrs, provisional: true, resolutionSuspect: true },
18519
+ lastUpdatedAt: ts
18520
+ });
18521
+ markRevisit(
18522
+ store,
18523
+ sol,
18524
+ `auto-closed off a pre-provenance anchor (guessed ${guessedAnchor}) \u2014 confirm the problem is really fixed, or reopen it`,
18525
+ ts
18526
+ );
18527
+ store.updateNode(p.id, {
18528
+ attrs: { ...p.attrs, resolutionSuspect: true },
18529
+ lastUpdatedAt: ts
18530
+ });
18531
+ report.suspects.push({
18532
+ problemId: p.id,
18533
+ problem: p.description,
18534
+ solutionId: sol.id,
18535
+ guessedAnchor
18536
+ });
18537
+ }
18538
+ } catch {
18539
+ }
18540
+ }
18541
+ return report;
18542
+ }
18543
+ var AUTO_MINT_PREFIX;
18544
+ var init_anchor_backfill = __esm({
18545
+ "../../packages/local-graph/src/anchor-backfill.ts"() {
18546
+ "use strict";
18547
+ init_justification();
18548
+ init_design_problem();
18549
+ AUTO_MINT_PREFIX = "addressed by an edit to ";
18550
+ }
18551
+ });
18552
+
18459
18553
  // ../../packages/local-graph/src/percolate.ts
18460
18554
  function observedProjects(node2) {
18461
18555
  const v = node2.attrs["observedInProjects"];
@@ -20280,6 +20374,100 @@ var init_problem_dedup = __esm({
20280
20374
  }
20281
20375
  });
20282
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
+
20283
20471
  // ../../packages/local-graph/src/principle-sync.ts
20284
20472
  function asStrings(v) {
20285
20473
  return Array.isArray(v) ? v : [];
@@ -20400,6 +20588,7 @@ __export(src_exports2, {
20400
20588
  anchorSolutionToDiff: () => anchorSolutionToDiff,
20401
20589
  applyAbstractionFence: () => applyAbstractionFence,
20402
20590
  applyPulledPrinciples: () => applyPulledPrinciples,
20591
+ backfillLegacyAnchors: () => backfillLegacyAnchors,
20403
20592
  backfillProblemContext: () => backfillProblemContext,
20404
20593
  backfillProblemPackageLinks: () => backfillProblemPackageLinks,
20405
20594
  buildLanguageIndex: () => buildLanguageIndex,
@@ -20434,12 +20623,14 @@ __export(src_exports2, {
20434
20623
  linkProblemToLanguages: () => linkProblemToLanguages,
20435
20624
  linkProblemToPackages: () => linkProblemToPackages,
20436
20625
  listNeedsRevisit: () => listNeedsRevisit,
20626
+ markRevisit: () => markRevisit,
20437
20627
  matchLanguagesInText: () => matchLanguagesInText,
20438
20628
  matchPackagesInText: () => matchPackagesInText,
20439
20629
  mergeCloudCounts: () => mergeCloudCounts,
20440
20630
  mergeDuplicateProblems: () => mergeDuplicateProblems,
20441
20631
  mintPatternNode: () => mintPatternNode,
20442
20632
  openGraphStore: () => openGraphStore,
20633
+ osNodeId: () => osNodeId,
20443
20634
  parseAbstractionFences: () => parseAbstractionFences,
20444
20635
  parseSemver: () => parseSemver,
20445
20636
  parseTriageFences: () => parseTriageFences,
@@ -20448,6 +20639,7 @@ __export(src_exports2, {
20448
20639
  priorsForFile: () => priorsForFile,
20449
20640
  propagateFactChange: () => propagateFactChange,
20450
20641
  propagateVersionChange: () => propagateVersionChange,
20642
+ rankToolsForHandles: () => rankToolsForHandles,
20451
20643
  recordAnchorHint: () => recordAnchorHint,
20452
20644
  recordClaim: () => recordClaim,
20453
20645
  recordMisreadPrior: () => recordMisreadPrior,
@@ -20457,13 +20649,17 @@ __export(src_exports2, {
20457
20649
  resolveDesignProblemById: () => resolveDesignProblemById,
20458
20650
  resolveDesignProblemByStatement: () => resolveDesignProblemByStatement,
20459
20651
  resolveDesignProblems: () => resolveDesignProblems,
20652
+ resolveOsNode: () => resolveOsNode,
20460
20653
  retractDesignProblemById: () => retractDesignProblemById,
20461
20654
  retractDesignProblemByStatement: () => retractDesignProblemByStatement,
20462
20655
  revisitContradictedPrinciples: () => revisitContradictedPrinciples,
20463
20656
  revisitStaleRoutes: () => revisitStaleRoutes,
20464
20657
  solutionForProblem: () => solutionForProblem,
20465
20658
  splittingAxis: () => splittingAxis,
20659
+ stampObservedOs: () => stampObservedOs,
20466
20660
  staticConductance: () => staticConductance,
20661
+ toolNodeId: () => toolNodeId,
20662
+ toolPriorsFor: () => toolPriorsFor,
20467
20663
  triageOf: () => triageOf,
20468
20664
  walk: () => walk
20469
20665
  });
@@ -20479,12 +20675,14 @@ var init_src4 = __esm({
20479
20675
  init_crystallize();
20480
20676
  init_aggregate();
20481
20677
  init_design_problem();
20678
+ init_anchor_backfill();
20482
20679
  init_percolate();
20483
20680
  init_abstraction();
20484
20681
  init_community2();
20485
20682
  init_triage2();
20486
20683
  init_problem_dedup();
20487
20684
  init_problem_package_link();
20685
+ init_tools();
20488
20686
  init_principle_sync();
20489
20687
  }
20490
20688
  });
@@ -20553,7 +20751,7 @@ function buildSnapshot(opts) {
20553
20751
  };
20554
20752
  const langNodes = opts.store.findNodesByLabel("Language");
20555
20753
  const pkgNodes = opts.store.findNodesByLabel("Package");
20556
- 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);
20557
20755
  const profileContext = {
20558
20756
  languages: opts.profile.languages.map((name2) => ({ name: name2, node: matchNode(langNodes, name2) })),
20559
20757
  packages: opts.profile.stack.map((name2) => ({ name: name2, node: matchNode(pkgNodes, pkgBase(name2)) })),
@@ -45110,8 +45308,8 @@ var init_tldr_tools_generated = __esm({
45110
45308
  });
45111
45309
 
45112
45310
  // src/tool-index.ts
45113
- function toolNodeId(name2) {
45114
- return `tool:${name2}`;
45311
+ function currentOsName() {
45312
+ return osNameForPlatform(process.platform);
45115
45313
  }
45116
45314
  function extractExecutables(command) {
45117
45315
  const out2 = [];
@@ -45136,8 +45334,10 @@ function extractExecutables(command) {
45136
45334
  }
45137
45335
  function observeCommandTools(store, command, ts) {
45138
45336
  const result = { minted: [], reinforced: [] };
45337
+ const osName = currentOsName();
45139
45338
  for (const name2 of extractExecutables(command)) {
45140
45339
  if (!PUBLIC_TOOLS.has(name2)) continue;
45340
+ if (PLUMBING.has(name2)) continue;
45141
45341
  const id = toolNodeId(name2);
45142
45342
  const existing = store.getNode(id);
45143
45343
  if (existing) {
@@ -45170,17 +45370,60 @@ function observeCommandTools(store, command, ts) {
45170
45370
  attrs: { name: name2, canonicalId: toolCanonicalId(name2), public: true }
45171
45371
  });
45172
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
+ }
45173
45390
  }
45174
45391
  }
45175
45392
  return result;
45176
45393
  }
45177
- var PUBLIC_TOOLS, PASSTHROUGH, SEGMENT_SPLIT;
45394
+ var PUBLIC_TOOLS, PLUMBING, PASSTHROUGH, SEGMENT_SPLIT;
45178
45395
  var init_tool_index = __esm({
45179
45396
  "src/tool-index.ts"() {
45180
45397
  "use strict";
45181
45398
  init_src();
45399
+ init_src();
45400
+ init_src4();
45182
45401
  init_tldr_tools_generated();
45183
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
+ ]);
45184
45427
  PASSTHROUGH = /* @__PURE__ */ new Set(["sudo", "npx", "pnpx", "bunx", "uvx", "time", "nohup", "xargs", "watch"]);
45185
45428
  SEGMENT_SPLIT = /\|\|?|&&|;|\r?\n/;
45186
45429
  }
@@ -45282,7 +45525,8 @@ __export(webui_exports, {
45282
45525
  decideContextInject: () => decideContextInject,
45283
45526
  fileUriToFsPath: () => fileUriToFsPath,
45284
45527
  findFileByPath: () => findFileByPath,
45285
- recallForFile: () => recallForFile
45528
+ recallForFile: () => recallForFile,
45529
+ recallForTool: () => recallForTool
45286
45530
  });
45287
45531
  import { join as join12 } from "node:path";
45288
45532
  function fileUriToFsPath(raw2) {
@@ -45335,6 +45579,35 @@ function recallForFile(store, relPath) {
45335
45579
  ${lines.join("\n")}
45336
45580
  ` + buildFileRecallInstruction();
45337
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
+ }
45338
45611
  function decideContextInject(args2) {
45339
45612
  const { event, source, sessionId, block, lastInjectedHash } = args2;
45340
45613
  if (!block) return null;
@@ -45506,6 +45779,15 @@ function buildWebUi(deps) {
45506
45779
  }
45507
45780
  return c.json({ ok: true, materialized });
45508
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
+ }
45509
45791
  }
45510
45792
  const filePath = extractWorkingFile(tool, input);
45511
45793
  let rel = null;
@@ -45597,6 +45879,11 @@ function buildWebUi(deps) {
45597
45879
  }
45598
45880
  return c.body(null, 204);
45599
45881
  }
45882
+ if (event === "PreToolUse" && recallCtx) {
45883
+ return c.json({
45884
+ hookSpecificOutput: { hookEventName: "PreToolUse", additionalContext: recallCtx }
45885
+ });
45886
+ }
45600
45887
  return c.json({ ok: true, event, tool, recognizedFile: filePath ?? null });
45601
45888
  });
45602
45889
  app.post("/api/turn", async (c) => {
@@ -45843,7 +46130,7 @@ function proposalToIngest(p, profile, daemonVersion) {
45843
46130
  payloadDigest: p.id
45844
46131
  };
45845
46132
  }
45846
- var META_LABELS;
46133
+ var wsPackagesCache, WS_PACKAGES_TTL_MS, META_LABELS;
45847
46134
  var init_webui = __esm({
45848
46135
  "src/webui.ts"() {
45849
46136
  "use strict";
@@ -45855,6 +46142,8 @@ var init_webui = __esm({
45855
46142
  init_vfile();
45856
46143
  init_tool_index();
45857
46144
  init_outbox();
46145
+ wsPackagesCache = /* @__PURE__ */ new WeakMap();
46146
+ WS_PACKAGES_TTL_MS = 6e4;
45858
46147
  META_LABELS = /* @__PURE__ */ new Set([
45859
46148
  "Pattern",
45860
46149
  "Technique",
@@ -48902,6 +49191,8 @@ function subagentTranscripts(mainTranscriptPath, sessionId) {
48902
49191
  init_src();
48903
49192
  init_src2();
48904
49193
  init_agent_signals();
49194
+ init_tool_index();
49195
+ init_src4();
48905
49196
  import { readFileSync as readFileSync9, writeFileSync as writeFileSync9 } from "node:fs";
48906
49197
  var NEG = /n['']t|\b(?:not|never|no|none|neither|nor|unrelated|irrelevant|would|might|could|if)\b/i;
48907
49198
  var CITE_GROUP_RE = /\(((?:[^()\n]|\([^()\n]*\)){1,200})\)/g;
@@ -49229,6 +49520,7 @@ function mintPriorEdge(store, source, target, sentence, touched, ts) {
49229
49520
  navFailures: 0,
49230
49521
  attrs: { provisional: true, priorTag: true, primingProvenance: true, corroborated }
49231
49522
  });
49523
+ if (type === "CONCERNS") stampObservedOs(store, source.id, currentOsName(), ts);
49232
49524
  return true;
49233
49525
  }
49234
49526
  function harvestInlineTags(store, text, opts) {
@@ -50940,7 +51232,7 @@ function startLoopLagMonitor(thresholdMs = 1e3) {
50940
51232
  }
50941
51233
 
50942
51234
  // src/engine.ts
50943
- var DAEMON_VERSION = true ? "2.0.0-dev.87" : "2.0.0-alpha.0";
51235
+ var DAEMON_VERSION = true ? "2.0.0-dev.89" : "2.0.0-alpha.0";
50944
51236
  var IGNORED_PATH = /[\\/](?:\.git|node_modules|\.errata|\.claude|\.codex|\.cursor|\.turbo|\.next|dist|coverage|test-results|playwright-report|__pycache__)(?:[\\/]|$)/;
50945
51237
  var IGNORED_NOISE = /castalia\.db|eventlog\.sqlite|turn-cursors/;
50946
51238
  var GIT_OP_MUTE_MS = 4e3;
@@ -51337,6 +51629,10 @@ function createWorkspaceEngine(opts) {
51337
51629
  refreshContextNow();
51338
51630
  console.log(`[errata] skills: ${r.skillsWritten} local, ${r.skillsPruned} pruned`);
51339
51631
  }
51632
+ if (r.anchorsDemoted > 0 || r.resolutionsSuspect > 0) {
51633
+ logAnchorBackfill(r.anchorsDemoted, r.resolutionsSuspect);
51634
+ refreshContextNow();
51635
+ }
51340
51636
  return { report: r.report, localSkills: r.localSkills };
51341
51637
  } catch (err2) {
51342
51638
  console.warn(
@@ -51347,7 +51643,21 @@ function createWorkspaceEngine(opts) {
51347
51643
  }
51348
51644
  return runNightlyInline();
51349
51645
  };
51646
+ const logAnchorBackfill = (demoted, suspect) => {
51647
+ console.log(
51648
+ `[errata] anchor backfill: ${demoted} pre-provenance anchor(s) demoted to hints` + (suspect > 0 ? `; ${suspect} auto-close(s) rode a guessed anchor \u2192 Solution demoted + flagged for revisit` : "")
51649
+ );
51650
+ };
51350
51651
  const runNightlyInline = () => {
51652
+ try {
51653
+ const a = backfillLegacyAnchors(store, Date.now());
51654
+ if (a.demotedEdges > 0 || a.suspects.length > 0) {
51655
+ logAnchorBackfill(a.demotedEdges, a.suspects.length);
51656
+ refreshContextNow();
51657
+ }
51658
+ } catch (err2) {
51659
+ console.warn("[errata] anchor backfill failed:", err2);
51660
+ }
51351
51661
  const report = runNightlyPipeline(store);
51352
51662
  try {
51353
51663
  const m = mergeDuplicateProblems(store, { ts: Date.now() });
@@ -55977,7 +56287,7 @@ async function installClaudeHooks(port) {
55977
56287
  }
55978
56288
  const matcher = "Read|Edit|Write|Grep|Glob|NotebookEdit|Bash";
55979
56289
  const postMatcher = `${matcher}|ToolSearch|mcp__errata__.*`;
55980
- const preCmd = `${hookCurlCommand(port)} ${ERRATA_TAG}`;
56290
+ const preCmd = `${hookRelayCommand(port, "/api/hook")} ${ERRATA_TAG}`;
55981
56291
  const postCmd = `${hookRelayCommand(port, "/api/hook")} ${ERRATA_TAG}`;
55982
56292
  settings.hooks ??= {};
55983
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.87",
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
@@ -24787,6 +24787,13 @@ function addDependency(store2, opts) {
24787
24787
  store2.mergeEdge(edge);
24788
24788
  return edge;
24789
24789
  }
24790
+ function markRevisit(store2, node, reason, ts) {
24791
+ const fresh = store2.getNode(node.id) ?? node;
24792
+ store2.updateNode(node.id, {
24793
+ attrs: { ...fresh.attrs, revisit: true, revisitReason: reason, revisitSinceTs: ts },
24794
+ lastUpdatedAt: ts
24795
+ });
24796
+ }
24790
24797
  function listNeedsRevisit(store2, asOf) {
24791
24798
  return store2.nodesAsOf(asOf).filter((n) => n.attrs["revisit"] === true).map((n) => ({
24792
24799
  id: n.id,
@@ -25190,6 +25197,15 @@ function priorsForFile(store2, relPath) {
25190
25197
  openProblems.sort((a, b) => (b.lastUpdatedAt ?? 0) - (a.lastUpdatedAt ?? 0));
25191
25198
  return { file: file2, openProblems, related: [...related.values()], solutionsByProblem };
25192
25199
  }
25200
+ function recordAnchorHint(store2, problemId, relPath, provenance, ts) {
25201
+ const p = store2.getNode(problemId);
25202
+ if (!p || p.label !== "Problem") return false;
25203
+ if (p.attrs["anchorHint"]) return false;
25204
+ store2.updateNode(problemId, {
25205
+ attrs: { ...p.attrs, anchorHint: { path: relPath, provenance, ts } }
25206
+ });
25207
+ return true;
25208
+ }
25193
25209
  function resolveDesignProblems(store2, t) {
25194
25210
  let resolved = 0;
25195
25211
  for (const p of store2.findNodesByLabel("Problem")) {
@@ -25233,6 +25249,69 @@ function resolveDesignProblems(store2, t) {
25233
25249
  return resolved;
25234
25250
  }
25235
25251
 
25252
+ // ../../packages/local-graph/src/anchor-backfill.ts
25253
+ var AUTO_MINT_PREFIX = "addressed by an edit to ";
25254
+ function isLegacyAnchor(attrs) {
25255
+ return attrs?.["captureTime"] === true && attrs["anchorProvenance"] === void 0;
25256
+ }
25257
+ function backfillLegacyAnchors(store2, ts) {
25258
+ const report = {
25259
+ demotedEdges: 0,
25260
+ demotedProblems: 0,
25261
+ labeledEdges: 0,
25262
+ suspects: []
25263
+ };
25264
+ for (const p of store2.findNodesByLabel("Problem")) {
25265
+ const legacy = store2.outEdges(p.id, ["ANCHORED_AT"]).filter((e) => isLegacyAnchor(e.attrs));
25266
+ if (legacy.length === 0) continue;
25267
+ const resolved = p.attrs["resolvedAt"] !== void 0;
25268
+ try {
25269
+ if (!resolved) {
25270
+ for (const e of legacy) {
25271
+ const file2 = store2.getNode(e.to);
25272
+ const path = String(file2?.attrs["relPath"] ?? file2?.description ?? "");
25273
+ if (path) recordAnchorHint(store2, p.id, path, "legacy", ts);
25274
+ store2.deleteEdge(e.id);
25275
+ report.demotedEdges++;
25276
+ }
25277
+ report.demotedProblems++;
25278
+ continue;
25279
+ }
25280
+ for (const e of legacy) {
25281
+ store2.mergeEdge({ ...e, attrs: { ...e.attrs, anchorProvenance: "legacy" }, lastSeenAt: ts });
25282
+ report.labeledEdges++;
25283
+ }
25284
+ for (const se of store2.outEdges(p.id, ["SOLVED_BY"])) {
25285
+ const sol = store2.getNode(se.to);
25286
+ if (!sol || !sol.description.startsWith(AUTO_MINT_PREFIX)) continue;
25287
+ const guessedAnchor = sol.description.slice(AUTO_MINT_PREFIX.length);
25288
+ store2.updateNode(sol.id, {
25289
+ attrs: { ...sol.attrs, provisional: true, resolutionSuspect: true },
25290
+ lastUpdatedAt: ts
25291
+ });
25292
+ markRevisit(
25293
+ store2,
25294
+ sol,
25295
+ `auto-closed off a pre-provenance anchor (guessed ${guessedAnchor}) \u2014 confirm the problem is really fixed, or reopen it`,
25296
+ ts
25297
+ );
25298
+ store2.updateNode(p.id, {
25299
+ attrs: { ...p.attrs, resolutionSuspect: true },
25300
+ lastUpdatedAt: ts
25301
+ });
25302
+ report.suspects.push({
25303
+ problemId: p.id,
25304
+ problem: p.description,
25305
+ solutionId: sol.id,
25306
+ guessedAnchor
25307
+ });
25308
+ }
25309
+ } catch {
25310
+ }
25311
+ }
25312
+ return report;
25313
+ }
25314
+
25236
25315
  // ../../packages/local-graph/src/percolate.ts
25237
25316
  init_src2();
25238
25317
 
@@ -25669,6 +25748,18 @@ function foldDuplicateProblem(store2, dup, survivor, ts) {
25669
25748
  store2.closeNode(dup.id, ts);
25670
25749
  }
25671
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
+
25672
25763
  // ../../packages/local-graph/src/principle-sync.ts
25673
25764
  init_src2();
25674
25765
 
@@ -25976,7 +26067,7 @@ function buildSnapshot(opts) {
25976
26067
  };
25977
26068
  const langNodes = opts.store.findNodesByLabel("Language");
25978
26069
  const pkgNodes = opts.store.findNodesByLabel("Package");
25979
- 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);
25980
26071
  const profileContext = {
25981
26072
  languages: opts.profile.languages.map((name2) => ({ name: name2, node: matchNode(langNodes, name2) })),
25982
26073
  packages: opts.profile.stack.map((name2) => ({ name: name2, node: matchNode(pkgNodes, pkgBase(name2)) })),
@@ -26236,6 +26327,14 @@ async function runReindex(p) {
26236
26327
  return { ...r, identityEvaluations };
26237
26328
  }
26238
26329
  function runNightly() {
26330
+ let anchorsDemoted = 0;
26331
+ let resolutionsSuspect = 0;
26332
+ try {
26333
+ const a = backfillLegacyAnchors(store, Date.now());
26334
+ anchorsDemoted = a.demotedEdges;
26335
+ resolutionsSuspect = a.suspects.length;
26336
+ } catch {
26337
+ }
26239
26338
  const report = runNightlyPipeline(store);
26240
26339
  let merged = 0;
26241
26340
  let clusters = 0;
@@ -26253,6 +26352,6 @@ function runNightly() {
26253
26352
  backfillProblemContext(store, Date.now());
26254
26353
  } catch {
26255
26354
  }
26256
- return { report, merged, clusters, localSkills: 0, skillsWritten: 0, skillsPruned: 0 };
26355
+ return { report, merged, clusters, localSkills: 0, skillsWritten: 0, skillsPruned: 0, anchorsDemoted, resolutionsSuspect };
26257
26356
  }
26258
26357
  port.postMessage({ ready: true });