@inerrata-corporation/errata 2.0.22-dev.4180 → 2.0.22-dev.4277

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
@@ -19108,17 +19108,23 @@ function installTextIndex(db) {
19108
19108
  db.transaction(() => {
19109
19109
  db.exec(`CREATE VIRTUAL TABLE IF NOT EXISTS nodes_text
19110
19110
  USING fts5(description, content='nodes', content_rowid='rowid', tokenize='trigram')`);
19111
+ db.exec(`DROP TRIGGER IF EXISTS nodes_text_update_out; DROP TRIGGER IF EXISTS nodes_text_update_in;
19112
+ DROP TRIGGER IF EXISTS nodes_text_update`);
19111
19113
  db.exec(`CREATE TRIGGER IF NOT EXISTS nodes_text_insert AFTER INSERT ON nodes WHEN NEW.valid_to IS NULL
19112
19114
  BEGIN INSERT INTO nodes_text(rowid, description) VALUES (NEW.rowid, NEW.description); END;`);
19113
- db.exec(`CREATE TRIGGER IF NOT EXISTS nodes_text_update_out AFTER UPDATE OF description, valid_to ON nodes
19114
- WHEN OLD.valid_to IS NULL
19115
- BEGIN INSERT INTO nodes_text(nodes_text, rowid, description) VALUES ('delete', OLD.rowid, OLD.description); END;`);
19116
- db.exec(`CREATE TRIGGER IF NOT EXISTS nodes_text_update_in AFTER UPDATE OF description, valid_to ON nodes
19117
- WHEN NEW.valid_to IS NULL
19118
- BEGIN INSERT INTO nodes_text(rowid, description) VALUES (NEW.rowid, NEW.description); END;`);
19115
+ db.exec(`CREATE TRIGGER nodes_text_update AFTER UPDATE OF description, valid_to ON nodes
19116
+ WHEN OLD.description IS NOT NEW.description OR OLD.valid_to IS NOT NEW.valid_to
19117
+ BEGIN
19118
+ INSERT INTO nodes_text(nodes_text, rowid, description)
19119
+ SELECT 'delete', OLD.rowid, OLD.description WHERE OLD.valid_to IS NULL;
19120
+ INSERT INTO nodes_text(rowid, description)
19121
+ SELECT NEW.rowid, NEW.description WHERE NEW.valid_to IS NULL;
19122
+ END;`);
19119
19123
  db.exec(`CREATE TRIGGER IF NOT EXISTS nodes_text_delete AFTER DELETE ON nodes WHEN OLD.valid_to IS NULL
19120
19124
  BEGIN INSERT INTO nodes_text(nodes_text, rowid, description) VALUES ('delete', OLD.rowid, OLD.description); END;`);
19125
+ db.exec(`INSERT INTO nodes_text(nodes_text) VALUES ('delete-all')`);
19121
19126
  db.exec(`INSERT INTO nodes_text(rowid, description) SELECT rowid, description FROM nodes WHERE valid_to IS NULL`);
19127
+ db.prepare("INSERT OR REPLACE INTO store_meta(key,value) VALUES (?,?)").run("text-index-trigram-1", "installed");
19122
19128
  db.prepare("INSERT INTO store_meta(key,value) VALUES (?,?)").run(TEXT_INDEX_KEY, "installed");
19123
19129
  });
19124
19130
  }
@@ -19129,7 +19135,7 @@ var TEXT_INDEX_KEY, TEXT_INDEX_MIN_TERM;
19129
19135
  var init_text_index = __esm({
19130
19136
  "../../packages/local-graph/src/text-index.ts"() {
19131
19137
  "use strict";
19132
- TEXT_INDEX_KEY = "text-index-trigram-1";
19138
+ TEXT_INDEX_KEY = "text-index-trigram-2";
19133
19139
  TEXT_INDEX_MIN_TERM = 3;
19134
19140
  }
19135
19141
  });
@@ -26226,6 +26232,20 @@ function clearCandidate(store, node2, ts, rejectTargetId) {
26226
26232
  }
26227
26233
  store.updateNode(node2.id, { attrs, lastUpdatedAt: ts });
26228
26234
  }
