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

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"];
@@ -1167,6 +1168,11 @@ function versionlessPurl(purl) {
1167
1168
  const lastAt = purl.lastIndexOf("@");
1168
1169
  return lastAt > lastSlash ? purl.slice(0, lastAt) : purl;
1169
1170
  }
1171
+ function splitNameAtVersion(slug2) {
1172
+ const at = slug2.lastIndexOf("@");
1173
+ if (at <= 0) return { name: slug2.trim(), version: null };
1174
+ return { name: slug2.slice(0, at).trim(), version: slug2.slice(at + 1).trim() || null };
1175
+ }
1170
1176
  function parsePackageRef(ref) {
1171
1177
  let rest2 = ref.trim();
1172
1178
  if (rest2.startsWith("pkg:")) {
@@ -1176,9 +1182,7 @@ function parsePackageRef(ref) {
1176
1182
  const q = rest2.search(/[?#]/);
1177
1183
  if (q !== -1) rest2 = rest2.slice(0, q);
1178
1184
  }
1179
- const at = rest2.lastIndexOf("@");
1180
- const name2 = at > 0 ? rest2.slice(0, at) : rest2;
1181
- const version3 = at > 0 ? rest2.slice(at + 1) || null : null;
1185
+ const { name: name2, version: version3 } = splitNameAtVersion(rest2);
1182
1186
  const slug2 = (version3 ? `${name2}@${version3}` : name2).toLowerCase();
1183
1187
  return { name: name2, version: version3, slug: slug2 };
1184
1188
  }
@@ -17625,6 +17629,7 @@ __export(src_exports, {
17625
17629
  PROBLEM_RESOLUTION: () => PROBLEM_RESOLUTION,
17626
17630
  PROJECT_ONLY_EDGE_TYPES: () => PROJECT_ONLY_EDGE_TYPES,
17627
17631
  PROJECT_ONLY_NODE_LABELS: () => PROJECT_ONLY_NODE_LABELS,
17632
+ PROJECT_SYNC_EDGE_TYPES: () => PROJECT_SYNC_EDGE_TYPES,
17628
17633
  QUARANTINE_EXTRACTION_SOURCE_PREFIX: () => QUARANTINE_EXTRACTION_SOURCE_PREFIX,
17629
17634
  REDACTED_CREDENTIAL: () => REDACTED_CREDENTIAL,
17630
17635
  REDACTED_EMAIL: () => REDACTED_EMAIL,
@@ -17744,6 +17749,7 @@ __export(src_exports, {
17744
17749
  sha256Short: () => sha256Short,
17745
17750
  sidecarDropBucket: () => sidecarDropBucket,
17746
17751
  spineDeps: () => spineDeps,
17752
+ splitNameAtVersion: () => splitNameAtVersion,
17747
17753
  splitPnpmKey: () => splitPnpmKey,
17748
17754
  stripAnchorLabels: () => stripAnchorLabels,
17749
17755
  substituteSymbolSummaries: () => substituteSymbolSummaries,
@@ -21452,6 +21458,20 @@ CREATE INDEX IF NOT EXISTS nodes_revisit_true ON nodes(valid_from) WHERE json_ty
21452
21458
  if (revived > 0) this.mutations++;
21453
21459
  return revived;
21454
21460
  }
21461
+ incomingEdgeCoverage(label, edgeTypes, cloudOnly) {
21462
+ if (edgeTypes.length === 0) return { count: 0, total: 0 };
21463
+ const r = this.db.prepare(
21464
+ `SELECT COUNT(*) AS total,
21465
+ COALESCE(SUM(CASE WHEN EXISTS (
21466
+ SELECT 1 FROM edges e WHERE e.to_id = n.id AND e.valid_to IS NULL
21467
+ AND e.type IN (${edgeTypes.map(() => "?").join(",")})
21468
+ ) THEN 1 ELSE 0 END), 0) AS count
21469
+ FROM nodes n
21470
+ WHERE n.label = ? AND n.valid_to IS NULL
21471
+ AND (? = 0 OR json_extract(n.attrs_json, '$.source') = 'cloud')`
21472
+ ).get(...edgeTypes, label, cloudOnly ? 1 : 0);
21473
+ return { count: Number(r.count), total: Number(r.total) };
21474
+ }
21455
21475
  recentEdgeAttrCoverage(marker, attr, limit) {
21456
21476
  const r = this.db.prepare(
21457
21477
  `SELECT COUNT(*) AS total,
@@ -26337,6 +26357,14 @@ var init_principle_sync = __esm({
26337
26357
 
26338
26358
  // ../../packages/local-graph/src/mechanism-liveness.ts
26339
26359
  function evaluateFed(store, d) {
26360
+ if (d.fedIncoming) {
26361
+ const { count: count2, total } = store.incomingEdgeCoverage?.(
26362
+ d.fedIncoming.label,
26363
+ d.fedIncoming.edgeTypes,
26364
+ d.fedIncoming.cloudOnly
26365
+ ) ?? { count: 0, total: 0 };
26366
+ return { count: count2, total, fraction: total === 0 ? 0 : count2 / total };
26367
+ }
26340
26368
  if (d.fedEdges) {
26341
26369
  const { count: count2, total } = store.recentEdgeAttrCoverage(
26342
26370
  d.fedEdges.marker,
@@ -26388,7 +26416,7 @@ function evaluateMechanisms(store, invocations = /* @__PURE__ */ new Map(), mech
26388
26416
  if (d.configCounter && inv?.lastTotals?.[d.configCounter] === 0) verdict = "unconfigured";
26389
26417
  else if ((backlog ?? 0) === 0 && (!hasInput && !d.inputOptional || missingRequiredNodes)) verdict = "no-input";
26390
26418
  else if (!inv || inv.runs === 0) verdict = "never-invoked";
26391
- else if (fed.fraction < (d.fedEdges?.minFraction ?? d.fed?.minFraction ?? 0)) verdict = "starved";
26419
+ else if (fed.fraction < minFractionOf(d)) verdict = "starved";
26392
26420
  else if (stalled) verdict = "stalled";
26393
26421
  else if (effectCount === 0) verdict = "no-effect";
26394
26422
  else verdict = "ok";
@@ -26399,7 +26427,7 @@ function evaluateMechanisms(store, invocations = /* @__PURE__ */ new Map(), mech
26399
26427
  fedCount: fed.count,
26400
26428
  fedTotal: fed.total,
26401
26429
  fedFraction: fed.fraction,
26402
- minFraction: d.fedEdges?.minFraction ?? d.fed?.minFraction ?? 0,
26430
+ minFraction: minFractionOf(d),
26403
26431
  ...inv ? { lastInvokedMs: inv.lastTs } : {},
26404
26432
  runs: inv?.runs ?? 0,
26405
26433
  effectCount,
@@ -26411,6 +26439,9 @@ function evaluateMechanisms(store, invocations = /* @__PURE__ */ new Map(), mech
26411
26439
  };
26412
26440
  });
26413
26441
  }
26442
+ function minFractionOf(d) {
26443
+ return d.fedIncoming?.minFraction ?? d.fedEdges?.minFraction ?? d.fed?.minFraction ?? 0;
26444
+ }
26414
26445
  function formatMechanismStatus(rows, nowMs) {
26415
26446
  return rows.map((r) => {
26416
26447
  const pct = (r.fedFraction * 100).toFixed(r.fedFraction < 0.01 ? 2 : 1);
@@ -26697,6 +26728,25 @@ var init_mechanism_liveness = __esm({
26697
26728
  // reading is IDLE — correct, and it declares no backlog on purpose.
26698
26729
  effectCounter: "alarms",
26699
26730
  note: "steady-state IDLE is healthy; the row exists for its invocation age"
26731
+ },
26732
+ {
26733
+ id: "project-causal-sync",
26734
+ what: "lands the cloud project stratum's SOLVED_BY/FIXED_BY edges onto the knowledge the anchor feed mirrors",
26735
+ // PRODUCER: the anchor feed's causal leg — `fetchProjectAnchors` returns the
26736
+ // edges, `syncProjectAnchors` (apps/daemon/src/project-reanchor.ts) lands or
26737
+ // parks them, on the `anchor-pull` beat. CONSUMERS: every local walk that
26738
+ // crosses Problem→Solution — errata_trace/why/burst over the store, and the
26739
+ // passive priming block that renders a problem with its fix. Before
26740
+ // PJ-sync-causal the feed mirrored 5,054 cloud Solutions on the dev checkout
26741
+ // with not one incoming SOLVED_BY: this row would have read 0.0% for months.
26742
+ pass: "anchor-pull",
26743
+ fedIncoming: { label: "Solution", edgeTypes: ["SOLVED_BY", "FIXED_BY"], cloudOnly: true, minFraction: 0.5 },
26744
+ effectCounter: "edgesLanded",
26745
+ // Parked edges waiting on an endpoint — a flat, non-zero backlog is a stratum
26746
+ // whose other ends never arrive here (a cap, or a gate that refuses them).
26747
+ backlogCounter: "edgesPending",
26748
+ requiresNodes: ["Problem"],
26749
+ 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
26750
  }
26701
26751
  ];
26702
26752
  COLUMN_INPUTS = {
@@ -28994,7 +29044,7 @@ var init_client = __esm({
28994
29044
  "GET",
28995
29045
  `/v2/projects/${encodeURIComponent(projectId)}/anchors?since=${String(Math.max(0, Math.floor(since)))}&limit=${String(limit)}`
28996
29046
  );
28997
- const { nodes } = this.toCastalia({ nodes: res.nodes ?? [], edges: [] });
29047
+ const { nodes, edges } = this.toCastalia({ nodes: res.nodes ?? [], edges: res.edges ?? [] });
28998
29048
  const anchors = (res.anchors ?? []).map((a) => ({
28999
29049
  from: a.fromCanonicalId,
29000
29050
  toSymbolId: a.toSymbolId,
@@ -29002,7 +29052,7 @@ var init_client = __esm({
29002
29052
  attrs: a.attrs ?? {},
29003
29053
  stampedAt: typeof a.stampedAt === "number" ? a.stampedAt : 0
29004
29054
  }));
29005
- return { nodes, anchors, cursor: typeof res.cursor === "number" ? res.cursor : since };
29055
+ return { nodes, edges, causalLeg: Array.isArray(res.edges), anchors, cursor: typeof res.cursor === "number" ? res.cursor : since };
29006
29056
  }
29007
29057
  /** Pull cloud-induced skills + the session-bootstrap prime payload. `seed` is the
29008
29058
  * canonical ids of the agent's recent problems — the cloud ranks the skills whose
@@ -76377,8 +76427,8 @@ var init_report_render = __esm({
76377
76427
 
76378
76428
  // src/cli.ts
76379
76429
  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";
76430
+ import { closeSync as closeSync3, existsSync as existsSync40, openSync as openSync3, readFileSync as readFileSync43, renameSync as renameSync8, statSync as statSync13 } from "node:fs";
76431
+ import { join as join50, resolve as pathResolve2 } from "node:path";
76382
76432
  import { spawn as spawn5 } from "node:child_process";
76383
76433
 
76384
76434
  // src/daemon.ts
@@ -77843,9 +77893,9 @@ var NodeFsHandler = class {
77843
77893
  if (this.fsw.closed) {
77844
77894
  return;
77845
77895
  }
77846
- const dirname17 = sysPath.dirname(file2);
77896
+ const dirname18 = sysPath.dirname(file2);
77847
77897
  const basename10 = sysPath.basename(file2);
77848
- const parent = this.fsw._getWatchedDir(dirname17);
77898
+ const parent = this.fsw._getWatchedDir(dirname18);
77849
77899
  let prevStats = stats;
77850
77900
  if (parent.has(basename10))
77851
77901
  return;
@@ -77872,7 +77922,7 @@ var NodeFsHandler = class {
77872
77922
  prevStats = newStats2;
77873
77923
  }
77874
77924
  } catch (error48) {
77875
- this.fsw._remove(dirname17, basename10);
77925
+ this.fsw._remove(dirname18, basename10);
77876
77926
  }
77877
77927
  } else if (parent.has(basename10)) {
77878
77928
  const at = newStats.atimeMs;
@@ -85786,7 +85836,7 @@ function createWatchBreaker(deps) {
85786
85836
  }
85787
85837
 
85788
85838
  // src/engine.ts
85789
- var DAEMON_VERSION = true ? "2.0.22-dev.4148" : "2.0.0-alpha.0";
85839
+ var DAEMON_VERSION = true ? "2.0.22-dev.4173" : "2.0.0-alpha.0";
85790
85840
  var IGNORED_PATH = /[\\/](?:\.git|node_modules|\.errata|\.claude|\.codex|\.cursor|\.turbo|\.next|dist|coverage|test-results|playwright-report|__pycache__)(?:[\\/]|$)/;
85791
85841
  var IGNORED_NOISE = /castalia\.db|eventlog\.sqlite|turn-cursors/;
85792
85842
  var GIT_OP_MUTE_MS = 4e3;
@@ -88912,7 +88962,7 @@ function invalidateInstanceReceipt(current, destination, failedId, mirrorLegacy)
88912
88962
  // src/multi.ts
88913
88963
  init_dist();
88914
88964
  init_src5();
88915
- import { existsSync as existsSync34, writeFileSync as writeFileSync26 } from "node:fs";
88965
+ import { existsSync as existsSync34, writeFileSync as writeFileSync27 } from "node:fs";
88916
88966
  import { resolve as pathResolve } from "node:path";
88917
88967
 
88918
88968
  // src/principle-sync.ts
@@ -90402,7 +90452,6 @@ function liveCloudClient(src) {
90402
90452
  init_identity2();
90403
90453
 
90404
90454
  // src/project-hydrate.ts
90405
- init_src11();
90406
90455
  init_profile2();
90407
90456
 
90408
90457
  // src/project-reanchor.ts
@@ -90477,6 +90526,62 @@ async function syncHistoryCorrections(opts) {
90477
90526
  }
90478
90527
  }
90479
90528
 
90529
+ // src/project-reanchor.ts
90530
+ init_paths();
90531
+
90532
+ // src/project-sync-landing.ts
90533
+ init_src11();
90534
+ function landCloudNode(store, n, isOwnTwin) {
90535
+ if (store.getNode(n.id)) return "present";
90536
+ if (isOwnTwin) return "own";
90537
+ store.mergeNode(n);
90538
+ return "landed";
90539
+ }
90540
+ function landCloudEdge(store, e, from, to) {
90541
+ if (store.outEdges(from, [e.type]).some((x) => x.to === to)) return false;
90542
+ const id = from === e.from && to === e.to ? e.id : edgeId(from, e.type, to);
90543
+ if (store.getEdge(id)) return false;
90544
+ store.mergeEdge({ ...e, id, from, to, attrs: { ...e.attrs, source: "cloud" } });
90545
+ return true;
90546
+ }
90547
+
90548
+ // src/causal-edge-queue.ts
90549
+ import { readFileSync as readFileSync35, renameSync as renameSync5, writeFileSync as writeFileSync25 } from "node:fs";
90550
+ import { dirname as dirname13, join as join39 } from "node:path";
90551
+ var CAUSAL_EDGE_QUEUE_CAP = 5e3;
90552
+ var CAUSAL_EDGE_TTL_MS = 30 * 24 * 60 * 60 * 1e3;
90553
+ function causalEdgeQueuePath(workspaceConfigDir) {
90554
+ return join39(workspaceConfigDir, "causal-edge-queue.json");
90555
+ }
90556
+ function parkedEdgeKey(e) {
90557
+ return `${e.from}|${e.type}|${e.to}`;
90558
+ }
90559
+ function loadCausalEdgeQueue(path3) {
90560
+ let raw2;
90561
+ try {
90562
+ raw2 = JSON.parse(readFileSync35(path3, "utf8"));
90563
+ } catch {
90564
+ return [];
90565
+ }
90566
+ if (!Array.isArray(raw2)) return [];
90567
+ return raw2.filter(
90568
+ (p) => !!p && typeof p === "object" && typeof p.ts === "number" && typeof p.edge?.from === "string" && typeof p.edge?.to === "string" && typeof p.edge?.type === "string"
90569
+ );
90570
+ }
90571
+ function saveCausalEdgeQueue(path3, queue) {
90572
+ try {
90573
+ const tmp = join39(dirname13(path3), `.${Date.now()}.causal-edge-queue.tmp`);
90574
+ writeFileSync25(tmp, JSON.stringify(queue), "utf8");
90575
+ renameSync5(tmp, path3);
90576
+ } catch {
90577
+ }
90578
+ }
90579
+ function pruneCausalEdgeQueue(queue, now) {
90580
+ const live3 = queue.filter((p) => now - p.ts < CAUSAL_EDGE_TTL_MS);
90581
+ if (live3.length <= CAUSAL_EDGE_QUEUE_CAP) return live3;
90582
+ return [...live3].sort((a, b) => a.ts - b.ts).slice(live3.length - CAUSAL_EDGE_QUEUE_CAP);
90583
+ }
90584
+
90480
90585
  // src/project-reanchor.ts
90481
90586
  var DEFAULT_LIMIT = 50;
90482
90587
  var ANCHOR_SYMBOL_KINDS2 = [
@@ -90676,10 +90781,12 @@ async function reanchorProject(opts) {
90676
90781
  }
90677
90782
  var SYNC_PAGE = 200;
90678
90783
  var SYNC_MAX_PAGES = 25;
90784
+ var SYNC_EDGE_TYPES = new Set(PROJECT_SYNC_EDGE_TYPES);
90679
90785
  async function syncProjectAnchors(opts) {
90680
90786
  const { root, profile, store, cloud, salt } = opts;
90681
90787
  if (!profile.projectId) return { synced: false, reason: "no-project" };
90682
90788
  const projectId = profile.projectId;
90789
+ const clock = opts.now ?? Date.now;
90683
90790
  const key = `${projectId}|${salt}`;
90684
90791
  const reverse = cachedMap(
90685
90792
  reverseCache,
@@ -90688,23 +90795,95 @@ async function syncProjectAnchors(opts) {
90688
90795
  () => buildReverseSymbolMap({ store, salt, projectId })
90689
90796
  );
90690
90797
  const own = cachedMap(ownCache, store, salt, () => collectLastWinsYielding(ownKnowledgeEntries({ store, salt })));
90798
+ const resolveKnowledge = async (id) => store.getNode(id) ? id : lookupLive(store, own, id);
90799
+ const queuePath = opts.edgeQueuePath ?? causalEdgeQueuePath(workspacePaths(root).configDir);
90800
+ let parked = pruneCausalEdgeQueue(loadCausalEdgeQueue(queuePath), clock());
90801
+ let parkedDirty = false;
90802
+ const parkedKeys = new Set(parked.map((p) => parkedEdgeKey(p.edge)));
90691
90803
  const limit = opts.limit ?? SYNC_PAGE;
90692
90804
  const maxPages = opts.maxPages ?? SYNC_MAX_PAGES;
90693
90805
  let anchors = 0;
90694
90806
  let updated = 0;
90695
90807
  let dropped = 0;
90696
90808
  let landed = 0;
90697
- let cursor = profile.projectAnchorCursor ?? 0;
90809
+ let edgesLanded = 0;
90810
+ let edgesParked = 0;
90811
+ let edgesReplayed = 0;
90812
+ let persistedCursor = 0;
90813
+ let cursor = 0;
90814
+ let backfillPending = false;
90815
+ let backfillStarted = false;
90816
+ const settleEdges = async (incoming) => {
90817
+ for (const e of incoming) {
90818
+ if (!SYNC_EDGE_TYPES.has(e.type)) continue;
90819
+ const from = await resolveKnowledge(e.from);
90820
+ const to = from ? await resolveKnowledge(e.to) : null;
90821
+ const k = parkedEdgeKey(e);
90822
+ if (from && to) {
90823
+ if (from !== to && landCloudEdge(store, e, from, to)) edgesLanded++;
90824
+ if (parkedKeys.delete(k)) {
90825
+ parked = parked.filter((p) => parkedEdgeKey(p.edge) !== k);
90826
+ parkedDirty = true;
90827
+ }
90828
+ } else if (!parkedKeys.has(k)) {
90829
+ parkedKeys.add(k);
90830
+ parked.push({ edge: e, ts: clock() });
90831
+ parkedDirty = true;
90832
+ edgesParked++;
90833
+ }
90834
+ }
90835
+ if (parked.length === 0) return;
90836
+ const still = [];
90837
+ for (const p of parked) {
90838
+ const from = await resolveKnowledge(p.edge.from);
90839
+ const to = from ? await resolveKnowledge(p.edge.to) : null;
90840
+ if (from && to) {
90841
+ if (from !== to && landCloudEdge(store, p.edge, from, to)) edgesReplayed++;
90842
+ parkedKeys.delete(parkedEdgeKey(p.edge));
90843
+ parkedDirty = true;
90844
+ } else {
90845
+ still.push(p);
90846
+ }
90847
+ }
90848
+ parked = still;
90849
+ };
90850
+ const flushParked = () => {
90851
+ if (!parkedDirty) return;
90852
+ parked = pruneCausalEdgeQueue(parked, clock());
90853
+ saveCausalEdgeQueue(queuePath, parked);
90854
+ parkedDirty = false;
90855
+ };
90698
90856
  try {
90699
90857
  await syncHistoryCorrections({ root, profile, store, cloud, ...opts.correctionMirrors ? { mirrors: opts.correctionMirrors } : {} });
90858
+ persistedCursor = profile.projectAnchorCursor ?? 0;
90859
+ backfillPending = !profile.projectCausalBackfillAt;
90860
+ cursor = backfillPending ? 0 : persistedCursor;
90700
90861
  for (let page = 0; page < maxPages; page++) {
90862
+ if (page > 0) await new Promise((r) => setImmediate(r));
90701
90863
  const res = await cloud.getProjectAnchors(projectId, cursor, limit);
90864
+ if (backfillPending) {
90865
+ backfillPending = false;
90866
+ if (res.causalLeg) {
90867
+ profile.projectCausalBackfillAt = clock();
90868
+ profile.projectAnchorCursor = 0;
90869
+ saveProfile(root, profile);
90870
+ backfillStarted = persistedCursor > 0;
90871
+ } else if (cursor !== persistedCursor) {
90872
+ cursor = persistedCursor;
90873
+ page--;
90874
+ continue;
90875
+ }
90876
+ }
90702
90877
  if (res.anchors.length === 0) break;
90703
90878
  if ((await reverse.get()).size === 0 && (await reverse.refresh()).size === 0) {
90704
90879
  return { synced: false, reason: "no-local-symbols" };
90705
90880
  }
90706
- const byId = new Map(res.nodes.map((n) => [n.id, n]));
90707
- const now = Date.now();
90881
+ for (const node2 of res.nodes) {
90882
+ if (store.getNode(node2.id)) continue;
90883
+ const ownTwin = await lookupLive(store, own, node2.id) !== null;
90884
+ if (landCloudNode(store, node2, ownTwin) === "landed") landed++;
90885
+ }
90886
+ const now = clock();
90708
90887
  for (const a of res.anchors) {
90709
90888
  if (a.type !== "ANCHORED_AT") continue;
90710
90889
  const localTo = await lookupLive(store, reverse, a.toSymbolId);
@@ -90712,16 +90891,10 @@ async function syncProjectAnchors(opts) {
90712
90891
  dropped++;
90713
90892
  continue;
90714
90893
  }
90715
- let from = store.getNode(a.from) ? a.from : await lookupLive(store, own, a.from);
90894
+ const from = await resolveKnowledge(a.from);
90716
90895
  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;
90896
+ dropped++;
90897
+ continue;
90725
90898
  }
90726
90899
  const existing = existingAnchor(store, from, localTo);
90727
90900
  const id = existing?.id ?? edgeId(from, "ANCHORED_AT", localTo);
@@ -90753,6 +90926,8 @@ async function syncProjectAnchors(opts) {
90753
90926
  if (existing) updated++;
90754
90927
  else anchors++;
90755
90928
  }
90929
+ await settleEdges(res.edges ?? []);
90930
+ flushParked();
90756
90931
  const next = typeof res.cursor === "number" && res.cursor > cursor ? res.cursor : cursor;
90757
90932
  if (next !== cursor) {
90758
90933
  cursor = next;
@@ -90761,8 +90936,23 @@ async function syncProjectAnchors(opts) {
90761
90936
  }
90762
90937
  if (res.anchors.length < limit) break;
90763
90938
  }
90764
- return { synced: true, anchors, updated, dropped, landed, cursor };
90939
+ await settleEdges([]);
90940
+ flushParked();
90941
+ return {
90942
+ synced: true,
90943
+ anchors,
90944
+ updated,
90945
+ dropped,
90946
+ landed,
90947
+ cursor,
90948
+ edgesLanded,
90949
+ edgesParked,
90950
+ edgesReplayed,
90951
+ edgesPending: parked.length,
90952
+ backfillStarted
90953
+ };
90765
90954
  } catch (err2) {
90955
+ flushParked();
90766
90956
  return { synced: false, reason: "error", detail: err2 instanceof Error ? err2.message : String(err2) };
90767
90957
  }
90768
90958
  }
@@ -90780,24 +90970,16 @@ async function hydrateProject(opts) {
90780
90970
  let landedNodes = 0;
90781
90971
  let ownNodes = 0;
90782
90972
  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++;
90973
+ const landing = landCloudNode(store, n, own.has(n.id));
90974
+ if (landing === "own") ownNodes++;
90975
+ else if (landing === "landed") landedNodes++;
90790
90976
  }
90791
90977
  let landedEdges = 0;
90792
90978
  for (const e of res.edges) {
90793
90979
  const from = localId(e.from);
90794
90980
  const to = localId(e.to);
90795
90981
  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++;
90982
+ if (landCloudEdge(store, e, from, to)) landedEdges++;
90801
90983
  }
90802
90984
  profile.projectHydratedAt = Date.now();
90803
90985
  saveProfile(root, profile);
@@ -91061,8 +91243,8 @@ async function syncHistoryRevisionPage(opts) {
91061
91243
  init_src7();
91062
91244
  init_src();
91063
91245
  import { execFile as execFile6 } from "node:child_process";
91064
- import { readFileSync as readFileSync35 } from "node:fs";
91065
- import { join as join39 } from "node:path";
91246
+ import { readFileSync as readFileSync36 } from "node:fs";
91247
+ import { join as join40 } from "node:path";
91066
91248
  import { promisify as promisify5 } from "node:util";
91067
91249
 
91068
91250
  // src/history-walk.ts
@@ -91614,7 +91796,7 @@ async function defaultGit(root, args2) {
91614
91796
  function readIgnoreLines(root, profile) {
91615
91797
  let lines = [];
91616
91798
  try {
91617
- lines = readFileSync35(join39(root, ".errataignore"), "utf8").split("\n");
91799
+ lines = readFileSync36(join40(root, ".errataignore"), "utf8").split("\n");
91618
91800
  } catch {
91619
91801
  }
91620
91802
  return [...lines, ...profile.ignoreExtra ?? []].map((l) => l.trim()).filter((l) => l && !l.startsWith("#"));
@@ -92190,8 +92372,8 @@ async function startHistoryStage(root, input, client, walk11 = {}) {
92190
92372
  init_cloud_auth();
92191
92373
  import { createHash as createHash19 } from "node:crypto";
92192
92374
  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";
92375
+ import { existsSync as existsSync32, writeFileSync as writeFileSync26 } from "node:fs";
92376
+ import { join as join41 } from "node:path";
92195
92377
 
92196
92378
  // src/device-poll.ts
92197
92379
  var THROTTLED_POLL_MIN_WAIT_MS = 11e3;
@@ -92650,9 +92832,9 @@ function applyLinkDecision(root, profile, config2, decision, now = Date.now) {
92650
92832
  delete nextProfile.projectLinkHold;
92651
92833
  let wroteIgnore = false;
92652
92834
  if (decision.writeIgnoreStarter !== false) {
92653
- const target = join40(root, ".errataignore");
92835
+ const target = join41(root, ".errataignore");
92654
92836
  if (!existsSync32(target)) {
92655
- writeFileSync25(target, IGNORE_STARTER, "utf8");
92837
+ writeFileSync26(target, IGNORE_STARTER, "utf8");
92656
92838
  wroteIgnore = true;
92657
92839
  }
92658
92840
  }
@@ -92666,12 +92848,12 @@ init_registry();
92666
92848
  // src/adopt.ts
92667
92849
  init_git_remote();
92668
92850
  import { existsSync as existsSync33 } from "node:fs";
92669
- import { dirname as dirname13, join as join41 } from "node:path";
92851
+ import { dirname as dirname14, join as join42 } from "node:path";
92670
92852
  function findGitRoot(absPath) {
92671
92853
  let dir = absPath;
92672
92854
  for (let depth = 0; depth < 64; depth++) {
92673
- if (existsSync33(join41(dir, ".git"))) return dir;
92674
- const parent = dirname13(dir);
92855
+ if (existsSync33(join42(dir, ".git"))) return dir;
92856
+ const parent = dirname14(dir);
92675
92857
  if (parent === dir) return null;
92676
92858
  dir = parent;
92677
92859
  }
@@ -93388,7 +93570,7 @@ async function startMultiDaemon(opts = {}) {
93388
93570
  records.push(rec);
93389
93571
  void ambientLinkAll();
93390
93572
  try {
93391
- writeFileSync26(
93573
+ writeFileSync27(
93392
93574
  rec.engine.paths.daemonLock,
93393
93575
  daemonLockPayload({
93394
93576
  pid: process.pid,
@@ -93767,7 +93949,7 @@ async function startMultiDaemon(opts = {}) {
93767
93949
  baseUrl = `http://127.0.0.1:${port}`;
93768
93950
  try {
93769
93951
  ensureDir(globalDir());
93770
- writeFileSync26(
93952
+ writeFileSync27(
93771
93953
  lockPath,
93772
93954
  daemonLockPayload({ pid: process.pid, webUiUrl: baseUrl, processStartedAt: PROCESS_STARTED_AT, entry: SELF_ENTRY, version: DAEMON_VERSION }),
93773
93955
  "utf8"
@@ -93776,7 +93958,7 @@ async function startMultiDaemon(opts = {}) {
93776
93958
  }
93777
93959
  for (const r of records) {
93778
93960
  try {
93779
- writeFileSync26(
93961
+ writeFileSync27(
93780
93962
  r.engine.paths.daemonLock,
93781
93963
  daemonLockPayload({
93782
93964
  pid: process.pid,
@@ -93818,6 +94000,7 @@ async function startMultiDaemon(opts = {}) {
93818
94000
  const lastAnchorPull = /* @__PURE__ */ new Map();
93819
94001
  const pullProjectAnchors = async (r, client, salt) => {
93820
94002
  const donePass = markPass(`anchor-pull:${r.engine.profile.name}`);
94003
+ const pullStartedAt = Date.now();
93821
94004
  const beforeCorrections = r.engine.profile.projectHistoryCorrectionCursor ?? 0;
93822
94005
  const sync = await syncProjectAnchors({
93823
94006
  root: r.root,
@@ -93839,10 +94022,22 @@ async function startMultiDaemon(opts = {}) {
93839
94022
  console.warn(`[errata] history revision reconciliation failed for ${r.engine.profile.name}: ${err2 instanceof Error ? err2.message : String(err2)}`);
93840
94023
  }
93841
94024
  if (sync.synced) {
93842
- if (sync.anchors + sync.updated > 0) {
94025
+ appendPassLedger(r.engine.paths.configDir, "anchor-pull", Date.now() - pullStartedAt, {
94026
+ anchorsLanded: sync.anchors,
94027
+ anchorsUpdated: sync.updated,
94028
+ nodesLanded: sync.landed,
94029
+ edgesLanded: sync.edgesLanded + sync.edgesReplayed,
94030
+ edgesParked: sync.edgesParked,
94031
+ edgesReplayed: sync.edgesReplayed,
94032
+ edgesPending: sync.edgesPending
94033
+ });
94034
+ if (sync.backfillStarted) {
94035
+ console.log(`[errata] causal re-walk started for ${r.engine.profile.name} \u2014 anchor cursor reset to 0 once`);
94036
+ }
94037
+ if (sync.anchors + sync.updated + sync.landed + sync.edgesLanded + sync.edgesReplayed > 0) {
93843
94038
  r.engine.markContextDirty();
93844
94039
  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})`
94040
+ `[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
94041
  );
93847
94042
  }
93848
94043
  } else if (sync.reason === "error") {
@@ -95258,7 +95453,7 @@ import { spawnSync as spawnSync2 } from "node:child_process";
95258
95453
 
95259
95454
  // src/codex-runtime.ts
95260
95455
  import { readdirSync as readdirSync13, statSync as statSync10 } from "node:fs";
95261
- import { join as join42 } from "node:path";
95456
+ import { join as join43 } from "node:path";
95262
95457
  function resolveCodexExecutable(options = {}) {
95263
95458
  const platform = options.platform ?? process.platform;
95264
95459
  const env2 = options.env ?? process.env;
@@ -95273,13 +95468,13 @@ function resolveCodexExecutable(options = {}) {
95273
95468
  };
95274
95469
  for (const dir of (env2["PATH"] ?? env2["Path"] ?? "").split(";")) {
95275
95470
  if (!dir.trim()) continue;
95276
- const path3 = join42(dir.trim().replace(/^"|"$/g, ""), "codex.exe");
95471
+ const path3 = join43(dir.trim().replace(/^"|"$/g, ""), "codex.exe");
95277
95472
  if (fileTime(path3) !== null) return path3;
95278
95473
  }
95279
95474
  if (!env2["LOCALAPPDATA"]) return "codex";
95280
- const root = join42(env2["LOCALAPPDATA"], "OpenAI", "Codex", "bin");
95475
+ const root = join43(env2["LOCALAPPDATA"], "OpenAI", "Codex", "bin");
95281
95476
  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));
95477
+ 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
95478
  return candidates[0]?.path ?? "codex";
95284
95479
  } catch {
95285
95480
  return "codex";
@@ -95418,14 +95613,14 @@ async function diagnoseInstallation(cfg, dependencies) {
95418
95613
 
95419
95614
  // src/codex-doctor.ts
95420
95615
  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";
95616
+ import { readFileSync as readFileSync38, statSync as statSync11 } from "node:fs";
95617
+ import { join as join45 } from "node:path";
95423
95618
  import { createInterface } from "node:readline";
95424
95619
 
95425
95620
  // 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";
95621
+ import { existsSync as existsSync35, mkdirSync as mkdirSync9, readFileSync as readFileSync37, renameSync as renameSync6, unlinkSync as unlinkSync5, writeFileSync as writeFileSync28 } from "node:fs";
95427
95622
  import { homedir as homedir7 } from "node:os";
95428
- import { join as join43 } from "node:path";
95623
+ import { join as join44 } from "node:path";
95429
95624
 
95430
95625
  // src/hook-commands.ts
95431
95626
  function hookCurlCommand(port, path3 = "/api/hook") {
@@ -95629,34 +95824,34 @@ function buildCodexRelaySource(workspaceRoot) {
95629
95824
  init_checkout_root();
95630
95825
  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
95826
  function writeRelay(file2, source) {
95632
- if (existsSync35(file2) && readFileSync36(file2, "utf8") === source) return;
95827
+ if (existsSync35(file2) && readFileSync37(file2, "utf8") === source) return;
95633
95828
  const temp = `${file2}.${process.pid}.tmp`;
95634
95829
  try {
95635
- writeFileSync27(temp, source, { encoding: "utf8", mode: 384 });
95636
- renameSync5(temp, file2);
95830
+ writeFileSync28(temp, source, { encoding: "utf8", mode: 384 });
95831
+ renameSync6(temp, file2);
95637
95832
  } finally {
95638
95833
  if (existsSync35(temp)) unlinkSync5(temp);
95639
95834
  }
95640
95835
  }
95641
95836
  function refreshCodexRelay(root) {
95642
- const config2 = join43(root, ".codex", "config.toml");
95837
+ const config2 = join44(root, ".codex", "config.toml");
95643
95838
  if (!existsSync35(config2)) return "absent";
95644
- const existing = readFileSync36(config2, "utf8");
95839
+ const existing = readFileSync37(config2, "utf8");
95645
95840
  if (!existing.includes(CODEX_HOOKS_BEGIN) && !existing.includes(CODEX_HOOKS_END)) return "absent";
95646
95841
  replaceCodexHooks(existing, "");
95647
- const relay = join43(root, ".codex", "hooks", "errata-relay.mjs");
95648
- const prior = existsSync35(relay) ? readFileSync36(relay, "utf8") : "";
95842
+ const relay = join44(root, ".codex", "hooks", "errata-relay.mjs");
95843
+ const prior = existsSync35(relay) ? readFileSync37(relay, "utf8") : "";
95649
95844
  if (prior && !prior.startsWith("// errata-managed: regenerated by errata install-hooks codex")) {
95650
95845
  throw new Error("Codex relay is not Errata-managed; preserved it. Run errata install-hooks codex to explicitly replace it.");
95651
95846
  }
95652
95847
  const source = buildCodexRelaySource(checkoutRootOf(root));
95653
95848
  if (prior === source) return "current";
95654
- mkdirSync9(join43(root, ".codex", "hooks"), { recursive: true });
95849
+ mkdirSync9(join44(root, ".codex", "hooks"), { recursive: true });
95655
95850
  writeRelay(relay, source);
95656
95851
  return "updated";
95657
95852
  }
95658
- function hasCodexConfig(root, codexHome = process.env["CODEX_HOME"] || join43(homedir7(), ".codex")) {
95659
- return existsSync35(join43(root, ".codex")) || existsSync35(codexHome);
95853
+ function hasCodexConfig(root, codexHome = process.env["CODEX_HOME"] || join44(homedir7(), ".codex")) {
95854
+ return existsSync35(join44(root, ".codex")) || existsSync35(codexHome);
95660
95855
  }
95661
95856
  function replaceCodexHooks(existing, block) {
95662
95857
  const begin = existing.indexOf(CODEX_HOOKS_BEGIN);
@@ -95672,14 +95867,14 @@ function replaceCodexHooks(existing, block) {
95672
95867
  return existing.trimEnd() + (existing.trim() ? "\n\n" : "") + block;
95673
95868
  }
95674
95869
  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");
95870
+ const dir = join44(root, ".codex");
95871
+ const file2 = join44(dir, "config.toml");
95872
+ const relay = join44(dir, "hooks", "errata-relay.mjs");
95678
95873
  const block = buildCodexHooksToml(port, { nodePath, relayPath: relay });
95679
- const final = replaceCodexHooks(existsSync35(file2) ? readFileSync36(file2, "utf8") : "", block);
95680
- mkdirSync9(join43(dir, "hooks"), { recursive: true });
95874
+ const final = replaceCodexHooks(existsSync35(file2) ? readFileSync37(file2, "utf8") : "", block);
95875
+ mkdirSync9(join44(dir, "hooks"), { recursive: true });
95681
95876
  writeRelay(relay, buildCodexRelaySource(checkoutRootOf(root)));
95682
- if (!existsSync35(file2) || readFileSync36(file2, "utf8") !== final) writeFileSync27(file2, final, "utf8");
95877
+ if (!existsSync35(file2) || readFileSync37(file2, "utf8") !== final) writeFileSync28(file2, final, "utf8");
95683
95878
  return file2;
95684
95879
  }
95685
95880
 
@@ -95688,7 +95883,7 @@ init_checkout_root();
95688
95883
  function inspectCodexRelay(cwd) {
95689
95884
  const root = nearestGitRoot(cwd) ?? cwd;
95690
95885
  try {
95691
- const source = readFileSync37(join44(root, ".codex", "hooks", "errata-relay.mjs"), "utf8");
95886
+ const source = readFileSync38(join45(root, ".codex", "hooks", "errata-relay.mjs"), "utf8");
95692
95887
  if (source === buildCodexRelaySource(checkoutRootOf(root))) {
95693
95888
  return { id: "codex_relay", status: "pass", detail: "Installed Codex relay matches this Errata version" };
95694
95889
  }
@@ -95699,8 +95894,8 @@ function inspectCodexRelay(cwd) {
95699
95894
  function inspectCodexContext(cwd) {
95700
95895
  const root = checkoutRootOf(nearestGitRoot(cwd) ?? cwd);
95701
95896
  try {
95702
- const file2 = join44(root, ".errata", "context.md");
95703
- if (statSync11(file2).size <= 128 * 1024 && readFileSync37(file2, "utf8").trim()) {
95897
+ const file2 = join45(root, ".errata", "context.md");
95898
+ if (statSync11(file2).size <= 128 * 1024 && readFileSync38(file2, "utf8").trim()) {
95704
95899
  return { id: "codex_context", status: "pass", detail: "Saved workspace context is readable by the relay; this does not prove live daemon freshness" };
95705
95900
  }
95706
95901
  } catch {
@@ -95878,9 +96073,9 @@ function consolidationGapMs(lastPassMs, policy) {
95878
96073
 
95879
96074
  // src/codex-context-plugin.ts
95880
96075
  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";
96076
+ import { cpSync as cpSync2, existsSync as existsSync36, mkdirSync as mkdirSync10, readFileSync as readFileSync39, renameSync as renameSync7, writeFileSync as writeFileSync29 } from "node:fs";
95882
96077
  import { homedir as homedir8 } from "node:os";
95883
- import { join as join45 } from "node:path";
96078
+ import { join as join46 } from "node:path";
95884
96079
  import { fileURLToPath as fileURLToPath2 } from "node:url";
95885
96080
 
95886
96081
  // ../../node_modules/.pnpm/smol-toml@1.6.1/node_modules/smol-toml/dist/error.js
@@ -96578,23 +96773,23 @@ var NAME = "errata-context";
96578
96773
  var PREFIX2 = `./.errata/plugins/${NAME}/`;
96579
96774
  var object2 = (value) => value !== null && typeof value === "object" && !Array.isArray(value) ? value : {};
96580
96775
  function readText(file2) {
96581
- return existsSync36(file2) ? readFileSync38(file2, "utf8") : "";
96776
+ return existsSync36(file2) ? readFileSync39(file2, "utf8") : "";
96582
96777
  }
96583
96778
  function writeChanged(file2, content) {
96584
96779
  if (readText(file2) === content) return;
96585
96780
  const temp = `${file2}.${process.pid}.tmp`;
96586
- writeFileSync28(temp, content, "utf8");
96587
- renameSync6(temp, file2);
96781
+ writeFileSync29(temp, content, "utf8");
96782
+ renameSync7(temp, file2);
96588
96783
  }
96589
96784
  function bundledContextPlugin() {
96590
96785
  const packaged = fileURLToPath2(new URL("./resources/context-plugin/", import.meta.url));
96591
- if (existsSync36(join45(packaged, ".codex-plugin/plugin.json"))) return packaged;
96786
+ if (existsSync36(join46(packaged, ".codex-plugin/plugin.json"))) return packaged;
96592
96787
  return fileURLToPath2(new URL("../dist/resources/context-plugin/", import.meta.url));
96593
96788
  }
96594
96789
  function refreshCodexContextPlugin(root) {
96595
- const file2 = join45(root, ".agents", "plugins", "marketplace.json");
96790
+ const file2 = join46(root, ".agents", "plugins", "marketplace.json");
96596
96791
  if (!existsSync36(file2)) return false;
96597
- const marketplace = JSON.parse(readFileSync38(file2, "utf8"));
96792
+ const marketplace = JSON.parse(readFileSync39(file2, "utf8"));
96598
96793
  const entries = Array.isArray(marketplace.plugins) ? marketplace.plugins : [];
96599
96794
  const entry = entries.map(object2).find((value) => value.name === NAME && String(object2(value.source).path).startsWith(PREFIX2));
96600
96795
  if (!entry) return false;
@@ -96605,24 +96800,24 @@ function refreshCodexContextPlugin(root) {
96605
96800
  function installCodexContextPlugin(root, options = {}) {
96606
96801
  const bundle = options.bundle ?? bundledContextPlugin();
96607
96802
  const manifest = JSON.parse(
96608
- readFileSync38(join45(bundle, ".codex-plugin/plugin.json"), "utf8")
96803
+ readFileSync39(join46(bundle, ".codex-plugin/plugin.json"), "utf8")
96609
96804
  );
96610
96805
  if (manifest.name !== NAME || typeof manifest.version !== "string" || !/^[\w.-]+$/.test(manifest.version)) {
96611
96806
  throw new Error("Invalid bundled Errata Context manifest.");
96612
96807
  }
96613
- const checksums = readFileSync38(join45(bundle, "SHA256SUMS"), "utf8");
96808
+ const checksums = readFileSync39(join46(bundle, "SHA256SUMS"), "utf8");
96614
96809
  for (const line of checksums.trim().split("\n")) {
96615
96810
  const match2 = /^([a-f0-9]{64}) ([\w./-]+)$/.exec(line);
96616
96811
  if (!match2 || match2[2].startsWith("/") || match2[2].split("/").includes("..")) {
96617
96812
  throw new Error("Invalid bundled Errata Context checksum manifest.");
96618
96813
  }
96619
- const actual = createHash20("sha256").update(readFileSync38(join45(bundle, match2[2]))).digest("hex");
96814
+ const actual = createHash20("sha256").update(readFileSync39(join46(bundle, match2[2]))).digest("hex");
96620
96815
  if (actual !== match2[1])
96621
96816
  throw new Error(`Bundled Errata Context checksum mismatch: ${match2[2]}`);
96622
96817
  }
96623
96818
  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");
96819
+ const plugin = join46(root, ".errata", "plugins", NAME, release);
96820
+ const marketplaceFile = join46(root, ".agents", "plugins", "marketplace.json");
96626
96821
  const priorMarketplace = readText(marketplaceFile);
96627
96822
  const marketplace = priorMarketplace ? JSON.parse(priorMarketplace) : {
96628
96823
  name: "errata-local",
@@ -96643,12 +96838,12 @@ function installCodexContextPlugin(root, options = {}) {
96643
96838
  );
96644
96839
  }
96645
96840
  const key = `${NAME}@${marketplace.name}`;
96646
- const configFile = join45(root, ".codex", "config.toml");
96841
+ const configFile = join46(root, ".codex", "config.toml");
96647
96842
  const config2 = readText(configFile);
96648
96843
  const parsed = parse4(config2);
96649
96844
  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);
96845
+ const codexHome = options.codexHome ?? process.env["CODEX_HOME"] ?? join46(homedir8(), ".codex");
96846
+ const globalPlugins = object2(parse4(readText(join46(codexHome, "config.toml"))).plugins);
96652
96847
  const disabledGlobally = Object.entries(globalPlugins).some(
96653
96848
  ([name2, value]) => (name2 === NAME || name2.startsWith(`${NAME}@`)) && object2(value).enabled === false
96654
96849
  );
@@ -96672,13 +96867,13 @@ enabled = ${enabled}
96672
96867
  mkdirSync10(plugin, { recursive: true });
96673
96868
  cpSync2(bundle, plugin, { recursive: true });
96674
96869
  writeChanged(
96675
- join45(plugin, ".mcp.json"),
96870
+ join46(plugin, ".mcp.json"),
96676
96871
  JSON.stringify(
96677
96872
  {
96678
96873
  mcpServers: {
96679
96874
  errata_context: {
96680
96875
  command: options.nodePath ?? process.execPath,
96681
- args: [join45(plugin, "dist", "mcp-server.mjs")],
96876
+ args: [join46(plugin, "dist", "mcp-server.mjs")],
96682
96877
  env: { ERRATA_WORKSPACE: root, ERRATA_CONTEXT_VERSION: manifest.version }
96683
96878
  }
96684
96879
  }
@@ -96687,8 +96882,8 @@ enabled = ${enabled}
96687
96882
  2
96688
96883
  ) + "\n"
96689
96884
  );
96690
- mkdirSync10(join45(root, ".agents", "plugins"), { recursive: true });
96691
- mkdirSync10(join45(root, ".codex"), { recursive: true });
96885
+ mkdirSync10(join46(root, ".agents", "plugins"), { recursive: true });
96886
+ mkdirSync10(join46(root, ".codex"), { recursive: true });
96692
96887
  writeChanged(marketplaceFile, JSON.stringify(marketplace, null, 2) + "\n");
96693
96888
  writeChanged(configFile, nextConfig);
96694
96889
  return { plugin, enabled, marketplace: marketplaceFile };
@@ -96696,15 +96891,15 @@ enabled = ${enabled}
96696
96891
 
96697
96892
  // src/codex-hook-refresh.ts
96698
96893
  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";
96894
+ import { existsSync as existsSync37, readdirSync as readdirSync14, readFileSync as readFileSync40 } from "node:fs";
96895
+ import { dirname as dirname15, join as join47, resolve as resolve8 } from "node:path";
96701
96896
  init_registry();
96702
96897
  function codexHookRoots(roots) {
96703
96898
  const found = new Set(roots.map((root) => resolve8(root)));
96704
96899
  for (const root of [...found]) {
96705
96900
  const main2 = mainCheckoutOfWorktree(root) ?? root;
96706
96901
  found.add(main2);
96707
- const dir = join46(main2, ".git", "worktrees");
96902
+ const dir = join47(main2, ".git", "worktrees");
96708
96903
  if (!existsSync37(dir)) continue;
96709
96904
  let names;
96710
96905
  try {
@@ -96714,7 +96909,7 @@ function codexHookRoots(roots) {
96714
96909
  }
96715
96910
  for (const name2 of names) {
96716
96911
  try {
96717
- const checkout = dirname14(readFileSync39(join46(dir, name2, "gitdir"), "utf8").trim());
96912
+ const checkout = dirname15(readFileSync40(join47(dir, name2, "gitdir"), "utf8").trim());
96718
96913
  if (mainCheckoutOfWorktree(checkout) === main2) found.add(checkout);
96719
96914
  } catch {
96720
96915
  }
@@ -96736,9 +96931,9 @@ function refreshInstalledCodexRelays(roots = listWorkspaceEntries().map((entry)
96736
96931
  }
96737
96932
 
96738
96933
  // src/claude-statusline.ts
96739
- import { existsSync as existsSync38, mkdirSync as mkdirSync11, readFileSync as readFileSync40, writeFileSync as writeFileSync29 } from "node:fs";
96934
+ import { existsSync as existsSync38, mkdirSync as mkdirSync11, readFileSync as readFileSync41, writeFileSync as writeFileSync30 } from "node:fs";
96740
96935
  import { homedir as homedir9 } from "node:os";
96741
- import { dirname as dirname15, join as join47 } from "node:path";
96936
+ import { dirname as dirname16, join as join48 } from "node:path";
96742
96937
  var STATUSLINE_RELAY_SOURCE = String.raw`// errata-managed: regenerated by errata init / install-hooks claude
96743
96938
  import { readFileSync } from 'node:fs';
96744
96939
 
@@ -96786,8 +96981,8 @@ function isSameInstall(value, relay) {
96786
96981
  return command.includes(relay.replace(/\\/g, "/").toLowerCase());
96787
96982
  }
96788
96983
  function userClaudeSettingsPath() {
96789
- const base = process.env["CLAUDE_CONFIG_DIR"] ?? join47(homedir9(), ".claude");
96790
- return join47(base, "settings.json");
96984
+ const base = process.env["CLAUDE_CONFIG_DIR"] ?? join48(homedir9(), ".claude");
96985
+ return join48(base, "settings.json");
96791
96986
  }
96792
96987
  function ensureUserStatusLine(opts) {
96793
96988
  const env2 = opts.env ?? process.env;
@@ -96797,21 +96992,21 @@ function ensureUserStatusLine(opts) {
96797
96992
  let settings = {};
96798
96993
  if (existsSync38(settingsPath)) {
96799
96994
  try {
96800
- const parsed = JSON.parse(readFileSync40(settingsPath, "utf8"));
96995
+ const parsed = JSON.parse(readFileSync41(settingsPath, "utf8"));
96801
96996
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return "unreadable";
96802
96997
  settings = parsed;
96803
96998
  } catch {
96804
96999
  return "unreadable";
96805
97000
  }
96806
97001
  }
96807
- const relay = join47(opts.relayDir, STATUSLINE_RELAY_FILE);
97002
+ const relay = join48(opts.relayDir, STATUSLINE_RELAY_FILE);
96808
97003
  const keep = (value) => value !== void 0 && (!isErrataStatusLine(value) || !isSameInstall(value, relay));
96809
97004
  const ownMain = keep(settings["statusLine"]);
96810
97005
  const ownRows = keep(settings["subagentStatusLine"]);
96811
97006
  if (ownMain && ownRows) return "kept-own";
96812
97007
  mkdirSync11(opts.relayDir, { recursive: true });
96813
- if (!existsSync38(relay) || readFileSync40(relay, "utf8") !== STATUSLINE_RELAY_SOURCE) {
96814
- writeFileSync29(relay, STATUSLINE_RELAY_SOURCE, "utf8");
97008
+ if (!existsSync38(relay) || readFileSync41(relay, "utf8") !== STATUSLINE_RELAY_SOURCE) {
97009
+ writeFileSync30(relay, STATUSLINE_RELAY_SOURCE, "utf8");
96815
97010
  }
96816
97011
  const nodePath = opts.nodePath ?? process.execPath;
96817
97012
  const next = {
@@ -96822,8 +97017,8 @@ function ensureUserStatusLine(opts) {
96822
97017
  return ownMain ? "kept-own" : "unchanged";
96823
97018
  }
96824
97019
  Object.assign(settings, next);
96825
- mkdirSync11(dirname15(settingsPath), { recursive: true });
96826
- writeFileSync29(settingsPath, JSON.stringify(settings, null, 2) + "\n", "utf8");
97020
+ mkdirSync11(dirname16(settingsPath), { recursive: true });
97021
+ writeFileSync30(settingsPath, JSON.stringify(settings, null, 2) + "\n", "utf8");
96827
97022
  return "installed";
96828
97023
  }
96829
97024
  function describeStatusLineOutcome(outcome) {
@@ -96843,8 +97038,8 @@ function describeStatusLineOutcome(outcome) {
96843
97038
 
96844
97039
  // src/claude-mods.ts
96845
97040
  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";
97041
+ 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";
97042
+ import { delimiter as delimiter2, dirname as dirname17, join as join49, relative as relative8, resolve as resolve9, sep as sep5 } from "node:path";
96848
97043
  import { fileURLToPath as fileURLToPath3 } from "node:url";
96849
97044
  var CLAUDE_PLUGIN_DIRS_ENV = "CLAUDE_CODE_PLUGIN_DIRS";
96850
97045
  var HASH_FILE = ".errata-mod-hash";
@@ -96859,7 +97054,7 @@ function isEngineOwned(relPath) {
96859
97054
  function listFiles(root, dir = root) {
96860
97055
  const out2 = [];
96861
97056
  for (const name2 of readdirSync15(dir)) {
96862
- const abs = join48(dir, name2);
97057
+ const abs = join49(dir, name2);
96863
97058
  if (isEngineOwned(relative8(root, abs))) continue;
96864
97059
  if (statSync12(abs).isDirectory()) out2.push(...listFiles(root, abs));
96865
97060
  else out2.push(abs);
@@ -96871,14 +97066,14 @@ function modHash(dir) {
96871
97066
  for (const abs of listFiles(dir).sort()) {
96872
97067
  h.update(relative8(dir, abs).split(sep5).join("/"));
96873
97068
  h.update("\0");
96874
- h.update(readFileSync41(abs));
97069
+ h.update(readFileSync42(abs));
96875
97070
  h.update("\0");
96876
97071
  }
96877
97072
  return h.digest("hex");
96878
97073
  }
96879
97074
  function bundledMods(bundleDir) {
96880
97075
  if (!existsSync39(bundleDir)) return [];
96881
- return readdirSync15(bundleDir).filter((name2) => existsSync39(join48(bundleDir, name2, ".claude-plugin", "plugin.json")));
97076
+ return readdirSync15(bundleDir).filter((name2) => existsSync39(join49(bundleDir, name2, ".claude-plugin", "plugin.json")));
96882
97077
  }
96883
97078
  function sameDir(a, b) {
96884
97079
  const norm = (p) => resolve9(p).replace(/[\\/]+$/, "").toLowerCase();
@@ -96895,7 +97090,7 @@ function off(env2) {
96895
97090
  function readSettings(path3) {
96896
97091
  if (!existsSync39(path3)) return {};
96897
97092
  try {
96898
- const parsed = JSON.parse(readFileSync41(path3, "utf8"));
97093
+ const parsed = JSON.parse(readFileSync42(path3, "utf8"));
96899
97094
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return null;
96900
97095
  return parsed;
96901
97096
  } catch {
@@ -96919,13 +97114,13 @@ function currentDirs(settings) {
96919
97114
  return raw2.split(delimiter2).map((s) => s.trim()).filter(Boolean);
96920
97115
  }
96921
97116
  function writeSettings(path3, settings) {
96922
- mkdirSync12(dirname16(path3), { recursive: true });
96923
- writeFileSync30(path3, JSON.stringify(settings, null, 2) + "\n", "utf8");
97117
+ mkdirSync12(dirname17(path3), { recursive: true });
97118
+ writeFileSync31(path3, JSON.stringify(settings, null, 2) + "\n", "utf8");
96924
97119
  }
96925
97120
  function ensureClaudeMods(opts) {
96926
97121
  const env2 = opts.env ?? process.env;
96927
97122
  const settingsPath = opts.userSettingsPath ?? userClaudeSettingsPath();
96928
- const modsRoot = join48(opts.installRoot, "claude-mods");
97123
+ const modsRoot = join49(opts.installRoot, "claude-mods");
96929
97124
  if (off(env2)) {
96930
97125
  const settings2 = readSettings(settingsPath);
96931
97126
  if (!settings2) return { kind: "unreadable" };
@@ -96942,14 +97137,14 @@ function ensureClaudeMods(opts) {
96942
97137
  let changed = false;
96943
97138
  const installed = [];
96944
97139
  for (const name2 of names) {
96945
- const src = join48(bundleDir, name2);
96946
- const dest = join48(modsRoot, name2);
97140
+ const src = join49(bundleDir, name2);
97141
+ const dest = join49(modsRoot, name2);
96947
97142
  const hash2 = modHash(src);
96948
- const hashFile = join48(dest, HASH_FILE);
96949
- if (!existsSync39(hashFile) || readFileSync41(hashFile, "utf8") !== hash2) {
97143
+ const hashFile = join49(dest, HASH_FILE);
97144
+ if (!existsSync39(hashFile) || readFileSync42(hashFile, "utf8") !== hash2) {
96950
97145
  rmSync4(dest, { recursive: true, force: true });
96951
97146
  cpSync3(src, dest, { recursive: true, filter: (p) => !isEngineOwned(relative8(src, p)) });
96952
- writeFileSync30(hashFile, hash2, "utf8");
97147
+ writeFileSync31(hashFile, hash2, "utf8");
96953
97148
  changed = true;
96954
97149
  }
96955
97150
  installed.push(dest);
@@ -97370,9 +97565,9 @@ function resolveHookPort(explicit) {
97370
97565
  }
97371
97566
  }
97372
97567
  }
97373
- const settingsPath = join49(ROOT, ".claude", "settings.json");
97568
+ const settingsPath = join50(ROOT, ".claude", "settings.json");
97374
97569
  try {
97375
- if (existsSync40(settingsPath)) return installedHookPort(readFileSync42(settingsPath, "utf8")) ?? 7891;
97570
+ if (existsSync40(settingsPath)) return installedHookPort(readFileSync43(settingsPath, "utf8")) ?? 7891;
97376
97571
  } catch {
97377
97572
  }
97378
97573
  return 7891;
@@ -97398,13 +97593,13 @@ async function cmdInit() {
97398
97593
  console.log("");
97399
97594
  console.log("installing harness hooks...");
97400
97595
  const { existsSync: existsSync41 } = await import("node:fs");
97401
- const { join: join50 } = await import("node:path");
97596
+ const { join: join51 } = await import("node:path");
97402
97597
  try {
97403
97598
  await installClaudeHooks(port);
97404
97599
  } catch (err2) {
97405
97600
  console.warn(` \u26A0\uFE0F Claude hook install failed: ${err2 instanceof Error ? err2.message : err2}`);
97406
97601
  }
97407
- if (existsSync41(join50(ROOT, ".cursor"))) {
97602
+ if (existsSync41(join51(ROOT, ".cursor"))) {
97408
97603
  try {
97409
97604
  await installCursorMcpConfig();
97410
97605
  } catch (err2) {
@@ -98626,7 +98821,7 @@ async function cmdReview() {
98626
98821
  console.log("(review queue empty)");
98627
98822
  return;
98628
98823
  }
98629
- const queue = JSON.parse(readFileSync42(paths.reviewQueue, "utf8"));
98824
+ const queue = JSON.parse(readFileSync43(paths.reviewQueue, "utf8"));
98630
98825
  if (queue.length === 0) {
98631
98826
  console.log("(review queue empty)");
98632
98827
  return;
@@ -99365,7 +99560,7 @@ async function gatherReportData(generatedAt) {
99365
99560
  };
99366
99561
  }
99367
99562
  async function cmdReport(args2) {
99368
- const { mkdirSync: mkdirSync13, writeFileSync: writeFileSync31 } = await import("node:fs");
99563
+ const { mkdirSync: mkdirSync13, writeFileSync: writeFileSync32 } = await import("node:fs");
99369
99564
  const { renderReport: renderReport2 } = await Promise.resolve().then(() => (init_report_render(), report_render_exports));
99370
99565
  const includeFutureVerbs = args2.includes("--future-verbs");
99371
99566
  const now = /* @__PURE__ */ new Date();
@@ -99378,8 +99573,8 @@ async function cmdReport(args2) {
99378
99573
  const outDir = workspacePaths(ROOT).configDir;
99379
99574
  mkdirSync13(outDir, { recursive: true });
99380
99575
  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");
99576
+ for (const f of files) writeFileSync32(join50(outDir, f.name), f.html, "utf8");
99577
+ const indexPath = join50(outDir, "report.html");
99383
99578
  console.log(`report \u2192 ${indexPath}`);
99384
99579
  console.log(
99385
99580
  ` ${data.repos.length} repo(s) \xB7 ${files.length} file(s) \xB7 ${data.rollup.nodes.toLocaleString("en-US")} nodes`
@@ -99435,7 +99630,7 @@ function spawnDaemonDetached(options = {}) {
99435
99630
  try {
99436
99631
  const logPath = daemonLogPath();
99437
99632
  try {
99438
- if (statSync13(logPath).size > 5 * 1024 * 1024) renameSync7(logPath, `${logPath}.1`);
99633
+ if (statSync13(logPath).size > 5 * 1024 * 1024) renameSync8(logPath, `${logPath}.1`);
99439
99634
  } catch {
99440
99635
  }
99441
99636
  out2 = openSync3(logPath, "a");
@@ -99504,24 +99699,24 @@ async function cmdInstallHooks(args2) {
99504
99699
  }
99505
99700
  }
99506
99701
  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");
99702
+ const { mkdirSync: mkdirSync13, existsSync: existsSync41, readFileSync: readFileSync44, writeFileSync: writeFileSync32 } = await import("node:fs");
99703
+ const { join: join51 } = await import("node:path");
99704
+ const dir = join51(ROOT, ".opencode", "plugin");
99510
99705
  if (!existsSync41(dir)) mkdirSync13(dir, { recursive: true });
99511
- const file2 = join50(dir, "inerrata.js");
99706
+ const file2 = join51(dir, "inerrata.js");
99512
99707
  if (existsSync41(file2)) {
99513
- const head2 = readFileSync43(file2, "utf8").split("\n")[0] ?? "";
99708
+ const head2 = readFileSync44(file2, "utf8").split("\n")[0] ?? "";
99514
99709
  if (head2.trim() !== OPENCODE_PLUGIN_MARKER) {
99515
99710
  console.error(`refusing to overwrite ${file2}: not an errata-managed plugin (line 1 lacks the marker)`);
99516
99711
  process.exit(2);
99517
99712
  }
99518
99713
  }
99519
- writeFileSync31(file2, buildOpencodePluginSource(port, { version: DAEMON_VERSION }), "utf8");
99520
- const cfgFile = join50(ROOT, "opencode.json");
99714
+ writeFileSync32(file2, buildOpencodePluginSource(port, { version: DAEMON_VERSION }), "utf8");
99715
+ const cfgFile = join51(ROOT, "opencode.json");
99521
99716
  let cfg = { $schema: "https://opencode.ai/config.json" };
99522
99717
  if (existsSync41(cfgFile)) {
99523
99718
  try {
99524
- cfg = JSON.parse(readFileSync43(cfgFile, "utf8"));
99719
+ cfg = JSON.parse(readFileSync44(cfgFile, "utf8"));
99525
99720
  } catch {
99526
99721
  console.error(`refusing to touch invalid JSON at ${cfgFile} \u2014 fix it and re-run`);
99527
99722
  process.exit(2);
@@ -99532,7 +99727,7 @@ async function installOpencodePlugin(port) {
99532
99727
  if (!hadErrata) {
99533
99728
  const inv = errataMcpInvocation();
99534
99729
  cfg.mcp["errata"] = { type: "local", command: [inv.command, ...inv.args] };
99535
- writeFileSync31(cfgFile, JSON.stringify(cfg, null, 2) + "\n", "utf8");
99730
+ writeFileSync32(cfgFile, JSON.stringify(cfg, null, 2) + "\n", "utf8");
99536
99731
  }
99537
99732
  console.log(`installed OpenCode plugin \u2192 ${file2}`);
99538
99733
  if (hadErrata) console.log(` mcp.errata already present in ${cfgFile} \u2014 left untouched`);
@@ -99567,15 +99762,15 @@ function installClaudeMods() {
99567
99762
  }
99568
99763
  }
99569
99764
  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");
99765
+ const { mkdirSync: mkdirSync13, existsSync: existsSync41, readFileSync: readFileSync44, writeFileSync: writeFileSync32 } = await import("node:fs");
99766
+ const { join: join51 } = await import("node:path");
99767
+ const dir = join51(ROOT, ".claude");
99573
99768
  if (!existsSync41(dir)) mkdirSync13(dir, { recursive: true });
99574
- const file2 = join50(dir, "settings.json");
99769
+ const file2 = join51(dir, "settings.json");
99575
99770
  let settings = {};
99576
99771
  if (existsSync41(file2)) {
99577
99772
  try {
99578
- settings = JSON.parse(readFileSync43(file2, "utf8"));
99773
+ settings = JSON.parse(readFileSync44(file2, "utf8"));
99579
99774
  } catch {
99580
99775
  console.error(`refusing to overwrite invalid JSON at ${file2}`);
99581
99776
  process.exit(2);
@@ -99624,12 +99819,12 @@ async function installClaudeHooks(port) {
99624
99819
  list.push({ hooks: [{ type: "command", command: injectCmd }] });
99625
99820
  }
99626
99821
  removeProjectStatusLine(settings);
99627
- writeFileSync31(file2, JSON.stringify(settings, null, 2) + "\n", "utf8");
99822
+ writeFileSync32(file2, JSON.stringify(settings, null, 2) + "\n", "utf8");
99628
99823
  console.log(`installed Claude Code hooks \u2192 ${file2}`);
99629
99824
  console.log(` ${ensureStatusLine(port)}`);
99630
99825
  console.log(` ${installClaudeMods().line}`);
99631
99826
  await installClaudeMcpConfig();
99632
- const claudeMd = join50(ROOT, "CLAUDE.md");
99827
+ const claudeMd = join51(ROOT, "CLAUDE.md");
99633
99828
  const recall = writeManagedBlock(claudeMd, { body: RECALL_FIRST_BLOCK });
99634
99829
  if (recall.kind === "collision") {
99635
99830
  console.warn(
@@ -99641,15 +99836,15 @@ async function installClaudeHooks(port) {
99641
99836
  console.log(` endpoint: http://127.0.0.1:${port}/api/hook`);
99642
99837
  }
99643
99838
  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);
99839
+ const { mkdirSync: mkdirSync13, existsSync: existsSync41, readFileSync: readFileSync44, writeFileSync: writeFileSync32 } = await import("node:fs");
99840
+ const { join: join51, dirname: dirname18 } = await import("node:path");
99841
+ const file2 = join51(ROOT, ".mcp.json");
99842
+ const dir = dirname18(file2);
99648
99843
  if (!existsSync41(dir)) mkdirSync13(dir, { recursive: true });
99649
99844
  let cfg = {};
99650
99845
  if (existsSync41(file2)) {
99651
99846
  try {
99652
- cfg = JSON.parse(readFileSync43(file2, "utf8"));
99847
+ cfg = JSON.parse(readFileSync44(file2, "utf8"));
99653
99848
  } catch {
99654
99849
  console.error(`refusing to overwrite invalid JSON at ${file2}`);
99655
99850
  process.exit(2);
@@ -99657,21 +99852,21 @@ async function installClaudeMcpConfig() {
99657
99852
  }
99658
99853
  cfg.mcpServers ??= {};
99659
99854
  cfg.mcpServers["errata"] = errataMcpInvocation();
99660
- writeFileSync31(file2, JSON.stringify(cfg, null, 2) + "\n", "utf8");
99855
+ writeFileSync32(file2, JSON.stringify(cfg, null, 2) + "\n", "utf8");
99661
99856
  console.log(`installed Claude Code MCP server config \u2192 ${file2}`);
99662
99857
  console.log(` Claude Code will spawn \`errata mcp\` on workspace open.`);
99663
99858
  console.log(` Tools: errata.search / locate / neighbors / callers_of / what_uses / show / similar`);
99664
99859
  }
99665
99860
  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");
99861
+ const { mkdirSync: mkdirSync13, existsSync: existsSync41, readFileSync: readFileSync44, writeFileSync: writeFileSync32 } = await import("node:fs");
99862
+ const { join: join51 } = await import("node:path");
99863
+ const dir = join51(ROOT, ".cursor");
99669
99864
  if (!existsSync41(dir)) mkdirSync13(dir, { recursive: true });
99670
- const file2 = join50(dir, "mcp.json");
99865
+ const file2 = join51(dir, "mcp.json");
99671
99866
  let cfg = {};
99672
99867
  if (existsSync41(file2)) {
99673
99868
  try {
99674
- cfg = JSON.parse(readFileSync43(file2, "utf8"));
99869
+ cfg = JSON.parse(readFileSync44(file2, "utf8"));
99675
99870
  } catch {
99676
99871
  console.error(`refusing to overwrite invalid JSON at ${file2}`);
99677
99872
  process.exit(2);
@@ -99679,7 +99874,7 @@ async function installCursorMcpConfig() {
99679
99874
  }
99680
99875
  cfg.mcpServers ??= {};
99681
99876
  cfg.mcpServers["errata"] = errataMcpInvocation();
99682
- writeFileSync31(file2, JSON.stringify(cfg, null, 2) + "\n", "utf8");
99877
+ writeFileSync32(file2, JSON.stringify(cfg, null, 2) + "\n", "utf8");
99683
99878
  console.log(`installed Cursor MCP server config \u2192 ${file2}`);
99684
99879
  console.log(` Cursor will spawn \`errata mcp\` on workspace open.`);
99685
99880
  console.log(` Tools: errata.search / locate / neighbors / callers_of / what_uses`);
@@ -99690,7 +99885,7 @@ async function installCodexHooks(port) {
99690
99885
  const gitRoot = nearestGitRoot(process.cwd());
99691
99886
  const hookRoot = gitRoot && mainCheckoutOfWorktree(gitRoot) ? gitRoot : ROOT;
99692
99887
  const file2 = writeCodexHooks(hookRoot, port);
99693
- const instructions = writeManagedBlock(join49(hookRoot, "AGENTS.md"), {
99888
+ const instructions = writeManagedBlock(join50(hookRoot, "AGENTS.md"), {
99694
99889
  body: AGENTS_POINTER_BODY,
99695
99890
  stable: true
99696
99891
  });
@@ -100136,9 +100331,9 @@ async function cmdDash(args2) {
100136
100331
  await yieldToLoop2();
100137
100332
  try {
100138
100333
  const items = selectDurableMemory(handle2.sharedStore, r.engine.profile, {
100139
- atCommit: readGitRefState(join49(r.root, ".git")).sha ?? void 0
100334
+ atCommit: readGitRefState(join50(r.root, ".git")).sha ?? void 0
100140
100335
  });
100141
- const res = bleedRules(join49(r.root, ".claude", "rules"), items);
100336
+ const res = bleedRules(join50(r.root, ".claude", "rules"), items);
100142
100337
  if (res.written || res.pruned) {
100143
100338
  console.log(
100144
100339
  `[rules:${r.entry.name}] ${res.written} collective principle(s) \u2192 .claude/rules` + (res.pruned ? `, ${res.pruned} pruned` : "")