@inerrata-corporation/errata 2.0.0-dev.90 → 2.0.0-dev.92

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/errata.mjs CHANGED
@@ -17918,11 +17918,90 @@ function linkProblemToLanguages(store, problemId, text, ts, index) {
17918
17918
  }
17919
17919
  return linked;
17920
17920
  }
17921
- function deriveContextFromStatement(store, problemId, text, ts, pkgIndex) {
17922
- return {
17923
- packages: linkProblemToPackages(store, problemId, text, ts, pkgIndex).linked,
17924
- languages: linkProblemToLanguages(store, problemId, text, ts)
17921
+ function isShapedSymbol(name2) {
17922
+ if (name2.length < SYMBOL_MIN_LEN) return false;
17923
+ return name2 !== name2.toLowerCase() || name2.includes("_") || name2.includes(".");
17924
+ }
17925
+ function buildSymbolIndex(store) {
17926
+ const idx = /* @__PURE__ */ new Map();
17927
+ const ambiguous = /* @__PURE__ */ new Set();
17928
+ for (const label of SYMBOL_LABELS) {
17929
+ for (const n of store.findNodesByLabel(label)) {
17930
+ const name2 = n.description?.trim();
17931
+ if (!name2 || ambiguous.has(name2) || !isShapedSymbol(name2)) continue;
17932
+ if (idx.has(name2)) {
17933
+ idx.delete(name2);
17934
+ ambiguous.add(name2);
17935
+ } else {
17936
+ idx.set(name2, n);
17937
+ }
17938
+ }
17939
+ }
17940
+ return idx;
17941
+ }
17942
+ function matchSymbolsInText(text, index) {
17943
+ const out2 = [];
17944
+ for (const [name2, node2] of index) {
17945
+ if (!text.includes(name2)) continue;
17946
+ const bounded = new RegExp(`(?<![\\w$])${escapeRe3(name2)}(?![\\w$])`);
17947
+ if (bounded.test(text)) out2.push(node2);
17948
+ }
17949
+ return out2;
17950
+ }
17951
+ function linkProblemToSymbols(store, problemId, text, ts, index) {
17952
+ const p = store.getNode(problemId);
17953
+ if (!p || p.label !== "Problem") return [];
17954
+ const idx = index ?? buildSymbolIndex(store);
17955
+ if (idx.size === 0) return [];
17956
+ let fileByPath = null;
17957
+ const fileFor2 = (relPath) => {
17958
+ if (!fileByPath) {
17959
+ fileByPath = /* @__PURE__ */ new Map();
17960
+ for (const f of store.findNodesByLabel("File")) {
17961
+ const rp = String(f.attrs["relPath"] ?? f.description ?? "");
17962
+ if (rp) fileByPath.set(rp, f);
17963
+ }
17964
+ }
17965
+ return fileByPath.get(relPath) ?? null;
17925
17966
  };
17967
+ const already = new Set(store.outEdges(problemId, ["ANCHORED_AT"]).map((e) => e.to));
17968
+ const linked = [];
17969
+ for (const sym of matchSymbolsInText(text, idx)) {
17970
+ const relPath = String(sym.attrs["relPath"] ?? "");
17971
+ if (!relPath) continue;
17972
+ const file2 = fileFor2(relPath);
17973
+ if (!file2 || already.has(file2.id)) continue;
17974
+ store.mergeEdge({
17975
+ id: `edge_${digest({ from: problemId, type: "ANCHORED_AT", to: file2.id })}`.slice(0, 24),
17976
+ from: problemId,
17977
+ to: file2.id,
17978
+ type: "ANCHORED_AT",
17979
+ confidence: 0.3,
17980
+ // soft — a lexical mention, below a witnessed anchor's 0.4
17981
+ extractionSource: "daemon-extracted",
17982
+ createdAt: ts,
17983
+ lastSeenAt: ts,
17984
+ navSuccesses: 0,
17985
+ navFailures: 0,
17986
+ // `mention` gates it out of resolveDesignProblems (fix-detection); the
17987
+ // symbol name is kept for provenance + eventual symbol-level anchoring.
17988
+ attrs: { provisional: true, mention: true, mentionSymbol: sym.description }
17989
+ });
17990
+ already.add(file2.id);
17991
+ linked.push(file2.id);
17992
+ }
17993
+ return linked;
17994
+ }
17995
+ function deriveContextFromStatement(store, problemId, text, ts, pkgIndex) {
17996
+ const packages = linkProblemToPackages(store, problemId, text, ts, pkgIndex).linked;
17997
+ const languages = linkProblemToLanguages(store, problemId, text, ts);
17998
+ const anchoredFiles = linkProblemToSymbols(store, problemId, text, ts);
17999
+ if (anchoredFiles.length > 0) {
18000
+ const ctx = deriveContextFromAnchors(store, problemId, ts, pkgIndex);
18001
+ for (const l of ctx.languages) if (!languages.includes(l)) languages.push(l);
18002
+ for (const pk of ctx.packages) if (!packages.includes(pk)) packages.push(pk);
18003
+ }
18004
+ return { packages, languages };
17926
18005
  }
17927
18006
  function problemText(store, p) {
17928
18007
  const parts2 = [p.description];
@@ -18045,7 +18124,7 @@ function backfillProblemContext(store, ts) {
18045
18124
  }
18046
18125
  return report;
18047
18126
  }
18048
- var NAME_SEPARATOR, MIN_NAME_LEN, LANGUAGE_MIN_LEN;
18127
+ var NAME_SEPARATOR, MIN_NAME_LEN, LANGUAGE_MIN_LEN, SYMBOL_MIN_LEN, SYMBOL_LABELS;
18049
18128
  var init_problem_package_link = __esm({
18050
18129
  "../../packages/local-graph/src/problem-package-link.ts"() {
18051
18130
  "use strict";
@@ -18054,6 +18133,8 @@ var init_problem_package_link = __esm({
18054
18133
  NAME_SEPARATOR = /[@/\-._]/;
18055
18134
  MIN_NAME_LEN = 3;
18056
18135
  LANGUAGE_MIN_LEN = 4;
18136
+ SYMBOL_MIN_LEN = 5;
18137
+ SYMBOL_LABELS = ["Function", "Method", "Class", "Const"];
18057
18138
  }
18058
18139
  });
18059
18140
 
@@ -18437,6 +18518,7 @@ function resolveDesignProblems(store, t) {
18437
18518
  let symRelPath;
18438
18519
  let edited = false;
18439
18520
  for (const e of store.outEdges(p.id, ["ANCHORED_AT"])) {
18521
+ if (e.attrs?.["mention"] === true) continue;
18440
18522
  const sym = store.getNode(e.to);
18441
18523
  if (sym && sym.lastUpdatedAt > p.createdAt) {
18442
18524
  edited = true;
@@ -20630,6 +20712,7 @@ __export(src_exports2, {
20630
20712
  buildLanguageIndex: () => buildLanguageIndex,
20631
20713
  buildPackageIndex: () => buildPackageIndex,
20632
20714
  buildPrincipleSync: () => buildPrincipleSync,
20715
+ buildSymbolIndex: () => buildSymbolIndex,
20633
20716
  causalChain: () => causalChain,
20634
20717
  claimId: () => claimId,
20635
20718
  clearRevisit: () => clearRevisit,
@@ -20658,10 +20741,12 @@ __export(src_exports2, {
20658
20741
  isPlaceholderStatement: () => isPlaceholderStatement,
20659
20742
  linkProblemToLanguages: () => linkProblemToLanguages,
20660
20743
  linkProblemToPackages: () => linkProblemToPackages,
20744
+ linkProblemToSymbols: () => linkProblemToSymbols,
20661
20745
  listNeedsRevisit: () => listNeedsRevisit,
20662
20746
  markRevisit: () => markRevisit,
20663
20747
  matchLanguagesInText: () => matchLanguagesInText,
20664
20748
  matchPackagesInText: () => matchPackagesInText,
20749
+ matchSymbolsInText: () => matchSymbolsInText,
20665
20750
  mergeCloudCounts: () => mergeCloudCounts,
20666
20751
  mergeDuplicateProblems: () => mergeDuplicateProblems,
20667
20752
  mintPatternNode: () => mintPatternNode,
@@ -25287,7 +25372,7 @@ function isDistinctiveIdentifier(name2) {
25287
25372
  function buildSymbolLexicon(store, summariesByBodyHash2) {
25288
25373
  const lex = /* @__PURE__ */ new Map();
25289
25374
  const candidates = [];
25290
- for (const [label, kind] of SYMBOL_LABELS) {
25375
+ for (const [label, kind] of SYMBOL_LABELS2) {
25291
25376
  for (const n of store.findNodesByLabel(label)) {
25292
25377
  const bodyHash = typeof n.attrs["bodyHash"] === "string" ? n.attrs["bodyHash"] : void 0;
25293
25378
  const summary = bodyHash ? summariesByBodyHash2?.get(bodyHash) : void 0;
@@ -25326,13 +25411,13 @@ function generalizeSymbols(text, lexicon, level = 1) {
25326
25411
  }
25327
25412
  return generalize(out2, { level }).text;
25328
25413
  }
25329
- var SYMBOL_LABELS, KIND_PHRASE, RE_RESERVED2, escapeRe4, TOKEN_RE3;
25414
+ var SYMBOL_LABELS2, KIND_PHRASE, RE_RESERVED2, escapeRe4, TOKEN_RE3;
25330
25415
  var init_generalize_graph = __esm({
25331
25416
  "src/generalize-graph.ts"() {
25332
25417
  "use strict";
25333
25418
  init_src8();
25334
25419
  init_src();
25335
- SYMBOL_LABELS = [
25420
+ SYMBOL_LABELS2 = [
25336
25421
  ["Function", "function"],
25337
25422
  ["Method", "method"],
25338
25423
  ["Class", "class"],
@@ -45370,12 +45455,13 @@ function extractExecutables(command) {
45370
45455
  return out2;
45371
45456
  }
45372
45457
  function observeCommandTools(store, command, ts) {
45373
- const result = { minted: [], reinforced: [] };
45458
+ const result = { minted: [], reinforced: [], nodeIds: [] };
45374
45459
  const osName = currentOsName();
45375
45460
  for (const name2 of extractExecutables(command)) {
45376
45461
  if (!PUBLIC_TOOLS.has(name2)) continue;
45377
45462
  if (PLUMBING.has(name2)) continue;
45378
45463
  const id = toolNodeId(name2);
45464
+ result.nodeIds.push(id);
45379
45465
  const existing = store.getNode(id);
45380
45466
  if (existing) {
45381
45467
  store.updateNode(id, {
@@ -45407,23 +45493,23 @@ function observeCommandTools(store, command, ts) {
45407
45493
  attrs: { name: name2, canonicalId: toolCanonicalId(name2), public: true }
45408
45494
  });
45409
45495
  result.minted.push(name2);
45410
- if (osName) {
45411
- const os2 = resolveOsNode(store, osName, ts);
45412
- store.mergeEdge({
45413
- id: `edge_${digest({ from: id, type: "RUNS_ON", to: os2.id })}`.slice(0, 24),
45414
- from: id,
45415
- to: os2.id,
45416
- type: "RUNS_ON",
45417
- confidence: 1,
45418
- // observed
45419
- extractionSource: "daemon-extracted",
45420
- createdAt: ts,
45421
- lastSeenAt: ts,
45422
- navSuccesses: 0,
45423
- navFailures: 0,
45424
- attrs: { observed: true }
45425
- });
45426
- }
45496
+ }
45497
+ if (osName) {
45498
+ const os2 = resolveOsNode(store, osName, ts);
45499
+ store.mergeEdge({
45500
+ id: `edge_${digest({ from: id, type: "RUNS_ON", to: os2.id })}`.slice(0, 24),
45501
+ from: id,
45502
+ to: os2.id,
45503
+ type: "RUNS_ON",
45504
+ confidence: 1,
45505
+ // observed
45506
+ extractionSource: "daemon-extracted",
45507
+ createdAt: ts,
45508
+ lastSeenAt: ts,
45509
+ navSuccesses: 0,
45510
+ navFailures: 0,
45511
+ attrs: { observed: true }
45512
+ });
45427
45513
  }
45428
45514
  }
45429
45515
  return result;
@@ -45862,7 +45948,8 @@ function buildWebUi(deps) {
45862
45948
  ts: Date.now()
45863
45949
  });
45864
45950
  try {
45865
- observeCommandTools(deps.store, input["command"], Date.now());
45951
+ const observed = observeCommandTools(deps.store, input["command"], Date.now());
45952
+ deps.onToolsObserved?.(String(body2["session_id"] ?? ""), observed.nodeIds);
45866
45953
  } catch {
45867
45954
  }
45868
45955
  if (failed) recallCtx = recallForError(deps.store, stderr || combined);
@@ -49244,11 +49331,8 @@ var SUPERSEDES_PREFIX = /^\s*supersedes:(?:#([a-z][\w-]{0,63}))?\s*/i;
49244
49331
  var ALTERNATIVE_PREFIX = /^\s*alternative:(?:#([a-z][\w-]{0,63}))?\s*/i;
49245
49332
  var INSTANCE_PREFIX = /^\s*instance:\s*/i;
49246
49333
  var PATTERN_RE = /\(\s*pattern:\s*([^()\n]{3,}?)\s*\)/gi;
49247
- var PATTERN_TEXT_MAX = 120;
49248
49334
  var CAUSE_TEXT_MIN = 8;
49249
- var CAUSE_TEXT_MAX = 200;
49250
49335
  var FLAG_RE = /\[([!?])(?:#([a-z][\w-]{0,63})\s+)?\s*([^\]\n]{8,}?)\s*(?:@\s*([^\s\]]+?)(?::(\d+))?\s*)?\]/g;
49251
- var FLAG_MAX = 200;
49252
49336
  var CONSTRAINT_MIN = 8;
49253
49337
  function clauseBefore(sentence, idx) {
49254
49338
  const win = sentence.slice(Math.max(0, idx - 80), idx);
@@ -49269,7 +49353,7 @@ function parseInlineTags(text) {
49269
49353
  let seqNo = -1;
49270
49354
  for (const raw2 of deFenced.split(/(?<=[.!?])\s+|\n+/)) {
49271
49355
  seqNo++;
49272
- if (raw2.length > 600) continue;
49356
+ if (raw2.length > 2e4) continue;
49273
49357
  const seqStart = out2.length;
49274
49358
  const sentence = raw2.replace(
49275
49359
  /`[^`]*`/g,
@@ -49323,7 +49407,7 @@ function parseInlineTags(text) {
49323
49407
  } else {
49324
49408
  const raw3 = content.replace(/\s+/g, " ").trim();
49325
49409
  if (raw3.length >= CAUSE_TEXT_MIN) {
49326
- const causeText = raw3.length > CAUSE_TEXT_MAX ? `${raw3.slice(0, CAUSE_TEXT_MAX - 1).trimEnd()}\u2026` : raw3;
49410
+ const causeText = raw3;
49327
49411
  out2.push({ kind: "triage", causeText, sentence: sfield, ...verbThread ? { threadId: verbThread } : {} });
49328
49412
  }
49329
49413
  }
@@ -49365,7 +49449,7 @@ function parseInlineTags(text) {
49365
49449
  if (raw3.length >= 8) {
49366
49450
  const segs = raw3.split(CAUSE_ARROW).map((s) => s.trim()).filter((s) => s.length > 0);
49367
49451
  const symptomRaw = segs.length > 1 ? segs[0] : raw3;
49368
- const statement = symptomRaw.length > FLAG_MAX ? `${symptomRaw.slice(0, FLAG_MAX - 1).trimEnd()}\u2026` : symptomRaw;
49452
+ const statement = symptomRaw;
49369
49453
  const asFix = f[1] === "!" && /^(?:fixed|resolved)\s*[:,-]\s*/i.exec(statement);
49370
49454
  if (asFix) {
49371
49455
  const note = statement.slice(asFix[0].length).trim();
@@ -49397,7 +49481,7 @@ function parseInlineTags(text) {
49397
49481
  while ((a = ATTEMPT_RE.exec(sentence)) !== null) {
49398
49482
  const raw3 = a[3].replace(/\s+/g, " ").trim();
49399
49483
  if (raw3.length >= CONSTRAINT_MIN) {
49400
- const statement = raw3.length > FLAG_MAX ? `${raw3.slice(0, FLAG_MAX - 1).trimEnd()}\u2026` : raw3;
49484
+ const statement = raw3;
49401
49485
  const isFailure = a[1].toLowerCase() === "failed";
49402
49486
  let refuteHandles;
49403
49487
  if (isFailure) {
@@ -49431,7 +49515,7 @@ function parseInlineTags(text) {
49431
49515
  } else {
49432
49516
  const raw3 = body2.replace(/\s+/g, " ").trim();
49433
49517
  if (raw3.length >= 3) {
49434
- const patternText = raw3.length > PATTERN_TEXT_MAX ? `${raw3.slice(0, PATTERN_TEXT_MAX - 1).trimEnd()}\u2026` : raw3;
49518
+ const patternText = raw3;
49435
49519
  out2.push({ kind: "pattern", patternText, sentence: sfield });
49436
49520
  }
49437
49521
  }
@@ -49441,7 +49525,7 @@ function parseInlineTags(text) {
49441
49525
  while ((c = CONSTRAINT_RE.exec(sentence)) !== null) {
49442
49526
  const raw3 = c[1].replace(/\s+/g, " ").trim();
49443
49527
  if (raw3.length >= CONSTRAINT_MIN) {
49444
- const statement = raw3.length > FLAG_MAX ? `${raw3.slice(0, FLAG_MAX - 1).trimEnd()}\u2026` : raw3;
49528
+ const statement = raw3;
49445
49529
  out2.push({ kind: "constraint", statement, sentence: sfield });
49446
49530
  }
49447
49531
  }
@@ -49540,6 +49624,7 @@ function mintPriorEdge(store, source, target, sentence, touched, ts) {
49540
49624
  if (anchorIds.size === 0 && (target.label === "Language" || target.label === "Package")) {
49541
49625
  for (const e of store.inEdges(target.id, STACK_GROUNDING_EDGES)) anchorIds.add(e.from);
49542
49626
  }
49627
+ if (anchorIds.size === 0 && target.label === "Tool") anchorIds.add(target.id);
49543
49628
  const corroborated = tagEdgeCorroborated(anchorIds, touched, false);
49544
49629
  store.mergeEdge({
49545
49630
  id: `edge_${digest({ from: source.id, type, to: target.id, k: "priorTag" })}`.slice(0, 24),
@@ -49556,7 +49641,12 @@ function mintPriorEdge(store, source, target, sentence, touched, ts) {
49556
49641
  navFailures: 0,
49557
49642
  attrs: { provisional: true, priorTag: true, primingProvenance: true, corroborated }
49558
49643
  });
49559
- if (type === "CONCERNS") stampObservedOs(store, source.id, currentOsName(), ts);
49644
+ if (type === "CONCERNS") {
49645
+ try {
49646
+ stampObservedOs(store, source.id, currentOsName(), ts);
49647
+ } catch {
49648
+ }
49649
+ }
49560
49650
  return true;
49561
49651
  }
49562
49652
  function harvestInlineTags(store, text, opts) {
@@ -50871,6 +50961,34 @@ function createWorkingFileState() {
50871
50961
  };
50872
50962
  }
50873
50963
 
50964
+ // src/tool-run-state.ts
50965
+ var MAX_SESSIONS = 64;
50966
+ var MAX_TOOLS_PER_SESSION = 64;
50967
+ function createToolRunState() {
50968
+ const bySession = /* @__PURE__ */ new Map();
50969
+ return {
50970
+ record(sessionId, toolNodeIds) {
50971
+ if (!sessionId || toolNodeIds.length === 0) return;
50972
+ let set2 = bySession.get(sessionId);
50973
+ if (!set2) {
50974
+ if (bySession.size >= MAX_SESSIONS) {
50975
+ const oldest = bySession.keys().next().value;
50976
+ if (oldest !== void 0) bySession.delete(oldest);
50977
+ }
50978
+ set2 = /* @__PURE__ */ new Set();
50979
+ bySession.set(sessionId, set2);
50980
+ }
50981
+ for (const id of toolNodeIds) {
50982
+ if (set2.size >= MAX_TOOLS_PER_SESSION) break;
50983
+ set2.add(id);
50984
+ }
50985
+ },
50986
+ get(sessionId) {
50987
+ return bySession.get(sessionId) ?? /* @__PURE__ */ new Set();
50988
+ }
50989
+ };
50990
+ }
50991
+
50874
50992
  // src/engine.ts
50875
50993
  init_paths();
50876
50994
 
@@ -51268,7 +51386,7 @@ function startLoopLagMonitor(thresholdMs = 1e3) {
51268
51386
  }
51269
51387
 
51270
51388
  // src/engine.ts
51271
- var DAEMON_VERSION = true ? "2.0.0-dev.90" : "2.0.0-alpha.0";
51389
+ var DAEMON_VERSION = true ? "2.0.0-dev.92" : "2.0.0-alpha.0";
51272
51390
  var IGNORED_PATH = /[\\/](?:\.git|node_modules|\.errata|\.claude|\.codex|\.cursor|\.turbo|\.next|dist|coverage|test-results|playwright-report|__pycache__)(?:[\\/]|$)/;
51273
51391
  var IGNORED_NOISE = /castalia\.db|eventlog\.sqlite|turn-cursors/;
51274
51392
  var GIT_OP_MUTE_MS = 4e3;
@@ -51549,6 +51667,7 @@ function createWorkspaceEngine(opts) {
51549
51667
  });
51550
51668
  }
51551
51669
  const workingFiles = createWorkingFileState();
51670
+ const toolRuns = createToolRunState();
51552
51671
  let ctxRefreshTimer = null;
51553
51672
  let contextDirty = false;
51554
51673
  let remotePriors = [];
@@ -51918,12 +52037,14 @@ function createWorkspaceEngine(opts) {
51918
52037
  }
51919
52038
  try {
51920
52039
  const touchedFileId = turnFile ? resolveFileId(turnFile) : void 0;
52040
+ const touched = new Set(toolRuns.get(sessionId));
52041
+ if (touchedFileId) touched.add(touchedFileId);
51921
52042
  const plan = harvestInlineTags(store, turn.text, {
51922
52043
  sourceId: sessionLastProblem.get(sessionId),
51923
52044
  handleMap,
51924
52045
  ts: t,
51925
52046
  mintPriors: elicit,
51926
- ...touchedFileId ? { sessionTouchedIds: /* @__PURE__ */ new Set([touchedFileId]) } : {}
52047
+ ...touched.size > 0 ? { sessionTouchedIds: touched } : {}
51927
52048
  });
51928
52049
  priorEdges += plan.priorEdges;
51929
52050
  const wf = workingFiles.get(sessionId);
@@ -52325,6 +52446,7 @@ function createWorkspaceEngine(opts) {
52325
52446
  webHooks: {
52326
52447
  onWorkingFileChanged,
52327
52448
  onHook: () => telemetry.count("hooks_fired"),
52449
+ onToolsObserved: (sessionId, toolNodeIds) => toolRuns.record(sessionId, toolNodeIds),
52328
52450
  onHookEvent,
52329
52451
  onShellEvent,
52330
52452
  onToolError,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inerrata-corporation/errata",
3
- "version": "2.0.0-dev.90",
3
+ "version": "2.0.0-dev.92",
4
4
  "description": "errata - local-first observation engine for AI coding agents",
5
5
  "type": "module",
6
6
  "bin": {
package/pass-worker.mjs CHANGED
@@ -25215,6 +25215,7 @@ function resolveDesignProblems(store2, t) {
25215
25215
  let symRelPath;
25216
25216
  let edited = false;
25217
25217
  for (const e of store2.outEdges(p.id, ["ANCHORED_AT"])) {
25218
+ if (e.attrs?.["mention"] === true) continue;
25218
25219
  const sym = store2.getNode(e.to);
25219
25220
  if (sym && sym.lastUpdatedAt > p.createdAt) {
25220
25221
  edited = true;