@inerrata-corporation/errata 2.0.22-dev.4148 → 2.0.22-dev.4164

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
@@ -94,7 +94,7 @@ function toCloudAttrs(attrs) {
94
94
  }
95
95
  return rest2;
96
96
  }
97
- var SEMANTIC_NODE_LABELS, ANCHOR_REFUSAL_REASONS, ROUTING_REASONS, CONTEXT_NODE_LABELS, CODE_NODE_LABELS, ALL_NODE_LABELS, STRUCTURAL_EDGES, CAUSAL_EDGES, RESOLUTION_EDGES, CONCEPTUAL_EDGES, EVIDENCE_EDGES, CODE_EDGES, BRIDGE_EDGES, IDENTITY_EDGES, JUSTIFICATION_EDGES, BELIEF_EDGES, ABSTRACTION_EDGES, DECOMPOSITION_EDGES, TRANSFER_EDGES, SOLUTION_STRUCTURE_EDGES, SUSPICION_EDGES, TAXONOMY_EDGES, TRIAGE_EDGES, GIT_EDGES, ALL_EDGE_TYPES, PAGERANK_EXCLUSIONS, EDGE_WEIGHT, EDGE_CONDUCTANCE_OVERRIDES, CAUSAL_PROTECT_EDGES, VALIDATION_SOURCES, TRUTH_KIND, ABSTRACTION_LEVEL, PROBLEM_RESOLUTION, DRIFT_KIND, TEST_PATH_RE, TEST_SCOPE_RE;
97
+ var SEMANTIC_NODE_LABELS, ANCHOR_REFUSAL_REASONS, ROUTING_REASONS, CONTEXT_NODE_LABELS, CODE_NODE_LABELS, ALL_NODE_LABELS, STRUCTURAL_EDGES, CAUSAL_EDGES, RESOLUTION_EDGES, CONCEPTUAL_EDGES, EVIDENCE_EDGES, CODE_EDGES, BRIDGE_EDGES, IDENTITY_EDGES, JUSTIFICATION_EDGES, BELIEF_EDGES, ABSTRACTION_EDGES, DECOMPOSITION_EDGES, TRANSFER_EDGES, PROJECT_SYNC_EDGE_TYPES, SOLUTION_STRUCTURE_EDGES, SUSPICION_EDGES, TAXONOMY_EDGES, TRIAGE_EDGES, GIT_EDGES, ALL_EDGE_TYPES, PAGERANK_EXCLUSIONS, EDGE_WEIGHT, EDGE_CONDUCTANCE_OVERRIDES, CAUSAL_PROTECT_EDGES, VALIDATION_SOURCES, TRUTH_KIND, ABSTRACTION_LEVEL, PROBLEM_RESOLUTION, DRIFT_KIND, TEST_PATH_RE, TEST_SCOPE_RE;
98
98
  var init_castalia = __esm({
99
99
  "../../packages/shared/src/castalia.ts"() {
100
100
  "use strict";
@@ -321,6 +321,7 @@ var init_castalia = __esm({
321
321
  ABSTRACTION_EDGES = ["GENERALIZES", "DERIVED_FROM"];
322
322
  DECOMPOSITION_EDGES = ["SPLIT_INTO"];
323
323
  TRANSFER_EDGES = ["MAY_RESOLVE"];
324
+ PROJECT_SYNC_EDGE_TYPES = ["SOLVED_BY", "CAUSED_BY", "FIXED_BY", "MAY_RESOLVE"];
324
325
  SOLUTION_STRUCTURE_EDGES = ["BUILDS_ON", "SUPERSEDES", "ALTERNATIVE_TO"];
325
326
  SUSPICION_EDGES = ["SUSPECTED_LINK", "REGRESSION_OF"];
326
327
  TAXONOMY_EDGES = ["IS_A"];
@@ -17625,6 +17626,7 @@ __export(src_exports, {
17625
17626
  PROBLEM_RESOLUTION: () => PROBLEM_RESOLUTION,
17626
17627
  PROJECT_ONLY_EDGE_TYPES: () => PROJECT_ONLY_EDGE_TYPES,
17627
17628
  PROJECT_ONLY_NODE_LABELS: () => PROJECT_ONLY_NODE_LABELS,
17629
+ PROJECT_SYNC_EDGE_TYPES: () => PROJECT_SYNC_EDGE_TYPES,
17628
17630
  QUARANTINE_EXTRACTION_SOURCE_PREFIX: () => QUARANTINE_EXTRACTION_SOURCE_PREFIX,
17629
17631
  REDACTED_CREDENTIAL: () => REDACTED_CREDENTIAL,
17630
17632
  REDACTED_EMAIL: () => REDACTED_EMAIL,
@@ -21452,6 +21454,20 @@ CREATE INDEX IF NOT EXISTS nodes_revisit_true ON nodes(valid_from) WHERE json_ty
21452
21454
  if (revived > 0) this.mutations++;
21453
21455
  return revived;
21454
21456
  }
21457
+ incomingEdgeCoverage(label, edgeTypes, cloudOnly) {
21458
+ if (edgeTypes.length === 0) return { count: 0, total: 0 };
21459
+ const r = this.db.prepare(
21460
+ `SELECT COUNT(*) AS total,
21461
+ COALESCE(SUM(CASE WHEN EXISTS (
21462
+ SELECT 1 FROM edges e WHERE e.to_id = n.id AND e.valid_to IS NULL
21463
+ AND e.type IN (${edgeTypes.map(() => "?").join(",")})
21464
+ ) THEN 1 ELSE 0 END), 0) AS count
21465
+ FROM nodes n
21466
+ WHERE n.label = ? AND n.valid_to IS NULL
21467
+ AND (? = 0 OR json_extract(n.attrs_json, '$.source') = 'cloud')`
21468
+ ).get(...edgeTypes, label, cloudOnly ? 1 : 0);
21469
+ return { count: Number(r.count), total: Number(r.total) };
21470
+ }
21455
21471
  recentEdgeAttrCoverage(marker, attr, limit) {
21456
21472
  const r = this.db.prepare(
21457
21473
  `SELECT COUNT(*) AS total,
@@ -26337,6 +26353,14 @@ var init_principle_sync = __esm({
26337
26353
 
26338
26354
  // ../../packages/local-graph/src/mechanism-liveness.ts
26339
26355
  function evaluateFed(store, d) {
26356
+ if (d.fedIncoming) {
26357
+ const { count: count2, total } = store.incomingEdgeCoverage?.(
26358
+ d.fedIncoming.label,
26359
+ d.fedIncoming.edgeTypes,
26360
+ d.fedIncoming.cloudOnly
26361
+ ) ?? { count: 0, total: 0 };
26362
+ return { count: count2, total, fraction: total === 0 ? 0 : count2 / total };
26363
+ }
26340
26364
  if (d.fedEdges) {
26341
26365
  const { count: count2, total } = store.recentEdgeAttrCoverage(
26342
26366
  d.fedEdges.marker,
@@ -26388,7 +26412,7 @@ function evaluateMechanisms(store, invocations = /* @__PURE__ */ new Map(), mech
26388
26412
  if (d.configCounter && inv?.lastTotals?.[d.configCounter] === 0) verdict = "unconfigured";
26389
26413
  else if ((backlog ?? 0) === 0 && (!hasInput && !d.inputOptional || missingRequiredNodes)) verdict = "no-input";
26390
26414
  else if (!inv || inv.runs === 0) verdict = "never-invoked";
26391
- else if (fed.fraction < (d.fedEdges?.minFraction ?? d.fed?.minFraction ?? 0)) verdict = "starved";
26415
+ else if (fed.fraction < minFractionOf(d)) verdict = "starved";
26392
26416
  else if (stalled) verdict = "stalled";
26393
26417
  else if (effectCount === 0) verdict = "no-effect";
26394
26418
  else verdict = "ok";
@@ -26399,7 +26423,7 @@ function evaluateMechanisms(store, invocations = /* @__PURE__ */ new Map(), mech
26399
26423
  fedCount: fed.count,
26400
26424
  fedTotal: fed.total,
26401
26425
  fedFraction: fed.fraction,
26402
- minFraction: d.fedEdges?.minFraction ?? d.fed?.minFraction ?? 0,
26426
+ minFraction: minFractionOf(d),
26403
26427
  ...inv ? { lastInvokedMs: inv.lastTs } : {},
26404
26428
  runs: inv?.runs ?? 0,
26405
26429
  effectCount,
@@ -26411,6 +26435,9 @@ function evaluateMechanisms(store, invocations = /* @__PURE__ */ new Map(), mech
26411
26435
  };
26412
26436
  });
26413
26437
  }
26438
+ function minFractionOf(d) {
26439
+ return d.fedIncoming?.minFraction ?? d.fedEdges?.minFraction ?? d.fed?.minFraction ?? 0;
26440
+ }
26414
26441
  function formatMechanismStatus(rows, nowMs) {
26415
26442
  return rows.map((r) => {
26416
26443
  const pct = (r.fedFraction * 100).toFixed(r.fedFraction < 0.01 ? 2 : 1);
@@ -26697,6 +26724,25 @@ var init_mechanism_liveness = __esm({
26697
26724
  // reading is IDLE — correct, and it declares no backlog on purpose.
26698
26725
  effectCounter: "alarms",
26699
26726
  note: "steady-state IDLE is healthy; the row exists for its invocation age"
26727
+ },
26728
+ {
26729
+ id: "project-causal-sync",
26730
+ what: "lands the cloud project stratum's SOLVED_BY/FIXED_BY edges onto the knowledge the anchor feed mirrors",
26731
+ // PRODUCER: the anchor feed's causal leg — `fetchProjectAnchors` returns the
26732
+ // edges, `syncProjectAnchors` (apps/daemon/src/project-reanchor.ts) lands or
26733
+ // parks them, on the `anchor-pull` beat. CONSUMERS: every local walk that
26734
+ // crosses Problem→Solution — errata_trace/why/burst over the store, and the
26735
+ // passive priming block that renders a problem with its fix. Before
26736
+ // PJ-sync-causal the feed mirrored 5,054 cloud Solutions on the dev checkout
26737
+ // with not one incoming SOLVED_BY: this row would have read 0.0% for months.
26738
+ pass: "anchor-pull",
26739
+ fedIncoming: { label: "Solution", edgeTypes: ["SOLVED_BY", "FIXED_BY"], cloudOnly: true, minFraction: 0.5 },
26740
+ effectCounter: "edgesLanded",
26741
+ // Parked edges waiting on an endpoint — a flat, non-zero backlog is a stratum
26742
+ // whose other ends never arrive here (a cap, or a gate that refuses them).
26743
+ backlogCounter: "edgesPending",
26744
+ requiresNodes: ["Problem"],
26745
+ note: "an orphaned cloud Solution reads as a fix with no problem; the one-time causal re-walk lifts this after the server ships the leg"
26700
26746
  }
26701
26747
  ];
26702
26748
  COLUMN_INPUTS = {
@@ -28994,7 +29040,7 @@ var init_client = __esm({
28994
29040
  "GET",
28995
29041
  `/v2/projects/${encodeURIComponent(projectId)}/anchors?since=${String(Math.max(0, Math.floor(since)))}&limit=${String(limit)}`
28996
29042
  );
28997
- const { nodes } = this.toCastalia({ nodes: res.nodes ?? [], edges: [] });
29043
+ const { nodes, edges } = this.toCastalia({ nodes: res.nodes ?? [], edges: res.edges ?? [] });
28998
29044
  const anchors = (res.anchors ?? []).map((a) => ({
28999
29045
  from: a.fromCanonicalId,
29000
29046
  toSymbolId: a.toSymbolId,
@@ -29002,7 +29048,7 @@ var init_client = __esm({
29002
29048
  attrs: a.attrs ?? {},
29003
29049
  stampedAt: typeof a.stampedAt === "number" ? a.stampedAt : 0
29004
29050
  }));
29005
- return { nodes, anchors, cursor: typeof res.cursor === "number" ? res.cursor : since };
29051
+ return { nodes, edges, causalLeg: Array.isArray(res.edges), anchors, cursor: typeof res.cursor === "number" ? res.cursor : since };
29006
29052
  }
29007
29053
  /** Pull cloud-induced skills + the session-bootstrap prime payload. `seed` is the
29008
29054
  * canonical ids of the agent's recent problems — the cloud ranks the skills whose
@@ -76377,8 +76423,8 @@ var init_report_render = __esm({
76377
76423
 
76378
76424
  // src/cli.ts
76379
76425
  init_src6();
76380
- import { closeSync as closeSync3, existsSync as existsSync40, openSync as openSync3, readFileSync as readFileSync42, renameSync as renameSync7, statSync as statSync13 } from "node:fs";
76381
- import { join as join49, resolve as pathResolve2 } from "node:path";
76426
+ import { closeSync as closeSync3, existsSync as existsSync40, openSync as openSync3, readFileSync as readFileSync43, renameSync as renameSync8, statSync as statSync13 } from "node:fs";
76427
+ import { join as join50, resolve as pathResolve2 } from "node:path";
76382
76428
  import { spawn as spawn5 } from "node:child_process";
76383
76429
 
76384
76430
  // src/daemon.ts
@@ -77843,9 +77889,9 @@ var NodeFsHandler = class {
77843
77889
  if (this.fsw.closed) {
77844
77890
  return;
77845
77891
  }
77846
- const dirname17 = sysPath.dirname(file2);
77892
+ const dirname18 = sysPath.dirname(file2);
77847
77893
  const basename10 = sysPath.basename(file2);
77848
- const parent = this.fsw._getWatchedDir(dirname17);
77894
+ const parent = this.fsw._getWatchedDir(dirname18);
77849
77895
  let prevStats = stats;
77850
77896
  if (parent.has(basename10))
77851
77897
  return;
@@ -77872,7 +77918,7 @@ var NodeFsHandler = class {
77872
77918
  prevStats = newStats2;
77873
77919
  }
77874
77920
  } catch (error48) {
77875
- this.fsw._remove(dirname17, basename10);
77921
+ this.fsw._remove(dirname18, basename10);
77876
77922
  }
77877
77923
  } else if (parent.has(basename10)) {
77878
77924
  const at = newStats.atimeMs;
@@ -85786,7 +85832,7 @@ function createWatchBreaker(deps) {
85786
85832
  }
85787
85833
 
85788
85834
  // src/engine.ts
85789
- var DAEMON_VERSION = true ? "2.0.22-dev.4148" : "2.0.0-alpha.0";
85835
+ var DAEMON_VERSION = true ? "2.0.22-dev.4164" : "2.0.0-alpha.0";
85790
85836
  var IGNORED_PATH = /[\\/](?:\.git|node_modules|\.errata|\.claude|\.codex|\.cursor|\.turbo|\.next|dist|coverage|test-results|playwright-report|__pycache__)(?:[\\/]|$)/;
85791
85837
  var IGNORED_NOISE = /castalia\.db|eventlog\.sqlite|turn-cursors/;
85792
85838
  var GIT_OP_MUTE_MS = 4e3;
@@ -88912,7 +88958,7 @@ function invalidateInstanceReceipt(current, destination, failedId, mirrorLegacy)
88912
88958
  // src/multi.ts
88913
88959
  init_dist();
88914
88960
  init_src5();
88915
- import { existsSync as existsSync34, writeFileSync as writeFileSync26 } from "node:fs";
88961
+ import { existsSync as existsSync34, writeFileSync as writeFileSync27 } from "node:fs";
88916
88962
  import { resolve as pathResolve } from "node:path";
88917
88963
 
88918
88964
  // src/principle-sync.ts
@@ -90402,7 +90448,6 @@ function liveCloudClient(src) {
90402
90448
  init_identity2();
90403
90449
 
90404
90450
  // src/project-hydrate.ts
90405
- init_src11();
90406
90451
  init_profile2();
90407
90452
 
90408
90453
  // src/project-reanchor.ts
@@ -90477,6 +90522,62 @@ async function syncHistoryCorrections(opts) {
90477
90522
  }
90478
90523
  }
90479
90524
 
90525
+ // src/project-reanchor.ts
90526
+ init_paths();
90527
+
90528
+ // src/project-sync-landing.ts
90529
+ init_src11();
90530
+ function landCloudNode(store, n, isOwnTwin) {
90531
+ if (store.getNode(n.id)) return "present";
90532
+ if (isOwnTwin) return "own";
90533
+ store.mergeNode(n);
90534
+ return "landed";
90535
+ }
90536
+ function landCloudEdge(store, e, from, to) {
90537
+ if (store.outEdges(from, [e.type]).some((x) => x.to === to)) return false;
90538
+ const id = from === e.from && to === e.to ? e.id : edgeId(from, e.type, to);
90539
+ if (store.getEdge(id)) return false;
90540
+ store.mergeEdge({ ...e, id, from, to, attrs: { ...e.attrs, source: "cloud" } });
90541
+ return true;
90542
+ }
90543
+
90544
+ // src/causal-edge-queue.ts
90545
+ import { readFileSync as readFileSync35, renameSync as renameSync5, writeFileSync as writeFileSync25 } from "node:fs";
90546
+ import { dirname as dirname13, join as join39 } from "node:path";
90547
+ var CAUSAL_EDGE_QUEUE_CAP = 5e3;
90548
+ var CAUSAL_EDGE_TTL_MS = 30 * 24 * 60 * 60 * 1e3;
90549
+ function causalEdgeQueuePath(workspaceConfigDir) {
90550
+ return join39(workspaceConfigDir, "causal-edge-queue.json");
90551
+ }
90552
+ function parkedEdgeKey(e) {
90553
+ return `${e.from}|${e.type}|${e.to}`;
90554
+ }
90555
+ function loadCausalEdgeQueue(path3) {
90556
+ let raw2;
90557
+ try {
90558
+ raw2 = JSON.parse(readFileSync35(path3, "utf8"));
90559
+ } catch {
90560
+ return [];
90561
+ }
90562
+ if (!Array.isArray(raw2)) return [];
90563
+ return raw2.filter(
90564
+ (p) => !!p && typeof p === "object" && typeof p.ts === "number" && typeof p.edge?.from === "string" && typeof p.edge?.to === "string" && typeof p.edge?.type === "string"
90565
+ );
90566
+ }
90567
+ function saveCausalEdgeQueue(path3, queue) {
90568
+ try {
90569
+ const tmp = join39(dirname13(path3), `.${Date.now()}.causal-edge-queue.tmp`);
90570
+ writeFileSync25(tmp, JSON.stringify(queue), "utf8");
90571
+ renameSync5(tmp, path3);
90572
+ } catch {
90573
+ }
90574
+ }
90575
+ function pruneCausalEdgeQueue(queue, now) {
90576
+ const live3 = queue.filter((p) => now - p.ts < CAUSAL_EDGE_TTL_MS);
90577
+ if (live3.length <= CAUSAL_EDGE_QUEUE_CAP) return live3;
90578
+ return [...live3].sort((a, b) => a.ts - b.ts).slice(live3.length - CAUSAL_EDGE_QUEUE_CAP);
90579
+ }
90580
+
90480
90581
  // src/project-reanchor.ts
90481
90582
  var DEFAULT_LIMIT = 50;
90482
90583
  var ANCHOR_SYMBOL_KINDS2 = [
@@ -90676,10 +90777,12 @@ async function reanchorProject(opts) {
90676
90777
  }
90677
90778
  var SYNC_PAGE = 200;
90678
90779
  var SYNC_MAX_PAGES = 25;
90780
+ var SYNC_EDGE_TYPES = new Set(PROJECT_SYNC_EDGE_TYPES);
90679
90781
  async function syncProjectAnchors(opts) {
90680
90782
  const { root, profile, store, cloud, salt } = opts;
90681
90783
  if (!profile.projectId) return { synced: false, reason: "no-project" };
90682
90784
  const projectId = profile.projectId;
90785
+ const clock = opts.now ?? Date.now;
90683
90786
  const key = `${projectId}|${salt}`;
90684
90787
  const reverse = cachedMap(
90685
90788
  reverseCache,
@@ -90688,23 +90791,95 @@ async function syncProjectAnchors(opts) {
90688
90791
  () => buildReverseSymbolMap({ store, salt, projectId })
90689
90792
  );
90690
90793
  const own = cachedMap(ownCache, store, salt, () => collectLastWinsYielding(ownKnowledgeEntries({ store, salt })));
90794
+ const resolveKnowledge = async (id) => store.getNode(id) ? id : lookupLive(store, own, id);
90795
+ const queuePath = opts.edgeQueuePath ?? causalEdgeQueuePath(workspacePaths(root).configDir);
90796
+ let parked = pruneCausalEdgeQueue(loadCausalEdgeQueue(queuePath), clock());
90797
+ let parkedDirty = false;
90798
+ const parkedKeys = new Set(parked.map((p) => parkedEdgeKey(p.edge)));
90691
90799
  const limit = opts.limit ?? SYNC_PAGE;
90692
90800
  const maxPages = opts.maxPages ?? SYNC_MAX_PAGES;
90693
90801
  let anchors = 0;
90694
90802
  let updated = 0;
90695
90803
  let dropped = 0;
90696
90804
  let landed = 0;
90697
- let cursor = profile.projectAnchorCursor ?? 0;
90805
+ let edgesLanded = 0;
90806
+ let edgesParked = 0;
90807
+ let edgesReplayed = 0;
90808
+ let persistedCursor = 0;
90809
+ let cursor = 0;
90810
+ let backfillPending = false;
90811
+ let backfillStarted = false;
90812
+ const settleEdges = async (incoming) => {
90813
+ for (const e of incoming) {
90814
+ if (!SYNC_EDGE_TYPES.has(e.type)) continue;
90815
+ const from = await resolveKnowledge(e.from);
90816
+ const to = from ? await resolveKnowledge(e.to) : null;
90817
+ const k = parkedEdgeKey(e);
90818
+ if (from && to) {
90819
+ if (from !== to && landCloudEdge(store, e, from, to)) edgesLanded++;
90820
+ if (parkedKeys.delete(k)) {
90821
+ parked = parked.filter((p) => parkedEdgeKey(p.edge) !== k);
90822
+ parkedDirty = true;
90823
+ }
90824
+ } else if (!parkedKeys.has(k)) {
90825
+ parkedKeys.add(k);
90826
+ parked.push({ edge: e, ts: clock() });
90827
+ parkedDirty = true;
90828
+ edgesParked++;
90829
+ }
90830
+ }
90831
+ if (parked.length === 0) return;
90832
+ const still = [];
90833
+ for (const p of parked) {
90834
+ const from = await resolveKnowledge(p.edge.from);
90835
+ const to = from ? await resolveKnowledge(p.edge.to) : null;
90836
+ if (from && to) {
90837
+ if (from !== to && landCloudEdge(store, p.edge, from, to)) edgesReplayed++;
90838
+ parkedKeys.delete(parkedEdgeKey(p.edge));
90839
+ parkedDirty = true;
90840
+ } else {
90841
+ still.push(p);
90842
+ }
90843
+ }
90844
+ parked = still;
90845
+ };
90846
+ const flushParked = () => {
90847
+ if (!parkedDirty) return;
90848
+ parked = pruneCausalEdgeQueue(parked, clock());
90849
+ saveCausalEdgeQueue(queuePath, parked);
90850
+ parkedDirty = false;
90851
+ };
90698
90852
  try {
90699
90853
  await syncHistoryCorrections({ root, profile, store, cloud, ...opts.correctionMirrors ? { mirrors: opts.correctionMirrors } : {} });
90854
+ persistedCursor = profile.projectAnchorCursor ?? 0;
90855
+ backfillPending = !profile.projectCausalBackfillAt;
90856
+ cursor = backfillPending ? 0 : persistedCursor;
90700
90857
  for (let page = 0; page < maxPages; page++) {
90858
+ if (page > 0) await new Promise((r) => setImmediate(r));
90701
90859
  const res = await cloud.getProjectAnchors(projectId, cursor, limit);
90860
+ if (backfillPending) {
90861
+ backfillPending = false;
90862
+ if (res.causalLeg) {
90863
+ profile.projectCausalBackfillAt = clock();
90864
+ profile.projectAnchorCursor = 0;
90865
+ saveProfile(root, profile);
90866
+ backfillStarted = persistedCursor > 0;
90867
+ } else if (cursor !== persistedCursor) {
90868
+ cursor = persistedCursor;
90869
+ page--;
90870
+ continue;
90871
+ }
90872
+ }
90702
90873
  if (res.anchors.length === 0) break;
90703
90874
  if ((await reverse.get()).size === 0 && (await reverse.refresh()).size === 0) {
90704
90875
  return { synced: false, reason: "no-local-symbols" };
90705
90876
  }
90706
- const byId = new Map(res.nodes.map((n) => [n.id, n]));
90707
- const now = Date.now();
90877
+ for (const node2 of res.nodes) {
90878
+ if (store.getNode(node2.id)) continue;
90879
+ const ownTwin = await lookupLive(store, own, node2.id) !== null;
90880
+ if (landCloudNode(store, node2, ownTwin) === "landed") landed++;
90881
+ }
90882
+ const now = clock();
90708
90883
  for (const a of res.anchors) {
90709
90884
  if (a.type !== "ANCHORED_AT") continue;
90710
90885
  const localTo = await lookupLive(store, reverse, a.toSymbolId);
@@ -90712,16 +90887,10 @@ async function syncProjectAnchors(opts) {
90712
90887
  dropped++;
90713
90888
  continue;
90714
90889
  }
90715
- let from = store.getNode(a.from) ? a.from : await lookupLive(store, own, a.from);
90890
+ const from = await resolveKnowledge(a.from);
90716
90891
  if (!from) {
90717
- const node2 = byId.get(a.from);
90718
- if (!node2) {
90719
- dropped++;
90720
- continue;
90721
- }
90722
- store.mergeNode(node2);
90723
- landed++;
90724
- from = node2.id;
90892
+ dropped++;
90893
+ continue;
90725
90894
  }
90726
90895
  const existing = existingAnchor(store, from, localTo);
90727
90896
  const id = existing?.id ?? edgeId(from, "ANCHORED_AT", localTo);
@@ -90753,6 +90922,8 @@ async function syncProjectAnchors(opts) {
90753
90922
  if (existing) updated++;
90754
90923
  else anchors++;
90755
90924
  }
90925
+ await settleEdges(res.edges ?? []);
90926
+ flushParked();
90756
90927
  const next = typeof res.cursor === "number" && res.cursor > cursor ? res.cursor : cursor;
90757
90928
  if (next !== cursor) {
90758
90929
  cursor = next;
@@ -90761,8 +90932,23 @@ async function syncProjectAnchors(opts) {
90761
90932
  }
90762
90933
  if (res.anchors.length < limit) break;
90763
90934
  }
90764
- return { synced: true, anchors, updated, dropped, landed, cursor };
90935
+ await settleEdges([]);
90936
+ flushParked();
90937
+ return {
90938
+ synced: true,
90939
+ anchors,
90940
+ updated,
90941
+ dropped,
90942
+ landed,
90943
+ cursor,
90944
+ edgesLanded,
90945
+ edgesParked,
90946
+ edgesReplayed,
90947
+ edgesPending: parked.length,
90948
+ backfillStarted
90949
+ };
90765
90950
  } catch (err2) {
90951
+ flushParked();
90766
90952
  return { synced: false, reason: "error", detail: err2 instanceof Error ? err2.message : String(err2) };
90767
90953
  }
90768
90954
  }
@@ -90780,24 +90966,16 @@ async function hydrateProject(opts) {
90780
90966
  let landedNodes = 0;
90781
90967
  let ownNodes = 0;
90782
90968
  for (const n of res.nodes) {
90783
- if (store.getNode(n.id)) continue;
90784
- if (own.has(n.id)) {
90785
- ownNodes++;
90786
- continue;
90787
- }
90788
- store.mergeNode(n);
90789
- landedNodes++;
90969
+ const landing = landCloudNode(store, n, own.has(n.id));
90970
+ if (landing === "own") ownNodes++;
90971
+ else if (landing === "landed") landedNodes++;
90790
90972
  }
90791
90973
  let landedEdges = 0;
90792
90974
  for (const e of res.edges) {
90793
90975
  const from = localId(e.from);
90794
90976
  const to = localId(e.to);
90795
90977
  if (!from || !to) continue;
90796
- if (store.outEdges(from, [e.type]).some((x) => x.to === to)) continue;
90797
- const id = from === e.from && to === e.to ? e.id : edgeId(from, e.type, to);
90798
- if (store.getEdge(id)) continue;
90799
- store.mergeEdge({ ...e, id, from, to });
90800
- landedEdges++;
90978
+ if (landCloudEdge(store, e, from, to)) landedEdges++;
90801
90979
  }
90802
90980
  profile.projectHydratedAt = Date.now();
90803
90981
  saveProfile(root, profile);
@@ -91061,8 +91239,8 @@ async function syncHistoryRevisionPage(opts) {
91061
91239
  init_src7();
91062
91240
  init_src();
91063
91241
  import { execFile as execFile6 } from "node:child_process";
91064
- import { readFileSync as readFileSync35 } from "node:fs";
91065
- import { join as join39 } from "node:path";
91242
+ import { readFileSync as readFileSync36 } from "node:fs";
91243
+ import { join as join40 } from "node:path";
91066
91244
  import { promisify as promisify5 } from "node:util";
91067
91245
 
91068
91246
  // src/history-walk.ts
@@ -91614,7 +91792,7 @@ async function defaultGit(root, args2) {
91614
91792
  function readIgnoreLines(root, profile) {
91615
91793
  let lines = [];
91616
91794
  try {
91617
- lines = readFileSync35(join39(root, ".errataignore"), "utf8").split("\n");
91795
+ lines = readFileSync36(join40(root, ".errataignore"), "utf8").split("\n");
91618
91796
  } catch {
91619
91797
  }
91620
91798
  return [...lines, ...profile.ignoreExtra ?? []].map((l) => l.trim()).filter((l) => l && !l.startsWith("#"));
@@ -92190,8 +92368,8 @@ async function startHistoryStage(root, input, client, walk11 = {}) {
92190
92368
  init_cloud_auth();
92191
92369
  import { createHash as createHash19 } from "node:crypto";
92192
92370
  import { execFileSync as execFileSync6 } from "node:child_process";
92193
- import { existsSync as existsSync32, writeFileSync as writeFileSync25 } from "node:fs";
92194
- import { join as join40 } from "node:path";
92371
+ import { existsSync as existsSync32, writeFileSync as writeFileSync26 } from "node:fs";
92372
+ import { join as join41 } from "node:path";
92195
92373
 
92196
92374
  // src/device-poll.ts
92197
92375
  var THROTTLED_POLL_MIN_WAIT_MS = 11e3;
@@ -92650,9 +92828,9 @@ function applyLinkDecision(root, profile, config2, decision, now = Date.now) {
92650
92828
  delete nextProfile.projectLinkHold;
92651
92829
  let wroteIgnore = false;
92652
92830
  if (decision.writeIgnoreStarter !== false) {
92653
- const target = join40(root, ".errataignore");
92831
+ const target = join41(root, ".errataignore");
92654
92832
  if (!existsSync32(target)) {
92655
- writeFileSync25(target, IGNORE_STARTER, "utf8");
92833
+ writeFileSync26(target, IGNORE_STARTER, "utf8");
92656
92834
  wroteIgnore = true;
92657
92835
  }
92658
92836
  }
@@ -92666,12 +92844,12 @@ init_registry();
92666
92844
  // src/adopt.ts
92667
92845
  init_git_remote();
92668
92846
  import { existsSync as existsSync33 } from "node:fs";
92669
- import { dirname as dirname13, join as join41 } from "node:path";
92847
+ import { dirname as dirname14, join as join42 } from "node:path";
92670
92848
  function findGitRoot(absPath) {
92671
92849
  let dir = absPath;
92672
92850
  for (let depth = 0; depth < 64; depth++) {
92673
- if (existsSync33(join41(dir, ".git"))) return dir;
92674
- const parent = dirname13(dir);
92851
+ if (existsSync33(join42(dir, ".git"))) return dir;
92852
+ const parent = dirname14(dir);
92675
92853
  if (parent === dir) return null;
92676
92854
  dir = parent;
92677
92855
  }
@@ -93388,7 +93566,7 @@ async function startMultiDaemon(opts = {}) {
93388
93566
  records.push(rec);
93389
93567
  void ambientLinkAll();
93390
93568
  try {
93391
- writeFileSync26(
93569
+ writeFileSync27(
93392
93570
  rec.engine.paths.daemonLock,
93393
93571
  daemonLockPayload({
93394
93572
  pid: process.pid,
@@ -93767,7 +93945,7 @@ async function startMultiDaemon(opts = {}) {
93767
93945
  baseUrl = `http://127.0.0.1:${port}`;
93768
93946
  try {
93769
93947
  ensureDir(globalDir());
93770
- writeFileSync26(
93948
+ writeFileSync27(
93771
93949
  lockPath,
93772
93950
  daemonLockPayload({ pid: process.pid, webUiUrl: baseUrl, processStartedAt: PROCESS_STARTED_AT, entry: SELF_ENTRY, version: DAEMON_VERSION }),
93773
93951
  "utf8"
@@ -93776,7 +93954,7 @@ async function startMultiDaemon(opts = {}) {
93776
93954
  }
93777
93955
  for (const r of records) {
93778
93956
  try {
93779
- writeFileSync26(
93957
+ writeFileSync27(
93780
93958
  r.engine.paths.daemonLock,
93781
93959
  daemonLockPayload({
93782
93960
  pid: process.pid,
@@ -93818,6 +93996,7 @@ async function startMultiDaemon(opts = {}) {
93818
93996
  const lastAnchorPull = /* @__PURE__ */ new Map();
93819
93997
  const pullProjectAnchors = async (r, client, salt) => {
93820
93998
  const donePass = markPass(`anchor-pull:${r.engine.profile.name}`);
93999
+ const pullStartedAt = Date.now();
93821
94000
  const beforeCorrections = r.engine.profile.projectHistoryCorrectionCursor ?? 0;
93822
94001
  const sync = await syncProjectAnchors({
93823
94002
  root: r.root,
@@ -93839,10 +94018,22 @@ async function startMultiDaemon(opts = {}) {
93839
94018
  console.warn(`[errata] history revision reconciliation failed for ${r.engine.profile.name}: ${err2 instanceof Error ? err2.message : String(err2)}`);
93840
94019
  }
93841
94020
  if (sync.synced) {
93842
- if (sync.anchors + sync.updated > 0) {
94021
+ appendPassLedger(r.engine.paths.configDir, "anchor-pull", Date.now() - pullStartedAt, {
94022
+ anchorsLanded: sync.anchors,
94023
+ anchorsUpdated: sync.updated,
94024
+ nodesLanded: sync.landed,
94025
+ edgesLanded: sync.edgesLanded + sync.edgesReplayed,
94026
+ edgesParked: sync.edgesParked,
94027
+ edgesReplayed: sync.edgesReplayed,
94028
+ edgesPending: sync.edgesPending
94029
+ });
94030
+ if (sync.backfillStarted) {
94031
+ console.log(`[errata] causal re-walk started for ${r.engine.profile.name} \u2014 anchor cursor reset to 0 once`);
94032
+ }
94033
+ if (sync.anchors + sync.updated + sync.landed + sync.edgesLanded + sync.edgesReplayed > 0) {
93843
94034
  r.engine.markContextDirty();
93844
94035
  console.log(
93845
- `[errata] anchors pulled for ${r.engine.profile.name} \u2014 ${sync.anchors} new, ${sync.updated} re-versioned, ${sync.dropped} unresolved (${sync.landed} priors landed, cursor ${sync.cursor})`
94036
+ `[errata] anchors pulled for ${r.engine.profile.name} \u2014 ${sync.anchors} new, ${sync.updated} re-versioned, ${sync.dropped} unresolved (${sync.landed} priors landed, ${sync.edgesLanded + sync.edgesReplayed} causal edges landed, ${sync.edgesPending} parked, cursor ${sync.cursor})`
93846
94037
  );
93847
94038
  }
93848
94039
  } else if (sync.reason === "error") {
@@ -95258,7 +95449,7 @@ import { spawnSync as spawnSync2 } from "node:child_process";
95258
95449
 
95259
95450
  // src/codex-runtime.ts
95260
95451
  import { readdirSync as readdirSync13, statSync as statSync10 } from "node:fs";
95261
- import { join as join42 } from "node:path";
95452
+ import { join as join43 } from "node:path";
95262
95453
  function resolveCodexExecutable(options = {}) {
95263
95454
  const platform = options.platform ?? process.platform;
95264
95455
  const env2 = options.env ?? process.env;
@@ -95273,13 +95464,13 @@ function resolveCodexExecutable(options = {}) {
95273
95464
  };
95274
95465
  for (const dir of (env2["PATH"] ?? env2["Path"] ?? "").split(";")) {
95275
95466
  if (!dir.trim()) continue;
95276
- const path3 = join42(dir.trim().replace(/^"|"$/g, ""), "codex.exe");
95467
+ const path3 = join43(dir.trim().replace(/^"|"$/g, ""), "codex.exe");
95277
95468
  if (fileTime(path3) !== null) return path3;
95278
95469
  }
95279
95470
  if (!env2["LOCALAPPDATA"]) return "codex";
95280
- const root = join42(env2["LOCALAPPDATA"], "OpenAI", "Codex", "bin");
95471
+ const root = join43(env2["LOCALAPPDATA"], "OpenAI", "Codex", "bin");
95281
95472
  try {
95282
- const candidates = readdirSync13(root, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => join42(root, entry.name, "codex.exe")).map((path3) => ({ path: path3, mtime: fileTime(path3) })).filter((candidate) => candidate.mtime !== null).sort((a, b) => b.mtime - a.mtime || a.path.localeCompare(b.path));
95473
+ const candidates = readdirSync13(root, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => join43(root, entry.name, "codex.exe")).map((path3) => ({ path: path3, mtime: fileTime(path3) })).filter((candidate) => candidate.mtime !== null).sort((a, b) => b.mtime - a.mtime || a.path.localeCompare(b.path));
95283
95474
  return candidates[0]?.path ?? "codex";
95284
95475
  } catch {
95285
95476
  return "codex";
@@ -95418,14 +95609,14 @@ async function diagnoseInstallation(cfg, dependencies) {
95418
95609
 
95419
95610
  // src/codex-doctor.ts
95420
95611
  import { spawn as spawn4 } from "node:child_process";
95421
- import { readFileSync as readFileSync37, statSync as statSync11 } from "node:fs";
95422
- import { join as join44 } from "node:path";
95612
+ import { readFileSync as readFileSync38, statSync as statSync11 } from "node:fs";
95613
+ import { join as join45 } from "node:path";
95423
95614
  import { createInterface } from "node:readline";
95424
95615
 
95425
95616
  // src/codex-hooks.ts
95426
- import { existsSync as existsSync35, mkdirSync as mkdirSync9, readFileSync as readFileSync36, renameSync as renameSync5, unlinkSync as unlinkSync5, writeFileSync as writeFileSync27 } from "node:fs";
95617
+ import { existsSync as existsSync35, mkdirSync as mkdirSync9, readFileSync as readFileSync37, renameSync as renameSync6, unlinkSync as unlinkSync5, writeFileSync as writeFileSync28 } from "node:fs";
95427
95618
  import { homedir as homedir7 } from "node:os";
95428
- import { join as join43 } from "node:path";
95619
+ import { join as join44 } from "node:path";
95429
95620
 
95430
95621
  // src/hook-commands.ts
95431
95622
  function hookCurlCommand(port, path3 = "/api/hook") {
@@ -95629,34 +95820,34 @@ function buildCodexRelaySource(workspaceRoot) {
95629
95820
  init_checkout_root();
95630
95821
  var CODEX_HOOK_REVIEW_HELP = "Codex desktop: Settings > Hooks, select this project, expand each event and Trust the Errata hook. CLI users can use /hooks.";
95631
95822
  function writeRelay(file2, source) {
95632
- if (existsSync35(file2) && readFileSync36(file2, "utf8") === source) return;
95823
+ if (existsSync35(file2) && readFileSync37(file2, "utf8") === source) return;
95633
95824
  const temp = `${file2}.${process.pid}.tmp`;
95634
95825
  try {
95635
- writeFileSync27(temp, source, { encoding: "utf8", mode: 384 });
95636
- renameSync5(temp, file2);
95826
+ writeFileSync28(temp, source, { encoding: "utf8", mode: 384 });
95827
+ renameSync6(temp, file2);
95637
95828
  } finally {
95638
95829
  if (existsSync35(temp)) unlinkSync5(temp);
95639
95830
  }
95640
95831
  }
95641
95832
  function refreshCodexRelay(root) {
95642
- const config2 = join43(root, ".codex", "config.toml");
95833
+ const config2 = join44(root, ".codex", "config.toml");
95643
95834
  if (!existsSync35(config2)) return "absent";
95644
- const existing = readFileSync36(config2, "utf8");
95835
+ const existing = readFileSync37(config2, "utf8");
95645
95836
  if (!existing.includes(CODEX_HOOKS_BEGIN) && !existing.includes(CODEX_HOOKS_END)) return "absent";
95646
95837
  replaceCodexHooks(existing, "");
95647
- const relay = join43(root, ".codex", "hooks", "errata-relay.mjs");
95648
- const prior = existsSync35(relay) ? readFileSync36(relay, "utf8") : "";
95838
+ const relay = join44(root, ".codex", "hooks", "errata-relay.mjs");
95839
+ const prior = existsSync35(relay) ? readFileSync37(relay, "utf8") : "";
95649
95840
  if (prior && !prior.startsWith("// errata-managed: regenerated by errata install-hooks codex")) {
95650
95841
  throw new Error("Codex relay is not Errata-managed; preserved it. Run errata install-hooks codex to explicitly replace it.");
95651
95842
  }
95652
95843
  const source = buildCodexRelaySource(checkoutRootOf(root));
95653
95844
  if (prior === source) return "current";
95654
- mkdirSync9(join43(root, ".codex", "hooks"), { recursive: true });
95845
+ mkdirSync9(join44(root, ".codex", "hooks"), { recursive: true });
95655
95846
  writeRelay(relay, source);
95656
95847
  return "updated";
95657
95848
  }
95658
- function hasCodexConfig(root, codexHome = process.env["CODEX_HOME"] || join43(homedir7(), ".codex")) {
95659
- return existsSync35(join43(root, ".codex")) || existsSync35(codexHome);
95849
+ function hasCodexConfig(root, codexHome = process.env["CODEX_HOME"] || join44(homedir7(), ".codex")) {
95850
+ return existsSync35(join44(root, ".codex")) || existsSync35(codexHome);
95660
95851
  }
95661
95852
  function replaceCodexHooks(existing, block) {
95662
95853
  const begin = existing.indexOf(CODEX_HOOKS_BEGIN);
@@ -95672,14 +95863,14 @@ function replaceCodexHooks(existing, block) {
95672
95863
  return existing.trimEnd() + (existing.trim() ? "\n\n" : "") + block;
95673
95864
  }
95674
95865
  function writeCodexHooks(root, port, nodePath = process.execPath) {
95675
- const dir = join43(root, ".codex");
95676
- const file2 = join43(dir, "config.toml");
95677
- const relay = join43(dir, "hooks", "errata-relay.mjs");
95866
+ const dir = join44(root, ".codex");
95867
+ const file2 = join44(dir, "config.toml");
95868
+ const relay = join44(dir, "hooks", "errata-relay.mjs");
95678
95869
  const block = buildCodexHooksToml(port, { nodePath, relayPath: relay });
95679
- const final = replaceCodexHooks(existsSync35(file2) ? readFileSync36(file2, "utf8") : "", block);
95680
- mkdirSync9(join43(dir, "hooks"), { recursive: true });
95870
+ const final = replaceCodexHooks(existsSync35(file2) ? readFileSync37(file2, "utf8") : "", block);
95871
+ mkdirSync9(join44(dir, "hooks"), { recursive: true });
95681
95872
  writeRelay(relay, buildCodexRelaySource(checkoutRootOf(root)));
95682
- if (!existsSync35(file2) || readFileSync36(file2, "utf8") !== final) writeFileSync27(file2, final, "utf8");
95873
+ if (!existsSync35(file2) || readFileSync37(file2, "utf8") !== final) writeFileSync28(file2, final, "utf8");
95683
95874
  return file2;
95684
95875
  }
95685
95876
 
@@ -95688,7 +95879,7 @@ init_checkout_root();
95688
95879
  function inspectCodexRelay(cwd) {
95689
95880
  const root = nearestGitRoot(cwd) ?? cwd;
95690
95881
  try {
95691
- const source = readFileSync37(join44(root, ".codex", "hooks", "errata-relay.mjs"), "utf8");
95882
+ const source = readFileSync38(join45(root, ".codex", "hooks", "errata-relay.mjs"), "utf8");
95692
95883
  if (source === buildCodexRelaySource(checkoutRootOf(root))) {
95693
95884
  return { id: "codex_relay", status: "pass", detail: "Installed Codex relay matches this Errata version" };
95694
95885
  }
@@ -95699,8 +95890,8 @@ function inspectCodexRelay(cwd) {
95699
95890
  function inspectCodexContext(cwd) {
95700
95891
  const root = checkoutRootOf(nearestGitRoot(cwd) ?? cwd);
95701
95892
  try {
95702
- const file2 = join44(root, ".errata", "context.md");
95703
- if (statSync11(file2).size <= 128 * 1024 && readFileSync37(file2, "utf8").trim()) {
95893
+ const file2 = join45(root, ".errata", "context.md");
95894
+ if (statSync11(file2).size <= 128 * 1024 && readFileSync38(file2, "utf8").trim()) {
95704
95895
  return { id: "codex_context", status: "pass", detail: "Saved workspace context is readable by the relay; this does not prove live daemon freshness" };
95705
95896
  }
95706
95897
  } catch {
@@ -95878,9 +96069,9 @@ function consolidationGapMs(lastPassMs, policy) {
95878
96069
 
95879
96070
  // src/codex-context-plugin.ts
95880
96071
  import { createHash as createHash20 } from "node:crypto";
95881
- import { cpSync as cpSync2, existsSync as existsSync36, mkdirSync as mkdirSync10, readFileSync as readFileSync38, renameSync as renameSync6, writeFileSync as writeFileSync28 } from "node:fs";
96072
+ import { cpSync as cpSync2, existsSync as existsSync36, mkdirSync as mkdirSync10, readFileSync as readFileSync39, renameSync as renameSync7, writeFileSync as writeFileSync29 } from "node:fs";
95882
96073
  import { homedir as homedir8 } from "node:os";
95883
- import { join as join45 } from "node:path";
96074
+ import { join as join46 } from "node:path";
95884
96075
  import { fileURLToPath as fileURLToPath2 } from "node:url";
95885
96076
 
95886
96077
  // ../../node_modules/.pnpm/smol-toml@1.6.1/node_modules/smol-toml/dist/error.js
@@ -96578,23 +96769,23 @@ var NAME = "errata-context";
96578
96769
  var PREFIX2 = `./.errata/plugins/${NAME}/`;
96579
96770
  var object2 = (value) => value !== null && typeof value === "object" && !Array.isArray(value) ? value : {};
96580
96771
  function readText(file2) {
96581
- return existsSync36(file2) ? readFileSync38(file2, "utf8") : "";
96772
+ return existsSync36(file2) ? readFileSync39(file2, "utf8") : "";
96582
96773
  }
96583
96774
  function writeChanged(file2, content) {
96584
96775
  if (readText(file2) === content) return;
96585
96776
  const temp = `${file2}.${process.pid}.tmp`;
96586
- writeFileSync28(temp, content, "utf8");
96587
- renameSync6(temp, file2);
96777
+ writeFileSync29(temp, content, "utf8");
96778
+ renameSync7(temp, file2);
96588
96779
  }
96589
96780
  function bundledContextPlugin() {
96590
96781
  const packaged = fileURLToPath2(new URL("./resources/context-plugin/", import.meta.url));
96591
- if (existsSync36(join45(packaged, ".codex-plugin/plugin.json"))) return packaged;
96782
+ if (existsSync36(join46(packaged, ".codex-plugin/plugin.json"))) return packaged;
96592
96783
  return fileURLToPath2(new URL("../dist/resources/context-plugin/", import.meta.url));
96593
96784
  }
96594
96785
  function refreshCodexContextPlugin(root) {
96595
- const file2 = join45(root, ".agents", "plugins", "marketplace.json");
96786
+ const file2 = join46(root, ".agents", "plugins", "marketplace.json");
96596
96787
  if (!existsSync36(file2)) return false;
96597
- const marketplace = JSON.parse(readFileSync38(file2, "utf8"));
96788
+ const marketplace = JSON.parse(readFileSync39(file2, "utf8"));
96598
96789
  const entries = Array.isArray(marketplace.plugins) ? marketplace.plugins : [];
96599
96790
  const entry = entries.map(object2).find((value) => value.name === NAME && String(object2(value.source).path).startsWith(PREFIX2));
96600
96791
  if (!entry) return false;
@@ -96605,24 +96796,24 @@ function refreshCodexContextPlugin(root) {
96605
96796
  function installCodexContextPlugin(root, options = {}) {
96606
96797
  const bundle = options.bundle ?? bundledContextPlugin();
96607
96798
  const manifest = JSON.parse(
96608
- readFileSync38(join45(bundle, ".codex-plugin/plugin.json"), "utf8")
96799
+ readFileSync39(join46(bundle, ".codex-plugin/plugin.json"), "utf8")
96609
96800
  );
96610
96801
  if (manifest.name !== NAME || typeof manifest.version !== "string" || !/^[\w.-]+$/.test(manifest.version)) {
96611
96802
  throw new Error("Invalid bundled Errata Context manifest.");
96612
96803
  }
96613
- const checksums = readFileSync38(join45(bundle, "SHA256SUMS"), "utf8");
96804
+ const checksums = readFileSync39(join46(bundle, "SHA256SUMS"), "utf8");
96614
96805
  for (const line of checksums.trim().split("\n")) {
96615
96806
  const match2 = /^([a-f0-9]{64}) ([\w./-]+)$/.exec(line);
96616
96807
  if (!match2 || match2[2].startsWith("/") || match2[2].split("/").includes("..")) {
96617
96808
  throw new Error("Invalid bundled Errata Context checksum manifest.");
96618
96809
  }
96619
- const actual = createHash20("sha256").update(readFileSync38(join45(bundle, match2[2]))).digest("hex");
96810
+ const actual = createHash20("sha256").update(readFileSync39(join46(bundle, match2[2]))).digest("hex");
96620
96811
  if (actual !== match2[1])
96621
96812
  throw new Error(`Bundled Errata Context checksum mismatch: ${match2[2]}`);
96622
96813
  }
96623
96814
  const release = `${manifest.version}-${createHash20("sha256").update(checksums).digest("hex").slice(0, 12)}`;
96624
- const plugin = join45(root, ".errata", "plugins", NAME, release);
96625
- const marketplaceFile = join45(root, ".agents", "plugins", "marketplace.json");
96815
+ const plugin = join46(root, ".errata", "plugins", NAME, release);
96816
+ const marketplaceFile = join46(root, ".agents", "plugins", "marketplace.json");
96626
96817
  const priorMarketplace = readText(marketplaceFile);
96627
96818
  const marketplace = priorMarketplace ? JSON.parse(priorMarketplace) : {
96628
96819
  name: "errata-local",
@@ -96643,12 +96834,12 @@ function installCodexContextPlugin(root, options = {}) {
96643
96834
  );
96644
96835
  }
96645
96836
  const key = `${NAME}@${marketplace.name}`;
96646
- const configFile = join45(root, ".codex", "config.toml");
96837
+ const configFile = join46(root, ".codex", "config.toml");
96647
96838
  const config2 = readText(configFile);
96648
96839
  const parsed = parse4(config2);
96649
96840
  const plugins = object2(parsed.plugins);
96650
- const codexHome = options.codexHome ?? process.env["CODEX_HOME"] ?? join45(homedir8(), ".codex");
96651
- const globalPlugins = object2(parse4(readText(join45(codexHome, "config.toml"))).plugins);
96841
+ const codexHome = options.codexHome ?? process.env["CODEX_HOME"] ?? join46(homedir8(), ".codex");
96842
+ const globalPlugins = object2(parse4(readText(join46(codexHome, "config.toml"))).plugins);
96652
96843
  const disabledGlobally = Object.entries(globalPlugins).some(
96653
96844
  ([name2, value]) => (name2 === NAME || name2.startsWith(`${NAME}@`)) && object2(value).enabled === false
96654
96845
  );
@@ -96672,13 +96863,13 @@ enabled = ${enabled}
96672
96863
  mkdirSync10(plugin, { recursive: true });
96673
96864
  cpSync2(bundle, plugin, { recursive: true });
96674
96865
  writeChanged(
96675
- join45(plugin, ".mcp.json"),
96866
+ join46(plugin, ".mcp.json"),
96676
96867
  JSON.stringify(
96677
96868
  {
96678
96869
  mcpServers: {
96679
96870
  errata_context: {
96680
96871
  command: options.nodePath ?? process.execPath,
96681
- args: [join45(plugin, "dist", "mcp-server.mjs")],
96872
+ args: [join46(plugin, "dist", "mcp-server.mjs")],
96682
96873
  env: { ERRATA_WORKSPACE: root, ERRATA_CONTEXT_VERSION: manifest.version }
96683
96874
  }
96684
96875
  }
@@ -96687,8 +96878,8 @@ enabled = ${enabled}
96687
96878
  2
96688
96879
  ) + "\n"
96689
96880
  );
96690
- mkdirSync10(join45(root, ".agents", "plugins"), { recursive: true });
96691
- mkdirSync10(join45(root, ".codex"), { recursive: true });
96881
+ mkdirSync10(join46(root, ".agents", "plugins"), { recursive: true });
96882
+ mkdirSync10(join46(root, ".codex"), { recursive: true });
96692
96883
  writeChanged(marketplaceFile, JSON.stringify(marketplace, null, 2) + "\n");
96693
96884
  writeChanged(configFile, nextConfig);
96694
96885
  return { plugin, enabled, marketplace: marketplaceFile };
@@ -96696,15 +96887,15 @@ enabled = ${enabled}
96696
96887
 
96697
96888
  // src/codex-hook-refresh.ts
96698
96889
  init_checkout_root();
96699
- import { existsSync as existsSync37, readdirSync as readdirSync14, readFileSync as readFileSync39 } from "node:fs";
96700
- import { dirname as dirname14, join as join46, resolve as resolve8 } from "node:path";
96890
+ import { existsSync as existsSync37, readdirSync as readdirSync14, readFileSync as readFileSync40 } from "node:fs";
96891
+ import { dirname as dirname15, join as join47, resolve as resolve8 } from "node:path";
96701
96892
  init_registry();
96702
96893
  function codexHookRoots(roots) {
96703
96894
  const found = new Set(roots.map((root) => resolve8(root)));
96704
96895
  for (const root of [...found]) {
96705
96896
  const main2 = mainCheckoutOfWorktree(root) ?? root;
96706
96897
  found.add(main2);
96707
- const dir = join46(main2, ".git", "worktrees");
96898
+ const dir = join47(main2, ".git", "worktrees");
96708
96899
  if (!existsSync37(dir)) continue;
96709
96900
  let names;
96710
96901
  try {
@@ -96714,7 +96905,7 @@ function codexHookRoots(roots) {
96714
96905
  }
96715
96906
  for (const name2 of names) {
96716
96907
  try {
96717
- const checkout = dirname14(readFileSync39(join46(dir, name2, "gitdir"), "utf8").trim());
96908
+ const checkout = dirname15(readFileSync40(join47(dir, name2, "gitdir"), "utf8").trim());
96718
96909
  if (mainCheckoutOfWorktree(checkout) === main2) found.add(checkout);
96719
96910
  } catch {
96720
96911
  }
@@ -96736,9 +96927,9 @@ function refreshInstalledCodexRelays(roots = listWorkspaceEntries().map((entry)
96736
96927
  }
96737
96928
 
96738
96929
  // src/claude-statusline.ts
96739
- import { existsSync as existsSync38, mkdirSync as mkdirSync11, readFileSync as readFileSync40, writeFileSync as writeFileSync29 } from "node:fs";
96930
+ import { existsSync as existsSync38, mkdirSync as mkdirSync11, readFileSync as readFileSync41, writeFileSync as writeFileSync30 } from "node:fs";
96740
96931
  import { homedir as homedir9 } from "node:os";
96741
- import { dirname as dirname15, join as join47 } from "node:path";
96932
+ import { dirname as dirname16, join as join48 } from "node:path";
96742
96933
  var STATUSLINE_RELAY_SOURCE = String.raw`// errata-managed: regenerated by errata init / install-hooks claude
96743
96934
  import { readFileSync } from 'node:fs';
96744
96935
 
@@ -96786,8 +96977,8 @@ function isSameInstall(value, relay) {
96786
96977
  return command.includes(relay.replace(/\\/g, "/").toLowerCase());
96787
96978
  }
96788
96979
  function userClaudeSettingsPath() {
96789
- const base = process.env["CLAUDE_CONFIG_DIR"] ?? join47(homedir9(), ".claude");
96790
- return join47(base, "settings.json");
96980
+ const base = process.env["CLAUDE_CONFIG_DIR"] ?? join48(homedir9(), ".claude");
96981
+ return join48(base, "settings.json");
96791
96982
  }
96792
96983
  function ensureUserStatusLine(opts) {
96793
96984
  const env2 = opts.env ?? process.env;
@@ -96797,21 +96988,21 @@ function ensureUserStatusLine(opts) {
96797
96988
  let settings = {};
96798
96989
  if (existsSync38(settingsPath)) {
96799
96990
  try {
96800
- const parsed = JSON.parse(readFileSync40(settingsPath, "utf8"));
96991
+ const parsed = JSON.parse(readFileSync41(settingsPath, "utf8"));
96801
96992
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return "unreadable";
96802
96993
  settings = parsed;
96803
96994
  } catch {
96804
96995
  return "unreadable";
96805
96996
  }
96806
96997
  }
96807
- const relay = join47(opts.relayDir, STATUSLINE_RELAY_FILE);
96998
+ const relay = join48(opts.relayDir, STATUSLINE_RELAY_FILE);
96808
96999
  const keep = (value) => value !== void 0 && (!isErrataStatusLine(value) || !isSameInstall(value, relay));
96809
97000
  const ownMain = keep(settings["statusLine"]);
96810
97001
  const ownRows = keep(settings["subagentStatusLine"]);
96811
97002
  if (ownMain && ownRows) return "kept-own";
96812
97003
  mkdirSync11(opts.relayDir, { recursive: true });
96813
- if (!existsSync38(relay) || readFileSync40(relay, "utf8") !== STATUSLINE_RELAY_SOURCE) {
96814
- writeFileSync29(relay, STATUSLINE_RELAY_SOURCE, "utf8");
97004
+ if (!existsSync38(relay) || readFileSync41(relay, "utf8") !== STATUSLINE_RELAY_SOURCE) {
97005
+ writeFileSync30(relay, STATUSLINE_RELAY_SOURCE, "utf8");
96815
97006
  }
96816
97007
  const nodePath = opts.nodePath ?? process.execPath;
96817
97008
  const next = {
@@ -96822,8 +97013,8 @@ function ensureUserStatusLine(opts) {
96822
97013
  return ownMain ? "kept-own" : "unchanged";
96823
97014
  }
96824
97015
  Object.assign(settings, next);
96825
- mkdirSync11(dirname15(settingsPath), { recursive: true });
96826
- writeFileSync29(settingsPath, JSON.stringify(settings, null, 2) + "\n", "utf8");
97016
+ mkdirSync11(dirname16(settingsPath), { recursive: true });
97017
+ writeFileSync30(settingsPath, JSON.stringify(settings, null, 2) + "\n", "utf8");
96827
97018
  return "installed";
96828
97019
  }
96829
97020
  function describeStatusLineOutcome(outcome) {
@@ -96843,8 +97034,8 @@ function describeStatusLineOutcome(outcome) {
96843
97034
 
96844
97035
  // src/claude-mods.ts
96845
97036
  import { createHash as createHash21 } from "node:crypto";
96846
- import { cpSync as cpSync3, existsSync as existsSync39, mkdirSync as mkdirSync12, readFileSync as readFileSync41, readdirSync as readdirSync15, rmSync as rmSync4, statSync as statSync12, writeFileSync as writeFileSync30 } from "node:fs";
96847
- import { delimiter as delimiter2, dirname as dirname16, join as join48, relative as relative8, resolve as resolve9, sep as sep5 } from "node:path";
97037
+ import { cpSync as cpSync3, existsSync as existsSync39, mkdirSync as mkdirSync12, readFileSync as readFileSync42, readdirSync as readdirSync15, rmSync as rmSync4, statSync as statSync12, writeFileSync as writeFileSync31 } from "node:fs";
97038
+ import { delimiter as delimiter2, dirname as dirname17, join as join49, relative as relative8, resolve as resolve9, sep as sep5 } from "node:path";
96848
97039
  import { fileURLToPath as fileURLToPath3 } from "node:url";
96849
97040
  var CLAUDE_PLUGIN_DIRS_ENV = "CLAUDE_CODE_PLUGIN_DIRS";
96850
97041
  var HASH_FILE = ".errata-mod-hash";
@@ -96859,7 +97050,7 @@ function isEngineOwned(relPath) {
96859
97050
  function listFiles(root, dir = root) {
96860
97051
  const out2 = [];
96861
97052
  for (const name2 of readdirSync15(dir)) {
96862
- const abs = join48(dir, name2);
97053
+ const abs = join49(dir, name2);
96863
97054
  if (isEngineOwned(relative8(root, abs))) continue;
96864
97055
  if (statSync12(abs).isDirectory()) out2.push(...listFiles(root, abs));
96865
97056
  else out2.push(abs);
@@ -96871,14 +97062,14 @@ function modHash(dir) {
96871
97062
  for (const abs of listFiles(dir).sort()) {
96872
97063
  h.update(relative8(dir, abs).split(sep5).join("/"));
96873
97064
  h.update("\0");
96874
- h.update(readFileSync41(abs));
97065
+ h.update(readFileSync42(abs));
96875
97066
  h.update("\0");
96876
97067
  }
96877
97068
  return h.digest("hex");
96878
97069
  }
96879
97070
  function bundledMods(bundleDir) {
96880
97071
  if (!existsSync39(bundleDir)) return [];
96881
- return readdirSync15(bundleDir).filter((name2) => existsSync39(join48(bundleDir, name2, ".claude-plugin", "plugin.json")));
97072
+ return readdirSync15(bundleDir).filter((name2) => existsSync39(join49(bundleDir, name2, ".claude-plugin", "plugin.json")));
96882
97073
  }
96883
97074
  function sameDir(a, b) {
96884
97075
  const norm = (p) => resolve9(p).replace(/[\\/]+$/, "").toLowerCase();
@@ -96895,7 +97086,7 @@ function off(env2) {
96895
97086
  function readSettings(path3) {
96896
97087
  if (!existsSync39(path3)) return {};
96897
97088
  try {
96898
- const parsed = JSON.parse(readFileSync41(path3, "utf8"));
97089
+ const parsed = JSON.parse(readFileSync42(path3, "utf8"));
96899
97090
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return null;
96900
97091
  return parsed;
96901
97092
  } catch {
@@ -96919,13 +97110,13 @@ function currentDirs(settings) {
96919
97110
  return raw2.split(delimiter2).map((s) => s.trim()).filter(Boolean);
96920
97111
  }
96921
97112
  function writeSettings(path3, settings) {
96922
- mkdirSync12(dirname16(path3), { recursive: true });
96923
- writeFileSync30(path3, JSON.stringify(settings, null, 2) + "\n", "utf8");
97113
+ mkdirSync12(dirname17(path3), { recursive: true });
97114
+ writeFileSync31(path3, JSON.stringify(settings, null, 2) + "\n", "utf8");
96924
97115
  }
96925
97116
  function ensureClaudeMods(opts) {
96926
97117
  const env2 = opts.env ?? process.env;
96927
97118
  const settingsPath = opts.userSettingsPath ?? userClaudeSettingsPath();
96928
- const modsRoot = join48(opts.installRoot, "claude-mods");
97119
+ const modsRoot = join49(opts.installRoot, "claude-mods");
96929
97120
  if (off(env2)) {
96930
97121
  const settings2 = readSettings(settingsPath);
96931
97122
  if (!settings2) return { kind: "unreadable" };
@@ -96942,14 +97133,14 @@ function ensureClaudeMods(opts) {
96942
97133
  let changed = false;
96943
97134
  const installed = [];
96944
97135
  for (const name2 of names) {
96945
- const src = join48(bundleDir, name2);
96946
- const dest = join48(modsRoot, name2);
97136
+ const src = join49(bundleDir, name2);
97137
+ const dest = join49(modsRoot, name2);
96947
97138
  const hash2 = modHash(src);
96948
- const hashFile = join48(dest, HASH_FILE);
96949
- if (!existsSync39(hashFile) || readFileSync41(hashFile, "utf8") !== hash2) {
97139
+ const hashFile = join49(dest, HASH_FILE);
97140
+ if (!existsSync39(hashFile) || readFileSync42(hashFile, "utf8") !== hash2) {
96950
97141
  rmSync4(dest, { recursive: true, force: true });
96951
97142
  cpSync3(src, dest, { recursive: true, filter: (p) => !isEngineOwned(relative8(src, p)) });
96952
- writeFileSync30(hashFile, hash2, "utf8");
97143
+ writeFileSync31(hashFile, hash2, "utf8");
96953
97144
  changed = true;
96954
97145
  }
96955
97146
  installed.push(dest);
@@ -97370,9 +97561,9 @@ function resolveHookPort(explicit) {
97370
97561
  }
97371
97562
  }
97372
97563
  }
97373
- const settingsPath = join49(ROOT, ".claude", "settings.json");
97564
+ const settingsPath = join50(ROOT, ".claude", "settings.json");
97374
97565
  try {
97375
- if (existsSync40(settingsPath)) return installedHookPort(readFileSync42(settingsPath, "utf8")) ?? 7891;
97566
+ if (existsSync40(settingsPath)) return installedHookPort(readFileSync43(settingsPath, "utf8")) ?? 7891;
97376
97567
  } catch {
97377
97568
  }
97378
97569
  return 7891;
@@ -97398,13 +97589,13 @@ async function cmdInit() {
97398
97589
  console.log("");
97399
97590
  console.log("installing harness hooks...");
97400
97591
  const { existsSync: existsSync41 } = await import("node:fs");
97401
- const { join: join50 } = await import("node:path");
97592
+ const { join: join51 } = await import("node:path");
97402
97593
  try {
97403
97594
  await installClaudeHooks(port);
97404
97595
  } catch (err2) {
97405
97596
  console.warn(` \u26A0\uFE0F Claude hook install failed: ${err2 instanceof Error ? err2.message : err2}`);
97406
97597
  }
97407
- if (existsSync41(join50(ROOT, ".cursor"))) {
97598
+ if (existsSync41(join51(ROOT, ".cursor"))) {
97408
97599
  try {
97409
97600
  await installCursorMcpConfig();
97410
97601
  } catch (err2) {
@@ -98626,7 +98817,7 @@ async function cmdReview() {
98626
98817
  console.log("(review queue empty)");
98627
98818
  return;
98628
98819
  }
98629
- const queue = JSON.parse(readFileSync42(paths.reviewQueue, "utf8"));
98820
+ const queue = JSON.parse(readFileSync43(paths.reviewQueue, "utf8"));
98630
98821
  if (queue.length === 0) {
98631
98822
  console.log("(review queue empty)");
98632
98823
  return;
@@ -99365,7 +99556,7 @@ async function gatherReportData(generatedAt) {
99365
99556
  };
99366
99557
  }
99367
99558
  async function cmdReport(args2) {
99368
- const { mkdirSync: mkdirSync13, writeFileSync: writeFileSync31 } = await import("node:fs");
99559
+ const { mkdirSync: mkdirSync13, writeFileSync: writeFileSync32 } = await import("node:fs");
99369
99560
  const { renderReport: renderReport2 } = await Promise.resolve().then(() => (init_report_render(), report_render_exports));
99370
99561
  const includeFutureVerbs = args2.includes("--future-verbs");
99371
99562
  const now = /* @__PURE__ */ new Date();
@@ -99378,8 +99569,8 @@ async function cmdReport(args2) {
99378
99569
  const outDir = workspacePaths(ROOT).configDir;
99379
99570
  mkdirSync13(outDir, { recursive: true });
99380
99571
  const files = renderReport2(data, { includeFutureVerbs });
99381
- for (const f of files) writeFileSync31(join49(outDir, f.name), f.html, "utf8");
99382
- const indexPath = join49(outDir, "report.html");
99572
+ for (const f of files) writeFileSync32(join50(outDir, f.name), f.html, "utf8");
99573
+ const indexPath = join50(outDir, "report.html");
99383
99574
  console.log(`report \u2192 ${indexPath}`);
99384
99575
  console.log(
99385
99576
  ` ${data.repos.length} repo(s) \xB7 ${files.length} file(s) \xB7 ${data.rollup.nodes.toLocaleString("en-US")} nodes`
@@ -99435,7 +99626,7 @@ function spawnDaemonDetached(options = {}) {
99435
99626
  try {
99436
99627
  const logPath = daemonLogPath();
99437
99628
  try {
99438
- if (statSync13(logPath).size > 5 * 1024 * 1024) renameSync7(logPath, `${logPath}.1`);
99629
+ if (statSync13(logPath).size > 5 * 1024 * 1024) renameSync8(logPath, `${logPath}.1`);
99439
99630
  } catch {
99440
99631
  }
99441
99632
  out2 = openSync3(logPath, "a");
@@ -99504,24 +99695,24 @@ async function cmdInstallHooks(args2) {
99504
99695
  }
99505
99696
  }
99506
99697
  async function installOpencodePlugin(port) {
99507
- const { mkdirSync: mkdirSync13, existsSync: existsSync41, readFileSync: readFileSync43, writeFileSync: writeFileSync31 } = await import("node:fs");
99508
- const { join: join50 } = await import("node:path");
99509
- const dir = join50(ROOT, ".opencode", "plugin");
99698
+ const { mkdirSync: mkdirSync13, existsSync: existsSync41, readFileSync: readFileSync44, writeFileSync: writeFileSync32 } = await import("node:fs");
99699
+ const { join: join51 } = await import("node:path");
99700
+ const dir = join51(ROOT, ".opencode", "plugin");
99510
99701
  if (!existsSync41(dir)) mkdirSync13(dir, { recursive: true });
99511
- const file2 = join50(dir, "inerrata.js");
99702
+ const file2 = join51(dir, "inerrata.js");
99512
99703
  if (existsSync41(file2)) {
99513
- const head2 = readFileSync43(file2, "utf8").split("\n")[0] ?? "";
99704
+ const head2 = readFileSync44(file2, "utf8").split("\n")[0] ?? "";
99514
99705
  if (head2.trim() !== OPENCODE_PLUGIN_MARKER) {
99515
99706
  console.error(`refusing to overwrite ${file2}: not an errata-managed plugin (line 1 lacks the marker)`);
99516
99707
  process.exit(2);
99517
99708
  }
99518
99709
  }
99519
- writeFileSync31(file2, buildOpencodePluginSource(port, { version: DAEMON_VERSION }), "utf8");
99520
- const cfgFile = join50(ROOT, "opencode.json");
99710
+ writeFileSync32(file2, buildOpencodePluginSource(port, { version: DAEMON_VERSION }), "utf8");
99711
+ const cfgFile = join51(ROOT, "opencode.json");
99521
99712
  let cfg = { $schema: "https://opencode.ai/config.json" };
99522
99713
  if (existsSync41(cfgFile)) {
99523
99714
  try {
99524
- cfg = JSON.parse(readFileSync43(cfgFile, "utf8"));
99715
+ cfg = JSON.parse(readFileSync44(cfgFile, "utf8"));
99525
99716
  } catch {
99526
99717
  console.error(`refusing to touch invalid JSON at ${cfgFile} \u2014 fix it and re-run`);
99527
99718
  process.exit(2);
@@ -99532,7 +99723,7 @@ async function installOpencodePlugin(port) {
99532
99723
  if (!hadErrata) {
99533
99724
  const inv = errataMcpInvocation();
99534
99725
  cfg.mcp["errata"] = { type: "local", command: [inv.command, ...inv.args] };
99535
- writeFileSync31(cfgFile, JSON.stringify(cfg, null, 2) + "\n", "utf8");
99726
+ writeFileSync32(cfgFile, JSON.stringify(cfg, null, 2) + "\n", "utf8");
99536
99727
  }
99537
99728
  console.log(`installed OpenCode plugin \u2192 ${file2}`);
99538
99729
  if (hadErrata) console.log(` mcp.errata already present in ${cfgFile} \u2014 left untouched`);
@@ -99567,15 +99758,15 @@ function installClaudeMods() {
99567
99758
  }
99568
99759
  }
99569
99760
  async function installClaudeHooks(port) {
99570
- const { mkdirSync: mkdirSync13, existsSync: existsSync41, readFileSync: readFileSync43, writeFileSync: writeFileSync31 } = await import("node:fs");
99571
- const { join: join50 } = await import("node:path");
99572
- const dir = join50(ROOT, ".claude");
99761
+ const { mkdirSync: mkdirSync13, existsSync: existsSync41, readFileSync: readFileSync44, writeFileSync: writeFileSync32 } = await import("node:fs");
99762
+ const { join: join51 } = await import("node:path");
99763
+ const dir = join51(ROOT, ".claude");
99573
99764
  if (!existsSync41(dir)) mkdirSync13(dir, { recursive: true });
99574
- const file2 = join50(dir, "settings.json");
99765
+ const file2 = join51(dir, "settings.json");
99575
99766
  let settings = {};
99576
99767
  if (existsSync41(file2)) {
99577
99768
  try {
99578
- settings = JSON.parse(readFileSync43(file2, "utf8"));
99769
+ settings = JSON.parse(readFileSync44(file2, "utf8"));
99579
99770
  } catch {
99580
99771
  console.error(`refusing to overwrite invalid JSON at ${file2}`);
99581
99772
  process.exit(2);
@@ -99624,12 +99815,12 @@ async function installClaudeHooks(port) {
99624
99815
  list.push({ hooks: [{ type: "command", command: injectCmd }] });
99625
99816
  }
99626
99817
  removeProjectStatusLine(settings);
99627
- writeFileSync31(file2, JSON.stringify(settings, null, 2) + "\n", "utf8");
99818
+ writeFileSync32(file2, JSON.stringify(settings, null, 2) + "\n", "utf8");
99628
99819
  console.log(`installed Claude Code hooks \u2192 ${file2}`);
99629
99820
  console.log(` ${ensureStatusLine(port)}`);
99630
99821
  console.log(` ${installClaudeMods().line}`);
99631
99822
  await installClaudeMcpConfig();
99632
- const claudeMd = join50(ROOT, "CLAUDE.md");
99823
+ const claudeMd = join51(ROOT, "CLAUDE.md");
99633
99824
  const recall = writeManagedBlock(claudeMd, { body: RECALL_FIRST_BLOCK });
99634
99825
  if (recall.kind === "collision") {
99635
99826
  console.warn(
@@ -99641,15 +99832,15 @@ async function installClaudeHooks(port) {
99641
99832
  console.log(` endpoint: http://127.0.0.1:${port}/api/hook`);
99642
99833
  }
99643
99834
  async function installClaudeMcpConfig() {
99644
- const { mkdirSync: mkdirSync13, existsSync: existsSync41, readFileSync: readFileSync43, writeFileSync: writeFileSync31 } = await import("node:fs");
99645
- const { join: join50, dirname: dirname17 } = await import("node:path");
99646
- const file2 = join50(ROOT, ".mcp.json");
99647
- const dir = dirname17(file2);
99835
+ const { mkdirSync: mkdirSync13, existsSync: existsSync41, readFileSync: readFileSync44, writeFileSync: writeFileSync32 } = await import("node:fs");
99836
+ const { join: join51, dirname: dirname18 } = await import("node:path");
99837
+ const file2 = join51(ROOT, ".mcp.json");
99838
+ const dir = dirname18(file2);
99648
99839
  if (!existsSync41(dir)) mkdirSync13(dir, { recursive: true });
99649
99840
  let cfg = {};
99650
99841
  if (existsSync41(file2)) {
99651
99842
  try {
99652
- cfg = JSON.parse(readFileSync43(file2, "utf8"));
99843
+ cfg = JSON.parse(readFileSync44(file2, "utf8"));
99653
99844
  } catch {
99654
99845
  console.error(`refusing to overwrite invalid JSON at ${file2}`);
99655
99846
  process.exit(2);
@@ -99657,21 +99848,21 @@ async function installClaudeMcpConfig() {
99657
99848
  }
99658
99849
  cfg.mcpServers ??= {};
99659
99850
  cfg.mcpServers["errata"] = errataMcpInvocation();
99660
- writeFileSync31(file2, JSON.stringify(cfg, null, 2) + "\n", "utf8");
99851
+ writeFileSync32(file2, JSON.stringify(cfg, null, 2) + "\n", "utf8");
99661
99852
  console.log(`installed Claude Code MCP server config \u2192 ${file2}`);
99662
99853
  console.log(` Claude Code will spawn \`errata mcp\` on workspace open.`);
99663
99854
  console.log(` Tools: errata.search / locate / neighbors / callers_of / what_uses / show / similar`);
99664
99855
  }
99665
99856
  async function installCursorMcpConfig() {
99666
- const { mkdirSync: mkdirSync13, existsSync: existsSync41, readFileSync: readFileSync43, writeFileSync: writeFileSync31 } = await import("node:fs");
99667
- const { join: join50 } = await import("node:path");
99668
- const dir = join50(ROOT, ".cursor");
99857
+ const { mkdirSync: mkdirSync13, existsSync: existsSync41, readFileSync: readFileSync44, writeFileSync: writeFileSync32 } = await import("node:fs");
99858
+ const { join: join51 } = await import("node:path");
99859
+ const dir = join51(ROOT, ".cursor");
99669
99860
  if (!existsSync41(dir)) mkdirSync13(dir, { recursive: true });
99670
- const file2 = join50(dir, "mcp.json");
99861
+ const file2 = join51(dir, "mcp.json");
99671
99862
  let cfg = {};
99672
99863
  if (existsSync41(file2)) {
99673
99864
  try {
99674
- cfg = JSON.parse(readFileSync43(file2, "utf8"));
99865
+ cfg = JSON.parse(readFileSync44(file2, "utf8"));
99675
99866
  } catch {
99676
99867
  console.error(`refusing to overwrite invalid JSON at ${file2}`);
99677
99868
  process.exit(2);
@@ -99679,7 +99870,7 @@ async function installCursorMcpConfig() {
99679
99870
  }
99680
99871
  cfg.mcpServers ??= {};
99681
99872
  cfg.mcpServers["errata"] = errataMcpInvocation();
99682
- writeFileSync31(file2, JSON.stringify(cfg, null, 2) + "\n", "utf8");
99873
+ writeFileSync32(file2, JSON.stringify(cfg, null, 2) + "\n", "utf8");
99683
99874
  console.log(`installed Cursor MCP server config \u2192 ${file2}`);
99684
99875
  console.log(` Cursor will spawn \`errata mcp\` on workspace open.`);
99685
99876
  console.log(` Tools: errata.search / locate / neighbors / callers_of / what_uses`);
@@ -99690,7 +99881,7 @@ async function installCodexHooks(port) {
99690
99881
  const gitRoot = nearestGitRoot(process.cwd());
99691
99882
  const hookRoot = gitRoot && mainCheckoutOfWorktree(gitRoot) ? gitRoot : ROOT;
99692
99883
  const file2 = writeCodexHooks(hookRoot, port);
99693
- const instructions = writeManagedBlock(join49(hookRoot, "AGENTS.md"), {
99884
+ const instructions = writeManagedBlock(join50(hookRoot, "AGENTS.md"), {
99694
99885
  body: AGENTS_POINTER_BODY,
99695
99886
  stable: true
99696
99887
  });
@@ -100136,9 +100327,9 @@ async function cmdDash(args2) {
100136
100327
  await yieldToLoop2();
100137
100328
  try {
100138
100329
  const items = selectDurableMemory(handle2.sharedStore, r.engine.profile, {
100139
- atCommit: readGitRefState(join49(r.root, ".git")).sha ?? void 0
100330
+ atCommit: readGitRefState(join50(r.root, ".git")).sha ?? void 0
100140
100331
  });
100141
- const res = bleedRules(join49(r.root, ".claude", "rules"), items);
100332
+ const res = bleedRules(join50(r.root, ".claude", "rules"), items);
100142
100333
  if (res.written || res.pruned) {
100143
100334
  console.log(
100144
100335
  `[rules:${r.entry.name}] ${res.written} collective principle(s) \u2192 .claude/rules` + (res.pruned ? `, ${res.pruned} pruned` : "")