@inerrata-corporation/errata 2.0.2-dev.245 → 2.0.2-dev.247

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
@@ -16410,6 +16410,21 @@ var init_src2 = __esm({
16410
16410
  });
16411
16411
 
16412
16412
  // ../../packages/local-graph/src/store.ts
16413
+ function localEdgeViolation(fromLabel, type, toLabel) {
16414
+ if (type in LOCAL_RULE_OVERRIDES) {
16415
+ const rule = LOCAL_RULE_OVERRIDES[type];
16416
+ if (!rule) return null;
16417
+ if (fromLabel && rule.from && !rule.from.includes(fromLabel)) {
16418
+ return `${type} cannot originate from ${fromLabel} locally (allowed: ${rule.from.join(", ")})`;
16419
+ }
16420
+ if (toLabel && rule.to && !rule.to.includes(toLabel)) {
16421
+ return `${type} cannot target ${toLabel} locally (allowed: ${rule.to.join(", ")})`;
16422
+ }
16423
+ return null;
16424
+ }
16425
+ const verdict = isValidEdge(fromLabel, type, toLabel);
16426
+ return verdict.ok ? null : verdict.reason ?? "edge rule violation";
16427
+ }
16413
16428
  function encodeEmbedding(emb) {
16414
16429
  if (!emb || emb.length === 0) return null;
16415
16430
  const f = Float32Array.from(emb);
@@ -16484,7 +16499,7 @@ var init_store = __esm({
16484
16499
  REVEALED_BY: null,
16485
16500
  PRODUCED: null
16486
16501
  };
16487
- SCHEMA_VERSION = 5;
16502
+ SCHEMA_VERSION = 6;
16488
16503
  SCHEMA_SQL = `
16489
16504
  CREATE TABLE IF NOT EXISTS schema_version (
16490
16505
  version INTEGER PRIMARY KEY
@@ -16499,6 +16514,21 @@ CREATE TABLE IF NOT EXISTS store_meta (
16499
16514
  value TEXT NOT NULL
16500
16515
  );
16501
16516
 
16517
+ -- Durable ledger of edges the ontology gate REFUSED, keyed by edge type.
16518
+ -- Durable rather than in-memory for one specific reason: the status command runs
16519
+ -- in a SEPARATE process and opens its own store handle, so a counter living on
16520
+ -- the instance reads 0 there forever. That is exactly how a producer rejecting
16521
+ -- 100% of its output stayed invisible for 17 days. Persisting it also survives
16522
+ -- the daemon restart that would otherwise erase the evidence.
16523
+ -- Keyed by type because a systematic producer bug shows up as ONE type
16524
+ -- dominating; sample keeps the latest reason so the count is actionable.
16525
+ CREATE TABLE IF NOT EXISTS edge_rejections (
16526
+ type TEXT PRIMARY KEY,
16527
+ count INTEGER NOT NULL DEFAULT 0,
16528
+ last_at INTEGER NOT NULL,
16529
+ sample TEXT
16530
+ );
16531
+
16502
16532
  CREATE TABLE IF NOT EXISTS nodes (
16503
16533
  id TEXT PRIMARY KEY,
16504
16534
  label TEXT NOT NULL,
@@ -16818,6 +16848,16 @@ CREATE INDEX IF NOT EXISTS nodes_relpath ON nodes(json_extract(attrs_json, '$.re
16818
16848
  if (!cols.has(name2)) this.db.exec(ddl);
16819
16849
  }
16820
16850
  }
16851
+ if (from < 6) {
16852
+ this.db.exec(`
16853
+ CREATE TABLE IF NOT EXISTS edge_rejections (
16854
+ type TEXT PRIMARY KEY,
16855
+ count INTEGER NOT NULL DEFAULT 0,
16856
+ last_at INTEGER NOT NULL,
16857
+ sample TEXT
16858
+ )
16859
+ `);
16860
+ }
16821
16861
  this.db.prepare("UPDATE schema_version SET version = ?").run(SCHEMA_VERSION);
16822
16862
  });
16823
16863
  }
@@ -16899,6 +16939,7 @@ CREATE INDEX IF NOT EXISTS nodes_relpath ON nodes(json_extract(attrs_json, '$.re
16899
16939
  const violation = this.edgeRuleViolation(edge2);
16900
16940
  if (violation) {
16901
16941
  this.rejectedEdgeCount++;
16942
+ this.recordEdgeRejection(edge2.type, violation, edge2.lastSeenAt || edge2.createdAt || 0);
16902
16943
  console.warn(`[local-graph] rejected edge ${edge2.from}-[:${edge2.type}]->${edge2.to}: ${violation}`);
16903
16944
  return;
16904
16945
  }
@@ -16923,22 +16964,51 @@ CREATE INDEX IF NOT EXISTS nodes_relpath ON nodes(json_extract(attrs_json, '$.re
16923
16964
  * overlay consulted first. Returns the reason string on a documented-
16924
16965
  * forbidden combination, else null. Point lookups on the id PK — negligible
16925
16966
  * next to the insert itself. */
16926
- edgeRuleViolation(edge2) {
16927
- const fromLabel = this.getNode(edge2.from)?.label;
16928
- const toLabel = this.getNode(edge2.to)?.label;
16929
- if (edge2.type in LOCAL_RULE_OVERRIDES) {
16930
- const rule = LOCAL_RULE_OVERRIDES[edge2.type];
16931
- if (!rule) return null;
16932
- if (fromLabel && rule.from && !rule.from.includes(fromLabel)) {
16933
- return `${edge2.type} cannot originate from ${fromLabel} locally (allowed: ${rule.from.join(", ")})`;
16934
- }
16935
- if (toLabel && rule.to && !rule.to.includes(toLabel)) {
16936
- return `${edge2.type} cannot target ${toLabel} locally (allowed: ${rule.to.join(", ")})`;
16937
- }
16938
- return null;
16967
+ /** Upsert one refusal into the durable ledger. Best-effort: a bookkeeping
16968
+ * failure must never turn a refused edge into a thrown write. */
16969
+ recordEdgeRejection(type, reason, at) {
16970
+ try {
16971
+ this.db.prepare(
16972
+ `INSERT INTO edge_rejections (type, count, last_at, sample) VALUES (?, 1, ?, ?)
16973
+ ON CONFLICT(type) DO UPDATE SET
16974
+ count = count + 1, last_at = excluded.last_at, sample = excluded.sample`
16975
+ ).run(type, at, reason.slice(0, 200));
16976
+ } catch {
16939
16977
  }
16940
- const verdict = isValidEdge(fromLabel, edge2.type, toLabel);
16941
- return verdict.ok ? null : verdict.reason ?? "edge rule violation";
16978
+ }
16979
+ /** Refusals recorded by the ontology gate, per edge type, newest activity first.
16980
+ * Durable across restarts and readable from any process (see the table note). */
16981
+ edgeRejections() {
16982
+ try {
16983
+ return this.db.prepare(
16984
+ "SELECT type, count, last_at AS lastAt, sample FROM edge_rejections ORDER BY count DESC, last_at DESC"
16985
+ ).all();
16986
+ } catch {
16987
+ return [];
16988
+ }
16989
+ }
16990
+ /** Drop ledger entries whose last refusal predates `cutoff`. A still-misbehaving
16991
+ * producer keeps refreshing `last_at` and survives; a fixed one fades out. */
16992
+ pruneEdgeRejections(cutoff) {
16993
+ try {
16994
+ this.db.prepare("DELETE FROM edge_rejections WHERE last_at < ?").run(cutoff);
16995
+ } catch {
16996
+ }
16997
+ }
16998
+ /** Clear the ledger outright, whole or per type — operator escape hatch. */
16999
+ clearEdgeRejections(type) {
17000
+ try {
17001
+ if (type) this.db.prepare("DELETE FROM edge_rejections WHERE type = ?").run(type);
17002
+ else this.db.exec("DELETE FROM edge_rejections");
17003
+ } catch {
17004
+ }
17005
+ }
17006
+ edgeRuleViolation(edge2) {
17007
+ return localEdgeViolation(
17008
+ this.getNode(edge2.from)?.label,
17009
+ edge2.type,
17010
+ this.getNode(edge2.to)?.label
17011
+ );
16942
17012
  }
16943
17013
  updateEdge(id, patch) {
16944
17014
  this.stmts.updateEdge.run({
@@ -17075,6 +17145,32 @@ CREATE INDEX IF NOT EXISTS nodes_relpath ON nodes(json_extract(attrs_json, '$.re
17075
17145
  const rows = this.db.prepare("SELECT from_id, to_id, type FROM edges WHERE valid_to IS NULL").all();
17076
17146
  return rows.map((r) => ({ from: r.from_id, to: r.to_id, type: r.type }));
17077
17147
  }
17148
+ /**
17149
+ * Live edges WITH their endpoint labels and ids, resolved in ONE join.
17150
+ *
17151
+ * The ontology sweep needs (id, type, fromLabel, toLabel) for every live edge.
17152
+ * Doing that as `scanLiveEdges()` + two `getNode()` calls is 2N node reads —
17153
+ * 550,000 on this store — and each one deserializes the node's embedding blob.
17154
+ * Measured: the sweep did not finish in 10 minutes. As a single join it is one
17155
+ * query over an index-covered scan. Labels only; nothing here touches embeddings.
17156
+ */
17157
+ scanLiveEdgeRows() {
17158
+ const rows = this.db.prepare(
17159
+ `SELECT e.id, e.from_id, e.to_id, e.type, a.label AS from_label, b.label AS to_label
17160
+ FROM edges e
17161
+ LEFT JOIN nodes a ON a.id = e.from_id AND a.valid_to IS NULL
17162
+ LEFT JOIN nodes b ON b.id = e.to_id AND b.valid_to IS NULL
17163
+ WHERE e.valid_to IS NULL`
17164
+ ).all();
17165
+ return rows.map((r) => ({
17166
+ id: r.id,
17167
+ from: r.from_id,
17168
+ to: r.to_id,
17169
+ type: r.type,
17170
+ fromLabel: r.from_label ?? void 0,
17171
+ toLabel: r.to_label ?? void 0
17172
+ }));
17173
+ }
17078
17174
  /** Live nodes whose attrs.relPath is one of `relPaths`. Uses the nodes_relpath
17079
17175
  * expression index so the incremental reindex fetches only the changed files'
17080
17176
  * symbols instead of scanning every versioned node. */
@@ -20879,6 +20975,7 @@ __export(src_exports2, {
20879
20975
  linkProblemToPackages: () => linkProblemToPackages,
20880
20976
  linkProblemToSymbols: () => linkProblemToSymbols,
20881
20977
  listNeedsRevisit: () => listNeedsRevisit,
20978
+ localEdgeViolation: () => localEdgeViolation,
20882
20979
  markRevisit: () => markRevisit,
20883
20980
  matchLanguagesInText: () => matchLanguagesInText,
20884
20981
  matchPackagesInText: () => matchPackagesInText,
@@ -47311,12 +47408,12 @@ var init_report_render = __esm({
47311
47408
 
47312
47409
  // src/cli.ts
47313
47410
  init_src5();
47314
- import { closeSync as closeSync2, existsSync as existsSync25, openSync as openSync2, readFileSync as readFileSync24, renameSync as renameSync4, statSync as statSync6 } from "node:fs";
47315
- import { join as join28 } from "node:path";
47411
+ import { closeSync as closeSync2, existsSync as existsSync26, openSync as openSync2, readFileSync as readFileSync25, renameSync as renameSync4, statSync as statSync6 } from "node:fs";
47412
+ import { join as join29 } from "node:path";
47316
47413
  import { spawn as spawn3 } from "node:child_process";
47317
47414
 
47318
47415
  // src/daemon.ts
47319
- import { existsSync as existsSync20, writeFileSync as writeFileSync17 } from "node:fs";
47416
+ import { existsSync as existsSync21, writeFileSync as writeFileSync18 } from "node:fs";
47320
47417
 
47321
47418
  // ../../node_modules/.pnpm/@hono+node-server@1.19.11_hono@4.12.8/node_modules/@hono/node-server/dist/index.mjs
47322
47419
  import { createServer as createServerHTTP } from "http";
@@ -47896,8 +47993,8 @@ init_config();
47896
47993
 
47897
47994
  // src/engine.ts
47898
47995
  import { execFileSync as execFileSync3 } from "node:child_process";
47899
- import { existsSync as existsSync19, statSync as statSync5, appendFileSync as appendFileSync2, readdirSync as readdirSync9, renameSync as renameSync3, readFileSync as readFileSync19, writeFileSync as writeFileSync16 } from "node:fs";
47900
- import { join as join24, relative as relative6, sep as sep4 } from "node:path";
47996
+ import { existsSync as existsSync20, statSync as statSync5, appendFileSync as appendFileSync2, readdirSync as readdirSync9, renameSync as renameSync3, readFileSync as readFileSync20, writeFileSync as writeFileSync17 } from "node:fs";
47997
+ import { join as join25, relative as relative6, sep as sep4 } from "node:path";
47901
47998
 
47902
47999
  // ../../node_modules/.pnpm/chokidar@4.0.3/node_modules/chokidar/esm/index.js
47903
48000
  import { stat as statcb } from "fs";
@@ -50341,6 +50438,10 @@ function tagEdgeCorroborated(targetAnchorIds, sessionTouchedNodeIds, independent
50341
50438
  for (const a of targetAnchorIds) if (sessionTouchedNodeIds.has(a)) return true;
50342
50439
  return false;
50343
50440
  }
50441
+ function citeEdgeType(targetLabel2) {
50442
+ const t = typePriorEdge("Problem", targetLabel2);
50443
+ return t === "SUPERSEDES" ? "RELATES_TO" : t;
50444
+ }
50344
50445
  function typePriorEdge(sourceLabel, targetLabel2, sentence = "") {
50345
50446
  const direct = LABEL_PAIR[`${sourceLabel}>${targetLabel2}`];
50346
50447
  if (direct) return direct;
@@ -50887,6 +50988,90 @@ function backfillConstraintKind(store, opts) {
50887
50988
  return report;
50888
50989
  }
50889
50990
 
50991
+ // src/edge-repair.ts
50992
+ init_src();
50993
+ init_src4();
50994
+ import { existsSync as existsSync14, readFileSync as readFileSync12, writeFileSync as writeFileSync12 } from "node:fs";
50995
+ import { join as join17 } from "node:path";
50996
+ function citeEdgeId(from, type, to) {
50997
+ return `edge_${digest({ from, type, to })}`.slice(0, 24);
50998
+ }
50999
+ var EDGE_REPAIR_VERSION = 1;
51000
+ var REJECTION_RETENTION_MS = 30 * 24 * 60 * 60 * 1e3;
51001
+ var EMPTY2 = {
51002
+ skipped: true,
51003
+ scanned: 0,
51004
+ invalid: 0,
51005
+ retyped: 0,
51006
+ closed: 0,
51007
+ byType: {}
51008
+ };
51009
+ function markerPath2(configDir) {
51010
+ return join17(configDir, "edge-repair.json");
51011
+ }
51012
+ function alreadyDone2(configDir) {
51013
+ const p = markerPath2(configDir);
51014
+ if (!existsSync14(p)) return false;
51015
+ try {
51016
+ return JSON.parse(readFileSync12(p, "utf8"))?.version === EDGE_REPAIR_VERSION;
51017
+ } catch {
51018
+ return false;
51019
+ }
51020
+ }
51021
+ function repairInvalidEdges(store, opts) {
51022
+ if (!opts.force && !opts.dryRun && alreadyDone2(opts.configDir)) return EMPTY2;
51023
+ const report = {
51024
+ skipped: false,
51025
+ scanned: 0,
51026
+ invalid: 0,
51027
+ retyped: 0,
51028
+ closed: 0,
51029
+ byType: {}
51030
+ };
51031
+ const work = [];
51032
+ for (const e of store.scanLiveEdgeRows()) {
51033
+ report.scanned++;
51034
+ if (!localEdgeViolation(e.fromLabel, e.type, e.toLabel)) continue;
51035
+ report.invalid++;
51036
+ const candidate = e.toLabel ? citeEdgeType(e.toLabel) : null;
51037
+ const retype = candidate && candidate !== e.type && !localEdgeViolation(e.fromLabel, candidate, e.toLabel) ? candidate : null;
51038
+ work.push({ edge: { id: e.id, from: e.from, to: e.to, type: e.type }, retype });
51039
+ report.byType[e.type] = (report.byType[e.type] ?? 0) + 1;
51040
+ if (retype) report.retyped++;
51041
+ else report.closed++;
51042
+ }
51043
+ if (opts.dryRun) return report;
51044
+ store.transaction(() => {
51045
+ for (const w of work) {
51046
+ const prior = store.getEdge(w.edge.id);
51047
+ store.closeEdge(w.edge.id, opts.now);
51048
+ if (!w.retype || !prior) continue;
51049
+ store.mergeEdge({
51050
+ ...prior,
51051
+ id: citeEdgeId(w.edge.from, w.retype, w.edge.to),
51052
+ type: w.retype,
51053
+ validFrom: opts.now,
51054
+ validTo: null,
51055
+ lastSeenAt: opts.now,
51056
+ // Mark the provenance of the rewrite so a later audit can tell a repaired
51057
+ // edge from one captured natively — without which this sweep would be
51058
+ // indistinguishable from the agent having witnessed it post-fix.
51059
+ attrs: { ...prior.attrs ?? {}, retypedFrom: w.edge.type, retypedBy: `edge-repair:v${EDGE_REPAIR_VERSION}` }
51060
+ });
51061
+ }
51062
+ });
51063
+ store.pruneEdgeRejections(opts.now - REJECTION_RETENTION_MS);
51064
+ try {
51065
+ writeFileSync12(
51066
+ markerPath2(opts.configDir),
51067
+ JSON.stringify({ version: EDGE_REPAIR_VERSION, at: opts.now, ...report }, null, 2),
51068
+ "utf8"
51069
+ );
51070
+ } catch {
51071
+ }
51072
+ return report;
51073
+ }
51074
+
50890
51075
  // src/engine.ts
50891
51076
  init_symbol_summaries();
50892
51077
  init_reconcile();
@@ -51085,11 +51270,11 @@ init_outbox();
51085
51270
  init_src8();
51086
51271
  init_src();
51087
51272
  init_src2();
51088
- import { readFileSync as readFileSync12 } from "node:fs";
51089
- import { join as join17 } from "node:path";
51273
+ import { readFileSync as readFileSync13 } from "node:fs";
51274
+ import { join as join18 } from "node:path";
51090
51275
  function loadClaimIgnorePatterns(workspaceRoot) {
51091
51276
  try {
51092
- return readFileSync12(join17(workspaceRoot, ".errataignore"), "utf8").split(/\r?\n/).map((l) => l.trim()).filter((l) => l.length > 0 && !l.startsWith("#")).map((l) => l.toLowerCase());
51277
+ return readFileSync13(join18(workspaceRoot, ".errataignore"), "utf8").split(/\r?\n/).map((l) => l.trim()).filter((l) => l.length > 0 && !l.startsWith("#")).map((l) => l.toLowerCase());
51093
51278
  } catch {
51094
51279
  return [];
51095
51280
  }
@@ -51450,22 +51635,22 @@ async function pullCloudTriage(shared, cloud, profile, limit = 50) {
51450
51635
  }
51451
51636
 
51452
51637
  // src/git-sensor.ts
51453
- import { existsSync as existsSync14, readFileSync as readFileSync13, watch as fsWatch } from "node:fs";
51454
- import { join as join18 } from "node:path";
51638
+ import { existsSync as existsSync15, readFileSync as readFileSync14, watch as fsWatch } from "node:fs";
51639
+ import { join as join19 } from "node:path";
51455
51640
  function readFirstLine(path2) {
51456
51641
  try {
51457
- return readFileSync13(path2, "utf8").split(/\r?\n/, 1)[0].trim();
51642
+ return readFileSync14(path2, "utf8").split(/\r?\n/, 1)[0].trim();
51458
51643
  } catch {
51459
51644
  return null;
51460
51645
  }
51461
51646
  }
51462
51647
  function readGitRefState(gitDir) {
51463
- const head2 = readFirstLine(join18(gitDir, "HEAD"));
51648
+ const head2 = readFirstLine(join19(gitDir, "HEAD"));
51464
51649
  const m = head2 ? /^ref:\s*refs\/heads\/(.+)$/.exec(head2) : null;
51465
51650
  const branch = m ? m[1] : null;
51466
51651
  let sha2 = null;
51467
51652
  if (branch) {
51468
- sha2 = readFirstLine(join18(gitDir, "refs", "heads", branch));
51653
+ sha2 = readFirstLine(join19(gitDir, "refs", "heads", branch));
51469
51654
  if (!sha2) sha2 = shaFromPackedRefs(gitDir, `refs/heads/${branch}`);
51470
51655
  } else if (head2 && /^[0-9a-f]{7,40}$/i.test(head2)) {
51471
51656
  sha2 = head2;
@@ -51473,13 +51658,13 @@ function readGitRefState(gitDir) {
51473
51658
  return {
51474
51659
  branch,
51475
51660
  sha: sha2,
51476
- mergeHeadExists: existsSync14(join18(gitDir, "MERGE_HEAD")),
51477
- origHeadExists: existsSync14(join18(gitDir, "ORIG_HEAD"))
51661
+ mergeHeadExists: existsSync15(join19(gitDir, "MERGE_HEAD")),
51662
+ origHeadExists: existsSync15(join19(gitDir, "ORIG_HEAD"))
51478
51663
  };
51479
51664
  }
51480
51665
  function shaFromPackedRefs(gitDir, ref) {
51481
51666
  try {
51482
- for (const line of readFileSync13(join18(gitDir, "packed-refs"), "utf8").split(/\r?\n/)) {
51667
+ for (const line of readFileSync14(join19(gitDir, "packed-refs"), "utf8").split(/\r?\n/)) {
51483
51668
  const [sha2, name2] = line.split(/\s+/);
51484
51669
  if (name2 === ref && sha2) return sha2;
51485
51670
  }
@@ -51513,7 +51698,7 @@ function startGitSensor(gitDir, onEvent, opts = {}) {
51513
51698
  const settle = () => {
51514
51699
  if (timer) clearTimeout(timer);
51515
51700
  timer = setTimeout(() => {
51516
- if (existsSync14(join18(gitDir, "index.lock"))) {
51701
+ if (existsSync15(join19(gitDir, "index.lock"))) {
51517
51702
  settle();
51518
51703
  return;
51519
51704
  }
@@ -51524,7 +51709,7 @@ function startGitSensor(gitDir, onEvent, opts = {}) {
51524
51709
  }, debounceMs);
51525
51710
  };
51526
51711
  for (const sub of ["HEAD", "logs/HEAD", "MERGE_HEAD", "ORIG_HEAD"]) {
51527
- const p = join18(gitDir, sub);
51712
+ const p = join19(gitDir, sub);
51528
51713
  try {
51529
51714
  watchers.push(fsWatch(p, settle));
51530
51715
  } catch {
@@ -51749,21 +51934,21 @@ var TelemetryRecorder = class {
51749
51934
 
51750
51935
  // src/skills.ts
51751
51936
  import {
51752
- existsSync as existsSync15,
51937
+ existsSync as existsSync16,
51753
51938
  mkdirSync as mkdirSync6,
51754
- readFileSync as readFileSync14,
51939
+ readFileSync as readFileSync15,
51755
51940
  readdirSync as readdirSync7,
51756
51941
  unlinkSync as unlinkSync2,
51757
- writeFileSync as writeFileSync12
51942
+ writeFileSync as writeFileSync13
51758
51943
  } from "node:fs";
51759
- import { basename as basename4, join as join19 } from "node:path";
51944
+ import { basename as basename4, join as join20 } from "node:path";
51760
51945
  function skillFileName(id) {
51761
51946
  return `${id.replace(/[^A-Za-z0-9_.-]/g, "_")}.md`;
51762
51947
  }
51763
51948
  function readSkillManifest(manifestPath) {
51764
- if (!existsSync15(manifestPath)) return [];
51949
+ if (!existsSync16(manifestPath)) return [];
51765
51950
  try {
51766
- const parsed = JSON.parse(readFileSync14(manifestPath, "utf8"));
51951
+ const parsed = JSON.parse(readFileSync15(manifestPath, "utf8"));
51767
51952
  return (parsed.skills ?? []).map((s) => ({
51768
51953
  title: s.title ?? "",
51769
51954
  layer: s.layer ?? "technique",
@@ -51787,7 +51972,7 @@ async function syncSkills(paths, client, seed, pins = [], techSeed) {
51787
51972
  for (const s of res.skills) {
51788
51973
  const fileName = skillFileName(s.id);
51789
51974
  keep.add(fileName);
51790
- writeFileSync12(join19(paths.skillsDir, fileName), s.markdown, "utf8");
51975
+ writeFileSync13(join20(paths.skillsDir, fileName), s.markdown, "utf8");
51791
51976
  rows.push({
51792
51977
  id: s.id,
51793
51978
  title: s.title,
@@ -51800,7 +51985,7 @@ async function syncSkills(paths, client, seed, pins = [], techSeed) {
51800
51985
  const fileName = skillFileName(p.id);
51801
51986
  if (keep.has(fileName)) continue;
51802
51987
  keep.add(fileName);
51803
- writeFileSync12(join19(paths.skillsDir, fileName), p.markdown, "utf8");
51988
+ writeFileSync13(join20(paths.skillsDir, fileName), p.markdown, "utf8");
51804
51989
  rows.push({
51805
51990
  id: p.id,
51806
51991
  title: p.title,
@@ -51814,13 +51999,13 @@ async function syncSkills(paths, client, seed, pins = [], techSeed) {
51814
51999
  if (!f.endsWith(".md")) continue;
51815
52000
  if (keep.has(basename4(f))) continue;
51816
52001
  try {
51817
- unlinkSync2(join19(paths.skillsDir, f));
52002
+ unlinkSync2(join20(paths.skillsDir, f));
51818
52003
  pruned++;
51819
52004
  } catch {
51820
52005
  }
51821
52006
  }
51822
52007
  rows.sort((a, b) => a.id.localeCompare(b.id));
51823
- writeFileSync12(
52008
+ writeFileSync13(
51824
52009
  paths.skillsManifest,
51825
52010
  JSON.stringify({ generatedAt: Date.now(), skills: rows }, null, 2),
51826
52011
  "utf8"
@@ -51832,22 +52017,22 @@ async function syncSkills(paths, client, seed, pins = [], techSeed) {
51832
52017
  init_src2();
51833
52018
  import {
51834
52019
  cpSync,
51835
- existsSync as existsSync16,
52020
+ existsSync as existsSync17,
51836
52021
  lstatSync,
51837
52022
  mkdirSync as mkdirSync7,
51838
- readFileSync as readFileSync15,
52023
+ readFileSync as readFileSync16,
51839
52024
  readdirSync as readdirSync8,
51840
52025
  rmSync as rmSync2,
51841
52026
  symlinkSync,
51842
- writeFileSync as writeFileSync13
52027
+ writeFileSync as writeFileSync14
51843
52028
  } from "node:fs";
51844
- import { join as join20 } from "node:path";
52029
+ import { join as join21 } from "node:path";
51845
52030
  var SKILL_NS = "errata-";
51846
52031
  var HARNESS_SKILL_DIRS = [
51847
- { configDir: ".claude", skillsDir: join20(".claude", "skills") },
52032
+ { configDir: ".claude", skillsDir: join21(".claude", "skills") },
51848
52033
  // Cursor adopted the standard; its exact project dir is still moving — kept
51849
52034
  // best-effort and gated on `.cursor/` presence so we never create it blind.
51850
- { configDir: ".cursor", skillsDir: join20(".cursor", "skills") }
52035
+ { configDir: ".cursor", skillsDir: join21(".cursor", "skills") }
51851
52036
  ];
51852
52037
  function skillSlug(title, id) {
51853
52038
  const base = title.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || id.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "skill";
@@ -51892,12 +52077,12 @@ function skillCiteHandle(s) {
51892
52077
  return priorHandle({ id: s.id, description: s.title });
51893
52078
  }
51894
52079
  function reconcileNamespaced(dir, keep) {
51895
- if (!existsSync16(dir)) return 0;
52080
+ if (!existsSync17(dir)) return 0;
51896
52081
  let pruned = 0;
51897
52082
  for (const name2 of readdirSync8(dir)) {
51898
52083
  if (!name2.startsWith(SKILL_NS) || keep.has(name2)) continue;
51899
52084
  try {
51900
- rmSync2(join20(dir, name2), { recursive: true, force: true });
52085
+ rmSync2(join21(dir, name2), { recursive: true, force: true });
51901
52086
  pruned++;
51902
52087
  } catch {
51903
52088
  }
@@ -51906,7 +52091,7 @@ function reconcileNamespaced(dir, keep) {
51906
52091
  }
51907
52092
  function linkOrCopy(linkPath, target) {
51908
52093
  try {
51909
- if (existsSync16(linkPath) || safeLstat(linkPath)) rmSync2(linkPath, { recursive: true, force: true });
52094
+ if (existsSync17(linkPath) || safeLstat(linkPath)) rmSync2(linkPath, { recursive: true, force: true });
51910
52095
  } catch {
51911
52096
  }
51912
52097
  try {
@@ -51927,7 +52112,7 @@ function safeLstat(p) {
51927
52112
  }
51928
52113
  }
51929
52114
  function emitAndProjectSkills(root, skills) {
51930
- const agentsSkillsDir = join20(root, ".agents", "skills");
52115
+ const agentsSkillsDir = join21(root, ".agents", "skills");
51931
52116
  mkdirSync7(agentsSkillsDir, { recursive: true });
51932
52117
  const slugs = [];
51933
52118
  const keep = /* @__PURE__ */ new Set();
@@ -51935,7 +52120,7 @@ function emitAndProjectSkills(root, skills) {
51935
52120
  for (const s of skills) {
51936
52121
  let body2;
51937
52122
  try {
51938
- body2 = readFileSync15(s.bodyPath, "utf8");
52123
+ body2 = readFileSync16(s.bodyPath, "utf8");
51939
52124
  } catch {
51940
52125
  continue;
51941
52126
  }
@@ -51944,9 +52129,9 @@ function emitAndProjectSkills(root, skills) {
51944
52129
  keep.add(slug2);
51945
52130
  slugs.push(slug2);
51946
52131
  const description = deriveDescription(s.title, s.layer, body2);
51947
- mkdirSync7(join20(agentsSkillsDir, slug2), { recursive: true });
51948
- writeFileSync13(
51949
- join20(agentsSkillsDir, slug2, "SKILL.md"),
52132
+ mkdirSync7(join21(agentsSkillsDir, slug2), { recursive: true });
52133
+ writeFileSync14(
52134
+ join21(agentsSkillsDir, slug2, "SKILL.md"),
51950
52135
  renderSkillMd(slug2, description, body2, skillCiteHandle(s)),
51951
52136
  "utf8"
51952
52137
  );
@@ -51955,11 +52140,11 @@ function emitAndProjectSkills(root, skills) {
51955
52140
  reconcileNamespaced(agentsSkillsDir, keep);
51956
52141
  let projected = 0;
51957
52142
  for (const h of HARNESS_SKILL_DIRS) {
51958
- if (!existsSync16(join20(root, h.configDir))) continue;
51959
- const dir = join20(root, h.skillsDir);
52143
+ if (!existsSync17(join21(root, h.configDir))) continue;
52144
+ const dir = join21(root, h.skillsDir);
51960
52145
  mkdirSync7(dir, { recursive: true });
51961
52146
  for (const slug2 of slugs) {
51962
- linkOrCopy(join20(dir, slug2), join20(agentsSkillsDir, slug2));
52147
+ linkOrCopy(join21(dir, slug2), join21(agentsSkillsDir, slug2));
51963
52148
  projected++;
51964
52149
  }
51965
52150
  reconcileNamespaced(dir, keep);
@@ -51968,15 +52153,15 @@ function emitAndProjectSkills(root, skills) {
51968
52153
  return { slugs, emitted, projected };
51969
52154
  }
51970
52155
  function emitInputsFromManifest(erretaDir, manifestPath) {
51971
- if (!existsSync16(manifestPath)) return [];
52156
+ if (!existsSync17(manifestPath)) return [];
51972
52157
  try {
51973
- const parsed = JSON.parse(readFileSync15(manifestPath, "utf8"));
52158
+ const parsed = JSON.parse(readFileSync16(manifestPath, "utf8"));
51974
52159
  return (parsed.skills ?? []).filter((s) => Boolean(s.id && s.file)).map((s) => ({
51975
52160
  id: s.id,
51976
52161
  title: s.title ?? s.id,
51977
52162
  layer: s.layer ?? "technique",
51978
52163
  confidence: s.confidence ?? 0,
51979
- bodyPath: join20(erretaDir, s.file)
52164
+ bodyPath: join21(erretaDir, s.file)
51980
52165
  }));
51981
52166
  } catch {
51982
52167
  return [];
@@ -51990,17 +52175,17 @@ var GITIGNORE_LINES = [
51990
52175
  ".cursor/skills/errata-*/"
51991
52176
  ];
51992
52177
  function ensureSkillGitignore(root) {
51993
- const path2 = join20(root, ".gitignore");
52178
+ const path2 = join21(root, ".gitignore");
51994
52179
  let current = "";
51995
52180
  try {
51996
- current = existsSync16(path2) ? readFileSync15(path2, "utf8") : "";
52181
+ current = existsSync17(path2) ? readFileSync16(path2, "utf8") : "";
51997
52182
  } catch {
51998
52183
  return;
51999
52184
  }
52000
52185
  if (current.includes(GITIGNORE_MARK)) return;
52001
52186
  const prefix = current.length > 0 && !current.endsWith("\n") ? "\n" : "";
52002
52187
  try {
52003
- writeFileSync13(path2, `${current}${prefix}
52188
+ writeFileSync14(path2, `${current}${prefix}
52004
52189
  ${GITIGNORE_LINES.join("\n")}
52005
52190
  `, "utf8");
52006
52191
  } catch {
@@ -52061,20 +52246,20 @@ init_paths();
52061
52246
  // src/profile.ts
52062
52247
  init_src2();
52063
52248
  init_paths();
52064
- import { existsSync as existsSync18, readFileSync as readFileSync17, writeFileSync as writeFileSync14 } from "node:fs";
52249
+ import { existsSync as existsSync19, readFileSync as readFileSync18, writeFileSync as writeFileSync15 } from "node:fs";
52065
52250
  import { createHash as createHash12 } from "node:crypto";
52066
- import { join as join22 } from "node:path";
52251
+ import { join as join23 } from "node:path";
52067
52252
 
52068
52253
  // src/git-remote.ts
52069
52254
  init_src();
52070
- import { existsSync as existsSync17, readFileSync as readFileSync16, statSync as statSync4 } from "node:fs";
52071
- import { isAbsolute as isAbsolute3, join as join21, resolve as resolve5 } from "node:path";
52255
+ import { existsSync as existsSync18, readFileSync as readFileSync17, statSync as statSync4 } from "node:fs";
52256
+ import { isAbsolute as isAbsolute3, join as join22, resolve as resolve5 } from "node:path";
52072
52257
  function resolveGitDir(root) {
52073
- const dotGit = join21(root, ".git");
52258
+ const dotGit = join22(root, ".git");
52074
52259
  try {
52075
52260
  const st = statSync4(dotGit);
52076
52261
  if (st.isDirectory()) return dotGit;
52077
- const m = /^gitdir:\s*(.+?)\s*$/m.exec(readFileSync16(dotGit, "utf8"));
52262
+ const m = /^gitdir:\s*(.+?)\s*$/m.exec(readFileSync17(dotGit, "utf8"));
52078
52263
  if (!m) return null;
52079
52264
  const dir = m[1];
52080
52265
  return isAbsolute3(dir) ? dir : resolve5(root, dir);
@@ -52083,22 +52268,22 @@ function resolveGitDir(root) {
52083
52268
  }
52084
52269
  }
52085
52270
  function gitConfigPath(gitDir) {
52086
- const commondirFile = join21(gitDir, "commondir");
52087
- if (existsSync17(commondirFile)) {
52088
- const common = readFileSync16(commondirFile, "utf8").trim();
52271
+ const commondirFile = join22(gitDir, "commondir");
52272
+ if (existsSync18(commondirFile)) {
52273
+ const common = readFileSync17(commondirFile, "utf8").trim();
52089
52274
  const commonDir = isAbsolute3(common) ? common : resolve5(gitDir, common);
52090
- return join21(commonDir, "config");
52275
+ return join22(commonDir, "config");
52091
52276
  }
52092
- return join21(gitDir, "config");
52277
+ return join22(gitDir, "config");
52093
52278
  }
52094
52279
  function readRemotes(root) {
52095
52280
  const gitDir = resolveGitDir(root);
52096
52281
  if (!gitDir) return [];
52097
52282
  const cfgPath = gitConfigPath(gitDir);
52098
- if (!existsSync17(cfgPath)) return [];
52283
+ if (!existsSync18(cfgPath)) return [];
52099
52284
  let txt;
52100
52285
  try {
52101
- txt = readFileSync16(cfgPath, "utf8");
52286
+ txt = readFileSync17(cfgPath, "utf8");
52102
52287
  } catch {
52103
52288
  return [];
52104
52289
  }
@@ -52134,13 +52319,13 @@ function refreshRepoLocator(root, profile) {
52134
52319
  }
52135
52320
  function loadProfile(root) {
52136
52321
  const p = workspacePaths(root);
52137
- if (!existsSync18(p.workspaceJson)) return null;
52138
- return JSON.parse(readFileSync17(p.workspaceJson, "utf8"));
52322
+ if (!existsSync19(p.workspaceJson)) return null;
52323
+ return JSON.parse(readFileSync18(p.workspaceJson, "utf8"));
52139
52324
  }
52140
52325
  function saveProfile(root, profile) {
52141
52326
  const p = workspacePaths(root);
52142
52327
  ensureDir(p.configDir);
52143
- writeFileSync14(p.workspaceJson, JSON.stringify(profile, null, 2), "utf8");
52328
+ writeFileSync15(p.workspaceJson, JSON.stringify(profile, null, 2), "utf8");
52144
52329
  }
52145
52330
  function autodetectProfile(root) {
52146
52331
  const id = workspaceId(root);
@@ -52148,10 +52333,10 @@ function autodetectProfile(root) {
52148
52333
  const p = emptyProfile(id, name2);
52149
52334
  const locator = detectRepoLocator(root);
52150
52335
  if (locator) p.repoLocator = locator;
52151
- const pkgPath = join22(root, "package.json");
52152
- if (existsSync18(pkgPath)) {
52336
+ const pkgPath = join23(root, "package.json");
52337
+ if (existsSync19(pkgPath)) {
52153
52338
  try {
52154
- const pkg = JSON.parse(readFileSync17(pkgPath, "utf8"));
52339
+ const pkg = JSON.parse(readFileSync18(pkgPath, "utf8"));
52155
52340
  p.languages.push("typescript", "javascript");
52156
52341
  const nodeVer = pkg.engines?.node ?? "node";
52157
52342
  p.stack.push(`node@${nodeVer}`);
@@ -52172,10 +52357,10 @@ function autodetectProfile(root) {
52172
52357
  } catch {
52173
52358
  }
52174
52359
  }
52175
- const pyproject = join22(root, "pyproject.toml");
52176
- if (existsSync18(pyproject)) {
52360
+ const pyproject = join23(root, "pyproject.toml");
52361
+ if (existsSync19(pyproject)) {
52177
52362
  try {
52178
- const txt = readFileSync17(pyproject, "utf8");
52363
+ const txt = readFileSync18(pyproject, "utf8");
52179
52364
  const py = /python\s*=\s*"([^"]+)"/.exec(txt)?.[1];
52180
52365
  p.languages.push("python");
52181
52366
  p.stack.push(`python@${py ?? "3"}`);
@@ -52186,16 +52371,16 @@ function autodetectProfile(root) {
52186
52371
  } catch {
52187
52372
  }
52188
52373
  }
52189
- const reqs = join22(root, "requirements.txt");
52190
- if (existsSync18(reqs)) {
52374
+ const reqs = join23(root, "requirements.txt");
52375
+ if (existsSync19(reqs)) {
52191
52376
  if (!p.languages.includes("python")) p.languages.push("python");
52192
52377
  if (!p.stack.includes("python@3")) p.stack.push("python@3");
52193
52378
  }
52194
- if (existsSync18(join22(root, "go.mod"))) {
52379
+ if (existsSync19(join23(root, "go.mod"))) {
52195
52380
  p.languages.push("go");
52196
52381
  p.stack.push("go");
52197
52382
  }
52198
- if (existsSync18(join22(root, "Cargo.toml"))) {
52383
+ if (existsSync19(join23(root, "Cargo.toml"))) {
52199
52384
  p.languages.push("rust");
52200
52385
  p.stack.push("rust");
52201
52386
  }
@@ -52205,17 +52390,17 @@ function autodetectProfile(root) {
52205
52390
  }
52206
52391
 
52207
52392
  // src/witness-queue.ts
52208
- import { readFileSync as readFileSync18, renameSync as renameSync2, writeFileSync as writeFileSync15 } from "node:fs";
52209
- import { dirname as dirname9, join as join23 } from "node:path";
52393
+ import { readFileSync as readFileSync19, renameSync as renameSync2, writeFileSync as writeFileSync16 } from "node:fs";
52394
+ import { dirname as dirname9, join as join24 } from "node:path";
52210
52395
  var WITNESS_QUEUE_CAP = 500;
52211
52396
  var WITNESS_TTL_MS = 14 * 24 * 60 * 60 * 1e3;
52212
52397
  var WITNESS_MAX_ATTEMPTS = 5;
52213
52398
  function witnessQueuePath(workspaceConfigDir) {
52214
- return join23(workspaceConfigDir, "witness-queue.json");
52399
+ return join24(workspaceConfigDir, "witness-queue.json");
52215
52400
  }
52216
52401
  function loadWitnessQueue(path2) {
52217
52402
  try {
52218
- const raw2 = JSON.parse(readFileSync18(path2, "utf8"));
52403
+ const raw2 = JSON.parse(readFileSync19(path2, "utf8"));
52219
52404
  if (!Array.isArray(raw2)) return [];
52220
52405
  return raw2.filter(
52221
52406
  (w) => !!w && typeof w === "object" && typeof w.nodeId === "string" && typeof w.witnessKey === "string"
@@ -52226,8 +52411,8 @@ function loadWitnessQueue(path2) {
52226
52411
  }
52227
52412
  function saveWitnessQueue(path2, queue) {
52228
52413
  try {
52229
- const tmp = join23(dirname9(path2), `.${Date.now()}.witness-queue.tmp`);
52230
- writeFileSync15(tmp, JSON.stringify(queue), "utf8");
52414
+ const tmp = join24(dirname9(path2), `.${Date.now()}.witness-queue.tmp`);
52415
+ writeFileSync16(tmp, JSON.stringify(queue), "utf8");
52231
52416
  renameSync2(tmp, path2);
52232
52417
  } catch {
52233
52418
  }
@@ -52507,7 +52692,7 @@ function startLoopLagMonitor(thresholdMs = 1e3) {
52507
52692
  }
52508
52693
 
52509
52694
  // src/engine.ts
52510
- var DAEMON_VERSION = true ? "2.0.2-dev.245" : "2.0.0-alpha.0";
52695
+ var DAEMON_VERSION = true ? "2.0.2-dev.247" : "2.0.0-alpha.0";
52511
52696
  var IGNORED_PATH = /[\\/](?:\.git|node_modules|\.errata|\.claude|\.codex|\.cursor|\.turbo|\.next|dist|coverage|test-results|playwright-report|__pycache__)(?:[\\/]|$)/;
52512
52697
  var IGNORED_NOISE = /castalia\.db|eventlog\.sqlite|turn-cursors/;
52513
52698
  var GIT_OP_MUTE_MS = 4e3;
@@ -52517,7 +52702,7 @@ var TURN_REPLAY_LOOKBACK_MS = 7 * 24 * 60 * 6e4;
52517
52702
  function appendIdentityAudit(path2, record2, line) {
52518
52703
  if (!record2.accepted && record2.score <= 0) return;
52519
52704
  try {
52520
- if (existsSync19(path2) && statSync5(path2).size >= IDENTITY_AUDIT_MAX_BYTES) {
52705
+ if (existsSync20(path2) && statSync5(path2).size >= IDENTITY_AUDIT_MAX_BYTES) {
52521
52706
  renameSync3(path2, `${path2}.1`);
52522
52707
  }
52523
52708
  appendFileSync2(path2, line);
@@ -52527,7 +52712,7 @@ function appendIdentityAudit(path2, record2, line) {
52527
52712
  var yieldToLoop = () => new Promise((r) => setImmediate(r));
52528
52713
  function loadTurnCursors(path2) {
52529
52714
  try {
52530
- const raw2 = JSON.parse(readFileSync19(path2, "utf8"));
52715
+ const raw2 = JSON.parse(readFileSync20(path2, "utf8"));
52531
52716
  return new Map(
52532
52717
  Object.entries(raw2).map(([k, v]) => [k, typeof v === "string" ? v : String(v?.uuid ?? "")])
52533
52718
  );
@@ -52537,7 +52722,7 @@ function loadTurnCursors(path2) {
52537
52722
  }
52538
52723
  function loadTurnOffsets(path2) {
52539
52724
  try {
52540
- const raw2 = JSON.parse(readFileSync19(path2, "utf8"));
52725
+ const raw2 = JSON.parse(readFileSync20(path2, "utf8"));
52541
52726
  const out2 = /* @__PURE__ */ new Map();
52542
52727
  for (const [k, v] of Object.entries(raw2)) {
52543
52728
  const off = typeof v === "object" && v !== null ? v.offset : void 0;
@@ -52553,7 +52738,7 @@ function saveTurnCursors(path2, cursors, offsets) {
52553
52738
  const merged = {};
52554
52739
  for (const [k, uuid3] of cursors) merged[k] = { uuid: uuid3, offset: offsets.get(k) ?? 0 };
52555
52740
  for (const [k, offset] of offsets) if (!merged[k]) merged[k] = { uuid: "", offset };
52556
- writeFileSync16(path2, JSON.stringify(merged), "utf8");
52741
+ writeFileSync17(path2, JSON.stringify(merged), "utf8");
52557
52742
  } catch {
52558
52743
  }
52559
52744
  }
@@ -52575,7 +52760,7 @@ function gitSourceWatchTargets(root) {
52575
52760
  ["-C", root, "ls-files", "--others", "--ignored", "--exclude-standard", "--directory", "-z"],
52576
52761
  { encoding: "utf8", maxBuffer: 256 * 1024 * 1024, windowsHide: true, stdio: ["ignore", "pipe", "ignore"] }
52577
52762
  );
52578
- ignoredDirs = igOut.split("\0").filter(Boolean).map((d) => d.replace(/\/+$/, "")).filter((d) => !IGNORED_PATH.test(join24(root, d) + sep4));
52763
+ ignoredDirs = igOut.split("\0").filter(Boolean).map((d) => d.replace(/\/+$/, "")).filter((d) => !IGNORED_PATH.test(join25(root, d) + sep4));
52579
52764
  } catch {
52580
52765
  }
52581
52766
  const hasIgnoredChild = (dir) => ignoredDirs.some((ig) => ig.startsWith(dir + "/"));
@@ -52587,19 +52772,19 @@ function gitSourceWatchTargets(root) {
52587
52772
  if (!f.startsWith(prefix)) continue;
52588
52773
  const rest2 = f.slice(prefix.length);
52589
52774
  if (rest2.includes("/")) children.add(dir === "" ? rest2.slice(0, rest2.indexOf("/")) : dir + "/" + rest2.slice(0, rest2.indexOf("/")));
52590
- else targets.add(join24(root, f));
52775
+ else targets.add(join25(root, f));
52591
52776
  }
52592
52777
  for (const c of children) {
52593
- if (IGNORED_PATH.test(join24(root, c) + sep4)) continue;
52778
+ if (IGNORED_PATH.test(join25(root, c) + sep4)) continue;
52594
52779
  if (hasIgnoredChild(c)) addUnder(c);
52595
- else targets.add(join24(root, c));
52780
+ else targets.add(join25(root, c));
52596
52781
  }
52597
52782
  };
52598
52783
  addUnder("");
52599
52784
  if (targets.size > 0) return [...targets];
52600
52785
  } catch {
52601
52786
  }
52602
- return readdirSync9(root, { withFileTypes: true }).filter((e) => e.isDirectory() && !IGNORED_PATH.test(join24(root, String(e.name)) + sep4)).map((e) => join24(root, String(e.name)));
52787
+ return readdirSync9(root, { withFileTypes: true }).filter((e) => e.isDirectory() && !IGNORED_PATH.test(join25(root, String(e.name)) + sep4)).map((e) => join25(root, String(e.name)));
52603
52788
  }
52604
52789
  function createWorkspaceEngine(opts) {
52605
52790
  const paths = workspacePaths(opts.workspaceRoot);
@@ -52757,7 +52942,7 @@ function createWorkspaceEngine(opts) {
52757
52942
  const srcPaths = diff.changedPaths.filter((p) => /\.(ts|tsx|js|jsx|mjs|cjs|py)$/i.test(p));
52758
52943
  let episodeId2;
52759
52944
  if (srcPaths.length > 0) {
52760
- const abs = srcPaths.map((p) => join24(opts.workspaceRoot, p));
52945
+ const abs = srcPaths.map((p) => join25(opts.workspaceRoot, p));
52761
52946
  try {
52762
52947
  const r = await runReindexPass(
52763
52948
  `git-reindex:${profile.name} (${abs.length} files)`,
@@ -52793,8 +52978,8 @@ function createWorkspaceEngine(opts) {
52793
52978
  `[errata] git: ${ev.kind} ${ev.newSha.slice(0, 7)} by ${meta3.authorName} \u2014 ${diff.changedPaths.length} file(s), ${diff.renames.length} rename(s)`
52794
52979
  );
52795
52980
  };
52796
- const gitDir = join24(opts.workspaceRoot, ".git");
52797
- if (existsSync19(gitDir)) {
52981
+ const gitDir = join25(opts.workspaceRoot, ".git");
52982
+ if (existsSync20(gitDir)) {
52798
52983
  stopGit = startGitSensor(gitDir, (ev) => {
52799
52984
  void handleGitEvent(ev).catch((err2) => {
52800
52985
  console.warn("[errata] git event handler failed:", err2);
@@ -52864,10 +53049,10 @@ function createWorkspaceEngine(opts) {
52864
53049
  });
52865
53050
  doneRender?.();
52866
53051
  writeContextFile(opts.workspaceRoot, body2);
52867
- const target = join24(opts.workspaceRoot, "AGENTS.md");
53052
+ const target = join25(opts.workspaceRoot, "AGENTS.md");
52868
53053
  writeManagedBlock(target, { body: AGENTS_POINTER_BODY, stable: true, force: true });
52869
53054
  if (elicit) {
52870
- writePrimingHandles(join24(paths.configDir, "priming-handles.json"), [
53055
+ writePrimingHandles(join25(paths.configDir, "priming-handles.json"), [
52871
53056
  ...snapshot.recentProblems.map((r) => r.node),
52872
53057
  // Resolved-band handles: the ✓ problem AND its Solution are citable
52873
53058
  // (a fix tag on an already-resolved problem no-ops idempotently; the
@@ -52958,6 +53143,17 @@ function createWorkspaceEngine(opts) {
52958
53143
  } catch (err2) {
52959
53144
  console.warn("[errata] anchor backfill failed:", err2);
52960
53145
  }
53146
+ try {
53147
+ const r = repairInvalidEdges(store, { configDir: paths.configDir, now: Date.now() });
53148
+ if (!r.skipped && r.invalid > 0) {
53149
+ console.log(
53150
+ `[errata] edge repair: ${r.retyped} edge(s) retyped, ${r.closed} closed (${Object.entries(r.byType).map(([t, n]) => `${t}x${n}`).join(", ")})`
53151
+ );
53152
+ refreshContextNow();
53153
+ }
53154
+ } catch (err2) {
53155
+ console.warn("[errata] edge repair failed:", err2);
53156
+ }
52961
53157
  try {
52962
53158
  const c = backfillConstraintKind(store, {
52963
53159
  root: opts.workspaceRoot,
@@ -53072,7 +53268,7 @@ function createWorkspaceEngine(opts) {
53072
53268
  resultSummary: { exitCode: e.exitCode ?? 1, errorTokens: e.errorTokens }
53073
53269
  });
53074
53270
  };
53075
- const turnCursorPath = join24(paths.configDir, "turn-cursors.json");
53271
+ const turnCursorPath = join25(paths.configDir, "turn-cursors.json");
53076
53272
  const lastTurnUuid = loadTurnCursors(turnCursorPath);
53077
53273
  const turnOffset = loadTurnOffsets(turnCursorPath);
53078
53274
  const sessionLastProblem = /* @__PURE__ */ new Map();
@@ -53096,7 +53292,7 @@ function createWorkspaceEngine(opts) {
53096
53292
  const t = Date.now();
53097
53293
  let processedTurns = 0;
53098
53294
  const elicit = isEdgeElicitationEnabled();
53099
- const handleMap = elicit ? readPrimingHandles(join24(paths.configDir, "priming-handles.json")) : {};
53295
+ const handleMap = elicit ? readPrimingHandles(join25(paths.configDir, "priming-handles.json")) : {};
53100
53296
  const wsRoot = (opts.workspaceRoot ?? "").replace(/\\/g, "/");
53101
53297
  const toRel = (abs) => {
53102
53298
  const p = abs.replace(/\\/g, "/");
@@ -53405,9 +53601,7 @@ function createWorkspaceEngine(opts) {
53405
53601
  if (targetId === pid) continue;
53406
53602
  const target = store.getNode(targetId);
53407
53603
  if (!target) continue;
53408
- const fallback = typePriorEdge("Problem", target.label);
53409
- const type = target.label === "Pattern" ? "INSTANCE_OF" : target.label === "Problem" ? "MATCHES" : fallback === "SUPERSEDES" ? "RELATES_TO" : fallback;
53410
- mintCiteEdge(pid, targetId, type, inst.evidence === "witnessed" ? 0.4 : 0.3, { instanceCite: true, evidence: inst.evidence });
53604
+ mintCiteEdge(pid, targetId, citeEdgeType(target.label), inst.evidence === "witnessed" ? 0.4 : 0.3, { instanceCite: true, evidence: inst.evidence });
53411
53605
  }
53412
53606
  }
53413
53607
  for (const tf of plan.transfers) {
@@ -53707,7 +53901,7 @@ function createWorkspaceEngine(opts) {
53707
53901
  try {
53708
53902
  const inputs = emitInputsFromManifest(paths.configDir, paths.skillsManifest);
53709
53903
  emitAndProjectSkills(opts.workspaceRoot, inputs);
53710
- writePrimingHandles(join24(paths.configDir, "priming-handles.json"), skillHandleNodes(inputs));
53904
+ writePrimingHandles(join25(paths.configDir, "priming-handles.json"), skillHandleNodes(inputs));
53711
53905
  } catch (err2) {
53712
53906
  console.warn("[skills] agent-skills projection failed (non-fatal):", err2 instanceof Error ? err2.message : err2);
53713
53907
  }
@@ -53894,7 +54088,7 @@ function createWorkspaceEngine(opts) {
53894
54088
  console.log(
53895
54089
  "[errata] sync skipped \u2014 cloud sync consent is off (enable with `errata consent sync on`)"
53896
54090
  );
53897
- const pending = existsSync19(paths.outbox) ? readdirSync9(paths.outbox).filter((f) => f.endsWith(".json")).length : 0;
54091
+ const pending = existsSync20(paths.outbox) ? readdirSync9(paths.outbox).filter((f) => f.endsWith(".json")).length : 0;
53898
54092
  return { uploaded: 0, failed: 0, remaining: pending };
53899
54093
  }
53900
54094
  try {
@@ -53981,7 +54175,7 @@ async function startDaemon(opts) {
53981
54175
  reviewUrl: () => webUiUrl + "/review"
53982
54176
  });
53983
54177
  const writeLockFile = (url2) => {
53984
- writeFileSync17(
54178
+ writeFileSync18(
53985
54179
  engine.paths.daemonLock,
53986
54180
  JSON.stringify({ pid: process.pid, webUiUrl: url2, startedAt: Date.now() }),
53987
54181
  "utf8"
@@ -54024,7 +54218,7 @@ async function startDaemon(opts) {
54024
54218
  );
54025
54219
  await engine.stop();
54026
54220
  try {
54027
- if (existsSync20(engine.paths.daemonLock)) {
54221
+ if (existsSync21(engine.paths.daemonLock)) {
54028
54222
  }
54029
54223
  } catch {
54030
54224
  }
@@ -54041,16 +54235,16 @@ async function listenServer(fetchFn, port) {
54041
54235
 
54042
54236
  // src/registry.ts
54043
54237
  init_paths();
54044
- import { existsSync as existsSync21, readFileSync as readFileSync20, writeFileSync as writeFileSync18 } from "node:fs";
54045
- import { join as join25 } from "node:path";
54238
+ import { existsSync as existsSync22, readFileSync as readFileSync21, writeFileSync as writeFileSync19 } from "node:fs";
54239
+ import { join as join26 } from "node:path";
54046
54240
  function registryPath() {
54047
- return process.env["ERRATA_REGISTRY_PATH"] ?? join25(globalDir(), "workspaces.json");
54241
+ return process.env["ERRATA_REGISTRY_PATH"] ?? join26(globalDir(), "workspaces.json");
54048
54242
  }
54049
54243
  function read() {
54050
54244
  const p = registryPath();
54051
- if (!existsSync21(p)) return { version: 1, workspaces: {} };
54245
+ if (!existsSync22(p)) return { version: 1, workspaces: {} };
54052
54246
  try {
54053
- const parsed = JSON.parse(readFileSync20(p, "utf8"));
54247
+ const parsed = JSON.parse(readFileSync21(p, "utf8"));
54054
54248
  return { version: 1, workspaces: parsed.workspaces ?? {} };
54055
54249
  } catch {
54056
54250
  return { version: 1, workspaces: {} };
@@ -54058,7 +54252,7 @@ function read() {
54058
54252
  }
54059
54253
  function write(reg) {
54060
54254
  ensureDir(globalDir());
54061
- writeFileSync18(registryPath(), JSON.stringify(reg, null, 2), "utf8");
54255
+ writeFileSync19(registryPath(), JSON.stringify(reg, null, 2), "utf8");
54062
54256
  }
54063
54257
  function registerWorkspace(profile, root, now = Date.now()) {
54064
54258
  const reg = read();
@@ -54075,7 +54269,7 @@ function pruneMissingWorkspaces() {
54075
54269
  const reg = read();
54076
54270
  const removed = [];
54077
54271
  for (const [id, entry] of Object.entries(reg.workspaces)) {
54078
- if (!existsSync21(entry.path)) {
54272
+ if (!existsSync22(entry.path)) {
54079
54273
  removed.push(entry);
54080
54274
  delete reg.workspaces[id];
54081
54275
  }
@@ -54084,13 +54278,13 @@ function pruneMissingWorkspaces() {
54084
54278
  return removed;
54085
54279
  }
54086
54280
  function workspaceStatus(entry) {
54087
- const missing = !existsSync21(entry.path);
54281
+ const missing = !existsSync22(entry.path);
54088
54282
  const lockPath = workspacePaths(entry.path).daemonLock;
54089
54283
  let running = false;
54090
54284
  let webUiUrl = null;
54091
- if (existsSync21(lockPath)) {
54285
+ if (existsSync22(lockPath)) {
54092
54286
  try {
54093
- const lock = JSON.parse(readFileSync20(lockPath, "utf8"));
54287
+ const lock = JSON.parse(readFileSync21(lockPath, "utf8"));
54094
54288
  if (lock.pid && lock.webUiUrl && pidAlive(lock.pid)) {
54095
54289
  running = true;
54096
54290
  webUiUrl = lock.webUiUrl;
@@ -54118,7 +54312,7 @@ function pidAlive(pid) {
54118
54312
  // src/multi.ts
54119
54313
  init_dist();
54120
54314
  init_src4();
54121
- import { readFileSync as readFileSync23, unlinkSync as unlinkSync3, writeFileSync as writeFileSync19 } from "node:fs";
54315
+ import { readFileSync as readFileSync24, unlinkSync as unlinkSync3, writeFileSync as writeFileSync20 } from "node:fs";
54122
54316
 
54123
54317
  // src/principle-sync.ts
54124
54318
  init_src4();
@@ -54146,8 +54340,8 @@ init_reconcile();
54146
54340
 
54147
54341
  // src/lockfile-auto.ts
54148
54342
  init_src();
54149
- import { existsSync as existsSync22, readFileSync as readFileSync21 } from "node:fs";
54150
- import { join as join26 } from "node:path";
54343
+ import { existsSync as existsSync23, readFileSync as readFileSync22 } from "node:fs";
54344
+ import { join as join27 } from "node:path";
54151
54345
 
54152
54346
  // src/package-index.ts
54153
54347
  init_src();
@@ -54296,11 +54490,11 @@ function runLockfilePass(opts) {
54296
54490
  { file: "package-lock.json", parse: parsePackageLockJson }
54297
54491
  ];
54298
54492
  for (const c of candidates) {
54299
- const p = join26(opts.root, c.file);
54300
- if (!existsSync22(p)) continue;
54493
+ const p = join27(opts.root, c.file);
54494
+ if (!existsSync23(p)) continue;
54301
54495
  let sbom;
54302
54496
  try {
54303
- sbom = c.parse(readFileSync21(p, "utf8"));
54497
+ sbom = c.parse(readFileSync22(p, "utf8"));
54304
54498
  } catch {
54305
54499
  continue;
54306
54500
  }
@@ -54748,7 +54942,7 @@ var ConsolidateWorker = class {
54748
54942
  init_paths();
54749
54943
 
54750
54944
  // src/lock.ts
54751
- import { existsSync as existsSync23, readFileSync as readFileSync22 } from "node:fs";
54945
+ import { existsSync as existsSync24, readFileSync as readFileSync23 } from "node:fs";
54752
54946
  function isProcessAlive(pid) {
54753
54947
  if (!pid || pid <= 0) return false;
54754
54948
  try {
@@ -54759,9 +54953,9 @@ function isProcessAlive(pid) {
54759
54953
  }
54760
54954
  }
54761
54955
  function readDaemonLock(lockPath) {
54762
- if (!existsSync23(lockPath)) return null;
54956
+ if (!existsSync24(lockPath)) return null;
54763
54957
  try {
54764
- const lock = JSON.parse(readFileSync22(lockPath, "utf8"));
54958
+ const lock = JSON.parse(readFileSync23(lockPath, "utf8"));
54765
54959
  return typeof lock.pid === "number" ? lock : null;
54766
54960
  } catch {
54767
54961
  return null;
@@ -55040,12 +55234,12 @@ async function reanchorProject(opts) {
55040
55234
  }
55041
55235
 
55042
55236
  // src/adopt.ts
55043
- import { existsSync as existsSync24 } from "node:fs";
55044
- import { dirname as dirname10, join as join27 } from "node:path";
55237
+ import { existsSync as existsSync25 } from "node:fs";
55238
+ import { dirname as dirname10, join as join28 } from "node:path";
55045
55239
  function findGitRoot(absPath) {
55046
55240
  let dir = absPath;
55047
55241
  for (let depth = 0; depth < 64; depth++) {
55048
- if (existsSync24(join27(dir, ".git"))) return dir;
55242
+ if (existsSync25(join28(dir, ".git"))) return dir;
55049
55243
  const parent = dirname10(dir);
55050
55244
  if (parent === dir) return null;
55051
55245
  dir = parent;
@@ -55294,7 +55488,7 @@ async function startMultiDaemon(opts = {}) {
55294
55488
  void ambientLinkAll();
55295
55489
  app.route(`/ws/${rec.id}`, rec.webApp);
55296
55490
  try {
55297
- writeFileSync19(
55491
+ writeFileSync20(
55298
55492
  rec.engine.paths.daemonLock,
55299
55493
  JSON.stringify({ pid: process.pid, webUiUrl: `${baseUrl}/ws/${rec.id}`, startedAt: Date.now() }),
55300
55494
  "utf8"
@@ -55483,7 +55677,7 @@ async function startMultiDaemon(opts = {}) {
55483
55677
  baseUrl = `http://127.0.0.1:${port}`;
55484
55678
  try {
55485
55679
  ensureDir(globalDir());
55486
- writeFileSync19(
55680
+ writeFileSync20(
55487
55681
  lockPath,
55488
55682
  JSON.stringify({ pid: process.pid, webUiUrl: baseUrl, startedAt: Date.now() }),
55489
55683
  "utf8"
@@ -55492,7 +55686,7 @@ async function startMultiDaemon(opts = {}) {
55492
55686
  }
55493
55687
  for (const r of records) {
55494
55688
  try {
55495
- writeFileSync19(
55689
+ writeFileSync20(
55496
55690
  r.engine.paths.daemonLock,
55497
55691
  JSON.stringify({ pid: process.pid, webUiUrl: `${baseUrl}/ws/${r.id}`, startedAt: Date.now() }),
55498
55692
  "utf8"
@@ -55990,7 +56184,7 @@ async function startMultiDaemon(opts = {}) {
55990
56184
  },
55991
56185
  async stop() {
55992
56186
  try {
55993
- const cur = readFileSync23(lockPath, "utf8");
56187
+ const cur = readFileSync24(lockPath, "utf8");
55994
56188
  if (JSON.parse(cur).pid === process.pid) unlinkSync3(lockPath);
55995
56189
  } catch {
55996
56190
  }
@@ -57007,21 +57201,21 @@ async function cmdInit() {
57007
57201
  if (!skipHooks) {
57008
57202
  console.log("");
57009
57203
  console.log("installing harness hooks...");
57010
- const { existsSync: existsSync26 } = await import("node:fs");
57011
- const { join: join29 } = await import("node:path");
57204
+ const { existsSync: existsSync27 } = await import("node:fs");
57205
+ const { join: join30 } = await import("node:path");
57012
57206
  try {
57013
57207
  await installClaudeHooks(port);
57014
57208
  } catch (err2) {
57015
57209
  console.warn(` \u26A0\uFE0F Claude hook install failed: ${err2 instanceof Error ? err2.message : err2}`);
57016
57210
  }
57017
- if (existsSync26(join29(ROOT, ".cursor"))) {
57211
+ if (existsSync27(join30(ROOT, ".cursor"))) {
57018
57212
  try {
57019
57213
  await installCursorMcpConfig();
57020
57214
  } catch (err2) {
57021
57215
  console.warn(` \u26A0\uFE0F Cursor MCP config failed: ${err2 instanceof Error ? err2.message : err2}`);
57022
57216
  }
57023
57217
  }
57024
- if (existsSync26(join29(ROOT, ".codex"))) {
57218
+ if (existsSync27(join30(ROOT, ".codex"))) {
57025
57219
  try {
57026
57220
  await installCodexHooks(port);
57027
57221
  } catch (err2) {
@@ -57178,9 +57372,9 @@ async function cmdStatus() {
57178
57372
  console.log(` stack: ${profile.stack.join(", ") || "(none)"}`);
57179
57373
  console.log(` languages: ${profile.languages.join(", ") || "(none)"}`);
57180
57374
  }
57181
- console.log(` graph db: ${existsSync25(paths.castalia) ? "yes" : "no"} (${paths.castalia})`);
57182
- console.log(` event log: ${existsSync25(paths.eventLog) ? "yes" : "no"} (${paths.eventLog})`);
57183
- if (existsSync25(paths.castalia)) {
57375
+ console.log(` graph db: ${existsSync26(paths.castalia) ? "yes" : "no"} (${paths.castalia})`);
57376
+ console.log(` event log: ${existsSync26(paths.eventLog) ? "yes" : "no"} (${paths.eventLog})`);
57377
+ if (existsSync26(paths.castalia)) {
57184
57378
  try {
57185
57379
  const { openGraphStore: openGraphStore2 } = await Promise.resolve().then(() => (init_src4(), src_exports2));
57186
57380
  const store = openGraphStore2({ path: paths.castalia });
@@ -57196,6 +57390,16 @@ async function cmdStatus() {
57196
57390
  }
57197
57391
  }
57198
57392
  console.log(` contribute: ${pending} pending of ${total} instance node(s)`);
57393
+ const rejections = store.edgeRejections();
57394
+ if (rejections.length > 0) {
57395
+ const refused = rejections.reduce((n, r) => n + r.count, 0);
57396
+ console.log(` edges: ${refused} refused by the ontology gate \u2014 a producer is emitting invalid edges`);
57397
+ for (const r of rejections.slice(0, 3)) {
57398
+ const mins = Math.max(0, Math.round((Date.now() - r.lastAt) / 6e4));
57399
+ const age = mins < 60 ? `${mins}m ago` : mins < 1440 ? `${Math.round(mins / 60)}h ago` : `${Math.round(mins / 1440)}d ago`;
57400
+ console.log(` ${r.count}x ${r.type} (last ${age})${r.sample ? ` \u2014 ${r.sample}` : ""}`);
57401
+ }
57402
+ }
57199
57403
  } finally {
57200
57404
  store.close();
57201
57405
  }
@@ -57844,11 +58048,11 @@ function cmdInstallationProfile(args2) {
57844
58048
  }
57845
58049
  async function cmdReview() {
57846
58050
  const paths = workspacePaths(ROOT);
57847
- if (!existsSync25(paths.reviewQueue)) {
58051
+ if (!existsSync26(paths.reviewQueue)) {
57848
58052
  console.log("(review queue empty)");
57849
58053
  return;
57850
58054
  }
57851
- const queue = JSON.parse(readFileSync24(paths.reviewQueue, "utf8"));
58055
+ const queue = JSON.parse(readFileSync25(paths.reviewQueue, "utf8"));
57852
58056
  if (queue.length === 0) {
57853
58057
  console.log("(review queue empty)");
57854
58058
  return;
@@ -58519,7 +58723,7 @@ async function gatherRepo(store, ws) {
58519
58723
  };
58520
58724
  }
58521
58725
  async function gatherReportData(generatedAt) {
58522
- const { existsSync: existsSync26 } = await import("node:fs");
58726
+ const { existsSync: existsSync27 } = await import("node:fs");
58523
58727
  const { openGraphStore: openGraphStore2 } = await Promise.resolve().then(() => (init_src4(), src_exports2));
58524
58728
  const cfg = loadConfig();
58525
58729
  const outbound = cfg.consent.sync ? "auto" : "off";
@@ -58527,7 +58731,7 @@ async function gatherReportData(generatedAt) {
58527
58731
  for (const ws of listWorkspaces()) {
58528
58732
  if (ws.missing) continue;
58529
58733
  const dbPath = workspacePaths(ws.path).castalia;
58530
- if (!existsSync26(dbPath)) continue;
58734
+ if (!existsSync27(dbPath)) continue;
58531
58735
  let store = null;
58532
58736
  try {
58533
58737
  store = openGraphStore2({ path: dbPath });
@@ -58558,7 +58762,7 @@ async function gatherReportData(generatedAt) {
58558
58762
  };
58559
58763
  }
58560
58764
  async function cmdReport(args2) {
58561
- const { mkdirSync: mkdirSync8, writeFileSync: writeFileSync20 } = await import("node:fs");
58765
+ const { mkdirSync: mkdirSync8, writeFileSync: writeFileSync21 } = await import("node:fs");
58562
58766
  const { renderReport: renderReport2 } = await Promise.resolve().then(() => (init_report_render(), report_render_exports));
58563
58767
  const includeFutureVerbs = args2.includes("--future-verbs");
58564
58768
  const now = /* @__PURE__ */ new Date();
@@ -58571,8 +58775,8 @@ async function cmdReport(args2) {
58571
58775
  const outDir = workspacePaths(ROOT).configDir;
58572
58776
  mkdirSync8(outDir, { recursive: true });
58573
58777
  const files = renderReport2(data, { includeFutureVerbs });
58574
- for (const f of files) writeFileSync20(join28(outDir, f.name), f.html, "utf8");
58575
- const indexPath = join28(outDir, "report.html");
58778
+ for (const f of files) writeFileSync21(join29(outDir, f.name), f.html, "utf8");
58779
+ const indexPath = join29(outDir, "report.html");
58576
58780
  console.log(`report \u2192 ${indexPath}`);
58577
58781
  console.log(
58578
58782
  ` ${data.repos.length} repo(s) \xB7 ${files.length} file(s) \xB7 ${data.rollup.nodes.toLocaleString("en-US")} nodes`
@@ -58690,15 +58894,15 @@ function hookRelayCommand(port, path2) {
58690
58894
  return process.platform === "win32" ? `cmd //c "curl -s --connect-timeout 1 --max-time 2 -X POST -H \\"Content-Type: application/json\\" --data-binary @- ${url2} 2>NUL || echo {}"` : `curl -s --connect-timeout 1 --max-time 2 -X POST -H 'Content-Type: application/json' --data-binary @- ${url2} 2>/dev/null || echo '{}'`;
58691
58895
  }
58692
58896
  async function installClaudeHooks(port) {
58693
- const { mkdirSync: mkdirSync8, existsSync: existsSync26, readFileSync: readFileSync25, writeFileSync: writeFileSync20 } = await import("node:fs");
58694
- const { join: join29 } = await import("node:path");
58695
- const dir = join29(ROOT, ".claude");
58696
- if (!existsSync26(dir)) mkdirSync8(dir, { recursive: true });
58697
- const file2 = join29(dir, "settings.json");
58897
+ const { mkdirSync: mkdirSync8, existsSync: existsSync27, readFileSync: readFileSync26, writeFileSync: writeFileSync21 } = await import("node:fs");
58898
+ const { join: join30 } = await import("node:path");
58899
+ const dir = join30(ROOT, ".claude");
58900
+ if (!existsSync27(dir)) mkdirSync8(dir, { recursive: true });
58901
+ const file2 = join30(dir, "settings.json");
58698
58902
  let settings = {};
58699
- if (existsSync26(file2)) {
58903
+ if (existsSync27(file2)) {
58700
58904
  try {
58701
- settings = JSON.parse(readFileSync25(file2, "utf8"));
58905
+ settings = JSON.parse(readFileSync26(file2, "utf8"));
58702
58906
  } catch {
58703
58907
  console.error(`refusing to overwrite invalid JSON at ${file2}`);
58704
58908
  process.exit(2);
@@ -58744,10 +58948,10 @@ async function installClaudeHooks(port) {
58744
58948
  dropErrata(list);
58745
58949
  list.push({ hooks: [{ type: "command", command: injectCmd }] });
58746
58950
  }
58747
- writeFileSync20(file2, JSON.stringify(settings, null, 2) + "\n", "utf8");
58951
+ writeFileSync21(file2, JSON.stringify(settings, null, 2) + "\n", "utf8");
58748
58952
  console.log(`installed Claude Code hooks \u2192 ${file2}`);
58749
58953
  await installClaudeMcpConfig();
58750
- const claudeMd = join29(ROOT, "CLAUDE.md");
58954
+ const claudeMd = join30(ROOT, "CLAUDE.md");
58751
58955
  const recall = writeManagedBlock(claudeMd, { body: RECALL_FIRST_BLOCK });
58752
58956
  if (recall.kind === "collision") {
58753
58957
  console.warn(
@@ -58759,15 +58963,15 @@ async function installClaudeHooks(port) {
58759
58963
  console.log(` endpoint: http://127.0.0.1:${port}/api/hook`);
58760
58964
  }
58761
58965
  async function installClaudeMcpConfig() {
58762
- const { mkdirSync: mkdirSync8, existsSync: existsSync26, readFileSync: readFileSync25, writeFileSync: writeFileSync20 } = await import("node:fs");
58763
- const { join: join29, dirname: dirname11 } = await import("node:path");
58764
- const file2 = join29(ROOT, ".mcp.json");
58966
+ const { mkdirSync: mkdirSync8, existsSync: existsSync27, readFileSync: readFileSync26, writeFileSync: writeFileSync21 } = await import("node:fs");
58967
+ const { join: join30, dirname: dirname11 } = await import("node:path");
58968
+ const file2 = join30(ROOT, ".mcp.json");
58765
58969
  const dir = dirname11(file2);
58766
- if (!existsSync26(dir)) mkdirSync8(dir, { recursive: true });
58970
+ if (!existsSync27(dir)) mkdirSync8(dir, { recursive: true });
58767
58971
  let cfg = {};
58768
- if (existsSync26(file2)) {
58972
+ if (existsSync27(file2)) {
58769
58973
  try {
58770
- cfg = JSON.parse(readFileSync25(file2, "utf8"));
58974
+ cfg = JSON.parse(readFileSync26(file2, "utf8"));
58771
58975
  } catch {
58772
58976
  console.error(`refusing to overwrite invalid JSON at ${file2}`);
58773
58977
  process.exit(2);
@@ -58775,21 +58979,21 @@ async function installClaudeMcpConfig() {
58775
58979
  }
58776
58980
  cfg.mcpServers ??= {};
58777
58981
  cfg.mcpServers["errata"] = errataMcpInvocation();
58778
- writeFileSync20(file2, JSON.stringify(cfg, null, 2) + "\n", "utf8");
58982
+ writeFileSync21(file2, JSON.stringify(cfg, null, 2) + "\n", "utf8");
58779
58983
  console.log(`installed Claude Code MCP server config \u2192 ${file2}`);
58780
58984
  console.log(` Claude Code will spawn \`errata mcp\` on workspace open.`);
58781
58985
  console.log(` Tools: errata.search / locate / neighbors / callers_of / what_uses / show / similar`);
58782
58986
  }
58783
58987
  async function installCursorMcpConfig() {
58784
- const { mkdirSync: mkdirSync8, existsSync: existsSync26, readFileSync: readFileSync25, writeFileSync: writeFileSync20 } = await import("node:fs");
58785
- const { join: join29 } = await import("node:path");
58786
- const dir = join29(ROOT, ".cursor");
58787
- if (!existsSync26(dir)) mkdirSync8(dir, { recursive: true });
58788
- const file2 = join29(dir, "mcp.json");
58988
+ const { mkdirSync: mkdirSync8, existsSync: existsSync27, readFileSync: readFileSync26, writeFileSync: writeFileSync21 } = await import("node:fs");
58989
+ const { join: join30 } = await import("node:path");
58990
+ const dir = join30(ROOT, ".cursor");
58991
+ if (!existsSync27(dir)) mkdirSync8(dir, { recursive: true });
58992
+ const file2 = join30(dir, "mcp.json");
58789
58993
  let cfg = {};
58790
- if (existsSync26(file2)) {
58994
+ if (existsSync27(file2)) {
58791
58995
  try {
58792
- cfg = JSON.parse(readFileSync25(file2, "utf8"));
58996
+ cfg = JSON.parse(readFileSync26(file2, "utf8"));
58793
58997
  } catch {
58794
58998
  console.error(`refusing to overwrite invalid JSON at ${file2}`);
58795
58999
  process.exit(2);
@@ -58797,7 +59001,7 @@ async function installCursorMcpConfig() {
58797
59001
  }
58798
59002
  cfg.mcpServers ??= {};
58799
59003
  cfg.mcpServers["errata"] = errataMcpInvocation();
58800
- writeFileSync20(file2, JSON.stringify(cfg, null, 2) + "\n", "utf8");
59004
+ writeFileSync21(file2, JSON.stringify(cfg, null, 2) + "\n", "utf8");
58801
59005
  console.log(`installed Cursor MCP server config \u2192 ${file2}`);
58802
59006
  console.log(` Cursor will spawn \`errata mcp\` on workspace open.`);
58803
59007
  console.log(` Tools: errata.search / locate / neighbors / callers_of / what_uses`);
@@ -58805,16 +59009,16 @@ async function installCursorMcpConfig() {
58805
59009
  console.log(` \u26A0\uFE0F reload Cursor (Cmd/Ctrl-Shift-P \u2192 "Reload Window") to pick it up.`);
58806
59010
  }
58807
59011
  async function installCodexHooks(port) {
58808
- const { mkdirSync: mkdirSync8, existsSync: existsSync26, readFileSync: readFileSync25, writeFileSync: writeFileSync20 } = await import("node:fs");
58809
- const { join: join29 } = await import("node:path");
58810
- const dir = join29(ROOT, ".codex");
58811
- if (!existsSync26(dir)) mkdirSync8(dir, { recursive: true });
58812
- const file2 = join29(dir, "config.toml");
59012
+ const { mkdirSync: mkdirSync8, existsSync: existsSync27, readFileSync: readFileSync26, writeFileSync: writeFileSync21 } = await import("node:fs");
59013
+ const { join: join30 } = await import("node:path");
59014
+ const dir = join30(ROOT, ".codex");
59015
+ if (!existsSync27(dir)) mkdirSync8(dir, { recursive: true });
59016
+ const file2 = join30(dir, "config.toml");
58813
59017
  const BEGIN = `# >>> errata hooks (errata-managed)`;
58814
59018
  const END = `# <<< errata hooks`;
58815
59019
  let existing = "";
58816
- if (existsSync26(file2)) {
58817
- existing = readFileSync25(file2, "utf8");
59020
+ if (existsSync27(file2)) {
59021
+ existing = readFileSync26(file2, "utf8");
58818
59022
  const beginIdx = existing.indexOf(BEGIN);
58819
59023
  const endIdx = existing.indexOf(END);
58820
59024
  if (beginIdx >= 0 && endIdx > beginIdx) {
@@ -58843,7 +59047,7 @@ ${END}
58843
59047
  const final = existing.length > 0 && !existing.endsWith("\n") ? `${existing}
58844
59048
 
58845
59049
  ${block}` : existing + (existing.endsWith("\n\n") ? "" : "\n") + block;
58846
- writeFileSync20(file2, final, "utf8");
59050
+ writeFileSync21(file2, final, "utf8");
58847
59051
  console.log(`installed Codex hooks \u2192 ${file2}`);
58848
59052
  console.log(` endpoint: http://127.0.0.1:${port}/api/hook`);
58849
59053
  console.log("");
@@ -59157,7 +59361,7 @@ async function cmdDash(args2) {
59157
59361
  await yieldToLoop2();
59158
59362
  try {
59159
59363
  const items = selectDurableMemory(handle2.sharedStore, r.engine.profile);
59160
- const res = bleedRules(join28(r.root, ".claude", "rules"), items);
59364
+ const res = bleedRules(join29(r.root, ".claude", "rules"), items);
59161
59365
  if (res.written || res.pruned) {
59162
59366
  console.log(
59163
59367
  `[rules:${r.entry.name}] ${res.written} collective principle(s) \u2192 .claude/rules` + (res.pruned ? `, ${res.pruned} pruned` : "")