@inerrata-corporation/errata 2.0.2-dev.196 → 2.0.2-dev.204

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 (3) hide show
  1. package/errata.mjs +370 -187
  2. package/package.json +1 -1
  3. package/pass-worker.mjs +7 -4
package/errata.mjs CHANGED
@@ -20982,10 +20982,13 @@ function buildSnapshot(opts) {
20982
20982
  episodeId: episodeId2,
20983
20983
  problems: problems2
20984
20984
  }));
20985
- const needsRevisit = listNeedsRevisit(
20986
- opts.store,
20987
- (opts.now ?? /* @__PURE__ */ new Date()).getTime()
20988
- ).slice(0, 10);
20985
+ const revisitSeen = /* @__PURE__ */ new Set();
20986
+ const needsRevisit = listNeedsRevisit(opts.store, (opts.now ?? /* @__PURE__ */ new Date()).getTime()).filter((r) => {
20987
+ const key = `${r.label}:${r.description.trim().toLowerCase()}`;
20988
+ if (revisitSeen.has(key)) return false;
20989
+ revisitSeen.add(key);
20990
+ return true;
20991
+ }).slice(0, 5);
20989
20992
  const norm = (x) => x.toLowerCase().replace(/[^a-z0-9]+/g, "");
20990
20993
  const pkgBase = (x) => {
20991
20994
  const at = x.lastIndexOf("@");
@@ -21386,8 +21389,16 @@ ${RECALL_FIRST_BODY}`;
21386
21389
  // A standing design tension outranks an enrichment nudge (it prevents a wrong
21387
21390
  // decision) but yields to a live defect (which is actionable now).
21388
21391
  "recentConstraints",
21389
- "recentProblems",
21390
- "needsRevisit"
21392
+ // `needsRevisit` used to sit LAST — the most protected band in the block. That
21393
+ // inverted the block's whole purpose once the link-elicitation instruction (4,942
21394
+ // chars, 55% of the budget, non-evictable) started competing for room: the
21395
+ // budgeter drained all 8 Problems and all 4 Solutions and kept nine stale
21396
+ // auto-close notices, so the agent was handed an instruction to cite `[handles]`
21397
+ // with zero problem handles left to cite. A revisit flag is a maintenance nudge
21398
+ // about something ALREADY closed; a live prior is the substrate every link verb
21399
+ // needs. Problems outrank it now.
21400
+ "needsRevisit",
21401
+ "recentProblems"
21391
21402
  ];
21392
21403
  DEFAULT_AGENT_CONTEXT_BUDGET = 9e3;
21393
21404
  }
@@ -25259,15 +25270,15 @@ function triageBullet(ref) {
25259
25270
  }
25260
25271
  function linkBullet(ref) {
25261
25272
  return [
25262
- " \u2022 a problem you flagged resembles prior knowledge \u2014 LINK it to the canonical priors, not just one:",
25273
+ " \u2022 you flagged a problem \u2014 LINK it, and do it ESPECIALLY when the finding feels novel.",
25274
+ " Work you just did feels specific to here; that feeling is why links go unwritten, and it is",
25275
+ " exactly backwards \u2014 a finding nobody can reach from anywhere else is one nobody reuses:",
25263
25276
  ` \xB7 (instance:[${ref}],[another-prior],\u2026) \u2014 the priors this problem is an instance of.`,
25264
25277
  " Aim for ~3 DIFFERENT relevant priors; one link is weak, three triangulate it.",
25265
25278
  ` \xB7 ${TAG_EXAMPLE.pattern()} \u2014 name the general shape it instantiates (e.g. (pattern: unbounded`,
25266
25279
  " queue growth under backpressure)) \u2014 this works with NO code anchor, and two agents naming",
25267
- " the same pattern converge on one node. Cite a shown Pattern by handle: (pattern:[handle]).",
25268
- ` \xB7 ${TAG_EXAMPLE.domain()} \u2014 name the ABSTRACT AREA it's about (e.g. (domain: Observability),`,
25269
- " (domain: Community Detection)). An abstract problem with no code anchor NEEDS this or it's",
25270
- " an invisible island: the Domain is the topic other problems in the area cluster on. Title Case.",
25280
+ " the same pattern converge on one node. Naming the shape costs your finding nothing and is",
25281
+ " what lets a stranger hit it. Cite a shown Pattern by handle: (pattern:[handle]).",
25271
25282
  ` \xB7 ${TAG_EXAMPLE.package()} \u2014 the PUBLIC PACKAGE the problem is about, even when this`,
25272
25283
  " workspace doesn't depend on it (e.g. (package: chokidar), (package: pypi/requests)) \u2014 a",
25273
25284
  " public-registry anchor lets the knowledge cross to the collective; internal names stay private.",
@@ -25291,9 +25302,9 @@ function attemptBullet() {
25291
25302
  ].join("\n");
25292
25303
  }
25293
25304
  function buildAgentInstruction(opts = {}) {
25294
- const signals = opts.signals ?? ["prior", "problem", "fix", "constraint", "triage", "attempt", "link"];
25305
+ const signals = opts.signals ?? ["prior", "problem", "domain", "fix", "constraint", "triage", "attempt", "link"];
25295
25306
  const ref = opts.referent ?? "its-handle";
25296
- const token = (s) => s === "problem" ? TAG_EXAMPLE.problem() : s === "constraint" ? TAG_EXAMPLE.constraint() : s === "attempt" ? TAG_EXAMPLE.tried() : s === "link" ? TAG_EXAMPLE.pattern() : TAG_EXAMPLE[s](ref);
25307
+ const token = (s) => s === "problem" ? TAG_EXAMPLE.problem() : s === "constraint" ? TAG_EXAMPLE.constraint() : s === "attempt" ? TAG_EXAMPLE.tried() : s === "domain" ? TAG_EXAMPLE.domain() : s === "link" ? TAG_EXAMPLE.pattern() : TAG_EXAMPLE[s](ref);
25297
25308
  const head2 = `We tag the priors we show you with a short handle like [${opts.handleExample ?? "chokidar-glob"}]. This is a capture protocol, not optional notes: what you DON'T tag is silently lost \u2014 the tag is the ONLY thing recorded. Whenever one of these is true, wrap it inline in your prose (no fences, no extra calls). Tag every one you state; we filter downstream, so don't self-censor or batch:`;
25298
25309
  const tail = "Mid-turn text (between tool calls) can be dropped by the harness \u2014 if a tag above appeared only mid-turn, RESTATE it in your final message of the turn; the final message always survives.";
25299
25310
  return [
@@ -25359,6 +25370,22 @@ var init_agent_signals = __esm({
25359
25370
  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)",
25360
25371
  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",
25361
25372
  attempt: "you're attempting an approach, or an attempt didn't pan out \u2014 (tried: \u2026) / (failed: \u2026); a failed attempt rules out a path for the next agent",
25373
+ // DOMAIN — promoted to a FIRST-CLASS signal (was nested inside linkBullet, whose
25374
+ // lead-in gates on "a problem you flagged resembles prior knowledge"). Naming the
25375
+ // area a problem is about is unconditional and has nothing to do with recognizing
25376
+ // a prior, so that gate silently suppressed it: field census 2026-07-30 across 387
25377
+ // sessions — `domain` in 10/194 tag-emitting sessions (5%) against `problem` in
25378
+ // 124/194 (64%), and bimodal (the 10 that do emit average ~7 each), i.e. the
25379
+ // syntax is fine and the trigger was never reached.
25380
+ //
25381
+ // The gloss carries the anti-performance framing Cycles 9–11 proved is the actual
25382
+ // lever (the tag alone scored 0 = control; naming the bias and inverting it is
25383
+ // what lifted capture). The bias here is the mirror of the constraint one: an
25384
+ // agent that has just named a problem *precisely* feels the precision IS the
25385
+ // contribution, so stating the general area reads as vague restatement — exactly
25386
+ // when it matters most, because precise wording is what makes a problem
25387
+ // unfindable to anyone who doesn't already share it.
25388
+ domain: "you flagged a problem that isn't about one specific file \u2014 name the AREA it's about. Precision is not a substitute: the sharper your wording, the LESS anyone else will search for it, and an abstract problem with no area is an invisible island. Title Case",
25362
25389
  link: "the problem you flagged is an instance of priors/abstractions you can name \u2014 (instance:[h1],[h2],\u2026) / (pattern: \u2026) / (aids:[h]); rendered whole via linkBullet"
25363
25390
  };
25364
25391
  }
@@ -47172,12 +47199,12 @@ var init_report_render = __esm({
47172
47199
 
47173
47200
  // src/cli.ts
47174
47201
  init_src5();
47175
- import { closeSync as closeSync2, existsSync as existsSync24, openSync as openSync2, readFileSync as readFileSync22, renameSync as renameSync3, statSync as statSync6 } from "node:fs";
47176
- import { join as join26 } from "node:path";
47202
+ import { closeSync as closeSync2, existsSync as existsSync25, openSync as openSync2, readFileSync as readFileSync23, renameSync as renameSync3, statSync as statSync6 } from "node:fs";
47203
+ import { join as join27 } from "node:path";
47177
47204
  import { spawn as spawn3 } from "node:child_process";
47178
47205
 
47179
47206
  // src/daemon.ts
47180
- import { existsSync as existsSync19, writeFileSync as writeFileSync15 } from "node:fs";
47207
+ import { existsSync as existsSync20, writeFileSync as writeFileSync16 } from "node:fs";
47181
47208
 
47182
47209
  // ../../node_modules/.pnpm/@hono+node-server@1.19.11_hono@4.12.8/node_modules/@hono/node-server/dist/index.mjs
47183
47210
  import { createServer as createServerHTTP } from "http";
@@ -47757,8 +47784,8 @@ init_config();
47757
47784
 
47758
47785
  // src/engine.ts
47759
47786
  import { execFileSync as execFileSync3 } from "node:child_process";
47760
- import { existsSync as existsSync18, statSync as statSync5, appendFileSync as appendFileSync2, readdirSync as readdirSync8, renameSync as renameSync2, readFileSync as readFileSync17, writeFileSync as writeFileSync14 } from "node:fs";
47761
- import { join as join22, relative as relative6, sep as sep4 } from "node:path";
47787
+ import { existsSync as existsSync19, statSync as statSync5, appendFileSync as appendFileSync2, readdirSync as readdirSync9, renameSync as renameSync2, readFileSync as readFileSync18, writeFileSync as writeFileSync15 } from "node:fs";
47788
+ import { join as join23, relative as relative6, sep as sep4 } from "node:path";
47762
47789
 
47763
47790
  // ../../node_modules/.pnpm/chokidar@4.0.3/node_modules/chokidar/esm/index.js
47764
47791
  import { stat as statcb } from "fs";
@@ -50541,6 +50568,147 @@ ${conversation}` }]
50541
50568
  };
50542
50569
  }
50543
50570
 
50571
+ // src/constraint-backfill.ts
50572
+ init_src4();
50573
+ init_src2();
50574
+ import { existsSync as existsSync13, readFileSync as readFileSync11, readdirSync as readdirSync6, writeFileSync as writeFileSync11 } from "node:fs";
50575
+ import { join as join16 } from "node:path";
50576
+ import { homedir as homedir4 } from "node:os";
50577
+ var BACKFILL_VERSION = 1;
50578
+ var EMPTY = {
50579
+ skipped: true,
50580
+ stamped: 0,
50581
+ detached: 0,
50582
+ reopened: 0,
50583
+ witnessed: 0,
50584
+ cloudTwins: []
50585
+ };
50586
+ function markerPath(configDir) {
50587
+ return join16(configDir, "constraint-backfill.json");
50588
+ }
50589
+ function alreadyDone(configDir) {
50590
+ const p = markerPath(configDir);
50591
+ if (!existsSync13(p)) return false;
50592
+ try {
50593
+ const raw2 = JSON.parse(readFileSync11(p, "utf8"));
50594
+ return raw2?.version === BACKFILL_VERSION;
50595
+ } catch {
50596
+ return false;
50597
+ }
50598
+ }
50599
+ function replay(root) {
50600
+ const statements = /* @__PURE__ */ new Set();
50601
+ const citedByFix = /* @__PURE__ */ new Set();
50602
+ const dir = claudeProjectDir(root, homedir4());
50603
+ if (!existsSync13(dir)) return { statements, citedByFix };
50604
+ let names;
50605
+ try {
50606
+ names = readdirSync6(dir).filter((n) => n.endsWith(".jsonl"));
50607
+ } catch {
50608
+ return { statements, citedByFix };
50609
+ }
50610
+ for (const f of names) {
50611
+ let lines;
50612
+ try {
50613
+ lines = readFileSync11(join16(dir, f), "utf8").split("\n");
50614
+ } catch {
50615
+ continue;
50616
+ }
50617
+ for (const line of lines) {
50618
+ if (!line.trim()) continue;
50619
+ let rec;
50620
+ try {
50621
+ rec = JSON.parse(line);
50622
+ } catch {
50623
+ continue;
50624
+ }
50625
+ if (rec.type !== "assistant" || !Array.isArray(rec.message?.content)) continue;
50626
+ for (const b of rec.message.content) {
50627
+ if (b?.type !== "text" || typeof b.text !== "string") continue;
50628
+ for (const tag of parseInlineTags(b.text)) {
50629
+ if (tag.kind === "constraint" && tag.statement) statements.add(tag.statement);
50630
+ if (tag.kind === "fix") {
50631
+ const t = tag;
50632
+ if (t.handle) citedByFix.add(t.handle);
50633
+ if (t.threadId) citedByFix.add(t.threadId);
50634
+ }
50635
+ }
50636
+ }
50637
+ }
50638
+ }
50639
+ return { statements, citedByFix };
50640
+ }
50641
+ function backfillConstraintKind(store, opts) {
50642
+ if (!opts.force && !opts.dryRun && alreadyDone(opts.configDir)) return EMPTY;
50643
+ const { statements, citedByFix } = replay(opts.root);
50644
+ const report = {
50645
+ skipped: false,
50646
+ stamped: 0,
50647
+ detached: 0,
50648
+ reopened: 0,
50649
+ witnessed: 0,
50650
+ cloudTwins: []
50651
+ };
50652
+ const seen = /* @__PURE__ */ new Set();
50653
+ const work = [];
50654
+ for (const statement of statements) {
50655
+ const id = designProblemId(statement);
50656
+ if (seen.has(id)) continue;
50657
+ seen.add(id);
50658
+ const node2 = store.getNode(id);
50659
+ if (!node2 || node2.label !== "Problem") continue;
50660
+ const isWitnessed = citedByFix.has(priorHandle(node2)) || citedByFix.has(id) || [...citedByFix].some((c) => c && id.startsWith(c));
50661
+ const fabricated = [];
50662
+ for (const e of store.outEdges(id, ["SOLVED_BY"])) {
50663
+ const sol = store.getNode(e.to);
50664
+ if (!sol) continue;
50665
+ const auto = sol.description.startsWith(AUTO_MINT_PREFIX);
50666
+ if (!auto && isWitnessed) report.witnessed++;
50667
+ else fabricated.push(sol.id);
50668
+ }
50669
+ const stamp = node2.attrs["kind"] !== "constraint";
50670
+ if (stamp) report.stamped++;
50671
+ if (fabricated.length > 0) {
50672
+ report.detached += fabricated.length;
50673
+ report.reopened++;
50674
+ }
50675
+ const cloudNodeId = node2.attrs["cloudNodeId"];
50676
+ if (typeof cloudNodeId === "string" && (stamp || fabricated.length > 0)) {
50677
+ report.cloudTwins.push(cloudNodeId);
50678
+ }
50679
+ if (stamp || fabricated.length > 0) work.push({ id, fabricated, stamp });
50680
+ }
50681
+ if (opts.dryRun) return report;
50682
+ store.transaction(() => {
50683
+ for (const w of work) {
50684
+ const node2 = store.getNode(w.id);
50685
+ if (!node2) continue;
50686
+ const attrs = { ...node2.attrs, kind: "constraint" };
50687
+ if (w.fabricated.length > 0) {
50688
+ delete attrs["resolvedAt"];
50689
+ delete attrs["resolvedReason"];
50690
+ }
50691
+ store.updateNode(w.id, { attrs, lastUpdatedAt: opts.now });
50692
+ for (const solId of w.fabricated) {
50693
+ for (const e of store.outEdges(w.id, ["SOLVED_BY"])) {
50694
+ if (e.to === solId) store.closeEdge(e.id, opts.now);
50695
+ }
50696
+ const sol = store.getNode(solId);
50697
+ if (sol?.description.startsWith(AUTO_MINT_PREFIX)) store.closeNode(solId, opts.now);
50698
+ }
50699
+ }
50700
+ });
50701
+ try {
50702
+ writeFileSync11(
50703
+ markerPath(opts.configDir),
50704
+ JSON.stringify({ version: BACKFILL_VERSION, at: opts.now, ...report, cloudTwins: report.cloudTwins.length }, null, 2),
50705
+ "utf8"
50706
+ );
50707
+ } catch {
50708
+ }
50709
+ return report;
50710
+ }
50711
+
50544
50712
  // src/engine.ts
50545
50713
  init_symbol_summaries();
50546
50714
  init_reconcile();
@@ -50739,11 +50907,11 @@ init_outbox();
50739
50907
  init_src8();
50740
50908
  init_src();
50741
50909
  init_src2();
50742
- import { readFileSync as readFileSync11 } from "node:fs";
50743
- import { join as join16 } from "node:path";
50910
+ import { readFileSync as readFileSync12 } from "node:fs";
50911
+ import { join as join17 } from "node:path";
50744
50912
  function loadClaimIgnorePatterns(workspaceRoot) {
50745
50913
  try {
50746
- return readFileSync11(join16(workspaceRoot, ".errataignore"), "utf8").split(/\r?\n/).map((l) => l.trim()).filter((l) => l.length > 0 && !l.startsWith("#")).map((l) => l.toLowerCase());
50914
+ return readFileSync12(join17(workspaceRoot, ".errataignore"), "utf8").split(/\r?\n/).map((l) => l.trim()).filter((l) => l.length > 0 && !l.startsWith("#")).map((l) => l.toLowerCase());
50747
50915
  } catch {
50748
50916
  return [];
50749
50917
  }
@@ -51104,22 +51272,22 @@ async function pullCloudTriage(shared, cloud, profile, limit = 50) {
51104
51272
  }
51105
51273
 
51106
51274
  // src/git-sensor.ts
51107
- import { existsSync as existsSync13, readFileSync as readFileSync12, watch as fsWatch } from "node:fs";
51108
- import { join as join17 } from "node:path";
51275
+ import { existsSync as existsSync14, readFileSync as readFileSync13, watch as fsWatch } from "node:fs";
51276
+ import { join as join18 } from "node:path";
51109
51277
  function readFirstLine(path2) {
51110
51278
  try {
51111
- return readFileSync12(path2, "utf8").split(/\r?\n/, 1)[0].trim();
51279
+ return readFileSync13(path2, "utf8").split(/\r?\n/, 1)[0].trim();
51112
51280
  } catch {
51113
51281
  return null;
51114
51282
  }
51115
51283
  }
51116
51284
  function readGitRefState(gitDir) {
51117
- const head2 = readFirstLine(join17(gitDir, "HEAD"));
51285
+ const head2 = readFirstLine(join18(gitDir, "HEAD"));
51118
51286
  const m = head2 ? /^ref:\s*refs\/heads\/(.+)$/.exec(head2) : null;
51119
51287
  const branch = m ? m[1] : null;
51120
51288
  let sha2 = null;
51121
51289
  if (branch) {
51122
- sha2 = readFirstLine(join17(gitDir, "refs", "heads", branch));
51290
+ sha2 = readFirstLine(join18(gitDir, "refs", "heads", branch));
51123
51291
  if (!sha2) sha2 = shaFromPackedRefs(gitDir, `refs/heads/${branch}`);
51124
51292
  } else if (head2 && /^[0-9a-f]{7,40}$/i.test(head2)) {
51125
51293
  sha2 = head2;
@@ -51127,13 +51295,13 @@ function readGitRefState(gitDir) {
51127
51295
  return {
51128
51296
  branch,
51129
51297
  sha: sha2,
51130
- mergeHeadExists: existsSync13(join17(gitDir, "MERGE_HEAD")),
51131
- origHeadExists: existsSync13(join17(gitDir, "ORIG_HEAD"))
51298
+ mergeHeadExists: existsSync14(join18(gitDir, "MERGE_HEAD")),
51299
+ origHeadExists: existsSync14(join18(gitDir, "ORIG_HEAD"))
51132
51300
  };
51133
51301
  }
51134
51302
  function shaFromPackedRefs(gitDir, ref) {
51135
51303
  try {
51136
- for (const line of readFileSync12(join17(gitDir, "packed-refs"), "utf8").split(/\r?\n/)) {
51304
+ for (const line of readFileSync13(join18(gitDir, "packed-refs"), "utf8").split(/\r?\n/)) {
51137
51305
  const [sha2, name2] = line.split(/\s+/);
51138
51306
  if (name2 === ref && sha2) return sha2;
51139
51307
  }
@@ -51167,7 +51335,7 @@ function startGitSensor(gitDir, onEvent, opts = {}) {
51167
51335
  const settle = () => {
51168
51336
  if (timer) clearTimeout(timer);
51169
51337
  timer = setTimeout(() => {
51170
- if (existsSync13(join17(gitDir, "index.lock"))) {
51338
+ if (existsSync14(join18(gitDir, "index.lock"))) {
51171
51339
  settle();
51172
51340
  return;
51173
51341
  }
@@ -51178,7 +51346,7 @@ function startGitSensor(gitDir, onEvent, opts = {}) {
51178
51346
  }, debounceMs);
51179
51347
  };
51180
51348
  for (const sub of ["HEAD", "logs/HEAD", "MERGE_HEAD", "ORIG_HEAD"]) {
51181
- const p = join17(gitDir, sub);
51349
+ const p = join18(gitDir, sub);
51182
51350
  try {
51183
51351
  watchers.push(fsWatch(p, settle));
51184
51352
  } catch {
@@ -51403,21 +51571,21 @@ var TelemetryRecorder = class {
51403
51571
 
51404
51572
  // src/skills.ts
51405
51573
  import {
51406
- existsSync as existsSync14,
51574
+ existsSync as existsSync15,
51407
51575
  mkdirSync as mkdirSync6,
51408
- readFileSync as readFileSync13,
51409
- readdirSync as readdirSync6,
51576
+ readFileSync as readFileSync14,
51577
+ readdirSync as readdirSync7,
51410
51578
  unlinkSync as unlinkSync2,
51411
- writeFileSync as writeFileSync11
51579
+ writeFileSync as writeFileSync12
51412
51580
  } from "node:fs";
51413
- import { basename as basename4, join as join18 } from "node:path";
51581
+ import { basename as basename4, join as join19 } from "node:path";
51414
51582
  function skillFileName(id) {
51415
51583
  return `${id.replace(/[^A-Za-z0-9_.-]/g, "_")}.md`;
51416
51584
  }
51417
51585
  function readSkillManifest(manifestPath) {
51418
- if (!existsSync14(manifestPath)) return [];
51586
+ if (!existsSync15(manifestPath)) return [];
51419
51587
  try {
51420
- const parsed = JSON.parse(readFileSync13(manifestPath, "utf8"));
51588
+ const parsed = JSON.parse(readFileSync14(manifestPath, "utf8"));
51421
51589
  return (parsed.skills ?? []).map((s) => ({
51422
51590
  title: s.title ?? "",
51423
51591
  layer: s.layer ?? "technique",
@@ -51433,7 +51601,7 @@ async function syncSkills(paths, client, seed, pins = [], techSeed) {
51433
51601
  const staleDaemon = res.staleDaemon && res.latestDaemonVersion ? { latest: res.latestDaemonVersion } : void 0;
51434
51602
  mkdirSync6(paths.skillsDir, { recursive: true });
51435
51603
  if (res.skills.length === 0 && pins.length === 0) {
51436
- const existing = readdirSync6(paths.skillsDir).filter((f) => f.endsWith(".md"));
51604
+ const existing = readdirSync7(paths.skillsDir).filter((f) => f.endsWith(".md"));
51437
51605
  if (existing.length > 0) return { written: 0, pruned: 0, ...staleDaemon ? { staleDaemon } : {} };
51438
51606
  }
51439
51607
  const rows = [];
@@ -51441,7 +51609,7 @@ async function syncSkills(paths, client, seed, pins = [], techSeed) {
51441
51609
  for (const s of res.skills) {
51442
51610
  const fileName = skillFileName(s.id);
51443
51611
  keep.add(fileName);
51444
- writeFileSync11(join18(paths.skillsDir, fileName), s.markdown, "utf8");
51612
+ writeFileSync12(join19(paths.skillsDir, fileName), s.markdown, "utf8");
51445
51613
  rows.push({
51446
51614
  id: s.id,
51447
51615
  title: s.title,
@@ -51454,7 +51622,7 @@ async function syncSkills(paths, client, seed, pins = [], techSeed) {
51454
51622
  const fileName = skillFileName(p.id);
51455
51623
  if (keep.has(fileName)) continue;
51456
51624
  keep.add(fileName);
51457
- writeFileSync11(join18(paths.skillsDir, fileName), p.markdown, "utf8");
51625
+ writeFileSync12(join19(paths.skillsDir, fileName), p.markdown, "utf8");
51458
51626
  rows.push({
51459
51627
  id: p.id,
51460
51628
  title: p.title,
@@ -51464,17 +51632,17 @@ async function syncSkills(paths, client, seed, pins = [], techSeed) {
51464
51632
  });
51465
51633
  }
51466
51634
  let pruned = 0;
51467
- for (const f of readdirSync6(paths.skillsDir)) {
51635
+ for (const f of readdirSync7(paths.skillsDir)) {
51468
51636
  if (!f.endsWith(".md")) continue;
51469
51637
  if (keep.has(basename4(f))) continue;
51470
51638
  try {
51471
- unlinkSync2(join18(paths.skillsDir, f));
51639
+ unlinkSync2(join19(paths.skillsDir, f));
51472
51640
  pruned++;
51473
51641
  } catch {
51474
51642
  }
51475
51643
  }
51476
51644
  rows.sort((a, b) => a.id.localeCompare(b.id));
51477
- writeFileSync11(
51645
+ writeFileSync12(
51478
51646
  paths.skillsManifest,
51479
51647
  JSON.stringify({ generatedAt: Date.now(), skills: rows }, null, 2),
51480
51648
  "utf8"
@@ -51486,22 +51654,22 @@ async function syncSkills(paths, client, seed, pins = [], techSeed) {
51486
51654
  init_src2();
51487
51655
  import {
51488
51656
  cpSync,
51489
- existsSync as existsSync15,
51657
+ existsSync as existsSync16,
51490
51658
  lstatSync,
51491
51659
  mkdirSync as mkdirSync7,
51492
- readFileSync as readFileSync14,
51493
- readdirSync as readdirSync7,
51660
+ readFileSync as readFileSync15,
51661
+ readdirSync as readdirSync8,
51494
51662
  rmSync as rmSync2,
51495
51663
  symlinkSync,
51496
- writeFileSync as writeFileSync12
51664
+ writeFileSync as writeFileSync13
51497
51665
  } from "node:fs";
51498
- import { join as join19 } from "node:path";
51666
+ import { join as join20 } from "node:path";
51499
51667
  var SKILL_NS = "errata-";
51500
51668
  var HARNESS_SKILL_DIRS = [
51501
- { configDir: ".claude", skillsDir: join19(".claude", "skills") },
51669
+ { configDir: ".claude", skillsDir: join20(".claude", "skills") },
51502
51670
  // Cursor adopted the standard; its exact project dir is still moving — kept
51503
51671
  // best-effort and gated on `.cursor/` presence so we never create it blind.
51504
- { configDir: ".cursor", skillsDir: join19(".cursor", "skills") }
51672
+ { configDir: ".cursor", skillsDir: join20(".cursor", "skills") }
51505
51673
  ];
51506
51674
  function skillSlug(title, id) {
51507
51675
  const base = title.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || id.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "skill";
@@ -51546,12 +51714,12 @@ function skillCiteHandle(s) {
51546
51714
  return priorHandle({ id: s.id, description: s.title });
51547
51715
  }
51548
51716
  function reconcileNamespaced(dir, keep) {
51549
- if (!existsSync15(dir)) return 0;
51717
+ if (!existsSync16(dir)) return 0;
51550
51718
  let pruned = 0;
51551
- for (const name2 of readdirSync7(dir)) {
51719
+ for (const name2 of readdirSync8(dir)) {
51552
51720
  if (!name2.startsWith(SKILL_NS) || keep.has(name2)) continue;
51553
51721
  try {
51554
- rmSync2(join19(dir, name2), { recursive: true, force: true });
51722
+ rmSync2(join20(dir, name2), { recursive: true, force: true });
51555
51723
  pruned++;
51556
51724
  } catch {
51557
51725
  }
@@ -51560,7 +51728,7 @@ function reconcileNamespaced(dir, keep) {
51560
51728
  }
51561
51729
  function linkOrCopy(linkPath, target) {
51562
51730
  try {
51563
- if (existsSync15(linkPath) || safeLstat(linkPath)) rmSync2(linkPath, { recursive: true, force: true });
51731
+ if (existsSync16(linkPath) || safeLstat(linkPath)) rmSync2(linkPath, { recursive: true, force: true });
51564
51732
  } catch {
51565
51733
  }
51566
51734
  try {
@@ -51581,7 +51749,7 @@ function safeLstat(p) {
51581
51749
  }
51582
51750
  }
51583
51751
  function emitAndProjectSkills(root, skills) {
51584
- const agentsSkillsDir = join19(root, ".agents", "skills");
51752
+ const agentsSkillsDir = join20(root, ".agents", "skills");
51585
51753
  mkdirSync7(agentsSkillsDir, { recursive: true });
51586
51754
  const slugs = [];
51587
51755
  const keep = /* @__PURE__ */ new Set();
@@ -51589,7 +51757,7 @@ function emitAndProjectSkills(root, skills) {
51589
51757
  for (const s of skills) {
51590
51758
  let body2;
51591
51759
  try {
51592
- body2 = readFileSync14(s.bodyPath, "utf8");
51760
+ body2 = readFileSync15(s.bodyPath, "utf8");
51593
51761
  } catch {
51594
51762
  continue;
51595
51763
  }
@@ -51598,9 +51766,9 @@ function emitAndProjectSkills(root, skills) {
51598
51766
  keep.add(slug2);
51599
51767
  slugs.push(slug2);
51600
51768
  const description = deriveDescription(s.title, s.layer, body2);
51601
- mkdirSync7(join19(agentsSkillsDir, slug2), { recursive: true });
51602
- writeFileSync12(
51603
- join19(agentsSkillsDir, slug2, "SKILL.md"),
51769
+ mkdirSync7(join20(agentsSkillsDir, slug2), { recursive: true });
51770
+ writeFileSync13(
51771
+ join20(agentsSkillsDir, slug2, "SKILL.md"),
51604
51772
  renderSkillMd(slug2, description, body2, skillCiteHandle(s)),
51605
51773
  "utf8"
51606
51774
  );
@@ -51609,11 +51777,11 @@ function emitAndProjectSkills(root, skills) {
51609
51777
  reconcileNamespaced(agentsSkillsDir, keep);
51610
51778
  let projected = 0;
51611
51779
  for (const h of HARNESS_SKILL_DIRS) {
51612
- if (!existsSync15(join19(root, h.configDir))) continue;
51613
- const dir = join19(root, h.skillsDir);
51780
+ if (!existsSync16(join20(root, h.configDir))) continue;
51781
+ const dir = join20(root, h.skillsDir);
51614
51782
  mkdirSync7(dir, { recursive: true });
51615
51783
  for (const slug2 of slugs) {
51616
- linkOrCopy(join19(dir, slug2), join19(agentsSkillsDir, slug2));
51784
+ linkOrCopy(join20(dir, slug2), join20(agentsSkillsDir, slug2));
51617
51785
  projected++;
51618
51786
  }
51619
51787
  reconcileNamespaced(dir, keep);
@@ -51622,15 +51790,15 @@ function emitAndProjectSkills(root, skills) {
51622
51790
  return { slugs, emitted, projected };
51623
51791
  }
51624
51792
  function emitInputsFromManifest(erretaDir, manifestPath) {
51625
- if (!existsSync15(manifestPath)) return [];
51793
+ if (!existsSync16(manifestPath)) return [];
51626
51794
  try {
51627
- const parsed = JSON.parse(readFileSync14(manifestPath, "utf8"));
51795
+ const parsed = JSON.parse(readFileSync15(manifestPath, "utf8"));
51628
51796
  return (parsed.skills ?? []).filter((s) => Boolean(s.id && s.file)).map((s) => ({
51629
51797
  id: s.id,
51630
51798
  title: s.title ?? s.id,
51631
51799
  layer: s.layer ?? "technique",
51632
51800
  confidence: s.confidence ?? 0,
51633
- bodyPath: join19(erretaDir, s.file)
51801
+ bodyPath: join20(erretaDir, s.file)
51634
51802
  }));
51635
51803
  } catch {
51636
51804
  return [];
@@ -51644,17 +51812,17 @@ var GITIGNORE_LINES = [
51644
51812
  ".cursor/skills/errata-*/"
51645
51813
  ];
51646
51814
  function ensureSkillGitignore(root) {
51647
- const path2 = join19(root, ".gitignore");
51815
+ const path2 = join20(root, ".gitignore");
51648
51816
  let current = "";
51649
51817
  try {
51650
- current = existsSync15(path2) ? readFileSync14(path2, "utf8") : "";
51818
+ current = existsSync16(path2) ? readFileSync15(path2, "utf8") : "";
51651
51819
  } catch {
51652
51820
  return;
51653
51821
  }
51654
51822
  if (current.includes(GITIGNORE_MARK)) return;
51655
51823
  const prefix = current.length > 0 && !current.endsWith("\n") ? "\n" : "";
51656
51824
  try {
51657
- writeFileSync12(path2, `${current}${prefix}
51825
+ writeFileSync13(path2, `${current}${prefix}
51658
51826
  ${GITIGNORE_LINES.join("\n")}
51659
51827
  `, "utf8");
51660
51828
  } catch {
@@ -51818,20 +51986,20 @@ var CausalBuffer = class {
51818
51986
  // src/profile.ts
51819
51987
  init_src2();
51820
51988
  init_paths();
51821
- import { existsSync as existsSync17, readFileSync as readFileSync16, writeFileSync as writeFileSync13 } from "node:fs";
51989
+ import { existsSync as existsSync18, readFileSync as readFileSync17, writeFileSync as writeFileSync14 } from "node:fs";
51822
51990
  import { createHash as createHash12 } from "node:crypto";
51823
- import { join as join21 } from "node:path";
51991
+ import { join as join22 } from "node:path";
51824
51992
 
51825
51993
  // src/git-remote.ts
51826
51994
  init_src();
51827
- import { existsSync as existsSync16, readFileSync as readFileSync15, statSync as statSync4 } from "node:fs";
51828
- import { isAbsolute as isAbsolute3, join as join20, resolve as resolve5 } from "node:path";
51995
+ import { existsSync as existsSync17, readFileSync as readFileSync16, statSync as statSync4 } from "node:fs";
51996
+ import { isAbsolute as isAbsolute3, join as join21, resolve as resolve5 } from "node:path";
51829
51997
  function resolveGitDir(root) {
51830
- const dotGit = join20(root, ".git");
51998
+ const dotGit = join21(root, ".git");
51831
51999
  try {
51832
52000
  const st = statSync4(dotGit);
51833
52001
  if (st.isDirectory()) return dotGit;
51834
- const m = /^gitdir:\s*(.+?)\s*$/m.exec(readFileSync15(dotGit, "utf8"));
52002
+ const m = /^gitdir:\s*(.+?)\s*$/m.exec(readFileSync16(dotGit, "utf8"));
51835
52003
  if (!m) return null;
51836
52004
  const dir = m[1];
51837
52005
  return isAbsolute3(dir) ? dir : resolve5(root, dir);
@@ -51840,22 +52008,22 @@ function resolveGitDir(root) {
51840
52008
  }
51841
52009
  }
51842
52010
  function gitConfigPath(gitDir) {
51843
- const commondirFile = join20(gitDir, "commondir");
51844
- if (existsSync16(commondirFile)) {
51845
- const common = readFileSync15(commondirFile, "utf8").trim();
52011
+ const commondirFile = join21(gitDir, "commondir");
52012
+ if (existsSync17(commondirFile)) {
52013
+ const common = readFileSync16(commondirFile, "utf8").trim();
51846
52014
  const commonDir = isAbsolute3(common) ? common : resolve5(gitDir, common);
51847
- return join20(commonDir, "config");
52015
+ return join21(commonDir, "config");
51848
52016
  }
51849
- return join20(gitDir, "config");
52017
+ return join21(gitDir, "config");
51850
52018
  }
51851
52019
  function readRemotes(root) {
51852
52020
  const gitDir = resolveGitDir(root);
51853
52021
  if (!gitDir) return [];
51854
52022
  const cfgPath = gitConfigPath(gitDir);
51855
- if (!existsSync16(cfgPath)) return [];
52023
+ if (!existsSync17(cfgPath)) return [];
51856
52024
  let txt;
51857
52025
  try {
51858
- txt = readFileSync15(cfgPath, "utf8");
52026
+ txt = readFileSync16(cfgPath, "utf8");
51859
52027
  } catch {
51860
52028
  return [];
51861
52029
  }
@@ -51887,13 +52055,13 @@ function refreshRepoLocator(root, profile) {
51887
52055
  }
51888
52056
  function loadProfile(root) {
51889
52057
  const p = workspacePaths(root);
51890
- if (!existsSync17(p.workspaceJson)) return null;
51891
- return JSON.parse(readFileSync16(p.workspaceJson, "utf8"));
52058
+ if (!existsSync18(p.workspaceJson)) return null;
52059
+ return JSON.parse(readFileSync17(p.workspaceJson, "utf8"));
51892
52060
  }
51893
52061
  function saveProfile(root, profile) {
51894
52062
  const p = workspacePaths(root);
51895
52063
  ensureDir(p.configDir);
51896
- writeFileSync13(p.workspaceJson, JSON.stringify(profile, null, 2), "utf8");
52064
+ writeFileSync14(p.workspaceJson, JSON.stringify(profile, null, 2), "utf8");
51897
52065
  }
51898
52066
  function autodetectProfile(root) {
51899
52067
  const id = workspaceId(root);
@@ -51901,10 +52069,10 @@ function autodetectProfile(root) {
51901
52069
  const p = emptyProfile(id, name2);
51902
52070
  const locator = detectRepoLocator(root);
51903
52071
  if (locator) p.repoLocator = locator;
51904
- const pkgPath = join21(root, "package.json");
51905
- if (existsSync17(pkgPath)) {
52072
+ const pkgPath = join22(root, "package.json");
52073
+ if (existsSync18(pkgPath)) {
51906
52074
  try {
51907
- const pkg = JSON.parse(readFileSync16(pkgPath, "utf8"));
52075
+ const pkg = JSON.parse(readFileSync17(pkgPath, "utf8"));
51908
52076
  p.languages.push("typescript", "javascript");
51909
52077
  const nodeVer = pkg.engines?.node ?? "node";
51910
52078
  p.stack.push(`node@${nodeVer}`);
@@ -51925,10 +52093,10 @@ function autodetectProfile(root) {
51925
52093
  } catch {
51926
52094
  }
51927
52095
  }
51928
- const pyproject = join21(root, "pyproject.toml");
51929
- if (existsSync17(pyproject)) {
52096
+ const pyproject = join22(root, "pyproject.toml");
52097
+ if (existsSync18(pyproject)) {
51930
52098
  try {
51931
- const txt = readFileSync16(pyproject, "utf8");
52099
+ const txt = readFileSync17(pyproject, "utf8");
51932
52100
  const py = /python\s*=\s*"([^"]+)"/.exec(txt)?.[1];
51933
52101
  p.languages.push("python");
51934
52102
  p.stack.push(`python@${py ?? "3"}`);
@@ -51939,16 +52107,16 @@ function autodetectProfile(root) {
51939
52107
  } catch {
51940
52108
  }
51941
52109
  }
51942
- const reqs = join21(root, "requirements.txt");
51943
- if (existsSync17(reqs)) {
52110
+ const reqs = join22(root, "requirements.txt");
52111
+ if (existsSync18(reqs)) {
51944
52112
  if (!p.languages.includes("python")) p.languages.push("python");
51945
52113
  if (!p.stack.includes("python@3")) p.stack.push("python@3");
51946
52114
  }
51947
- if (existsSync17(join21(root, "go.mod"))) {
52115
+ if (existsSync18(join22(root, "go.mod"))) {
51948
52116
  p.languages.push("go");
51949
52117
  p.stack.push("go");
51950
52118
  }
51951
- if (existsSync17(join21(root, "Cargo.toml"))) {
52119
+ if (existsSync18(join22(root, "Cargo.toml"))) {
51952
52120
  p.languages.push("rust");
51953
52121
  p.stack.push("rust");
51954
52122
  }
@@ -52106,7 +52274,7 @@ function startLoopLagMonitor(thresholdMs = 1e3) {
52106
52274
  }
52107
52275
 
52108
52276
  // src/engine.ts
52109
- var DAEMON_VERSION = true ? "2.0.2-dev.196" : "2.0.0-alpha.0";
52277
+ var DAEMON_VERSION = true ? "2.0.2-dev.204" : "2.0.0-alpha.0";
52110
52278
  var IGNORED_PATH = /[\\/](?:\.git|node_modules|\.errata|\.claude|\.codex|\.cursor|\.turbo|\.next|dist|coverage|test-results|playwright-report|__pycache__)(?:[\\/]|$)/;
52111
52279
  var IGNORED_NOISE = /castalia\.db|eventlog\.sqlite|turn-cursors/;
52112
52280
  var GIT_OP_MUTE_MS = 4e3;
@@ -52116,7 +52284,7 @@ var TURN_REPLAY_LOOKBACK_MS = 7 * 24 * 60 * 6e4;
52116
52284
  function appendIdentityAudit(path2, record2, line) {
52117
52285
  if (!record2.accepted && record2.score <= 0) return;
52118
52286
  try {
52119
- if (existsSync18(path2) && statSync5(path2).size >= IDENTITY_AUDIT_MAX_BYTES) {
52287
+ if (existsSync19(path2) && statSync5(path2).size >= IDENTITY_AUDIT_MAX_BYTES) {
52120
52288
  renameSync2(path2, `${path2}.1`);
52121
52289
  }
52122
52290
  appendFileSync2(path2, line);
@@ -52126,14 +52294,14 @@ function appendIdentityAudit(path2, record2, line) {
52126
52294
  var yieldToLoop = () => new Promise((r) => setImmediate(r));
52127
52295
  function loadTurnCursors(path2) {
52128
52296
  try {
52129
- return new Map(Object.entries(JSON.parse(readFileSync17(path2, "utf8"))));
52297
+ return new Map(Object.entries(JSON.parse(readFileSync18(path2, "utf8"))));
52130
52298
  } catch {
52131
52299
  return /* @__PURE__ */ new Map();
52132
52300
  }
52133
52301
  }
52134
52302
  function saveTurnCursors(path2, cursors) {
52135
52303
  try {
52136
- writeFileSync14(path2, JSON.stringify(Object.fromEntries(cursors)), "utf8");
52304
+ writeFileSync15(path2, JSON.stringify(Object.fromEntries(cursors)), "utf8");
52137
52305
  } catch {
52138
52306
  }
52139
52307
  }
@@ -52155,7 +52323,7 @@ function gitSourceWatchTargets(root) {
52155
52323
  ["-C", root, "ls-files", "--others", "--ignored", "--exclude-standard", "--directory", "-z"],
52156
52324
  { encoding: "utf8", maxBuffer: 256 * 1024 * 1024, windowsHide: true, stdio: ["ignore", "pipe", "ignore"] }
52157
52325
  );
52158
- ignoredDirs = igOut.split("\0").filter(Boolean).map((d) => d.replace(/\/+$/, "")).filter((d) => !IGNORED_PATH.test(join22(root, d) + sep4));
52326
+ ignoredDirs = igOut.split("\0").filter(Boolean).map((d) => d.replace(/\/+$/, "")).filter((d) => !IGNORED_PATH.test(join23(root, d) + sep4));
52159
52327
  } catch {
52160
52328
  }
52161
52329
  const hasIgnoredChild = (dir) => ignoredDirs.some((ig) => ig.startsWith(dir + "/"));
@@ -52167,19 +52335,19 @@ function gitSourceWatchTargets(root) {
52167
52335
  if (!f.startsWith(prefix)) continue;
52168
52336
  const rest2 = f.slice(prefix.length);
52169
52337
  if (rest2.includes("/")) children.add(dir === "" ? rest2.slice(0, rest2.indexOf("/")) : dir + "/" + rest2.slice(0, rest2.indexOf("/")));
52170
- else targets.add(join22(root, f));
52338
+ else targets.add(join23(root, f));
52171
52339
  }
52172
52340
  for (const c of children) {
52173
- if (IGNORED_PATH.test(join22(root, c) + sep4)) continue;
52341
+ if (IGNORED_PATH.test(join23(root, c) + sep4)) continue;
52174
52342
  if (hasIgnoredChild(c)) addUnder(c);
52175
- else targets.add(join22(root, c));
52343
+ else targets.add(join23(root, c));
52176
52344
  }
52177
52345
  };
52178
52346
  addUnder("");
52179
52347
  if (targets.size > 0) return [...targets];
52180
52348
  } catch {
52181
52349
  }
52182
- return readdirSync8(root, { withFileTypes: true }).filter((e) => e.isDirectory() && !IGNORED_PATH.test(join22(root, String(e.name)) + sep4)).map((e) => join22(root, String(e.name)));
52350
+ return readdirSync9(root, { withFileTypes: true }).filter((e) => e.isDirectory() && !IGNORED_PATH.test(join23(root, String(e.name)) + sep4)).map((e) => join23(root, String(e.name)));
52183
52351
  }
52184
52352
  function createWorkspaceEngine(opts) {
52185
52353
  const paths = workspacePaths(opts.workspaceRoot);
@@ -52333,7 +52501,7 @@ function createWorkspaceEngine(opts) {
52333
52501
  const srcPaths = diff.changedPaths.filter((p) => /\.(ts|tsx|js|jsx|mjs|cjs|py)$/i.test(p));
52334
52502
  let episodeId2;
52335
52503
  if (srcPaths.length > 0) {
52336
- const abs = srcPaths.map((p) => join22(opts.workspaceRoot, p));
52504
+ const abs = srcPaths.map((p) => join23(opts.workspaceRoot, p));
52337
52505
  try {
52338
52506
  const r = await runReindexPass(
52339
52507
  `git-reindex:${profile.name} (${abs.length} files)`,
@@ -52369,8 +52537,8 @@ function createWorkspaceEngine(opts) {
52369
52537
  `[errata] git: ${ev.kind} ${ev.newSha.slice(0, 7)} by ${meta3.authorName} \u2014 ${diff.changedPaths.length} file(s), ${diff.renames.length} rename(s)`
52370
52538
  );
52371
52539
  };
52372
- const gitDir = join22(opts.workspaceRoot, ".git");
52373
- if (existsSync18(gitDir)) {
52540
+ const gitDir = join23(opts.workspaceRoot, ".git");
52541
+ if (existsSync19(gitDir)) {
52374
52542
  stopGit = startGitSensor(gitDir, (ev) => {
52375
52543
  void handleGitEvent(ev).catch((err2) => {
52376
52544
  console.warn("[errata] git event handler failed:", err2);
@@ -52440,10 +52608,10 @@ function createWorkspaceEngine(opts) {
52440
52608
  });
52441
52609
  doneRender?.();
52442
52610
  writeContextFile(opts.workspaceRoot, body2);
52443
- const target = join22(opts.workspaceRoot, "AGENTS.md");
52611
+ const target = join23(opts.workspaceRoot, "AGENTS.md");
52444
52612
  writeManagedBlock(target, { body: AGENTS_POINTER_BODY, stable: true, force: true });
52445
52613
  if (elicit) {
52446
- writePrimingHandles(join22(paths.configDir, "priming-handles.json"), [
52614
+ writePrimingHandles(join23(paths.configDir, "priming-handles.json"), [
52447
52615
  ...snapshot.recentProblems.map((r) => r.node),
52448
52616
  // Resolved-band handles: the ✓ problem AND its Solution are citable
52449
52617
  // (a fix tag on an already-resolved problem no-ops idempotently; the
@@ -52534,6 +52702,21 @@ function createWorkspaceEngine(opts) {
52534
52702
  } catch (err2) {
52535
52703
  console.warn("[errata] anchor backfill failed:", err2);
52536
52704
  }
52705
+ try {
52706
+ const c = backfillConstraintKind(store, {
52707
+ root: opts.workspaceRoot,
52708
+ configDir: paths.configDir,
52709
+ now: Date.now()
52710
+ });
52711
+ if (!c.skipped && (c.stamped > 0 || c.detached > 0)) {
52712
+ console.log(
52713
+ `[errata] constraint backfill: ${c.stamped} design tension(s) marked` + (c.detached > 0 ? `; ${c.detached} fabricated resolution(s) detached, ${c.reopened} reopened` : "") + (c.witnessed > 0 ? `; ${c.witnessed} cited discharge(s) kept` : "") + (c.cloudTwins.length > 0 ? ` \u2014 ${c.cloudTwins.length} already contributed; run scripts/repair-cloud-constraints.ts to repair the cloud twins` : "")
52714
+ );
52715
+ refreshContextNow();
52716
+ }
52717
+ } catch (err2) {
52718
+ console.warn("[errata] constraint backfill failed:", err2);
52719
+ }
52537
52720
  const report = runNightlyPipeline(store);
52538
52721
  try {
52539
52722
  const m = mergeDuplicateProblems(store, { ts: Date.now() });
@@ -52633,7 +52816,7 @@ function createWorkspaceEngine(opts) {
52633
52816
  resultSummary: { exitCode: e.exitCode ?? 1, errorTokens: e.errorTokens }
52634
52817
  });
52635
52818
  };
52636
- const turnCursorPath = join22(paths.configDir, "turn-cursors.json");
52819
+ const turnCursorPath = join23(paths.configDir, "turn-cursors.json");
52637
52820
  const lastTurnUuid = loadTurnCursors(turnCursorPath);
52638
52821
  const sessionLastProblem = /* @__PURE__ */ new Map();
52639
52822
  const sessionThreads = /* @__PURE__ */ new Map();
@@ -52656,7 +52839,7 @@ function createWorkspaceEngine(opts) {
52656
52839
  const t = Date.now();
52657
52840
  let processedTurns = 0;
52658
52841
  const elicit = isEdgeElicitationEnabled();
52659
- const handleMap = elicit ? readPrimingHandles(join22(paths.configDir, "priming-handles.json")) : {};
52842
+ const handleMap = elicit ? readPrimingHandles(join23(paths.configDir, "priming-handles.json")) : {};
52660
52843
  const wsRoot = (opts.workspaceRoot ?? "").replace(/\\/g, "/");
52661
52844
  const toRel = (abs) => {
52662
52845
  const p = abs.replace(/\\/g, "/");
@@ -53191,7 +53374,7 @@ function createWorkspaceEngine(opts) {
53191
53374
  try {
53192
53375
  const inputs = emitInputsFromManifest(paths.configDir, paths.skillsManifest);
53193
53376
  emitAndProjectSkills(opts.workspaceRoot, inputs);
53194
- writePrimingHandles(join22(paths.configDir, "priming-handles.json"), skillHandleNodes(inputs));
53377
+ writePrimingHandles(join23(paths.configDir, "priming-handles.json"), skillHandleNodes(inputs));
53195
53378
  } catch (err2) {
53196
53379
  console.warn("[skills] agent-skills projection failed (non-fatal):", err2 instanceof Error ? err2.message : err2);
53197
53380
  }
@@ -53378,7 +53561,7 @@ function createWorkspaceEngine(opts) {
53378
53561
  console.log(
53379
53562
  "[errata] sync skipped \u2014 cloud sync consent is off (enable with `errata consent sync on`)"
53380
53563
  );
53381
- const pending = existsSync18(paths.outbox) ? readdirSync8(paths.outbox).filter((f) => f.endsWith(".json")).length : 0;
53564
+ const pending = existsSync19(paths.outbox) ? readdirSync9(paths.outbox).filter((f) => f.endsWith(".json")).length : 0;
53382
53565
  return { uploaded: 0, failed: 0, remaining: pending };
53383
53566
  }
53384
53567
  try {
@@ -53465,7 +53648,7 @@ async function startDaemon(opts) {
53465
53648
  reviewUrl: () => webUiUrl + "/review"
53466
53649
  });
53467
53650
  const writeLockFile = (url2) => {
53468
- writeFileSync15(
53651
+ writeFileSync16(
53469
53652
  engine.paths.daemonLock,
53470
53653
  JSON.stringify({ pid: process.pid, webUiUrl: url2, startedAt: Date.now() }),
53471
53654
  "utf8"
@@ -53508,7 +53691,7 @@ async function startDaemon(opts) {
53508
53691
  );
53509
53692
  await engine.stop();
53510
53693
  try {
53511
- if (existsSync19(engine.paths.daemonLock)) {
53694
+ if (existsSync20(engine.paths.daemonLock)) {
53512
53695
  }
53513
53696
  } catch {
53514
53697
  }
@@ -53525,16 +53708,16 @@ async function listenServer(fetchFn, port) {
53525
53708
 
53526
53709
  // src/registry.ts
53527
53710
  init_paths();
53528
- import { existsSync as existsSync20, readFileSync as readFileSync18, writeFileSync as writeFileSync16 } from "node:fs";
53529
- import { join as join23 } from "node:path";
53711
+ import { existsSync as existsSync21, readFileSync as readFileSync19, writeFileSync as writeFileSync17 } from "node:fs";
53712
+ import { join as join24 } from "node:path";
53530
53713
  function registryPath() {
53531
- return process.env["ERRATA_REGISTRY_PATH"] ?? join23(globalDir(), "workspaces.json");
53714
+ return process.env["ERRATA_REGISTRY_PATH"] ?? join24(globalDir(), "workspaces.json");
53532
53715
  }
53533
53716
  function read() {
53534
53717
  const p = registryPath();
53535
- if (!existsSync20(p)) return { version: 1, workspaces: {} };
53718
+ if (!existsSync21(p)) return { version: 1, workspaces: {} };
53536
53719
  try {
53537
- const parsed = JSON.parse(readFileSync18(p, "utf8"));
53720
+ const parsed = JSON.parse(readFileSync19(p, "utf8"));
53538
53721
  return { version: 1, workspaces: parsed.workspaces ?? {} };
53539
53722
  } catch {
53540
53723
  return { version: 1, workspaces: {} };
@@ -53542,7 +53725,7 @@ function read() {
53542
53725
  }
53543
53726
  function write(reg) {
53544
53727
  ensureDir(globalDir());
53545
- writeFileSync16(registryPath(), JSON.stringify(reg, null, 2), "utf8");
53728
+ writeFileSync17(registryPath(), JSON.stringify(reg, null, 2), "utf8");
53546
53729
  }
53547
53730
  function registerWorkspace(profile, root, now = Date.now()) {
53548
53731
  const reg = read();
@@ -53559,7 +53742,7 @@ function pruneMissingWorkspaces() {
53559
53742
  const reg = read();
53560
53743
  const removed = [];
53561
53744
  for (const [id, entry] of Object.entries(reg.workspaces)) {
53562
- if (!existsSync20(entry.path)) {
53745
+ if (!existsSync21(entry.path)) {
53563
53746
  removed.push(entry);
53564
53747
  delete reg.workspaces[id];
53565
53748
  }
@@ -53568,13 +53751,13 @@ function pruneMissingWorkspaces() {
53568
53751
  return removed;
53569
53752
  }
53570
53753
  function workspaceStatus(entry) {
53571
- const missing = !existsSync20(entry.path);
53754
+ const missing = !existsSync21(entry.path);
53572
53755
  const lockPath = workspacePaths(entry.path).daemonLock;
53573
53756
  let running = false;
53574
53757
  let webUiUrl = null;
53575
- if (existsSync20(lockPath)) {
53758
+ if (existsSync21(lockPath)) {
53576
53759
  try {
53577
- const lock = JSON.parse(readFileSync18(lockPath, "utf8"));
53760
+ const lock = JSON.parse(readFileSync19(lockPath, "utf8"));
53578
53761
  if (lock.pid && lock.webUiUrl && pidAlive(lock.pid)) {
53579
53762
  running = true;
53580
53763
  webUiUrl = lock.webUiUrl;
@@ -53602,7 +53785,7 @@ function pidAlive(pid) {
53602
53785
  // src/multi.ts
53603
53786
  init_dist();
53604
53787
  init_src4();
53605
- import { readFileSync as readFileSync21, unlinkSync as unlinkSync3, writeFileSync as writeFileSync17 } from "node:fs";
53788
+ import { readFileSync as readFileSync22, unlinkSync as unlinkSync3, writeFileSync as writeFileSync18 } from "node:fs";
53606
53789
 
53607
53790
  // src/principle-sync.ts
53608
53791
  init_src4();
@@ -53630,8 +53813,8 @@ init_reconcile();
53630
53813
 
53631
53814
  // src/lockfile-auto.ts
53632
53815
  init_src();
53633
- import { existsSync as existsSync21, readFileSync as readFileSync19 } from "node:fs";
53634
- import { join as join24 } from "node:path";
53816
+ import { existsSync as existsSync22, readFileSync as readFileSync20 } from "node:fs";
53817
+ import { join as join25 } from "node:path";
53635
53818
 
53636
53819
  // src/package-index.ts
53637
53820
  init_src();
@@ -53777,11 +53960,11 @@ function runLockfilePass(opts) {
53777
53960
  { file: "package-lock.json", parse: parsePackageLockJson }
53778
53961
  ];
53779
53962
  for (const c of candidates) {
53780
- const p = join24(opts.root, c.file);
53781
- if (!existsSync21(p)) continue;
53963
+ const p = join25(opts.root, c.file);
53964
+ if (!existsSync22(p)) continue;
53782
53965
  let sbom;
53783
53966
  try {
53784
- sbom = c.parse(readFileSync19(p, "utf8"));
53967
+ sbom = c.parse(readFileSync20(p, "utf8"));
53785
53968
  } catch {
53786
53969
  continue;
53787
53970
  }
@@ -54224,7 +54407,7 @@ var ConsolidateWorker = class {
54224
54407
  init_paths();
54225
54408
 
54226
54409
  // src/lock.ts
54227
- import { existsSync as existsSync22, readFileSync as readFileSync20 } from "node:fs";
54410
+ import { existsSync as existsSync23, readFileSync as readFileSync21 } from "node:fs";
54228
54411
  function isProcessAlive(pid) {
54229
54412
  if (!pid || pid <= 0) return false;
54230
54413
  try {
@@ -54235,9 +54418,9 @@ function isProcessAlive(pid) {
54235
54418
  }
54236
54419
  }
54237
54420
  function readDaemonLock(lockPath) {
54238
- if (!existsSync22(lockPath)) return null;
54421
+ if (!existsSync23(lockPath)) return null;
54239
54422
  try {
54240
- const lock = JSON.parse(readFileSync20(lockPath, "utf8"));
54423
+ const lock = JSON.parse(readFileSync21(lockPath, "utf8"));
54241
54424
  return typeof lock.pid === "number" ? lock : null;
54242
54425
  } catch {
54243
54426
  return null;
@@ -54479,12 +54662,12 @@ async function reanchorProject(opts) {
54479
54662
  }
54480
54663
 
54481
54664
  // src/adopt.ts
54482
- import { existsSync as existsSync23 } from "node:fs";
54483
- import { dirname as dirname9, join as join25 } from "node:path";
54665
+ import { existsSync as existsSync24 } from "node:fs";
54666
+ import { dirname as dirname9, join as join26 } from "node:path";
54484
54667
  function findGitRoot(absPath) {
54485
54668
  let dir = absPath;
54486
54669
  for (let depth = 0; depth < 64; depth++) {
54487
- if (existsSync23(join25(dir, ".git"))) return dir;
54670
+ if (existsSync24(join26(dir, ".git"))) return dir;
54488
54671
  const parent = dirname9(dir);
54489
54672
  if (parent === dir) return null;
54490
54673
  dir = parent;
@@ -54706,7 +54889,7 @@ async function startMultiDaemon(opts = {}) {
54706
54889
  void ambientLinkAll();
54707
54890
  app.route(`/ws/${rec.id}`, rec.webApp);
54708
54891
  try {
54709
- writeFileSync17(
54892
+ writeFileSync18(
54710
54893
  rec.engine.paths.daemonLock,
54711
54894
  JSON.stringify({ pid: process.pid, webUiUrl: `${baseUrl}/ws/${rec.id}`, startedAt: Date.now() }),
54712
54895
  "utf8"
@@ -54895,7 +55078,7 @@ async function startMultiDaemon(opts = {}) {
54895
55078
  baseUrl = `http://127.0.0.1:${port}`;
54896
55079
  try {
54897
55080
  ensureDir(globalDir());
54898
- writeFileSync17(
55081
+ writeFileSync18(
54899
55082
  lockPath,
54900
55083
  JSON.stringify({ pid: process.pid, webUiUrl: baseUrl, startedAt: Date.now() }),
54901
55084
  "utf8"
@@ -54904,7 +55087,7 @@ async function startMultiDaemon(opts = {}) {
54904
55087
  }
54905
55088
  for (const r of records) {
54906
55089
  try {
54907
- writeFileSync17(
55090
+ writeFileSync18(
54908
55091
  r.engine.paths.daemonLock,
54909
55092
  JSON.stringify({ pid: process.pid, webUiUrl: `${baseUrl}/ws/${r.id}`, startedAt: Date.now() }),
54910
55093
  "utf8"
@@ -55372,7 +55555,7 @@ async function startMultiDaemon(opts = {}) {
55372
55555
  },
55373
55556
  async stop() {
55374
55557
  try {
55375
- const cur = readFileSync21(lockPath, "utf8");
55558
+ const cur = readFileSync22(lockPath, "utf8");
55376
55559
  if (JSON.parse(cur).pid === process.pid) unlinkSync3(lockPath);
55377
55560
  } catch {
55378
55561
  }
@@ -56392,21 +56575,21 @@ async function cmdInit() {
56392
56575
  if (!skipHooks) {
56393
56576
  console.log("");
56394
56577
  console.log("installing harness hooks...");
56395
- const { existsSync: existsSync25 } = await import("node:fs");
56396
- const { join: join27 } = await import("node:path");
56578
+ const { existsSync: existsSync26 } = await import("node:fs");
56579
+ const { join: join28 } = await import("node:path");
56397
56580
  try {
56398
56581
  await installClaudeHooks(port);
56399
56582
  } catch (err2) {
56400
56583
  console.warn(` \u26A0\uFE0F Claude hook install failed: ${err2 instanceof Error ? err2.message : err2}`);
56401
56584
  }
56402
- if (existsSync25(join27(ROOT, ".cursor"))) {
56585
+ if (existsSync26(join28(ROOT, ".cursor"))) {
56403
56586
  try {
56404
56587
  await installCursorMcpConfig();
56405
56588
  } catch (err2) {
56406
56589
  console.warn(` \u26A0\uFE0F Cursor MCP config failed: ${err2 instanceof Error ? err2.message : err2}`);
56407
56590
  }
56408
56591
  }
56409
- if (existsSync25(join27(ROOT, ".codex"))) {
56592
+ if (existsSync26(join28(ROOT, ".codex"))) {
56410
56593
  try {
56411
56594
  await installCodexHooks(port);
56412
56595
  } catch (err2) {
@@ -56563,8 +56746,8 @@ async function cmdStatus() {
56563
56746
  console.log(` stack: ${profile.stack.join(", ") || "(none)"}`);
56564
56747
  console.log(` languages: ${profile.languages.join(", ") || "(none)"}`);
56565
56748
  }
56566
- console.log(` graph db: ${existsSync24(paths.castalia) ? "yes" : "no"} (${paths.castalia})`);
56567
- console.log(` event log: ${existsSync24(paths.eventLog) ? "yes" : "no"} (${paths.eventLog})`);
56749
+ console.log(` graph db: ${existsSync25(paths.castalia) ? "yes" : "no"} (${paths.castalia})`);
56750
+ console.log(` event log: ${existsSync25(paths.eventLog) ? "yes" : "no"} (${paths.eventLog})`);
56568
56751
  const lockPath = globalDaemonLock();
56569
56752
  const running = isDaemonAlive(lockPath) ? readDaemonLock(lockPath) : null;
56570
56753
  console.log(
@@ -57194,11 +57377,11 @@ function cmdInstallationProfile(args2) {
57194
57377
  }
57195
57378
  async function cmdReview() {
57196
57379
  const paths = workspacePaths(ROOT);
57197
- if (!existsSync24(paths.reviewQueue)) {
57380
+ if (!existsSync25(paths.reviewQueue)) {
57198
57381
  console.log("(review queue empty)");
57199
57382
  return;
57200
57383
  }
57201
- const queue = JSON.parse(readFileSync22(paths.reviewQueue, "utf8"));
57384
+ const queue = JSON.parse(readFileSync23(paths.reviewQueue, "utf8"));
57202
57385
  if (queue.length === 0) {
57203
57386
  console.log("(review queue empty)");
57204
57387
  return;
@@ -57869,7 +58052,7 @@ async function gatherRepo(store, ws) {
57869
58052
  };
57870
58053
  }
57871
58054
  async function gatherReportData(generatedAt) {
57872
- const { existsSync: existsSync25 } = await import("node:fs");
58055
+ const { existsSync: existsSync26 } = await import("node:fs");
57873
58056
  const { openGraphStore: openGraphStore2 } = await Promise.resolve().then(() => (init_src4(), src_exports2));
57874
58057
  const cfg = loadConfig();
57875
58058
  const outbound = cfg.consent.sync ? "auto" : "off";
@@ -57877,7 +58060,7 @@ async function gatherReportData(generatedAt) {
57877
58060
  for (const ws of listWorkspaces()) {
57878
58061
  if (ws.missing) continue;
57879
58062
  const dbPath = workspacePaths(ws.path).castalia;
57880
- if (!existsSync25(dbPath)) continue;
58063
+ if (!existsSync26(dbPath)) continue;
57881
58064
  let store = null;
57882
58065
  try {
57883
58066
  store = openGraphStore2({ path: dbPath });
@@ -57908,7 +58091,7 @@ async function gatherReportData(generatedAt) {
57908
58091
  };
57909
58092
  }
57910
58093
  async function cmdReport(args2) {
57911
- const { mkdirSync: mkdirSync8, writeFileSync: writeFileSync18 } = await import("node:fs");
58094
+ const { mkdirSync: mkdirSync8, writeFileSync: writeFileSync19 } = await import("node:fs");
57912
58095
  const { renderReport: renderReport2 } = await Promise.resolve().then(() => (init_report_render(), report_render_exports));
57913
58096
  const includeFutureVerbs = args2.includes("--future-verbs");
57914
58097
  const now = /* @__PURE__ */ new Date();
@@ -57921,8 +58104,8 @@ async function cmdReport(args2) {
57921
58104
  const outDir = workspacePaths(ROOT).configDir;
57922
58105
  mkdirSync8(outDir, { recursive: true });
57923
58106
  const files = renderReport2(data, { includeFutureVerbs });
57924
- for (const f of files) writeFileSync18(join26(outDir, f.name), f.html, "utf8");
57925
- const indexPath = join26(outDir, "report.html");
58107
+ for (const f of files) writeFileSync19(join27(outDir, f.name), f.html, "utf8");
58108
+ const indexPath = join27(outDir, "report.html");
57926
58109
  console.log(`report \u2192 ${indexPath}`);
57927
58110
  console.log(
57928
58111
  ` ${data.repos.length} repo(s) \xB7 ${files.length} file(s) \xB7 ${data.rollup.nodes.toLocaleString("en-US")} nodes`
@@ -58040,15 +58223,15 @@ function hookRelayCommand(port, path2) {
58040
58223
  return process.platform === "win32" ? `cmd //c "curl -s --connect-timeout 1 --max-time 2 -X POST -H \\"Content-Type: application/json\\" --data-binary @- ${url2} 2>NUL || echo {}"` : `curl -s --connect-timeout 1 --max-time 2 -X POST -H 'Content-Type: application/json' --data-binary @- ${url2} 2>/dev/null || echo '{}'`;
58041
58224
  }
58042
58225
  async function installClaudeHooks(port) {
58043
- const { mkdirSync: mkdirSync8, existsSync: existsSync25, readFileSync: readFileSync23, writeFileSync: writeFileSync18 } = await import("node:fs");
58044
- const { join: join27 } = await import("node:path");
58045
- const dir = join27(ROOT, ".claude");
58046
- if (!existsSync25(dir)) mkdirSync8(dir, { recursive: true });
58047
- const file2 = join27(dir, "settings.json");
58226
+ const { mkdirSync: mkdirSync8, existsSync: existsSync26, readFileSync: readFileSync24, writeFileSync: writeFileSync19 } = await import("node:fs");
58227
+ const { join: join28 } = await import("node:path");
58228
+ const dir = join28(ROOT, ".claude");
58229
+ if (!existsSync26(dir)) mkdirSync8(dir, { recursive: true });
58230
+ const file2 = join28(dir, "settings.json");
58048
58231
  let settings = {};
58049
- if (existsSync25(file2)) {
58232
+ if (existsSync26(file2)) {
58050
58233
  try {
58051
- settings = JSON.parse(readFileSync23(file2, "utf8"));
58234
+ settings = JSON.parse(readFileSync24(file2, "utf8"));
58052
58235
  } catch {
58053
58236
  console.error(`refusing to overwrite invalid JSON at ${file2}`);
58054
58237
  process.exit(2);
@@ -58094,10 +58277,10 @@ async function installClaudeHooks(port) {
58094
58277
  dropErrata(list);
58095
58278
  list.push({ hooks: [{ type: "command", command: injectCmd }] });
58096
58279
  }
58097
- writeFileSync18(file2, JSON.stringify(settings, null, 2) + "\n", "utf8");
58280
+ writeFileSync19(file2, JSON.stringify(settings, null, 2) + "\n", "utf8");
58098
58281
  console.log(`installed Claude Code hooks \u2192 ${file2}`);
58099
58282
  await installClaudeMcpConfig();
58100
- const claudeMd = join27(ROOT, "CLAUDE.md");
58283
+ const claudeMd = join28(ROOT, "CLAUDE.md");
58101
58284
  const recall = writeManagedBlock(claudeMd, { body: RECALL_FIRST_BLOCK });
58102
58285
  if (recall.kind === "collision") {
58103
58286
  console.warn(
@@ -58109,15 +58292,15 @@ async function installClaudeHooks(port) {
58109
58292
  console.log(` endpoint: http://127.0.0.1:${port}/api/hook`);
58110
58293
  }
58111
58294
  async function installClaudeMcpConfig() {
58112
- const { mkdirSync: mkdirSync8, existsSync: existsSync25, readFileSync: readFileSync23, writeFileSync: writeFileSync18 } = await import("node:fs");
58113
- const { join: join27, dirname: dirname10 } = await import("node:path");
58114
- const file2 = join27(ROOT, ".mcp.json");
58295
+ const { mkdirSync: mkdirSync8, existsSync: existsSync26, readFileSync: readFileSync24, writeFileSync: writeFileSync19 } = await import("node:fs");
58296
+ const { join: join28, dirname: dirname10 } = await import("node:path");
58297
+ const file2 = join28(ROOT, ".mcp.json");
58115
58298
  const dir = dirname10(file2);
58116
- if (!existsSync25(dir)) mkdirSync8(dir, { recursive: true });
58299
+ if (!existsSync26(dir)) mkdirSync8(dir, { recursive: true });
58117
58300
  let cfg = {};
58118
- if (existsSync25(file2)) {
58301
+ if (existsSync26(file2)) {
58119
58302
  try {
58120
- cfg = JSON.parse(readFileSync23(file2, "utf8"));
58303
+ cfg = JSON.parse(readFileSync24(file2, "utf8"));
58121
58304
  } catch {
58122
58305
  console.error(`refusing to overwrite invalid JSON at ${file2}`);
58123
58306
  process.exit(2);
@@ -58125,21 +58308,21 @@ async function installClaudeMcpConfig() {
58125
58308
  }
58126
58309
  cfg.mcpServers ??= {};
58127
58310
  cfg.mcpServers["errata"] = errataMcpInvocation();
58128
- writeFileSync18(file2, JSON.stringify(cfg, null, 2) + "\n", "utf8");
58311
+ writeFileSync19(file2, JSON.stringify(cfg, null, 2) + "\n", "utf8");
58129
58312
  console.log(`installed Claude Code MCP server config \u2192 ${file2}`);
58130
58313
  console.log(` Claude Code will spawn \`errata mcp\` on workspace open.`);
58131
58314
  console.log(` Tools: errata.search / locate / neighbors / callers_of / what_uses / show / similar`);
58132
58315
  }
58133
58316
  async function installCursorMcpConfig() {
58134
- const { mkdirSync: mkdirSync8, existsSync: existsSync25, readFileSync: readFileSync23, writeFileSync: writeFileSync18 } = await import("node:fs");
58135
- const { join: join27 } = await import("node:path");
58136
- const dir = join27(ROOT, ".cursor");
58137
- if (!existsSync25(dir)) mkdirSync8(dir, { recursive: true });
58138
- const file2 = join27(dir, "mcp.json");
58317
+ const { mkdirSync: mkdirSync8, existsSync: existsSync26, readFileSync: readFileSync24, writeFileSync: writeFileSync19 } = await import("node:fs");
58318
+ const { join: join28 } = await import("node:path");
58319
+ const dir = join28(ROOT, ".cursor");
58320
+ if (!existsSync26(dir)) mkdirSync8(dir, { recursive: true });
58321
+ const file2 = join28(dir, "mcp.json");
58139
58322
  let cfg = {};
58140
- if (existsSync25(file2)) {
58323
+ if (existsSync26(file2)) {
58141
58324
  try {
58142
- cfg = JSON.parse(readFileSync23(file2, "utf8"));
58325
+ cfg = JSON.parse(readFileSync24(file2, "utf8"));
58143
58326
  } catch {
58144
58327
  console.error(`refusing to overwrite invalid JSON at ${file2}`);
58145
58328
  process.exit(2);
@@ -58147,7 +58330,7 @@ async function installCursorMcpConfig() {
58147
58330
  }
58148
58331
  cfg.mcpServers ??= {};
58149
58332
  cfg.mcpServers["errata"] = errataMcpInvocation();
58150
- writeFileSync18(file2, JSON.stringify(cfg, null, 2) + "\n", "utf8");
58333
+ writeFileSync19(file2, JSON.stringify(cfg, null, 2) + "\n", "utf8");
58151
58334
  console.log(`installed Cursor MCP server config \u2192 ${file2}`);
58152
58335
  console.log(` Cursor will spawn \`errata mcp\` on workspace open.`);
58153
58336
  console.log(` Tools: errata.search / locate / neighbors / callers_of / what_uses`);
@@ -58155,16 +58338,16 @@ async function installCursorMcpConfig() {
58155
58338
  console.log(` \u26A0\uFE0F reload Cursor (Cmd/Ctrl-Shift-P \u2192 "Reload Window") to pick it up.`);
58156
58339
  }
58157
58340
  async function installCodexHooks(port) {
58158
- const { mkdirSync: mkdirSync8, existsSync: existsSync25, readFileSync: readFileSync23, writeFileSync: writeFileSync18 } = await import("node:fs");
58159
- const { join: join27 } = await import("node:path");
58160
- const dir = join27(ROOT, ".codex");
58161
- if (!existsSync25(dir)) mkdirSync8(dir, { recursive: true });
58162
- const file2 = join27(dir, "config.toml");
58341
+ const { mkdirSync: mkdirSync8, existsSync: existsSync26, readFileSync: readFileSync24, writeFileSync: writeFileSync19 } = await import("node:fs");
58342
+ const { join: join28 } = await import("node:path");
58343
+ const dir = join28(ROOT, ".codex");
58344
+ if (!existsSync26(dir)) mkdirSync8(dir, { recursive: true });
58345
+ const file2 = join28(dir, "config.toml");
58163
58346
  const BEGIN = `# >>> errata hooks (errata-managed)`;
58164
58347
  const END = `# <<< errata hooks`;
58165
58348
  let existing = "";
58166
- if (existsSync25(file2)) {
58167
- existing = readFileSync23(file2, "utf8");
58349
+ if (existsSync26(file2)) {
58350
+ existing = readFileSync24(file2, "utf8");
58168
58351
  const beginIdx = existing.indexOf(BEGIN);
58169
58352
  const endIdx = existing.indexOf(END);
58170
58353
  if (beginIdx >= 0 && endIdx > beginIdx) {
@@ -58193,7 +58376,7 @@ ${END}
58193
58376
  const final = existing.length > 0 && !existing.endsWith("\n") ? `${existing}
58194
58377
 
58195
58378
  ${block}` : existing + (existing.endsWith("\n\n") ? "" : "\n") + block;
58196
- writeFileSync18(file2, final, "utf8");
58379
+ writeFileSync19(file2, final, "utf8");
58197
58380
  console.log(`installed Codex hooks \u2192 ${file2}`);
58198
58381
  console.log(` endpoint: http://127.0.0.1:${port}/api/hook`);
58199
58382
  console.log("");
@@ -58483,7 +58666,7 @@ async function cmdDash(args2) {
58483
58666
  await yieldToLoop2();
58484
58667
  try {
58485
58668
  const items = selectDurableMemory(handle2.sharedStore, r.engine.profile);
58486
- const res = bleedRules(join26(r.root, ".claude", "rules"), items);
58669
+ const res = bleedRules(join27(r.root, ".claude", "rules"), items);
58487
58670
  if (res.written || res.pruned) {
58488
58671
  console.log(
58489
58672
  `[rules:${r.entry.name}] ${res.written} collective principle(s) \u2192 .claude/rules` + (res.pruned ? `, ${res.pruned} pruned` : "")
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inerrata-corporation/errata",
3
- "version": "2.0.2-dev.196",
3
+ "version": "2.0.2-dev.204",
4
4
  "description": "errata - local-first observation engine for AI coding agents",
5
5
  "type": "module",
6
6
  "bin": {
package/pass-worker.mjs CHANGED
@@ -26106,10 +26106,13 @@ function buildSnapshot(opts) {
26106
26106
  episodeId,
26107
26107
  problems: problems2
26108
26108
  }));
26109
- const needsRevisit = listNeedsRevisit(
26110
- opts.store,
26111
- (opts.now ?? /* @__PURE__ */ new Date()).getTime()
26112
- ).slice(0, 10);
26109
+ const revisitSeen = /* @__PURE__ */ new Set();
26110
+ const needsRevisit = listNeedsRevisit(opts.store, (opts.now ?? /* @__PURE__ */ new Date()).getTime()).filter((r) => {
26111
+ const key = `${r.label}:${r.description.trim().toLowerCase()}`;
26112
+ if (revisitSeen.has(key)) return false;
26113
+ revisitSeen.add(key);
26114
+ return true;
26115
+ }).slice(0, 5);
26113
26116
  const norm = (x) => x.toLowerCase().replace(/[^a-z0-9]+/g, "");
26114
26117
  const pkgBase = (x) => {
26115
26118
  const at = x.lastIndexOf("@");