26235
+ function markStanding(store, node2, mark, reason, ts) {
26236
+ const stamped = {
26237
+ ...mark,
26238
+ examinedAtSeq: store.currentIngestSeq(),
26239
+ examinations: (mark.examinations ?? 0) + 1,
26240
+ standingReason: reason
26241
+ };
26242
+ store.updateNode(node2.id, { attrs: { ...node2.attrs, foldCandidate: stamped }, lastUpdatedAt: ts });
26243
+ }
26244
+ function foldCandidateEligible(mark, currentSeq, judgeConfigured) {
26245
+ if (mark.examinedAtSeq === void 0) return true;
26246
+ if (mark.standingReason === "no-judge" && judgeConfigured) return true;
26247
+ return currentSeq - mark.examinedAtSeq >= FOLD_REEXAMINE_SEQ;
26248
+ }
26229
26249
  async function resolveFoldCandidates(store, opts) {
26230
26250
  const report = {
26231
26251
  examined: 0,
@@ -26235,10 +26255,17 @@ async function resolveFoldCandidates(store, opts) {
26235
26255
  rejected: 0,
26236
26256
  standing: 0,
26237
26257
  judgeErrors: 0,
26238
- retargeted: 0
26258
+ retargeted: 0,
26259
+ pending: 0,
26260
+ neverExamined: 0,
26261
+ firstExamined: 0,
26262
+ waiting: 0,
26263
+ judgeBudgetDeferred: 0
26239
26264
  };
26240
- const limit = opts.limit ?? 8;
26241
- const marked = store.selectNodes({
26265
+ const limit = opts.limit ?? FOLD_EXAMINE_LIMIT;
26266
+ const judgeBudget = opts.judgeBudget ?? FOLD_JUDGE_BUDGET;
26267
+ const currentSeq = store.currentIngestSeq();
26268
+ const pool = store.selectNodes({
26242
26269
  labels: ["Problem"],
26243
26270
  attrs: ["foldCandidate"],
26244
26271
  where: [
@@ -26246,16 +26273,35 @@ async function resolveFoldCandidates(store, opts) {
26246
26273
  { attr: "mergedInto", absent: true },
26247
26274
  { attr: "foldCandidate", present: true }
26248
26275
  ]
26249
- }).sort((a, b) => {
26250
- const ma = a.attrs["foldCandidate"].ts ?? 0;
26251
- const mb = b.attrs["foldCandidate"].ts ?? 0;
26252
- return ma - mb;
26276
+ });
26277
+ const markOf = (n) => n.attrs["foldCandidate"];
26278
+ report.pending = pool.length;
26279
+ let neverExamined = pool.filter((n) => markOf(n).examinedAtSeq === void 0).length;
26280
+ const eligible = pool.filter((n) => foldCandidateEligible(markOf(n), currentSeq, !!opts.judge));
26281
+ report.waiting = pool.length - eligible.length;
26282
+ const marked = eligible.sort((a, b) => {
26283
+ const ma = markOf(a);
26284
+ const mb = markOf(b);
26285
+ const ea = ma.examinedAtSeq ?? -1;
26286
+ const eb = mb.examinedAtSeq ?? -1;
26287
+ if (ea !== eb) return ea - eb;
26288
+ return (ma.ts ?? 0) - (mb.ts ?? 0);
26253
26289
  }).slice(0, limit);
26290
+ let judgeCalls = 0;
26291
+ const unseenMark = (n) => {
26292
+ const m = n.attrs["foldCandidate"];
26293
+ return m !== void 0 && m.examinedAtSeq === void 0;
26294
+ };
26254
26295
  for (const node2 of marked) {
26255
26296
  const fresh = store.getNode(node2.id);
26256
26297
  if (!openProblem(fresh)) continue;
26257
- report.examined++;
26258
26298
  const mark = fresh.attrs["foldCandidate"];
26299
+ const firstLook = mark.examinedAtSeq === void 0;
26300
+ report.examined++;
26301
+ if (firstLook) {
26302
+ report.firstExamined++;
26303
+ neverExamined--;
26304
+ }
26259
26305
  let target = followMerges(store, mark.targetId);
26260
26306
  if (target && target.id !== mark.targetId) report.retargeted++;
26261
26307
  if (!openProblem(target)) {
@@ -26273,6 +26319,7 @@ async function resolveFoldCandidates(store, opts) {
26273
26319
  cos = cosine(fresh.embedding, target.embedding);
26274
26320
  }
26275
26321
  if (cos !== null && cos >= FOLD_EMBED_AUTO_COSINE) {
26322
+ if (unseenMark(target)) neverExamined--;
26276
26323
  foldPair(store, fresh, target, opts.ts);
26277
26324
  report.folded++;
26278
26325
  report.foldedEmbedding++;
@@ -26284,9 +26331,20 @@ async function resolveFoldCandidates(store, opts) {
26284
26331
  continue;
26285
26332
  }
26286
26333
  if (!opts.judge) {
26334
+ markStanding(store, fresh, mark, "no-judge", opts.ts);
26287
26335
  report.standing++;
26288
26336
  continue;
26289
26337
  }
26338
+ if (judgeCalls >= judgeBudget) {
26339
+ report.examined--;
26340
+ if (firstLook) {
26341
+ report.firstExamined--;
26342
+ neverExamined++;
26343
+ }
26344
+ report.judgeBudgetDeferred++;
26345
+ continue;
26346
+ }
26347
+ judgeCalls++;
26290
26348
  let verdict = null;
26291
26349
  try {
26292
26350
  verdict = await opts.judge(fresh.description, target.description);
@@ -26294,6 +26352,7 @@ async function resolveFoldCandidates(store, opts) {
26294
26352
  verdict = null;
26295
26353
  }
26296
26354
  if (verdict === "same") {
26355
+ if (unseenMark(target)) neverExamined--;
26297
26356
  foldPair(store, fresh, target, opts.ts);
26298
26357
  report.folded++;
26299
26358
  report.foldedJudge++;
@@ -26301,10 +26360,12 @@ async function resolveFoldCandidates(store, opts) {
26301
26360
  clearCandidate(store, fresh, opts.ts, target.id);
26302
26361
  report.rejected++;
26303
26362
  } else {
26363
+ markStanding(store, fresh, mark, "judge-error", opts.ts);
26304
26364
  report.judgeErrors++;
26305
26365
  report.standing++;
26306
26366
  }
26307
26367
  }
26368
+ report.neverExamined = neverExamined;
26308
26369
  return report;
26309
26370
  }
26310
26371
  function foldPair(store, a, b, ts) {
@@ -26319,7 +26380,7 @@ function foldPair(store, a, b, ts) {
26319
26380
  if (!freshSurvivor || !freshDup) return;
26320
26381
  foldDuplicateProblem(store, freshDup, freshSurvivor, ts);
26321
26382
  }
26322
- var FOLD_SCOUT_AUTO_COSINE, FOLD_SCOUT_MIN_COSINE, FOLD_SCOUT_MIN_JACCARD, FOLD_EMBED_AUTO_COSINE, FOLD_JUDGE_MIN_COSINE, FOLD_REJECTED_CAP, WORKSPACE_SCAN_CAP, openProblem;
26383
+ var FOLD_SCOUT_AUTO_COSINE, FOLD_SCOUT_MIN_COSINE, FOLD_SCOUT_MIN_JACCARD, FOLD_EMBED_AUTO_COSINE, FOLD_JUDGE_MIN_COSINE, FOLD_REJECTED_CAP, FOLD_REEXAMINE_SEQ, FOLD_EXAMINE_LIMIT, FOLD_JUDGE_BUDGET, WORKSPACE_SCAN_CAP, openProblem;
26323
26384
  var init_fold_candidates = __esm({
26324
26385
  "../../packages/local-graph/src/fold-candidates.ts"() {
26325
26386
  "use strict";
@@ -26332,6 +26393,9 @@ var init_fold_candidates = __esm({
26332
26393
  FOLD_EMBED_AUTO_COSINE = 0.88;
26333
26394
  FOLD_JUDGE_MIN_COSINE = 0.5;
26334
26395
  FOLD_REJECTED_CAP = 8;
26396
+ FOLD_REEXAMINE_SEQ = 100;
26397
+ FOLD_EXAMINE_LIMIT = 32;
26398
+ FOLD_JUDGE_BUDGET = 8;
26335
26399
  WORKSPACE_SCAN_CAP = 400;
26336
26400
  openProblem = (n) => !!n && n.label === "Problem" && n.attrs["resolvedAt"] == null && n.attrs["mergedInto"] === void 0;
26337
26401
  }
@@ -26790,6 +26854,28 @@ var init_mechanism_liveness = __esm({
26790
26854
  // climbs while `accepted` stays flat is the shape of a silently-closed door.
26791
26855
  backlogCounter: "candidates"
26792
26856
  },
26857
+ {
26858
+ id: "edge-park-replay",
26859
+ what: "parks causal/anchor edges the door refused as unresolvable, replays them when due, drops them with a disposition",
26860
+ pass: "ship",
26861
+ // FED = a source whose whole binding-edge family LANDED: the digest is
26862
+ // stamped only when every edge in it came back created/reinforced, so it is
26863
+ // the store-side proof that edges (not just nodes) cross. Live dev
26864
+ // 2026-10-12 sat with the same 241 refusals re-sent every drain and this
26865
+ // stamp frozen — nodes crossed, their causal wiring did not.
26866
+ fed: {
26867
+ labels: ["Problem", "RootCause"],
26868
+ attr: "semanticEdgesContributedDigest",
26869
+ minFraction: 0.01
26870
+ },
26871
+ // A parked edge that later LANDED — the replay doing its job.
26872
+ effectCounter: "edgesReplayLanded",
26873
+ // Outstanding parked edges (a level). Flat-and-nonzero while replays keep
26874
+ // re-parking is an endpoint that never resolves; it drains to tombstones
26875
+ // (`edgesDroppedExhausted`) instead of being resent forever.
26876
+ backlogCounter: "edgeParkSize",
26877
+ note: "edge-park.ts; quiet (no-effect) is healthy when nothing is refused \u2014 read edgesParked/edgesDropped* on the ship row"
26878
+ },
26793
26879
  {
26794
26880
  id: "orphan-reap",
26795
26881
  what: "closes File nodes whose path the indexer no longer covers",
@@ -26844,12 +26930,31 @@ var init_mechanism_liveness = __esm({
26844
26930
  // the bar is "the field is written at all", the revisit-sweep precedent.
26845
26931
  fed: { labels: ["Problem"], attr: "foldCandidate", minFraction: 0 },
26846
26932
  effectCounter: "folded",
26847
- // Standing nominations ARE the judge-less backlog — without the gauge a
26848
- // deployment with no judge configured reads as "nothing to fold".
26849
- backlogCounter: "standing",
26933
+ // The open-nomination POOL is the backlog. It used to be `standing`, which
26934
+ // only counts what the pass examined — capped at the per-run limit — so it
26935
+ // read a flat 8 for weeks while 824 nominations sat open (2026-10-12): the
26936
+ // gauge could not see past the slice it was meant to be measuring.
26937
+ backlogCounter: "pending",
26850
26938
  configCounter: "judgeConfigured",
26851
26939
  note: "the ambiguous band needs the opt-in judge: set ERRATA_FOLD_JUDGE=1 + a configured chat provider (azure env), or leave it off and the nominations stand"
26852
26940
  },
26941
+ {
26942
+ id: "fold-candidate-coverage",
26943
+ what: "rotates the fold-judge pass through every open nomination (never-examined first, standing ones re-examined on new evidence)",
26944
+ // Judge-INDEPENDENT on purpose — no configCounter. The embedding-certain
26945
+ // bands fold/reject with no judge at all, and the defect this watches is
26946
+ // the pass re-reading the same oldest 8 forever (101 runs, 8 distinct
26947
+ // nodes, 816 of 824 nominations never looked at). That starves those
26948
+ // bands on a judge-less daemon exactly as much as on a judged one, so an
26949
+ // opt-in being off must not excuse it.
26950
+ pass: "fold-judge",
26951
+ fed: { labels: ["Problem"], attr: "foldCandidate", minFraction: 0 },
26952
+ effectCounter: "firstExamined",
26953
+ // A LEVEL: open nominations never examined. Flat-and-positive with no
26954
+ // first examinations across the stall window = the rotation is stuck.
26955
+ backlogCounter: "neverExamined",
26956
+ note: "neverExamined must drain while the pass runs; flat means the selection is re-reading the same slice"
26957
+ },
26853
26958
  {
26854
26959
  id: "cite-anchor-accrual",
26855
26960
  what: "accrues cite-context anchor evidence on anchorless cited priors; two distinct sessions promote a cite-confirmed ANCHORED_AT",
@@ -27029,7 +27134,10 @@ __export(src_exports2, {
27029
27134
  FINGERPRINT_INDEXED_LABELS: () => FINGERPRINT_INDEXED_LABELS,
27030
27135
  FIX_CANDIDATE_ASK_LIMIT: () => FIX_CANDIDATE_ASK_LIMIT,
27031
27136
  FOLD_EMBED_AUTO_COSINE: () => FOLD_EMBED_AUTO_COSINE,
27137
+ FOLD_EXAMINE_LIMIT: () => FOLD_EXAMINE_LIMIT,
27138
+ FOLD_JUDGE_BUDGET: () => FOLD_JUDGE_BUDGET,
27032
27139
  FOLD_JUDGE_MIN_COSINE: () => FOLD_JUDGE_MIN_COSINE,
27140
+ FOLD_REEXAMINE_SEQ: () => FOLD_REEXAMINE_SEQ,
27033
27141
  FOLD_REJECTED_CAP: () => FOLD_REJECTED_CAP,
27034
27142
  FOLD_SCOUT_AUTO_COSINE: () => FOLD_SCOUT_AUTO_COSINE,
27035
27143
  FOLD_SCOUT_MIN_COSINE: () => FOLD_SCOUT_MIN_COSINE,
@@ -27106,6 +27214,7 @@ __export(src_exports2, {
27106
27214
  findReusableSolution: () => findReusableSolution,
27107
27215
  findWorkspaceFoldCandidate: () => findWorkspaceFoldCandidate,
27108
27216
  flattenCloudCounts: () => flattenCloudCounts,
27217
+ foldCandidateEligible: () => foldCandidateEligible,
27109
27218
  foldDuplicateProblem: () => foldDuplicateProblem,
27110
27219
  foldSameAnchorProblem: () => foldSameAnchorProblem,
27111
27220
  formatMechanismStatus: () => formatMechanismStatus,
@@ -28663,7 +28772,7 @@ function parseRestErrorEnvelope(text) {
28663
28772
  return null;
28664
28773
  }
28665
28774
  }
28666
- var asWireCount, INGEST_NODE_CHUNK, INGEST_EDGE_CHUNK, E6B_PUBLIC_CONTEXT_SENTINEL, gzipAsync, CloudClient, CloudError;
28775
+ var asWireCount, INGEST_NODE_CHUNK, INGEST_EDGE_CHUNK, ENDPOINT_NOT_LANDED_PREFIX, E6B_PUBLIC_CONTEXT_SENTINEL, gzipAsync, CloudClient, CloudError;
28667
28776
  var init_client = __esm({
28668
28777
  "../../packages/cloud-client/src/client.ts"() {
28669
28778
  "use strict";
@@ -28672,6 +28781,7 @@ var init_client = __esm({
28672
28781
  asWireCount = (n) => typeof n === "number" && Number.isFinite(n) && n >= 0 ? Math.floor(n) : null;
28673
28782
  INGEST_NODE_CHUNK = 8;
28674
28783
  INGEST_EDGE_CHUNK = 32;
28784
+ ENDPOINT_NOT_LANDED_PREFIX = "endpoint did not land this drain";
28675
28785
  E6B_PUBLIC_CONTEXT_SENTINEL = "00000000-0000-4e6b-8000-000000000e6b";
28676
28786
  gzipAsync = promisify(gzip);
28677
28787
  CloudClient = class {
@@ -28874,7 +28984,7 @@ var init_client = __esm({
28874
28984
  pendingEdges = pendingEdges.filter((e) => !shipped.has(e));
28875
28985
  return { nodes, edges };
28876
28986
  });
28877
- const totalChunks = single ? 1 : nodePlan.length + Math.ceil(pendingEdges.length / INGEST_EDGE_CHUNK);
28987
+ let totalChunks = single ? 1 : nodePlan.length + Math.ceil(pendingEdges.length / INGEST_EDGE_CHUNK);
28878
28988
  let chunkIndex = 0;
28879
28989
  const blocked = [];
28880
28990
  const emit = async (nodeIds, result) => {
@@ -28901,9 +29011,18 @@ var init_client = __esm({
28901
29011
  }
28902
29012
  const merged = { runId, nodes: [], edges: [] };
28903
29013
  const echoedCloudId = /* @__PURE__ */ new Map();
29014
+ const notLanded = /* @__PURE__ */ new Map();
28904
29015
  for (const { nodes: nodeChunk, edges: inChunk } of nodePlan) {
28905
29016
  const r = await this.ingestWithSplit(batch, nodeChunk, inChunk, blocked);
29017
+ const refusedHere = new Set(blocked);
28906
29018
  await emit(nodeChunk.map((n) => n.id), r);
29019
+ const verdict = new Map(r.nodes.map((rn) => [rn.canonicalId, rn]));
29020
+ for (const n of nodeChunk) {
29021
+ const rn = verdict.get(n.id);
29022
+ if (refusedHere.has(n.id)) notLanded.set(n.id, "refused by an intermediary");
29023
+ else if (!rn) notLanded.set(n.id, "no verdict from the door");
29024
+ else if (rn.decision === "rejected") notLanded.set(n.id, rn.reason ?? "rejected");
29025
+ }
28907
29026
  merged.nodes.push(...r.nodes);
28908
29027
  merged.edges.push(...r.edges);
28909
29028
  for (const rn of r.nodes) {
@@ -28915,6 +29034,19 @@ var init_client = __esm({
28915
29034
  merged.patternReconciliation = { ...merged.patternReconciliation, ...r.patternReconciliation };
28916
29035
  }
28917
29036
  }
29037
+ pendingEdges = pendingEdges.filter((e) => {
29038
+ const missing = notLanded.has(e.from) && !echoedCloudId.has(e.from) ? e.from : notLanded.has(e.to) && !echoedCloudId.has(e.to) ? e.to : null;
29039
+ if (missing === null) return true;
29040
+ merged.edges.push({
29041
+ from: e.from,
29042
+ to: e.to,
29043
+ type: e.type,
29044
+ decision: "rejected",
29045
+ reason: `${ENDPOINT_NOT_LANDED_PREFIX} '${missing}' \u2014 ${notLanded.get(missing)}`
29046
+ });
29047
+ return false;
29048
+ });
29049
+ totalChunks = nodePlan.length + Math.ceil(pendingEdges.length / INGEST_EDGE_CHUNK);
28918
29050
  for (const edgeChunk of chunkArray(pendingEdges, INGEST_EDGE_CHUNK)) {
28919
29051
  const projected = edgeChunk.map((e) => ({
28920
29052
  ...e,
@@ -37332,6 +37464,7 @@ function isQuotaError(err2) {
37332
37464
  async function dualAugment(opts) {
37333
37465
  const { store, cloud, localHits, seedNode, queryText, limit, generalizeSoft } = opts;
37334
37466
  const cloudHits = [];
37467
+ let completeResponse = true;
37335
37468
  let seedUsageCount;
37336
37469
  let seedProvenance = "local";
37337
37470
  const calls = [];
@@ -37358,6 +37491,7 @@ async function dualAugment(opts) {
37358
37491
  if (cloudSeeds.length > 0 || softQ) {
37359
37492
  calls.push(
37360
37493
  cloud.search({ stack: [], domains: [], kinds: [], seed: cloudSeeds, ...softQ ? { q: softQ } : {}, limit, community: true, via: true }).then((res) => {
37494
+ if (res.seeds?.some((seed) => seed.status === "error")) completeResponse = false;
37361
37495
  cloudHits.push(...searchResultToCloudHits(res));
37362
37496
  })
37363
37497
  );
@@ -37379,18 +37513,29 @@ async function dualAugment(opts) {
37379
37513
  }
37380
37514
  if (cloudHits.length === 0) return { status: "empty" };
37381
37515
  const deduped = dedupCloudHits(cloudHits);
37516
+ const merged = mergeDualBurst(localHits, deduped, {
37517
+ // A hit's `via` parent is resolved too, so an edge from a folded twin
37518
+ // can be re-pointed at the entity it folded into.
37519
+ twins: storeTwinIndex(store, deduped.flatMap((c) => {
37520
+ const parent = c.via?.parentId;
37521
+ return parent ? [c.id, parent] : [c.id];
37522
+ })),
37523
+ ...seedNode ? { seedId: seedNode.id } : {},
37524
+ ...opts.fuse ? { fuse: opts.fuse } : {}
37525
+ });
37526
+ if (completeResponse) {
37527
+ const candidates = new Set(deduped.filter((hit) => !isCodeLabel(hit.label)).map((hit) => hit.id));
37528
+ const localIds = /* @__PURE__ */ new Set([...localHits.map((hit) => hit.id), ...seedNode ? [seedNode.id] : []]);
37529
+ const emitted = [];
37530
+ for (const node2 of merged.nodes) {
37531
+ const ids = [...node2.provenance === "collective" ? [node2.id] : [], ...node2.twins ?? []];
37532
+ for (const id of ids) if (candidates.has(id) && !localIds.has(id)) emitted.push(id);
37533
+ }
37534
+ rememberCollectiveIds(cloud, emitted);
37535
+ }
37382
37536
  return {
37383
37537
  status: "merged",
37384
- merged: mergeDualBurst(localHits, deduped, {
37385
- // A hit's `via` parent is resolved too, so an edge from a folded twin
37386
- // can be re-pointed at the entity it folded into.
37387
- twins: storeTwinIndex(store, deduped.flatMap((c) => {
37388
- const parent = c.via?.parentId;
37389
- return parent ? [c.id, parent] : [c.id];
37390
- })),
37391
- ...seedNode ? { seedId: seedNode.id } : {},
37392
- ...opts.fuse ? { fuse: opts.fuse } : {}
37393
- }),
37538
+ merged,
37394
37539
  seedProvenance,
37395
37540
  seedUsageCount
37396
37541
  };
@@ -37408,6 +37553,38 @@ function federationHint(status) {
37408
37553
  function hasCloudNodeShape(id) {
37409
37554
  return CANONICAL_KNOWLEDGE_ID.test(id) || UUID_ID.test(id) || id.startsWith("pkg:");
37410
37555
  }
37556
+ function safeCollectiveId(id) {
37557
+ if (typeof id !== "string") return false;
37558
+ const separator = id.indexOf("_");
37559
+ return id.length > 0 && id.trim() === id && !/[\u0000-\u001f\u007f,]/.test(id) && !(separator > 0 && isCodeLabel(id.slice(0, separator)));
37560
+ }
37561
+ function rememberCollectiveIds(cloud, ids) {
37562
+ const now = Date.now();
37563
+ let remembered = returnedCollectiveIds.get(cloud);
37564
+ if (!remembered) {
37565
+ remembered = /* @__PURE__ */ new Map();
37566
+ returnedCollectiveIds.set(cloud, remembered);
37567
+ }
37568
+ for (const [id, expiresAt] of remembered) if (expiresAt <= now) remembered.delete(id);
37569
+ for (const id of ids) {
37570
+ if (!safeCollectiveId(id) || id.length > 160) continue;
37571
+ remembered.delete(id);
37572
+ remembered.set(id, now + COLLECTIVE_ID_TTL_MS);
37573
+ if (remembered.size > COLLECTIVE_ID_LIMIT) remembered.delete(remembered.keys().next().value);
37574
+ }
37575
+ }
37576
+ function canFollowCollectiveId(cloud, id) {
37577
+ if (!safeCollectiveId(id)) return false;
37578
+ if (hasCloudNodeShape(id)) return true;
37579
+ const remembered = returnedCollectiveIds.get(cloud);
37580
+ const expiresAt = remembered?.get(id);
37581
+ if (expiresAt === void 0) return false;
37582
+ if (expiresAt <= Date.now()) {
37583
+ remembered.delete(id);
37584
+ return false;
37585
+ }
37586
+ return true;
37587
+ }
37411
37588
  function attrsCommunity(attrs) {
37412
37589
  const id = attrs?.["community"];
37413
37590
  if (typeof id !== "number") return void 0;
@@ -37447,7 +37624,7 @@ async function collectiveDrilldown(cloud, seedId, limit, opts = {}) {
37447
37624
  if (resolution === "unresolved") return { status: "no-twin" };
37448
37625
  if (resolution === "error") return { status: "seed-error" };
37449
37626
  if (res.nodes.length === 0 && resolution !== "resolved") return { status: "no-twin" };
37450
- return {
37627
+ const resolved = {
37451
37628
  status: "resolved",
37452
37629
  neighborhood: {
37453
37630
  seed: seedId,
@@ -37474,6 +37651,10 @@ async function collectiveDrilldown(cloud, seedId, limit, opts = {}) {
37474
37651
  ...seedEntry?.bridges ? { bridges: seedEntry.bridges } : {}
37475
37652
  }
37476
37653
  };
37654
+ if (!res.seeds?.some((seed) => seed.status === "error")) {
37655
+ rememberCollectiveIds(cloud, resolved.neighborhood.nodes.filter((node2) => node2.id !== seedId && !isCodeLabel(node2.label)).map((node2) => node2.id));
37656
+ }
37657
+ return resolved;
37477
37658
  }
37478
37659
  async function collectiveNodeDetail(cloud, id) {
37479
37660
  const read2 = async (nodeId) => {
@@ -37550,7 +37731,7 @@ function formatDualNodes(merged) {
37550
37731
  ...n.uploaded ? { uploaded: true } : {}
37551
37732
  }));
37552
37733
  }
37553
- var BRIDGE_LABELS, CANONICAL_KNOWLEDGE_ID, UUID_ID;
37734
+ var BRIDGE_LABELS, CANONICAL_KNOWLEDGE_ID, UUID_ID, COLLECTIVE_ID_LIMIT, COLLECTIVE_ID_TTL_MS, returnedCollectiveIds;
37554
37735
  var init_dual_augment = __esm({
37555
37736
  "src/dual-augment.ts"() {
37556
37737
  "use strict";
@@ -37561,6 +37742,9 @@ var init_dual_augment = __esm({
37561
37742
  BRIDGE_LABELS = new Set(SEMANTIC_NODE_LABELS);
37562
37743
  CANONICAL_KNOWLEDGE_ID = /^[a-z][a-z0-9]*_[0-9a-f]{8,}$/;
37563
37744
  UUID_ID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
37745
+ COLLECTIVE_ID_LIMIT = 512;
37746
+ COLLECTIVE_ID_TTL_MS = 15 * 6e4;
37747
+ returnedCollectiveIds = /* @__PURE__ */ new WeakMap();
37564
37748
  }
37565
37749
  });
37566
37750
 
@@ -46957,7 +47141,7 @@ function cosine3(a, b) {
46957
47141
  }
46958
47142
  async function collectiveSeedFallback(args2, ctx, defaultLimit, opts = {}) {
46959
47143
  const seedId = typeof args2["nodeId"] === "string" ? args2["nodeId"] : null;
46960
- if (!seedId || !ctx.cloud || !hasCloudNodeShape(seedId)) return null;
47144
+ if (!seedId || !ctx.cloud || !canFollowCollectiveId(ctx.cloud, seedId)) return null;
46961
47145
  const limit = Math.max(1, Math.min(100, Number(args2["limit"] ?? defaultLimit)));
46962
47146
  const scope = args2["scope"];
46963
47147
  return collectiveDrilldown(ctx.cloud, seedId, limit, {
@@ -48051,7 +48235,7 @@ var init_mcp = __esm({
48051
48235
  const id = resolveSymbol2(store, args2);
48052
48236
  if (!id) {
48053
48237
  const seedId = typeof args2["nodeId"] === "string" ? args2["nodeId"] : null;
48054
- if (!seedId || !ctx.cloud || !hasCloudNodeShape(seedId)) return unresolved(args2);
48238
+ if (!seedId || !ctx.cloud || !canFollowCollectiveId(ctx.cloud, seedId)) return unresolved(args2);
48055
48239
  const shown = await collectiveNodeDetail(ctx.cloud, seedId);
48056
48240
  if (shown.status !== "found") return collectiveSeedMiss(args2, shown);
48057
48241
  return {
@@ -76634,8 +76818,8 @@ var init_report_render = __esm({
76634
76818
 
76635
76819
  // src/cli.ts
76636
76820
  init_src6();
76637
- import { closeSync as closeSync3, existsSync as existsSync40, openSync as openSync3, readFileSync as readFileSync43, renameSync as renameSync8, statSync as statSync13 } from "node:fs";
76638
- import { join as join50, resolve as pathResolve2 } from "node:path";
76821
+ import { closeSync as closeSync3, existsSync as existsSync40, openSync as openSync3, readFileSync as readFileSync44, renameSync as renameSync9, statSync as statSync13 } from "node:fs";
76822
+ import { join as join51, resolve as pathResolve2 } from "node:path";
76639
76823
  import { spawn as spawn5 } from "node:child_process";
76640
76824
 
76641
76825
  // src/daemon.ts
@@ -78100,9 +78284,9 @@ var NodeFsHandler = class {
78100
78284
  if (this.fsw.closed) {
78101
78285
  return;
78102
78286
  }
78103
- const dirname18 = sysPath.dirname(file2);
78287
+ const dirname19 = sysPath.dirname(file2);
78104
78288
  const basename10 = sysPath.basename(file2);
78105
- const parent = this.fsw._getWatchedDir(dirname18);
78289
+ const parent = this.fsw._getWatchedDir(dirname19);
78106
78290
  let prevStats = stats;
78107
78291
  if (parent.has(basename10))
78108
78292
  return;
@@ -78129,7 +78313,7 @@ var NodeFsHandler = class {
78129
78313
  prevStats = newStats2;
78130
78314
  }
78131
78315
  } catch (error48) {
78132
- this.fsw._remove(dirname18, basename10);
78316
+ this.fsw._remove(dirname19, basename10);
78133
78317
  }
78134
78318
  } else if (parent.has(basename10)) {
78135
78319
  const at = newStats.atimeMs;
@@ -86043,7 +86227,7 @@ function createWatchBreaker(deps) {
86043
86227
  }
86044
86228
 
86045
86229
  // src/engine.ts
86046
- var DAEMON_VERSION = true ? "2.0.22-dev.4180" : "2.0.0-alpha.0";
86230
+ var DAEMON_VERSION = true ? "2.0.22-dev.4277" : "2.0.0-alpha.0";
86047
86231
  var IGNORED_PATH = /[\\/](?:\.git|node_modules|\.errata|\.claude|\.codex|\.cursor|\.turbo|\.next|dist|coverage|test-results|playwright-report|__pycache__)(?:[\\/]|$)/;
86048
86232
  var IGNORED_NOISE = /castalia\.db|eventlog\.sqlite|turn-cursors/;
86049
86233
  var GIT_OP_MUTE_MS = 4e3;
@@ -88564,7 +88748,12 @@ B: ${b}`,
88564
88748
  standing: fj.standing,
88565
88749
  judgeErrors: fj.judgeErrors,
88566
88750
  retargeted: fj.retargeted,
88567
- judgeConfigured: foldJudge ? 1 : 0
88751
+ judgeConfigured: foldJudge ? 1 : 0,
88752
+ pending: fj.pending,
88753
+ neverExamined: fj.neverExamined,
88754
+ firstExamined: fj.firstExamined,
88755
+ waiting: fj.waiting,
88756
+ judgeBudgetDeferred: fj.judgeBudgetDeferred
88568
88757
  });
88569
88758
  if (fj.folded > 0) {
88570
88759
  console.log(`[errata] fold-judge: folded ${fj.folded} paraphrase pair(s) (${fj.foldedEmbedding} by embedding, ${fj.foldedJudge} by judge), ${fj.standing} standing`);
@@ -89028,6 +89217,212 @@ async function linkRegisteredWorkspaces(cfg, loggedInProfile = cfg.activeInstall
89028
89217
  }
89029
89218
  }
89030
89219
 
89220
+ // src/edge-park.ts
89221
+ import { readFileSync as readFileSync33, renameSync as renameSync5, writeFileSync as writeFileSync25 } from "node:fs";
89222
+ import { dirname as dirname13, join as join36 } from "node:path";
89223
+ var EDGE_PARK_CAP = 2e3;
89224
+ var EDGE_PARK_TTL_MS = 14 * 24 * 60 * 60 * 1e3;
89225
+ var EDGE_PARK_MAX_ATTEMPTS = 6;
89226
+ var EDGE_RETRY_BASE_MS = 30 * 60 * 1e3;
89227
+ var EDGE_RETRY_MAX_MS = 12 * 60 * 60 * 1e3;
89228
+ var EDGE_TOMBSTONE_TTL_MS = 30 * 24 * 60 * 60 * 1e3;
89229
+ var EDGE_EXHAUSTED_TOMBSTONE_TTL_MS = 3 * 24 * 60 * 60 * 1e3;
89230
+ function tombstoneTtl(e) {
89231
+ return e.dropReason === "refused" ? EDGE_TOMBSTONE_TTL_MS : EDGE_EXHAUSTED_TOMBSTONE_TTL_MS;
89232
+ }
89233
+ function wireEdgeKey(from, type, to) {
89234
+ return JSON.stringify([from, type, to]);
89235
+ }
89236
+ function edgeParkPath(workspaceConfigDir, destinationKey) {
89237
+ return join36(workspaceConfigDir, `edge-park.${destinationKey.slice(0, 16)}.json`);
89238
+ }
89239
+ function loadEdgePark(path3) {
89240
+ let raw2;
89241
+ try {
89242
+ raw2 = JSON.parse(readFileSync33(path3, "utf8"));
89243
+ } catch {
89244
+ return [];
89245
+ }
89246
+ if (!Array.isArray(raw2)) return [];
89247
+ return raw2.filter(
89248
+ (e) => !!e && typeof e === "object" && typeof e.key === "string" && typeof e.from === "string" && typeof e.to === "string" && typeof e.type === "string" && (e.state === "parked" || e.state === "dropped")
89249
+ );
89250
+ }
89251
+ function saveEdgePark(path3, queue) {
89252
+ try {
89253
+ const tmp = join36(dirname13(path3), `.${Date.now()}.edge-park.tmp`);
89254
+ writeFileSync25(tmp, JSON.stringify(queue), "utf8");
89255
+ renameSync5(tmp, path3);
89256
+ } catch {
89257
+ }
89258
+ }
89259
+ function edgeHolds(queue, now) {
89260
+ const holds = {};
89261
+ for (const e of queue) {
89262
+ if (e.state === "dropped") {
89263
+ if (now - (e.droppedAt ?? e.ts) < tombstoneTtl(e)) holds[e.key] = "dropped";
89264
+ } else if (e.dueAt > now) {
89265
+ holds[e.key] = "held";
89266
+ }
89267
+ }
89268
+ return holds;
89269
+ }
89270
+ function classifyEdgeVerdict(decision, reason) {
89271
+ if (decision === "created" || decision === "reinforced") return "landed";
89272
+ const why = reason ?? "";
89273
+ if (/^unresolved endpoint\b/.test(why) || /^endpoint did not land this drain\b/.test(why) || /\bretry\b/i.test(why)) {
89274
+ return "park";
89275
+ }
89276
+ return "drop";
89277
+ }
89278
+ function matchEdgeVerdicts(sent, received, echo) {
89279
+ const byKey = /* @__PURE__ */ new Map();
89280
+ for (const r of received) {
89281
+ const k = wireEdgeKey(r.from, r.type, r.to);
89282
+ if (!byKey.has(k) || r.decision === "rejected") byKey.set(k, { decision: r.decision, reason: r.reason });
89283
+ }
89284
+ const out2 = /* @__PURE__ */ new Map();
89285
+ for (const e of sent) {
89286
+ const v = byKey.get(wireEdgeKey(echo.get(e.from) ?? e.from, e.type, echo.get(e.to) ?? e.to)) ?? byKey.get(wireEdgeKey(e.from, e.type, e.to));
89287
+ if (v) out2.set(e.id, v);
89288
+ }
89289
+ return out2;
89290
+ }
89291
+ function zeroEdgeSettleCounts(queue) {
89292
+ const parked = queue.filter((e) => e.state === "parked").length;
89293
+ return {
89294
+ edgesSent: 0,
89295
+ edgesLanded: 0,
89296
+ edgesReplayLanded: 0,
89297
+ edgesReplayed: 0,
89298
+ edgesParked: 0,
89299
+ edgesReparked: 0,
89300
+ edgesDroppedRefused: 0,
89301
+ edgesDroppedExhausted: 0,
89302
+ edgesDroppedExpired: 0,
89303
+ edgesDroppedCapped: 0,
89304
+ edgesNoVerdict: 0,
89305
+ edgeParkSize: parked,
89306
+ edgeTombstones: queue.length - parked
89307
+ };
89308
+ }
89309
+ function backoff(attempts) {
89310
+ return Math.min(EDGE_RETRY_MAX_MS, EDGE_RETRY_BASE_MS * 2 ** Math.max(0, attempts - 1));
89311
+ }
89312
+ function settleEdgeOutcomes(queue, sent, verdicts, now) {
89313
+ const counts = {
89314
+ edgesSent: sent.length,
89315
+ edgesLanded: 0,
89316
+ edgesReplayLanded: 0,
89317
+ edgesReplayed: 0,
89318
+ edgesParked: 0,
89319
+ edgesReparked: 0,
89320
+ edgesDroppedRefused: 0,
89321
+ edgesDroppedExhausted: 0,
89322
+ edgesDroppedExpired: 0,
89323
+ edgesDroppedCapped: 0,
89324
+ edgesNoVerdict: 0,
89325
+ edgeParkSize: 0,
89326
+ edgeTombstones: 0
89327
+ };
89328
+ const byKey = new Map(queue.map((e) => [e.key, { ...e }]));
89329
+ const seen = /* @__PURE__ */ new Set();
89330
+ for (const e of sent) {
89331
+ const key = e.id;
89332
+ if (seen.has(key)) continue;
89333
+ seen.add(key);
89334
+ const prior = byKey.get(key);
89335
+ if (prior?.state === "parked") counts.edgesReplayed++;
89336
+ const v = verdicts.get(key);
89337
+ if (!v) {
89338
+ counts.edgesNoVerdict++;
89339
+ continue;
89340
+ }
89341
+ const disposition = classifyEdgeVerdict(v.decision, v.reason);
89342
+ if (disposition === "landed") {
89343
+ counts.edgesLanded++;
89344
+ if (prior) {
89345
+ byKey.delete(key);
89346
+ if (prior.state === "parked") counts.edgesReplayLanded++;
89347
+ }
89348
+ continue;
89349
+ }
89350
+ const reason = v.reason ?? "rejected";
89351
+ if (prior?.state === "dropped") continue;
89352
+ if (disposition === "drop") {
89353
+ byKey.set(key, {
89354
+ key,
89355
+ from: e.from,
89356
+ type: e.type,
89357
+ to: e.to,
89358
+ ts: prior?.ts ?? now,
89359
+ attempts: (prior?.attempts ?? 0) + 1,
89360
+ lastReason: reason,
89361
+ dueAt: now,
89362
+ state: "dropped",
89363
+ dropReason: "refused",
89364
+ droppedAt: now
89365
+ });
89366
+ counts.edgesDroppedRefused++;
89367
+ continue;
89368
+ }
89369
+ const attempts = (prior?.state === "parked" ? prior.attempts : 0) + 1;
89370
+ const ts = prior?.state === "parked" ? prior.ts : now;
89371
+ if (attempts >= EDGE_PARK_MAX_ATTEMPTS || now - ts >= EDGE_PARK_TTL_MS) {
89372
+ const why = attempts >= EDGE_PARK_MAX_ATTEMPTS ? "exhausted" : "expired";
89373
+ byKey.set(key, {
89374
+ key,
89375
+ from: e.from,
89376
+ type: e.type,
89377
+ to: e.to,
89378
+ ts,
89379
+ attempts,
89380
+ lastReason: reason,
89381
+ dueAt: now,
89382
+ state: "dropped",
89383
+ dropReason: why,
89384
+ droppedAt: now
89385
+ });
89386
+ if (why === "exhausted") counts.edgesDroppedExhausted++;
89387
+ else counts.edgesDroppedExpired++;
89388
+ continue;
89389
+ }
89390
+ byKey.set(key, {
89391
+ key,
89392
+ from: e.from,
89393
+ type: e.type,
89394
+ to: e.to,
89395
+ ts,
89396
+ attempts,
89397
+ lastReason: reason,
89398
+ dueAt: now + backoff(attempts),
89399
+ state: "parked"
89400
+ });
89401
+ if (prior?.state === "parked") counts.edgesReparked++;
89402
+ else counts.edgesParked++;
89403
+ }
89404
+ const live3 = [];
89405
+ for (const e of byKey.values()) {
89406
+ if (e.state === "parked" && now - e.ts >= EDGE_PARK_TTL_MS) {
89407
+ counts.edgesDroppedExpired++;
89408
+ continue;
89409
+ }
89410
+ if (e.state === "dropped" && now - (e.droppedAt ?? e.ts) >= tombstoneTtl(e)) continue;
89411
+ live3.push(e);
89412
+ }
89413
+ let next = live3;
89414
+ if (next.length > EDGE_PARK_CAP) {
89415
+ const over = next.length - EDGE_PARK_CAP;
89416
+ const order = [...next].sort((a, b) => (a.state === b.state ? 0 : a.state === "dropped" ? -1 : 1) || a.ts - b.ts);
89417
+ const evict = new Set(order.slice(0, over).map((e) => e.key));
89418
+ counts.edgesDroppedCapped = order.slice(0, over).filter((e) => e.state === "parked").length;
89419
+ next = next.filter((e) => !evict.has(e.key));
89420
+ }
89421
+ counts.edgeParkSize = next.filter((e) => e.state === "parked").length;
89422
+ counts.edgeTombstones = next.length - counts.edgeParkSize;
89423
+ return { queue: next, counts };
89424
+ }
89425
+
89031
89426
  // src/instance-receipts.ts
89032
89427
  import { createHash as createHash18 } from "node:crypto";
89033
89428
  var INSTANCE_SEMANTIC_EDGE_TYPES = ["CAUSED_BY", "SOLVED_BY"];
@@ -89169,7 +89564,7 @@ function invalidateInstanceReceipt(current, destination, failedId, mirrorLegacy)
89169
89564
  // src/multi.ts
89170
89565
  init_dist();
89171
89566
  init_src5();
89172
- import { existsSync as existsSync34, writeFileSync as writeFileSync27 } from "node:fs";
89567
+ import { existsSync as existsSync34, writeFileSync as writeFileSync28 } from "node:fs";
89173
89568
  import { resolve as pathResolve } from "node:path";
89174
89569
 
89175
89570
  // src/principle-sync.ts
@@ -89198,8 +89593,8 @@ init_reconcile();
89198
89593
 
89199
89594
  // src/lockfile-auto.ts
89200
89595
  init_src();
89201
- import { existsSync as existsSync30, readFileSync as readFileSync33 } from "node:fs";
89202
- import { join as join36 } from "node:path";
89596
+ import { existsSync as existsSync30, readFileSync as readFileSync34 } from "node:fs";
89597
+ import { join as join37 } from "node:path";
89203
89598
 
89204
89599
  // src/package-index.ts
89205
89600
  init_src();
@@ -89351,11 +89746,11 @@ function runLockfilePass(opts) {
89351
89746
  { file: "package-lock.json", parse: parsePackageLockJson }
89352
89747
  ];
89353
89748
  for (const c of candidates) {
89354
- const p = join36(opts.root, c.file);
89749
+ const p = join37(opts.root, c.file);
89355
89750
  if (!existsSync30(p)) continue;
89356
89751
  let sbom;
89357
89752
  try {
89358
- sbom = c.parse(readFileSync33(p, "utf8"));
89753
+ sbom = c.parse(readFileSync34(p, "utf8"));
89359
89754
  } catch {
89360
89755
  continue;
89361
89756
  }
@@ -89416,8 +89811,8 @@ init_profile2();
89416
89811
  init_session_registry();
89417
89812
 
89418
89813
  // src/public-symbols.ts
89419
- import { readFileSync as readFileSync34, readdirSync as readdirSync12, existsSync as existsSync31 } from "node:fs";
89420
- import { join as join37 } from "node:path";
89814
+ import { readFileSync as readFileSync35, readdirSync as readdirSync12, existsSync as existsSync31 } from "node:fs";
89815
+ import { join as join38 } from "node:path";
89421
89816
  var HEAD_BYTES = 8 * 1024;
89422
89817
  var INDEX_TTL_MS = 10 * 60 * 1e3;
89423
89818
  var MIN_SYMBOL_LEN = 4;
@@ -89450,20 +89845,20 @@ function bindingNames(clause) {
89450
89845
  function internalPackageNames(workspaceRoot) {
89451
89846
  const names = /* @__PURE__ */ new Set();
89452
89847
  const tryRead = (dir) => {
89453
- const pj = join37(dir, "package.json");
89848
+ const pj = join38(dir, "package.json");
89454
89849
  if (!existsSync31(pj)) return;
89455
89850
  try {
89456
- const name2 = JSON.parse(readFileSync34(pj, "utf8")).name;
89851
+ const name2 = JSON.parse(readFileSync35(pj, "utf8")).name;
89457
89852
  if (typeof name2 === "string" && name2.length > 0) names.add(name2);
89458
89853
  } catch {
89459
89854
  }
89460
89855
  };
89461
89856
  tryRead(workspaceRoot);
89462
89857
  for (const group of ["packages", "apps"]) {
89463
- const groupDir = join37(workspaceRoot, group);
89858
+ const groupDir = join38(workspaceRoot, group);
89464
89859
  if (!existsSync31(groupDir)) continue;
89465
89860
  try {
89466
- for (const entry of readdirSync12(groupDir)) tryRead(join37(groupDir, entry));
89861
+ for (const entry of readdirSync12(groupDir)) tryRead(join38(groupDir, entry));
89467
89862
  } catch {
89468
89863
  }
89469
89864
  }
@@ -89482,7 +89877,7 @@ function publicSymbolIndex(store, workspaceRoot, deps = {}) {
89482
89877
  }
89483
89878
  const readHead = deps.readHead ?? ((absPath) => {
89484
89879
  try {
89485
- return readFileSync34(absPath, "utf8").slice(0, HEAD_BYTES);
89880
+ return readFileSync35(absPath, "utf8").slice(0, HEAD_BYTES);
89486
89881
  } catch {
89487
89882
  return "";
89488
89883
  }
@@ -89502,7 +89897,7 @@ function publicSymbolIndex(store, workspaceRoot, deps = {}) {
89502
89897
  }
89503
89898
  const symbols = /* @__PURE__ */ new Set();
89504
89899
  for (const rel of files) {
89505
- const head2 = readHead(join37(workspaceRoot, rel));
89900
+ const head2 = readHead(join38(workspaceRoot, rel));
89506
89901
  if (!head2) continue;
89507
89902
  for (const re of [NAMED_IMPORT_RE, REQUIRE_RE]) {
89508
89903
  re.lastIndex = 0;
@@ -89727,7 +90122,9 @@ function buildInstanceIngest(store, profile, daemonVersion, ignorePatterns = [],
89727
90122
  sidecarNoSummary: 0,
89728
90123
  fileRefsSubstituted: 0,
89729
90124
  fileRefLexiconMisses: 0,
89730
- collapsedEdges: 0
90125
+ collapsedEdges: 0,
90126
+ edgesHeldParked: 0,
90127
+ edgesHeldDropped: 0
89731
90128
  };
89732
90129
  const sharedCauses = /* @__PURE__ */ new Map();
89733
90130
  const causalQueue = store.findNodeFieldsByLabel("Problem", ["source", "resolvedAs"]).filter((r) => r.attrs["source"] !== "cloud" && r.attrs["resolvedAs"] !== PROBLEM_RESOLUTION.FALSE_POSITIVE).map((r) => r.id).filter((id) => ignorePatterns.length === 0 || !ignored(store.getNode(id)?.description ?? ""));
@@ -90038,6 +90435,30 @@ function buildInstanceIngest(store, profile, daemonVersion, ignorePatterns = [],
90038
90435
  if (count > 0) symbolSummaries = sidecar;
90039
90436
  }
90040
90437
  edges.push(...anchorEdges);
90438
+ if (opts.edgeHolds && Object.keys(opts.edgeHolds).length > 0) {
90439
+ const holds = opts.edgeHolds;
90440
+ const shipsHere = (wireId) => (endpointSources[wireId] ?? [wireId]).some((localId) => shippedById.has(localId));
90441
+ const kept = [];
90442
+ for (const e of edges) {
90443
+ const hold = holds[e.id];
90444
+ if (!hold || hold === "held" && (shipsHere(e.from) || shipsHere(e.to))) {
90445
+ kept.push(e);
90446
+ continue;
90447
+ }
90448
+ if (hold === "held") {
90449
+ composition.edgesHeldParked++;
90450
+ for (const localId of endpointSources[e.from] ?? [e.from]) {
90451
+ delete anchorDigests[localId];
90452
+ delete semanticEdgeDigests[localId];
90453
+ delete projectAnchorDigests[localId];
90454
+ }
90455
+ } else {
90456
+ composition.edgesHeldDropped++;
90457
+ }
90458
+ }
90459
+ edges.length = 0;
90460
+ edges.push(...kept);
90461
+ }
90041
90462
  const bindingEndpoints = /* @__PURE__ */ new Set();
90042
90463
  for (const e of edges) {
90043
90464
  if (e.type === "CAUSED_BY" || e.type === "SOLVED_BY") {
@@ -90203,7 +90624,8 @@ function buildDrainInstances(store, sharedStore, input) {
90203
90624
  ...lexicon ? { lexicon } : {},
90204
90625
  ...fileLexicon ? { fileLexicon } : {},
90205
90626
  ...input.project ? { project: input.project } : {},
90206
- ...input.quarantinedSessions?.length ? { quarantinedSessions: input.quarantinedSessions } : {}
90627
+ ...input.quarantinedSessions?.length ? { quarantinedSessions: input.quarantinedSessions } : {},
90628
+ ...input.edgeHolds ? { edgeHolds: input.edgeHolds } : {}
90207
90629
  });
90208
90630
  return {
90209
90631
  batch,
@@ -90460,7 +90882,7 @@ init_config();
90460
90882
 
90461
90883
  // src/update.ts
90462
90884
  import { spawn as spawn2 } from "node:child_process";
90463
- import { isAbsolute as isAbsolute6, join as join38 } from "node:path";
90885
+ import { isAbsolute as isAbsolute6, join as join39 } from "node:path";
90464
90886
  var PACKAGE_NAME = "@inerrata-corporation/errata";
90465
90887
  function parse3(v) {
90466
90888
  const m = /^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z][0-9A-Za-z.-]*))?/.exec(v.trim());
@@ -90607,7 +91029,7 @@ async function runInstalledHookRefresh() {
90607
91029
  });
90608
91030
  if (!isAbsolute6(root)) return 1;
90609
91031
  return new Promise((resolve10) => {
90610
- const child = spawn2(process.execPath, [join38(root, PACKAGE_NAME, "errata.mjs"), "install-hooks", "codex", "--refresh-existing"], {
91032
+ const child = spawn2(process.execPath, [join39(root, PACKAGE_NAME, "errata.mjs"), "install-hooks", "codex", "--refresh-existing"], {
90611
91033
  windowsHide: true,
90612
91034
  stdio: "inherit",
90613
91035
  timeout: 3e4
@@ -90753,12 +91175,12 @@ function landCloudEdge(store, e, from, to) {
90753
91175
  }
90754
91176
 
90755
91177
  // src/causal-edge-queue.ts
90756
- import { readFileSync as readFileSync35, renameSync as renameSync5, writeFileSync as writeFileSync25 } from "node:fs";
90757
- import { dirname as dirname13, join as join39 } from "node:path";
91178
+ import { readFileSync as readFileSync36, renameSync as renameSync6, writeFileSync as writeFileSync26 } from "node:fs";
91179
+ import { dirname as dirname14, join as join40 } from "node:path";
90758
91180
  var CAUSAL_EDGE_QUEUE_CAP = 5e3;
90759
91181
  var CAUSAL_EDGE_TTL_MS = 30 * 24 * 60 * 60 * 1e3;
90760
91182
  function causalEdgeQueuePath(workspaceConfigDir) {
90761
- return join39(workspaceConfigDir, "causal-edge-queue.json");
91183
+ return join40(workspaceConfigDir, "causal-edge-queue.json");
90762
91184
  }
90763
91185
  function parkedEdgeKey(e) {
90764
91186
  return `${e.from}|${e.type}|${e.to}`;
@@ -90766,7 +91188,7 @@ function parkedEdgeKey(e) {
90766
91188
  function loadCausalEdgeQueue(path3) {
90767
91189
  let raw2;
90768
91190
  try {
90769
- raw2 = JSON.parse(readFileSync35(path3, "utf8"));
91191
+ raw2 = JSON.parse(readFileSync36(path3, "utf8"));
90770
91192
  } catch {
90771
91193
  return [];
90772
91194
  }
@@ -90777,9 +91199,9 @@ function loadCausalEdgeQueue(path3) {
90777
91199
  }
90778
91200
  function saveCausalEdgeQueue(path3, queue) {
90779
91201
  try {
90780
- const tmp = join39(dirname13(path3), `.${Date.now()}.causal-edge-queue.tmp`);
90781
- writeFileSync25(tmp, JSON.stringify(queue), "utf8");
90782
- renameSync5(tmp, path3);
91202
+ const tmp = join40(dirname14(path3), `.${Date.now()}.causal-edge-queue.tmp`);
91203
+ writeFileSync26(tmp, JSON.stringify(queue), "utf8");
91204
+ renameSync6(tmp, path3);
90783
91205
  } catch {
90784
91206
  }
90785
91207
  }
@@ -91450,8 +91872,8 @@ async function syncHistoryRevisionPage(opts) {
91450
91872
  init_src7();
91451
91873
  init_src();
91452
91874
  import { execFile as execFile6 } from "node:child_process";
91453
- import { readFileSync as readFileSync36 } from "node:fs";
91454
- import { join as join40 } from "node:path";
91875
+ import { readFileSync as readFileSync37 } from "node:fs";
91876
+ import { join as join41 } from "node:path";
91455
91877
  import { promisify as promisify5 } from "node:util";
91456
91878
 
91457
91879
  // src/history-walk.ts
@@ -92003,7 +92425,7 @@ async function defaultGit(root, args2) {
92003
92425
  function readIgnoreLines(root, profile) {
92004
92426
  let lines = [];
92005
92427
  try {
92006
- lines = readFileSync36(join40(root, ".errataignore"), "utf8").split("\n");
92428
+ lines = readFileSync37(join41(root, ".errataignore"), "utf8").split("\n");
92007
92429
  } catch {
92008
92430
  }
92009
92431
  return [...lines, ...profile.ignoreExtra ?? []].map((l) => l.trim()).filter((l) => l && !l.startsWith("#"));
@@ -92579,8 +93001,8 @@ async function startHistoryStage(root, input, client, walk11 = {}) {
92579
93001
  init_cloud_auth();
92580
93002
  import { createHash as createHash19 } from "node:crypto";
92581
93003
  import { execFileSync as execFileSync6 } from "node:child_process";
92582
- import { existsSync as existsSync32, writeFileSync as writeFileSync26 } from "node:fs";
92583
- import { join as join41 } from "node:path";
93004
+ import { existsSync as existsSync32, writeFileSync as writeFileSync27 } from "node:fs";
93005
+ import { join as join42 } from "node:path";
92584
93006
 
92585
93007
  // src/device-poll.ts
92586
93008
  var THROTTLED_POLL_MIN_WAIT_MS = 11e3;
@@ -93039,9 +93461,9 @@ function applyLinkDecision(root, profile, config2, decision, now = Date.now) {
93039
93461
  delete nextProfile.projectLinkHold;
93040
93462
  let wroteIgnore = false;
93041
93463
  if (decision.writeIgnoreStarter !== false) {
93042
- const target = join41(root, ".errataignore");
93464
+ const target = join42(root, ".errataignore");
93043
93465
  if (!existsSync32(target)) {
93044
- writeFileSync26(target, IGNORE_STARTER, "utf8");
93466
+ writeFileSync27(target, IGNORE_STARTER, "utf8");
93045
93467
  wroteIgnore = true;
93046
93468
  }
93047
93469
  }
@@ -93055,12 +93477,12 @@ init_registry();
93055
93477
  // src/adopt.ts
93056
93478
  init_git_remote();
93057
93479
  import { existsSync as existsSync33 } from "node:fs";
93058
- import { dirname as dirname14, join as join42 } from "node:path";
93480
+ import { dirname as dirname15, join as join43 } from "node:path";
93059
93481
  function findGitRoot(absPath) {
93060
93482
  let dir = absPath;
93061
93483
  for (let depth = 0; depth < 64; depth++) {
93062
- if (existsSync33(join42(dir, ".git"))) return dir;
93063
- const parent = dirname14(dir);
93484
+ if (existsSync33(join43(dir, ".git"))) return dir;
93485
+ const parent = dirname15(dir);
93064
93486
  if (parent === dir) return null;
93065
93487
  dir = parent;
93066
93488
  }
@@ -93777,7 +94199,7 @@ async function startMultiDaemon(opts = {}) {
93777
94199
  records.push(rec);
93778
94200
  void ambientLinkAll();
93779
94201
  try {
93780
- writeFileSync27(
94202
+ writeFileSync28(
93781
94203
  rec.engine.paths.daemonLock,
93782
94204
  daemonLockPayload({
93783
94205
  pid: process.pid,
@@ -94156,7 +94578,7 @@ async function startMultiDaemon(opts = {}) {
94156
94578
  baseUrl = `http://127.0.0.1:${port}`;
94157
94579
  try {
94158
94580
  ensureDir(globalDir());
94159
- writeFileSync27(
94581
+ writeFileSync28(
94160
94582
  lockPath,
94161
94583
  daemonLockPayload({ pid: process.pid, webUiUrl: baseUrl, processStartedAt: PROCESS_STARTED_AT, entry: SELF_ENTRY, version: DAEMON_VERSION }),
94162
94584
  "utf8"
@@ -94165,7 +94587,7 @@ async function startMultiDaemon(opts = {}) {
94165
94587
  }
94166
94588
  for (const r of records) {
94167
94589
  try {
94168
- writeFileSync27(
94590
+ writeFileSync28(
94169
94591
  r.engine.paths.daemonLock,
94170
94592
  daemonLockPayload({
94171
94593
  pid: process.pid,
@@ -94866,7 +95288,10 @@ async function startMultiDaemon(opts = {}) {
94866
95288
  projectId: project?.projectId,
94867
95289
  writeTarget: project ? null : receiptContext.context.default_write_target
94868
95290
  });
95291
+ const parkPath = edgeParkPath(r.engine.paths.configDir, destinationKey);
95292
+ const parkQueue = loadEdgePark(parkPath);
94869
95293
  const built = await buildInstanceBatch(r, {
95294
+ edgeHolds: edgeHolds(parkQueue, Date.now()),
94870
95295
  destinationKey,
94871
95296
  profile: r.engine.profile,
94872
95297
  daemonVersion: DAEMON_VERSION,
@@ -94892,7 +95317,8 @@ async function startMultiDaemon(opts = {}) {
94892
95317
  // straddle rows where the counter is merely absent.
94893
95318
  blockedRepeat: 0,
94894
95319
  rejectedRepeat: 0,
94895
- edgesRejected: 0
95320
+ edgesRejected: 0,
95321
+ ...zeroEdgeSettleCounts(parkQueue)
94896
95322
  });
94897
95323
  }
94898
95324
  if (instances) {
@@ -94957,14 +95383,26 @@ async function startMultiDaemon(opts = {}) {
94957
95383
  if (typeof cloudId === "string" && cloudId) cloudIds.set(localId, cloudId);
94958
95384
  }
94959
95385
  const edgeReceipts = instanceEdgeReceipts(instances.edges, res.result.edges, cloudIds);
95386
+ const echo = /* @__PURE__ */ new Map();
95387
+ for (const node2 of res.result.nodes) {
95388
+ if (node2.nodeId && node2.decision !== "rejected") echo.set(node2.canonicalId, node2.nodeId);
95389
+ }
95390
+ const settled = settleEdgeOutcomes(
95391
+ parkQueue,
95392
+ instances.edges,
95393
+ matchEdgeVerdicts(instances.edges, res.result.edges, echo),
95394
+ Date.now()
95395
+ );
95396
+ saveEdgePark(parkPath, settled.queue);
95397
+ const edgeCounts = settled.counts;
94960
95398
  if (rejectedEdges.length > 0) {
94961
95399
  const byReason = /* @__PURE__ */ new Map();
94962
95400
  for (const re of rejectedEdges) {
94963
- const why = `${re.type}: ${re.reason ?? "no reason given"}`;
95401
+ const why = `${re.type}: ${(re.reason ?? "no reason given").replace(/'[^']*'/g, "'\u2026'")}`;
94964
95402
  byReason.set(why, (byReason.get(why) ?? 0) + 1);
94965
95403
  }
94966
95404
  console.warn(
94967
- `[sync\u2192cloud] [${projectName}] instances: ${rejectedEdges.length} edge(s) REJECTED by the door: ` + [...byReason.entries()].map(([why, n]) => `${n}\xD7 ${why}`).join(" | ")
95405
+ `[sync\u2192cloud] [${projectName}] instances: ${rejectedEdges.length} edge(s) REJECTED by the door (parked ${edgeCounts.edgesParked}, re-parked ${edgeCounts.edgesReparked}, dropped ${edgeCounts.edgesDroppedRefused + edgeCounts.edgesDroppedExhausted + edgeCounts.edgesDroppedExpired}; park now ${edgeCounts.edgeParkSize}): ` + [...byReason.entries()].map(([why, n]) => `${n}\xD7 ${why}`).join(" | ")
94968
95406
  );
94969
95407
  }
94970
95408
  if (rejected.size > 0) {
@@ -95041,7 +95479,13 @@ async function startMultiDaemon(opts = {}) {
95041
95479
  });
95042
95480
  });
95043
95481
  let invalidatedReceipts = 0;
95482
+ const affirmedThisDrain = new Set(echo.values());
95483
+ let invalidationSkipped = 0;
95044
95484
  for (const failedId of invalidInstanceEndpointIds(res.result.edges)) {
95485
+ if (affirmedThisDrain.has(failedId)) {
95486
+ invalidationSkipped++;
95487
+ continue;
95488
+ }
95045
95489
  const localIds = new Set(instances.endpointSources[failedId] ?? []);
95046
95490
  for (const [wireId, cloudId] of cloudIds) if (cloudId === failedId) {
95047
95491
  for (const id of instances.endpointSources[wireId] ?? [instances.contextNodeSources[wireId] ?? wireId]) localIds.add(id);
@@ -95068,7 +95512,9 @@ async function startMultiDaemon(opts = {}) {
95068
95512
  // failing every pass. Same total, different bug.
95069
95513
  blockedRepeat,
95070
95514
  rejectedRepeat,
95071
- edgesRejected: rejectedEdges.length
95515
+ edgesRejected: rejectedEdges.length,
95516
+ invalidationSkipped,
95517
+ ...edgeCounts
95072
95518
  });
95073
95519
  return res.accepted;
95074
95520
  });
@@ -95660,7 +96106,7 @@ import { spawnSync as spawnSync2 } from "node:child_process";
95660
96106
 
95661
96107
  // src/codex-runtime.ts
95662
96108
  import { readdirSync as readdirSync13, statSync as statSync10 } from "node:fs";
95663
- import { join as join43 } from "node:path";
96109
+ import { join as join44 } from "node:path";
95664
96110
  function resolveCodexExecutable(options = {}) {
95665
96111
  const platform = options.platform ?? process.platform;
95666
96112
  const env2 = options.env ?? process.env;
@@ -95675,13 +96121,13 @@ function resolveCodexExecutable(options = {}) {
95675
96121
  };
95676
96122
  for (const dir of (env2["PATH"] ?? env2["Path"] ?? "").split(";")) {
95677
96123
  if (!dir.trim()) continue;
95678
- const path3 = join43(dir.trim().replace(/^"|"$/g, ""), "codex.exe");
96124
+ const path3 = join44(dir.trim().replace(/^"|"$/g, ""), "codex.exe");
95679
96125
  if (fileTime(path3) !== null) return path3;
95680
96126
  }
95681
96127
  if (!env2["LOCALAPPDATA"]) return "codex";
95682
- const root = join43(env2["LOCALAPPDATA"], "OpenAI", "Codex", "bin");
96128
+ const root = join44(env2["LOCALAPPDATA"], "OpenAI", "Codex", "bin");
95683
96129
  try {
95684
- 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));
96130
+ const candidates = readdirSync13(root, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => join44(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));
95685
96131
  return candidates[0]?.path ?? "codex";
95686
96132
  } catch {
95687
96133
  return "codex";
@@ -95820,14 +96266,14 @@ async function diagnoseInstallation(cfg, dependencies) {
95820
96266
 
95821
96267
  // src/codex-doctor.ts
95822
96268
  import { spawn as spawn4 } from "node:child_process";
95823
- import { readFileSync as readFileSync38, statSync as statSync11 } from "node:fs";
95824
- import { join as join45 } from "node:path";
96269
+ import { readFileSync as readFileSync39, statSync as statSync11 } from "node:fs";
96270
+ import { join as join46 } from "node:path";
95825
96271
  import { createInterface } from "node:readline";
95826
96272
 
95827
96273
  // src/codex-hooks.ts
95828
- import { existsSync as existsSync35, mkdirSync as mkdirSync9, readFileSync as readFileSync37, renameSync as renameSync6, unlinkSync as unlinkSync5, writeFileSync as writeFileSync28 } from "node:fs";
96274
+ import { existsSync as existsSync35, mkdirSync as mkdirSync9, readFileSync as readFileSync38, renameSync as renameSync7, unlinkSync as unlinkSync5, writeFileSync as writeFileSync29 } from "node:fs";
95829
96275
  import { homedir as homedir7 } from "node:os";
95830
- import { join as join44 } from "node:path";
96276
+ import { join as join45 } from "node:path";
95831
96277
 
95832
96278
  // src/hook-commands.ts
95833
96279
  function hookCurlCommand(port, path3 = "/api/hook") {
@@ -96031,34 +96477,34 @@ function buildCodexRelaySource(workspaceRoot) {
96031
96477
  init_checkout_root();
96032
96478
  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.";
96033
96479
  function writeRelay(file2, source) {
96034
- if (existsSync35(file2) && readFileSync37(file2, "utf8") === source) return;
96480
+ if (existsSync35(file2) && readFileSync38(file2, "utf8") === source) return;
96035
96481
  const temp = `${file2}.${process.pid}.tmp`;
96036
96482
  try {
96037
- writeFileSync28(temp, source, { encoding: "utf8", mode: 384 });
96038
- renameSync6(temp, file2);
96483
+ writeFileSync29(temp, source, { encoding: "utf8", mode: 384 });
96484
+ renameSync7(temp, file2);
96039
96485
  } finally {
96040
96486
  if (existsSync35(temp)) unlinkSync5(temp);
96041
96487
  }
96042
96488
  }
96043
96489
  function refreshCodexRelay(root) {
96044
- const config2 = join44(root, ".codex", "config.toml");
96490
+ const config2 = join45(root, ".codex", "config.toml");
96045
96491
  if (!existsSync35(config2)) return "absent";
96046
- const existing = readFileSync37(config2, "utf8");
96492
+ const existing = readFileSync38(config2, "utf8");
96047
96493
  if (!existing.includes(CODEX_HOOKS_BEGIN) && !existing.includes(CODEX_HOOKS_END)) return "absent";
96048
96494
  replaceCodexHooks(existing, "");
96049
- const relay = join44(root, ".codex", "hooks", "errata-relay.mjs");
96050
- const prior = existsSync35(relay) ? readFileSync37(relay, "utf8") : "";
96495
+ const relay = join45(root, ".codex", "hooks", "errata-relay.mjs");
96496
+ const prior = existsSync35(relay) ? readFileSync38(relay, "utf8") : "";
96051
96497
  if (prior && !prior.startsWith("// errata-managed: regenerated by errata install-hooks codex")) {
96052
96498
  throw new Error("Codex relay is not Errata-managed; preserved it. Run errata install-hooks codex to explicitly replace it.");
96053
96499
  }
96054
96500
  const source = buildCodexRelaySource(checkoutRootOf(root));
96055
96501
  if (prior === source) return "current";
96056
- mkdirSync9(join44(root, ".codex", "hooks"), { recursive: true });
96502
+ mkdirSync9(join45(root, ".codex", "hooks"), { recursive: true });
96057
96503
  writeRelay(relay, source);
96058
96504
  return "updated";
96059
96505
  }
96060
- function hasCodexConfig(root, codexHome = process.env["CODEX_HOME"] || join44(homedir7(), ".codex")) {
96061
- return existsSync35(join44(root, ".codex")) || existsSync35(codexHome);
96506
+ function hasCodexConfig(root, codexHome = process.env["CODEX_HOME"] || join45(homedir7(), ".codex")) {
96507
+ return existsSync35(join45(root, ".codex")) || existsSync35(codexHome);
96062
96508
  }
96063
96509
  function replaceCodexHooks(existing, block) {
96064
96510
  const begin = existing.indexOf(CODEX_HOOKS_BEGIN);
@@ -96074,14 +96520,14 @@ function replaceCodexHooks(existing, block) {
96074
96520
  return existing.trimEnd() + (existing.trim() ? "\n\n" : "") + block;
96075
96521
  }
96076
96522
  function writeCodexHooks(root, port, nodePath = process.execPath) {
96077
- const dir = join44(root, ".codex");
96078
- const file2 = join44(dir, "config.toml");
96079
- const relay = join44(dir, "hooks", "errata-relay.mjs");
96523
+ const dir = join45(root, ".codex");
96524
+ const file2 = join45(dir, "config.toml");
96525
+ const relay = join45(dir, "hooks", "errata-relay.mjs");
96080
96526
  const block = buildCodexHooksToml(port, { nodePath, relayPath: relay });
96081
- const final = replaceCodexHooks(existsSync35(file2) ? readFileSync37(file2, "utf8") : "", block);
96082
- mkdirSync9(join44(dir, "hooks"), { recursive: true });
96527
+ const final = replaceCodexHooks(existsSync35(file2) ? readFileSync38(file2, "utf8") : "", block);
96528
+ mkdirSync9(join45(dir, "hooks"), { recursive: true });
96083
96529
  writeRelay(relay, buildCodexRelaySource(checkoutRootOf(root)));
96084
- if (!existsSync35(file2) || readFileSync37(file2, "utf8") !== final) writeFileSync28(file2, final, "utf8");
96530
+ if (!existsSync35(file2) || readFileSync38(file2, "utf8") !== final) writeFileSync29(file2, final, "utf8");
96085
96531
  return file2;
96086
96532
  }
96087
96533
 
@@ -96090,7 +96536,7 @@ init_checkout_root();
96090
96536
  function inspectCodexRelay(cwd) {
96091
96537
  const root = nearestGitRoot(cwd) ?? cwd;
96092
96538
  try {
96093
- const source = readFileSync38(join45(root, ".codex", "hooks", "errata-relay.mjs"), "utf8");
96539
+ const source = readFileSync39(join46(root, ".codex", "hooks", "errata-relay.mjs"), "utf8");
96094
96540
  if (source === buildCodexRelaySource(checkoutRootOf(root))) {
96095
96541
  return { id: "codex_relay", status: "pass", detail: "Installed Codex relay matches this Errata version" };
96096
96542
  }
@@ -96101,8 +96547,8 @@ function inspectCodexRelay(cwd) {
96101
96547
  function inspectCodexContext(cwd) {
96102
96548
  const root = checkoutRootOf(nearestGitRoot(cwd) ?? cwd);
96103
96549
  try {
96104
- const file2 = join45(root, ".errata", "context.md");
96105
- if (statSync11(file2).size <= 128 * 1024 && readFileSync38(file2, "utf8").trim()) {
96550
+ const file2 = join46(root, ".errata", "context.md");
96551
+ if (statSync11(file2).size <= 128 * 1024 && readFileSync39(file2, "utf8").trim()) {
96106
96552
  return { id: "codex_context", status: "pass", detail: "Saved workspace context is readable by the relay; this does not prove live daemon freshness" };
96107
96553
  }
96108
96554
  } catch {
@@ -96280,9 +96726,9 @@ function consolidationGapMs(lastPassMs, policy) {
96280
96726
 
96281
96727
  // src/codex-context-plugin.ts
96282
96728
  import { createHash as createHash20 } from "node:crypto";
96283
- import { cpSync as cpSync2, existsSync as existsSync36, mkdirSync as mkdirSync10, readFileSync as readFileSync39, renameSync as renameSync7, writeFileSync as writeFileSync29 } from "node:fs";
96729
+ import { cpSync as cpSync2, existsSync as existsSync36, mkdirSync as mkdirSync10, readFileSync as readFileSync40, renameSync as renameSync8, writeFileSync as writeFileSync30 } from "node:fs";
96284
96730
  import { homedir as homedir8 } from "node:os";
96285
- import { join as join46 } from "node:path";
96731
+ import { join as join47 } from "node:path";
96286
96732
  import { fileURLToPath as fileURLToPath2 } from "node:url";
96287
96733
 
96288
96734
  // ../../node_modules/.pnpm/smol-toml@1.6.1/node_modules/smol-toml/dist/error.js
@@ -96980,23 +97426,23 @@ var NAME = "errata-context";
96980
97426
  var PREFIX2 = `./.errata/plugins/${NAME}/`;
96981
97427
  var object2 = (value) => value !== null && typeof value === "object" && !Array.isArray(value) ? value : {};
96982
97428
  function readText(file2) {
96983
- return existsSync36(file2) ? readFileSync39(file2, "utf8") : "";
97429
+ return existsSync36(file2) ? readFileSync40(file2, "utf8") : "";
96984
97430
  }
96985
97431
  function writeChanged(file2, content) {
96986
97432
  if (readText(file2) === content) return;
96987
97433
  const temp = `${file2}.${process.pid}.tmp`;
96988
- writeFileSync29(temp, content, "utf8");
96989
- renameSync7(temp, file2);
97434
+ writeFileSync30(temp, content, "utf8");
97435
+ renameSync8(temp, file2);
96990
97436
  }
96991
97437
  function bundledContextPlugin() {
96992
97438
  const packaged = fileURLToPath2(new URL("./resources/context-plugin/", import.meta.url));
96993
- if (existsSync36(join46(packaged, ".codex-plugin/plugin.json"))) return packaged;
97439
+ if (existsSync36(join47(packaged, ".codex-plugin/plugin.json"))) return packaged;
96994
97440
  return fileURLToPath2(new URL("../dist/resources/context-plugin/", import.meta.url));
96995
97441
  }
96996
97442
  function refreshCodexContextPlugin(root) {
96997
- const file2 = join46(root, ".agents", "plugins", "marketplace.json");
97443
+ const file2 = join47(root, ".agents", "plugins", "marketplace.json");
96998
97444
  if (!existsSync36(file2)) return false;
96999
- const marketplace = JSON.parse(readFileSync39(file2, "utf8"));
97445
+ const marketplace = JSON.parse(readFileSync40(file2, "utf8"));
97000
97446
  const entries = Array.isArray(marketplace.plugins) ? marketplace.plugins : [];
97001
97447
  const entry = entries.map(object2).find((value) => value.name === NAME && String(object2(value.source).path).startsWith(PREFIX2));
97002
97448
  if (!entry) return false;
@@ -97007,24 +97453,24 @@ function refreshCodexContextPlugin(root) {
97007
97453
  function installCodexContextPlugin(root, options = {}) {
97008
97454
  const bundle = options.bundle ?? bundledContextPlugin();
97009
97455
  const manifest = JSON.parse(
97010
- readFileSync39(join46(bundle, ".codex-plugin/plugin.json"), "utf8")
97456
+ readFileSync40(join47(bundle, ".codex-plugin/plugin.json"), "utf8")
97011
97457
  );
97012
97458
  if (manifest.name !== NAME || typeof manifest.version !== "string" || !/^[\w.-]+$/.test(manifest.version)) {
97013
97459
  throw new Error("Invalid bundled Errata Context manifest.");
97014
97460
  }
97015
- const checksums = readFileSync39(join46(bundle, "SHA256SUMS"), "utf8");
97461
+ const checksums = readFileSync40(join47(bundle, "SHA256SUMS"), "utf8");
97016
97462
  for (const line of checksums.trim().split("\n")) {
97017
97463
  const match2 = /^([a-f0-9]{64}) ([\w./-]+)$/.exec(line);
97018
97464
  if (!match2 || match2[2].startsWith("/") || match2[2].split("/").includes("..")) {
97019
97465
  throw new Error("Invalid bundled Errata Context checksum manifest.");
97020
97466
  }
97021
- const actual = createHash20("sha256").update(readFileSync39(join46(bundle, match2[2]))).digest("hex");
97467
+ const actual = createHash20("sha256").update(readFileSync40(join47(bundle, match2[2]))).digest("hex");
97022
97468
  if (actual !== match2[1])
97023
97469
  throw new Error(`Bundled Errata Context checksum mismatch: ${match2[2]}`);
97024
97470
  }
97025
97471
  const release = `${manifest.version}-${createHash20("sha256").update(checksums).digest("hex").slice(0, 12)}`;
97026
- const plugin = join46(root, ".errata", "plugins", NAME, release);
97027
- const marketplaceFile = join46(root, ".agents", "plugins", "marketplace.json");
97472
+ const plugin = join47(root, ".errata", "plugins", NAME, release);
97473
+ const marketplaceFile = join47(root, ".agents", "plugins", "marketplace.json");
97028
97474
  const priorMarketplace = readText(marketplaceFile);
97029
97475
  const marketplace = priorMarketplace ? JSON.parse(priorMarketplace) : {
97030
97476
  name: "errata-local",
@@ -97045,12 +97491,12 @@ function installCodexContextPlugin(root, options = {}) {
97045
97491
  );
97046
97492
  }
97047
97493
  const key = `${NAME}@${marketplace.name}`;
97048
- const configFile = join46(root, ".codex", "config.toml");
97494
+ const configFile = join47(root, ".codex", "config.toml");
97049
97495
  const config2 = readText(configFile);
97050
97496
  const parsed = parse4(config2);
97051
97497
  const plugins = object2(parsed.plugins);
97052
- const codexHome = options.codexHome ?? process.env["CODEX_HOME"] ?? join46(homedir8(), ".codex");
97053
- const globalPlugins = object2(parse4(readText(join46(codexHome, "config.toml"))).plugins);
97498
+ const codexHome = options.codexHome ?? process.env["CODEX_HOME"] ?? join47(homedir8(), ".codex");
97499
+ const globalPlugins = object2(parse4(readText(join47(codexHome, "config.toml"))).plugins);
97054
97500
  const disabledGlobally = Object.entries(globalPlugins).some(
97055
97501
  ([name2, value]) => (name2 === NAME || name2.startsWith(`${NAME}@`)) && object2(value).enabled === false
97056
97502
  );
@@ -97074,13 +97520,13 @@ enabled = ${enabled}
97074
97520
  mkdirSync10(plugin, { recursive: true });
97075
97521
  cpSync2(bundle, plugin, { recursive: true });
97076
97522
  writeChanged(
97077
- join46(plugin, ".mcp.json"),
97523
+ join47(plugin, ".mcp.json"),
97078
97524
  JSON.stringify(
97079
97525
  {
97080
97526
  mcpServers: {
97081
97527
  errata_context: {
97082
97528
  command: options.nodePath ?? process.execPath,
97083
- args: [join46(plugin, "dist", "mcp-server.mjs")],
97529
+ args: [join47(plugin, "dist", "mcp-server.mjs")],
97084
97530
  env: { ERRATA_WORKSPACE: root, ERRATA_CONTEXT_VERSION: manifest.version }
97085
97531
  }
97086
97532
  }
@@ -97089,8 +97535,8 @@ enabled = ${enabled}
97089
97535
  2
97090
97536
  ) + "\n"
97091
97537
  );
97092
- mkdirSync10(join46(root, ".agents", "plugins"), { recursive: true });
97093
- mkdirSync10(join46(root, ".codex"), { recursive: true });
97538
+ mkdirSync10(join47(root, ".agents", "plugins"), { recursive: true });
97539
+ mkdirSync10(join47(root, ".codex"), { recursive: true });
97094
97540
  writeChanged(marketplaceFile, JSON.stringify(marketplace, null, 2) + "\n");
97095
97541
  writeChanged(configFile, nextConfig);
97096
97542
  return { plugin, enabled, marketplace: marketplaceFile };
@@ -97098,15 +97544,15 @@ enabled = ${enabled}
97098
97544
 
97099
97545
  // src/codex-hook-refresh.ts
97100
97546
  init_checkout_root();
97101
- import { existsSync as existsSync37, readdirSync as readdirSync14, readFileSync as readFileSync40 } from "node:fs";
97102
- import { dirname as dirname15, join as join47, resolve as resolve8 } from "node:path";
97547
+ import { existsSync as existsSync37, readdirSync as readdirSync14, readFileSync as readFileSync41 } from "node:fs";
97548
+ import { dirname as dirname16, join as join48, resolve as resolve8 } from "node:path";
97103
97549
  init_registry();
97104
97550
  function codexHookRoots(roots) {
97105
97551
  const found = new Set(roots.map((root) => resolve8(root)));
97106
97552
  for (const root of [...found]) {
97107
97553
  const main2 = mainCheckoutOfWorktree(root) ?? root;
97108
97554
  found.add(main2);
97109
- const dir = join47(main2, ".git", "worktrees");
97555
+ const dir = join48(main2, ".git", "worktrees");
97110
97556
  if (!existsSync37(dir)) continue;
97111
97557
  let names;
97112
97558
  try {
@@ -97116,7 +97562,7 @@ function codexHookRoots(roots) {
97116
97562
  }
97117
97563
  for (const name2 of names) {
97118
97564
  try {
97119
- const checkout = dirname15(readFileSync40(join47(dir, name2, "gitdir"), "utf8").trim());
97565
+ const checkout = dirname16(readFileSync41(join48(dir, name2, "gitdir"), "utf8").trim());
97120
97566
  if (mainCheckoutOfWorktree(checkout) === main2) found.add(checkout);
97121
97567
  } catch {
97122
97568
  }
@@ -97138,9 +97584,9 @@ function refreshInstalledCodexRelays(roots = listWorkspaceEntries().map((entry)
97138
97584
  }
97139
97585
 
97140
97586
  // src/claude-statusline.ts
97141
- import { existsSync as existsSync38, mkdirSync as mkdirSync11, readFileSync as readFileSync41, writeFileSync as writeFileSync30 } from "node:fs";
97587
+ import { existsSync as existsSync38, mkdirSync as mkdirSync11, readFileSync as readFileSync42, writeFileSync as writeFileSync31 } from "node:fs";
97142
97588
  import { homedir as homedir9 } from "node:os";
97143
- import { dirname as dirname16, join as join48 } from "node:path";
97589
+ import { dirname as dirname17, join as join49 } from "node:path";
97144
97590
  var STATUSLINE_RELAY_SOURCE = String.raw`// errata-managed: regenerated by errata init / install-hooks claude
97145
97591
  import { readFileSync } from 'node:fs';
97146
97592
 
@@ -97188,8 +97634,8 @@ function isSameInstall(value, relay) {
97188
97634
  return command.includes(relay.replace(/\\/g, "/").toLowerCase());
97189
97635
  }
97190
97636
  function userClaudeSettingsPath() {
97191
- const base = process.env["CLAUDE_CONFIG_DIR"] ?? join48(homedir9(), ".claude");
97192
- return join48(base, "settings.json");
97637
+ const base = process.env["CLAUDE_CONFIG_DIR"] ?? join49(homedir9(), ".claude");
97638
+ return join49(base, "settings.json");
97193
97639
  }
97194
97640
  function ensureUserStatusLine(opts) {
97195
97641
  const env2 = opts.env ?? process.env;
@@ -97199,21 +97645,21 @@ function ensureUserStatusLine(opts) {
97199
97645
  let settings = {};
97200
97646
  if (existsSync38(settingsPath)) {
97201
97647
  try {
97202
- const parsed = JSON.parse(readFileSync41(settingsPath, "utf8"));
97648
+ const parsed = JSON.parse(readFileSync42(settingsPath, "utf8"));
97203
97649
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return "unreadable";
97204
97650
  settings = parsed;
97205
97651
  } catch {
97206
97652
  return "unreadable";
97207
97653
  }
97208
97654
  }
97209
- const relay = join48(opts.relayDir, STATUSLINE_RELAY_FILE);
97655
+ const relay = join49(opts.relayDir, STATUSLINE_RELAY_FILE);
97210
97656
  const keep = (value) => value !== void 0 && (!isErrataStatusLine(value) || !isSameInstall(value, relay));
97211
97657
  const ownMain = keep(settings["statusLine"]);
97212
97658
  const ownRows = keep(settings["subagentStatusLine"]);
97213
97659
  if (ownMain && ownRows) return "kept-own";
97214
97660
  mkdirSync11(opts.relayDir, { recursive: true });
97215
- if (!existsSync38(relay) || readFileSync41(relay, "utf8") !== STATUSLINE_RELAY_SOURCE) {
97216
- writeFileSync30(relay, STATUSLINE_RELAY_SOURCE, "utf8");
97661
+ if (!existsSync38(relay) || readFileSync42(relay, "utf8") !== STATUSLINE_RELAY_SOURCE) {
97662
+ writeFileSync31(relay, STATUSLINE_RELAY_SOURCE, "utf8");
97217
97663
  }
97218
97664
  const nodePath = opts.nodePath ?? process.execPath;
97219
97665
  const next = {
@@ -97224,8 +97670,8 @@ function ensureUserStatusLine(opts) {
97224
97670
  return ownMain ? "kept-own" : "unchanged";
97225
97671
  }
97226
97672
  Object.assign(settings, next);
97227
- mkdirSync11(dirname16(settingsPath), { recursive: true });
97228
- writeFileSync30(settingsPath, JSON.stringify(settings, null, 2) + "\n", "utf8");
97673
+ mkdirSync11(dirname17(settingsPath), { recursive: true });
97674
+ writeFileSync31(settingsPath, JSON.stringify(settings, null, 2) + "\n", "utf8");
97229
97675
  return "installed";
97230
97676
  }
97231
97677
  function describeStatusLineOutcome(outcome) {
@@ -97245,8 +97691,8 @@ function describeStatusLineOutcome(outcome) {
97245
97691
 
97246
97692
  // src/claude-mods.ts
97247
97693
  import { createHash as createHash21 } from "node:crypto";
97248
- 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";
97249
- import { delimiter as delimiter2, dirname as dirname17, join as join49, relative as relative8, resolve as resolve9, sep as sep5 } from "node:path";
97694
+ import { cpSync as cpSync3, existsSync as existsSync39, mkdirSync as mkdirSync12, readFileSync as readFileSync43, readdirSync as readdirSync15, rmSync as rmSync4, statSync as statSync12, writeFileSync as writeFileSync32 } from "node:fs";
97695
+ import { delimiter as delimiter2, dirname as dirname18, join as join50, relative as relative8, resolve as resolve9, sep as sep5 } from "node:path";
97250
97696
  import { fileURLToPath as fileURLToPath3 } from "node:url";
97251
97697
  var CLAUDE_PLUGIN_DIRS_ENV = "CLAUDE_CODE_PLUGIN_DIRS";
97252
97698
  var HASH_FILE = ".errata-mod-hash";
@@ -97261,7 +97707,7 @@ function isEngineOwned(relPath) {
97261
97707
  function listFiles(root, dir = root) {
97262
97708
  const out2 = [];
97263
97709
  for (const name2 of readdirSync15(dir)) {
97264
- const abs = join49(dir, name2);
97710
+ const abs = join50(dir, name2);
97265
97711
  if (isEngineOwned(relative8(root, abs))) continue;
97266
97712
  if (statSync12(abs).isDirectory()) out2.push(...listFiles(root, abs));
97267
97713
  else out2.push(abs);
@@ -97273,14 +97719,14 @@ function modHash(dir) {
97273
97719
  for (const abs of listFiles(dir).sort()) {
97274
97720
  h.update(relative8(dir, abs).split(sep5).join("/"));
97275
97721
  h.update("\0");
97276
- h.update(readFileSync42(abs));
97722
+ h.update(readFileSync43(abs));
97277
97723
  h.update("\0");
97278
97724
  }
97279
97725
  return h.digest("hex");
97280
97726
  }
97281
97727
  function bundledMods(bundleDir) {
97282
97728
  if (!existsSync39(bundleDir)) return [];
97283
- return readdirSync15(bundleDir).filter((name2) => existsSync39(join49(bundleDir, name2, ".claude-plugin", "plugin.json")));
97729
+ return readdirSync15(bundleDir).filter((name2) => existsSync39(join50(bundleDir, name2, ".claude-plugin", "plugin.json")));
97284
97730
  }
97285
97731
  function sameDir(a, b) {
97286
97732
  const norm = (p) => resolve9(p).replace(/[\\/]+$/, "").toLowerCase();
@@ -97297,7 +97743,7 @@ function off(env2) {
97297
97743
  function readSettings(path3) {
97298
97744
  if (!existsSync39(path3)) return {};
97299
97745
  try {
97300
- const parsed = JSON.parse(readFileSync42(path3, "utf8"));
97746
+ const parsed = JSON.parse(readFileSync43(path3, "utf8"));
97301
97747
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return null;
97302
97748
  return parsed;
97303
97749
  } catch {
@@ -97321,13 +97767,13 @@ function currentDirs(settings) {
97321
97767
  return raw2.split(delimiter2).map((s) => s.trim()).filter(Boolean);
97322
97768
  }
97323
97769
  function writeSettings(path3, settings) {
97324
- mkdirSync12(dirname17(path3), { recursive: true });
97325
- writeFileSync31(path3, JSON.stringify(settings, null, 2) + "\n", "utf8");
97770
+ mkdirSync12(dirname18(path3), { recursive: true });
97771
+ writeFileSync32(path3, JSON.stringify(settings, null, 2) + "\n", "utf8");
97326
97772
  }
97327
97773
  function ensureClaudeMods(opts) {
97328
97774
  const env2 = opts.env ?? process.env;
97329
97775
  const settingsPath = opts.userSettingsPath ?? userClaudeSettingsPath();
97330
- const modsRoot = join49(opts.installRoot, "claude-mods");
97776
+ const modsRoot = join50(opts.installRoot, "claude-mods");
97331
97777
  if (off(env2)) {
97332
97778
  const settings2 = readSettings(settingsPath);
97333
97779
  if (!settings2) return { kind: "unreadable" };
@@ -97344,14 +97790,14 @@ function ensureClaudeMods(opts) {
97344
97790
  let changed = false;
97345
97791
  const installed = [];
97346
97792
  for (const name2 of names) {
97347
- const src = join49(bundleDir, name2);
97348
- const dest = join49(modsRoot, name2);
97793
+ const src = join50(bundleDir, name2);
97794
+ const dest = join50(modsRoot, name2);
97349
97795
  const hash2 = modHash(src);
97350
- const hashFile = join49(dest, HASH_FILE);
97351
- if (!existsSync39(hashFile) || readFileSync42(hashFile, "utf8") !== hash2) {
97796
+ const hashFile = join50(dest, HASH_FILE);
97797
+ if (!existsSync39(hashFile) || readFileSync43(hashFile, "utf8") !== hash2) {
97352
97798
  rmSync4(dest, { recursive: true, force: true });
97353
97799
  cpSync3(src, dest, { recursive: true, filter: (p) => !isEngineOwned(relative8(src, p)) });
97354
- writeFileSync31(hashFile, hash2, "utf8");
97800
+ writeFileSync32(hashFile, hash2, "utf8");
97355
97801
  changed = true;
97356
97802
  }
97357
97803
  installed.push(dest);
@@ -97772,9 +98218,9 @@ function resolveHookPort(explicit) {
97772
98218
  }
97773
98219
  }
97774
98220
  }
97775
- const settingsPath = join50(ROOT, ".claude", "settings.json");
98221
+ const settingsPath = join51(ROOT, ".claude", "settings.json");
97776
98222
  try {
97777
- if (existsSync40(settingsPath)) return installedHookPort(readFileSync43(settingsPath, "utf8")) ?? 7891;
98223
+ if (existsSync40(settingsPath)) return installedHookPort(readFileSync44(settingsPath, "utf8")) ?? 7891;
97778
98224
  } catch {
97779
98225
  }
97780
98226
  return 7891;
@@ -97800,13 +98246,13 @@ async function cmdInit() {
97800
98246
  console.log("");
97801
98247
  console.log("installing harness hooks...");
97802
98248
  const { existsSync: existsSync41 } = await import("node:fs");
97803
- const { join: join51 } = await import("node:path");
98249
+ const { join: join52 } = await import("node:path");
97804
98250
  try {
97805
98251
  await installClaudeHooks(port);
97806
98252
  } catch (err2) {
97807
98253
  console.warn(` \u26A0\uFE0F Claude hook install failed: ${err2 instanceof Error ? err2.message : err2}`);
97808
98254
  }
97809
- if (existsSync41(join51(ROOT, ".cursor"))) {
98255
+ if (existsSync41(join52(ROOT, ".cursor"))) {
97810
98256
  try {
97811
98257
  await installCursorMcpConfig();
97812
98258
  } catch (err2) {
@@ -99028,7 +99474,7 @@ async function cmdReview() {
99028
99474
  console.log("(review queue empty)");
99029
99475
  return;
99030
99476
  }
99031
- const queue = JSON.parse(readFileSync43(paths.reviewQueue, "utf8"));
99477
+ const queue = JSON.parse(readFileSync44(paths.reviewQueue, "utf8"));
99032
99478
  if (queue.length === 0) {
99033
99479
  console.log("(review queue empty)");
99034
99480
  return;
@@ -99767,7 +100213,7 @@ async function gatherReportData(generatedAt) {
99767
100213
  };
99768
100214
  }
99769
100215
  async function cmdReport(args2) {
99770
- const { mkdirSync: mkdirSync13, writeFileSync: writeFileSync32 } = await import("node:fs");
100216
+ const { mkdirSync: mkdirSync13, writeFileSync: writeFileSync33 } = await import("node:fs");
99771
100217
  const { renderReport: renderReport2 } = await Promise.resolve().then(() => (init_report_render(), report_render_exports));
99772
100218
  const includeFutureVerbs = args2.includes("--future-verbs");
99773
100219
  const now = /* @__PURE__ */ new Date();
@@ -99780,8 +100226,8 @@ async function cmdReport(args2) {
99780
100226
  const outDir = workspacePaths(ROOT).configDir;
99781
100227
  mkdirSync13(outDir, { recursive: true });
99782
100228
  const files = renderReport2(data, { includeFutureVerbs });
99783
- for (const f of files) writeFileSync32(join50(outDir, f.name), f.html, "utf8");
99784
- const indexPath = join50(outDir, "report.html");
100229
+ for (const f of files) writeFileSync33(join51(outDir, f.name), f.html, "utf8");
100230
+ const indexPath = join51(outDir, "report.html");
99785
100231
  console.log(`report \u2192 ${indexPath}`);
99786
100232
  console.log(
99787
100233
  ` ${data.repos.length} repo(s) \xB7 ${files.length} file(s) \xB7 ${data.rollup.nodes.toLocaleString("en-US")} nodes`
@@ -99837,7 +100283,7 @@ function spawnDaemonDetached(options = {}) {
99837
100283
  try {
99838
100284
  const logPath = daemonLogPath();
99839
100285
  try {
99840
- if (statSync13(logPath).size > 5 * 1024 * 1024) renameSync8(logPath, `${logPath}.1`);
100286
+ if (statSync13(logPath).size > 5 * 1024 * 1024) renameSync9(logPath, `${logPath}.1`);
99841
100287
  } catch {
99842
100288
  }
99843
100289
  out2 = openSync3(logPath, "a");
@@ -99906,24 +100352,24 @@ async function cmdInstallHooks(args2) {
99906
100352
  }
99907
100353
  }
99908
100354
  async function installOpencodePlugin(port) {
99909
- const { mkdirSync: mkdirSync13, existsSync: existsSync41, readFileSync: readFileSync44, writeFileSync: writeFileSync32 } = await import("node:fs");
99910
- const { join: join51 } = await import("node:path");
99911
- const dir = join51(ROOT, ".opencode", "plugin");
100355
+ const { mkdirSync: mkdirSync13, existsSync: existsSync41, readFileSync: readFileSync45, writeFileSync: writeFileSync33 } = await import("node:fs");
100356
+ const { join: join52 } = await import("node:path");
100357
+ const dir = join52(ROOT, ".opencode", "plugin");
99912
100358
  if (!existsSync41(dir)) mkdirSync13(dir, { recursive: true });
99913
- const file2 = join51(dir, "inerrata.js");
100359
+ const file2 = join52(dir, "inerrata.js");
99914
100360
  if (existsSync41(file2)) {
99915
- const head2 = readFileSync44(file2, "utf8").split("\n")[0] ?? "";
100361
+ const head2 = readFileSync45(file2, "utf8").split("\n")[0] ?? "";
99916
100362
  if (head2.trim() !== OPENCODE_PLUGIN_MARKER) {
99917
100363
  console.error(`refusing to overwrite ${file2}: not an errata-managed plugin (line 1 lacks the marker)`);
99918
100364
  process.exit(2);
99919
100365
  }
99920
100366
  }
99921
- writeFileSync32(file2, buildOpencodePluginSource(port, { version: DAEMON_VERSION }), "utf8");
99922
- const cfgFile = join51(ROOT, "opencode.json");
100367
+ writeFileSync33(file2, buildOpencodePluginSource(port, { version: DAEMON_VERSION }), "utf8");
100368
+ const cfgFile = join52(ROOT, "opencode.json");
99923
100369
  let cfg = { $schema: "https://opencode.ai/config.json" };
99924
100370
  if (existsSync41(cfgFile)) {
99925
100371
  try {
99926
- cfg = JSON.parse(readFileSync44(cfgFile, "utf8"));
100372
+ cfg = JSON.parse(readFileSync45(cfgFile, "utf8"));
99927
100373
  } catch {
99928
100374
  console.error(`refusing to touch invalid JSON at ${cfgFile} \u2014 fix it and re-run`);
99929
100375
  process.exit(2);
@@ -99934,7 +100380,7 @@ async function installOpencodePlugin(port) {
99934
100380
  if (!hadErrata) {
99935
100381
  const inv = errataMcpInvocation();
99936
100382
  cfg.mcp["errata"] = { type: "local", command: [inv.command, ...inv.args] };
99937
- writeFileSync32(cfgFile, JSON.stringify(cfg, null, 2) + "\n", "utf8");
100383
+ writeFileSync33(cfgFile, JSON.stringify(cfg, null, 2) + "\n", "utf8");
99938
100384
  }
99939
100385
  console.log(`installed OpenCode plugin \u2192 ${file2}`);
99940
100386
  if (hadErrata) console.log(` mcp.errata already present in ${cfgFile} \u2014 left untouched`);
@@ -99969,15 +100415,15 @@ function installClaudeMods() {
99969
100415
  }
99970
100416
  }
99971
100417
  async function installClaudeHooks(port) {
99972
- const { mkdirSync: mkdirSync13, existsSync: existsSync41, readFileSync: readFileSync44, writeFileSync: writeFileSync32 } = await import("node:fs");
99973
- const { join: join51 } = await import("node:path");
99974
- const dir = join51(ROOT, ".claude");
100418
+ const { mkdirSync: mkdirSync13, existsSync: existsSync41, readFileSync: readFileSync45, writeFileSync: writeFileSync33 } = await import("node:fs");
100419
+ const { join: join52 } = await import("node:path");
100420
+ const dir = join52(ROOT, ".claude");
99975
100421
  if (!existsSync41(dir)) mkdirSync13(dir, { recursive: true });
99976
- const file2 = join51(dir, "settings.json");
100422
+ const file2 = join52(dir, "settings.json");
99977
100423
  let settings = {};
99978
100424
  if (existsSync41(file2)) {
99979
100425
  try {
99980
- settings = JSON.parse(readFileSync44(file2, "utf8"));
100426
+ settings = JSON.parse(readFileSync45(file2, "utf8"));
99981
100427
  } catch {
99982
100428
  console.error(`refusing to overwrite invalid JSON at ${file2}`);
99983
100429
  process.exit(2);
@@ -100026,12 +100472,12 @@ async function installClaudeHooks(port) {
100026
100472
  list.push({ hooks: [{ type: "command", command: injectCmd }] });
100027
100473
  }
100028
100474
  removeProjectStatusLine(settings);
100029
- writeFileSync32(file2, JSON.stringify(settings, null, 2) + "\n", "utf8");
100475
+ writeFileSync33(file2, JSON.stringify(settings, null, 2) + "\n", "utf8");
100030
100476
  console.log(`installed Claude Code hooks \u2192 ${file2}`);
100031
100477
  console.log(` ${ensureStatusLine(port)}`);
100032
100478
  console.log(` ${installClaudeMods().line}`);
100033
100479
  await installClaudeMcpConfig();
100034
- const claudeMd = join51(ROOT, "CLAUDE.md");
100480
+ const claudeMd = join52(ROOT, "CLAUDE.md");
100035
100481
  const recall = writeManagedBlock(claudeMd, { body: RECALL_FIRST_BLOCK });
100036
100482
  if (recall.kind === "collision") {
100037
100483
  console.warn(
@@ -100043,15 +100489,15 @@ async function installClaudeHooks(port) {
100043
100489
  console.log(` endpoint: http://127.0.0.1:${port}/api/hook`);
100044
100490
  }
100045
100491
  async function installClaudeMcpConfig() {
100046
- const { mkdirSync: mkdirSync13, existsSync: existsSync41, readFileSync: readFileSync44, writeFileSync: writeFileSync32 } = await import("node:fs");
100047
- const { join: join51, dirname: dirname18 } = await import("node:path");
100048
- const file2 = join51(ROOT, ".mcp.json");
100049
- const dir = dirname18(file2);
100492
+ const { mkdirSync: mkdirSync13, existsSync: existsSync41, readFileSync: readFileSync45, writeFileSync: writeFileSync33 } = await import("node:fs");
100493
+ const { join: join52, dirname: dirname19 } = await import("node:path");
100494
+ const file2 = join52(ROOT, ".mcp.json");
100495
+ const dir = dirname19(file2);
100050
100496
  if (!existsSync41(dir)) mkdirSync13(dir, { recursive: true });
100051
100497
  let cfg = {};
100052
100498
  if (existsSync41(file2)) {
100053
100499
  try {
100054
- cfg = JSON.parse(readFileSync44(file2, "utf8"));
100500
+ cfg = JSON.parse(readFileSync45(file2, "utf8"));
100055
100501
  } catch {
100056
100502
  console.error(`refusing to overwrite invalid JSON at ${file2}`);
100057
100503
  process.exit(2);
@@ -100059,21 +100505,21 @@ async function installClaudeMcpConfig() {
100059
100505
  }
100060
100506
  cfg.mcpServers ??= {};
100061
100507
  cfg.mcpServers["errata"] = errataMcpInvocation();
100062
- writeFileSync32(file2, JSON.stringify(cfg, null, 2) + "\n", "utf8");
100508
+ writeFileSync33(file2, JSON.stringify(cfg, null, 2) + "\n", "utf8");
100063
100509
  console.log(`installed Claude Code MCP server config \u2192 ${file2}`);
100064
100510
  console.log(` Claude Code will spawn \`errata mcp\` on workspace open.`);
100065
100511
  console.log(` Tools: errata.search / locate / neighbors / callers_of / what_uses / show / similar`);
100066
100512
  }
100067
100513
  async function installCursorMcpConfig() {
100068
- const { mkdirSync: mkdirSync13, existsSync: existsSync41, readFileSync: readFileSync44, writeFileSync: writeFileSync32 } = await import("node:fs");
100069
- const { join: join51 } = await import("node:path");
100070
- const dir = join51(ROOT, ".cursor");
100514
+ const { mkdirSync: mkdirSync13, existsSync: existsSync41, readFileSync: readFileSync45, writeFileSync: writeFileSync33 } = await import("node:fs");
100515
+ const { join: join52 } = await import("node:path");
100516
+ const dir = join52(ROOT, ".cursor");
100071
100517
  if (!existsSync41(dir)) mkdirSync13(dir, { recursive: true });
100072
- const file2 = join51(dir, "mcp.json");
100518
+ const file2 = join52(dir, "mcp.json");
100073
100519
  let cfg = {};
100074
100520
  if (existsSync41(file2)) {
100075
100521
  try {
100076
- cfg = JSON.parse(readFileSync44(file2, "utf8"));
100522
+ cfg = JSON.parse(readFileSync45(file2, "utf8"));
100077
100523
  } catch {
100078
100524
  console.error(`refusing to overwrite invalid JSON at ${file2}`);
100079
100525
  process.exit(2);
@@ -100081,7 +100527,7 @@ async function installCursorMcpConfig() {
100081
100527
  }
100082
100528
  cfg.mcpServers ??= {};
100083
100529
  cfg.mcpServers["errata"] = errataMcpInvocation();
100084
- writeFileSync32(file2, JSON.stringify(cfg, null, 2) + "\n", "utf8");
100530
+ writeFileSync33(file2, JSON.stringify(cfg, null, 2) + "\n", "utf8");
100085
100531
  console.log(`installed Cursor MCP server config \u2192 ${file2}`);
100086
100532
  console.log(` Cursor will spawn \`errata mcp\` on workspace open.`);
100087
100533
  console.log(` Tools: errata.search / locate / neighbors / callers_of / what_uses`);
@@ -100092,7 +100538,7 @@ async function installCodexHooks(port) {
100092
100538
  const gitRoot = nearestGitRoot(process.cwd());
100093
100539
  const hookRoot = gitRoot && mainCheckoutOfWorktree(gitRoot) ? gitRoot : ROOT;
100094
100540
  const file2 = writeCodexHooks(hookRoot, port);
100095
- const instructions = writeManagedBlock(join50(hookRoot, "AGENTS.md"), {
100541
+ const instructions = writeManagedBlock(join51(hookRoot, "AGENTS.md"), {
100096
100542
  body: AGENTS_POINTER_BODY,
100097
100543
  stable: true
100098
100544
  });
@@ -100538,9 +100984,9 @@ async function cmdDash(args2) {
100538
100984
  await yieldToLoop2();
100539
100985
  try {
100540
100986
  const items = selectDurableMemory(handle2.sharedStore, r.engine.profile, {
100541
- atCommit: readGitRefState(join50(r.root, ".git")).sha ?? void 0
100987
+ atCommit: readGitRefState(join51(r.root, ".git")).sha ?? void 0
100542
100988
  });
100543
- const res = bleedRules(join50(r.root, ".claude", "rules"), items);
100989
+ const res = bleedRules(join51(r.root, ".claude", "rules"), items);
100544
100990
  if (res.written || res.pruned) {
100545
100991
  console.log(
100546
100992
  `[rules:${r.entry.name}] ${res.written} collective principle(s) \u2192 .claude/rules` + (res.pruned ? `, ${res.pruned} pruned` : "")