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

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 {
16977
+ }
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 {
16939
17004
  }
16940
- const verdict = isValidEdge(fromLabel, edge2.type, toLabel);
16941
- return verdict.ok ? null : verdict.reason ?? "edge rule violation";
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,
@@ -21643,7 +21740,6 @@ var init_oauth = __esm({
21643
21740
 
21644
21741
  // ../../packages/cloud-client/src/client.ts
21645
21742
  import { randomUUID } from "node:crypto";
21646
- import { gzipSync } from "node:zlib";
21647
21743
  function wirePerContext(value) {
21648
21744
  if (!value || typeof value !== "object" || Array.isArray(value)) return null;
21649
21745
  const out2 = {};
@@ -21863,7 +21959,7 @@ function provenanceHeaders(provenance) {
21863
21959
  ...provenance.agentModel ? { "x-inerrata-agent-model": provenance.agentModel } : {}
21864
21960
  };
21865
21961
  }
21866
- var asWireCount, INGEST_NODE_CHUNK, COMPRESS_MIN_BYTES, CloudClient, CloudError;
21962
+ var asWireCount, INGEST_NODE_CHUNK, CloudClient, CloudError;
21867
21963
  var init_client = __esm({
21868
21964
  "../../packages/cloud-client/src/client.ts"() {
21869
21965
  "use strict";
@@ -21871,7 +21967,6 @@ var init_client = __esm({
21871
21967
  init_src();
21872
21968
  asWireCount = (n) => typeof n === "number" && Number.isFinite(n) && n >= 0 ? Math.floor(n) : null;
21873
21969
  INGEST_NODE_CHUNK = 8;
21874
- COMPRESS_MIN_BYTES = 4096;
21875
21970
  CloudClient = class {
21876
21971
  baseUrl;
21877
21972
  apiKey;
@@ -21886,8 +21981,6 @@ var init_client = __esm({
21886
21981
  daemonVersion;
21887
21982
  daemonChannel;
21888
21983
  provenance;
21889
- /** Cleared for the process once a server proves it cannot inflate (see `json`). */
21890
- compressRequests;
21891
21984
  constructor(opts) {
21892
21985
  this.baseUrl = opts.baseUrl.replace(/\/+$/, "");
21893
21986
  if (opts.apiKey !== void 0) this.apiKey = opts.apiKey;
@@ -21901,7 +21994,6 @@ var init_client = __esm({
21901
21994
  this.timeoutMs = opts.timeoutMs ?? 15e3;
21902
21995
  this.daemonVersion = opts.daemonVersion;
21903
21996
  this.daemonChannel = opts.daemonChannel;
21904
- this.compressRequests = opts.compressRequests ?? true;
21905
21997
  this.provenance = opts.provenance ?? {
21906
21998
  clientProduct: "inerrata_cloud_client",
21907
21999
  clientKind: "sdk",
@@ -22430,43 +22522,15 @@ var init_client = __esm({
22430
22522
  const token = opts?.bearerToken ?? await this.authToken();
22431
22523
  if (token) headers["authorization"] = `Bearer ${token}`;
22432
22524
  }
22433
- let payload;
22434
- if (body2 !== void 0) {
22435
- const raw2 = JSON.stringify(body2);
22436
- if (this.compressRequests && Buffer.byteLength(raw2) >= COMPRESS_MIN_BYTES) {
22437
- payload = gzipSync(Buffer.from(raw2));
22438
- headers["content-encoding"] = "gzip";
22439
- } else {
22440
- payload = raw2;
22441
- }
22442
- }
22443
22525
  const ac = new AbortController();
22444
22526
  const tid = setTimeout(() => ac.abort(), this.timeoutMs);
22445
22527
  try {
22446
22528
  const res = await this.fetchFn(url2, {
22447
22529
  method,
22448
22530
  headers,
22449
- body: payload,
22531
+ body: body2 === void 0 ? void 0 : JSON.stringify(body2),
22450
22532
  signal: ac.signal
22451
22533
  });
22452
- if (res.status === 400 && headers["content-encoding"] === "gzip") {
22453
- delete headers["content-encoding"];
22454
- const retry = await this.fetchFn(url2, {
22455
- method,
22456
- headers,
22457
- body: JSON.stringify(body2),
22458
- signal: ac.signal
22459
- });
22460
- if (!retry.ok) {
22461
- const text = await retry.text();
22462
- throw new CloudError(
22463
- `${method} ${path2} failed: HTTP ${retry.status} ${text.slice(0, 200)}`,
22464
- retry.status
22465
- );
22466
- }
22467
- this.compressRequests = false;
22468
- return await retry.json();
22469
- }
22470
22534
  if (!res.ok) {
22471
22535
  const text = await res.text();
22472
22536
  throw new CloudError(
@@ -47311,12 +47375,12 @@ var init_report_render = __esm({
47311
47375
 
47312
47376
  // src/cli.ts
47313
47377
  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";
47378
+ import { closeSync as closeSync2, existsSync as existsSync26, openSync as openSync2, readFileSync as readFileSync25, renameSync as renameSync4, statSync as statSync6 } from "node:fs";
47379
+ import { join as join29 } from "node:path";
47316
47380
  import { spawn as spawn3 } from "node:child_process";
47317
47381
 
47318
47382
  // src/daemon.ts
47319
- import { existsSync as existsSync20, writeFileSync as writeFileSync17 } from "node:fs";
47383
+ import { existsSync as existsSync21, writeFileSync as writeFileSync18 } from "node:fs";
47320
47384
 
47321
47385
  // ../../node_modules/.pnpm/@hono+node-server@1.19.11_hono@4.12.8/node_modules/@hono/node-server/dist/index.mjs
47322
47386
  import { createServer as createServerHTTP } from "http";
@@ -47896,8 +47960,8 @@ init_config();
47896
47960
 
47897
47961
  // src/engine.ts
47898
47962
  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";
47963
+ 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";
47964
+ import { join as join25, relative as relative6, sep as sep4 } from "node:path";
47901
47965
 
47902
47966
  // ../../node_modules/.pnpm/chokidar@4.0.3/node_modules/chokidar/esm/index.js
47903
47967
  import { stat as statcb } from "fs";
@@ -50341,6 +50405,10 @@ function tagEdgeCorroborated(targetAnchorIds, sessionTouchedNodeIds, independent
50341
50405
  for (const a of targetAnchorIds) if (sessionTouchedNodeIds.has(a)) return true;
50342
50406
  return false;
50343
50407
  }
50408
+ function citeEdgeType(targetLabel2) {
50409
+ const t = typePriorEdge("Problem", targetLabel2);
50410
+ return t === "SUPERSEDES" ? "RELATES_TO" : t;
50411
+ }
50344
50412
  function typePriorEdge(sourceLabel, targetLabel2, sentence = "") {
50345
50413
  const direct = LABEL_PAIR[`${sourceLabel}>${targetLabel2}`];
50346
50414
  if (direct) return direct;
@@ -50887,6 +50955,90 @@ function backfillConstraintKind(store, opts) {
50887
50955
  return report;
50888
50956
  }
50889
50957
 
50958
+ // src/edge-repair.ts
50959
+ init_src();
50960
+ init_src4();
50961
+ import { existsSync as existsSync14, readFileSync as readFileSync12, writeFileSync as writeFileSync12 } from "node:fs";
50962
+ import { join as join17 } from "node:path";
50963
+ function citeEdgeId(from, type, to) {
50964
+ return `edge_${digest({ from, type, to })}`.slice(0, 24);
50965
+ }
50966
+ var EDGE_REPAIR_VERSION = 1;
50967
+ var REJECTION_RETENTION_MS = 30 * 24 * 60 * 60 * 1e3;
50968
+ var EMPTY2 = {
50969
+ skipped: true,
50970
+ scanned: 0,
50971
+ invalid: 0,
50972
+ retyped: 0,
50973
+ closed: 0,
50974
+ byType: {}
50975
+ };
50976
+ function markerPath2(configDir) {
50977
+ return join17(configDir, "edge-repair.json");
50978
+ }
50979
+ function alreadyDone2(configDir) {
50980
+ const p = markerPath2(configDir);
50981
+ if (!existsSync14(p)) return false;
50982
+ try {
50983
+ return JSON.parse(readFileSync12(p, "utf8"))?.version === EDGE_REPAIR_VERSION;
50984
+ } catch {
50985
+ return false;
50986
+ }
50987
+ }
50988
+ function repairInvalidEdges(store, opts) {
50989
+ if (!opts.force && !opts.dryRun && alreadyDone2(opts.configDir)) return EMPTY2;
50990
+ const report = {
50991
+ skipped: false,
50992
+ scanned: 0,
50993
+ invalid: 0,
50994
+ retyped: 0,
50995
+ closed: 0,
50996
+ byType: {}
50997
+ };
50998
+ const work = [];
50999
+ for (const e of store.scanLiveEdgeRows()) {
51000
+ report.scanned++;
51001
+ if (!localEdgeViolation(e.fromLabel, e.type, e.toLabel)) continue;
51002
+ report.invalid++;
51003
+ const candidate = e.toLabel ? citeEdgeType(e.toLabel) : null;
51004
+ const retype = candidate && candidate !== e.type && !localEdgeViolation(e.fromLabel, candidate, e.toLabel) ? candidate : null;
51005
+ work.push({ edge: { id: e.id, from: e.from, to: e.to, type: e.type }, retype });
51006
+ report.byType[e.type] = (report.byType[e.type] ?? 0) + 1;
51007
+ if (retype) report.retyped++;
51008
+ else report.closed++;
51009
+ }
51010
+ if (opts.dryRun) return report;
51011
+ store.transaction(() => {
51012
+ for (const w of work) {
51013
+ const prior = store.getEdge(w.edge.id);
51014
+ store.closeEdge(w.edge.id, opts.now);
51015
+ if (!w.retype || !prior) continue;
51016
+ store.mergeEdge({
51017
+ ...prior,
51018
+ id: citeEdgeId(w.edge.from, w.retype, w.edge.to),
51019
+ type: w.retype,
51020
+ validFrom: opts.now,
51021
+ validTo: null,
51022
+ lastSeenAt: opts.now,
51023
+ // Mark the provenance of the rewrite so a later audit can tell a repaired
51024
+ // edge from one captured natively — without which this sweep would be
51025
+ // indistinguishable from the agent having witnessed it post-fix.
51026
+ attrs: { ...prior.attrs ?? {}, retypedFrom: w.edge.type, retypedBy: `edge-repair:v${EDGE_REPAIR_VERSION}` }
51027
+ });
51028
+ }
51029
+ });
51030
+ store.pruneEdgeRejections(opts.now - REJECTION_RETENTION_MS);
51031
+ try {
51032
+ writeFileSync12(
51033
+ markerPath2(opts.configDir),
51034
+ JSON.stringify({ version: EDGE_REPAIR_VERSION, at: opts.now, ...report }, null, 2),
51035
+ "utf8"
51036
+ );
51037
+ } catch {
51038
+ }
51039
+ return report;
51040
+ }
51041
+
50890
51042
  // src/engine.ts
50891
51043
  init_symbol_summaries();
50892
51044
  init_reconcile();
@@ -51085,11 +51237,11 @@ init_outbox();
51085
51237
  init_src8();
51086
51238
  init_src();
51087
51239
  init_src2();
51088
- import { readFileSync as readFileSync12 } from "node:fs";
51089
- import { join as join17 } from "node:path";
51240
+ import { readFileSync as readFileSync13 } from "node:fs";
51241
+ import { join as join18 } from "node:path";
51090
51242
  function loadClaimIgnorePatterns(workspaceRoot) {
51091
51243
  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());
51244
+ 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
51245
  } catch {
51094
51246
  return [];
51095
51247
  }
@@ -51450,22 +51602,22 @@ async function pullCloudTriage(shared, cloud, profile, limit = 50) {
51450
51602
  }
51451
51603
 
51452
51604
  // 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";
51605
+ import { existsSync as existsSync15, readFileSync as readFileSync14, watch as fsWatch } from "node:fs";
51606
+ import { join as join19 } from "node:path";
51455
51607
  function readFirstLine(path2) {
51456
51608
  try {
51457
- return readFileSync13(path2, "utf8").split(/\r?\n/, 1)[0].trim();
51609
+ return readFileSync14(path2, "utf8").split(/\r?\n/, 1)[0].trim();
51458
51610
  } catch {
51459
51611
  return null;
51460
51612
  }
51461
51613
  }
51462
51614
  function readGitRefState(gitDir) {
51463
- const head2 = readFirstLine(join18(gitDir, "HEAD"));
51615
+ const head2 = readFirstLine(join19(gitDir, "HEAD"));
51464
51616
  const m = head2 ? /^ref:\s*refs\/heads\/(.+)$/.exec(head2) : null;
51465
51617
  const branch = m ? m[1] : null;
51466
51618
  let sha2 = null;
51467
51619
  if (branch) {
51468
- sha2 = readFirstLine(join18(gitDir, "refs", "heads", branch));
51620
+ sha2 = readFirstLine(join19(gitDir, "refs", "heads", branch));
51469
51621
  if (!sha2) sha2 = shaFromPackedRefs(gitDir, `refs/heads/${branch}`);
51470
51622
  } else if (head2 && /^[0-9a-f]{7,40}$/i.test(head2)) {
51471
51623
  sha2 = head2;
@@ -51473,13 +51625,13 @@ function readGitRefState(gitDir) {
51473
51625
  return {
51474
51626
  branch,
51475
51627
  sha: sha2,
51476
- mergeHeadExists: existsSync14(join18(gitDir, "MERGE_HEAD")),
51477
- origHeadExists: existsSync14(join18(gitDir, "ORIG_HEAD"))
51628
+ mergeHeadExists: existsSync15(join19(gitDir, "MERGE_HEAD")),
51629
+ origHeadExists: existsSync15(join19(gitDir, "ORIG_HEAD"))
51478
51630
  };
51479
51631
  }
51480
51632
  function shaFromPackedRefs(gitDir, ref) {
51481
51633
  try {
51482
- for (const line of readFileSync13(join18(gitDir, "packed-refs"), "utf8").split(/\r?\n/)) {
51634
+ for (const line of readFileSync14(join19(gitDir, "packed-refs"), "utf8").split(/\r?\n/)) {
51483
51635
  const [sha2, name2] = line.split(/\s+/);
51484
51636
  if (name2 === ref && sha2) return sha2;
51485
51637
  }
@@ -51513,7 +51665,7 @@ function startGitSensor(gitDir, onEvent, opts = {}) {
51513
51665
  const settle = () => {
51514
51666
  if (timer) clearTimeout(timer);
51515
51667
  timer = setTimeout(() => {
51516
- if (existsSync14(join18(gitDir, "index.lock"))) {
51668
+ if (existsSync15(join19(gitDir, "index.lock"))) {
51517
51669
  settle();
51518
51670
  return;
51519
51671
  }
@@ -51524,7 +51676,7 @@ function startGitSensor(gitDir, onEvent, opts = {}) {
51524
51676
  }, debounceMs);
51525
51677
  };
51526
51678
  for (const sub of ["HEAD", "logs/HEAD", "MERGE_HEAD", "ORIG_HEAD"]) {
51527
- const p = join18(gitDir, sub);
51679
+ const p = join19(gitDir, sub);
51528
51680
  try {
51529
51681
  watchers.push(fsWatch(p, settle));
51530
51682
  } catch {
@@ -51749,21 +51901,21 @@ var TelemetryRecorder = class {
51749
51901
 
51750
51902
  // src/skills.ts
51751
51903
  import {
51752
- existsSync as existsSync15,
51904
+ existsSync as existsSync16,
51753
51905
  mkdirSync as mkdirSync6,
51754
- readFileSync as readFileSync14,
51906
+ readFileSync as readFileSync15,
51755
51907
  readdirSync as readdirSync7,
51756
51908
  unlinkSync as unlinkSync2,
51757
- writeFileSync as writeFileSync12
51909
+ writeFileSync as writeFileSync13
51758
51910
  } from "node:fs";
51759
- import { basename as basename4, join as join19 } from "node:path";
51911
+ import { basename as basename4, join as join20 } from "node:path";
51760
51912
  function skillFileName(id) {
51761
51913
  return `${id.replace(/[^A-Za-z0-9_.-]/g, "_")}.md`;
51762
51914
  }
51763
51915
  function readSkillManifest(manifestPath) {
51764
- if (!existsSync15(manifestPath)) return [];
51916
+ if (!existsSync16(manifestPath)) return [];
51765
51917
  try {
51766
- const parsed = JSON.parse(readFileSync14(manifestPath, "utf8"));
51918
+ const parsed = JSON.parse(readFileSync15(manifestPath, "utf8"));
51767
51919
  return (parsed.skills ?? []).map((s) => ({
51768
51920
  title: s.title ?? "",
51769
51921
  layer: s.layer ?? "technique",
@@ -51787,7 +51939,7 @@ async function syncSkills(paths, client, seed, pins = [], techSeed) {
51787
51939
  for (const s of res.skills) {
51788
51940
  const fileName = skillFileName(s.id);
51789
51941
  keep.add(fileName);
51790
- writeFileSync12(join19(paths.skillsDir, fileName), s.markdown, "utf8");
51942
+ writeFileSync13(join20(paths.skillsDir, fileName), s.markdown, "utf8");
51791
51943
  rows.push({
51792
51944
  id: s.id,
51793
51945
  title: s.title,
@@ -51800,7 +51952,7 @@ async function syncSkills(paths, client, seed, pins = [], techSeed) {
51800
51952
  const fileName = skillFileName(p.id);
51801
51953
  if (keep.has(fileName)) continue;
51802
51954
  keep.add(fileName);
51803
- writeFileSync12(join19(paths.skillsDir, fileName), p.markdown, "utf8");
51955
+ writeFileSync13(join20(paths.skillsDir, fileName), p.markdown, "utf8");
51804
51956
  rows.push({
51805
51957
  id: p.id,
51806
51958
  title: p.title,
@@ -51814,13 +51966,13 @@ async function syncSkills(paths, client, seed, pins = [], techSeed) {
51814
51966
  if (!f.endsWith(".md")) continue;
51815
51967
  if (keep.has(basename4(f))) continue;
51816
51968
  try {
51817
- unlinkSync2(join19(paths.skillsDir, f));
51969
+ unlinkSync2(join20(paths.skillsDir, f));
51818
51970
  pruned++;
51819
51971
  } catch {
51820
51972
  }
51821
51973
  }
51822
51974
  rows.sort((a, b) => a.id.localeCompare(b.id));
51823
- writeFileSync12(
51975
+ writeFileSync13(
51824
51976
  paths.skillsManifest,
51825
51977
  JSON.stringify({ generatedAt: Date.now(), skills: rows }, null, 2),
51826
51978
  "utf8"
@@ -51832,22 +51984,22 @@ async function syncSkills(paths, client, seed, pins = [], techSeed) {
51832
51984
  init_src2();
51833
51985
  import {
51834
51986
  cpSync,
51835
- existsSync as existsSync16,
51987
+ existsSync as existsSync17,
51836
51988
  lstatSync,
51837
51989
  mkdirSync as mkdirSync7,
51838
- readFileSync as readFileSync15,
51990
+ readFileSync as readFileSync16,
51839
51991
  readdirSync as readdirSync8,
51840
51992
  rmSync as rmSync2,
51841
51993
  symlinkSync,
51842
- writeFileSync as writeFileSync13
51994
+ writeFileSync as writeFileSync14
51843
51995
  } from "node:fs";
51844
- import { join as join20 } from "node:path";
51996
+ import { join as join21 } from "node:path";
51845
51997
  var SKILL_NS = "errata-";
51846
51998
  var HARNESS_SKILL_DIRS = [
51847
- { configDir: ".claude", skillsDir: join20(".claude", "skills") },
51999
+ { configDir: ".claude", skillsDir: join21(".claude", "skills") },
51848
52000
  // Cursor adopted the standard; its exact project dir is still moving — kept
51849
52001
  // best-effort and gated on `.cursor/` presence so we never create it blind.
51850
- { configDir: ".cursor", skillsDir: join20(".cursor", "skills") }
52002
+ { configDir: ".cursor", skillsDir: join21(".cursor", "skills") }
51851
52003
  ];
51852
52004
  function skillSlug(title, id) {
51853
52005
  const base = title.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || id.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "skill";
@@ -51892,12 +52044,12 @@ function skillCiteHandle(s) {
51892
52044
  return priorHandle({ id: s.id, description: s.title });
51893
52045
  }
51894
52046
  function reconcileNamespaced(dir, keep) {
51895
- if (!existsSync16(dir)) return 0;
52047
+ if (!existsSync17(dir)) return 0;
51896
52048
  let pruned = 0;
51897
52049
  for (const name2 of readdirSync8(dir)) {
51898
52050
  if (!name2.startsWith(SKILL_NS) || keep.has(name2)) continue;
51899
52051
  try {
51900
- rmSync2(join20(dir, name2), { recursive: true, force: true });
52052
+ rmSync2(join21(dir, name2), { recursive: true, force: true });
51901
52053
  pruned++;
51902
52054
  } catch {
51903
52055
  }
@@ -51906,7 +52058,7 @@ function reconcileNamespaced(dir, keep) {
51906
52058
  }
51907
52059
  function linkOrCopy(linkPath, target) {
51908
52060
  try {
51909
- if (existsSync16(linkPath) || safeLstat(linkPath)) rmSync2(linkPath, { recursive: true, force: true });
52061
+ if (existsSync17(linkPath) || safeLstat(linkPath)) rmSync2(linkPath, { recursive: true, force: true });
51910
52062
  } catch {
51911
52063
  }
51912
52064
  try {
@@ -51927,7 +52079,7 @@ function safeLstat(p) {
51927
52079
  }
51928
52080
  }
51929
52081
  function emitAndProjectSkills(root, skills) {
51930
- const agentsSkillsDir = join20(root, ".agents", "skills");
52082
+ const agentsSkillsDir = join21(root, ".agents", "skills");
51931
52083
  mkdirSync7(agentsSkillsDir, { recursive: true });
51932
52084
  const slugs = [];
51933
52085
  const keep = /* @__PURE__ */ new Set();
@@ -51935,7 +52087,7 @@ function emitAndProjectSkills(root, skills) {
51935
52087
  for (const s of skills) {
51936
52088
  let body2;
51937
52089
  try {
51938
- body2 = readFileSync15(s.bodyPath, "utf8");
52090
+ body2 = readFileSync16(s.bodyPath, "utf8");
51939
52091
  } catch {
51940
52092
  continue;
51941
52093
  }
@@ -51944,9 +52096,9 @@ function emitAndProjectSkills(root, skills) {
51944
52096
  keep.add(slug2);
51945
52097
  slugs.push(slug2);
51946
52098
  const description = deriveDescription(s.title, s.layer, body2);
51947
- mkdirSync7(join20(agentsSkillsDir, slug2), { recursive: true });
51948
- writeFileSync13(
51949
- join20(agentsSkillsDir, slug2, "SKILL.md"),
52099
+ mkdirSync7(join21(agentsSkillsDir, slug2), { recursive: true });
52100
+ writeFileSync14(
52101
+ join21(agentsSkillsDir, slug2, "SKILL.md"),
51950
52102
  renderSkillMd(slug2, description, body2, skillCiteHandle(s)),
51951
52103
  "utf8"
51952
52104
  );
@@ -51955,11 +52107,11 @@ function emitAndProjectSkills(root, skills) {
51955
52107
  reconcileNamespaced(agentsSkillsDir, keep);
51956
52108
  let projected = 0;
51957
52109
  for (const h of HARNESS_SKILL_DIRS) {
51958
- if (!existsSync16(join20(root, h.configDir))) continue;
51959
- const dir = join20(root, h.skillsDir);
52110
+ if (!existsSync17(join21(root, h.configDir))) continue;
52111
+ const dir = join21(root, h.skillsDir);
51960
52112
  mkdirSync7(dir, { recursive: true });
51961
52113
  for (const slug2 of slugs) {
51962
- linkOrCopy(join20(dir, slug2), join20(agentsSkillsDir, slug2));
52114
+ linkOrCopy(join21(dir, slug2), join21(agentsSkillsDir, slug2));
51963
52115
  projected++;
51964
52116
  }
51965
52117
  reconcileNamespaced(dir, keep);
@@ -51968,15 +52120,15 @@ function emitAndProjectSkills(root, skills) {
51968
52120
  return { slugs, emitted, projected };
51969
52121
  }
51970
52122
  function emitInputsFromManifest(erretaDir, manifestPath) {
51971
- if (!existsSync16(manifestPath)) return [];
52123
+ if (!existsSync17(manifestPath)) return [];
51972
52124
  try {
51973
- const parsed = JSON.parse(readFileSync15(manifestPath, "utf8"));
52125
+ const parsed = JSON.parse(readFileSync16(manifestPath, "utf8"));
51974
52126
  return (parsed.skills ?? []).filter((s) => Boolean(s.id && s.file)).map((s) => ({
51975
52127
  id: s.id,
51976
52128
  title: s.title ?? s.id,
51977
52129
  layer: s.layer ?? "technique",
51978
52130
  confidence: s.confidence ?? 0,
51979
- bodyPath: join20(erretaDir, s.file)
52131
+ bodyPath: join21(erretaDir, s.file)
51980
52132
  }));
51981
52133
  } catch {
51982
52134
  return [];
@@ -51990,17 +52142,17 @@ var GITIGNORE_LINES = [
51990
52142
  ".cursor/skills/errata-*/"
51991
52143
  ];
51992
52144
  function ensureSkillGitignore(root) {
51993
- const path2 = join20(root, ".gitignore");
52145
+ const path2 = join21(root, ".gitignore");
51994
52146
  let current = "";
51995
52147
  try {
51996
- current = existsSync16(path2) ? readFileSync15(path2, "utf8") : "";
52148
+ current = existsSync17(path2) ? readFileSync16(path2, "utf8") : "";
51997
52149
  } catch {
51998
52150
  return;
51999
52151
  }
52000
52152
  if (current.includes(GITIGNORE_MARK)) return;
52001
52153
  const prefix = current.length > 0 && !current.endsWith("\n") ? "\n" : "";
52002
52154
  try {
52003
- writeFileSync13(path2, `${current}${prefix}
52155
+ writeFileSync14(path2, `${current}${prefix}
52004
52156
  ${GITIGNORE_LINES.join("\n")}
52005
52157
  `, "utf8");
52006
52158
  } catch {
@@ -52061,20 +52213,20 @@ init_paths();
52061
52213
  // src/profile.ts
52062
52214
  init_src2();
52063
52215
  init_paths();
52064
- import { existsSync as existsSync18, readFileSync as readFileSync17, writeFileSync as writeFileSync14 } from "node:fs";
52216
+ import { existsSync as existsSync19, readFileSync as readFileSync18, writeFileSync as writeFileSync15 } from "node:fs";
52065
52217
  import { createHash as createHash12 } from "node:crypto";
52066
- import { join as join22 } from "node:path";
52218
+ import { join as join23 } from "node:path";
52067
52219
 
52068
52220
  // src/git-remote.ts
52069
52221
  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";
52222
+ import { existsSync as existsSync18, readFileSync as readFileSync17, statSync as statSync4 } from "node:fs";
52223
+ import { isAbsolute as isAbsolute3, join as join22, resolve as resolve5 } from "node:path";
52072
52224
  function resolveGitDir(root) {
52073
- const dotGit = join21(root, ".git");
52225
+ const dotGit = join22(root, ".git");
52074
52226
  try {
52075
52227
  const st = statSync4(dotGit);
52076
52228
  if (st.isDirectory()) return dotGit;
52077
- const m = /^gitdir:\s*(.+?)\s*$/m.exec(readFileSync16(dotGit, "utf8"));
52229
+ const m = /^gitdir:\s*(.+?)\s*$/m.exec(readFileSync17(dotGit, "utf8"));
52078
52230
  if (!m) return null;
52079
52231
  const dir = m[1];
52080
52232
  return isAbsolute3(dir) ? dir : resolve5(root, dir);
@@ -52083,22 +52235,22 @@ function resolveGitDir(root) {
52083
52235
  }
52084
52236
  }
52085
52237
  function gitConfigPath(gitDir) {
52086
- const commondirFile = join21(gitDir, "commondir");
52087
- if (existsSync17(commondirFile)) {
52088
- const common = readFileSync16(commondirFile, "utf8").trim();
52238
+ const commondirFile = join22(gitDir, "commondir");
52239
+ if (existsSync18(commondirFile)) {
52240
+ const common = readFileSync17(commondirFile, "utf8").trim();
52089
52241
  const commonDir = isAbsolute3(common) ? common : resolve5(gitDir, common);
52090
- return join21(commonDir, "config");
52242
+ return join22(commonDir, "config");
52091
52243
  }
52092
- return join21(gitDir, "config");
52244
+ return join22(gitDir, "config");
52093
52245
  }
52094
52246
  function readRemotes(root) {
52095
52247
  const gitDir = resolveGitDir(root);
52096
52248
  if (!gitDir) return [];
52097
52249
  const cfgPath = gitConfigPath(gitDir);
52098
- if (!existsSync17(cfgPath)) return [];
52250
+ if (!existsSync18(cfgPath)) return [];
52099
52251
  let txt;
52100
52252
  try {
52101
- txt = readFileSync16(cfgPath, "utf8");
52253
+ txt = readFileSync17(cfgPath, "utf8");
52102
52254
  } catch {
52103
52255
  return [];
52104
52256
  }
@@ -52134,13 +52286,13 @@ function refreshRepoLocator(root, profile) {
52134
52286
  }
52135
52287
  function loadProfile(root) {
52136
52288
  const p = workspacePaths(root);
52137
- if (!existsSync18(p.workspaceJson)) return null;
52138
- return JSON.parse(readFileSync17(p.workspaceJson, "utf8"));
52289
+ if (!existsSync19(p.workspaceJson)) return null;
52290
+ return JSON.parse(readFileSync18(p.workspaceJson, "utf8"));
52139
52291
  }
52140
52292
  function saveProfile(root, profile) {
52141
52293
  const p = workspacePaths(root);
52142
52294
  ensureDir(p.configDir);
52143
- writeFileSync14(p.workspaceJson, JSON.stringify(profile, null, 2), "utf8");
52295
+ writeFileSync15(p.workspaceJson, JSON.stringify(profile, null, 2), "utf8");
52144
52296
  }
52145
52297
  function autodetectProfile(root) {
52146
52298
  const id = workspaceId(root);
@@ -52148,10 +52300,10 @@ function autodetectProfile(root) {
52148
52300
  const p = emptyProfile(id, name2);
52149
52301
  const locator = detectRepoLocator(root);
52150
52302
  if (locator) p.repoLocator = locator;
52151
- const pkgPath = join22(root, "package.json");
52152
- if (existsSync18(pkgPath)) {
52303
+ const pkgPath = join23(root, "package.json");
52304
+ if (existsSync19(pkgPath)) {
52153
52305
  try {
52154
- const pkg = JSON.parse(readFileSync17(pkgPath, "utf8"));
52306
+ const pkg = JSON.parse(readFileSync18(pkgPath, "utf8"));
52155
52307
  p.languages.push("typescript", "javascript");
52156
52308
  const nodeVer = pkg.engines?.node ?? "node";
52157
52309
  p.stack.push(`node@${nodeVer}`);
@@ -52172,10 +52324,10 @@ function autodetectProfile(root) {
52172
52324
  } catch {
52173
52325
  }
52174
52326
  }
52175
- const pyproject = join22(root, "pyproject.toml");
52176
- if (existsSync18(pyproject)) {
52327
+ const pyproject = join23(root, "pyproject.toml");
52328
+ if (existsSync19(pyproject)) {
52177
52329
  try {
52178
- const txt = readFileSync17(pyproject, "utf8");
52330
+ const txt = readFileSync18(pyproject, "utf8");
52179
52331
  const py = /python\s*=\s*"([^"]+)"/.exec(txt)?.[1];
52180
52332
  p.languages.push("python");
52181
52333
  p.stack.push(`python@${py ?? "3"}`);
@@ -52186,16 +52338,16 @@ function autodetectProfile(root) {
52186
52338
  } catch {
52187
52339
  }
52188
52340
  }
52189
- const reqs = join22(root, "requirements.txt");
52190
- if (existsSync18(reqs)) {
52341
+ const reqs = join23(root, "requirements.txt");
52342
+ if (existsSync19(reqs)) {
52191
52343
  if (!p.languages.includes("python")) p.languages.push("python");
52192
52344
  if (!p.stack.includes("python@3")) p.stack.push("python@3");
52193
52345
  }
52194
- if (existsSync18(join22(root, "go.mod"))) {
52346
+ if (existsSync19(join23(root, "go.mod"))) {
52195
52347
  p.languages.push("go");
52196
52348
  p.stack.push("go");
52197
52349
  }
52198
- if (existsSync18(join22(root, "Cargo.toml"))) {
52350
+ if (existsSync19(join23(root, "Cargo.toml"))) {
52199
52351
  p.languages.push("rust");
52200
52352
  p.stack.push("rust");
52201
52353
  }
@@ -52205,17 +52357,17 @@ function autodetectProfile(root) {
52205
52357
  }
52206
52358
 
52207
52359
  // 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";
52360
+ import { readFileSync as readFileSync19, renameSync as renameSync2, writeFileSync as writeFileSync16 } from "node:fs";
52361
+ import { dirname as dirname9, join as join24 } from "node:path";
52210
52362
  var WITNESS_QUEUE_CAP = 500;
52211
52363
  var WITNESS_TTL_MS = 14 * 24 * 60 * 60 * 1e3;
52212
52364
  var WITNESS_MAX_ATTEMPTS = 5;
52213
52365
  function witnessQueuePath(workspaceConfigDir) {
52214
- return join23(workspaceConfigDir, "witness-queue.json");
52366
+ return join24(workspaceConfigDir, "witness-queue.json");
52215
52367
  }
52216
52368
  function loadWitnessQueue(path2) {
52217
52369
  try {
52218
- const raw2 = JSON.parse(readFileSync18(path2, "utf8"));
52370
+ const raw2 = JSON.parse(readFileSync19(path2, "utf8"));
52219
52371
  if (!Array.isArray(raw2)) return [];
52220
52372
  return raw2.filter(
52221
52373
  (w) => !!w && typeof w === "object" && typeof w.nodeId === "string" && typeof w.witnessKey === "string"
@@ -52226,8 +52378,8 @@ function loadWitnessQueue(path2) {
52226
52378
  }
52227
52379
  function saveWitnessQueue(path2, queue) {
52228
52380
  try {
52229
- const tmp = join23(dirname9(path2), `.${Date.now()}.witness-queue.tmp`);
52230
- writeFileSync15(tmp, JSON.stringify(queue), "utf8");
52381
+ const tmp = join24(dirname9(path2), `.${Date.now()}.witness-queue.tmp`);
52382
+ writeFileSync16(tmp, JSON.stringify(queue), "utf8");
52231
52383
  renameSync2(tmp, path2);
52232
52384
  } catch {
52233
52385
  }
@@ -52507,7 +52659,7 @@ function startLoopLagMonitor(thresholdMs = 1e3) {
52507
52659
  }
52508
52660
 
52509
52661
  // src/engine.ts
52510
- var DAEMON_VERSION = true ? "2.0.2-dev.245" : "2.0.0-alpha.0";
52662
+ var DAEMON_VERSION = true ? "2.0.2-dev.249" : "2.0.0-alpha.0";
52511
52663
  var IGNORED_PATH = /[\\/](?:\.git|node_modules|\.errata|\.claude|\.codex|\.cursor|\.turbo|\.next|dist|coverage|test-results|playwright-report|__pycache__)(?:[\\/]|$)/;
52512
52664
  var IGNORED_NOISE = /castalia\.db|eventlog\.sqlite|turn-cursors/;
52513
52665
  var GIT_OP_MUTE_MS = 4e3;
@@ -52517,7 +52669,7 @@ var TURN_REPLAY_LOOKBACK_MS = 7 * 24 * 60 * 6e4;
52517
52669
  function appendIdentityAudit(path2, record2, line) {
52518
52670
  if (!record2.accepted && record2.score <= 0) return;
52519
52671
  try {
52520
- if (existsSync19(path2) && statSync5(path2).size >= IDENTITY_AUDIT_MAX_BYTES) {
52672
+ if (existsSync20(path2) && statSync5(path2).size >= IDENTITY_AUDIT_MAX_BYTES) {
52521
52673
  renameSync3(path2, `${path2}.1`);
52522
52674
  }
52523
52675
  appendFileSync2(path2, line);
@@ -52527,7 +52679,7 @@ function appendIdentityAudit(path2, record2, line) {
52527
52679
  var yieldToLoop = () => new Promise((r) => setImmediate(r));
52528
52680
  function loadTurnCursors(path2) {
52529
52681
  try {
52530
- const raw2 = JSON.parse(readFileSync19(path2, "utf8"));
52682
+ const raw2 = JSON.parse(readFileSync20(path2, "utf8"));
52531
52683
  return new Map(
52532
52684
  Object.entries(raw2).map(([k, v]) => [k, typeof v === "string" ? v : String(v?.uuid ?? "")])
52533
52685
  );
@@ -52537,7 +52689,7 @@ function loadTurnCursors(path2) {
52537
52689
  }
52538
52690
  function loadTurnOffsets(path2) {
52539
52691
  try {
52540
- const raw2 = JSON.parse(readFileSync19(path2, "utf8"));
52692
+ const raw2 = JSON.parse(readFileSync20(path2, "utf8"));
52541
52693
  const out2 = /* @__PURE__ */ new Map();
52542
52694
  for (const [k, v] of Object.entries(raw2)) {
52543
52695
  const off = typeof v === "object" && v !== null ? v.offset : void 0;
@@ -52553,7 +52705,7 @@ function saveTurnCursors(path2, cursors, offsets) {
52553
52705
  const merged = {};
52554
52706
  for (const [k, uuid3] of cursors) merged[k] = { uuid: uuid3, offset: offsets.get(k) ?? 0 };
52555
52707
  for (const [k, offset] of offsets) if (!merged[k]) merged[k] = { uuid: "", offset };
52556
- writeFileSync16(path2, JSON.stringify(merged), "utf8");
52708
+ writeFileSync17(path2, JSON.stringify(merged), "utf8");
52557
52709
  } catch {
52558
52710
  }
52559
52711
  }
@@ -52575,7 +52727,7 @@ function gitSourceWatchTargets(root) {
52575
52727
  ["-C", root, "ls-files", "--others", "--ignored", "--exclude-standard", "--directory", "-z"],
52576
52728
  { encoding: "utf8", maxBuffer: 256 * 1024 * 1024, windowsHide: true, stdio: ["ignore", "pipe", "ignore"] }
52577
52729
  );
52578
- ignoredDirs = igOut.split("\0").filter(Boolean).map((d) => d.replace(/\/+$/, "")).filter((d) => !IGNORED_PATH.test(join24(root, d) + sep4));
52730
+ ignoredDirs = igOut.split("\0").filter(Boolean).map((d) => d.replace(/\/+$/, "")).filter((d) => !IGNORED_PATH.test(join25(root, d) + sep4));
52579
52731
  } catch {
52580
52732
  }
52581
52733
  const hasIgnoredChild = (dir) => ignoredDirs.some((ig) => ig.startsWith(dir + "/"));
@@ -52587,19 +52739,19 @@ function gitSourceWatchTargets(root) {
52587
52739
  if (!f.startsWith(prefix)) continue;
52588
52740
  const rest2 = f.slice(prefix.length);
52589
52741
  if (rest2.includes("/")) children.add(dir === "" ? rest2.slice(0, rest2.indexOf("/")) : dir + "/" + rest2.slice(0, rest2.indexOf("/")));
52590
- else targets.add(join24(root, f));
52742
+ else targets.add(join25(root, f));
52591
52743
  }
52592
52744
  for (const c of children) {
52593
- if (IGNORED_PATH.test(join24(root, c) + sep4)) continue;
52745
+ if (IGNORED_PATH.test(join25(root, c) + sep4)) continue;
52594
52746
  if (hasIgnoredChild(c)) addUnder(c);
52595
- else targets.add(join24(root, c));
52747
+ else targets.add(join25(root, c));
52596
52748
  }
52597
52749
  };
52598
52750
  addUnder("");
52599
52751
  if (targets.size > 0) return [...targets];
52600
52752
  } catch {
52601
52753
  }
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)));
52754
+ 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
52755
  }
52604
52756
  function createWorkspaceEngine(opts) {
52605
52757
  const paths = workspacePaths(opts.workspaceRoot);
@@ -52757,7 +52909,7 @@ function createWorkspaceEngine(opts) {
52757
52909
  const srcPaths = diff.changedPaths.filter((p) => /\.(ts|tsx|js|jsx|mjs|cjs|py)$/i.test(p));
52758
52910
  let episodeId2;
52759
52911
  if (srcPaths.length > 0) {
52760
- const abs = srcPaths.map((p) => join24(opts.workspaceRoot, p));
52912
+ const abs = srcPaths.map((p) => join25(opts.workspaceRoot, p));
52761
52913
  try {
52762
52914
  const r = await runReindexPass(
52763
52915
  `git-reindex:${profile.name} (${abs.length} files)`,
@@ -52793,8 +52945,8 @@ function createWorkspaceEngine(opts) {
52793
52945
  `[errata] git: ${ev.kind} ${ev.newSha.slice(0, 7)} by ${meta3.authorName} \u2014 ${diff.changedPaths.length} file(s), ${diff.renames.length} rename(s)`
52794
52946
  );
52795
52947
  };
52796
- const gitDir = join24(opts.workspaceRoot, ".git");
52797
- if (existsSync19(gitDir)) {
52948
+ const gitDir = join25(opts.workspaceRoot, ".git");
52949
+ if (existsSync20(gitDir)) {
52798
52950
  stopGit = startGitSensor(gitDir, (ev) => {
52799
52951
  void handleGitEvent(ev).catch((err2) => {
52800
52952
  console.warn("[errata] git event handler failed:", err2);
@@ -52864,10 +53016,10 @@ function createWorkspaceEngine(opts) {
52864
53016
  });
52865
53017
  doneRender?.();
52866
53018
  writeContextFile(opts.workspaceRoot, body2);
52867
- const target = join24(opts.workspaceRoot, "AGENTS.md");
53019
+ const target = join25(opts.workspaceRoot, "AGENTS.md");
52868
53020
  writeManagedBlock(target, { body: AGENTS_POINTER_BODY, stable: true, force: true });
52869
53021
  if (elicit) {
52870
- writePrimingHandles(join24(paths.configDir, "priming-handles.json"), [
53022
+ writePrimingHandles(join25(paths.configDir, "priming-handles.json"), [
52871
53023
  ...snapshot.recentProblems.map((r) => r.node),
52872
53024
  // Resolved-band handles: the ✓ problem AND its Solution are citable
52873
53025
  // (a fix tag on an already-resolved problem no-ops idempotently; the
@@ -52958,6 +53110,17 @@ function createWorkspaceEngine(opts) {
52958
53110
  } catch (err2) {
52959
53111
  console.warn("[errata] anchor backfill failed:", err2);
52960
53112
  }
53113
+ try {
53114
+ const r = repairInvalidEdges(store, { configDir: paths.configDir, now: Date.now() });
53115
+ if (!r.skipped && r.invalid > 0) {
53116
+ console.log(
53117
+ `[errata] edge repair: ${r.retyped} edge(s) retyped, ${r.closed} closed (${Object.entries(r.byType).map(([t, n]) => `${t}x${n}`).join(", ")})`
53118
+ );
53119
+ refreshContextNow();
53120
+ }
53121
+ } catch (err2) {
53122
+ console.warn("[errata] edge repair failed:", err2);
53123
+ }
52961
53124
  try {
52962
53125
  const c = backfillConstraintKind(store, {
52963
53126
  root: opts.workspaceRoot,
@@ -53072,7 +53235,7 @@ function createWorkspaceEngine(opts) {
53072
53235
  resultSummary: { exitCode: e.exitCode ?? 1, errorTokens: e.errorTokens }
53073
53236
  });
53074
53237
  };
53075
- const turnCursorPath = join24(paths.configDir, "turn-cursors.json");
53238
+ const turnCursorPath = join25(paths.configDir, "turn-cursors.json");
53076
53239
  const lastTurnUuid = loadTurnCursors(turnCursorPath);
53077
53240
  const turnOffset = loadTurnOffsets(turnCursorPath);
53078
53241
  const sessionLastProblem = /* @__PURE__ */ new Map();
@@ -53096,7 +53259,7 @@ function createWorkspaceEngine(opts) {
53096
53259
  const t = Date.now();
53097
53260
  let processedTurns = 0;
53098
53261
  const elicit = isEdgeElicitationEnabled();
53099
- const handleMap = elicit ? readPrimingHandles(join24(paths.configDir, "priming-handles.json")) : {};
53262
+ const handleMap = elicit ? readPrimingHandles(join25(paths.configDir, "priming-handles.json")) : {};
53100
53263
  const wsRoot = (opts.workspaceRoot ?? "").replace(/\\/g, "/");
53101
53264
  const toRel = (abs) => {
53102
53265
  const p = abs.replace(/\\/g, "/");
@@ -53405,9 +53568,7 @@ function createWorkspaceEngine(opts) {
53405
53568
  if (targetId === pid) continue;
53406
53569
  const target = store.getNode(targetId);
53407
53570
  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 });
53571
+ mintCiteEdge(pid, targetId, citeEdgeType(target.label), inst.evidence === "witnessed" ? 0.4 : 0.3, { instanceCite: true, evidence: inst.evidence });
53411
53572
  }
53412
53573
  }
53413
53574
  for (const tf of plan.transfers) {
@@ -53707,7 +53868,7 @@ function createWorkspaceEngine(opts) {
53707
53868
  try {
53708
53869
  const inputs = emitInputsFromManifest(paths.configDir, paths.skillsManifest);
53709
53870
  emitAndProjectSkills(opts.workspaceRoot, inputs);
53710
- writePrimingHandles(join24(paths.configDir, "priming-handles.json"), skillHandleNodes(inputs));
53871
+ writePrimingHandles(join25(paths.configDir, "priming-handles.json"), skillHandleNodes(inputs));
53711
53872
  } catch (err2) {
53712
53873
  console.warn("[skills] agent-skills projection failed (non-fatal):", err2 instanceof Error ? err2.message : err2);
53713
53874
  }
@@ -53894,7 +54055,7 @@ function createWorkspaceEngine(opts) {
53894
54055
  console.log(
53895
54056
  "[errata] sync skipped \u2014 cloud sync consent is off (enable with `errata consent sync on`)"
53896
54057
  );
53897
- const pending = existsSync19(paths.outbox) ? readdirSync9(paths.outbox).filter((f) => f.endsWith(".json")).length : 0;
54058
+ const pending = existsSync20(paths.outbox) ? readdirSync9(paths.outbox).filter((f) => f.endsWith(".json")).length : 0;
53898
54059
  return { uploaded: 0, failed: 0, remaining: pending };
53899
54060
  }
53900
54061
  try {
@@ -53981,7 +54142,7 @@ async function startDaemon(opts) {
53981
54142
  reviewUrl: () => webUiUrl + "/review"
53982
54143
  });
53983
54144
  const writeLockFile = (url2) => {
53984
- writeFileSync17(
54145
+ writeFileSync18(
53985
54146
  engine.paths.daemonLock,
53986
54147
  JSON.stringify({ pid: process.pid, webUiUrl: url2, startedAt: Date.now() }),
53987
54148
  "utf8"
@@ -54024,7 +54185,7 @@ async function startDaemon(opts) {
54024
54185
  );
54025
54186
  await engine.stop();
54026
54187
  try {
54027
- if (existsSync20(engine.paths.daemonLock)) {
54188
+ if (existsSync21(engine.paths.daemonLock)) {
54028
54189
  }
54029
54190
  } catch {
54030
54191
  }
@@ -54041,16 +54202,16 @@ async function listenServer(fetchFn, port) {
54041
54202
 
54042
54203
  // src/registry.ts
54043
54204
  init_paths();
54044
- import { existsSync as existsSync21, readFileSync as readFileSync20, writeFileSync as writeFileSync18 } from "node:fs";
54045
- import { join as join25 } from "node:path";
54205
+ import { existsSync as existsSync22, readFileSync as readFileSync21, writeFileSync as writeFileSync19 } from "node:fs";
54206
+ import { join as join26 } from "node:path";
54046
54207
  function registryPath() {
54047
- return process.env["ERRATA_REGISTRY_PATH"] ?? join25(globalDir(), "workspaces.json");
54208
+ return process.env["ERRATA_REGISTRY_PATH"] ?? join26(globalDir(), "workspaces.json");
54048
54209
  }
54049
54210
  function read() {
54050
54211
  const p = registryPath();
54051
- if (!existsSync21(p)) return { version: 1, workspaces: {} };
54212
+ if (!existsSync22(p)) return { version: 1, workspaces: {} };
54052
54213
  try {
54053
- const parsed = JSON.parse(readFileSync20(p, "utf8"));
54214
+ const parsed = JSON.parse(readFileSync21(p, "utf8"));
54054
54215
  return { version: 1, workspaces: parsed.workspaces ?? {} };
54055
54216
  } catch {
54056
54217
  return { version: 1, workspaces: {} };
@@ -54058,7 +54219,7 @@ function read() {
54058
54219
  }
54059
54220
  function write(reg) {
54060
54221
  ensureDir(globalDir());
54061
- writeFileSync18(registryPath(), JSON.stringify(reg, null, 2), "utf8");
54222
+ writeFileSync19(registryPath(), JSON.stringify(reg, null, 2), "utf8");
54062
54223
  }
54063
54224
  function registerWorkspace(profile, root, now = Date.now()) {
54064
54225
  const reg = read();
@@ -54075,7 +54236,7 @@ function pruneMissingWorkspaces() {
54075
54236
  const reg = read();
54076
54237
  const removed = [];
54077
54238
  for (const [id, entry] of Object.entries(reg.workspaces)) {
54078
- if (!existsSync21(entry.path)) {
54239
+ if (!existsSync22(entry.path)) {
54079
54240
  removed.push(entry);
54080
54241
  delete reg.workspaces[id];
54081
54242
  }
@@ -54084,13 +54245,13 @@ function pruneMissingWorkspaces() {
54084
54245
  return removed;
54085
54246
  }
54086
54247
  function workspaceStatus(entry) {
54087
- const missing = !existsSync21(entry.path);
54248
+ const missing = !existsSync22(entry.path);
54088
54249
  const lockPath = workspacePaths(entry.path).daemonLock;
54089
54250
  let running = false;
54090
54251
  let webUiUrl = null;
54091
- if (existsSync21(lockPath)) {
54252
+ if (existsSync22(lockPath)) {
54092
54253
  try {
54093
- const lock = JSON.parse(readFileSync20(lockPath, "utf8"));
54254
+ const lock = JSON.parse(readFileSync21(lockPath, "utf8"));
54094
54255
  if (lock.pid && lock.webUiUrl && pidAlive(lock.pid)) {
54095
54256
  running = true;
54096
54257
  webUiUrl = lock.webUiUrl;
@@ -54118,7 +54279,7 @@ function pidAlive(pid) {
54118
54279
  // src/multi.ts
54119
54280
  init_dist();
54120
54281
  init_src4();
54121
- import { readFileSync as readFileSync23, unlinkSync as unlinkSync3, writeFileSync as writeFileSync19 } from "node:fs";
54282
+ import { readFileSync as readFileSync24, unlinkSync as unlinkSync3, writeFileSync as writeFileSync20 } from "node:fs";
54122
54283
 
54123
54284
  // src/principle-sync.ts
54124
54285
  init_src4();
@@ -54146,8 +54307,8 @@ init_reconcile();
54146
54307
 
54147
54308
  // src/lockfile-auto.ts
54148
54309
  init_src();
54149
- import { existsSync as existsSync22, readFileSync as readFileSync21 } from "node:fs";
54150
- import { join as join26 } from "node:path";
54310
+ import { existsSync as existsSync23, readFileSync as readFileSync22 } from "node:fs";
54311
+ import { join as join27 } from "node:path";
54151
54312
 
54152
54313
  // src/package-index.ts
54153
54314
  init_src();
@@ -54296,11 +54457,11 @@ function runLockfilePass(opts) {
54296
54457
  { file: "package-lock.json", parse: parsePackageLockJson }
54297
54458
  ];
54298
54459
  for (const c of candidates) {
54299
- const p = join26(opts.root, c.file);
54300
- if (!existsSync22(p)) continue;
54460
+ const p = join27(opts.root, c.file);
54461
+ if (!existsSync23(p)) continue;
54301
54462
  let sbom;
54302
54463
  try {
54303
- sbom = c.parse(readFileSync21(p, "utf8"));
54464
+ sbom = c.parse(readFileSync22(p, "utf8"));
54304
54465
  } catch {
54305
54466
  continue;
54306
54467
  }
@@ -54748,7 +54909,7 @@ var ConsolidateWorker = class {
54748
54909
  init_paths();
54749
54910
 
54750
54911
  // src/lock.ts
54751
- import { existsSync as existsSync23, readFileSync as readFileSync22 } from "node:fs";
54912
+ import { existsSync as existsSync24, readFileSync as readFileSync23 } from "node:fs";
54752
54913
  function isProcessAlive(pid) {
54753
54914
  if (!pid || pid <= 0) return false;
54754
54915
  try {
@@ -54759,9 +54920,9 @@ function isProcessAlive(pid) {
54759
54920
  }
54760
54921
  }
54761
54922
  function readDaemonLock(lockPath) {
54762
- if (!existsSync23(lockPath)) return null;
54923
+ if (!existsSync24(lockPath)) return null;
54763
54924
  try {
54764
- const lock = JSON.parse(readFileSync22(lockPath, "utf8"));
54925
+ const lock = JSON.parse(readFileSync23(lockPath, "utf8"));
54765
54926
  return typeof lock.pid === "number" ? lock : null;
54766
54927
  } catch {
54767
54928
  return null;
@@ -55040,12 +55201,12 @@ async function reanchorProject(opts) {
55040
55201
  }
55041
55202
 
55042
55203
  // src/adopt.ts
55043
- import { existsSync as existsSync24 } from "node:fs";
55044
- import { dirname as dirname10, join as join27 } from "node:path";
55204
+ import { existsSync as existsSync25 } from "node:fs";
55205
+ import { dirname as dirname10, join as join28 } from "node:path";
55045
55206
  function findGitRoot(absPath) {
55046
55207
  let dir = absPath;
55047
55208
  for (let depth = 0; depth < 64; depth++) {
55048
- if (existsSync24(join27(dir, ".git"))) return dir;
55209
+ if (existsSync25(join28(dir, ".git"))) return dir;
55049
55210
  const parent = dirname10(dir);
55050
55211
  if (parent === dir) return null;
55051
55212
  dir = parent;
@@ -55294,7 +55455,7 @@ async function startMultiDaemon(opts = {}) {
55294
55455
  void ambientLinkAll();
55295
55456
  app.route(`/ws/${rec.id}`, rec.webApp);
55296
55457
  try {
55297
- writeFileSync19(
55458
+ writeFileSync20(
55298
55459
  rec.engine.paths.daemonLock,
55299
55460
  JSON.stringify({ pid: process.pid, webUiUrl: `${baseUrl}/ws/${rec.id}`, startedAt: Date.now() }),
55300
55461
  "utf8"
@@ -55483,7 +55644,7 @@ async function startMultiDaemon(opts = {}) {
55483
55644
  baseUrl = `http://127.0.0.1:${port}`;
55484
55645
  try {
55485
55646
  ensureDir(globalDir());
55486
- writeFileSync19(
55647
+ writeFileSync20(
55487
55648
  lockPath,
55488
55649
  JSON.stringify({ pid: process.pid, webUiUrl: baseUrl, startedAt: Date.now() }),
55489
55650
  "utf8"
@@ -55492,7 +55653,7 @@ async function startMultiDaemon(opts = {}) {
55492
55653
  }
55493
55654
  for (const r of records) {
55494
55655
  try {
55495
- writeFileSync19(
55656
+ writeFileSync20(
55496
55657
  r.engine.paths.daemonLock,
55497
55658
  JSON.stringify({ pid: process.pid, webUiUrl: `${baseUrl}/ws/${r.id}`, startedAt: Date.now() }),
55498
55659
  "utf8"
@@ -55990,7 +56151,7 @@ async function startMultiDaemon(opts = {}) {
55990
56151
  },
55991
56152
  async stop() {
55992
56153
  try {
55993
- const cur = readFileSync23(lockPath, "utf8");
56154
+ const cur = readFileSync24(lockPath, "utf8");
55994
56155
  if (JSON.parse(cur).pid === process.pid) unlinkSync3(lockPath);
55995
56156
  } catch {
55996
56157
  }
@@ -57007,21 +57168,21 @@ async function cmdInit() {
57007
57168
  if (!skipHooks) {
57008
57169
  console.log("");
57009
57170
  console.log("installing harness hooks...");
57010
- const { existsSync: existsSync26 } = await import("node:fs");
57011
- const { join: join29 } = await import("node:path");
57171
+ const { existsSync: existsSync27 } = await import("node:fs");
57172
+ const { join: join30 } = await import("node:path");
57012
57173
  try {
57013
57174
  await installClaudeHooks(port);
57014
57175
  } catch (err2) {
57015
57176
  console.warn(` \u26A0\uFE0F Claude hook install failed: ${err2 instanceof Error ? err2.message : err2}`);
57016
57177
  }
57017
- if (existsSync26(join29(ROOT, ".cursor"))) {
57178
+ if (existsSync27(join30(ROOT, ".cursor"))) {
57018
57179
  try {
57019
57180
  await installCursorMcpConfig();
57020
57181
  } catch (err2) {
57021
57182
  console.warn(` \u26A0\uFE0F Cursor MCP config failed: ${err2 instanceof Error ? err2.message : err2}`);
57022
57183
  }
57023
57184
  }
57024
- if (existsSync26(join29(ROOT, ".codex"))) {
57185
+ if (existsSync27(join30(ROOT, ".codex"))) {
57025
57186
  try {
57026
57187
  await installCodexHooks(port);
57027
57188
  } catch (err2) {
@@ -57178,9 +57339,9 @@ async function cmdStatus() {
57178
57339
  console.log(` stack: ${profile.stack.join(", ") || "(none)"}`);
57179
57340
  console.log(` languages: ${profile.languages.join(", ") || "(none)"}`);
57180
57341
  }
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)) {
57342
+ console.log(` graph db: ${existsSync26(paths.castalia) ? "yes" : "no"} (${paths.castalia})`);
57343
+ console.log(` event log: ${existsSync26(paths.eventLog) ? "yes" : "no"} (${paths.eventLog})`);
57344
+ if (existsSync26(paths.castalia)) {
57184
57345
  try {
57185
57346
  const { openGraphStore: openGraphStore2 } = await Promise.resolve().then(() => (init_src4(), src_exports2));
57186
57347
  const store = openGraphStore2({ path: paths.castalia });
@@ -57196,6 +57357,16 @@ async function cmdStatus() {
57196
57357
  }
57197
57358
  }
57198
57359
  console.log(` contribute: ${pending} pending of ${total} instance node(s)`);
57360
+ const rejections = store.edgeRejections();
57361
+ if (rejections.length > 0) {
57362
+ const refused = rejections.reduce((n, r) => n + r.count, 0);
57363
+ console.log(` edges: ${refused} refused by the ontology gate \u2014 a producer is emitting invalid edges`);
57364
+ for (const r of rejections.slice(0, 3)) {
57365
+ const mins = Math.max(0, Math.round((Date.now() - r.lastAt) / 6e4));
57366
+ const age = mins < 60 ? `${mins}m ago` : mins < 1440 ? `${Math.round(mins / 60)}h ago` : `${Math.round(mins / 1440)}d ago`;
57367
+ console.log(` ${r.count}x ${r.type} (last ${age})${r.sample ? ` \u2014 ${r.sample}` : ""}`);
57368
+ }
57369
+ }
57199
57370
  } finally {
57200
57371
  store.close();
57201
57372
  }
@@ -57844,11 +58015,11 @@ function cmdInstallationProfile(args2) {
57844
58015
  }
57845
58016
  async function cmdReview() {
57846
58017
  const paths = workspacePaths(ROOT);
57847
- if (!existsSync25(paths.reviewQueue)) {
58018
+ if (!existsSync26(paths.reviewQueue)) {
57848
58019
  console.log("(review queue empty)");
57849
58020
  return;
57850
58021
  }
57851
- const queue = JSON.parse(readFileSync24(paths.reviewQueue, "utf8"));
58022
+ const queue = JSON.parse(readFileSync25(paths.reviewQueue, "utf8"));
57852
58023
  if (queue.length === 0) {
57853
58024
  console.log("(review queue empty)");
57854
58025
  return;
@@ -58519,7 +58690,7 @@ async function gatherRepo(store, ws) {
58519
58690
  };
58520
58691
  }
58521
58692
  async function gatherReportData(generatedAt) {
58522
- const { existsSync: existsSync26 } = await import("node:fs");
58693
+ const { existsSync: existsSync27 } = await import("node:fs");
58523
58694
  const { openGraphStore: openGraphStore2 } = await Promise.resolve().then(() => (init_src4(), src_exports2));
58524
58695
  const cfg = loadConfig();
58525
58696
  const outbound = cfg.consent.sync ? "auto" : "off";
@@ -58527,7 +58698,7 @@ async function gatherReportData(generatedAt) {
58527
58698
  for (const ws of listWorkspaces()) {
58528
58699
  if (ws.missing) continue;
58529
58700
  const dbPath = workspacePaths(ws.path).castalia;
58530
- if (!existsSync26(dbPath)) continue;
58701
+ if (!existsSync27(dbPath)) continue;
58531
58702
  let store = null;
58532
58703
  try {
58533
58704
  store = openGraphStore2({ path: dbPath });
@@ -58558,7 +58729,7 @@ async function gatherReportData(generatedAt) {
58558
58729
  };
58559
58730
  }
58560
58731
  async function cmdReport(args2) {
58561
- const { mkdirSync: mkdirSync8, writeFileSync: writeFileSync20 } = await import("node:fs");
58732
+ const { mkdirSync: mkdirSync8, writeFileSync: writeFileSync21 } = await import("node:fs");
58562
58733
  const { renderReport: renderReport2 } = await Promise.resolve().then(() => (init_report_render(), report_render_exports));
58563
58734
  const includeFutureVerbs = args2.includes("--future-verbs");
58564
58735
  const now = /* @__PURE__ */ new Date();
@@ -58571,8 +58742,8 @@ async function cmdReport(args2) {
58571
58742
  const outDir = workspacePaths(ROOT).configDir;
58572
58743
  mkdirSync8(outDir, { recursive: true });
58573
58744
  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");
58745
+ for (const f of files) writeFileSync21(join29(outDir, f.name), f.html, "utf8");
58746
+ const indexPath = join29(outDir, "report.html");
58576
58747
  console.log(`report \u2192 ${indexPath}`);
58577
58748
  console.log(
58578
58749
  ` ${data.repos.length} repo(s) \xB7 ${files.length} file(s) \xB7 ${data.rollup.nodes.toLocaleString("en-US")} nodes`
@@ -58690,15 +58861,15 @@ function hookRelayCommand(port, path2) {
58690
58861
  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
58862
  }
58692
58863
  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");
58864
+ const { mkdirSync: mkdirSync8, existsSync: existsSync27, readFileSync: readFileSync26, writeFileSync: writeFileSync21 } = await import("node:fs");
58865
+ const { join: join30 } = await import("node:path");
58866
+ const dir = join30(ROOT, ".claude");
58867
+ if (!existsSync27(dir)) mkdirSync8(dir, { recursive: true });
58868
+ const file2 = join30(dir, "settings.json");
58698
58869
  let settings = {};
58699
- if (existsSync26(file2)) {
58870
+ if (existsSync27(file2)) {
58700
58871
  try {
58701
- settings = JSON.parse(readFileSync25(file2, "utf8"));
58872
+ settings = JSON.parse(readFileSync26(file2, "utf8"));
58702
58873
  } catch {
58703
58874
  console.error(`refusing to overwrite invalid JSON at ${file2}`);
58704
58875
  process.exit(2);
@@ -58744,10 +58915,10 @@ async function installClaudeHooks(port) {
58744
58915
  dropErrata(list);
58745
58916
  list.push({ hooks: [{ type: "command", command: injectCmd }] });
58746
58917
  }
58747
- writeFileSync20(file2, JSON.stringify(settings, null, 2) + "\n", "utf8");
58918
+ writeFileSync21(file2, JSON.stringify(settings, null, 2) + "\n", "utf8");
58748
58919
  console.log(`installed Claude Code hooks \u2192 ${file2}`);
58749
58920
  await installClaudeMcpConfig();
58750
- const claudeMd = join29(ROOT, "CLAUDE.md");
58921
+ const claudeMd = join30(ROOT, "CLAUDE.md");
58751
58922
  const recall = writeManagedBlock(claudeMd, { body: RECALL_FIRST_BLOCK });
58752
58923
  if (recall.kind === "collision") {
58753
58924
  console.warn(
@@ -58759,15 +58930,15 @@ async function installClaudeHooks(port) {
58759
58930
  console.log(` endpoint: http://127.0.0.1:${port}/api/hook`);
58760
58931
  }
58761
58932
  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");
58933
+ const { mkdirSync: mkdirSync8, existsSync: existsSync27, readFileSync: readFileSync26, writeFileSync: writeFileSync21 } = await import("node:fs");
58934
+ const { join: join30, dirname: dirname11 } = await import("node:path");
58935
+ const file2 = join30(ROOT, ".mcp.json");
58765
58936
  const dir = dirname11(file2);
58766
- if (!existsSync26(dir)) mkdirSync8(dir, { recursive: true });
58937
+ if (!existsSync27(dir)) mkdirSync8(dir, { recursive: true });
58767
58938
  let cfg = {};
58768
- if (existsSync26(file2)) {
58939
+ if (existsSync27(file2)) {
58769
58940
  try {
58770
- cfg = JSON.parse(readFileSync25(file2, "utf8"));
58941
+ cfg = JSON.parse(readFileSync26(file2, "utf8"));
58771
58942
  } catch {
58772
58943
  console.error(`refusing to overwrite invalid JSON at ${file2}`);
58773
58944
  process.exit(2);
@@ -58775,21 +58946,21 @@ async function installClaudeMcpConfig() {
58775
58946
  }
58776
58947
  cfg.mcpServers ??= {};
58777
58948
  cfg.mcpServers["errata"] = errataMcpInvocation();
58778
- writeFileSync20(file2, JSON.stringify(cfg, null, 2) + "\n", "utf8");
58949
+ writeFileSync21(file2, JSON.stringify(cfg, null, 2) + "\n", "utf8");
58779
58950
  console.log(`installed Claude Code MCP server config \u2192 ${file2}`);
58780
58951
  console.log(` Claude Code will spawn \`errata mcp\` on workspace open.`);
58781
58952
  console.log(` Tools: errata.search / locate / neighbors / callers_of / what_uses / show / similar`);
58782
58953
  }
58783
58954
  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");
58955
+ const { mkdirSync: mkdirSync8, existsSync: existsSync27, readFileSync: readFileSync26, writeFileSync: writeFileSync21 } = await import("node:fs");
58956
+ const { join: join30 } = await import("node:path");
58957
+ const dir = join30(ROOT, ".cursor");
58958
+ if (!existsSync27(dir)) mkdirSync8(dir, { recursive: true });
58959
+ const file2 = join30(dir, "mcp.json");
58789
58960
  let cfg = {};
58790
- if (existsSync26(file2)) {
58961
+ if (existsSync27(file2)) {
58791
58962
  try {
58792
- cfg = JSON.parse(readFileSync25(file2, "utf8"));
58963
+ cfg = JSON.parse(readFileSync26(file2, "utf8"));
58793
58964
  } catch {
58794
58965
  console.error(`refusing to overwrite invalid JSON at ${file2}`);
58795
58966
  process.exit(2);
@@ -58797,7 +58968,7 @@ async function installCursorMcpConfig() {
58797
58968
  }
58798
58969
  cfg.mcpServers ??= {};
58799
58970
  cfg.mcpServers["errata"] = errataMcpInvocation();
58800
- writeFileSync20(file2, JSON.stringify(cfg, null, 2) + "\n", "utf8");
58971
+ writeFileSync21(file2, JSON.stringify(cfg, null, 2) + "\n", "utf8");
58801
58972
  console.log(`installed Cursor MCP server config \u2192 ${file2}`);
58802
58973
  console.log(` Cursor will spawn \`errata mcp\` on workspace open.`);
58803
58974
  console.log(` Tools: errata.search / locate / neighbors / callers_of / what_uses`);
@@ -58805,16 +58976,16 @@ async function installCursorMcpConfig() {
58805
58976
  console.log(` \u26A0\uFE0F reload Cursor (Cmd/Ctrl-Shift-P \u2192 "Reload Window") to pick it up.`);
58806
58977
  }
58807
58978
  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");
58979
+ const { mkdirSync: mkdirSync8, existsSync: existsSync27, readFileSync: readFileSync26, writeFileSync: writeFileSync21 } = await import("node:fs");
58980
+ const { join: join30 } = await import("node:path");
58981
+ const dir = join30(ROOT, ".codex");
58982
+ if (!existsSync27(dir)) mkdirSync8(dir, { recursive: true });
58983
+ const file2 = join30(dir, "config.toml");
58813
58984
  const BEGIN = `# >>> errata hooks (errata-managed)`;
58814
58985
  const END = `# <<< errata hooks`;
58815
58986
  let existing = "";
58816
- if (existsSync26(file2)) {
58817
- existing = readFileSync25(file2, "utf8");
58987
+ if (existsSync27(file2)) {
58988
+ existing = readFileSync26(file2, "utf8");
58818
58989
  const beginIdx = existing.indexOf(BEGIN);
58819
58990
  const endIdx = existing.indexOf(END);
58820
58991
  if (beginIdx >= 0 && endIdx > beginIdx) {
@@ -58843,7 +59014,7 @@ ${END}
58843
59014
  const final = existing.length > 0 && !existing.endsWith("\n") ? `${existing}
58844
59015
 
58845
59016
  ${block}` : existing + (existing.endsWith("\n\n") ? "" : "\n") + block;
58846
- writeFileSync20(file2, final, "utf8");
59017
+ writeFileSync21(file2, final, "utf8");
58847
59018
  console.log(`installed Codex hooks \u2192 ${file2}`);
58848
59019
  console.log(` endpoint: http://127.0.0.1:${port}/api/hook`);
58849
59020
  console.log("");
@@ -59157,7 +59328,7 @@ async function cmdDash(args2) {
59157
59328
  await yieldToLoop2();
59158
59329
  try {
59159
59330
  const items = selectDurableMemory(handle2.sharedStore, r.engine.profile);
59160
- const res = bleedRules(join28(r.root, ".claude", "rules"), items);
59331
+ const res = bleedRules(join29(r.root, ".claude", "rules"), items);
59161
59332
  if (res.written || res.pruned) {
59162
59333
  console.log(
59163
59334
  `[rules:${r.entry.name}] ${res.written} collective principle(s) \u2192 .claude/rules` + (res.pruned ? `, ${res.pruned} pruned` : "")