@inerrata-corporation/errata 2.0.2-dev.793 → 2.0.2-dev.831

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.
Files changed (2) hide show
  1. package/errata.mjs +809 -616
  2. package/package.json +1 -1
package/errata.mjs CHANGED
@@ -27989,36 +27989,428 @@ var init_src9 = __esm({
27989
27989
  }
27990
27990
  });
27991
27991
 
27992
+ // src/derive-summary.ts
27993
+ function inflect(verb) {
27994
+ if (/(?:s|x|ch|sh|z)$/.test(verb)) return `${verb}es`;
27995
+ if (/[^aeiou]y$/.test(verb)) return `${verb.slice(0, -1)}ies`;
27996
+ return `${verb}s`;
27997
+ }
27998
+ function deinflect(word) {
27999
+ if (word.endsWith("ies") && VERBS.has(`${word.slice(0, -3)}y`)) return `${word.slice(0, -3)}y`;
28000
+ if (word.endsWith("es") && VERBS.has(word.slice(0, -2))) return word.slice(0, -2);
28001
+ if (word.endsWith("s") && VERBS.has(word.slice(0, -1))) return word.slice(0, -1);
28002
+ return null;
28003
+ }
28004
+ function verbHead(word) {
28005
+ const w = word.toLowerCase().replace(/[^a-z]/g, "");
28006
+ if (!w) return null;
28007
+ if (VERBS.has(w)) return inflect(w);
28008
+ return deinflect(w) !== null ? w : null;
28009
+ }
28010
+ function identifierWords(name2) {
28011
+ return name2.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1 $2").replace(/[_$]+/g, " ").toLowerCase().split(/\s+/).filter(Boolean);
28012
+ }
28013
+ function clipClause(text) {
28014
+ let t = tidy(text.split(/\s+[—–-]\s+|[:;(]|,|\s+(?:and|or|plus)\s+|\s\+\s/)[0] ?? "");
28015
+ if (t.length > MAX_PAYLOAD_CHARS) {
28016
+ const cut = t.slice(0, MAX_PAYLOAD_CHARS).lastIndexOf(" ");
28017
+ if (cut <= 20) return null;
28018
+ t = tidy(t.slice(0, cut));
28019
+ }
28020
+ const words = t.split(/\s+/);
28021
+ while (words.length > 0 && DANGLING.has(words[words.length - 1].toLowerCase().replace(/[^a-z]/g, ""))) {
28022
+ words.pop();
28023
+ }
28024
+ const out2 = tidy(words.join(" "));
28025
+ return out2.length >= 12 && out2.split(/\s+/).length >= 2 ? out2 : null;
28026
+ }
28027
+ function firstSentence(doc) {
28028
+ const clean = doc.replace(/^[\s*/]+/gm, " ").replace(/\s+/g, " ").trim();
28029
+ const m = clean.match(/^(.{10,400}?[.!?])(\s|$)/);
28030
+ return (m ? m[1] : clean).slice(0, 280);
28031
+ }
28032
+ function stripUnshippable(sentence) {
28033
+ return sentence.replace(/`[^`]*`|"[^"]*"|'[^']{2,}'/g, " ").replace(/[\w.~-]+[/\\][\w.$~-]+/g, " ").replace(/\([^)]*\)/g, " ");
28034
+ }
28035
+ function summaryFromDoc(doc, kind) {
28036
+ const clipped = clipClause(stripUnshippable(firstSentence(doc)).replace(/^[^A-Za-z]+/, ""));
28037
+ if (clipped === null) return null;
28038
+ const words = clipped.split(/\s+/);
28039
+ const verb = verbHead(words[0]);
28040
+ if (verb !== null && words.length > 1) {
28041
+ return tidy(`${lead(kind)} that ${verb} ${words.slice(1).join(" ")}`);
28042
+ }
28043
+ if (verb !== null) return null;
28044
+ const noun = clipped.replace(/^(?:the|a|an)\s+/i, "");
28045
+ return tidy(`${lead(kind)} for ${noun.charAt(0).toLowerCase()}${noun.slice(1)}`);
28046
+ }
28047
+ function summaryFromName(name2, kind) {
28048
+ if (!NAME_DERIVED_ENABLED) return null;
28049
+ const words = identifierWords(name2);
28050
+ while (words.length > 1 && DANGLING.has(words[words.length - 1])) words.pop();
28051
+ if (words.length === 0) return null;
28052
+ const verb = VERB_PHRASE_KINDS.has(kind) ? verbHead(words[0]) : null;
28053
+ const rest2 = words.slice(1).join(" ");
28054
+ const phrase = verb !== null && rest2 ? `${lead(kind)} that ${verb} the ${rest2}` : verb !== null ? null : `${lead(kind)} for the ${words.join(" ")}`;
28055
+ if (phrase === null) return null;
28056
+ const trimmed = tidy(phrase);
28057
+ return trimmed.length <= MAX_PAYLOAD_CHARS + 24 ? trimmed : null;
28058
+ }
28059
+ function summaryCandidates(name2, kind, doc) {
28060
+ const candidates = [];
28061
+ const fromDoc = doc ? summaryFromDoc(doc, kind) : null;
28062
+ if (fromDoc !== null) candidates.push(fromDoc);
28063
+ const fromName = summaryFromName(name2, kind);
28064
+ if (fromName !== null && fromName !== fromDoc) candidates.push(fromName);
28065
+ return candidates;
28066
+ }
28067
+ var NAME_DERIVED_ENABLED, KIND_ARTICLE, lead, MAX_PAYLOAD_CHARS, DANGLING, VERBS, tidy, VERB_PHRASE_KINDS;
28068
+ var init_derive_summary = __esm({
28069
+ "src/derive-summary.ts"() {
28070
+ "use strict";
28071
+ NAME_DERIVED_ENABLED = true;
28072
+ KIND_ARTICLE = {
28073
+ function: "a",
28074
+ method: "a",
28075
+ class: "a",
28076
+ interface: "an",
28077
+ constant: "a"
28078
+ };
28079
+ lead = (kind) => `${KIND_ARTICLE[kind]} ${kind}`;
28080
+ MAX_PAYLOAD_CHARS = 56;
28081
+ DANGLING = /* @__PURE__ */ new Set([
28082
+ "a",
28083
+ "an",
28084
+ "the",
28085
+ "and",
28086
+ "or",
28087
+ "but",
28088
+ "of",
28089
+ "to",
28090
+ "in",
28091
+ "on",
28092
+ "at",
28093
+ "by",
28094
+ "for",
28095
+ "from",
28096
+ "with",
28097
+ "into",
28098
+ "onto",
28099
+ "over",
28100
+ "under",
28101
+ "as",
28102
+ "that",
28103
+ "which",
28104
+ "when",
28105
+ "while",
28106
+ "if",
28107
+ "so",
28108
+ "then",
28109
+ "than",
28110
+ "its",
28111
+ "their",
28112
+ "this",
28113
+ "these",
28114
+ "those",
28115
+ "is",
28116
+ "are",
28117
+ "was",
28118
+ "be",
28119
+ "been",
28120
+ "not",
28121
+ "no",
28122
+ "per",
28123
+ "via",
28124
+ "up",
28125
+ "out",
28126
+ "off",
28127
+ "about",
28128
+ "after",
28129
+ "before",
28130
+ "during",
28131
+ "without",
28132
+ "within",
28133
+ "against",
28134
+ "between",
28135
+ "through",
28136
+ "across",
28137
+ "upon"
28138
+ ]);
28139
+ VERBS = /* @__PURE__ */ new Set([
28140
+ "accept",
28141
+ "add",
28142
+ "advance",
28143
+ "allow",
28144
+ "apply",
28145
+ "assert",
28146
+ "attach",
28147
+ "bind",
28148
+ "build",
28149
+ "bump",
28150
+ "cache",
28151
+ "call",
28152
+ "cap",
28153
+ "carry",
28154
+ "check",
28155
+ "choose",
28156
+ "clamp",
28157
+ "classify",
28158
+ "clean",
28159
+ "clear",
28160
+ "close",
28161
+ "collapse",
28162
+ "collect",
28163
+ "compare",
28164
+ "compute",
28165
+ "connect",
28166
+ "contain",
28167
+ "convert",
28168
+ "count",
28169
+ "cover",
28170
+ "create",
28171
+ "decide",
28172
+ "declare",
28173
+ "decode",
28174
+ "define",
28175
+ "delete",
28176
+ "demote",
28177
+ "derive",
28178
+ "describe",
28179
+ "detach",
28180
+ "detect",
28181
+ "determine",
28182
+ "disable",
28183
+ "drain",
28184
+ "drop",
28185
+ "emit",
28186
+ "enable",
28187
+ "encode",
28188
+ "ensure",
28189
+ "enqueue",
28190
+ "evaluate",
28191
+ "expand",
28192
+ "expose",
28193
+ "extend",
28194
+ "extract",
28195
+ "fetch",
28196
+ "fill",
28197
+ "filter",
28198
+ "find",
28199
+ "fire",
28200
+ "fix",
28201
+ "flag",
28202
+ "flatten",
28203
+ "flip",
28204
+ "flush",
28205
+ "fold",
28206
+ "format",
28207
+ "gate",
28208
+ "gather",
28209
+ "generate",
28210
+ "get",
28211
+ "give",
28212
+ "grant",
28213
+ "guard",
28214
+ "handle",
28215
+ "hash",
28216
+ "hide",
28217
+ "hold",
28218
+ "hook",
28219
+ "index",
28220
+ "infer",
28221
+ "initialize",
28222
+ "insert",
28223
+ "inspect",
28224
+ "join",
28225
+ "keep",
28226
+ "limit",
28227
+ "link",
28228
+ "list",
28229
+ "load",
28230
+ "locate",
28231
+ "log",
28232
+ "make",
28233
+ "map",
28234
+ "mark",
28235
+ "match",
28236
+ "materialize",
28237
+ "measure",
28238
+ "merge",
28239
+ "mint",
28240
+ "mount",
28241
+ "move",
28242
+ "name",
28243
+ "normalize",
28244
+ "note",
28245
+ "observe",
28246
+ "open",
28247
+ "package",
28248
+ "parse",
28249
+ "persist",
28250
+ "pick",
28251
+ "pop",
28252
+ "populate",
28253
+ "prepare",
28254
+ "produce",
28255
+ "promote",
28256
+ "prune",
28257
+ "publish",
28258
+ "pull",
28259
+ "push",
28260
+ "query",
28261
+ "queue",
28262
+ "raise",
28263
+ "rank",
28264
+ "read",
28265
+ "rebuild",
28266
+ "record",
28267
+ "recover",
28268
+ "redact",
28269
+ "reduce",
28270
+ "refresh",
28271
+ "register",
28272
+ "reject",
28273
+ "release",
28274
+ "remove",
28275
+ "rename",
28276
+ "render",
28277
+ "repair",
28278
+ "replace",
28279
+ "replay",
28280
+ "report",
28281
+ "represent",
28282
+ "require",
28283
+ "reset",
28284
+ "resolve",
28285
+ "restore",
28286
+ "retire",
28287
+ "retry",
28288
+ "return",
28289
+ "reveal",
28290
+ "revive",
28291
+ "rewrite",
28292
+ "route",
28293
+ "run",
28294
+ "sanitize",
28295
+ "save",
28296
+ "scan",
28297
+ "schedule",
28298
+ "score",
28299
+ "scrub",
28300
+ "seed",
28301
+ "select",
28302
+ "send",
28303
+ "serialize",
28304
+ "serve",
28305
+ "set",
28306
+ "show",
28307
+ "sign",
28308
+ "skip",
28309
+ "sort",
28310
+ "split",
28311
+ "stamp",
28312
+ "start",
28313
+ "stop",
28314
+ "store",
28315
+ "strip",
28316
+ "summarize",
28317
+ "supply",
28318
+ "suppress",
28319
+ "sweep",
28320
+ "switch",
28321
+ "sync",
28322
+ "tag",
28323
+ "take",
28324
+ "test",
28325
+ "throw",
28326
+ "toggle",
28327
+ "touch",
28328
+ "trace",
28329
+ "track",
28330
+ "transform",
28331
+ "translate",
28332
+ "traverse",
28333
+ "trigger",
28334
+ "trim",
28335
+ "turn",
28336
+ "unwrap",
28337
+ "update",
28338
+ "upsert",
28339
+ "validate",
28340
+ "verify",
28341
+ "walk",
28342
+ "warn",
28343
+ "watch",
28344
+ "wire",
28345
+ "wrap",
28346
+ "write",
28347
+ "yield"
28348
+ ]);
28349
+ tidy = (s) => s.replace(/\s+/g, " ").replace(/\s+([,.;:])/g, "$1").replace(/[\s,;:.]+$/, "").trim();
28350
+ VERB_PHRASE_KINDS = /* @__PURE__ */ new Set(["function", "method"]);
28351
+ }
28352
+ });
28353
+
27992
28354
  // src/generalize-graph.ts
27993
28355
  function isDistinctiveIdentifier(name2) {
27994
28356
  if (name2.length < 3) return false;
28357
+ if (/[\s:]/.test(name2)) return false;
28358
+ if (BUILTIN_TYPE_NAMES.has(name2)) return false;
27995
28359
  if (name2.includes(".") || name2.includes("_") || /\d/.test(name2)) return true;
27996
28360
  if (/[a-z][A-Z]/.test(name2)) return true;
27997
28361
  if (/^[A-Z]/.test(name2) && /[a-z]/.test(name2) && name2.length >= 4) return true;
27998
28362
  return false;
27999
28363
  }
28000
- function buildSymbolLexicon(store, summariesByBodyHash2) {
28364
+ function buildDocIndex(store) {
28365
+ const byName = /* @__PURE__ */ new Map();
28366
+ for (const c of store.findNodesByLabel("Comment")) {
28367
+ const name2 = c.attrs["attachedTo"];
28368
+ const kind = c.attrs["kind"];
28369
+ if (typeof name2 !== "string" || !name2) continue;
28370
+ if (typeof kind !== "string" || !DOC_COMMENT_KINDS.has(kind)) continue;
28371
+ const text = typeof c.attrs["text"] === "string" ? c.attrs["text"] : c.description;
28372
+ if (!text?.trim()) continue;
28373
+ if (!byName.has(name2)) byName.set(name2, text.trim().slice(0, MAX_DOC_CHARS));
28374
+ }
28375
+ return byName;
28376
+ }
28377
+ function buildSymbolLexicon(store) {
28001
28378
  const lex = /* @__PURE__ */ new Map();
28379
+ const docs = buildDocIndex(store);
28002
28380
  const candidates = [];
28003
28381
  for (const [label, kind] of SYMBOL_LABELS2) {
28004
28382
  for (const n of store.findNodesByLabel(label)) {
28005
- const bodyHash = typeof n.attrs["bodyHash"] === "string" ? n.attrs["bodyHash"] : void 0;
28006
- const summary = bodyHash ? summariesByBodyHash2?.get(bodyHash) : void 0;
28007
- for (const name2 of [n.description, String(n.attrs["qname"] ?? "")]) {
28008
- if (name2 && isDistinctiveIdentifier(name2)) {
28009
- if (!lex.has(name2)) lex.set(name2, { kind });
28010
- if (summary) candidates.push([name2, summary]);
28383
+ const qname = String(n.attrs["qname"] ?? "");
28384
+ const doc = (n.description ? docs.get(n.description) : void 0) ?? (qname ? docs.get(qname) : void 0);
28385
+ for (const name2 of [n.description, qname]) {
28386
+ if (name2 && isDistinctiveIdentifier(name2) && !lex.has(name2)) {
28387
+ lex.set(name2, { kind });
28388
+ candidates.push([name2, kind, doc]);
28011
28389
  }
28012
28390
  }
28013
28391
  }
28014
28392
  }
28015
- for (const [name2, summary] of candidates) {
28016
- if (summaryRejectionReason(summary, (tok) => lex.has(tok)) === null) {
28017
- lex.get(name2).summary = summary;
28393
+ const isKnown = (tok) => lex.has(tok);
28394
+ for (const [name2, kind, doc] of candidates) {
28395
+ for (const phrase of summaryCandidates(name2, kind, doc)) {
28396
+ if (summaryRejectionReason(phrase, isKnown) === null) {
28397
+ lex.get(name2).summary = phrase;
28398
+ break;
28399
+ }
28018
28400
  }
28019
28401
  }
28020
28402
  return lex;
28021
28403
  }
28404
+ function replaceWithPhrase(text, before, escapedKey, after, phrase) {
28405
+ if (!RE_LEADING_ARTICLE.test(phrase)) {
28406
+ return text.replace(new RegExp(`${before}${escapedKey}${after}`, "g"), phrase);
28407
+ }
28408
+ const re = new RegExp(`${before}${String.raw`(?:(An|an|A|a|The|the)\s+)?`}${escapedKey}${after}`, "g");
28409
+ return text.replace(
28410
+ re,
28411
+ (_match, article) => article !== void 0 && /^[A-Z]/.test(article) ? phrase.charAt(0).toUpperCase() + phrase.slice(1) : phrase
28412
+ );
28413
+ }
28022
28414
  function isBareMatchableStem(stem) {
28023
28415
  return stem.length >= 5 && /^[A-Za-z0-9]+(?:[-_][A-Za-z0-9]+)+$/.test(stem);
28024
28416
  }
@@ -28114,8 +28506,13 @@ function generalizeFileRefs(text, fileLexicon, level = 1) {
28114
28506
  }
28115
28507
  files.sort((a, b) => b[0].length - a[0].length);
28116
28508
  for (const [tok, entry] of files) {
28117
- const re = new RegExp(`(?<![\\w$/\\\\.-])${escapeRe4(tok)}(?![\\w$-])`, "g");
28118
- out2 = out2.replace(re, fileRolePhrase(entry.relPath, level));
28509
+ out2 = replaceWithPhrase(
28510
+ out2,
28511
+ "(?<![\\w$/\\\\.-])",
28512
+ escapeRe4(tok),
28513
+ "(?![\\w$-])",
28514
+ fileRolePhrase(entry.relPath, level)
28515
+ );
28119
28516
  }
28120
28517
  const stems = [];
28121
28518
  const seenStems = /* @__PURE__ */ new Set();
@@ -28128,8 +28525,13 @@ function generalizeFileRefs(text, fileLexicon, level = 1) {
28128
28525
  }
28129
28526
  stems.sort((a, b) => b[0].length - a[0].length);
28130
28527
  for (const [tok, entry] of stems) {
28131
- const re = new RegExp(`(?<![\\w$/\\\\.-])${escapeRe4(tok)}(?![\\w$/\\\\.-])`, "g");
28132
- out2 = out2.replace(re, fileRolePhrase(entry.relPath, level));
28528
+ out2 = replaceWithPhrase(
28529
+ out2,
28530
+ "(?<![\\w$/\\\\.-])",
28531
+ escapeRe4(tok),
28532
+ "(?![\\w$/\\\\.-])",
28533
+ fileRolePhrase(entry.relPath, level)
28534
+ );
28133
28535
  }
28134
28536
  return { text: out2, substitutions: files.length + stems.length, lexiconMisses };
28135
28537
  }
@@ -28148,17 +28550,23 @@ function generalizeSymbols(text, lexicon, level = 1, fileLexicon) {
28148
28550
  for (const key of present) {
28149
28551
  const entry = lexicon.get(key);
28150
28552
  const phrase = level === 1 && entry.summary ? entry.summary : KIND_PHRASE[entry.kind][level === 1 ? "l1" : "l2"];
28151
- const re = new RegExp(`(?<![A-Za-z0-9_$.])${escapeRe4(key)}(?![A-Za-z0-9_$])`, "g");
28152
- out2 = out2.replace(re, phrase);
28553
+ out2 = replaceWithPhrase(
28554
+ out2,
28555
+ String.raw`(?<![A-Za-z0-9_$.])`,
28556
+ escapeRe4(key),
28557
+ String.raw`(?![A-Za-z0-9_$])`,
28558
+ phrase
28559
+ );
28153
28560
  }
28154
28561
  return generalize(out2, { level }).text;
28155
28562
  }
28156
- var SYMBOL_LABELS2, KIND_PHRASE, RE_RESERVED2, escapeRe4, CONVENTION_FILENAMES, CONVENTION_BASENAME_MIN_FILES, CONVENTION_STEMS, FILE_TOKEN_RE, STEM_TOKEN_RE, SOURCE_EXTENSIONS, TOKEN_RE3;
28563
+ var SYMBOL_LABELS2, KIND_PHRASE, BUILTIN_TYPE_NAMES, DOC_COMMENT_KINDS, MAX_DOC_CHARS, RE_RESERVED2, escapeRe4, RE_LEADING_ARTICLE, CONVENTION_FILENAMES, CONVENTION_BASENAME_MIN_FILES, CONVENTION_STEMS, FILE_TOKEN_RE, STEM_TOKEN_RE, SOURCE_EXTENSIONS, TOKEN_RE3;
28157
28564
  var init_generalize_graph = __esm({
28158
28565
  "src/generalize-graph.ts"() {
28159
28566
  "use strict";
28160
28567
  init_src9();
28161
28568
  init_src();
28569
+ init_derive_summary();
28162
28570
  SYMBOL_LABELS2 = [
28163
28571
  ["Function", "function"],
28164
28572
  ["Method", "method"],
@@ -28173,8 +28581,38 @@ var init_generalize_graph = __esm({
28173
28581
  interface: { l1: "an interface", l2: "an interface" },
28174
28582
  constant: { l1: "a constant", l2: "a value" }
28175
28583
  };
28584
+ BUILTIN_TYPE_NAMES = /* @__PURE__ */ new Set([
28585
+ "Array",
28586
+ "Boolean",
28587
+ "Buffer",
28588
+ "Date",
28589
+ "Error",
28590
+ "Function",
28591
+ "Map",
28592
+ "Math",
28593
+ "Number",
28594
+ "Object",
28595
+ "Promise",
28596
+ "Proxy",
28597
+ "RegExp",
28598
+ "Set",
28599
+ "String",
28600
+ "Symbol",
28601
+ "WeakMap",
28602
+ "WeakSet",
28603
+ "TypeError",
28604
+ "RangeError",
28605
+ "SyntaxError",
28606
+ "URL",
28607
+ "Request",
28608
+ "Response",
28609
+ "Headers"
28610
+ ]);
28611
+ DOC_COMMENT_KINDS = /* @__PURE__ */ new Set(["docstring", "explanation"]);
28612
+ MAX_DOC_CHARS = 600;
28176
28613
  RE_RESERVED2 = /[.*+?^${}()|[\]\\]/g;
28177
28614
  escapeRe4 = (s) => s.replace(RE_RESERVED2, "\\$&");
28615
+ RE_LEADING_ARTICLE = /^(?:an?|the)\s/i;
28178
28616
  CONVENTION_FILENAMES = /* @__PURE__ */ new Set([
28179
28617
  "package.json",
28180
28618
  "package-lock.json",
@@ -28379,7 +28817,7 @@ async function dualAugment(opts) {
28379
28817
  let seedProvenance = "local";
28380
28818
  const calls = [];
28381
28819
  try {
28382
- const lexicon = buildSymbolLexicon(store, opts.summaries);
28820
+ const lexicon = buildSymbolLexicon(store);
28383
28821
  const hardIds = [.../* @__PURE__ */ new Set([...seedNode ? [seedNode.id] : [], ...localHits.map((h) => h.id)])].filter((nid) => {
28384
28822
  const n = seedNode && nid === seedNode.id ? seedNode : store.getNode(nid);
28385
28823
  return !!n && isHardBridge(n);
@@ -30324,281 +30762,6 @@ var init_src10 = __esm({
30324
30762
  }
30325
30763
  });
30326
30764
 
30327
- // src/llm-provider.ts
30328
- function chatProvider() {
30329
- return (process.env["EXTRACTION_PROVIDER"] ?? "anthropic").toLowerCase() === "azure" ? "azure" : "anthropic";
30330
- }
30331
- function deploymentFor(model) {
30332
- const key = `MODEL_${model.toUpperCase().replace(/[^A-Z0-9]/g, "_")}_OPENAI`;
30333
- return process.env[key] ?? process.env["AZURE_OPENAI_DEPLOYMENT"];
30334
- }
30335
- function isChatConfigured(model) {
30336
- if (chatProvider() === "azure") {
30337
- return Boolean(
30338
- process.env["AZURE_OPENAI_API_KEY"] && process.env["AZURE_OPENAI_ENDPOINT"] && deploymentFor(model)
30339
- );
30340
- }
30341
- return Boolean(process.env["ANTHROPIC_API_KEY"]);
30342
- }
30343
- async function chat(req) {
30344
- const provider = chatProvider();
30345
- try {
30346
- if (provider === "azure") {
30347
- const endpoint = (process.env["AZURE_OPENAI_ENDPOINT"] ?? "").replace(/\/+$/, "");
30348
- const version2 = process.env["AZURE_OPENAI_API_VERSION"] ?? "2024-10-21";
30349
- const deployment = deploymentFor(req.model);
30350
- if (!endpoint || !deployment) {
30351
- console.warn("[errata] llm: azure selected but endpoint/deployment missing \u2014 skipping");
30352
- return null;
30353
- }
30354
- const resp2 = await fetch(
30355
- `${endpoint}/openai/deployments/${deployment}/chat/completions?api-version=${version2}`,
30356
- {
30357
- method: "POST",
30358
- headers: {
30359
- "api-key": process.env["AZURE_OPENAI_API_KEY"] ?? "",
30360
- "content-type": "application/json"
30361
- },
30362
- body: JSON.stringify({
30363
- messages: [
30364
- ...req.system ? [{ role: "system", content: req.system }] : [],
30365
- { role: "user", content: req.user }
30366
- ],
30367
- // `max_completion_tokens`: the newer deployments reject `max_tokens`.
30368
- max_completion_tokens: req.maxTokens
30369
- })
30370
- }
30371
- );
30372
- if (!resp2.ok) {
30373
- console.warn(
30374
- `[errata] llm: azure ${resp2.status} \u2014 ${(await resp2.text().catch(() => "")).slice(0, 200)}`
30375
- );
30376
- return null;
30377
- }
30378
- const json3 = await resp2.json();
30379
- return json3.choices?.[0]?.message?.content ?? null;
30380
- }
30381
- const resp = await fetch("https://api.anthropic.com/v1/messages", {
30382
- method: "POST",
30383
- headers: {
30384
- "x-api-key": process.env["ANTHROPIC_API_KEY"] ?? "",
30385
- "anthropic-version": "2023-06-01",
30386
- "content-type": "application/json"
30387
- },
30388
- body: JSON.stringify({
30389
- model: req.model,
30390
- max_tokens: req.maxTokens,
30391
- ...req.system ? { system: req.system } : {},
30392
- messages: [{ role: "user", content: req.user }]
30393
- })
30394
- });
30395
- if (!resp.ok) {
30396
- console.warn(
30397
- `[errata] llm: anthropic ${resp.status} \u2014 ${(await resp.text().catch(() => "")).slice(0, 200)}`
30398
- );
30399
- return null;
30400
- }
30401
- const json2 = await resp.json();
30402
- return json2.content?.find((c) => c.type === "text")?.text ?? null;
30403
- } catch (err2) {
30404
- console.warn(
30405
- `[errata] llm: ${provider} transport failed \u2014`,
30406
- err2 instanceof Error ? err2.message : err2
30407
- );
30408
- return null;
30409
- }
30410
- }
30411
- var init_llm_provider = __esm({
30412
- "src/llm-provider.ts"() {
30413
- "use strict";
30414
- }
30415
- });
30416
-
30417
- // src/symbol-summaries.ts
30418
- import { existsSync as existsSync9, readFileSync as readFileSync7, writeFileSync as writeFileSync8 } from "node:fs";
30419
- import { join as join8 } from "node:path";
30420
- function symbolSummariesPath(configDir) {
30421
- return join8(configDir, "symbol-summaries.json");
30422
- }
30423
- function loadSymbolSummaryCache(configDir) {
30424
- const p = symbolSummariesPath(configDir);
30425
- if (existsSync9(p)) {
30426
- try {
30427
- const raw2 = JSON.parse(readFileSync7(p, "utf8"));
30428
- if (raw2 && raw2.version === 1 && raw2.entries && typeof raw2.entries === "object") {
30429
- return { version: 1, entries: raw2.entries };
30430
- }
30431
- } catch {
30432
- }
30433
- }
30434
- return { version: 1, entries: {} };
30435
- }
30436
- function saveSymbolSummaryCache(configDir, cache2) {
30437
- writeFileSync8(symbolSummariesPath(configDir), JSON.stringify(cache2, null, 2), "utf8");
30438
- }
30439
- function summariesByBodyHash(cache2) {
30440
- const m = /* @__PURE__ */ new Map();
30441
- for (const [bodyHash, e] of Object.entries(cache2.entries)) {
30442
- if (!e.rejected && typeof e.summary === "string" && e.summary.trim()) m.set(bodyHash, e.summary);
30443
- }
30444
- return m;
30445
- }
30446
- function buildDocIndex(store) {
30447
- const byName = /* @__PURE__ */ new Map();
30448
- for (const c of store.findNodesByLabel("Comment")) {
30449
- const name2 = c.attrs["attachedTo"];
30450
- const kind = c.attrs["kind"];
30451
- if (typeof name2 !== "string" || !name2) continue;
30452
- if (typeof kind !== "string" || !DOC_COMMENT_KINDS.has(kind)) continue;
30453
- const text = typeof c.attrs["text"] === "string" ? c.attrs["text"] : c.description;
30454
- if (!text?.trim()) continue;
30455
- if (!byName.has(name2)) byName.set(name2, text.trim().slice(0, MAX_DOC_CHARS));
30456
- }
30457
- return byName;
30458
- }
30459
- function parseSummaryJson(text, expected) {
30460
- const start2 = text.indexOf("[");
30461
- const end = text.lastIndexOf("]");
30462
- if (start2 < 0 || end <= start2) return new Array(expected).fill(null);
30463
- let arr;
30464
- try {
30465
- arr = JSON.parse(text.slice(start2, end + 1));
30466
- } catch {
30467
- return new Array(expected).fill(null);
30468
- }
30469
- if (!Array.isArray(arr)) return new Array(expected).fill(null);
30470
- const out2 = [];
30471
- for (let i2 = 0; i2 < expected; i2++) {
30472
- const v = arr[i2];
30473
- out2.push(typeof v === "string" && v.trim() ? v.trim().slice(0, MAX_SYMBOL_SUMMARY_CHARS) : null);
30474
- }
30475
- return out2;
30476
- }
30477
- function haikuIntentSummarizer(_apiKey) {
30478
- if (!isChatConfigured(SUMMARY_MODEL)) return void 0;
30479
- return async (symbols) => {
30480
- const listing = symbols.map(
30481
- (s, i2) => `### ${i2 + 1}. kind: ${s.kind}
30482
- name: ${s.name}
30483
- ` + (s.doc ? `doc: ${s.doc}
30484
- ` : "") + `${s.snippet ? `\`\`\`
30485
- ${s.snippet}
30486
- \`\`\`` : "(no source available \u2014 describe from the name)"}`
30487
- ).join("\n\n");
30488
- const text = await chat({
30489
- model: SUMMARY_MODEL,
30490
- user: `${SUMMARY_PROMPT}
30491
-
30492
- SYMBOLS:
30493
- ${listing}`,
30494
- maxTokens: 2e3
30495
- });
30496
- if (text === null) return symbols.map(() => null);
30497
- return parseSummaryJson(text, symbols.length);
30498
- };
30499
- }
30500
- function envIntentSummarizer() {
30501
- if (process.env["ERRATA_SYMBOL_SUMMARIES"] !== "1") return void 0;
30502
- return haikuIntentSummarizer();
30503
- }
30504
- function readSnippet(workspaceRoot, attrs) {
30505
- const relPath = attrs["relPath"];
30506
- const startByte = attrs["startByte"];
30507
- const endByte = attrs["endByte"];
30508
- if (typeof relPath !== "string" || typeof startByte !== "number" || typeof endByte !== "number") {
30509
- return void 0;
30510
- }
30511
- try {
30512
- const buf = readFileSync7(join8(workspaceRoot, ...relPath.split("/")));
30513
- const slice = buf.subarray(Math.max(0, startByte), Math.min(buf.length, endByte));
30514
- const text = slice.toString("utf8");
30515
- return text.length > MAX_SNIPPET_CHARS ? text.slice(0, MAX_SNIPPET_CHARS) : text;
30516
- } catch {
30517
- return void 0;
30518
- }
30519
- }
30520
- async function runSymbolSummarySweep(store, workspaceRoot, configDir, summarizer, opts = {}) {
30521
- const maxSymbols = opts.maxSymbols ?? DEFAULT_MAX_SYMBOLS_PER_SWEEP;
30522
- const batchSize = Math.max(1, opts.batchSize ?? DEFAULT_BATCH_SIZE);
30523
- const cache2 = loadSymbolSummaryCache(configDir);
30524
- const candidates = [];
30525
- const seen = /* @__PURE__ */ new Set();
30526
- const docs = buildDocIndex(store);
30527
- for (const [label, kind] of SUMMARY_LABELS) {
30528
- for (const n of store.findNodesByLabel(label)) {
30529
- const bodyHash = n.attrs["bodyHash"];
30530
- if (typeof bodyHash !== "string" || !bodyHash || seen.has(bodyHash)) continue;
30531
- if (cache2.entries[bodyHash]) continue;
30532
- const name2 = n.description;
30533
- if (!name2 || !isDistinctiveIdentifier(name2)) continue;
30534
- seen.add(bodyHash);
30535
- const snippet = readSnippet(workspaceRoot, n.attrs);
30536
- const qname = typeof n.attrs["qname"] === "string" ? n.attrs["qname"] : void 0;
30537
- const doc = docs.get(name2) ?? (qname ? docs.get(qname) : void 0);
30538
- candidates.push({
30539
- bodyHash,
30540
- name: name2,
30541
- kind,
30542
- ...snippet ? { snippet } : {},
30543
- ...doc ? { doc } : {}
30544
- });
30545
- }
30546
- }
30547
- const todo = candidates.slice(0, maxSymbols);
30548
- const remaining = candidates.length - todo.length;
30549
- if (todo.length === 0) return { generated: 0, rejected: 0, remaining };
30550
- const lexicon = buildSymbolLexicon(store);
30551
- const isKnown = (tok) => lexicon.has(tok);
30552
- let generated = 0;
30553
- let rejected = 0;
30554
- for (let i2 = 0; i2 < todo.length; i2 += batchSize) {
30555
- const batch = todo.slice(i2, i2 + batchSize);
30556
- const phrases = await summarizer(batch);
30557
- const now = Date.now();
30558
- for (let j = 0; j < batch.length; j++) {
30559
- const sym = batch[j];
30560
- const phrase = phrases[j];
30561
- if (phrase == null) continue;
30562
- if (summaryRejectionReason(phrase, isKnown) === null) {
30563
- cache2.entries[sym.bodyHash] = { summary: phrase, model: SUMMARY_MODEL, createdAt: now };
30564
- generated++;
30565
- } else {
30566
- cache2.entries[sym.bodyHash] = { rejected: true, model: SUMMARY_MODEL, createdAt: now };
30567
- rejected++;
30568
- }
30569
- }
30570
- saveSymbolSummaryCache(configDir, cache2);
30571
- }
30572
- return { generated, rejected, remaining };
30573
- }
30574
- var SUMMARY_LABELS, MAX_SNIPPET_CHARS, DEFAULT_MAX_SYMBOLS_PER_SWEEP, DEFAULT_BATCH_SIZE, DOC_COMMENT_KINDS, MAX_DOC_CHARS, SUMMARY_MODEL, SUMMARY_PROMPT;
30575
- var init_symbol_summaries = __esm({
30576
- "src/symbol-summaries.ts"() {
30577
- "use strict";
30578
- init_src();
30579
- init_generalize_graph();
30580
- init_llm_provider();
30581
- SUMMARY_LABELS = [
30582
- ["Function", "function"],
30583
- ["Method", "method"],
30584
- ["Class", "class"]
30585
- ];
30586
- MAX_SNIPPET_CHARS = 1500;
30587
- DEFAULT_MAX_SYMBOLS_PER_SWEEP = 64;
30588
- DEFAULT_BATCH_SIZE = 16;
30589
- DOC_COMMENT_KINDS = /* @__PURE__ */ new Set(["docstring", "explanation"]);
30590
- MAX_DOC_CHARS = 600;
30591
- SUMMARY_MODEL = "claude-haiku-4-5-20251001";
30592
- SUMMARY_PROMPT = `For each code symbol below, write ONE short English phrase stating its intent/role, shaped like "a <kind> that <does what>" (e.g. "a function that binds the server's listen port").
30593
- Some symbols include a "doc:" line \u2014 the author's own description of what it is for. When present TRUST IT as the primary source of intent and translate it into the required shape; the code is secondary evidence. Carry the SPECIFIC job the symbol does, not the category it belongs to: "a function that releases a pooled connection on every exit path including cancellation" is useful; "a function that handles cleanup" is not.
30594
- HARD RULES \u2014 a violating phrase is discarded:
30595
- - NEVER include any identifier, symbol name, variable, type name, file path, or module name from the code or the doc \u2014 describe meaning in plain English words only.
30596
- - NEVER include quoted strings, literals, numbers copied from the code, or code syntax.
30597
- - One phrase per symbol, under 200 characters, lowercase start, no trailing period.
30598
- Output a JSON array of strings, one per symbol in the SAME ORDER (use null for a symbol you cannot describe). Output JSON only, no prose.`;
30599
- }
30600
- });
30601
-
30602
30765
  // ../../packages/indexer/src/simhash.ts
30603
30766
  function fnv1a64(s) {
30604
30767
  let h = FNV_OFFSET;
@@ -30822,9 +30985,9 @@ var init_identity3 = __esm({
30822
30985
  });
30823
30986
 
30824
30987
  // ../../packages/indexer/src/pipeline.ts
30825
- import { appendFileSync, readFileSync as readFileSync8, statSync } from "node:fs";
30988
+ import { appendFileSync, readFileSync as readFileSync7, statSync } from "node:fs";
30826
30989
  import { readdir } from "node:fs/promises";
30827
- import { extname, join as join9, relative as relative2, sep } from "node:path";
30990
+ import { extname, join as join8, relative as relative2, sep } from "node:path";
30828
30991
  import { createHash as createHash3 } from "node:crypto";
30829
30992
  import { execFileSync } from "node:child_process";
30830
30993
  function nowTs() {
@@ -30958,7 +31121,7 @@ async function incrementalReindex(store, rootPath, workspaceId2, changedAbsPaths
30958
31121
  for (const rel of [...changedRelPaths]) {
30959
31122
  let h;
30960
31123
  try {
30961
- h = createHash3("sha256").update(readFileSync8(join9(rootPath, rel))).digest("hex");
31124
+ h = createHash3("sha256").update(readFileSync7(join8(rootPath, rel))).digest("hex");
30962
31125
  } catch {
30963
31126
  continue;
30964
31127
  }
@@ -31007,13 +31170,13 @@ async function incrementalReindex(store, rootPath, workspaceId2, changedAbsPaths
31007
31170
  let parsedFiles = 0;
31008
31171
  for (const rel of changedRelPaths) {
31009
31172
  if (parsedFiles++ > 0) await new Promise((r2) => setImmediate(r2));
31010
- const abs = join9(rootPath, ...rel.split("/"));
31173
+ const abs = join8(rootPath, ...rel.split("/"));
31011
31174
  const ext = extname(abs).toLowerCase();
31012
31175
  const provider = providers.find((p) => p.fileExtensions.includes(ext));
31013
31176
  if (!provider) continue;
31014
31177
  let symbols;
31015
31178
  try {
31016
- symbols = provider.extractSymbols(readFileSync8(abs, "utf8"), abs);
31179
+ symbols = provider.extractSymbols(readFileSync7(abs, "utf8"), abs);
31017
31180
  } catch {
31018
31181
  continue;
31019
31182
  }
@@ -31327,7 +31490,7 @@ async function runIndexer(store, opts) {
31327
31490
  report.filesSkipped++;
31328
31491
  continue;
31329
31492
  }
31330
- source = readFileSync8(f.absPath, "utf8");
31493
+ source = readFileSync7(f.absPath, "utf8");
31331
31494
  } catch {
31332
31495
  report.filesSkipped++;
31333
31496
  continue;
@@ -31385,7 +31548,7 @@ async function runIndexer(store, opts) {
31385
31548
  const depth = fileNode.relPath.split("/").length;
31386
31549
  if (depth !== 3) continue;
31387
31550
  try {
31388
- const pkg = JSON.parse(readFileSync8(fileNode.absPath, "utf8"));
31551
+ const pkg = JSON.parse(readFileSync7(fileNode.absPath, "utf8"));
31389
31552
  if (!pkg.name) continue;
31390
31553
  const pkgDir = fileNode.relPath.replace(/\/package\.json$/, "");
31391
31554
  const candidates = [
@@ -31767,7 +31930,7 @@ async function scan(root, current, ignores, providers, out2) {
31767
31930
  for (const ent of entries) {
31768
31931
  if (ignores.has(ent.name)) continue;
31769
31932
  if (ent.name.startsWith(".") && ent.name !== ".") continue;
31770
- const abs = join9(current, ent.name);
31933
+ const abs = join8(current, ent.name);
31771
31934
  if (ent.isDirectory()) {
31772
31935
  await scan(root, abs, ignores, providers, out2);
31773
31936
  } else if (ent.isFile()) {
@@ -31822,7 +31985,7 @@ function gitListFiles(root, ignores, providers) {
31822
31985
  if (rels === null) return null;
31823
31986
  const out2 = [];
31824
31987
  for (const rel of rels) {
31825
- const abs = join9(root, rel);
31988
+ const abs = join8(root, rel);
31826
31989
  let size;
31827
31990
  try {
31828
31991
  size = statSync(abs).size;
@@ -31845,7 +32008,7 @@ function upsertFile(store, id, f, workspaceId2) {
31845
32008
  const now = nowTs();
31846
32009
  let contentHash;
31847
32010
  try {
31848
- contentHash = createHash3("sha256").update(readFileSync8(f.absPath)).digest("hex");
32011
+ contentHash = createHash3("sha256").update(readFileSync7(f.absPath)).digest("hex");
31849
32012
  } catch {
31850
32013
  }
31851
32014
  const node2 = {
@@ -36208,8 +36371,8 @@ ${JSON.stringify(symbolNames, null, 2)}`);
36208
36371
 
36209
36372
  // ../../packages/indexer/src/languages/tree-sitter-loader.ts
36210
36373
  import { fileURLToPath } from "node:url";
36211
- import { dirname as dirname5, join as join10 } from "node:path";
36212
- import { existsSync as existsSync10, readdirSync as readdirSync2 } from "node:fs";
36374
+ import { dirname as dirname5, join as join9 } from "node:path";
36375
+ import { existsSync as existsSync9, readdirSync as readdirSync2 } from "node:fs";
36213
36376
  import { createRequire as createRequire2 } from "node:module";
36214
36377
  function entryDir() {
36215
36378
  try {
@@ -36223,27 +36386,27 @@ function entryDir() {
36223
36386
  }
36224
36387
  function findWasmDir() {
36225
36388
  const here = entryDir();
36226
- const seaWasm = join10(here, "resources", "wasm");
36227
- if (existsSync10(join10(seaWasm, "tree-sitter-typescript.wasm"))) return seaWasm;
36389
+ const seaWasm = join9(here, "resources", "wasm");
36390
+ if (existsSync9(join9(seaWasm, "tree-sitter-typescript.wasm"))) return seaWasm;
36228
36391
  let dir = here;
36229
36392
  for (let i2 = 0; i2 < 6; i2++) {
36230
- const flat = join10(
36393
+ const flat = join9(
36231
36394
  dir,
36232
36395
  "node_modules",
36233
36396
  "@vscode",
36234
36397
  "tree-sitter-wasm",
36235
36398
  "wasm"
36236
36399
  );
36237
- if (existsSync10(join10(flat, "tree-sitter-typescript.wasm"))) return flat;
36400
+ if (existsSync9(join9(flat, "tree-sitter-typescript.wasm"))) return flat;
36238
36401
  dir = dirname5(dir);
36239
36402
  }
36240
36403
  let root = here;
36241
36404
  for (let i2 = 0; i2 < 6; i2++) {
36242
- const pnpmDir = join10(root, "node_modules", ".pnpm");
36243
- if (existsSync10(pnpmDir)) {
36405
+ const pnpmDir = join9(root, "node_modules", ".pnpm");
36406
+ if (existsSync9(pnpmDir)) {
36244
36407
  for (const entry of readdirSync2(pnpmDir)) {
36245
36408
  if (entry.startsWith("@vscode+tree-sitter-wasm@")) {
36246
- const candidate = join10(
36409
+ const candidate = join9(
36247
36410
  pnpmDir,
36248
36411
  entry,
36249
36412
  "node_modules",
@@ -36251,7 +36414,7 @@ function findWasmDir() {
36251
36414
  "tree-sitter-wasm",
36252
36415
  "wasm"
36253
36416
  );
36254
- if (existsSync10(join10(candidate, "tree-sitter-typescript.wasm"))) {
36417
+ if (existsSync9(join9(candidate, "tree-sitter-typescript.wasm"))) {
36255
36418
  return candidate;
36256
36419
  }
36257
36420
  }
@@ -36265,27 +36428,27 @@ function findWasmDir() {
36265
36428
  }
36266
36429
  function findRuntimeDir() {
36267
36430
  const here = entryDir();
36268
- const seaRuntime = join10(here, "resources", "wasm");
36269
- if (existsSync10(join10(seaRuntime, "web-tree-sitter.wasm"))) return seaRuntime;
36431
+ const seaRuntime = join9(here, "resources", "wasm");
36432
+ if (existsSync9(join9(seaRuntime, "web-tree-sitter.wasm"))) return seaRuntime;
36270
36433
  let dir = here;
36271
36434
  for (let i2 = 0; i2 < 6; i2++) {
36272
- const flat = join10(dir, "node_modules", "web-tree-sitter");
36273
- if (existsSync10(join10(flat, "web-tree-sitter.wasm"))) return flat;
36435
+ const flat = join9(dir, "node_modules", "web-tree-sitter");
36436
+ if (existsSync9(join9(flat, "web-tree-sitter.wasm"))) return flat;
36274
36437
  dir = dirname5(dir);
36275
36438
  }
36276
36439
  let root = here;
36277
36440
  for (let i2 = 0; i2 < 6; i2++) {
36278
- const pnpmDir = join10(root, "node_modules", ".pnpm");
36279
- if (existsSync10(pnpmDir)) {
36441
+ const pnpmDir = join9(root, "node_modules", ".pnpm");
36442
+ if (existsSync9(pnpmDir)) {
36280
36443
  for (const entry of readdirSync2(pnpmDir)) {
36281
36444
  if (entry.startsWith("web-tree-sitter@")) {
36282
- const candidate = join10(
36445
+ const candidate = join9(
36283
36446
  pnpmDir,
36284
36447
  entry,
36285
36448
  "node_modules",
36286
36449
  "web-tree-sitter"
36287
36450
  );
36288
- if (existsSync10(join10(candidate, "web-tree-sitter.wasm"))) {
36451
+ if (existsSync9(join9(candidate, "web-tree-sitter.wasm"))) {
36289
36452
  return candidate;
36290
36453
  }
36291
36454
  }
@@ -36302,7 +36465,7 @@ async function loadWebTreeSitter() {
36302
36465
  void err2;
36303
36466
  }
36304
36467
  const here = entryDir();
36305
- const seaResourceBase = join10(here, "resources", "_resolve.js");
36468
+ const seaResourceBase = join9(here, "resources", "_resolve.js");
36306
36469
  const resourceRequire = createRequire2(seaResourceBase);
36307
36470
  return resourceRequire("web-tree-sitter");
36308
36471
  }
@@ -36317,9 +36480,9 @@ async function ensureTreeSitterReady() {
36317
36480
  await Parser2.init({
36318
36481
  locateFile: (name2) => {
36319
36482
  if (name2 === "tree-sitter.wasm" || name2 === "web-tree-sitter.wasm") {
36320
- return join10(runtime, name2);
36483
+ return join9(runtime, name2);
36321
36484
  }
36322
- return join10(grammars, name2);
36485
+ return join9(grammars, name2);
36323
36486
  }
36324
36487
  });
36325
36488
  })();
@@ -36331,7 +36494,7 @@ async function loadGrammar(name2) {
36331
36494
  if (cached2) return cached2;
36332
36495
  if (!languageClass) throw new Error("tree-sitter not initialized");
36333
36496
  const grammars = findWasmDir();
36334
- const lang = await languageClass.load(join10(grammars, `${name2}.wasm`));
36497
+ const lang = await languageClass.load(join9(grammars, `${name2}.wasm`));
36335
36498
  grammarCache.set(name2, lang);
36336
36499
  return lang;
36337
36500
  }
@@ -39235,7 +39398,7 @@ var init_src11 = __esm({
39235
39398
  // src/reconcile.ts
39236
39399
  import { execFileSync as execFileSync2 } from "node:child_process";
39237
39400
  import { readdirSync as readdirSync3, statSync as statSync2 } from "node:fs";
39238
- import { join as join11, relative as relative3, sep as sep2 } from "node:path";
39401
+ import { join as join10, relative as relative3, sep as sep2 } from "node:path";
39239
39402
  function gitSourceFiles(root) {
39240
39403
  let stdout;
39241
39404
  try {
@@ -39250,7 +39413,7 @@ function gitSourceFiles(root) {
39250
39413
  const out2 = [];
39251
39414
  for (const rel of stdout.split("\0")) {
39252
39415
  if (!rel || !SOURCE_RE.test(rel)) continue;
39253
- const abs = join11(root, rel);
39416
+ const abs = join10(root, rel);
39254
39417
  if (IGNORED.test(abs)) continue;
39255
39418
  out2.push(abs);
39256
39419
  }
@@ -39265,7 +39428,7 @@ function* walkSource(dir) {
39265
39428
  }
39266
39429
  for (const e of entries) {
39267
39430
  const name2 = String(e.name);
39268
- const full = join11(dir, name2);
39431
+ const full = join10(dir, name2);
39269
39432
  if (IGNORED.test(full)) continue;
39270
39433
  if (e.isDirectory()) yield* walkSource(full);
39271
39434
  else if (SOURCE_RE.test(name2)) yield full;
@@ -39411,7 +39574,7 @@ __export(mcp_exports, {
39411
39574
  runTool: () => runTool,
39412
39575
  searchGraph: () => searchGraph
39413
39576
  });
39414
- import { existsSync as existsSync11, readFileSync as readFileSync9 } from "node:fs";
39577
+ import { existsSync as existsSync10, readFileSync as readFileSync8 } from "node:fs";
39415
39578
  import { resolve } from "node:path";
39416
39579
  function collectEnrichmentPulls(store, opts = {}) {
39417
39580
  const pending = store.findNodesByLabel("Solution").filter((s) => s.attrs["enrichmentPending"] === true).filter((s) => !opts.onlyUnsurfaced || s.attrs["enrichmentSurfaced"] !== true);
@@ -39448,7 +39611,7 @@ function takeEnrichmentNudge(store) {
39448
39611
  ` + items;
39449
39612
  }
39450
39613
  function takeDiscriminatorNudge(path2) {
39451
- if (!path2 || !existsSync11(path2)) return null;
39614
+ if (!path2 || !existsSync10(path2)) return null;
39452
39615
  let shared;
39453
39616
  try {
39454
39617
  shared = openGraphStore({ path: path2 });
@@ -39554,10 +39717,10 @@ function showNode(store, node2, maxLines) {
39554
39717
  if (!relPath) return { found: false, reason: "no file owner for node" };
39555
39718
  const workspaceRoot = process.cwd();
39556
39719
  const absPath = resolve(workspaceRoot, relPath);
39557
- if (!existsSync11(absPath)) {
39720
+ if (!existsSync10(absPath)) {
39558
39721
  return { found: false, reason: `file not found on disk: ${absPath}` };
39559
39722
  }
39560
- const source = readFileSync9(absPath, "utf8");
39723
+ const source = readFileSync8(absPath, "utf8");
39561
39724
  const attrs = node2.attrs;
39562
39725
  let startByte = attrs["bodyStartByte"] ?? attrs["startByte"];
39563
39726
  let endByte = attrs["bodyEndByte"] ?? attrs["endByte"];
@@ -39800,22 +39963,8 @@ function buildToolContext(workspaceRoot) {
39800
39963
  async function runMcpServer(workspaceRoot) {
39801
39964
  const paths = workspacePaths(workspaceRoot);
39802
39965
  const store = openGraphStore({ path: paths.castalia });
39803
- let summariesMemo = null;
39804
- const symbolSummaries = () => {
39805
- const now = Date.now();
39806
- if (!summariesMemo || now - summariesMemo.at > 6e4) {
39807
- let map2 = /* @__PURE__ */ new Map();
39808
- try {
39809
- map2 = summariesByBodyHash(loadSymbolSummaryCache(paths.configDir));
39810
- } catch {
39811
- }
39812
- summariesMemo = { at: now, map: map2 };
39813
- }
39814
- return summariesMemo.map;
39815
- };
39816
39966
  const handle2 = createMcpHandler(store, {
39817
39967
  ...buildToolContext(workspaceRoot),
39818
- symbolSummaries,
39819
39968
  sharedDbPath: sharedStorePath()
39820
39969
  });
39821
39970
  process.stdin.setEncoding("utf8");
@@ -39859,7 +40008,6 @@ var init_mcp = __esm({
39859
40008
  init_src10();
39860
40009
  init_dual_burst();
39861
40010
  init_paths();
39862
- init_symbol_summaries();
39863
40011
  init_webui();
39864
40012
  init_reconcile();
39865
40013
  init_agent_signals();
@@ -39973,8 +40121,7 @@ var init_mcp = __esm({
39973
40121
  cloud: ctx.cloud,
39974
40122
  localHits,
39975
40123
  queryText: query,
39976
- limit,
39977
- ...ctx.symbolSummaries ? { summaries: ctx.symbolSummaries() } : {}
40124
+ limit
39978
40125
  });
39979
40126
  if (dual.status === "merged") {
39980
40127
  return {
@@ -40153,8 +40300,7 @@ var init_mcp = __esm({
40153
40300
  cloud: ctx.cloud,
40154
40301
  localHits,
40155
40302
  seedNode,
40156
- limit: args2["limit"] != null ? Number(args2["limit"]) : 20,
40157
- ...ctx.symbolSummaries ? { summaries: ctx.symbolSummaries() } : {}
40303
+ limit: args2["limit"] != null ? Number(args2["limit"]) : 20
40158
40304
  });
40159
40305
  if (dual.status === "merged") {
40160
40306
  return {
@@ -40319,7 +40465,7 @@ var init_mcp = __esm({
40319
40465
  const local = causalChain(store, { seedId: id, direction: "both", maxHops, limit });
40320
40466
  try {
40321
40467
  const path2 = sharedStorePath();
40322
- if (!existsSync11(path2)) return { found: true, ...local };
40468
+ if (!existsSync10(path2)) return { found: true, ...local };
40323
40469
  const shared = openGraphStore({ path: path2 });
40324
40470
  try {
40325
40471
  if (!shared.getNode(id)) return { found: true, ...local };
@@ -40722,8 +40868,7 @@ var init_mcp = __esm({
40722
40868
  cloud: ctx.cloud,
40723
40869
  localHits,
40724
40870
  seedNode: node2,
40725
- limit,
40726
- ...ctx.symbolSummaries ? { summaries: ctx.symbolSummaries() } : {}
40871
+ limit
40727
40872
  });
40728
40873
  if (dual.status === "merged") {
40729
40874
  return {
@@ -40920,7 +41065,7 @@ var init_mcp = __esm({
40920
41065
  inputSchema: { type: "object", properties: {} },
40921
41066
  handler: () => {
40922
41067
  const path2 = sharedStorePath();
40923
- if (!existsSync11(path2)) return { count: 0, pending: [] };
41068
+ if (!existsSync10(path2)) return { count: 0, pending: [] };
40924
41069
  const shared = openGraphStore({ path: path2 });
40925
41070
  try {
40926
41071
  const pending = pendingAbstractions(shared);
@@ -40948,7 +41093,7 @@ var init_mcp = __esm({
40948
41093
  },
40949
41094
  handler: (args2) => {
40950
41095
  const path2 = sharedStorePath();
40951
- if (!existsSync11(path2)) return { count: 0, pending: [] };
41096
+ if (!existsSync10(path2)) return { count: 0, pending: [] };
40952
41097
  const shared = openGraphStore({ path: path2 });
40953
41098
  try {
40954
41099
  const pending = pendingDiscriminators(shared, {
@@ -40992,7 +41137,7 @@ var init_mcp = __esm({
40992
41137
  },
40993
41138
  handler: (args2) => {
40994
41139
  const path2 = sharedStorePath();
40995
- if (!existsSync11(path2)) return { count: 0, routes: [] };
41140
+ if (!existsSync10(path2)) return { count: 0, routes: [] };
40996
41141
  const shared = openGraphStore({ path: path2 });
40997
41142
  try {
40998
41143
  const result = triageOf(shared, {
@@ -41377,8 +41522,8 @@ __export(vfile_exports, {
41377
41522
  resolvePath: () => resolvePath,
41378
41523
  segmentsOf: () => segmentsOf
41379
41524
  });
41380
- import { writeFileSync as writeFileSync9 } from "node:fs";
41381
- import { join as join12, resolve as resolve2, sep as sep3 } from "node:path";
41525
+ import { writeFileSync as writeFileSync8 } from "node:fs";
41526
+ import { join as join11, resolve as resolve2, sep as sep3 } from "node:path";
41382
41527
  function segmentsOf(rawPath) {
41383
41528
  let p = rawPath.replace(/\\/g, "/");
41384
41529
  p = p.replace(/^.*\.errata\/g\//, "").replace(/^\/?g\//, "").replace(/^\/+/, "");
@@ -41452,14 +41597,14 @@ async function renderVFile(rawPath, store, ctx = {}) {
41452
41597
  }
41453
41598
  async function materializeVFile(rawPath, workspaceRoot, store, ctx = {}) {
41454
41599
  const segs = segmentsOf(rawPath);
41455
- const gRoot = join12(workspaceRoot, ".errata", "g");
41600
+ const gRoot = join11(workspaceRoot, ".errata", "g");
41456
41601
  const abs = resolve2(gRoot, ...segs.length ? segs : ["index"]);
41457
41602
  if (abs !== gRoot && !abs.startsWith(gRoot + sep3)) {
41458
41603
  throw new Error(`refusing to materialize outside .errata/g: ${rawPath}`);
41459
41604
  }
41460
41605
  const text = await renderVFile(rawPath, store, ctx);
41461
41606
  ensureParent(abs);
41462
- writeFileSync9(abs, text, "utf8");
41607
+ writeFileSync8(abs, text, "utf8");
41463
41608
  return abs;
41464
41609
  }
41465
41610
  async function materializeOverview(workspaceRoot, store, ctx = {}) {
@@ -48879,25 +49024,25 @@ var init_tool_index = __esm({
48879
49024
 
48880
49025
  // src/outbox.ts
48881
49026
  import {
48882
- existsSync as existsSync12,
49027
+ existsSync as existsSync11,
48883
49028
  readdirSync as readdirSync4,
48884
- readFileSync as readFileSync10,
49029
+ readFileSync as readFileSync9,
48885
49030
  renameSync,
48886
49031
  unlinkSync,
48887
- writeFileSync as writeFileSync10
49032
+ writeFileSync as writeFileSync9
48888
49033
  } from "node:fs";
48889
- import { join as join13 } from "node:path";
49034
+ import { join as join12 } from "node:path";
48890
49035
  import { createHash as createHash11 } from "node:crypto";
48891
49036
  function enqueueOutbox(paths, payload) {
48892
49037
  ensureDir(paths.outbox);
48893
49038
  const id = createHash11("sha256").update(JSON.stringify(payload)).digest("hex").slice(0, 16);
48894
- const file2 = join13(paths.outbox, `${Date.now()}-${id}.json`);
48895
- writeFileSync10(file2, JSON.stringify(payload, null, 2), "utf8");
49039
+ const file2 = join12(paths.outbox, `${Date.now()}-${id}.json`);
49040
+ writeFileSync9(file2, JSON.stringify(payload, null, 2), "utf8");
48896
49041
  return file2;
48897
49042
  }
48898
49043
  async function flushOutbox(paths, client, store) {
48899
49044
  ensureDir(paths.outbox);
48900
- const entries = existsSync12(paths.outbox) ? readdirSync4(paths.outbox) : [];
49045
+ const entries = existsSync11(paths.outbox) ? readdirSync4(paths.outbox) : [];
48901
49046
  let uploaded = 0;
48902
49047
  let failed = 0;
48903
49048
  const quarantine = (abs, reason) => {
@@ -48908,10 +49053,10 @@ async function flushOutbox(paths, client, store) {
48908
49053
  }
48909
49054
  };
48910
49055
  for (const f of entries.filter((e) => e.endsWith(".json")).sort()) {
48911
- const abs = join13(paths.outbox, f);
49056
+ const abs = join12(paths.outbox, f);
48912
49057
  let payload;
48913
49058
  try {
48914
- payload = JSON.parse(readFileSync10(abs, "utf8"));
49059
+ payload = JSON.parse(readFileSync9(abs, "utf8"));
48915
49060
  } catch {
48916
49061
  failed++;
48917
49062
  quarantine(abs, "unparseable JSON");
@@ -48956,7 +49101,7 @@ async function flushOutbox(paths, client, store) {
48956
49101
  }
48957
49102
  }
48958
49103
  }
48959
- const remainingFiles = existsSync12(paths.outbox) ? readdirSync4(paths.outbox).filter((e) => e.endsWith(".json")) : [];
49104
+ const remainingFiles = existsSync11(paths.outbox) ? readdirSync4(paths.outbox).filter((e) => e.endsWith(".json")) : [];
48960
49105
  return { uploaded, failed, remaining: remainingFiles.length };
48961
49106
  }
48962
49107
  var init_outbox = __esm({
@@ -49665,27 +49810,27 @@ __export(witness_ledger_exports, {
49665
49810
  summarizeWitnessLedger: () => summarizeWitnessLedger,
49666
49811
  witnessLedgerPath: () => witnessLedgerPath
49667
49812
  });
49668
- import { appendFileSync as appendFileSync3, existsSync as existsSync22, readFileSync as readFileSync22, writeFileSync as writeFileSync19 } from "node:fs";
49669
- import { join as join27 } from "node:path";
49813
+ import { appendFileSync as appendFileSync3, existsSync as existsSync21, readFileSync as readFileSync21, writeFileSync as writeFileSync18 } from "node:fs";
49814
+ import { join as join26 } from "node:path";
49670
49815
  function witnessLedgerPath(configDir) {
49671
- return join27(configDir, "witness-ledger.jsonl");
49816
+ return join26(configDir, "witness-ledger.jsonl");
49672
49817
  }
49673
49818
  function appendWitnessLedger(configDir, entry) {
49674
49819
  const path2 = witnessLedgerPath(configDir);
49675
49820
  try {
49676
49821
  appendFileSync3(path2, JSON.stringify(entry) + "\n");
49677
- const lines = readFileSync22(path2, "utf8").split("\n").filter(Boolean);
49822
+ const lines = readFileSync21(path2, "utf8").split("\n").filter(Boolean);
49678
49823
  if (lines.length > LEDGER_MAX_LINES) {
49679
- writeFileSync19(path2, lines.slice(-Math.floor(LEDGER_MAX_LINES / 2)).join("\n") + "\n");
49824
+ writeFileSync18(path2, lines.slice(-Math.floor(LEDGER_MAX_LINES / 2)).join("\n") + "\n");
49680
49825
  }
49681
49826
  } catch {
49682
49827
  }
49683
49828
  }
49684
49829
  function readWitnessLedger(configDir) {
49685
49830
  const path2 = witnessLedgerPath(configDir);
49686
- if (!existsSync22(path2)) return [];
49831
+ if (!existsSync21(path2)) return [];
49687
49832
  try {
49688
- return readFileSync22(path2, "utf8").split("\n").filter(Boolean).map((l) => JSON.parse(l)).filter((e) => typeof e.ts === "number" && typeof e.channel === "string");
49833
+ return readFileSync21(path2, "utf8").split("\n").filter(Boolean).map((l) => JSON.parse(l)).filter((e) => typeof e.ts === "number" && typeof e.channel === "string");
49689
49834
  } catch {
49690
49835
  return [];
49691
49836
  }
@@ -50111,12 +50256,12 @@ var init_report_render = __esm({
50111
50256
 
50112
50257
  // src/cli.ts
50113
50258
  init_src6();
50114
- import { closeSync as closeSync2, existsSync as existsSync30, openSync as openSync2, readFileSync as readFileSync28, renameSync as renameSync4, statSync as statSync6 } from "node:fs";
50115
- import { join as join32, resolve as pathResolve } from "node:path";
50259
+ import { closeSync as closeSync2, existsSync as existsSync29, openSync as openSync2, readFileSync as readFileSync27, renameSync as renameSync4, statSync as statSync6 } from "node:fs";
50260
+ import { join as join31, resolve as pathResolve } from "node:path";
50116
50261
  import { spawn as spawn3 } from "node:child_process";
50117
50262
 
50118
50263
  // src/daemon.ts
50119
- import { existsSync as existsSync24, writeFileSync as writeFileSync21 } from "node:fs";
50264
+ import { existsSync as existsSync23, writeFileSync as writeFileSync20 } from "node:fs";
50120
50265
 
50121
50266
  // ../../node_modules/.pnpm/@hono+node-server@1.19.11_hono@4.12.8/node_modules/@hono/node-server/dist/index.mjs
50122
50267
  import { createServer as createServerHTTP } from "http";
@@ -50696,8 +50841,8 @@ init_config();
50696
50841
 
50697
50842
  // src/engine.ts
50698
50843
  import { execFileSync as execFileSync3 } from "node:child_process";
50699
- import { existsSync as existsSync23, statSync as statSync5, appendFileSync as appendFileSync4, readdirSync as readdirSync9, renameSync as renameSync3, readFileSync as readFileSync23, writeFileSync as writeFileSync20 } from "node:fs";
50700
- import { join as join28, relative as relative6, sep as sep4 } from "node:path";
50844
+ import { existsSync as existsSync22, statSync as statSync5, appendFileSync as appendFileSync4, readdirSync as readdirSync9, renameSync as renameSync3, readFileSync as readFileSync22, writeFileSync as writeFileSync19 } from "node:fs";
50845
+ import { join as join27, relative as relative6, sep as sep4 } from "node:path";
50701
50846
 
50702
50847
  // ../../node_modules/.pnpm/chokidar@4.0.3/node_modules/chokidar/esm/index.js
50703
50848
  import { stat as statcb } from "fs";
@@ -52559,8 +52704,8 @@ init_src10();
52559
52704
  init_review2();
52560
52705
 
52561
52706
  // src/turn.ts
52562
- import { closeSync, existsSync as existsSync13, fstatSync, openSync, readdirSync as readdirSync5, readSync, statSync as statSync3 } from "node:fs";
52563
- import { basename as basename3, dirname as dirname8, join as join16 } from "node:path";
52707
+ import { closeSync, existsSync as existsSync12, fstatSync, openSync, readdirSync as readdirSync5, readSync, statSync as statSync3 } from "node:fs";
52708
+ import { basename as basename3, dirname as dirname8, join as join15 } from "node:path";
52564
52709
  import { homedir as homedir3 } from "node:os";
52565
52710
  function readFrom(path2, fromByte, maxBytes) {
52566
52711
  let fd;
@@ -52780,11 +52925,11 @@ function turnsSince(turns, mark) {
52780
52925
  return at >= 0 ? turns.slice(at + 1) : turns;
52781
52926
  }
52782
52927
  function claudeProjectDir(cwd, home = homedir3()) {
52783
- return join16(home, ".claude", "projects", cwd.replace(/[\\/:.]/g, "-"));
52928
+ return join15(home, ".claude", "projects", cwd.replace(/[\\/:.]/g, "-"));
52784
52929
  }
52785
52930
  function recentTranscripts(cwd, opts = {}) {
52786
52931
  const dir = claudeProjectDir(cwd, opts.home ?? homedir3());
52787
- if (!existsSync13(dir)) return [];
52932
+ if (!existsSync12(dir)) return [];
52788
52933
  let names;
52789
52934
  try {
52790
52935
  names = readdirSync5(dir);
@@ -52795,7 +52940,7 @@ function recentTranscripts(cwd, opts = {}) {
52795
52940
  const refs = [];
52796
52941
  for (const name2 of names) {
52797
52942
  if (!name2.endsWith(".jsonl")) continue;
52798
- const path2 = join16(dir, name2);
52943
+ const path2 = join15(dir, name2);
52799
52944
  let mtimeMs;
52800
52945
  try {
52801
52946
  mtimeMs = statSync3(path2).mtimeMs;
@@ -52810,8 +52955,8 @@ function recentTranscripts(cwd, opts = {}) {
52810
52955
  }
52811
52956
  function subagentTranscripts(mainTranscriptPath, sessionId) {
52812
52957
  if (!mainTranscriptPath || !sessionId) return [];
52813
- const dir = join16(dirname8(mainTranscriptPath), sessionId, "subagents");
52814
- if (!existsSync13(dir)) return [];
52958
+ const dir = join15(dirname8(mainTranscriptPath), sessionId, "subagents");
52959
+ if (!existsSync12(dir)) return [];
52815
52960
  let names;
52816
52961
  try {
52817
52962
  names = readdirSync5(dir);
@@ -52821,7 +52966,7 @@ function subagentTranscripts(mainTranscriptPath, sessionId) {
52821
52966
  const refs = [];
52822
52967
  for (const name2 of names) {
52823
52968
  if (!name2.endsWith(".jsonl")) continue;
52824
- const path2 = join16(dir, name2);
52969
+ const path2 = join15(dir, name2);
52825
52970
  let mtimeMs;
52826
52971
  try {
52827
52972
  mtimeMs = statSync3(path2).mtimeMs;
@@ -52840,7 +52985,7 @@ init_src2();
52840
52985
  init_agent_signals();
52841
52986
  init_tool_index();
52842
52987
  init_src5();
52843
- import { readFileSync as readFileSync11, writeFileSync as writeFileSync11 } from "node:fs";
52988
+ import { readFileSync as readFileSync10, writeFileSync as writeFileSync10 } from "node:fs";
52844
52989
  var NEG = /n['']t|\b(?:not|never|no|none|neither|nor|unrelated|irrelevant|would|might|could|if)\b/i;
52845
52990
  var CITE_GROUP_RE = /\(((?:[^()\n]|\([^()\n]*\)){1,200})\)/g;
52846
52991
  var HANDLE_RE = /\[([a-z0-9][\w-]{0,80})\]|((?:pat|sol|drc|dcause|dfix|dprob|prob|claim|err)_[0-9a-f]{6,})/gi;
@@ -53298,13 +53443,13 @@ function writePrimingHandles(path2, nodes, now = Date.now()) {
53298
53443
  entries.sort((a, b) => (b[1].seenAt ?? 0) - (a[1].seenAt ?? 0));
53299
53444
  entries.length = HANDLE_MAP_MAX;
53300
53445
  }
53301
- writeFileSync11(path2, JSON.stringify(Object.fromEntries(entries)));
53446
+ writeFileSync10(path2, JSON.stringify(Object.fromEntries(entries)));
53302
53447
  } catch {
53303
53448
  }
53304
53449
  }
53305
53450
  function readPrimingHandles(path2) {
53306
53451
  try {
53307
- return JSON.parse(readFileSync11(path2, "utf8"));
53452
+ return JSON.parse(readFileSync10(path2, "utf8"));
53308
53453
  } catch {
53309
53454
  return {};
53310
53455
  }
@@ -53717,8 +53862,8 @@ ${conversation}` }]
53717
53862
  // src/constraint-backfill.ts
53718
53863
  init_src5();
53719
53864
  init_src2();
53720
- import { existsSync as existsSync14, readFileSync as readFileSync12, readdirSync as readdirSync6, writeFileSync as writeFileSync12 } from "node:fs";
53721
- import { join as join17 } from "node:path";
53865
+ import { existsSync as existsSync13, readFileSync as readFileSync11, readdirSync as readdirSync6, writeFileSync as writeFileSync11 } from "node:fs";
53866
+ import { join as join16 } from "node:path";
53722
53867
  import { homedir as homedir4 } from "node:os";
53723
53868
  var BACKFILL_VERSION = 1;
53724
53869
  var EMPTY = {
@@ -53732,13 +53877,13 @@ var EMPTY = {
53732
53877
  recoverable: 0
53733
53878
  };
53734
53879
  function markerPath(configDir) {
53735
- return join17(configDir, "constraint-backfill.json");
53880
+ return join16(configDir, "constraint-backfill.json");
53736
53881
  }
53737
53882
  function alreadyDone(configDir) {
53738
53883
  const p = markerPath(configDir);
53739
- if (!existsSync14(p)) return false;
53884
+ if (!existsSync13(p)) return false;
53740
53885
  try {
53741
- const raw2 = JSON.parse(readFileSync12(p, "utf8"));
53886
+ const raw2 = JSON.parse(readFileSync11(p, "utf8"));
53742
53887
  return raw2?.version === BACKFILL_VERSION;
53743
53888
  } catch {
53744
53889
  return false;
@@ -53748,7 +53893,7 @@ function replay(root) {
53748
53893
  const statements = /* @__PURE__ */ new Set();
53749
53894
  const citedByFix = /* @__PURE__ */ new Set();
53750
53895
  const dir = claudeProjectDir(root, homedir4());
53751
- if (!existsSync14(dir)) return { statements, citedByFix };
53896
+ if (!existsSync13(dir)) return { statements, citedByFix };
53752
53897
  let names;
53753
53898
  try {
53754
53899
  names = readdirSync6(dir).filter((n) => n.endsWith(".jsonl"));
@@ -53758,7 +53903,7 @@ function replay(root) {
53758
53903
  for (const f of names) {
53759
53904
  let lines;
53760
53905
  try {
53761
- lines = readFileSync12(join17(dir, f), "utf8").split("\n");
53906
+ lines = readFileSync11(join16(dir, f), "utf8").split("\n");
53762
53907
  } catch {
53763
53908
  continue;
53764
53909
  }
@@ -53872,7 +54017,7 @@ function backfillConstraintKind(store, opts) {
53872
54017
  }
53873
54018
  });
53874
54019
  try {
53875
- writeFileSync12(
54020
+ writeFileSync11(
53876
54021
  markerPath(opts.configDir),
53877
54022
  JSON.stringify({ version: BACKFILL_VERSION, at: opts.now, ...report, cloudTwins: report.cloudTwins.length }, null, 2),
53878
54023
  "utf8"
@@ -53885,8 +54030,8 @@ function backfillConstraintKind(store, opts) {
53885
54030
  // src/edge-repair.ts
53886
54031
  init_src();
53887
54032
  init_src5();
53888
- import { existsSync as existsSync15, readFileSync as readFileSync13, writeFileSync as writeFileSync13 } from "node:fs";
53889
- import { join as join18 } from "node:path";
54033
+ import { existsSync as existsSync14, readFileSync as readFileSync12, writeFileSync as writeFileSync12 } from "node:fs";
54034
+ import { join as join17 } from "node:path";
53890
54035
  function citeEdgeId(from, type, to) {
53891
54036
  return `edge_${digest({ from, type, to })}`.slice(0, 24);
53892
54037
  }
@@ -53901,13 +54046,13 @@ var EMPTY2 = {
53901
54046
  byType: {}
53902
54047
  };
53903
54048
  function markerPath2(configDir) {
53904
- return join18(configDir, "edge-repair.json");
54049
+ return join17(configDir, "edge-repair.json");
53905
54050
  }
53906
54051
  function alreadyDone2(configDir) {
53907
54052
  const p = markerPath2(configDir);
53908
- if (!existsSync15(p)) return false;
54053
+ if (!existsSync14(p)) return false;
53909
54054
  try {
53910
- return JSON.parse(readFileSync13(p, "utf8"))?.version === EDGE_REPAIR_VERSION;
54055
+ return JSON.parse(readFileSync12(p, "utf8"))?.version === EDGE_REPAIR_VERSION;
53911
54056
  } catch {
53912
54057
  return false;
53913
54058
  }
@@ -53956,7 +54101,7 @@ function repairInvalidEdges(store, opts) {
53956
54101
  });
53957
54102
  store.pruneEdgeRejections(opts.now - REJECTION_RETENTION_MS);
53958
54103
  try {
53959
- writeFileSync13(
54104
+ writeFileSync12(
53960
54105
  markerPath2(opts.configDir),
53961
54106
  JSON.stringify({ version: EDGE_REPAIR_VERSION, at: opts.now, ...report }, null, 2),
53962
54107
  "utf8"
@@ -53967,12 +54112,11 @@ function repairInvalidEdges(store, opts) {
53967
54112
  }
53968
54113
 
53969
54114
  // src/engine.ts
53970
- init_symbol_summaries();
53971
54115
  init_reconcile();
53972
54116
 
53973
54117
  // src/pass-ledger.ts
53974
- import { appendFileSync as appendFileSync2, existsSync as existsSync16, readFileSync as readFileSync14, writeFileSync as writeFileSync14 } from "node:fs";
53975
- import { join as join19 } from "node:path";
54118
+ import { appendFileSync as appendFileSync2, existsSync as existsSync15, readFileSync as readFileSync13, writeFileSync as writeFileSync13 } from "node:fs";
54119
+ import { join as join18 } from "node:path";
53976
54120
 
53977
54121
  // src/isolate-census.ts
53978
54122
  var live = 0;
@@ -53995,7 +54139,7 @@ var PER_KIND_MAX = 100;
53995
54139
  var TRIM_EVERY = 50;
53996
54140
  var appendsSinceTrim = /* @__PURE__ */ new Map();
53997
54141
  function passLedgerPath(configDir) {
53998
- return join19(configDir, "pass-ledger.jsonl");
54142
+ return join18(configDir, "pass-ledger.jsonl");
53999
54143
  }
54000
54144
  function appendPassLedger(configDir, kind, durationMs, counts) {
54001
54145
  const path2 = passLedgerPath(configDir);
@@ -54024,7 +54168,7 @@ function appendPassLedger(configDir, kind, durationMs, counts) {
54024
54168
  return;
54025
54169
  }
54026
54170
  appendsSinceTrim.set(path2, 0);
54027
- const lines = readFileSync14(path2, "utf8").split("\n").filter(Boolean);
54171
+ const lines = readFileSync13(path2, "utf8").split("\n").filter(Boolean);
54028
54172
  const keptByKind = /* @__PURE__ */ new Map();
54029
54173
  const kept = [];
54030
54174
  for (let i2 = lines.length - 1; i2 >= 0; i2--) {
@@ -54040,16 +54184,16 @@ function appendPassLedger(configDir, kind, durationMs, counts) {
54040
54184
  kept.push(lines[i2]);
54041
54185
  }
54042
54186
  if (kept.length < lines.length) {
54043
- writeFileSync14(path2, kept.reverse().join("\n") + "\n");
54187
+ writeFileSync13(path2, kept.reverse().join("\n") + "\n");
54044
54188
  }
54045
54189
  } catch {
54046
54190
  }
54047
54191
  }
54048
54192
  function readPassLedger(configDir) {
54049
54193
  const path2 = passLedgerPath(configDir);
54050
- if (!existsSync16(path2)) return [];
54194
+ if (!existsSync15(path2)) return [];
54051
54195
  try {
54052
- return readFileSync14(path2, "utf8").split("\n").filter(Boolean).map((l) => JSON.parse(l)).filter(
54196
+ return readFileSync13(path2, "utf8").split("\n").filter(Boolean).map((l) => JSON.parse(l)).filter(
54053
54197
  (e) => typeof e?.ts === "number" && typeof e?.kind === "string" && typeof e?.durationMs === "number"
54054
54198
  ).map((e) => ({ ...e, counts: e.counts ?? {} }));
54055
54199
  } catch {
@@ -54416,11 +54560,11 @@ init_outbox();
54416
54560
  init_src9();
54417
54561
  init_src();
54418
54562
  init_src2();
54419
- import { readFileSync as readFileSync15 } from "node:fs";
54420
- import { join as join20 } from "node:path";
54563
+ import { readFileSync as readFileSync14 } from "node:fs";
54564
+ import { join as join19 } from "node:path";
54421
54565
  function loadClaimIgnorePatterns(workspaceRoot) {
54422
54566
  try {
54423
- return readFileSync15(join20(workspaceRoot, ".errataignore"), "utf8").split(/\r?\n/).map((l) => l.trim()).filter((l) => l.length > 0 && !l.startsWith("#")).map((l) => l.toLowerCase());
54567
+ return readFileSync14(join19(workspaceRoot, ".errataignore"), "utf8").split(/\r?\n/).map((l) => l.trim()).filter((l) => l.length > 0 && !l.startsWith("#")).map((l) => l.toLowerCase());
54424
54568
  } catch {
54425
54569
  return [];
54426
54570
  }
@@ -54781,22 +54925,22 @@ async function pullCloudTriage(shared, cloud, profile, limit = 50) {
54781
54925
  }
54782
54926
 
54783
54927
  // src/git-sensor.ts
54784
- import { existsSync as existsSync17, readFileSync as readFileSync16, watch as fsWatch } from "node:fs";
54785
- import { join as join21 } from "node:path";
54928
+ import { existsSync as existsSync16, readFileSync as readFileSync15, watch as fsWatch } from "node:fs";
54929
+ import { join as join20 } from "node:path";
54786
54930
  function readFirstLine(path2) {
54787
54931
  try {
54788
- return readFileSync16(path2, "utf8").split(/\r?\n/, 1)[0].trim();
54932
+ return readFileSync15(path2, "utf8").split(/\r?\n/, 1)[0].trim();
54789
54933
  } catch {
54790
54934
  return null;
54791
54935
  }
54792
54936
  }
54793
54937
  function readGitRefState(gitDir) {
54794
- const head2 = readFirstLine(join21(gitDir, "HEAD"));
54938
+ const head2 = readFirstLine(join20(gitDir, "HEAD"));
54795
54939
  const m = head2 ? /^ref:\s*refs\/heads\/(.+)$/.exec(head2) : null;
54796
54940
  const branch = m ? m[1] : null;
54797
54941
  let sha2 = null;
54798
54942
  if (branch) {
54799
- sha2 = readFirstLine(join21(gitDir, "refs", "heads", branch));
54943
+ sha2 = readFirstLine(join20(gitDir, "refs", "heads", branch));
54800
54944
  if (!sha2) sha2 = shaFromPackedRefs(gitDir, `refs/heads/${branch}`);
54801
54945
  } else if (head2 && /^[0-9a-f]{7,40}$/i.test(head2)) {
54802
54946
  sha2 = head2;
@@ -54804,13 +54948,13 @@ function readGitRefState(gitDir) {
54804
54948
  return {
54805
54949
  branch,
54806
54950
  sha: sha2,
54807
- mergeHeadExists: existsSync17(join21(gitDir, "MERGE_HEAD")),
54808
- origHeadExists: existsSync17(join21(gitDir, "ORIG_HEAD"))
54951
+ mergeHeadExists: existsSync16(join20(gitDir, "MERGE_HEAD")),
54952
+ origHeadExists: existsSync16(join20(gitDir, "ORIG_HEAD"))
54809
54953
  };
54810
54954
  }
54811
54955
  function shaFromPackedRefs(gitDir, ref) {
54812
54956
  try {
54813
- for (const line of readFileSync16(join21(gitDir, "packed-refs"), "utf8").split(/\r?\n/)) {
54957
+ for (const line of readFileSync15(join20(gitDir, "packed-refs"), "utf8").split(/\r?\n/)) {
54814
54958
  const [sha2, name2] = line.split(/\s+/);
54815
54959
  if (name2 === ref && sha2) return sha2;
54816
54960
  }
@@ -54844,7 +54988,7 @@ function startGitSensor(gitDir, onEvent, opts = {}) {
54844
54988
  const settle = () => {
54845
54989
  if (timer) clearTimeout(timer);
54846
54990
  timer = setTimeout(() => {
54847
- if (existsSync17(join21(gitDir, "index.lock"))) {
54991
+ if (existsSync16(join20(gitDir, "index.lock"))) {
54848
54992
  settle();
54849
54993
  return;
54850
54994
  }
@@ -54855,7 +54999,7 @@ function startGitSensor(gitDir, onEvent, opts = {}) {
54855
54999
  }, debounceMs);
54856
55000
  };
54857
55001
  for (const sub of ["HEAD", "logs/HEAD", "MERGE_HEAD", "ORIG_HEAD"]) {
54858
- const p = join21(gitDir, sub);
55002
+ const p = join20(gitDir, sub);
54859
55003
  try {
54860
55004
  watchers.push(fsWatch(p, settle));
54861
55005
  } catch {
@@ -55080,21 +55224,21 @@ var TelemetryRecorder = class {
55080
55224
 
55081
55225
  // src/skills.ts
55082
55226
  import {
55083
- existsSync as existsSync18,
55227
+ existsSync as existsSync17,
55084
55228
  mkdirSync as mkdirSync6,
55085
- readFileSync as readFileSync17,
55229
+ readFileSync as readFileSync16,
55086
55230
  readdirSync as readdirSync7,
55087
55231
  unlinkSync as unlinkSync2,
55088
- writeFileSync as writeFileSync15
55232
+ writeFileSync as writeFileSync14
55089
55233
  } from "node:fs";
55090
- import { basename as basename4, join as join22 } from "node:path";
55234
+ import { basename as basename4, join as join21 } from "node:path";
55091
55235
  function skillFileName(id) {
55092
55236
  return `${id.replace(/[^A-Za-z0-9_.-]/g, "_")}.md`;
55093
55237
  }
55094
55238
  function readSkillManifest(manifestPath) {
55095
- if (!existsSync18(manifestPath)) return [];
55239
+ if (!existsSync17(manifestPath)) return [];
55096
55240
  try {
55097
- const parsed = JSON.parse(readFileSync17(manifestPath, "utf8"));
55241
+ const parsed = JSON.parse(readFileSync16(manifestPath, "utf8"));
55098
55242
  return (parsed.skills ?? []).map((s) => ({
55099
55243
  title: s.title ?? "",
55100
55244
  layer: s.layer ?? "technique",
@@ -55118,7 +55262,7 @@ async function syncSkills(paths, client, seed, pins = [], techSeed) {
55118
55262
  for (const s of res.skills) {
55119
55263
  const fileName = skillFileName(s.id);
55120
55264
  keep.add(fileName);
55121
- writeFileSync15(join22(paths.skillsDir, fileName), s.markdown, "utf8");
55265
+ writeFileSync14(join21(paths.skillsDir, fileName), s.markdown, "utf8");
55122
55266
  rows.push({
55123
55267
  id: s.id,
55124
55268
  title: s.title,
@@ -55131,7 +55275,7 @@ async function syncSkills(paths, client, seed, pins = [], techSeed) {
55131
55275
  const fileName = skillFileName(p.id);
55132
55276
  if (keep.has(fileName)) continue;
55133
55277
  keep.add(fileName);
55134
- writeFileSync15(join22(paths.skillsDir, fileName), p.markdown, "utf8");
55278
+ writeFileSync14(join21(paths.skillsDir, fileName), p.markdown, "utf8");
55135
55279
  rows.push({
55136
55280
  id: p.id,
55137
55281
  title: p.title,
@@ -55145,13 +55289,13 @@ async function syncSkills(paths, client, seed, pins = [], techSeed) {
55145
55289
  if (!f.endsWith(".md")) continue;
55146
55290
  if (keep.has(basename4(f))) continue;
55147
55291
  try {
55148
- unlinkSync2(join22(paths.skillsDir, f));
55292
+ unlinkSync2(join21(paths.skillsDir, f));
55149
55293
  pruned++;
55150
55294
  } catch {
55151
55295
  }
55152
55296
  }
55153
55297
  rows.sort((a, b) => a.id.localeCompare(b.id));
55154
- writeFileSync15(
55298
+ writeFileSync14(
55155
55299
  paths.skillsManifest,
55156
55300
  JSON.stringify({ generatedAt: Date.now(), skills: rows }, null, 2),
55157
55301
  "utf8"
@@ -55163,22 +55307,22 @@ async function syncSkills(paths, client, seed, pins = [], techSeed) {
55163
55307
  init_src2();
55164
55308
  import {
55165
55309
  cpSync,
55166
- existsSync as existsSync19,
55310
+ existsSync as existsSync18,
55167
55311
  lstatSync,
55168
55312
  mkdirSync as mkdirSync7,
55169
- readFileSync as readFileSync18,
55313
+ readFileSync as readFileSync17,
55170
55314
  readdirSync as readdirSync8,
55171
55315
  rmSync as rmSync2,
55172
55316
  symlinkSync,
55173
- writeFileSync as writeFileSync16
55317
+ writeFileSync as writeFileSync15
55174
55318
  } from "node:fs";
55175
- import { join as join23 } from "node:path";
55319
+ import { join as join22 } from "node:path";
55176
55320
  var SKILL_NS = "errata-";
55177
55321
  var HARNESS_SKILL_DIRS = [
55178
- { configDir: ".claude", skillsDir: join23(".claude", "skills") },
55322
+ { configDir: ".claude", skillsDir: join22(".claude", "skills") },
55179
55323
  // Cursor adopted the standard; its exact project dir is still moving — kept
55180
55324
  // best-effort and gated on `.cursor/` presence so we never create it blind.
55181
- { configDir: ".cursor", skillsDir: join23(".cursor", "skills") }
55325
+ { configDir: ".cursor", skillsDir: join22(".cursor", "skills") }
55182
55326
  ];
55183
55327
  function skillSlug(title, id) {
55184
55328
  const base = title.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || id.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "skill";
@@ -55189,9 +55333,9 @@ function yamlScalar(s) {
55189
55333
  }
55190
55334
  function deriveDescription(title, layer, body2) {
55191
55335
  const firstProse = body2.split(/\r?\n/).map((l) => l.trim()).find((l) => l.length > 0 && !l.startsWith("#") && !l.startsWith("---"));
55192
- const lead = firstProse && firstProse.length >= 24 ? firstProse : title;
55336
+ const lead2 = firstProse && firstProse.length >= 24 ? firstProse : title;
55193
55337
  const when = ` Apply when working on ${layer === "antipattern" ? "code that risks this pitfall" : "problems in this area"}.`;
55194
- return `${lead}${lead.endsWith(".") ? "" : "."}${when}`.slice(0, 1024);
55338
+ return `${lead2}${lead2.endsWith(".") ? "" : "."}${when}`.slice(0, 1024);
55195
55339
  }
55196
55340
  function renderSkillMd(name2, description, body2, citeHandle) {
55197
55341
  const footer = citeHandle ? `
@@ -55223,12 +55367,12 @@ function skillCiteHandle(s) {
55223
55367
  return priorHandle({ id: s.id, description: s.title });
55224
55368
  }
55225
55369
  function reconcileNamespaced(dir, keep) {
55226
- if (!existsSync19(dir)) return 0;
55370
+ if (!existsSync18(dir)) return 0;
55227
55371
  let pruned = 0;
55228
55372
  for (const name2 of readdirSync8(dir)) {
55229
55373
  if (!name2.startsWith(SKILL_NS) || keep.has(name2)) continue;
55230
55374
  try {
55231
- rmSync2(join23(dir, name2), { recursive: true, force: true });
55375
+ rmSync2(join22(dir, name2), { recursive: true, force: true });
55232
55376
  pruned++;
55233
55377
  } catch {
55234
55378
  }
@@ -55237,7 +55381,7 @@ function reconcileNamespaced(dir, keep) {
55237
55381
  }
55238
55382
  function linkOrCopy(linkPath, target) {
55239
55383
  try {
55240
- if (existsSync19(linkPath) || safeLstat(linkPath)) rmSync2(linkPath, { recursive: true, force: true });
55384
+ if (existsSync18(linkPath) || safeLstat(linkPath)) rmSync2(linkPath, { recursive: true, force: true });
55241
55385
  } catch {
55242
55386
  }
55243
55387
  try {
@@ -55258,7 +55402,7 @@ function safeLstat(p) {
55258
55402
  }
55259
55403
  }
55260
55404
  function emitAndProjectSkills(root, skills) {
55261
- const agentsSkillsDir = join23(root, ".agents", "skills");
55405
+ const agentsSkillsDir = join22(root, ".agents", "skills");
55262
55406
  mkdirSync7(agentsSkillsDir, { recursive: true });
55263
55407
  const slugs = [];
55264
55408
  const keep = /* @__PURE__ */ new Set();
@@ -55266,7 +55410,7 @@ function emitAndProjectSkills(root, skills) {
55266
55410
  for (const s of skills) {
55267
55411
  let body2;
55268
55412
  try {
55269
- body2 = readFileSync18(s.bodyPath, "utf8");
55413
+ body2 = readFileSync17(s.bodyPath, "utf8");
55270
55414
  } catch {
55271
55415
  continue;
55272
55416
  }
@@ -55275,9 +55419,9 @@ function emitAndProjectSkills(root, skills) {
55275
55419
  keep.add(slug2);
55276
55420
  slugs.push(slug2);
55277
55421
  const description = deriveDescription(s.title, s.layer, body2);
55278
- mkdirSync7(join23(agentsSkillsDir, slug2), { recursive: true });
55279
- writeFileSync16(
55280
- join23(agentsSkillsDir, slug2, "SKILL.md"),
55422
+ mkdirSync7(join22(agentsSkillsDir, slug2), { recursive: true });
55423
+ writeFileSync15(
55424
+ join22(agentsSkillsDir, slug2, "SKILL.md"),
55281
55425
  renderSkillMd(slug2, description, body2, skillCiteHandle(s)),
55282
55426
  "utf8"
55283
55427
  );
@@ -55286,11 +55430,11 @@ function emitAndProjectSkills(root, skills) {
55286
55430
  reconcileNamespaced(agentsSkillsDir, keep);
55287
55431
  let projected = 0;
55288
55432
  for (const h of HARNESS_SKILL_DIRS) {
55289
- if (!existsSync19(join23(root, h.configDir))) continue;
55290
- const dir = join23(root, h.skillsDir);
55433
+ if (!existsSync18(join22(root, h.configDir))) continue;
55434
+ const dir = join22(root, h.skillsDir);
55291
55435
  mkdirSync7(dir, { recursive: true });
55292
55436
  for (const slug2 of slugs) {
55293
- linkOrCopy(join23(dir, slug2), join23(agentsSkillsDir, slug2));
55437
+ linkOrCopy(join22(dir, slug2), join22(agentsSkillsDir, slug2));
55294
55438
  projected++;
55295
55439
  }
55296
55440
  reconcileNamespaced(dir, keep);
@@ -55299,15 +55443,15 @@ function emitAndProjectSkills(root, skills) {
55299
55443
  return { slugs, emitted, projected };
55300
55444
  }
55301
55445
  function emitInputsFromManifest(erretaDir, manifestPath) {
55302
- if (!existsSync19(manifestPath)) return [];
55446
+ if (!existsSync18(manifestPath)) return [];
55303
55447
  try {
55304
- const parsed = JSON.parse(readFileSync18(manifestPath, "utf8"));
55448
+ const parsed = JSON.parse(readFileSync17(manifestPath, "utf8"));
55305
55449
  return (parsed.skills ?? []).filter((s) => Boolean(s.id && s.file)).map((s) => ({
55306
55450
  id: s.id,
55307
55451
  title: s.title ?? s.id,
55308
55452
  layer: s.layer ?? "technique",
55309
55453
  confidence: s.confidence ?? 0,
55310
- bodyPath: join23(erretaDir, s.file)
55454
+ bodyPath: join22(erretaDir, s.file)
55311
55455
  }));
55312
55456
  } catch {
55313
55457
  return [];
@@ -55321,17 +55465,17 @@ var GITIGNORE_LINES = [
55321
55465
  ".cursor/skills/errata-*/"
55322
55466
  ];
55323
55467
  function ensureSkillGitignore(root) {
55324
- const path2 = join23(root, ".gitignore");
55468
+ const path2 = join22(root, ".gitignore");
55325
55469
  let current = "";
55326
55470
  try {
55327
- current = existsSync19(path2) ? readFileSync18(path2, "utf8") : "";
55471
+ current = existsSync18(path2) ? readFileSync17(path2, "utf8") : "";
55328
55472
  } catch {
55329
55473
  return;
55330
55474
  }
55331
55475
  if (current.includes(GITIGNORE_MARK)) return;
55332
55476
  const prefix = current.length > 0 && !current.endsWith("\n") ? "\n" : "";
55333
55477
  try {
55334
- writeFileSync16(path2, `${current}${prefix}
55478
+ writeFileSync15(path2, `${current}${prefix}
55335
55479
  ${GITIGNORE_LINES.join("\n")}
55336
55480
  `, "utf8");
55337
55481
  } catch {
@@ -55428,20 +55572,20 @@ init_paths();
55428
55572
  // src/profile.ts
55429
55573
  init_src2();
55430
55574
  init_paths();
55431
- import { existsSync as existsSync21, readFileSync as readFileSync20, writeFileSync as writeFileSync17 } from "node:fs";
55575
+ import { existsSync as existsSync20, readFileSync as readFileSync19, writeFileSync as writeFileSync16 } from "node:fs";
55432
55576
  import { createHash as createHash12 } from "node:crypto";
55433
- import { join as join25 } from "node:path";
55577
+ import { join as join24 } from "node:path";
55434
55578
 
55435
55579
  // src/git-remote.ts
55436
55580
  init_src();
55437
- import { existsSync as existsSync20, readFileSync as readFileSync19, statSync as statSync4 } from "node:fs";
55438
- import { isAbsolute as isAbsolute3, join as join24, resolve as resolve5 } from "node:path";
55581
+ import { existsSync as existsSync19, readFileSync as readFileSync18, statSync as statSync4 } from "node:fs";
55582
+ import { isAbsolute as isAbsolute3, join as join23, resolve as resolve5 } from "node:path";
55439
55583
  function resolveGitDir(root) {
55440
- const dotGit = join24(root, ".git");
55584
+ const dotGit = join23(root, ".git");
55441
55585
  try {
55442
55586
  const st = statSync4(dotGit);
55443
55587
  if (st.isDirectory()) return dotGit;
55444
- const m = /^gitdir:\s*(.+?)\s*$/m.exec(readFileSync19(dotGit, "utf8"));
55588
+ const m = /^gitdir:\s*(.+?)\s*$/m.exec(readFileSync18(dotGit, "utf8"));
55445
55589
  if (!m) return null;
55446
55590
  const dir = m[1];
55447
55591
  return isAbsolute3(dir) ? dir : resolve5(root, dir);
@@ -55450,22 +55594,22 @@ function resolveGitDir(root) {
55450
55594
  }
55451
55595
  }
55452
55596
  function gitConfigPath(gitDir) {
55453
- const commondirFile = join24(gitDir, "commondir");
55454
- if (existsSync20(commondirFile)) {
55455
- const common = readFileSync19(commondirFile, "utf8").trim();
55597
+ const commondirFile = join23(gitDir, "commondir");
55598
+ if (existsSync19(commondirFile)) {
55599
+ const common = readFileSync18(commondirFile, "utf8").trim();
55456
55600
  const commonDir = isAbsolute3(common) ? common : resolve5(gitDir, common);
55457
- return join24(commonDir, "config");
55601
+ return join23(commonDir, "config");
55458
55602
  }
55459
- return join24(gitDir, "config");
55603
+ return join23(gitDir, "config");
55460
55604
  }
55461
55605
  function readRemotes(root) {
55462
55606
  const gitDir = resolveGitDir(root);
55463
55607
  if (!gitDir) return [];
55464
55608
  const cfgPath = gitConfigPath(gitDir);
55465
- if (!existsSync20(cfgPath)) return [];
55609
+ if (!existsSync19(cfgPath)) return [];
55466
55610
  let txt;
55467
55611
  try {
55468
- txt = readFileSync19(cfgPath, "utf8");
55612
+ txt = readFileSync18(cfgPath, "utf8");
55469
55613
  } catch {
55470
55614
  return [];
55471
55615
  }
@@ -55507,13 +55651,13 @@ function refreshRepoLocator(root, profile) {
55507
55651
  }
55508
55652
  function loadProfile(root) {
55509
55653
  const p = workspacePaths(root);
55510
- if (!existsSync21(p.workspaceJson)) return null;
55511
- return JSON.parse(readFileSync20(p.workspaceJson, "utf8"));
55654
+ if (!existsSync20(p.workspaceJson)) return null;
55655
+ return JSON.parse(readFileSync19(p.workspaceJson, "utf8"));
55512
55656
  }
55513
55657
  function saveProfile(root, profile) {
55514
55658
  const p = workspacePaths(root);
55515
55659
  ensureDir(p.configDir);
55516
- writeFileSync17(p.workspaceJson, JSON.stringify(profile, null, 2), "utf8");
55660
+ writeFileSync16(p.workspaceJson, JSON.stringify(profile, null, 2), "utf8");
55517
55661
  }
55518
55662
  function autodetectProfile(root) {
55519
55663
  const id = workspaceId(root);
@@ -55521,10 +55665,10 @@ function autodetectProfile(root) {
55521
55665
  const p = emptyProfile(id, name2);
55522
55666
  const locator = detectRepoLocator(root);
55523
55667
  if (locator) p.repoLocator = locator;
55524
- const pkgPath = join25(root, "package.json");
55525
- if (existsSync21(pkgPath)) {
55668
+ const pkgPath = join24(root, "package.json");
55669
+ if (existsSync20(pkgPath)) {
55526
55670
  try {
55527
- const pkg = JSON.parse(readFileSync20(pkgPath, "utf8"));
55671
+ const pkg = JSON.parse(readFileSync19(pkgPath, "utf8"));
55528
55672
  p.languages.push("typescript", "javascript");
55529
55673
  const nodeVer = pkg.engines?.node ?? "node";
55530
55674
  p.stack.push(`node@${nodeVer}`);
@@ -55545,10 +55689,10 @@ function autodetectProfile(root) {
55545
55689
  } catch {
55546
55690
  }
55547
55691
  }
55548
- const pyproject = join25(root, "pyproject.toml");
55549
- if (existsSync21(pyproject)) {
55692
+ const pyproject = join24(root, "pyproject.toml");
55693
+ if (existsSync20(pyproject)) {
55550
55694
  try {
55551
- const txt = readFileSync20(pyproject, "utf8");
55695
+ const txt = readFileSync19(pyproject, "utf8");
55552
55696
  const py = /python\s*=\s*"([^"]+)"/.exec(txt)?.[1];
55553
55697
  p.languages.push("python");
55554
55698
  p.stack.push(`python@${py ?? "3"}`);
@@ -55559,16 +55703,16 @@ function autodetectProfile(root) {
55559
55703
  } catch {
55560
55704
  }
55561
55705
  }
55562
- const reqs = join25(root, "requirements.txt");
55563
- if (existsSync21(reqs)) {
55706
+ const reqs = join24(root, "requirements.txt");
55707
+ if (existsSync20(reqs)) {
55564
55708
  if (!p.languages.includes("python")) p.languages.push("python");
55565
55709
  if (!p.stack.includes("python@3")) p.stack.push("python@3");
55566
55710
  }
55567
- if (existsSync21(join25(root, "go.mod"))) {
55711
+ if (existsSync20(join24(root, "go.mod"))) {
55568
55712
  p.languages.push("go");
55569
55713
  p.stack.push("go");
55570
55714
  }
55571
- if (existsSync21(join25(root, "Cargo.toml"))) {
55715
+ if (existsSync20(join24(root, "Cargo.toml"))) {
55572
55716
  p.languages.push("rust");
55573
55717
  p.stack.push("rust");
55574
55718
  }
@@ -55578,18 +55722,18 @@ function autodetectProfile(root) {
55578
55722
  }
55579
55723
 
55580
55724
  // src/witness-queue.ts
55581
- import { readFileSync as readFileSync21, renameSync as renameSync2, writeFileSync as writeFileSync18 } from "node:fs";
55582
- import { dirname as dirname9, join as join26 } from "node:path";
55725
+ import { readFileSync as readFileSync20, renameSync as renameSync2, writeFileSync as writeFileSync17 } from "node:fs";
55726
+ import { dirname as dirname9, join as join25 } from "node:path";
55583
55727
  var WITNESS_QUEUE_CAP = 500;
55584
55728
  var WITNESS_TTL_MS = 14 * 24 * 60 * 60 * 1e3;
55585
55729
  var WITNESS_MAX_ATTEMPTS = 5;
55586
55730
  function witnessQueuePath(workspaceConfigDir) {
55587
- return join26(workspaceConfigDir, "witness-queue.json");
55731
+ return join25(workspaceConfigDir, "witness-queue.json");
55588
55732
  }
55589
55733
  function loadWitnessQueueWithLosses(path2) {
55590
55734
  let raw2;
55591
55735
  try {
55592
- raw2 = JSON.parse(readFileSync21(path2, "utf8"));
55736
+ raw2 = JSON.parse(readFileSync20(path2, "utf8"));
55593
55737
  } catch (err2) {
55594
55738
  const absent = err2?.code === "ENOENT";
55595
55739
  return { queue: [], fileUnreadable: !absent, malformedEntries: 0 };
@@ -55602,8 +55746,8 @@ function loadWitnessQueueWithLosses(path2) {
55602
55746
  }
55603
55747
  function saveWitnessQueue(path2, queue) {
55604
55748
  try {
55605
- const tmp = join26(dirname9(path2), `.${Date.now()}.witness-queue.tmp`);
55606
- writeFileSync18(tmp, JSON.stringify(queue), "utf8");
55749
+ const tmp = join25(dirname9(path2), `.${Date.now()}.witness-queue.tmp`);
55750
+ writeFileSync17(tmp, JSON.stringify(queue), "utf8");
55607
55751
  renameSync2(tmp, path2);
55608
55752
  } catch {
55609
55753
  }
@@ -55955,7 +56099,7 @@ function startLoopLagMonitor(thresholdMs = 1e3) {
55955
56099
  }
55956
56100
 
55957
56101
  // src/engine.ts
55958
- var DAEMON_VERSION = true ? "2.0.2-dev.793" : "2.0.0-alpha.0";
56102
+ var DAEMON_VERSION = true ? "2.0.2-dev.831" : "2.0.0-alpha.0";
55959
56103
  var IGNORED_PATH = /[\\/](?:\.git|node_modules|\.errata|\.claude|\.codex|\.cursor|\.turbo|\.next|dist|coverage|test-results|playwright-report|__pycache__)(?:[\\/]|$)/;
55960
56104
  var IGNORED_NOISE = /castalia\.db|eventlog\.sqlite|turn-cursors/;
55961
56105
  var GIT_OP_MUTE_MS = 4e3;
@@ -55965,7 +56109,7 @@ var TURN_REPLAY_LOOKBACK_MS = 7 * 24 * 60 * 6e4;
55965
56109
  function appendIdentityAudit(path2, record2, line) {
55966
56110
  if (!record2.accepted && record2.score <= 0) return;
55967
56111
  try {
55968
- if (existsSync23(path2) && statSync5(path2).size >= IDENTITY_AUDIT_MAX_BYTES) {
56112
+ if (existsSync22(path2) && statSync5(path2).size >= IDENTITY_AUDIT_MAX_BYTES) {
55969
56113
  renameSync3(path2, `${path2}.1`);
55970
56114
  }
55971
56115
  appendFileSync4(path2, line);
@@ -55975,7 +56119,7 @@ function appendIdentityAudit(path2, record2, line) {
55975
56119
  var yieldToLoop = () => new Promise((r) => setImmediate(r));
55976
56120
  function loadTurnCursors(path2) {
55977
56121
  try {
55978
- const raw2 = JSON.parse(readFileSync23(path2, "utf8"));
56122
+ const raw2 = JSON.parse(readFileSync22(path2, "utf8"));
55979
56123
  return new Map(
55980
56124
  Object.entries(raw2).map(([k, v]) => [k, typeof v === "string" ? v : String(v?.uuid ?? "")])
55981
56125
  );
@@ -55985,7 +56129,7 @@ function loadTurnCursors(path2) {
55985
56129
  }
55986
56130
  function loadTurnOffsets(path2) {
55987
56131
  try {
55988
- const raw2 = JSON.parse(readFileSync23(path2, "utf8"));
56132
+ const raw2 = JSON.parse(readFileSync22(path2, "utf8"));
55989
56133
  const out2 = /* @__PURE__ */ new Map();
55990
56134
  for (const [k, v] of Object.entries(raw2)) {
55991
56135
  const off = typeof v === "object" && v !== null ? v.offset : void 0;
@@ -56001,7 +56145,7 @@ function saveTurnCursors(path2, cursors, offsets) {
56001
56145
  const merged = {};
56002
56146
  for (const [k, uuid3] of cursors) merged[k] = { uuid: uuid3, offset: offsets.get(k) ?? 0 };
56003
56147
  for (const [k, offset] of offsets) if (!merged[k]) merged[k] = { uuid: "", offset };
56004
- writeFileSync20(path2, JSON.stringify(merged), "utf8");
56148
+ writeFileSync19(path2, JSON.stringify(merged), "utf8");
56005
56149
  } catch {
56006
56150
  }
56007
56151
  }
@@ -56023,7 +56167,7 @@ function gitSourceWatchTargets(root) {
56023
56167
  ["-C", root, "ls-files", "--others", "--ignored", "--exclude-standard", "--directory", "-z"],
56024
56168
  { encoding: "utf8", maxBuffer: 256 * 1024 * 1024, windowsHide: true, stdio: ["ignore", "pipe", "ignore"] }
56025
56169
  );
56026
- ignoredDirs = igOut.split("\0").filter(Boolean).map((d) => d.replace(/\/+$/, "")).filter((d) => !IGNORED_PATH.test(join28(root, d) + sep4));
56170
+ ignoredDirs = igOut.split("\0").filter(Boolean).map((d) => d.replace(/\/+$/, "")).filter((d) => !IGNORED_PATH.test(join27(root, d) + sep4));
56027
56171
  } catch {
56028
56172
  }
56029
56173
  const hasIgnoredChild = (dir) => ignoredDirs.some((ig) => ig.startsWith(dir + "/"));
@@ -56035,19 +56179,19 @@ function gitSourceWatchTargets(root) {
56035
56179
  if (!f.startsWith(prefix)) continue;
56036
56180
  const rest2 = f.slice(prefix.length);
56037
56181
  if (rest2.includes("/")) children.add(dir === "" ? rest2.slice(0, rest2.indexOf("/")) : dir + "/" + rest2.slice(0, rest2.indexOf("/")));
56038
- else targets.add(join28(root, f));
56182
+ else targets.add(join27(root, f));
56039
56183
  }
56040
56184
  for (const c of children) {
56041
- if (IGNORED_PATH.test(join28(root, c) + sep4)) continue;
56185
+ if (IGNORED_PATH.test(join27(root, c) + sep4)) continue;
56042
56186
  if (hasIgnoredChild(c)) addUnder(c);
56043
- else targets.add(join28(root, c));
56187
+ else targets.add(join27(root, c));
56044
56188
  }
56045
56189
  };
56046
56190
  addUnder("");
56047
56191
  if (targets.size > 0) return [...targets];
56048
56192
  } catch {
56049
56193
  }
56050
- return readdirSync9(root, { withFileTypes: true }).filter((e) => e.isDirectory() && !IGNORED_PATH.test(join28(root, String(e.name)) + sep4)).map((e) => join28(root, String(e.name)));
56194
+ return readdirSync9(root, { withFileTypes: true }).filter((e) => e.isDirectory() && !IGNORED_PATH.test(join27(root, String(e.name)) + sep4)).map((e) => join27(root, String(e.name)));
56051
56195
  }
56052
56196
  function createWorkspaceEngine(opts) {
56053
56197
  const paths = workspacePaths(opts.workspaceRoot);
@@ -56216,7 +56360,7 @@ function createWorkspaceEngine(opts) {
56216
56360
  const srcPaths = diff.changedPaths.filter((p) => /\.(ts|tsx|js|jsx|mjs|cjs|py)$/i.test(p));
56217
56361
  let episodeId2;
56218
56362
  if (srcPaths.length > 0) {
56219
- const abs = srcPaths.map((p) => join28(opts.workspaceRoot, p));
56363
+ const abs = srcPaths.map((p) => join27(opts.workspaceRoot, p));
56220
56364
  try {
56221
56365
  const r = await runReindexPass(
56222
56366
  `git-reindex:${profile.name} (${abs.length} files)`,
@@ -56252,8 +56396,8 @@ function createWorkspaceEngine(opts) {
56252
56396
  `[errata] git: ${ev.kind} ${ev.newSha.slice(0, 7)} by ${meta3.authorName} \u2014 ${diff.changedPaths.length} file(s), ${diff.renames.length} rename(s)`
56253
56397
  );
56254
56398
  };
56255
- const gitDir = join28(opts.workspaceRoot, ".git");
56256
- if (existsSync23(gitDir)) {
56399
+ const gitDir = join27(opts.workspaceRoot, ".git");
56400
+ if (existsSync22(gitDir)) {
56257
56401
  stopGit = startGitSensor(gitDir, (ev) => {
56258
56402
  void handleGitEvent(ev).catch((err2) => {
56259
56403
  console.warn("[errata] git event handler failed:", err2);
@@ -56417,10 +56561,10 @@ function createWorkspaceEngine(opts) {
56417
56561
  console.warn("[errata] render ledger failed:", err2.message?.slice(0, 120));
56418
56562
  }
56419
56563
  writeContextFile(opts.workspaceRoot, body2);
56420
- const target = join28(opts.workspaceRoot, "AGENTS.md");
56564
+ const target = join27(opts.workspaceRoot, "AGENTS.md");
56421
56565
  writeManagedBlock(target, { body: AGENTS_POINTER_BODY, stable: true, force: true });
56422
56566
  if (elicit) {
56423
- writePrimingHandles(join28(paths.configDir, "priming-handles.json"), [
56567
+ writePrimingHandles(join27(paths.configDir, "priming-handles.json"), [
56424
56568
  ...snapshot.recentProblems.map((r) => r.node),
56425
56569
  // Resolved-band handles: the ✓ problem AND its Solution are citable
56426
56570
  // (a fix tag on an already-resolved problem no-ops idempotently; the
@@ -56702,7 +56846,7 @@ function createWorkspaceEngine(opts) {
56702
56846
  resultSummary: { exitCode: e.exitCode ?? 1, errorTokens: e.errorTokens }
56703
56847
  });
56704
56848
  };
56705
- const turnCursorPath = join28(paths.configDir, "turn-cursors.json");
56849
+ const turnCursorPath = join27(paths.configDir, "turn-cursors.json");
56706
56850
  const lastTurnUuid = loadTurnCursors(turnCursorPath);
56707
56851
  const turnOffset = loadTurnOffsets(turnCursorPath);
56708
56852
  const readLosses = { parseFailures: 0, ioFailures: 0, bytesUnreachable: 0, sliceGuardHits: 0 };
@@ -56739,7 +56883,7 @@ function createWorkspaceEngine(opts) {
56739
56883
  let processedTurns = 0;
56740
56884
  const seqAtStart = store.currentIngestSeq();
56741
56885
  const elicit = isEdgeElicitationEnabled();
56742
- const handleMap = elicit ? readPrimingHandles(join28(paths.configDir, "priming-handles.json")) : {};
56886
+ const handleMap = elicit ? readPrimingHandles(join27(paths.configDir, "priming-handles.json")) : {};
56743
56887
  const wsRoot = (opts.workspaceRoot ?? "").replace(/\\/g, "/");
56744
56888
  const toRel = (abs) => {
56745
56889
  const p = abs.replace(/\\/g, "/");
@@ -57526,7 +57670,7 @@ function createWorkspaceEngine(opts) {
57526
57670
  try {
57527
57671
  const inputs = emitInputsFromManifest(paths.configDir, paths.skillsManifest);
57528
57672
  emitAndProjectSkills(opts.workspaceRoot, inputs);
57529
- writePrimingHandles(join28(paths.configDir, "priming-handles.json"), skillHandleNodes(inputs));
57673
+ writePrimingHandles(join27(paths.configDir, "priming-handles.json"), skillHandleNodes(inputs));
57530
57674
  } catch (err2) {
57531
57675
  console.warn("[skills] agent-skills projection failed (non-fatal):", err2 instanceof Error ? err2.message : err2);
57532
57676
  }
@@ -57654,19 +57798,6 @@ function createWorkspaceEngine(opts) {
57654
57798
  },
57655
57799
  async nightly() {
57656
57800
  const report = (await runNightly()).report;
57657
- const summarizer = opts.intentSummarizer ?? envIntentSummarizer();
57658
- if (summarizer) {
57659
- try {
57660
- const s = await runSymbolSummarySweep(store, opts.workspaceRoot, paths.configDir, summarizer);
57661
- if (s.generated > 0 || s.rejected > 0) {
57662
- console.log(
57663
- `[errata] symbol summaries: +${s.generated}${s.rejected > 0 ? ` (${s.rejected} rejected by no-verbatim check)` : ""}${s.remaining > 0 ? `, ${s.remaining} pending` : ""}`
57664
- );
57665
- }
57666
- } catch (err2) {
57667
- console.warn("[errata] symbol summary sweep failed:", err2 instanceof Error ? err2.message : err2);
57668
- }
57669
- }
57670
57801
  appendPassLedger(paths.configDir, "graph-rescore", report.durationMs, {
57671
57802
  scoredNodes: report.scoredNodes,
57672
57803
  landmarks: report.landmarks,
@@ -57794,7 +57925,7 @@ function createWorkspaceEngine(opts) {
57794
57925
  console.log(
57795
57926
  "[errata] sync skipped \u2014 cloud sync consent is off (enable with `errata consent sync on`)"
57796
57927
  );
57797
- const pending = existsSync23(paths.outbox) ? readdirSync9(paths.outbox).filter((f) => f.endsWith(".json")).length : 0;
57928
+ const pending = existsSync22(paths.outbox) ? readdirSync9(paths.outbox).filter((f) => f.endsWith(".json")).length : 0;
57798
57929
  return { uploaded: 0, failed: 0, remaining: pending };
57799
57930
  }
57800
57931
  try {
@@ -57881,7 +58012,7 @@ async function startDaemon(opts) {
57881
58012
  reviewUrl: () => webUiUrl + "/review"
57882
58013
  });
57883
58014
  const writeLockFile = (url2) => {
57884
- writeFileSync21(
58015
+ writeFileSync20(
57885
58016
  engine.paths.daemonLock,
57886
58017
  JSON.stringify({ pid: process.pid, webUiUrl: url2, startedAt: Date.now() }),
57887
58018
  "utf8"
@@ -57924,7 +58055,7 @@ async function startDaemon(opts) {
57924
58055
  );
57925
58056
  await engine.stop();
57926
58057
  try {
57927
- if (existsSync24(engine.paths.daemonLock)) {
58058
+ if (existsSync23(engine.paths.daemonLock)) {
57928
58059
  }
57929
58060
  } catch {
57930
58061
  }
@@ -57946,7 +58077,7 @@ init_identity2();
57946
58077
  // src/multi.ts
57947
58078
  init_dist();
57948
58079
  init_src5();
57949
- import { existsSync as existsSync29, readFileSync as readFileSync27, unlinkSync as unlinkSync3, writeFileSync as writeFileSync22 } from "node:fs";
58080
+ import { existsSync as existsSync28, readFileSync as readFileSync26, unlinkSync as unlinkSync3, writeFileSync as writeFileSync21 } from "node:fs";
57950
58081
 
57951
58082
  // src/principle-sync.ts
57952
58083
  init_src5();
@@ -57974,8 +58105,8 @@ init_reconcile();
57974
58105
 
57975
58106
  // src/lockfile-auto.ts
57976
58107
  init_src();
57977
- import { existsSync as existsSync25, readFileSync as readFileSync24 } from "node:fs";
57978
- import { join as join29 } from "node:path";
58108
+ import { existsSync as existsSync24, readFileSync as readFileSync23 } from "node:fs";
58109
+ import { join as join28 } from "node:path";
57979
58110
 
57980
58111
  // src/package-index.ts
57981
58112
  init_src();
@@ -58124,11 +58255,11 @@ function runLockfilePass(opts) {
58124
58255
  { file: "package-lock.json", parse: parsePackageLockJson }
58125
58256
  ];
58126
58257
  for (const c of candidates) {
58127
- const p = join29(opts.root, c.file);
58128
- if (!existsSync25(p)) continue;
58258
+ const p = join28(opts.root, c.file);
58259
+ if (!existsSync24(p)) continue;
58129
58260
  let sbom;
58130
58261
  try {
58131
- sbom = c.parse(readFileSync24(p, "utf8"));
58262
+ sbom = c.parse(readFileSync23(p, "utf8"));
58132
58263
  } catch {
58133
58264
  continue;
58134
58265
  }
@@ -58185,8 +58316,8 @@ function noveltyAgainst(node2, neighbors, opts = {}) {
58185
58316
  }
58186
58317
 
58187
58318
  // src/public-symbols.ts
58188
- import { readFileSync as readFileSync25, readdirSync as readdirSync10, existsSync as existsSync26 } from "node:fs";
58189
- import { join as join30 } from "node:path";
58319
+ import { readFileSync as readFileSync24, readdirSync as readdirSync10, existsSync as existsSync25 } from "node:fs";
58320
+ import { join as join29 } from "node:path";
58190
58321
  var HEAD_BYTES = 8 * 1024;
58191
58322
  var INDEX_TTL_MS = 10 * 60 * 1e3;
58192
58323
  var MIN_SYMBOL_LEN = 4;
@@ -58219,20 +58350,20 @@ function bindingNames(clause) {
58219
58350
  function internalPackageNames(workspaceRoot) {
58220
58351
  const names = /* @__PURE__ */ new Set();
58221
58352
  const tryRead = (dir) => {
58222
- const pj = join30(dir, "package.json");
58223
- if (!existsSync26(pj)) return;
58353
+ const pj = join29(dir, "package.json");
58354
+ if (!existsSync25(pj)) return;
58224
58355
  try {
58225
- const name2 = JSON.parse(readFileSync25(pj, "utf8")).name;
58356
+ const name2 = JSON.parse(readFileSync24(pj, "utf8")).name;
58226
58357
  if (typeof name2 === "string" && name2.length > 0) names.add(name2);
58227
58358
  } catch {
58228
58359
  }
58229
58360
  };
58230
58361
  tryRead(workspaceRoot);
58231
58362
  for (const group of ["packages", "apps"]) {
58232
- const groupDir = join30(workspaceRoot, group);
58233
- if (!existsSync26(groupDir)) continue;
58363
+ const groupDir = join29(workspaceRoot, group);
58364
+ if (!existsSync25(groupDir)) continue;
58234
58365
  try {
58235
- for (const entry of readdirSync10(groupDir)) tryRead(join30(groupDir, entry));
58366
+ for (const entry of readdirSync10(groupDir)) tryRead(join29(groupDir, entry));
58236
58367
  } catch {
58237
58368
  }
58238
58369
  }
@@ -58245,7 +58376,7 @@ function publicSymbolIndex(store, workspaceRoot, deps = {}) {
58245
58376
  if (cached2 && now - cached2.builtAt < INDEX_TTL_MS) return cached2;
58246
58377
  const readHead = deps.readHead ?? ((absPath) => {
58247
58378
  try {
58248
- return readFileSync25(absPath, "utf8").slice(0, HEAD_BYTES);
58379
+ return readFileSync24(absPath, "utf8").slice(0, HEAD_BYTES);
58249
58380
  } catch {
58250
58381
  return "";
58251
58382
  }
@@ -58265,7 +58396,7 @@ function publicSymbolIndex(store, workspaceRoot, deps = {}) {
58265
58396
  }
58266
58397
  const symbols = /* @__PURE__ */ new Set();
58267
58398
  for (const rel of files) {
58268
- const head2 = readHead(join30(workspaceRoot, rel));
58399
+ const head2 = readHead(join29(workspaceRoot, rel));
58269
58400
  if (!head2) continue;
58270
58401
  for (const re of [NAMED_IMPORT_RE, REQUIRE_RE]) {
58271
58402
  re.lastIndex = 0;
@@ -58755,7 +58886,6 @@ function buildCausalEdgeBackfill(store, profile, daemonVersion) {
58755
58886
 
58756
58887
  // src/multi.ts
58757
58888
  init_generalize_graph();
58758
- init_symbol_summaries();
58759
58889
  init_webui();
58760
58890
 
58761
58891
  // src/consolidate-worker-client.ts
@@ -58856,7 +58986,7 @@ var ConsolidateWorker = class {
58856
58986
  init_paths();
58857
58987
 
58858
58988
  // src/lock.ts
58859
- import { existsSync as existsSync27, readFileSync as readFileSync26 } from "node:fs";
58989
+ import { existsSync as existsSync26, readFileSync as readFileSync25 } from "node:fs";
58860
58990
  function isProcessAlive(pid) {
58861
58991
  if (!pid || pid <= 0) return false;
58862
58992
  try {
@@ -58867,9 +58997,9 @@ function isProcessAlive(pid) {
58867
58997
  }
58868
58998
  }
58869
58999
  function readDaemonLock(lockPath) {
58870
- if (!existsSync27(lockPath)) return null;
59000
+ if (!existsSync26(lockPath)) return null;
58871
59001
  try {
58872
- const lock = JSON.parse(readFileSync26(lockPath, "utf8"));
59002
+ const lock = JSON.parse(readFileSync25(lockPath, "utf8"));
58873
59003
  return typeof lock.pid === "number" ? lock : null;
58874
59004
  } catch {
58875
59005
  return null;
@@ -59157,12 +59287,12 @@ async function reanchorProject(opts) {
59157
59287
  init_registry();
59158
59288
 
59159
59289
  // src/adopt.ts
59160
- import { existsSync as existsSync28 } from "node:fs";
59161
- import { dirname as dirname10, join as join31 } from "node:path";
59290
+ import { existsSync as existsSync27 } from "node:fs";
59291
+ import { dirname as dirname10, join as join30 } from "node:path";
59162
59292
  function findGitRoot(absPath) {
59163
59293
  let dir = absPath;
59164
59294
  for (let depth = 0; depth < 64; depth++) {
59165
- if (existsSync28(join31(dir, ".git"))) return dir;
59295
+ if (existsSync27(join30(dir, ".git"))) return dir;
59166
59296
  const parent = dirname10(dir);
59167
59297
  if (parent === dir) return null;
59168
59298
  dir = parent;
@@ -59290,6 +59420,18 @@ async function startMultiDaemon(opts = {}) {
59290
59420
  const clearIdentityBlock = (wsId) => {
59291
59421
  if (identityBlocks.delete(wsId)) console.log(`[identity] workspace unblocked \u2014 spooled capture drains on this pass`);
59292
59422
  };
59423
+ const projectHolds = /* @__PURE__ */ new Map();
59424
+ const noteProjectHold = (wsId, wsName, reason) => {
59425
+ if (!projectHolds.has(wsId)) {
59426
+ projectHolds.set(wsId, { workspace: wsName, reason, since: Date.now() });
59427
+ console.error(
59428
+ `[project] HOLDING cloud push for workspace "${wsName}": cannot prove its project \u2014 ${reason}. Shipping without the assertion would publish project-scoped knowledge to the whole org; the batch stays pending instead.`
59429
+ );
59430
+ }
59431
+ };
59432
+ const clearProjectHold = (wsId) => {
59433
+ if (projectHolds.delete(wsId)) console.log(`[project] project assertion restored \u2014 held contributions drain on this pass`);
59434
+ };
59293
59435
  const cloudForIdentity = (identity) => {
59294
59436
  if (identity.invalid) return blockedCloudClient(identity.reason);
59295
59437
  if (identity.rule === "workspace-binding" && identity.profileName) {
@@ -59368,7 +59510,26 @@ async function startMultiDaemon(opts = {}) {
59368
59510
  units: boundaryFlushUnits,
59369
59511
  items: boundaryFlushItems,
59370
59512
  chunks: boundaryFlushBatches,
59371
- stalledMs: boundaryFlushLastAdvanceAt ? Date.now() - boundaryFlushLastAdvanceAt : 0
59513
+ stalledMs: boundaryFlushLastAdvanceAt ? Date.now() - boundaryFlushLastAdvanceAt : 0,
59514
+ // Held workspaces, so a hold is REPORTABLE and not merely logged once at the
59515
+ // transition. `errata status` reads this rather than the on-disk profile:
59516
+ // the profile records what the workspace INTENDS to assert, which is why
59517
+ // status could print "→ project 019f462d" for hours while every batch was
59518
+ // being held or shipped unlinked. A hold is the daemon's actual behavior.
59519
+ holds: [
59520
+ ...[...projectHolds.values()].map((h) => ({
59521
+ workspace: h.workspace,
59522
+ kind: "project",
59523
+ reason: h.reason,
59524
+ sinceMs: Date.now() - h.since
59525
+ })),
59526
+ ...[...identityBlocks.values()].map((h) => ({
59527
+ workspace: h.workspace,
59528
+ kind: "identity",
59529
+ reason: h.reason,
59530
+ sinceMs: Date.now() - h.since
59531
+ }))
59532
+ ]
59372
59533
  });
59373
59534
  const endFlush = () => {
59374
59535
  boundaryFlushing = false;
@@ -59479,7 +59640,7 @@ async function startMultiDaemon(opts = {}) {
59479
59640
  app.route(`/ws/${rec.id}`, rec.webApp);
59480
59641
  }
59481
59642
  try {
59482
- writeFileSync22(
59643
+ writeFileSync21(
59483
59644
  rec.engine.paths.daemonLock,
59484
59645
  JSON.stringify({ pid: process.pid, webUiUrl: `${baseUrl}/ws/${rec.id}`, startedAt: Date.now() }),
59485
59646
  "utf8"
@@ -59666,7 +59827,7 @@ async function startMultiDaemon(opts = {}) {
59666
59827
  lastActiveAt = Math.max(lastActiveAt, rec.engine.lastActivityAt());
59667
59828
  } catch {
59668
59829
  }
59669
- const reason = retireDecision({ exists: existsSync29(rec.root), lastActiveAt, now });
59830
+ const reason = retireDecision({ exists: existsSync28(rec.root), lastActiveAt, now });
59670
59831
  if (reason) void retireWorkspace(rec, reason);
59671
59832
  }
59672
59833
  };
@@ -59707,7 +59868,7 @@ async function startMultiDaemon(opts = {}) {
59707
59868
  baseUrl = `http://127.0.0.1:${port}`;
59708
59869
  try {
59709
59870
  ensureDir(globalDir());
59710
- writeFileSync22(
59871
+ writeFileSync21(
59711
59872
  lockPath,
59712
59873
  JSON.stringify({ pid: process.pid, webUiUrl: baseUrl, startedAt: Date.now() }),
59713
59874
  "utf8"
@@ -59716,7 +59877,7 @@ async function startMultiDaemon(opts = {}) {
59716
59877
  }
59717
59878
  for (const r of records) {
59718
59879
  try {
59719
- writeFileSync22(
59880
+ writeFileSync21(
59720
59881
  r.engine.paths.daemonLock,
59721
59882
  JSON.stringify({ pid: process.pid, webUiUrl: `${baseUrl}/ws/${r.id}`, startedAt: Date.now() }),
59722
59883
  "utf8"
@@ -60103,6 +60264,27 @@ async function startMultiDaemon(opts = {}) {
60103
60264
  const client = poolFor(recordIdentity);
60104
60265
  const store = r.engine.store;
60105
60266
  const projectName = r.engine.profile.name ?? r.engine.profile.id;
60267
+ const onDiskProjectId = loadProfile(r.root)?.projectId;
60268
+ if (onDiskProjectId !== r.engine.profile.projectId) {
60269
+ if (onDiskProjectId) r.engine.profile.projectId = onDiskProjectId;
60270
+ else delete r.engine.profile.projectId;
60271
+ console.log(
60272
+ `[project] workspace "${r.entry.name}" relinked on disk \u2192 ${onDiskProjectId ? onDiskProjectId.slice(0, 8) : "(unlinked)"} \u2014 picked up without a restart`
60273
+ );
60274
+ }
60275
+ const projectId = r.engine.profile.projectId;
60276
+ let project;
60277
+ if (projectId) {
60278
+ try {
60279
+ project = await resolveProjectSymbolSalt(client, projectId);
60280
+ } catch (err2) {
60281
+ const why = err2 instanceof Error ? err2.message : String(err2);
60282
+ noteProjectHold(r.id, r.entry.name, why);
60283
+ errors.push(`[${r.entry.name}] project: ${why}`);
60284
+ continue;
60285
+ }
60286
+ }
60287
+ clearProjectHold(r.id);
60106
60288
  const context = buildContextIngest(store, r.engine.profile, DAEMON_VERSION, ignore, {
60107
60289
  includePackages: cfg2.consent.contributePackages
60108
60290
  });
@@ -60131,18 +60313,9 @@ async function startMultiDaemon(opts = {}) {
60131
60313
  }
60132
60314
  let lexicon;
60133
60315
  try {
60134
- const summaries = summariesByBodyHash(loadSymbolSummaryCache(r.engine.paths.configDir));
60135
- if (summaries.size > 0) lexicon = buildSymbolLexicon(store, summaries);
60316
+ lexicon = buildSymbolLexicon(store);
60136
60317
  } catch {
60137
60318
  }
60138
- const projectId = r.engine.profile.projectId;
60139
- let project;
60140
- if (projectId) {
60141
- try {
60142
- project = await resolveProjectSymbolSalt(client, projectId);
60143
- } catch {
60144
- }
60145
- }
60146
60319
  let composition = null;
60147
60320
  const instances = buildInstanceIngest(store, r.engine.profile, DAEMON_VERSION, ignore, {
60148
60321
  includePackages: cfg2.consent.contributePackages,
@@ -60333,7 +60506,7 @@ async function startMultiDaemon(opts = {}) {
60333
60506
  async stop() {
60334
60507
  clearInterval(idleSweep);
60335
60508
  try {
60336
- const cur = readFileSync27(lockPath, "utf8");
60509
+ const cur = readFileSync26(lockPath, "utf8");
60337
60510
  if (JSON.parse(cur).pid === process.pid) unlinkSync3(lockPath);
60338
60511
  } catch {
60339
60512
  }
@@ -61374,21 +61547,21 @@ async function cmdInit() {
61374
61547
  if (!skipHooks) {
61375
61548
  console.log("");
61376
61549
  console.log("installing harness hooks...");
61377
- const { existsSync: existsSync31 } = await import("node:fs");
61378
- const { join: join33 } = await import("node:path");
61550
+ const { existsSync: existsSync30 } = await import("node:fs");
61551
+ const { join: join32 } = await import("node:path");
61379
61552
  try {
61380
61553
  await installClaudeHooks(port);
61381
61554
  } catch (err2) {
61382
61555
  console.warn(` \u26A0\uFE0F Claude hook install failed: ${err2 instanceof Error ? err2.message : err2}`);
61383
61556
  }
61384
- if (existsSync31(join33(ROOT, ".cursor"))) {
61557
+ if (existsSync30(join32(ROOT, ".cursor"))) {
61385
61558
  try {
61386
61559
  await installCursorMcpConfig();
61387
61560
  } catch (err2) {
61388
61561
  console.warn(` \u26A0\uFE0F Cursor MCP config failed: ${err2 instanceof Error ? err2.message : err2}`);
61389
61562
  }
61390
61563
  }
61391
- if (existsSync31(join33(ROOT, ".codex"))) {
61564
+ if (existsSync30(join32(ROOT, ".codex"))) {
61392
61565
  try {
61393
61566
  await installCodexHooks(port);
61394
61567
  } catch (err2) {
@@ -61530,6 +61703,20 @@ async function waitForDaemon(lockPath, timeoutMs) {
61530
61703
  }
61531
61704
  return null;
61532
61705
  }
61706
+ async function daemonHolds() {
61707
+ const lockPath = globalDaemonLock();
61708
+ if (!isDaemonAlive(lockPath)) return [];
61709
+ const url2 = readDaemonLock(lockPath)?.webUiUrl;
61710
+ if (!url2) return [];
61711
+ try {
61712
+ const res = await fetch(`${url2}/api/sync`, { signal: AbortSignal.timeout(2e3) });
61713
+ if (!res.ok) return [];
61714
+ const j = await res.json();
61715
+ return j.holds ?? [];
61716
+ } catch {
61717
+ return [];
61718
+ }
61719
+ }
61533
61720
  async function cmdStatus() {
61534
61721
  const profile = loadProfile(ROOT);
61535
61722
  const cfg = loadConfig();
@@ -61542,12 +61729,18 @@ async function cmdStatus() {
61542
61729
  console.log(
61543
61730
  ` repo: ${profile.repoLocator ? `${profile.repoLocator}${link}` : "(no git remote \u2014 unlinked)"}`
61544
61731
  );
61732
+ for (const h of await daemonHolds()) {
61733
+ if (h.workspace !== profile.name && h.workspace !== profile.id) continue;
61734
+ console.log(
61735
+ ` HELD: ${h.kind} \u2014 ${h.reason} (${Math.round(h.sinceMs / 1e3)}s). Contributions stay pending; they drain once this clears.`
61736
+ );
61737
+ }
61545
61738
  console.log(` stack: ${profile.stack.join(", ") || "(none)"}`);
61546
61739
  console.log(` languages: ${profile.languages.join(", ") || "(none)"}`);
61547
61740
  }
61548
- console.log(` graph db: ${existsSync30(paths.castalia) ? "yes" : "no"} (${paths.castalia})`);
61549
- console.log(` event log: ${existsSync30(paths.eventLog) ? "yes" : "no"} (${paths.eventLog})`);
61550
- if (existsSync30(paths.castalia)) {
61741
+ console.log(` graph db: ${existsSync29(paths.castalia) ? "yes" : "no"} (${paths.castalia})`);
61742
+ console.log(` event log: ${existsSync29(paths.eventLog) ? "yes" : "no"} (${paths.eventLog})`);
61743
+ if (existsSync29(paths.castalia)) {
61551
61744
  try {
61552
61745
  const { openGraphStore: openGraphStore2 } = await Promise.resolve().then(() => (init_src5(), src_exports2));
61553
61746
  const store = openGraphStore2({ path: paths.castalia });
@@ -62319,11 +62512,11 @@ function cmdInstallationProfile(args2) {
62319
62512
  }
62320
62513
  async function cmdReview() {
62321
62514
  const paths = workspacePaths(ROOT);
62322
- if (!existsSync30(paths.reviewQueue)) {
62515
+ if (!existsSync29(paths.reviewQueue)) {
62323
62516
  console.log("(review queue empty)");
62324
62517
  return;
62325
62518
  }
62326
- const queue = JSON.parse(readFileSync28(paths.reviewQueue, "utf8"));
62519
+ const queue = JSON.parse(readFileSync27(paths.reviewQueue, "utf8"));
62327
62520
  if (queue.length === 0) {
62328
62521
  console.log("(review queue empty)");
62329
62522
  return;
@@ -62994,7 +63187,7 @@ async function gatherRepo(store, ws) {
62994
63187
  };
62995
63188
  }
62996
63189
  async function gatherReportData(generatedAt) {
62997
- const { existsSync: existsSync31 } = await import("node:fs");
63190
+ const { existsSync: existsSync30 } = await import("node:fs");
62998
63191
  const { openGraphStore: openGraphStore2 } = await Promise.resolve().then(() => (init_src5(), src_exports2));
62999
63192
  const cfg = loadConfig();
63000
63193
  const outbound = cfg.consent.sync ? "auto" : "off";
@@ -63002,7 +63195,7 @@ async function gatherReportData(generatedAt) {
63002
63195
  for (const ws of listWorkspaces()) {
63003
63196
  if (ws.missing) continue;
63004
63197
  const dbPath = workspacePaths(ws.path).castalia;
63005
- if (!existsSync31(dbPath)) continue;
63198
+ if (!existsSync30(dbPath)) continue;
63006
63199
  let store = null;
63007
63200
  try {
63008
63201
  store = openGraphStore2({ path: dbPath });
@@ -63033,7 +63226,7 @@ async function gatherReportData(generatedAt) {
63033
63226
  };
63034
63227
  }
63035
63228
  async function cmdReport(args2) {
63036
- const { mkdirSync: mkdirSync8, writeFileSync: writeFileSync23 } = await import("node:fs");
63229
+ const { mkdirSync: mkdirSync8, writeFileSync: writeFileSync22 } = await import("node:fs");
63037
63230
  const { renderReport: renderReport2 } = await Promise.resolve().then(() => (init_report_render(), report_render_exports));
63038
63231
  const includeFutureVerbs = args2.includes("--future-verbs");
63039
63232
  const now = /* @__PURE__ */ new Date();
@@ -63046,8 +63239,8 @@ async function cmdReport(args2) {
63046
63239
  const outDir = workspacePaths(ROOT).configDir;
63047
63240
  mkdirSync8(outDir, { recursive: true });
63048
63241
  const files = renderReport2(data, { includeFutureVerbs });
63049
- for (const f of files) writeFileSync23(join32(outDir, f.name), f.html, "utf8");
63050
- const indexPath = join32(outDir, "report.html");
63242
+ for (const f of files) writeFileSync22(join31(outDir, f.name), f.html, "utf8");
63243
+ const indexPath = join31(outDir, "report.html");
63051
63244
  console.log(`report \u2192 ${indexPath}`);
63052
63245
  console.log(
63053
63246
  ` ${data.repos.length} repo(s) \xB7 ${files.length} file(s) \xB7 ${data.rollup.nodes.toLocaleString("en-US")} nodes`
@@ -63174,15 +63367,15 @@ function hookRelayCommand(port, path2) {
63174
63367
  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 '{}'`;
63175
63368
  }
63176
63369
  async function installClaudeHooks(port) {
63177
- const { mkdirSync: mkdirSync8, existsSync: existsSync31, readFileSync: readFileSync29, writeFileSync: writeFileSync23 } = await import("node:fs");
63178
- const { join: join33 } = await import("node:path");
63179
- const dir = join33(ROOT, ".claude");
63180
- if (!existsSync31(dir)) mkdirSync8(dir, { recursive: true });
63181
- const file2 = join33(dir, "settings.json");
63370
+ const { mkdirSync: mkdirSync8, existsSync: existsSync30, readFileSync: readFileSync28, writeFileSync: writeFileSync22 } = await import("node:fs");
63371
+ const { join: join32 } = await import("node:path");
63372
+ const dir = join32(ROOT, ".claude");
63373
+ if (!existsSync30(dir)) mkdirSync8(dir, { recursive: true });
63374
+ const file2 = join32(dir, "settings.json");
63182
63375
  let settings = {};
63183
- if (existsSync31(file2)) {
63376
+ if (existsSync30(file2)) {
63184
63377
  try {
63185
- settings = JSON.parse(readFileSync29(file2, "utf8"));
63378
+ settings = JSON.parse(readFileSync28(file2, "utf8"));
63186
63379
  } catch {
63187
63380
  console.error(`refusing to overwrite invalid JSON at ${file2}`);
63188
63381
  process.exit(2);
@@ -63228,10 +63421,10 @@ async function installClaudeHooks(port) {
63228
63421
  dropErrata(list);
63229
63422
  list.push({ hooks: [{ type: "command", command: injectCmd }] });
63230
63423
  }
63231
- writeFileSync23(file2, JSON.stringify(settings, null, 2) + "\n", "utf8");
63424
+ writeFileSync22(file2, JSON.stringify(settings, null, 2) + "\n", "utf8");
63232
63425
  console.log(`installed Claude Code hooks \u2192 ${file2}`);
63233
63426
  await installClaudeMcpConfig();
63234
- const claudeMd = join33(ROOT, "CLAUDE.md");
63427
+ const claudeMd = join32(ROOT, "CLAUDE.md");
63235
63428
  const recall = writeManagedBlock(claudeMd, { body: RECALL_FIRST_BLOCK });
63236
63429
  if (recall.kind === "collision") {
63237
63430
  console.warn(
@@ -63243,15 +63436,15 @@ async function installClaudeHooks(port) {
63243
63436
  console.log(` endpoint: http://127.0.0.1:${port}/api/hook`);
63244
63437
  }
63245
63438
  async function installClaudeMcpConfig() {
63246
- const { mkdirSync: mkdirSync8, existsSync: existsSync31, readFileSync: readFileSync29, writeFileSync: writeFileSync23 } = await import("node:fs");
63247
- const { join: join33, dirname: dirname11 } = await import("node:path");
63248
- const file2 = join33(ROOT, ".mcp.json");
63439
+ const { mkdirSync: mkdirSync8, existsSync: existsSync30, readFileSync: readFileSync28, writeFileSync: writeFileSync22 } = await import("node:fs");
63440
+ const { join: join32, dirname: dirname11 } = await import("node:path");
63441
+ const file2 = join32(ROOT, ".mcp.json");
63249
63442
  const dir = dirname11(file2);
63250
- if (!existsSync31(dir)) mkdirSync8(dir, { recursive: true });
63443
+ if (!existsSync30(dir)) mkdirSync8(dir, { recursive: true });
63251
63444
  let cfg = {};
63252
- if (existsSync31(file2)) {
63445
+ if (existsSync30(file2)) {
63253
63446
  try {
63254
- cfg = JSON.parse(readFileSync29(file2, "utf8"));
63447
+ cfg = JSON.parse(readFileSync28(file2, "utf8"));
63255
63448
  } catch {
63256
63449
  console.error(`refusing to overwrite invalid JSON at ${file2}`);
63257
63450
  process.exit(2);
@@ -63259,21 +63452,21 @@ async function installClaudeMcpConfig() {
63259
63452
  }
63260
63453
  cfg.mcpServers ??= {};
63261
63454
  cfg.mcpServers["errata"] = errataMcpInvocation();
63262
- writeFileSync23(file2, JSON.stringify(cfg, null, 2) + "\n", "utf8");
63455
+ writeFileSync22(file2, JSON.stringify(cfg, null, 2) + "\n", "utf8");
63263
63456
  console.log(`installed Claude Code MCP server config \u2192 ${file2}`);
63264
63457
  console.log(` Claude Code will spawn \`errata mcp\` on workspace open.`);
63265
63458
  console.log(` Tools: errata.search / locate / neighbors / callers_of / what_uses / show / similar`);
63266
63459
  }
63267
63460
  async function installCursorMcpConfig() {
63268
- const { mkdirSync: mkdirSync8, existsSync: existsSync31, readFileSync: readFileSync29, writeFileSync: writeFileSync23 } = await import("node:fs");
63269
- const { join: join33 } = await import("node:path");
63270
- const dir = join33(ROOT, ".cursor");
63271
- if (!existsSync31(dir)) mkdirSync8(dir, { recursive: true });
63272
- const file2 = join33(dir, "mcp.json");
63461
+ const { mkdirSync: mkdirSync8, existsSync: existsSync30, readFileSync: readFileSync28, writeFileSync: writeFileSync22 } = await import("node:fs");
63462
+ const { join: join32 } = await import("node:path");
63463
+ const dir = join32(ROOT, ".cursor");
63464
+ if (!existsSync30(dir)) mkdirSync8(dir, { recursive: true });
63465
+ const file2 = join32(dir, "mcp.json");
63273
63466
  let cfg = {};
63274
- if (existsSync31(file2)) {
63467
+ if (existsSync30(file2)) {
63275
63468
  try {
63276
- cfg = JSON.parse(readFileSync29(file2, "utf8"));
63469
+ cfg = JSON.parse(readFileSync28(file2, "utf8"));
63277
63470
  } catch {
63278
63471
  console.error(`refusing to overwrite invalid JSON at ${file2}`);
63279
63472
  process.exit(2);
@@ -63281,7 +63474,7 @@ async function installCursorMcpConfig() {
63281
63474
  }
63282
63475
  cfg.mcpServers ??= {};
63283
63476
  cfg.mcpServers["errata"] = errataMcpInvocation();
63284
- writeFileSync23(file2, JSON.stringify(cfg, null, 2) + "\n", "utf8");
63477
+ writeFileSync22(file2, JSON.stringify(cfg, null, 2) + "\n", "utf8");
63285
63478
  console.log(`installed Cursor MCP server config \u2192 ${file2}`);
63286
63479
  console.log(` Cursor will spawn \`errata mcp\` on workspace open.`);
63287
63480
  console.log(` Tools: errata.search / locate / neighbors / callers_of / what_uses`);
@@ -63289,16 +63482,16 @@ async function installCursorMcpConfig() {
63289
63482
  console.log(` \u26A0\uFE0F reload Cursor (Cmd/Ctrl-Shift-P \u2192 "Reload Window") to pick it up.`);
63290
63483
  }
63291
63484
  async function installCodexHooks(port) {
63292
- const { mkdirSync: mkdirSync8, existsSync: existsSync31, readFileSync: readFileSync29, writeFileSync: writeFileSync23 } = await import("node:fs");
63293
- const { join: join33 } = await import("node:path");
63294
- const dir = join33(ROOT, ".codex");
63295
- if (!existsSync31(dir)) mkdirSync8(dir, { recursive: true });
63296
- const file2 = join33(dir, "config.toml");
63485
+ const { mkdirSync: mkdirSync8, existsSync: existsSync30, readFileSync: readFileSync28, writeFileSync: writeFileSync22 } = await import("node:fs");
63486
+ const { join: join32 } = await import("node:path");
63487
+ const dir = join32(ROOT, ".codex");
63488
+ if (!existsSync30(dir)) mkdirSync8(dir, { recursive: true });
63489
+ const file2 = join32(dir, "config.toml");
63297
63490
  const BEGIN = `# >>> errata hooks (errata-managed)`;
63298
63491
  const END = `# <<< errata hooks`;
63299
63492
  let existing = "";
63300
- if (existsSync31(file2)) {
63301
- existing = readFileSync29(file2, "utf8");
63493
+ if (existsSync30(file2)) {
63494
+ existing = readFileSync28(file2, "utf8");
63302
63495
  const beginIdx = existing.indexOf(BEGIN);
63303
63496
  const endIdx = existing.indexOf(END);
63304
63497
  if (beginIdx >= 0 && endIdx > beginIdx) {
@@ -63327,7 +63520,7 @@ ${END}
63327
63520
  const final = existing.length > 0 && !existing.endsWith("\n") ? `${existing}
63328
63521
 
63329
63522
  ${block}` : existing + (existing.endsWith("\n\n") ? "" : "\n") + block;
63330
- writeFileSync23(file2, final, "utf8");
63523
+ writeFileSync22(file2, final, "utf8");
63331
63524
  console.log(`installed Codex hooks \u2192 ${file2}`);
63332
63525
  console.log(` endpoint: http://127.0.0.1:${port}/api/hook`);
63333
63526
  console.log("");
@@ -63664,7 +63857,7 @@ async function cmdDash(args2) {
63664
63857
  await yieldToLoop2();
63665
63858
  try {
63666
63859
  const items = selectDurableMemory(handle2.sharedStore, r.engine.profile);
63667
- const res = bleedRules(join32(r.root, ".claude", "rules"), items);
63860
+ const res = bleedRules(join31(r.root, ".claude", "rules"), items);
63668
63861
  if (res.written || res.pruned) {
63669
63862
  console.log(
63670
63863
  `[rules:${r.entry.name}] ${res.written} collective principle(s) \u2192 .claude/rules` + (res.pruned ? `, ${res.pruned} pruned` : "")