@inerrata-corporation/errata 2.0.0-dev.84 → 2.0.0-dev.85

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.
Files changed (2) hide show
  1. package/errata.mjs +133 -21
  2. package/package.json +1 -1
package/errata.mjs CHANGED
@@ -17773,6 +17773,59 @@ function linkProblemToPackages(store, problemId, text, ts, index) {
17773
17773
  }
17774
17774
  return { linked };
17775
17775
  }
17776
+ function buildLanguageIndex(store) {
17777
+ const idx = /* @__PURE__ */ new Map();
17778
+ for (const n of store.findNodesByLabel("Language")) {
17779
+ const name2 = String(n.attrs["name"] ?? n.description ?? "").trim().toLowerCase();
17780
+ if (name2) idx.set(name2, n);
17781
+ }
17782
+ return idx;
17783
+ }
17784
+ function matchLanguagesInText(text, index) {
17785
+ const hay = text.toLowerCase();
17786
+ const out2 = [];
17787
+ for (const [key, node2] of index) {
17788
+ if (key.length < LANGUAGE_MIN_LEN) continue;
17789
+ if (!hay.includes(key)) continue;
17790
+ const bounded = new RegExp(`(?<![\\w@/.\\-])${escapeRe3(key)}(?![\\w])`);
17791
+ if (bounded.test(hay)) out2.push(node2);
17792
+ }
17793
+ return out2;
17794
+ }
17795
+ function linkProblemToLanguages(store, problemId, text, ts, index) {
17796
+ const p = store.getNode(problemId);
17797
+ if (!p || p.label !== "Problem") return [];
17798
+ const idx = index ?? buildLanguageIndex(store);
17799
+ if (idx.size === 0) return [];
17800
+ const already = new Set(store.outEdges(problemId, ["OCCURS_IN"]).map((e) => e.to));
17801
+ const linked = [];
17802
+ for (const node2 of matchLanguagesInText(text, idx)) {
17803
+ if (already.has(node2.id)) continue;
17804
+ store.mergeEdge({
17805
+ id: `edge_${digest({ from: problemId, type: "OCCURS_IN", to: node2.id })}`.slice(0, 24),
17806
+ from: problemId,
17807
+ to: node2.id,
17808
+ type: "OCCURS_IN",
17809
+ confidence: 0.3,
17810
+ // below the structural walk's 0.4 — a mention, not an anchor walk
17811
+ extractionSource: "daemon-extracted",
17812
+ createdAt: ts,
17813
+ lastSeenAt: ts,
17814
+ navSuccesses: 0,
17815
+ navFailures: 0,
17816
+ attrs: { provisional: true, mention: true }
17817
+ });
17818
+ already.add(node2.id);
17819
+ linked.push(node2.id);
17820
+ }
17821
+ return linked;
17822
+ }
17823
+ function deriveContextFromStatement(store, problemId, text, ts, pkgIndex) {
17824
+ return {
17825
+ packages: linkProblemToPackages(store, problemId, text, ts, pkgIndex).linked,
17826
+ languages: linkProblemToLanguages(store, problemId, text, ts)
17827
+ };
17828
+ }
17776
17829
  function problemText(store, p) {
17777
17830
  const parts2 = [p.description];
17778
17831
  for (const e of store.outEdges(p.id, ["CAUSED_BY"])) {
@@ -17894,7 +17947,7 @@ function backfillProblemContext(store, ts) {
17894
17947
  }
17895
17948
  return report;
17896
17949
  }
17897
- var NAME_SEPARATOR, MIN_NAME_LEN;
17950
+ var NAME_SEPARATOR, MIN_NAME_LEN, LANGUAGE_MIN_LEN;
17898
17951
  var init_problem_package_link = __esm({
17899
17952
  "../../packages/local-graph/src/problem-package-link.ts"() {
17900
17953
  "use strict";
@@ -17902,6 +17955,7 @@ var init_problem_package_link = __esm({
17902
17955
  init_justification();
17903
17956
  NAME_SEPARATOR = /[@/\-._]/;
17904
17957
  MIN_NAME_LEN = 3;
17958
+ LANGUAGE_MIN_LEN = 4;
17905
17959
  }
17906
17960
  });
17907
17961
 
@@ -18191,7 +18245,7 @@ function solutionForProblem(store, problemId) {
18191
18245
  const e = store.outEdges(problemId, ["SOLVED_BY"])[0];
18192
18246
  return e ? e.to : null;
18193
18247
  }
18194
- function anchorProblemToWorkingFile(store, problemId, relPath, workspaceId2, ts) {
18248
+ function anchorProblemToWorkingFile(store, problemId, relPath, workspaceId2, ts, provenance = "edited") {
18195
18249
  const p = store.getNode(problemId);
18196
18250
  if (!p || p.label !== "Problem") return false;
18197
18251
  if (!ANCHORABLE_CODE.test(relPath)) return false;
@@ -18204,14 +18258,23 @@ function anchorProblemToWorkingFile(store, problemId, relPath, workspaceId2, ts)
18204
18258
  from: problemId,
18205
18259
  to: file2.id,
18206
18260
  type: "ANCHORED_AT",
18207
- confidence: 0.3,
18208
- // soft: in-focus file is a heuristic, below F2's resolve-diff anchor (0.4)
18261
+ // witnessed = the agent's own declaration, F2-grade; edited = soft heuristic.
18262
+ confidence: provenance === "witnessed" ? 0.4 : 0.3,
18209
18263
  extractionSource: "agent-observed",
18210
18264
  createdAt: ts,
18211
18265
  lastSeenAt: ts,
18212
18266
  navSuccesses: 0,
18213
18267
  navFailures: 0,
18214
- attrs: { provisional: true, captureTime: true }
18268
+ attrs: { provisional: true, captureTime: true, anchorProvenance: provenance }
18269
+ });
18270
+ return true;
18271
+ }
18272
+ function recordAnchorHint(store, problemId, relPath, provenance, ts) {
18273
+ const p = store.getNode(problemId);
18274
+ if (!p || p.label !== "Problem") return false;
18275
+ if (p.attrs["anchorHint"]) return false;
18276
+ store.updateNode(problemId, {
18277
+ attrs: { ...p.attrs, anchorHint: { path: relPath, provenance, ts } }
18215
18278
  });
18216
18279
  return true;
18217
18280
  }
@@ -20300,6 +20363,7 @@ __export(src_exports2, {
20300
20363
  applyPulledPrinciples: () => applyPulledPrinciples,
20301
20364
  backfillProblemContext: () => backfillProblemContext,
20302
20365
  backfillProblemPackageLinks: () => backfillProblemPackageLinks,
20366
+ buildLanguageIndex: () => buildLanguageIndex,
20303
20367
  buildPackageIndex: () => buildPackageIndex,
20304
20368
  buildPrincipleSync: () => buildPrincipleSync,
20305
20369
  causalChain: () => causalChain,
@@ -20312,6 +20376,7 @@ __export(src_exports2, {
20312
20376
  creditAssignment: () => creditAssignment,
20313
20377
  crystallize: () => crystallize,
20314
20378
  deriveContextFromAnchors: () => deriveContextFromAnchors,
20379
+ deriveContextFromStatement: () => deriveContextFromStatement,
20315
20380
  designProblemId: () => designProblemId,
20316
20381
  detectLocalCommunities: () => detectLocalCommunities,
20317
20382
  edgeConductance: () => edgeConductance,
@@ -20327,8 +20392,10 @@ __export(src_exports2, {
20327
20392
  induceTriage: () => induceTriage,
20328
20393
  ingestDesignProblem: () => ingestDesignProblem,
20329
20394
  isPlaceholderStatement: () => isPlaceholderStatement,
20395
+ linkProblemToLanguages: () => linkProblemToLanguages,
20330
20396
  linkProblemToPackages: () => linkProblemToPackages,
20331
20397
  listNeedsRevisit: () => listNeedsRevisit,
20398
+ matchLanguagesInText: () => matchLanguagesInText,
20332
20399
  matchPackagesInText: () => matchPackagesInText,
20333
20400
  mergeCloudCounts: () => mergeCloudCounts,
20334
20401
  mergeDuplicateProblems: () => mergeDuplicateProblems,
@@ -20342,6 +20409,7 @@ __export(src_exports2, {
20342
20409
  priorsForFile: () => priorsForFile,
20343
20410
  propagateFactChange: () => propagateFactChange,
20344
20411
  propagateVersionChange: () => propagateVersionChange,
20412
+ recordAnchorHint: () => recordAnchorHint,
20345
20413
  recordClaim: () => recordClaim,
20346
20414
  recordMisreadPrior: () => recordMisreadPrior,
20347
20415
  recordTriageObservation: () => recordTriageObservation,
@@ -24568,7 +24636,7 @@ var init_agent_signals = __esm({
24568
24636
  };
24569
24637
  GLOSS = {
24570
24638
  prior: "a prior we showed you helped \u2014 or this work sits in a primed language/package",
24571
- problem: "you hit a real problem \u2014 incidental, or the one you're fixing",
24639
+ problem: "you hit a real problem \u2014 incidental, or the one you're fixing. About specific code? NAME the file in the tag: [!what's wrong @ src/file.ts:42] \u2014 we anchor to what you name, or to a file you edited this turn, never to one you merely read; a design/topic problem is fine with no @",
24572
24640
  fix: "your edit fixes a problem \u2014 cite the one we showed you, or just say how you fixed one you found yourself: (fix: what you changed)",
24573
24641
  constraint: "you made a design decision because requirements conflict or something's constrained \u2014 tag the tension, ESPECIALLY when your fix makes it 'only look' contradictory (a clean solution still hides a real trap the next agent needs)",
24574
24642
  triage: "you diagnosed a bug \u2014 SPLIT the symptom (what breaks \u2192 [!\u2026]) from the cause (the mechanism you'd change \u2192 (cause:\u2026)); if the line says WHY it breaks, it's a cause, not a problem",
@@ -41402,12 +41470,27 @@ function parseDesignResolutions(text) {
41402
41470
  return out2;
41403
41471
  }
41404
41472
  var FILE_TOOLS = /* @__PURE__ */ new Set(["Read", "Edit", "Write", "MultiEdit", "NotebookEdit"]);
41473
+ var WRITE_TOOLS = /* @__PURE__ */ new Set(["Edit", "Write", "MultiEdit", "NotebookEdit"]);
41474
+ function isUserTurnBoundary(obj) {
41475
+ if (obj.type !== "user") return false;
41476
+ const content = obj.message?.content;
41477
+ if (typeof content === "string") return content.trim().length > 0;
41478
+ if (!Array.isArray(content)) return false;
41479
+ const blocks = content;
41480
+ if (blocks.some((b) => b["type"] === "tool_result")) return false;
41481
+ return blocks.some((b) => b["type"] === "text");
41482
+ }
41405
41483
  function readAssistantTurns(transcriptPath, includeThinking = true, maxBytes = 2e6) {
41406
41484
  const raw2 = readTail(transcriptPath, maxBytes);
41407
41485
  if (!raw2) return [];
41408
41486
  const turns = [];
41409
41487
  const lines = raw2.split(/\r?\n/);
41410
41488
  let lastFile;
41489
+ let lastFileIsWrite = false;
41490
+ let lastFileTurnSeq = 0;
41491
+ let editedFile;
41492
+ let editedFileTurnSeq = 0;
41493
+ let turnSeq = 0;
41411
41494
  for (let i2 = 0; i2 < lines.length; i2++) {
41412
41495
  const line = lines[i2];
41413
41496
  if (!line) continue;
@@ -41417,6 +41500,10 @@ function readAssistantTurns(transcriptPath, includeThinking = true, maxBytes = 2
41417
41500
  } catch {
41418
41501
  continue;
41419
41502
  }
41503
+ if (isUserTurnBoundary(obj)) {
41504
+ turnSeq++;
41505
+ continue;
41506
+ }
41420
41507
  if (obj.type !== "assistant" || !Array.isArray(obj.message?.content)) continue;
41421
41508
  const parts2 = [];
41422
41509
  for (const b of obj.message.content) {
@@ -41426,13 +41513,24 @@ function readAssistantTurns(transcriptPath, includeThinking = true, maxBytes = 2
41426
41513
  else if (b["type"] === "tool_use" && typeof b["name"] === "string" && FILE_TOOLS.has(b["name"])) {
41427
41514
  const input = b["input"];
41428
41515
  const fp = input && typeof input === "object" ? input["file_path"] : void 0;
41429
- if (typeof fp === "string" && fp) lastFile = fp;
41516
+ if (typeof fp === "string" && fp) {
41517
+ lastFile = fp;
41518
+ lastFileIsWrite = WRITE_TOOLS.has(b["name"]);
41519
+ lastFileTurnSeq = turnSeq;
41520
+ if (lastFileIsWrite) {
41521
+ editedFile = fp;
41522
+ editedFileTurnSeq = turnSeq;
41523
+ }
41524
+ }
41430
41525
  }
41431
41526
  }
41527
+ const provenance = lastFile ? lastFileTurnSeq === turnSeq ? lastFileIsWrite ? "edited" : "read" : "carried" : void 0;
41432
41528
  turns.push({
41433
41529
  uuid: String(obj.uuid ?? i2),
41434
41530
  text: parts2.join("\n\n"),
41435
- ...lastFile ? { workingFile: lastFile } : {}
41531
+ ...lastFile ? { workingFile: lastFile } : {},
41532
+ ...provenance ? { workingFileProvenance: provenance } : {},
41533
+ ...editedFile && editedFileTurnSeq === turnSeq ? { editedFile } : {}
41436
41534
  });
41437
41535
  }
41438
41536
  return turns;
@@ -43533,7 +43631,7 @@ function startLoopLagMonitor(thresholdMs = 1e3) {
43533
43631
  }
43534
43632
 
43535
43633
  // src/engine.ts
43536
- var DAEMON_VERSION = true ? "2.0.0-dev.84" : "2.0.0-alpha.0";
43634
+ var DAEMON_VERSION = true ? "2.0.0-dev.85" : "2.0.0-alpha.0";
43537
43635
  var IGNORED_PATH = /[\\/](?:\.git|node_modules|\.errata|\.claude|\.codex|\.cursor|\.turbo|\.next|dist|coverage|test-results|playwright-report|__pycache__)(?:[\\/]|$)/;
43538
43636
  var IGNORED_NOISE = /castalia\.db|eventlog\.sqlite|turn-cursors/;
43539
43637
  var GIT_OP_MUTE_MS = 4e3;
@@ -44078,6 +44176,7 @@ function createWorkspaceEngine(opts) {
44078
44176
  for (const turn of items) {
44079
44177
  if (processedTurns++ > 0) await yieldToLoop();
44080
44178
  const turnFile = turn.workingFile ? toRel(turn.workingFile) : void 0;
44179
+ const editedTurnFile = turn.editedFile ? toRel(turn.editedFile) : void 0;
44081
44180
  if (opts.sharedStore) {
44082
44181
  try {
44083
44182
  abstracted += harvestAbstractionFences(opts.sharedStore, turn.text, t).applied;
@@ -44103,12 +44202,19 @@ function createWorkspaceEngine(opts) {
44103
44202
  });
44104
44203
  if (r.created || r.corroborated) minted++;
44105
44204
  sessionLastProblem.set(sessionId, designProblemId(flag.problem));
44106
- const fencedAnchor = turnFile ?? workingFiles.get(sessionId);
44107
- if ((r.created || r.corroborated) && fencedAnchor) {
44205
+ if (r.created || r.corroborated) {
44108
44206
  try {
44109
- if (anchorProblemToWorkingFile(store, r.problemId, fencedAnchor, profile.id, t)) {
44110
- deriveContextFromAnchors(store, r.problemId, t);
44207
+ if (editedTurnFile) {
44208
+ if (anchorProblemToWorkingFile(store, r.problemId, editedTurnFile, profile.id, t, "edited")) {
44209
+ deriveContextFromAnchors(store, r.problemId, t);
44210
+ }
44211
+ } else if (!flag.anchor) {
44212
+ const hintPath = turnFile ?? workingFiles.get(sessionId);
44213
+ if (hintPath) {
44214
+ recordAnchorHint(store, r.problemId, hintPath, turn.workingFileProvenance === "read" ? "read" : "carried", t);
44215
+ }
44111
44216
  }
44217
+ deriveContextFromStatement(store, r.problemId, flag.problem, t);
44112
44218
  } catch {
44113
44219
  }
44114
44220
  }
@@ -44167,10 +44273,13 @@ function createWorkspaceEngine(opts) {
44167
44273
  const threads = sessionThreads.get(sessionId) ?? /* @__PURE__ */ new Map();
44168
44274
  sessionThreads.set(sessionId, threads);
44169
44275
  for (const p of plan.problems) {
44170
- const anchorPath = p.location?.path ?? turnFile ?? wf;
44171
- if (anchorPath) {
44276
+ const anchorPath = p.location?.path ?? editedTurnFile;
44277
+ const anchorProvenance = p.location?.path ? "witnessed" : "edited";
44278
+ const hintPath = anchorPath ? void 0 : turnFile ?? wf;
44279
+ const dedupPath = anchorPath ?? hintPath;
44280
+ if (dedupPath) {
44172
44281
  try {
44173
- const dupId = reinforceSameAnchorProblem(store, anchorPath, profile.id, p.statement, sessionId, t);
44282
+ const dupId = reinforceSameAnchorProblem(store, dedupPath, profile.id, p.statement, sessionId, t);
44174
44283
  if (dupId) {
44175
44284
  minted++;
44176
44285
  sessionLastProblem.set(sessionId, dupId);
@@ -44191,13 +44300,16 @@ function createWorkspaceEngine(opts) {
44191
44300
  sessionLastProblem.set(sessionId, designProblemId(p.statement));
44192
44301
  inScopeProblemId = designProblemId(p.statement);
44193
44302
  if (p.threadId) threads.set(p.threadId, designProblemId(p.statement));
44194
- if (anchorPath) {
44195
- try {
44196
- if (anchorProblemToWorkingFile(store, r.problemId, anchorPath, profile.id, t)) {
44303
+ try {
44304
+ if (anchorPath) {
44305
+ if (anchorProblemToWorkingFile(store, r.problemId, anchorPath, profile.id, t, anchorProvenance)) {
44197
44306
  deriveContextFromAnchors(store, r.problemId, t);
44198
44307
  }
44199
- } catch {
44308
+ } else if (hintPath) {
44309
+ recordAnchorHint(store, r.problemId, hintPath, turn.workingFileProvenance === "read" ? "read" : "carried", t);
44200
44310
  }
44311
+ deriveContextFromStatement(store, r.problemId, p.statement, t);
44312
+ } catch {
44201
44313
  }
44202
44314
  }
44203
44315
  }
@@ -44218,7 +44330,7 @@ function createWorkspaceEngine(opts) {
44218
44330
  }
44219
44331
  if (resolveDesignProblemById(store, pid, fx.fixNote, t)) {
44220
44332
  resolved++;
44221
- const fxAnchor = turnFile ?? wf;
44333
+ const fxAnchor = editedTurnFile ?? turnFile ?? wf;
44222
44334
  if (fxAnchor) {
44223
44335
  try {
44224
44336
  anchorProblemToDiff(store, pid, [fxAnchor], profile.id, t);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inerrata-corporation/errata",
3
- "version": "2.0.0-dev.84",
3
+ "version": "2.0.0-dev.85",
4
4
  "description": "errata - local-first observation engine for AI coding agents",
5
5
  "type": "module",
6
6
  "bin": {