@inerrata-corporation/errata 2.0.0-dev.35 → 2.0.0-dev.37

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/errata.mjs CHANGED
@@ -15268,6 +15268,85 @@ var init_edge_rules = __esm({
15268
15268
  }
15269
15269
  });
15270
15270
 
15271
+ // ../../packages/shared/src/symbol-intent.ts
15272
+ function extractIdentifierTokens(text) {
15273
+ const out2 = [];
15274
+ const seen = /* @__PURE__ */ new Set();
15275
+ for (const m of text.matchAll(TOKEN_RE2)) {
15276
+ if (!seen.has(m[0])) {
15277
+ seen.add(m[0]);
15278
+ out2.push(m[0]);
15279
+ }
15280
+ }
15281
+ return out2;
15282
+ }
15283
+ function summaryRejectionReason(summary, isKnownToken) {
15284
+ if (!summary.trim()) return "empty summary";
15285
+ if (summary.length > MAX_SYMBOL_SUMMARY_CHARS) return "summary too long";
15286
+ if (PATH_SHAPE_RE.test(summary)) return "contains a path shape";
15287
+ if (QUOTED_LITERAL_RE.test(summary.replace(CONTRACTION_RE, "$1$2")))
15288
+ return "contains a quoted literal";
15289
+ for (const tok of extractIdentifierTokens(summary)) {
15290
+ if (isKnownToken(tok)) return `contains verbatim identifier '${tok}'`;
15291
+ if (tok.includes(".")) {
15292
+ const segs = tok.split(".");
15293
+ for (let i2 = 0; i2 < segs.length; i2++) {
15294
+ let span = "";
15295
+ for (let j = i2; j < segs.length; j++) {
15296
+ span = span ? `${span}.${segs[j]}` : segs[j];
15297
+ if (span !== tok && span && isKnownToken(span))
15298
+ return `contains verbatim identifier '${span}'`;
15299
+ }
15300
+ }
15301
+ }
15302
+ }
15303
+ return null;
15304
+ }
15305
+ function substituteSymbolSummaries(text, summaryByToken) {
15306
+ if (summaryByToken.size === 0) return text;
15307
+ const present = extractIdentifierTokens(text).filter((t) => summaryByToken.has(t));
15308
+ present.sort((a, b) => b.length - a.length);
15309
+ let out2 = text;
15310
+ for (const key of present) {
15311
+ const re = new RegExp(`(?<![A-Za-z0-9_$.])${escapeRe2(key)}(?![A-Za-z0-9_$])`, "g");
15312
+ out2 = out2.replace(re, summaryByToken.get(key));
15313
+ }
15314
+ return out2;
15315
+ }
15316
+ function vetSidecarSummaries(sidecar) {
15317
+ if (!sidecar) return null;
15318
+ const keys = new Set(Object.keys(sidecar));
15319
+ if (keys.size === 0 || keys.size > MAX_SIDECAR_SYMBOLS) return null;
15320
+ const clean = /* @__PURE__ */ new Map();
15321
+ for (const [symbol2, entry] of Object.entries(sidecar)) {
15322
+ if (!entry || typeof entry.summary !== "string") continue;
15323
+ if (summaryRejectionReason(entry.summary, (t) => keys.has(t)) !== null) continue;
15324
+ clean.set(symbol2, entry.summary);
15325
+ }
15326
+ return clean.size > 0 ? clean : null;
15327
+ }
15328
+ var SYMBOL_SUMMARY_KINDS, MAX_SYMBOL_SUMMARY_CHARS, MAX_SIDECAR_SYMBOLS, TOKEN_RE2, RE_RESERVED, escapeRe2, PATH_SHAPE_RE, CONTRACTION_RE, QUOTED_LITERAL_RE;
15329
+ var init_symbol_intent = __esm({
15330
+ "../../packages/shared/src/symbol-intent.ts"() {
15331
+ "use strict";
15332
+ SYMBOL_SUMMARY_KINDS = [
15333
+ "function",
15334
+ "method",
15335
+ "class",
15336
+ "interface",
15337
+ "constant"
15338
+ ];
15339
+ MAX_SYMBOL_SUMMARY_CHARS = 300;
15340
+ MAX_SIDECAR_SYMBOLS = 200;
15341
+ TOKEN_RE2 = /[A-Za-z_$][A-Za-z0-9_$]*(?:\.[A-Za-z_$][A-Za-z0-9_$]*)*/g;
15342
+ RE_RESERVED = /[.*+?^${}()|[\]\\]/g;
15343
+ escapeRe2 = (s) => s.replace(RE_RESERVED, "\\$&");
15344
+ PATH_SHAPE_RE = /[\w.~-]+[/\\][\w.$~-]+/;
15345
+ CONTRACTION_RE = /([A-Za-z])'([A-Za-z])/g;
15346
+ QUOTED_LITERAL_RE = /"[^"]+"|'[^']+'|`[^`]+`/;
15347
+ }
15348
+ });
15349
+
15271
15350
  // ../../packages/shared/src/wire.ts
15272
15351
  function provenanceBand(source) {
15273
15352
  switch (source) {
@@ -15317,13 +15396,14 @@ function summarizeIngestResult(r) {
15317
15396
  ...r.patternReconciliation ? { patternReconciliation: r.patternReconciliation } : {}
15318
15397
  };
15319
15398
  }
15320
- var CLOUD_NODE_LABELS, CLOUD_EDGE_TYPES, INGEST_SOURCES, INGEST_EXTRACTION_SOURCES, MAX_NODES_PER_PAYLOAD, MAX_EDGES_PER_PAYLOAD, CastaliaIngestNodeSchema, RouteContextCountWireSchema, CastaliaIngestEdgeSchema, CastaliaIngestPayloadSchema;
15399
+ var CLOUD_NODE_LABELS, CLOUD_EDGE_TYPES, INGEST_SOURCES, INGEST_EXTRACTION_SOURCES, MAX_NODES_PER_PAYLOAD, MAX_EDGES_PER_PAYLOAD, CastaliaIngestNodeSchema, RouteContextCountWireSchema, CastaliaIngestEdgeSchema, SymbolSummarySidecarSchema, CastaliaIngestPayloadSchema;
15321
15400
  var init_wire = __esm({
15322
15401
  "../../packages/shared/src/wire.ts"() {
15323
15402
  "use strict";
15324
15403
  init_zod();
15325
15404
  init_castalia();
15326
15405
  init_edge_rules();
15406
+ init_symbol_intent();
15327
15407
  CLOUD_NODE_LABELS = [
15328
15408
  ...SEMANTIC_NODE_LABELS,
15329
15409
  ...CONTEXT_NODE_LABELS
@@ -15373,12 +15453,24 @@ var init_wire = __esm({
15373
15453
  perContext: external_exports.record(external_exports.string(), RouteContextCountWireSchema).optional()
15374
15454
  }).optional()
15375
15455
  });
15456
+ SymbolSummarySidecarSchema = external_exports.record(
15457
+ external_exports.string().min(1).max(160),
15458
+ external_exports.object({
15459
+ kind: external_exports.enum(SYMBOL_SUMMARY_KINDS),
15460
+ summary: external_exports.string().min(1).max(MAX_SYMBOL_SUMMARY_CHARS)
15461
+ })
15462
+ ).refine((m) => Object.keys(m).length <= MAX_SIDECAR_SYMBOLS, {
15463
+ message: `symbolSummaries sidecar exceeds ${MAX_SIDECAR_SYMBOLS} entries`
15464
+ });
15376
15465
  CastaliaIngestPayloadSchema = external_exports.object({
15377
15466
  /** Client-supplied UUID — one batch; pairs with the payload digest for replay. */
15378
15467
  runId: external_exports.string().uuid(),
15379
15468
  source: external_exports.enum(INGEST_SOURCES),
15380
15469
  nodes: external_exports.array(CastaliaIngestNodeSchema).max(1e3),
15381
- edges: external_exports.array(CastaliaIngestEdgeSchema).max(5e3)
15470
+ edges: external_exports.array(CastaliaIngestEdgeSchema).max(5e3),
15471
+ /** Optional symbol→intent-summary sidecar (PP-symbol-intent). Only symbols
15472
+ * present in this payload's node text; server re-vets no-verbatim. */
15473
+ symbolSummaries: SymbolSummarySidecarSchema.optional()
15382
15474
  });
15383
15475
  }
15384
15476
  });
@@ -15443,12 +15535,16 @@ __export(src_exports, {
15443
15535
  JUSTIFICATION_EDGES: () => JUSTIFICATION_EDGES,
15444
15536
  MAX_EDGES_PER_PAYLOAD: () => MAX_EDGES_PER_PAYLOAD,
15445
15537
  MAX_NODES_PER_PAYLOAD: () => MAX_NODES_PER_PAYLOAD,
15538
+ MAX_SIDECAR_SYMBOLS: () => MAX_SIDECAR_SYMBOLS,
15539
+ MAX_SYMBOL_SUMMARY_CHARS: () => MAX_SYMBOL_SUMMARY_CHARS,
15446
15540
  PAGERANK_EXCLUSIONS: () => PAGERANK_EXCLUSIONS,
15447
15541
  PROBLEM_RESOLUTION: () => PROBLEM_RESOLUTION,
15448
15542
  RESOLUTION_EDGES: () => RESOLUTION_EDGES,
15449
15543
  RouteContextCountWireSchema: () => RouteContextCountWireSchema,
15450
15544
  SEMANTIC_NODE_LABELS: () => SEMANTIC_NODE_LABELS,
15451
15545
  STRUCTURAL_EDGES: () => STRUCTURAL_EDGES,
15546
+ SYMBOL_SUMMARY_KINDS: () => SYMBOL_SUMMARY_KINDS,
15547
+ SymbolSummarySidecarSchema: () => SymbolSummarySidecarSchema,
15452
15548
  TAXONOMY_EDGES: () => TAXONOMY_EDGES,
15453
15549
  TRANSFER_EDGES: () => TRANSFER_EDGES,
15454
15550
  TRIAGE_EDGES: () => TRIAGE_EDGES,
@@ -15468,6 +15564,7 @@ __export(src_exports, {
15468
15564
  detectStance: () => detectStance,
15469
15565
  digest: () => digest,
15470
15566
  errorSignatureEqual: () => errorSignatureEqual,
15567
+ extractIdentifierTokens: () => extractIdentifierTokens,
15471
15568
  genericCanonicalId: () => genericCanonicalId,
15472
15569
  identityId: () => identityId,
15473
15570
  isCausalProtected: () => isCausalProtected,
@@ -15493,9 +15590,12 @@ __export(src_exports, {
15493
15590
  resolveCanonicalId: () => resolveCanonicalId,
15494
15591
  sha256: () => sha256,
15495
15592
  sha256Short: () => sha256Short,
15593
+ substituteSymbolSummaries: () => substituteSymbolSummaries,
15496
15594
  summarizeIngestResult: () => summarizeIngestResult,
15595
+ summaryRejectionReason: () => summaryRejectionReason,
15497
15596
  toCloudAttrs: () => toCloudAttrs,
15498
- validateCastaliaPayload: () => validateCastaliaPayload
15597
+ validateCastaliaPayload: () => validateCastaliaPayload,
15598
+ vetSidecarSummaries: () => vetSidecarSummaries
15499
15599
  });
15500
15600
  var init_src = __esm({
15501
15601
  "../../packages/shared/src/index.ts"() {
@@ -15504,6 +15604,7 @@ var init_src = __esm({
15504
15604
  init_identity();
15505
15605
  init_wire();
15506
15606
  init_edge_rules();
15607
+ init_symbol_intent();
15507
15608
  init_hash();
15508
15609
  init_error_signature();
15509
15610
  init_canonicalize();
@@ -17246,7 +17347,7 @@ function buildPackageIndex(store) {
17246
17347
  }
17247
17348
  return idx;
17248
17349
  }
17249
- function escapeRe2(s) {
17350
+ function escapeRe3(s) {
17250
17351
  return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
17251
17352
  }
17252
17353
  function matchPackagesInText(text, index) {
@@ -17256,7 +17357,7 @@ function matchPackagesInText(text, index) {
17256
17357
  for (const [key, node2] of index) {
17257
17358
  if (key.length < MIN_NAME_LEN) continue;
17258
17359
  if (!hay.includes(key)) continue;
17259
- const esc3 = escapeRe2(key);
17360
+ const esc3 = escapeRe3(key);
17260
17361
  const bounded = new RegExp(`(?<![\\w@/.\\-])${esc3}(?![\\w])`);
17261
17362
  if (!bounded.test(hay)) continue;
17262
17363
  const verMatch = new RegExp(`${esc3}\\s*@?\\s*v?(\\d+(?:\\.\\d+){0,2})\\b`).exec(hay);
@@ -20507,6 +20608,38 @@ var init_oauth = __esm({
20507
20608
 
20508
20609
  // ../../packages/cloud-client/src/client.ts
20509
20610
  import { randomUUID } from "node:crypto";
20611
+ function wirePerContext(value) {
20612
+ if (!value || typeof value !== "object" || Array.isArray(value)) return null;
20613
+ const out2 = {};
20614
+ for (const [bucket, entry] of Object.entries(value)) {
20615
+ if (!entry || typeof entry !== "object" || Array.isArray(entry)) continue;
20616
+ const e = entry;
20617
+ const confirmed = asWireCount(e["confirmed"]);
20618
+ if (confirmed === null) continue;
20619
+ const independent = asWireCount(e["independent"]);
20620
+ const inferredIndependent = asWireCount(e["inferredIndependent"]);
20621
+ out2[bucket] = {
20622
+ confirmed,
20623
+ ...independent !== null ? { independent } : {},
20624
+ ...inferredIndependent !== null ? { inferredIndependent } : {}
20625
+ };
20626
+ }
20627
+ return Object.keys(out2).length > 0 ? out2 : null;
20628
+ }
20629
+ function sidecarForNodes(sidecar, nodes) {
20630
+ if (!sidecar) return void 0;
20631
+ const present = /* @__PURE__ */ new Set();
20632
+ for (const n of nodes) for (const tok of extractIdentifierTokens(n.description)) present.add(tok);
20633
+ const filtered = {};
20634
+ let count = 0;
20635
+ for (const [symbol2, entry] of Object.entries(sidecar)) {
20636
+ if (present.has(symbol2)) {
20637
+ filtered[symbol2] = entry;
20638
+ count++;
20639
+ }
20640
+ }
20641
+ return count > 0 ? filtered : void 0;
20642
+ }
20510
20643
  function toWirePayload(batch, runId) {
20511
20644
  const nodes = batch.nodes.map((n) => ({
20512
20645
  canonicalId: n.id,
@@ -20517,15 +20650,20 @@ function toWirePayload(batch, runId) {
20517
20650
  attrs: n.attrs ?? {},
20518
20651
  extractionSource: n.extractionSource
20519
20652
  }));
20520
- const edges = batch.edges.map((e) => ({
20521
- fromCanonicalId: e.from,
20522
- toCanonicalId: e.to,
20523
- type: e.type,
20524
- attrs: {
20525
- ...typeof e.confidence === "number" ? { confidence: clamp012(e.confidence) } : {}
20526
- }
20527
- }));
20528
- return { runId, source: "daemon", nodes, edges };
20653
+ const edges = batch.edges.map((e) => {
20654
+ const perContext = wirePerContext(e.attrs?.["perContext"]);
20655
+ return {
20656
+ fromCanonicalId: e.from,
20657
+ toCanonicalId: e.to,
20658
+ type: e.type,
20659
+ attrs: {
20660
+ ...typeof e.confidence === "number" ? { confidence: clamp012(e.confidence) } : {},
20661
+ ...perContext ? { perContext } : {}
20662
+ }
20663
+ };
20664
+ });
20665
+ const symbolSummaries = sidecarForNodes(batch.symbolSummaries, nodes);
20666
+ return { runId, source: "daemon", nodes, edges, ...symbolSummaries ? { symbolSummaries } : {} };
20529
20667
  }
20530
20668
  function clamp012(x) {
20531
20669
  return Math.max(0, Math.min(1, x));
@@ -20536,12 +20674,13 @@ function chunkArray(items, size) {
20536
20674
  for (let i2 = 0; i2 < items.length; i2 += size) out2.push(items.slice(i2, i2 + size));
20537
20675
  return out2;
20538
20676
  }
20539
- var INGEST_NODE_CHUNK, CloudClient, CloudError;
20677
+ var asWireCount, INGEST_NODE_CHUNK, CloudClient, CloudError;
20540
20678
  var init_client = __esm({
20541
20679
  "../../packages/cloud-client/src/client.ts"() {
20542
20680
  "use strict";
20543
20681
  init_oauth();
20544
20682
  init_src();
20683
+ asWireCount = (n) => typeof n === "number" && Number.isFinite(n) && n >= 0 ? Math.floor(n) : null;
20545
20684
  INGEST_NODE_CHUNK = 25;
20546
20685
  CloudClient = class {
20547
20686
  baseUrl;
@@ -23939,21 +24078,32 @@ function isDistinctiveIdentifier(name2) {
23939
24078
  if (/^[A-Z]/.test(name2) && name2.length >= 4) return true;
23940
24079
  return name2.length >= 8;
23941
24080
  }
23942
- function buildSymbolLexicon(store) {
24081
+ function buildSymbolLexicon(store, summariesByBodyHash2) {
23943
24082
  const lex = /* @__PURE__ */ new Map();
24083
+ const candidates = [];
23944
24084
  for (const [label, kind] of SYMBOL_LABELS) {
23945
24085
  for (const n of store.findNodesByLabel(label)) {
24086
+ const bodyHash = typeof n.attrs["bodyHash"] === "string" ? n.attrs["bodyHash"] : void 0;
24087
+ const summary = bodyHash ? summariesByBodyHash2?.get(bodyHash) : void 0;
23946
24088
  for (const name2 of [n.description, String(n.attrs["qname"] ?? "")]) {
23947
- if (name2 && isDistinctiveIdentifier(name2)) lex.set(name2, kind);
24089
+ if (name2 && isDistinctiveIdentifier(name2)) {
24090
+ if (!lex.has(name2)) lex.set(name2, { kind });
24091
+ if (summary) candidates.push([name2, summary]);
24092
+ }
23948
24093
  }
23949
24094
  }
23950
24095
  }
24096
+ for (const [name2, summary] of candidates) {
24097
+ if (summaryRejectionReason(summary, (tok) => lex.has(tok)) === null) {
24098
+ lex.get(name2).summary = summary;
24099
+ }
24100
+ }
23951
24101
  return lex;
23952
24102
  }
23953
24103
  function generalizeSymbols(text, lexicon, level = 1) {
23954
24104
  const present = [];
23955
24105
  const seen = /* @__PURE__ */ new Set();
23956
- for (const m of text.matchAll(TOKEN_RE2)) {
24106
+ for (const m of text.matchAll(TOKEN_RE3)) {
23957
24107
  const tok = m[0];
23958
24108
  if (!seen.has(tok) && lexicon.has(tok)) {
23959
24109
  seen.add(tok);
@@ -23963,17 +24113,19 @@ function generalizeSymbols(text, lexicon, level = 1) {
23963
24113
  present.sort((a, b) => b.length - a.length);
23964
24114
  let out2 = text;
23965
24115
  for (const key of present) {
23966
- const phrase = KIND_PHRASE[lexicon.get(key)][level === 1 ? "l1" : "l2"];
23967
- const re = new RegExp(`(?<![A-Za-z0-9_$.])${escapeRe3(key)}(?![A-Za-z0-9_$])`, "g");
24116
+ const entry = lexicon.get(key);
24117
+ const phrase = level === 1 && entry.summary ? entry.summary : KIND_PHRASE[entry.kind][level === 1 ? "l1" : "l2"];
24118
+ const re = new RegExp(`(?<![A-Za-z0-9_$.])${escapeRe4(key)}(?![A-Za-z0-9_$])`, "g");
23968
24119
  out2 = out2.replace(re, phrase);
23969
24120
  }
23970
24121
  return generalize(out2, { level }).text;
23971
24122
  }
23972
- var SYMBOL_LABELS, KIND_PHRASE, RE_RESERVED, escapeRe3, TOKEN_RE2;
24123
+ var SYMBOL_LABELS, KIND_PHRASE, RE_RESERVED2, escapeRe4, TOKEN_RE3;
23973
24124
  var init_generalize_graph = __esm({
23974
24125
  "src/generalize-graph.ts"() {
23975
24126
  "use strict";
23976
24127
  init_src8();
24128
+ init_src();
23977
24129
  SYMBOL_LABELS = [
23978
24130
  ["Function", "function"],
23979
24131
  ["Method", "method"],
@@ -23988,9 +24140,9 @@ var init_generalize_graph = __esm({
23988
24140
  interface: { l1: "an interface", l2: "an interface" },
23989
24141
  constant: { l1: "a constant", l2: "a value" }
23990
24142
  };
23991
- RE_RESERVED = /[.*+?^${}()|[\]\\]/g;
23992
- escapeRe3 = (s) => s.replace(RE_RESERVED, "\\$&");
23993
- TOKEN_RE2 = /[A-Za-z_$][A-Za-z0-9_$]*(?:\.[A-Za-z_$][A-Za-z0-9_$]*)*/g;
24143
+ RE_RESERVED2 = /[.*+?^${}()|[\]\\]/g;
24144
+ escapeRe4 = (s) => s.replace(RE_RESERVED2, "\\$&");
24145
+ TOKEN_RE3 = /[A-Za-z_$][A-Za-z0-9_$]*(?:\.[A-Za-z_$][A-Za-z0-9_$]*)*/g;
23994
24146
  }
23995
24147
  });
23996
24148
 
@@ -24095,7 +24247,7 @@ async function dualAugment(opts) {
24095
24247
  let seedProvenance = "local";
24096
24248
  const calls = [];
24097
24249
  try {
24098
- const lexicon = buildSymbolLexicon(store);
24250
+ const lexicon = buildSymbolLexicon(store, opts.summaries);
24099
24251
  const hardIds = [.../* @__PURE__ */ new Set([...seedNode ? [seedNode.id] : [], ...localHits.map((h) => h.id)])].filter((nid) => {
24100
24252
  const n = seedNode && nid === seedNode.id ? seedNode : store.getNode(nid);
24101
24253
  return !!n && isHardBridge(n);
@@ -25920,6 +26072,177 @@ var init_src10 = __esm({
25920
26072
  }
25921
26073
  });
25922
26074
 
26075
+ // src/symbol-summaries.ts
26076
+ import { existsSync as existsSync7, readFileSync as readFileSync5, writeFileSync as writeFileSync6 } from "node:fs";
26077
+ import { join as join6 } from "node:path";
26078
+ function symbolSummariesPath(configDir) {
26079
+ return join6(configDir, "symbol-summaries.json");
26080
+ }
26081
+ function loadSymbolSummaryCache(configDir) {
26082
+ const p = symbolSummariesPath(configDir);
26083
+ if (existsSync7(p)) {
26084
+ try {
26085
+ const raw2 = JSON.parse(readFileSync5(p, "utf8"));
26086
+ if (raw2 && raw2.version === 1 && raw2.entries && typeof raw2.entries === "object") {
26087
+ return { version: 1, entries: raw2.entries };
26088
+ }
26089
+ } catch {
26090
+ }
26091
+ }
26092
+ return { version: 1, entries: {} };
26093
+ }
26094
+ function saveSymbolSummaryCache(configDir, cache) {
26095
+ writeFileSync6(symbolSummariesPath(configDir), JSON.stringify(cache, null, 2), "utf8");
26096
+ }
26097
+ function summariesByBodyHash(cache) {
26098
+ const m = /* @__PURE__ */ new Map();
26099
+ for (const [bodyHash, e] of Object.entries(cache.entries)) {
26100
+ if (!e.rejected && typeof e.summary === "string" && e.summary.trim()) m.set(bodyHash, e.summary);
26101
+ }
26102
+ return m;
26103
+ }
26104
+ function parseSummaryJson(text, expected) {
26105
+ const start2 = text.indexOf("[");
26106
+ const end = text.lastIndexOf("]");
26107
+ if (start2 < 0 || end <= start2) return new Array(expected).fill(null);
26108
+ let arr;
26109
+ try {
26110
+ arr = JSON.parse(text.slice(start2, end + 1));
26111
+ } catch {
26112
+ return new Array(expected).fill(null);
26113
+ }
26114
+ if (!Array.isArray(arr)) return new Array(expected).fill(null);
26115
+ const out2 = [];
26116
+ for (let i2 = 0; i2 < expected; i2++) {
26117
+ const v = arr[i2];
26118
+ out2.push(typeof v === "string" && v.trim() ? v.trim().slice(0, MAX_SYMBOL_SUMMARY_CHARS) : null);
26119
+ }
26120
+ return out2;
26121
+ }
26122
+ function haikuIntentSummarizer(apiKey) {
26123
+ if (!apiKey) return void 0;
26124
+ return async (symbols) => {
26125
+ try {
26126
+ const listing = symbols.map(
26127
+ (s, i2) => `### ${i2 + 1}. kind: ${s.kind}
26128
+ name: ${s.name}
26129
+ ${s.snippet ? `\`\`\`
26130
+ ${s.snippet}
26131
+ \`\`\`` : "(no source available \u2014 describe from the name)"}`
26132
+ ).join("\n\n");
26133
+ const resp = await fetch("https://api.anthropic.com/v1/messages", {
26134
+ method: "POST",
26135
+ headers: {
26136
+ "x-api-key": apiKey,
26137
+ "anthropic-version": "2023-06-01",
26138
+ "content-type": "application/json"
26139
+ },
26140
+ body: JSON.stringify({
26141
+ model: SUMMARY_MODEL,
26142
+ max_tokens: 2e3,
26143
+ messages: [{ role: "user", content: `${SUMMARY_PROMPT}
26144
+
26145
+ SYMBOLS:
26146
+ ${listing}` }]
26147
+ })
26148
+ });
26149
+ if (!resp.ok) return symbols.map(() => null);
26150
+ const json2 = await resp.json();
26151
+ return parseSummaryJson(json2.content?.find((c) => c.type === "text")?.text ?? "", symbols.length);
26152
+ } catch {
26153
+ return symbols.map(() => null);
26154
+ }
26155
+ };
26156
+ }
26157
+ function envIntentSummarizer() {
26158
+ if (process.env["ERRATA_SYMBOL_SUMMARIES"] !== "1") return void 0;
26159
+ return haikuIntentSummarizer(process.env["ANTHROPIC_API_KEY"] ?? null);
26160
+ }
26161
+ function readSnippet(workspaceRoot, attrs) {
26162
+ const relPath = attrs["relPath"];
26163
+ const startByte = attrs["startByte"];
26164
+ const endByte = attrs["endByte"];
26165
+ if (typeof relPath !== "string" || typeof startByte !== "number" || typeof endByte !== "number") {
26166
+ return void 0;
26167
+ }
26168
+ try {
26169
+ const buf = readFileSync5(join6(workspaceRoot, ...relPath.split("/")));
26170
+ const slice = buf.subarray(Math.max(0, startByte), Math.min(buf.length, endByte));
26171
+ const text = slice.toString("utf8");
26172
+ return text.length > MAX_SNIPPET_CHARS ? text.slice(0, MAX_SNIPPET_CHARS) : text;
26173
+ } catch {
26174
+ return void 0;
26175
+ }
26176
+ }
26177
+ async function runSymbolSummarySweep(store, workspaceRoot, configDir, summarizer, opts = {}) {
26178
+ const maxSymbols = opts.maxSymbols ?? DEFAULT_MAX_SYMBOLS_PER_SWEEP;
26179
+ const batchSize = Math.max(1, opts.batchSize ?? DEFAULT_BATCH_SIZE);
26180
+ const cache = loadSymbolSummaryCache(configDir);
26181
+ const candidates = [];
26182
+ const seen = /* @__PURE__ */ new Set();
26183
+ for (const [label, kind] of SUMMARY_LABELS) {
26184
+ for (const n of store.findNodesByLabel(label)) {
26185
+ const bodyHash = n.attrs["bodyHash"];
26186
+ if (typeof bodyHash !== "string" || !bodyHash || seen.has(bodyHash)) continue;
26187
+ if (cache.entries[bodyHash]) continue;
26188
+ const name2 = n.description;
26189
+ if (!name2 || !isDistinctiveIdentifier(name2)) continue;
26190
+ seen.add(bodyHash);
26191
+ const snippet = readSnippet(workspaceRoot, n.attrs);
26192
+ candidates.push({ bodyHash, name: name2, kind, ...snippet ? { snippet } : {} });
26193
+ }
26194
+ }
26195
+ const todo = candidates.slice(0, maxSymbols);
26196
+ const remaining = candidates.length - todo.length;
26197
+ if (todo.length === 0) return { generated: 0, rejected: 0, remaining };
26198
+ const lexicon = buildSymbolLexicon(store);
26199
+ const isKnown = (tok) => lexicon.has(tok);
26200
+ let generated = 0;
26201
+ let rejected = 0;
26202
+ for (let i2 = 0; i2 < todo.length; i2 += batchSize) {
26203
+ const batch = todo.slice(i2, i2 + batchSize);
26204
+ const phrases = await summarizer(batch);
26205
+ const now = Date.now();
26206
+ for (let j = 0; j < batch.length; j++) {
26207
+ const sym = batch[j];
26208
+ const phrase = phrases[j];
26209
+ if (phrase == null) continue;
26210
+ if (summaryRejectionReason(phrase, isKnown) === null) {
26211
+ cache.entries[sym.bodyHash] = { summary: phrase, model: SUMMARY_MODEL, createdAt: now };
26212
+ generated++;
26213
+ } else {
26214
+ cache.entries[sym.bodyHash] = { rejected: true, model: SUMMARY_MODEL, createdAt: now };
26215
+ rejected++;
26216
+ }
26217
+ }
26218
+ saveSymbolSummaryCache(configDir, cache);
26219
+ }
26220
+ return { generated, rejected, remaining };
26221
+ }
26222
+ var SUMMARY_LABELS, MAX_SNIPPET_CHARS, DEFAULT_MAX_SYMBOLS_PER_SWEEP, DEFAULT_BATCH_SIZE, SUMMARY_MODEL, SUMMARY_PROMPT;
26223
+ var init_symbol_summaries = __esm({
26224
+ "src/symbol-summaries.ts"() {
26225
+ "use strict";
26226
+ init_src();
26227
+ init_generalize_graph();
26228
+ SUMMARY_LABELS = [
26229
+ ["Function", "function"],
26230
+ ["Method", "method"],
26231
+ ["Class", "class"]
26232
+ ];
26233
+ MAX_SNIPPET_CHARS = 1500;
26234
+ DEFAULT_MAX_SYMBOLS_PER_SWEEP = 64;
26235
+ DEFAULT_BATCH_SIZE = 16;
26236
+ SUMMARY_MODEL = "claude-haiku-4-5-20251001";
26237
+ 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").
26238
+ HARD RULES \u2014 a violating phrase is discarded:
26239
+ - NEVER include any identifier, symbol name, variable, type name, file path, or module name from the code \u2014 describe meaning in plain English words only.
26240
+ - NEVER include quoted strings, literals, numbers copied from the code, or code syntax.
26241
+ - One phrase per symbol, under 200 characters, lowercase start, no trailing period.
26242
+ 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.`;
26243
+ }
26244
+ });
26245
+
25923
26246
  // ../../packages/indexer/src/simhash.ts
25924
26247
  function fnv1a64(s) {
25925
26248
  let h = FNV_OFFSET;
@@ -26143,9 +26466,9 @@ var init_identity2 = __esm({
26143
26466
  });
26144
26467
 
26145
26468
  // ../../packages/indexer/src/pipeline.ts
26146
- import { appendFileSync, readFileSync as readFileSync5, statSync } from "node:fs";
26469
+ import { appendFileSync, readFileSync as readFileSync6, statSync } from "node:fs";
26147
26470
  import { readdir } from "node:fs/promises";
26148
- import { extname, join as join6, relative as relative2, sep } from "node:path";
26471
+ import { extname, join as join7, relative as relative2, sep } from "node:path";
26149
26472
  import { createHash as createHash3 } from "node:crypto";
26150
26473
  import { execFileSync } from "node:child_process";
26151
26474
  function nowTs() {
@@ -26261,7 +26584,7 @@ async function incrementalReindex(store, rootPath, workspaceId2, changedAbsPaths
26261
26584
  for (const rel of [...changedRelPaths]) {
26262
26585
  let h;
26263
26586
  try {
26264
- h = createHash3("sha256").update(readFileSync5(join6(rootPath, rel))).digest("hex");
26587
+ h = createHash3("sha256").update(readFileSync6(join7(rootPath, rel))).digest("hex");
26265
26588
  } catch {
26266
26589
  continue;
26267
26590
  }
@@ -26308,13 +26631,13 @@ async function incrementalReindex(store, rootPath, workspaceId2, changedAbsPaths
26308
26631
  let parsedFiles = 0;
26309
26632
  for (const rel of changedRelPaths) {
26310
26633
  if (parsedFiles++ > 0) await new Promise((r2) => setImmediate(r2));
26311
- const abs = join6(rootPath, ...rel.split("/"));
26634
+ const abs = join7(rootPath, ...rel.split("/"));
26312
26635
  const ext = extname(abs).toLowerCase();
26313
26636
  const provider = providers.find((p) => p.fileExtensions.includes(ext));
26314
26637
  if (!provider) continue;
26315
26638
  let symbols;
26316
26639
  try {
26317
- symbols = provider.extractSymbols(readFileSync5(abs, "utf8"), abs);
26640
+ symbols = provider.extractSymbols(readFileSync6(abs, "utf8"), abs);
26318
26641
  } catch {
26319
26642
  continue;
26320
26643
  }
@@ -26614,7 +26937,7 @@ async function runIndexer(store, opts) {
26614
26937
  report.filesSkipped++;
26615
26938
  continue;
26616
26939
  }
26617
- source = readFileSync5(f.absPath, "utf8");
26940
+ source = readFileSync6(f.absPath, "utf8");
26618
26941
  } catch {
26619
26942
  report.filesSkipped++;
26620
26943
  continue;
@@ -26666,7 +26989,7 @@ async function runIndexer(store, opts) {
26666
26989
  const depth = fileNode.relPath.split("/").length;
26667
26990
  if (depth !== 3) continue;
26668
26991
  try {
26669
- const pkg = JSON.parse(readFileSync5(fileNode.absPath, "utf8"));
26992
+ const pkg = JSON.parse(readFileSync6(fileNode.absPath, "utf8"));
26670
26993
  if (!pkg.name) continue;
26671
26994
  const pkgDir = fileNode.relPath.replace(/\/package\.json$/, "");
26672
26995
  const candidates = [
@@ -27048,7 +27371,7 @@ async function scan(root, current, ignores, providers, out2) {
27048
27371
  for (const ent of entries) {
27049
27372
  if (ignores.has(ent.name)) continue;
27050
27373
  if (ent.name.startsWith(".") && ent.name !== ".") continue;
27051
- const abs = join6(current, ent.name);
27374
+ const abs = join7(current, ent.name);
27052
27375
  if (ent.isDirectory()) {
27053
27376
  await scan(root, abs, ignores, providers, out2);
27054
27377
  } else if (ent.isFile()) {
@@ -27094,7 +27417,7 @@ function gitListFiles(root, ignores, providers) {
27094
27417
  if (segs.some((s) => ignores.has(s) || s.startsWith(".") && s.length > 1)) {
27095
27418
  continue;
27096
27419
  }
27097
- const abs = join6(root, rel);
27420
+ const abs = join7(root, rel);
27098
27421
  let size;
27099
27422
  try {
27100
27423
  size = statSync(abs).size;
@@ -27117,7 +27440,7 @@ function upsertFile(store, id, f, workspaceId2) {
27117
27440
  const now = nowTs();
27118
27441
  let contentHash;
27119
27442
  try {
27120
- contentHash = createHash3("sha256").update(readFileSync5(f.absPath)).digest("hex");
27443
+ contentHash = createHash3("sha256").update(readFileSync6(f.absPath)).digest("hex");
27121
27444
  } catch {
27122
27445
  }
27123
27446
  const node2 = {
@@ -31479,8 +31802,8 @@ ${JSON.stringify(symbolNames, null, 2)}`);
31479
31802
 
31480
31803
  // ../../packages/indexer/src/languages/tree-sitter-loader.ts
31481
31804
  import { fileURLToPath } from "node:url";
31482
- import { dirname as dirname4, join as join7 } from "node:path";
31483
- import { existsSync as existsSync7, readdirSync as readdirSync2 } from "node:fs";
31805
+ import { dirname as dirname4, join as join8 } from "node:path";
31806
+ import { existsSync as existsSync8, readdirSync as readdirSync2 } from "node:fs";
31484
31807
  import { createRequire as createRequire2 } from "node:module";
31485
31808
  function entryDir() {
31486
31809
  try {
@@ -31494,27 +31817,27 @@ function entryDir() {
31494
31817
  }
31495
31818
  function findWasmDir() {
31496
31819
  const here = entryDir();
31497
- const seaWasm = join7(here, "resources", "wasm");
31498
- if (existsSync7(join7(seaWasm, "tree-sitter-typescript.wasm"))) return seaWasm;
31820
+ const seaWasm = join8(here, "resources", "wasm");
31821
+ if (existsSync8(join8(seaWasm, "tree-sitter-typescript.wasm"))) return seaWasm;
31499
31822
  let dir = here;
31500
31823
  for (let i2 = 0; i2 < 6; i2++) {
31501
- const flat = join7(
31824
+ const flat = join8(
31502
31825
  dir,
31503
31826
  "node_modules",
31504
31827
  "@vscode",
31505
31828
  "tree-sitter-wasm",
31506
31829
  "wasm"
31507
31830
  );
31508
- if (existsSync7(join7(flat, "tree-sitter-typescript.wasm"))) return flat;
31831
+ if (existsSync8(join8(flat, "tree-sitter-typescript.wasm"))) return flat;
31509
31832
  dir = dirname4(dir);
31510
31833
  }
31511
31834
  let root = here;
31512
31835
  for (let i2 = 0; i2 < 6; i2++) {
31513
- const pnpmDir = join7(root, "node_modules", ".pnpm");
31514
- if (existsSync7(pnpmDir)) {
31836
+ const pnpmDir = join8(root, "node_modules", ".pnpm");
31837
+ if (existsSync8(pnpmDir)) {
31515
31838
  for (const entry of readdirSync2(pnpmDir)) {
31516
31839
  if (entry.startsWith("@vscode+tree-sitter-wasm@")) {
31517
- const candidate = join7(
31840
+ const candidate = join8(
31518
31841
  pnpmDir,
31519
31842
  entry,
31520
31843
  "node_modules",
@@ -31522,7 +31845,7 @@ function findWasmDir() {
31522
31845
  "tree-sitter-wasm",
31523
31846
  "wasm"
31524
31847
  );
31525
- if (existsSync7(join7(candidate, "tree-sitter-typescript.wasm"))) {
31848
+ if (existsSync8(join8(candidate, "tree-sitter-typescript.wasm"))) {
31526
31849
  return candidate;
31527
31850
  }
31528
31851
  }
@@ -31536,27 +31859,27 @@ function findWasmDir() {
31536
31859
  }
31537
31860
  function findRuntimeDir() {
31538
31861
  const here = entryDir();
31539
- const seaRuntime = join7(here, "resources", "wasm");
31540
- if (existsSync7(join7(seaRuntime, "web-tree-sitter.wasm"))) return seaRuntime;
31862
+ const seaRuntime = join8(here, "resources", "wasm");
31863
+ if (existsSync8(join8(seaRuntime, "web-tree-sitter.wasm"))) return seaRuntime;
31541
31864
  let dir = here;
31542
31865
  for (let i2 = 0; i2 < 6; i2++) {
31543
- const flat = join7(dir, "node_modules", "web-tree-sitter");
31544
- if (existsSync7(join7(flat, "web-tree-sitter.wasm"))) return flat;
31866
+ const flat = join8(dir, "node_modules", "web-tree-sitter");
31867
+ if (existsSync8(join8(flat, "web-tree-sitter.wasm"))) return flat;
31545
31868
  dir = dirname4(dir);
31546
31869
  }
31547
31870
  let root = here;
31548
31871
  for (let i2 = 0; i2 < 6; i2++) {
31549
- const pnpmDir = join7(root, "node_modules", ".pnpm");
31550
- if (existsSync7(pnpmDir)) {
31872
+ const pnpmDir = join8(root, "node_modules", ".pnpm");
31873
+ if (existsSync8(pnpmDir)) {
31551
31874
  for (const entry of readdirSync2(pnpmDir)) {
31552
31875
  if (entry.startsWith("web-tree-sitter@")) {
31553
- const candidate = join7(
31876
+ const candidate = join8(
31554
31877
  pnpmDir,
31555
31878
  entry,
31556
31879
  "node_modules",
31557
31880
  "web-tree-sitter"
31558
31881
  );
31559
- if (existsSync7(join7(candidate, "web-tree-sitter.wasm"))) {
31882
+ if (existsSync8(join8(candidate, "web-tree-sitter.wasm"))) {
31560
31883
  return candidate;
31561
31884
  }
31562
31885
  }
@@ -31573,7 +31896,7 @@ async function loadWebTreeSitter() {
31573
31896
  void err2;
31574
31897
  }
31575
31898
  const here = entryDir();
31576
- const seaResourceBase = join7(here, "resources", "_resolve.js");
31899
+ const seaResourceBase = join8(here, "resources", "_resolve.js");
31577
31900
  const resourceRequire = createRequire2(seaResourceBase);
31578
31901
  return resourceRequire("web-tree-sitter");
31579
31902
  }
@@ -31588,9 +31911,9 @@ async function ensureTreeSitterReady() {
31588
31911
  await Parser2.init({
31589
31912
  locateFile: (name2) => {
31590
31913
  if (name2 === "tree-sitter.wasm" || name2 === "web-tree-sitter.wasm") {
31591
- return join7(runtime, name2);
31914
+ return join8(runtime, name2);
31592
31915
  }
31593
- return join7(grammars, name2);
31916
+ return join8(grammars, name2);
31594
31917
  }
31595
31918
  });
31596
31919
  })();
@@ -31602,7 +31925,7 @@ async function loadGrammar(name2) {
31602
31925
  if (cached2) return cached2;
31603
31926
  if (!languageClass) throw new Error("tree-sitter not initialized");
31604
31927
  const grammars = findWasmDir();
31605
- const lang = await languageClass.load(join7(grammars, `${name2}.wasm`));
31928
+ const lang = await languageClass.load(join8(grammars, `${name2}.wasm`));
31606
31929
  grammarCache.set(name2, lang);
31607
31930
  return lang;
31608
31931
  }
@@ -34504,7 +34827,7 @@ var init_src11 = __esm({
34504
34827
  // src/reconcile.ts
34505
34828
  import { execFileSync as execFileSync2 } from "node:child_process";
34506
34829
  import { readdirSync as readdirSync3, statSync as statSync2 } from "node:fs";
34507
- import { join as join8, relative as relative3, sep as sep2 } from "node:path";
34830
+ import { join as join9, relative as relative3, sep as sep2 } from "node:path";
34508
34831
  function gitSourceFiles(root) {
34509
34832
  let stdout;
34510
34833
  try {
@@ -34519,7 +34842,7 @@ function gitSourceFiles(root) {
34519
34842
  const out2 = [];
34520
34843
  for (const rel of stdout.split("\0")) {
34521
34844
  if (!rel || !SOURCE_RE.test(rel)) continue;
34522
- const abs = join8(root, rel);
34845
+ const abs = join9(root, rel);
34523
34846
  if (IGNORED.test(abs)) continue;
34524
34847
  out2.push(abs);
34525
34848
  }
@@ -34534,7 +34857,7 @@ function* walkSource(dir) {
34534
34857
  }
34535
34858
  for (const e of entries) {
34536
34859
  const name2 = String(e.name);
34537
- const full = join8(dir, name2);
34860
+ const full = join9(dir, name2);
34538
34861
  if (IGNORED.test(full)) continue;
34539
34862
  if (e.isDirectory()) yield* walkSource(full);
34540
34863
  else if (SOURCE_RE.test(name2)) yield full;
@@ -34612,7 +34935,7 @@ __export(mcp_exports, {
34612
34935
  runTool: () => runTool,
34613
34936
  searchGraph: () => searchGraph
34614
34937
  });
34615
- import { existsSync as existsSync8, readFileSync as readFileSync6 } from "node:fs";
34938
+ import { existsSync as existsSync9, readFileSync as readFileSync7 } from "node:fs";
34616
34939
  import { resolve } from "node:path";
34617
34940
  function collectEnrichmentPulls(store, opts = {}) {
34618
34941
  const pending = store.findNodesByLabel("Solution").filter((s) => s.attrs["enrichmentPending"] === true).filter((s) => !opts.onlyUnsurfaced || s.attrs["enrichmentSurfaced"] !== true);
@@ -34725,10 +35048,10 @@ function showNode(store, node2, maxLines) {
34725
35048
  if (!relPath) return { found: false, reason: "no file owner for node" };
34726
35049
  const workspaceRoot = process.cwd();
34727
35050
  const absPath = resolve(workspaceRoot, relPath);
34728
- if (!existsSync8(absPath)) {
35051
+ if (!existsSync9(absPath)) {
34729
35052
  return { found: false, reason: `file not found on disk: ${absPath}` };
34730
35053
  }
34731
- const source = readFileSync6(absPath, "utf8");
35054
+ const source = readFileSync7(absPath, "utf8");
34732
35055
  const attrs = node2.attrs;
34733
35056
  let startByte = attrs["bodyStartByte"] ?? attrs["startByte"];
34734
35057
  let endByte = attrs["bodyEndByte"] ?? attrs["endByte"];
@@ -34941,7 +35264,20 @@ function buildToolContext() {
34941
35264
  async function runMcpServer(workspaceRoot) {
34942
35265
  const paths = workspacePaths(workspaceRoot);
34943
35266
  const store = openGraphStore({ path: paths.castalia });
34944
- const handle2 = createMcpHandler(store, buildToolContext());
35267
+ let summariesMemo = null;
35268
+ const symbolSummaries = () => {
35269
+ const now = Date.now();
35270
+ if (!summariesMemo || now - summariesMemo.at > 6e4) {
35271
+ let map2 = /* @__PURE__ */ new Map();
35272
+ try {
35273
+ map2 = summariesByBodyHash(loadSymbolSummaryCache(paths.configDir));
35274
+ } catch {
35275
+ }
35276
+ summariesMemo = { at: now, map: map2 };
35277
+ }
35278
+ return summariesMemo.map;
35279
+ };
35280
+ const handle2 = createMcpHandler(store, { ...buildToolContext(), symbolSummaries });
34945
35281
  process.stdin.setEncoding("utf8");
34946
35282
  let buffer = "";
34947
35283
  process.stdin.on("data", (chunk) => {
@@ -34980,6 +35316,7 @@ var init_mcp = __esm({
34980
35316
  init_src2();
34981
35317
  init_src10();
34982
35318
  init_paths();
35319
+ init_symbol_summaries();
34983
35320
  init_webui();
34984
35321
  init_reconcile();
34985
35322
  init_agent_signals();
@@ -35052,7 +35389,14 @@ var init_mcp = __esm({
35052
35389
  score: h.pageRank,
35053
35390
  hops: 0
35054
35391
  }));
35055
- const dual = await dualAugment({ store, cloud: ctx.cloud, localHits, queryText: query, limit });
35392
+ const dual = await dualAugment({
35393
+ store,
35394
+ cloud: ctx.cloud,
35395
+ localHits,
35396
+ queryText: query,
35397
+ limit,
35398
+ ...ctx.symbolSummaries ? { summaries: ctx.symbolSummaries() } : {}
35399
+ });
35056
35400
  if (dual.status === "merged") {
35057
35401
  return {
35058
35402
  query,
@@ -35217,7 +35561,8 @@ var init_mcp = __esm({
35217
35561
  cloud: ctx.cloud,
35218
35562
  localHits,
35219
35563
  seedNode,
35220
- limit: args2["limit"] != null ? Number(args2["limit"]) : 20
35564
+ limit: args2["limit"] != null ? Number(args2["limit"]) : 20,
35565
+ ...ctx.symbolSummaries ? { summaries: ctx.symbolSummaries() } : {}
35221
35566
  });
35222
35567
  if (dual.status === "merged") {
35223
35568
  return {
@@ -35732,7 +36077,14 @@ var init_mcp = __esm({
35732
36077
  score: h.score,
35733
36078
  hops: 0
35734
36079
  }));
35735
- const dual = await dualAugment({ store, cloud: ctx.cloud, localHits, seedNode: node2, limit });
36080
+ const dual = await dualAugment({
36081
+ store,
36082
+ cloud: ctx.cloud,
36083
+ localHits,
36084
+ seedNode: node2,
36085
+ limit,
36086
+ ...ctx.symbolSummaries ? { summaries: ctx.symbolSummaries() } : {}
36087
+ });
35736
36088
  if (dual.status === "merged") {
35737
36089
  return {
35738
36090
  seedId: id,
@@ -35923,7 +36275,7 @@ var init_mcp = __esm({
35923
36275
  inputSchema: { type: "object", properties: {} },
35924
36276
  handler: () => {
35925
36277
  const path2 = sharedStorePath();
35926
- if (!existsSync8(path2)) return { count: 0, pending: [] };
36278
+ if (!existsSync9(path2)) return { count: 0, pending: [] };
35927
36279
  const shared = openGraphStore({ path: path2 });
35928
36280
  try {
35929
36281
  const pending = pendingAbstractions(shared);
@@ -35954,7 +36306,7 @@ var init_mcp = __esm({
35954
36306
  },
35955
36307
  handler: (args2) => {
35956
36308
  const path2 = sharedStorePath();
35957
- if (!existsSync8(path2)) return { count: 0, routes: [] };
36309
+ if (!existsSync9(path2)) return { count: 0, routes: [] };
35958
36310
  const shared = openGraphStore({ path: path2 });
35959
36311
  try {
35960
36312
  const result = triageOf(shared, {
@@ -36339,8 +36691,8 @@ __export(vfile_exports, {
36339
36691
  resolvePath: () => resolvePath,
36340
36692
  segmentsOf: () => segmentsOf
36341
36693
  });
36342
- import { writeFileSync as writeFileSync6 } from "node:fs";
36343
- import { join as join9, resolve as resolve2, sep as sep3 } from "node:path";
36694
+ import { writeFileSync as writeFileSync7 } from "node:fs";
36695
+ import { join as join10, resolve as resolve2, sep as sep3 } from "node:path";
36344
36696
  function segmentsOf(rawPath) {
36345
36697
  let p = rawPath.replace(/\\/g, "/");
36346
36698
  p = p.replace(/^.*\.errata\/g\//, "").replace(/^\/?g\//, "").replace(/^\/+/, "");
@@ -36414,14 +36766,14 @@ async function renderVFile(rawPath, store, ctx = {}) {
36414
36766
  }
36415
36767
  async function materializeVFile(rawPath, workspaceRoot, store, ctx = {}) {
36416
36768
  const segs = segmentsOf(rawPath);
36417
- const gRoot = join9(workspaceRoot, ".errata", "g");
36769
+ const gRoot = join10(workspaceRoot, ".errata", "g");
36418
36770
  const abs = resolve2(gRoot, ...segs.length ? segs : ["index"]);
36419
36771
  if (abs !== gRoot && !abs.startsWith(gRoot + sep3)) {
36420
36772
  throw new Error(`refusing to materialize outside .errata/g: ${rawPath}`);
36421
36773
  }
36422
36774
  const text = await renderVFile(rawPath, store, ctx);
36423
36775
  ensureParent(abs);
36424
- writeFileSync6(abs, text, "utf8");
36776
+ writeFileSync7(abs, text, "utf8");
36425
36777
  return abs;
36426
36778
  }
36427
36779
  async function materializeOverview(workspaceRoot, store, ctx = {}) {
@@ -36506,25 +36858,25 @@ the tool surface; the path is the thin, composable channel.
36506
36858
 
36507
36859
  // src/outbox.ts
36508
36860
  import {
36509
- existsSync as existsSync9,
36861
+ existsSync as existsSync10,
36510
36862
  readdirSync as readdirSync4,
36511
- readFileSync as readFileSync7,
36863
+ readFileSync as readFileSync8,
36512
36864
  renameSync,
36513
36865
  unlinkSync,
36514
- writeFileSync as writeFileSync7
36866
+ writeFileSync as writeFileSync8
36515
36867
  } from "node:fs";
36516
- import { join as join10 } from "node:path";
36868
+ import { join as join11 } from "node:path";
36517
36869
  import { createHash as createHash11 } from "node:crypto";
36518
36870
  function enqueueOutbox(paths, payload) {
36519
36871
  ensureDir(paths.outbox);
36520
36872
  const id = createHash11("sha256").update(JSON.stringify(payload)).digest("hex").slice(0, 16);
36521
- const file2 = join10(paths.outbox, `${Date.now()}-${id}.json`);
36522
- writeFileSync7(file2, JSON.stringify(payload, null, 2), "utf8");
36873
+ const file2 = join11(paths.outbox, `${Date.now()}-${id}.json`);
36874
+ writeFileSync8(file2, JSON.stringify(payload, null, 2), "utf8");
36523
36875
  return file2;
36524
36876
  }
36525
36877
  async function flushOutbox(paths, client, store) {
36526
36878
  ensureDir(paths.outbox);
36527
- const entries = existsSync9(paths.outbox) ? readdirSync4(paths.outbox) : [];
36879
+ const entries = existsSync10(paths.outbox) ? readdirSync4(paths.outbox) : [];
36528
36880
  let uploaded = 0;
36529
36881
  let failed = 0;
36530
36882
  const quarantine = (abs, reason) => {
@@ -36535,10 +36887,10 @@ async function flushOutbox(paths, client, store) {
36535
36887
  }
36536
36888
  };
36537
36889
  for (const f of entries.filter((e) => e.endsWith(".json")).sort()) {
36538
- const abs = join10(paths.outbox, f);
36890
+ const abs = join11(paths.outbox, f);
36539
36891
  let payload;
36540
36892
  try {
36541
- payload = JSON.parse(readFileSync7(abs, "utf8"));
36893
+ payload = JSON.parse(readFileSync8(abs, "utf8"));
36542
36894
  } catch {
36543
36895
  failed++;
36544
36896
  quarantine(abs, "unparseable JSON");
@@ -36566,7 +36918,7 @@ async function flushOutbox(paths, client, store) {
36566
36918
  }
36567
36919
  }
36568
36920
  }
36569
- const remainingFiles = existsSync9(paths.outbox) ? readdirSync4(paths.outbox).filter((e) => e.endsWith(".json")) : [];
36921
+ const remainingFiles = existsSync10(paths.outbox) ? readdirSync4(paths.outbox).filter((e) => e.endsWith(".json")) : [];
36570
36922
  return { uploaded, failed, remaining: remainingFiles.length };
36571
36923
  }
36572
36924
  var init_outbox = __esm({
@@ -36585,7 +36937,7 @@ __export(webui_exports, {
36585
36937
  findFileByPath: () => findFileByPath,
36586
36938
  recallForFile: () => recallForFile
36587
36939
  });
36588
- import { join as join11 } from "node:path";
36940
+ import { join as join12 } from "node:path";
36589
36941
  function fileUriToFsPath(raw2) {
36590
36942
  let p = raw2.replace(/^file:\/\//, "").replace(/\\/g, "/");
36591
36943
  if (/^\/[A-Za-z]:/.test(p)) p = p.slice(1);
@@ -36946,7 +37298,7 @@ function buildWebUi(deps) {
36946
37298
  } catch {
36947
37299
  return c.json({});
36948
37300
  }
36949
- const block = readManagedBlockWithHash(join11(deps.paths.root, "AGENTS.md"));
37301
+ const block = readManagedBlockWithHash(join12(deps.paths.root, "AGENTS.md"));
36950
37302
  const decision = decideContextInject({
36951
37303
  event: String(body2["hook_event_name"] ?? "UserPromptSubmit"),
36952
37304
  source: String(body2["source"] ?? ""),
@@ -37548,12 +37900,12 @@ var init_report_render = __esm({
37548
37900
 
37549
37901
  // src/cli.ts
37550
37902
  init_src5();
37551
- import { closeSync as closeSync2, existsSync as existsSync19, openSync as openSync2, readFileSync as readFileSync18, renameSync as renameSync3, statSync as statSync5 } from "node:fs";
37552
- import { join as join22 } from "node:path";
37903
+ import { closeSync as closeSync2, existsSync as existsSync20, openSync as openSync2, readFileSync as readFileSync19, renameSync as renameSync3, statSync as statSync5 } from "node:fs";
37904
+ import { join as join23 } from "node:path";
37553
37905
  import { spawn as spawn3 } from "node:child_process";
37554
37906
 
37555
37907
  // src/daemon.ts
37556
- import { existsSync as existsSync15, writeFileSync as writeFileSync12 } from "node:fs";
37908
+ import { existsSync as existsSync16, writeFileSync as writeFileSync13 } from "node:fs";
37557
37909
 
37558
37910
  // ../../node_modules/.pnpm/@hono+node-server@1.19.11_hono@4.12.8/node_modules/@hono/node-server/dist/index.mjs
37559
37911
  import { createServer as createServerHTTP } from "http";
@@ -38133,8 +38485,8 @@ init_config();
38133
38485
 
38134
38486
  // src/engine.ts
38135
38487
  import { execFileSync as execFileSync3 } from "node:child_process";
38136
- import { existsSync as existsSync14, statSync as statSync4, appendFileSync as appendFileSync2, readdirSync as readdirSync7, renameSync as renameSync2, readFileSync as readFileSync13, writeFileSync as writeFileSync11 } from "node:fs";
38137
- import { join as join19, relative as relative6, sep as sep4 } from "node:path";
38488
+ import { existsSync as existsSync15, statSync as statSync4, appendFileSync as appendFileSync2, readdirSync as readdirSync7, renameSync as renameSync2, readFileSync as readFileSync14, writeFileSync as writeFileSync12 } from "node:fs";
38489
+ import { join as join20, relative as relative6, sep as sep4 } from "node:path";
38138
38490
 
38139
38491
  // ../../node_modules/.pnpm/chokidar@4.0.3/node_modules/chokidar/esm/index.js
38140
38492
  import { stat as statcb } from "fs";
@@ -39996,8 +40348,8 @@ init_src10();
39996
40348
  init_review2();
39997
40349
 
39998
40350
  // src/turn.ts
39999
- import { closeSync, existsSync as existsSync10, fstatSync, openSync, readdirSync as readdirSync5, readSync, statSync as statSync3 } from "node:fs";
40000
- import { basename as basename3, dirname as dirname7, join as join14 } from "node:path";
40351
+ import { closeSync, existsSync as existsSync11, fstatSync, openSync, readdirSync as readdirSync5, readSync, statSync as statSync3 } from "node:fs";
40352
+ import { basename as basename3, dirname as dirname7, join as join15 } from "node:path";
40001
40353
  import { homedir as homedir3 } from "node:os";
40002
40354
  function readTail(path2, maxBytes) {
40003
40355
  let fd;
@@ -40106,11 +40458,11 @@ function turnsSince(turns, mark) {
40106
40458
  return at >= 0 ? turns.slice(at + 1) : turns;
40107
40459
  }
40108
40460
  function claudeProjectDir(cwd, home = homedir3()) {
40109
- return join14(home, ".claude", "projects", cwd.replace(/[\\/:.]/g, "-"));
40461
+ return join15(home, ".claude", "projects", cwd.replace(/[\\/:.]/g, "-"));
40110
40462
  }
40111
40463
  function recentTranscripts(cwd, opts = {}) {
40112
40464
  const dir = claudeProjectDir(cwd, opts.home ?? homedir3());
40113
- if (!existsSync10(dir)) return [];
40465
+ if (!existsSync11(dir)) return [];
40114
40466
  let names;
40115
40467
  try {
40116
40468
  names = readdirSync5(dir);
@@ -40121,7 +40473,7 @@ function recentTranscripts(cwd, opts = {}) {
40121
40473
  const refs = [];
40122
40474
  for (const name2 of names) {
40123
40475
  if (!name2.endsWith(".jsonl")) continue;
40124
- const path2 = join14(dir, name2);
40476
+ const path2 = join15(dir, name2);
40125
40477
  let mtimeMs;
40126
40478
  try {
40127
40479
  mtimeMs = statSync3(path2).mtimeMs;
@@ -40136,8 +40488,8 @@ function recentTranscripts(cwd, opts = {}) {
40136
40488
  }
40137
40489
  function subagentTranscripts(mainTranscriptPath, sessionId) {
40138
40490
  if (!mainTranscriptPath || !sessionId) return [];
40139
- const dir = join14(dirname7(mainTranscriptPath), sessionId, "subagents");
40140
- if (!existsSync10(dir)) return [];
40491
+ const dir = join15(dirname7(mainTranscriptPath), sessionId, "subagents");
40492
+ if (!existsSync11(dir)) return [];
40141
40493
  let names;
40142
40494
  try {
40143
40495
  names = readdirSync5(dir);
@@ -40147,7 +40499,7 @@ function subagentTranscripts(mainTranscriptPath, sessionId) {
40147
40499
  const refs = [];
40148
40500
  for (const name2 of names) {
40149
40501
  if (!name2.endsWith(".jsonl")) continue;
40150
- const path2 = join14(dir, name2);
40502
+ const path2 = join15(dir, name2);
40151
40503
  let mtimeMs;
40152
40504
  try {
40153
40505
  mtimeMs = statSync3(path2).mtimeMs;
@@ -40164,7 +40516,7 @@ function subagentTranscripts(mainTranscriptPath, sessionId) {
40164
40516
  init_src();
40165
40517
  init_src2();
40166
40518
  init_agent_signals();
40167
- import { readFileSync as readFileSync8, writeFileSync as writeFileSync8 } from "node:fs";
40519
+ import { readFileSync as readFileSync9, writeFileSync as writeFileSync9 } from "node:fs";
40168
40520
  var NEG = /n['']t|\b(?:not|never|no|none|neither|nor|unrelated|irrelevant|would|might|could|if)\b/i;
40169
40521
  var CITE_GROUP_RE = /\(((?:[^()\n]|\([^()\n]*\)){1,200})\)/g;
40170
40522
  var HANDLE_RE = /\[([a-z0-9][\w-]{0,40})\]|((?:pat|sol|drc|dcause|dfix|dprob|prob|claim|err)_[0-9a-f]{6,})/gi;
@@ -40414,13 +40766,13 @@ function writePrimingHandles(path2, nodes, now = Date.now()) {
40414
40766
  entries.sort((a, b) => (b[1].seenAt ?? 0) - (a[1].seenAt ?? 0));
40415
40767
  entries.length = HANDLE_MAP_MAX;
40416
40768
  }
40417
- writeFileSync8(path2, JSON.stringify(Object.fromEntries(entries)));
40769
+ writeFileSync9(path2, JSON.stringify(Object.fromEntries(entries)));
40418
40770
  } catch {
40419
40771
  }
40420
40772
  }
40421
40773
  function readPrimingHandles(path2) {
40422
40774
  try {
40423
- return JSON.parse(readFileSync8(path2, "utf8"));
40775
+ return JSON.parse(readFileSync9(path2, "utf8"));
40424
40776
  } catch {
40425
40777
  return {};
40426
40778
  }
@@ -40676,6 +41028,7 @@ ${conversation}` }]
40676
41028
  }
40677
41029
 
40678
41030
  // src/engine.ts
41031
+ init_symbol_summaries();
40679
41032
  init_reconcile();
40680
41033
 
40681
41034
  // src/episode.ts
@@ -40872,11 +41225,11 @@ init_outbox();
40872
41225
  init_src8();
40873
41226
  init_src();
40874
41227
  init_src2();
40875
- import { readFileSync as readFileSync9 } from "node:fs";
40876
- import { join as join15 } from "node:path";
41228
+ import { readFileSync as readFileSync10 } from "node:fs";
41229
+ import { join as join16 } from "node:path";
40877
41230
  function loadClaimIgnorePatterns(workspaceRoot) {
40878
41231
  try {
40879
- return readFileSync9(join15(workspaceRoot, ".errataignore"), "utf8").split(/\r?\n/).map((l) => l.trim()).filter((l) => l.length > 0 && !l.startsWith("#")).map((l) => l.toLowerCase());
41232
+ return readFileSync10(join16(workspaceRoot, ".errataignore"), "utf8").split(/\r?\n/).map((l) => l.trim()).filter((l) => l.length > 0 && !l.startsWith("#")).map((l) => l.toLowerCase());
40880
41233
  } catch {
40881
41234
  return [];
40882
41235
  }
@@ -41067,13 +41420,21 @@ function isSyncableRoute(edge2, shared, triage, ignorePatterns = []) {
41067
41420
  function generalizeRouteForSync(edge2, level) {
41068
41421
  const disc = edge2.attrs["discriminator"];
41069
41422
  const local = edge2.attrs["perContext"] ?? {};
41070
- const confirmed = {};
41071
- for (const [b, c] of Object.entries(local)) confirmed[b] = c.confirmed;
41423
+ const perContext = {};
41424
+ for (const [b, c] of Object.entries(local)) {
41425
+ const independent = c.independent ?? c.contributors?.length;
41426
+ const inferredIndependent = c.inferredIndependent ?? c.inferredContributors?.length;
41427
+ perContext[b] = {
41428
+ confirmed: c.confirmed,
41429
+ ...typeof independent === "number" && independent > 0 ? { independent } : {},
41430
+ ...typeof inferredIndependent === "number" && inferredIndependent > 0 ? { inferredIndependent } : {}
41431
+ };
41432
+ }
41072
41433
  return {
41073
41434
  ...edge2,
41074
41435
  attrs: {
41075
41436
  driftKind: edge2.attrs["driftKind"],
41076
- perContext: confirmed,
41437
+ perContext,
41077
41438
  provisional: false,
41078
41439
  ...typeof disc === "string" && disc.trim() ? { discriminator: generalize(disc, { level }).text } : {}
41079
41440
  },
@@ -41168,22 +41529,22 @@ async function pullCloudTriage(shared, cloud, profile, limit = 50) {
41168
41529
  }
41169
41530
 
41170
41531
  // src/git-sensor.ts
41171
- import { existsSync as existsSync11, readFileSync as readFileSync10, watch as fsWatch } from "node:fs";
41172
- import { join as join16 } from "node:path";
41532
+ import { existsSync as existsSync12, readFileSync as readFileSync11, watch as fsWatch } from "node:fs";
41533
+ import { join as join17 } from "node:path";
41173
41534
  function readFirstLine(path2) {
41174
41535
  try {
41175
- return readFileSync10(path2, "utf8").split(/\r?\n/, 1)[0].trim();
41536
+ return readFileSync11(path2, "utf8").split(/\r?\n/, 1)[0].trim();
41176
41537
  } catch {
41177
41538
  return null;
41178
41539
  }
41179
41540
  }
41180
41541
  function readGitRefState(gitDir) {
41181
- const head2 = readFirstLine(join16(gitDir, "HEAD"));
41542
+ const head2 = readFirstLine(join17(gitDir, "HEAD"));
41182
41543
  const m = head2 ? /^ref:\s*refs\/heads\/(.+)$/.exec(head2) : null;
41183
41544
  const branch = m ? m[1] : null;
41184
41545
  let sha2 = null;
41185
41546
  if (branch) {
41186
- sha2 = readFirstLine(join16(gitDir, "refs", "heads", branch));
41547
+ sha2 = readFirstLine(join17(gitDir, "refs", "heads", branch));
41187
41548
  if (!sha2) sha2 = shaFromPackedRefs(gitDir, `refs/heads/${branch}`);
41188
41549
  } else if (head2 && /^[0-9a-f]{7,40}$/i.test(head2)) {
41189
41550
  sha2 = head2;
@@ -41191,13 +41552,13 @@ function readGitRefState(gitDir) {
41191
41552
  return {
41192
41553
  branch,
41193
41554
  sha: sha2,
41194
- mergeHeadExists: existsSync11(join16(gitDir, "MERGE_HEAD")),
41195
- origHeadExists: existsSync11(join16(gitDir, "ORIG_HEAD"))
41555
+ mergeHeadExists: existsSync12(join17(gitDir, "MERGE_HEAD")),
41556
+ origHeadExists: existsSync12(join17(gitDir, "ORIG_HEAD"))
41196
41557
  };
41197
41558
  }
41198
41559
  function shaFromPackedRefs(gitDir, ref) {
41199
41560
  try {
41200
- for (const line of readFileSync10(join16(gitDir, "packed-refs"), "utf8").split(/\r?\n/)) {
41561
+ for (const line of readFileSync11(join17(gitDir, "packed-refs"), "utf8").split(/\r?\n/)) {
41201
41562
  const [sha2, name2] = line.split(/\s+/);
41202
41563
  if (name2 === ref && sha2) return sha2;
41203
41564
  }
@@ -41231,7 +41592,7 @@ function startGitSensor(gitDir, onEvent, opts = {}) {
41231
41592
  const settle = () => {
41232
41593
  if (timer) clearTimeout(timer);
41233
41594
  timer = setTimeout(() => {
41234
- if (existsSync11(join16(gitDir, "index.lock"))) {
41595
+ if (existsSync12(join17(gitDir, "index.lock"))) {
41235
41596
  settle();
41236
41597
  return;
41237
41598
  }
@@ -41242,7 +41603,7 @@ function startGitSensor(gitDir, onEvent, opts = {}) {
41242
41603
  }, debounceMs);
41243
41604
  };
41244
41605
  for (const sub of ["HEAD", "logs/HEAD", "MERGE_HEAD", "ORIG_HEAD"]) {
41245
- const p = join16(gitDir, sub);
41606
+ const p = join17(gitDir, sub);
41246
41607
  try {
41247
41608
  watchers.push(fsWatch(p, settle));
41248
41609
  } catch {
@@ -41467,21 +41828,21 @@ var TelemetryRecorder = class {
41467
41828
 
41468
41829
  // src/skills.ts
41469
41830
  import {
41470
- existsSync as existsSync12,
41831
+ existsSync as existsSync13,
41471
41832
  mkdirSync as mkdirSync5,
41472
- readFileSync as readFileSync11,
41833
+ readFileSync as readFileSync12,
41473
41834
  readdirSync as readdirSync6,
41474
41835
  unlinkSync as unlinkSync2,
41475
- writeFileSync as writeFileSync9
41836
+ writeFileSync as writeFileSync10
41476
41837
  } from "node:fs";
41477
- import { basename as basename4, join as join17 } from "node:path";
41838
+ import { basename as basename4, join as join18 } from "node:path";
41478
41839
  function skillFileName(id) {
41479
41840
  return `${id.replace(/[^A-Za-z0-9_.-]/g, "_")}.md`;
41480
41841
  }
41481
41842
  function readSkillManifest(manifestPath) {
41482
- if (!existsSync12(manifestPath)) return [];
41843
+ if (!existsSync13(manifestPath)) return [];
41483
41844
  try {
41484
- const parsed = JSON.parse(readFileSync11(manifestPath, "utf8"));
41845
+ const parsed = JSON.parse(readFileSync12(manifestPath, "utf8"));
41485
41846
  return (parsed.skills ?? []).map((s) => ({
41486
41847
  title: s.title ?? "",
41487
41848
  layer: s.layer ?? "technique",
@@ -41504,7 +41865,7 @@ async function syncSkills(paths, client, seed) {
41504
41865
  for (const s of res.skills) {
41505
41866
  const fileName = skillFileName(s.id);
41506
41867
  keep.add(fileName);
41507
- writeFileSync9(join17(paths.skillsDir, fileName), s.markdown, "utf8");
41868
+ writeFileSync10(join18(paths.skillsDir, fileName), s.markdown, "utf8");
41508
41869
  rows.push({
41509
41870
  id: s.id,
41510
41871
  title: s.title,
@@ -41518,13 +41879,13 @@ async function syncSkills(paths, client, seed) {
41518
41879
  if (!f.endsWith(".md")) continue;
41519
41880
  if (keep.has(basename4(f))) continue;
41520
41881
  try {
41521
- unlinkSync2(join17(paths.skillsDir, f));
41882
+ unlinkSync2(join18(paths.skillsDir, f));
41522
41883
  pruned++;
41523
41884
  } catch {
41524
41885
  }
41525
41886
  }
41526
41887
  rows.sort((a, b) => a.id.localeCompare(b.id));
41527
- writeFileSync9(
41888
+ writeFileSync10(
41528
41889
  paths.skillsManifest,
41529
41890
  JSON.stringify({ generatedAt: Date.now(), skills: rows }, null, 2),
41530
41891
  "utf8"
@@ -41661,30 +42022,30 @@ var CausalBuffer = class {
41661
42022
  // src/profile.ts
41662
42023
  init_src2();
41663
42024
  init_paths();
41664
- import { existsSync as existsSync13, readFileSync as readFileSync12, writeFileSync as writeFileSync10 } from "node:fs";
42025
+ import { existsSync as existsSync14, readFileSync as readFileSync13, writeFileSync as writeFileSync11 } from "node:fs";
41665
42026
  import { createHash as createHash12 } from "node:crypto";
41666
- import { join as join18 } from "node:path";
42027
+ import { join as join19 } from "node:path";
41667
42028
  function workspaceId(root) {
41668
42029
  return "wp_" + createHash12("sha256").update(root).digest("hex").slice(0, 12);
41669
42030
  }
41670
42031
  function loadProfile(root) {
41671
42032
  const p = workspacePaths(root);
41672
- if (!existsSync13(p.workspaceJson)) return null;
41673
- return JSON.parse(readFileSync12(p.workspaceJson, "utf8"));
42033
+ if (!existsSync14(p.workspaceJson)) return null;
42034
+ return JSON.parse(readFileSync13(p.workspaceJson, "utf8"));
41674
42035
  }
41675
42036
  function saveProfile(root, profile) {
41676
42037
  const p = workspacePaths(root);
41677
42038
  ensureDir(p.configDir);
41678
- writeFileSync10(p.workspaceJson, JSON.stringify(profile, null, 2), "utf8");
42039
+ writeFileSync11(p.workspaceJson, JSON.stringify(profile, null, 2), "utf8");
41679
42040
  }
41680
42041
  function autodetectProfile(root) {
41681
42042
  const id = workspaceId(root);
41682
42043
  const name2 = root.split(/[\\/]/).filter(Boolean).pop() ?? "workspace";
41683
42044
  const p = emptyProfile(id, name2);
41684
- const pkgPath = join18(root, "package.json");
41685
- if (existsSync13(pkgPath)) {
42045
+ const pkgPath = join19(root, "package.json");
42046
+ if (existsSync14(pkgPath)) {
41686
42047
  try {
41687
- const pkg = JSON.parse(readFileSync12(pkgPath, "utf8"));
42048
+ const pkg = JSON.parse(readFileSync13(pkgPath, "utf8"));
41688
42049
  p.languages.push("typescript", "javascript");
41689
42050
  const nodeVer = pkg.engines?.node ?? "node";
41690
42051
  p.stack.push(`node@${nodeVer}`);
@@ -41705,10 +42066,10 @@ function autodetectProfile(root) {
41705
42066
  } catch {
41706
42067
  }
41707
42068
  }
41708
- const pyproject = join18(root, "pyproject.toml");
41709
- if (existsSync13(pyproject)) {
42069
+ const pyproject = join19(root, "pyproject.toml");
42070
+ if (existsSync14(pyproject)) {
41710
42071
  try {
41711
- const txt = readFileSync12(pyproject, "utf8");
42072
+ const txt = readFileSync13(pyproject, "utf8");
41712
42073
  const py = /python\s*=\s*"([^"]+)"/.exec(txt)?.[1];
41713
42074
  p.languages.push("python");
41714
42075
  p.stack.push(`python@${py ?? "3"}`);
@@ -41719,16 +42080,16 @@ function autodetectProfile(root) {
41719
42080
  } catch {
41720
42081
  }
41721
42082
  }
41722
- const reqs = join18(root, "requirements.txt");
41723
- if (existsSync13(reqs)) {
42083
+ const reqs = join19(root, "requirements.txt");
42084
+ if (existsSync14(reqs)) {
41724
42085
  if (!p.languages.includes("python")) p.languages.push("python");
41725
42086
  if (!p.stack.includes("python@3")) p.stack.push("python@3");
41726
42087
  }
41727
- if (existsSync13(join18(root, "go.mod"))) {
42088
+ if (existsSync14(join19(root, "go.mod"))) {
41728
42089
  p.languages.push("go");
41729
42090
  p.stack.push("go");
41730
42091
  }
41731
- if (existsSync13(join18(root, "Cargo.toml"))) {
42092
+ if (existsSync14(join19(root, "Cargo.toml"))) {
41732
42093
  p.languages.push("rust");
41733
42094
  p.stack.push("rust");
41734
42095
  }
@@ -41886,7 +42247,7 @@ function startLoopLagMonitor(thresholdMs = 1e3) {
41886
42247
  }
41887
42248
 
41888
42249
  // src/engine.ts
41889
- var DAEMON_VERSION = true ? "2.0.0-dev.35" : "2.0.0-alpha.0";
42250
+ var DAEMON_VERSION = true ? "2.0.0-dev.37" : "2.0.0-alpha.0";
41890
42251
  var IGNORED_PATH = /[\\/](?:\.git|node_modules|\.errata|\.claude|\.codex|\.cursor|\.turbo|\.next|dist|coverage|test-results|playwright-report|__pycache__)(?:[\\/]|$)/;
41891
42252
  var IGNORED_NOISE = /castalia\.db|eventlog\.sqlite|turn-cursors/;
41892
42253
  var GIT_OP_MUTE_MS = 4e3;
@@ -41896,7 +42257,7 @@ var TURN_REPLAY_LOOKBACK_MS = 7 * 24 * 60 * 6e4;
41896
42257
  function appendIdentityAudit(path2, record2, line) {
41897
42258
  if (!record2.accepted && record2.score <= 0) return;
41898
42259
  try {
41899
- if (existsSync14(path2) && statSync4(path2).size >= IDENTITY_AUDIT_MAX_BYTES) {
42260
+ if (existsSync15(path2) && statSync4(path2).size >= IDENTITY_AUDIT_MAX_BYTES) {
41900
42261
  renameSync2(path2, `${path2}.1`);
41901
42262
  }
41902
42263
  appendFileSync2(path2, line);
@@ -41906,14 +42267,14 @@ function appendIdentityAudit(path2, record2, line) {
41906
42267
  var yieldToLoop = () => new Promise((r) => setImmediate(r));
41907
42268
  function loadTurnCursors(path2) {
41908
42269
  try {
41909
- return new Map(Object.entries(JSON.parse(readFileSync13(path2, "utf8"))));
42270
+ return new Map(Object.entries(JSON.parse(readFileSync14(path2, "utf8"))));
41910
42271
  } catch {
41911
42272
  return /* @__PURE__ */ new Map();
41912
42273
  }
41913
42274
  }
41914
42275
  function saveTurnCursors(path2, cursors) {
41915
42276
  try {
41916
- writeFileSync11(path2, JSON.stringify(Object.fromEntries(cursors)), "utf8");
42277
+ writeFileSync12(path2, JSON.stringify(Object.fromEntries(cursors)), "utf8");
41917
42278
  } catch {
41918
42279
  }
41919
42280
  }
@@ -41935,7 +42296,7 @@ function gitSourceWatchTargets(root) {
41935
42296
  ["-C", root, "ls-files", "--others", "--ignored", "--exclude-standard", "--directory", "-z"],
41936
42297
  { encoding: "utf8", maxBuffer: 256 * 1024 * 1024, windowsHide: true, stdio: ["ignore", "pipe", "ignore"] }
41937
42298
  );
41938
- ignoredDirs = igOut.split("\0").filter(Boolean).map((d) => d.replace(/\/+$/, "")).filter((d) => !IGNORED_PATH.test(join19(root, d) + sep4));
42299
+ ignoredDirs = igOut.split("\0").filter(Boolean).map((d) => d.replace(/\/+$/, "")).filter((d) => !IGNORED_PATH.test(join20(root, d) + sep4));
41939
42300
  } catch {
41940
42301
  }
41941
42302
  const hasIgnoredChild = (dir) => ignoredDirs.some((ig) => ig.startsWith(dir + "/"));
@@ -41947,19 +42308,19 @@ function gitSourceWatchTargets(root) {
41947
42308
  if (!f.startsWith(prefix)) continue;
41948
42309
  const rest2 = f.slice(prefix.length);
41949
42310
  if (rest2.includes("/")) children.add(dir === "" ? rest2.slice(0, rest2.indexOf("/")) : dir + "/" + rest2.slice(0, rest2.indexOf("/")));
41950
- else targets.add(join19(root, f));
42311
+ else targets.add(join20(root, f));
41951
42312
  }
41952
42313
  for (const c of children) {
41953
- if (IGNORED_PATH.test(join19(root, c) + sep4)) continue;
42314
+ if (IGNORED_PATH.test(join20(root, c) + sep4)) continue;
41954
42315
  if (hasIgnoredChild(c)) addUnder(c);
41955
- else targets.add(join19(root, c));
42316
+ else targets.add(join20(root, c));
41956
42317
  }
41957
42318
  };
41958
42319
  addUnder("");
41959
42320
  if (targets.size > 0) return [...targets];
41960
42321
  } catch {
41961
42322
  }
41962
- return readdirSync7(root, { withFileTypes: true }).filter((e) => e.isDirectory() && !IGNORED_PATH.test(join19(root, String(e.name)) + sep4)).map((e) => join19(root, String(e.name)));
42323
+ return readdirSync7(root, { withFileTypes: true }).filter((e) => e.isDirectory() && !IGNORED_PATH.test(join20(root, String(e.name)) + sep4)).map((e) => join20(root, String(e.name)));
41963
42324
  }
41964
42325
  function createWorkspaceEngine(opts) {
41965
42326
  const paths = workspacePaths(opts.workspaceRoot);
@@ -42111,7 +42472,7 @@ function createWorkspaceEngine(opts) {
42111
42472
  const srcPaths = diff.changedPaths.filter((p) => /\.(ts|tsx|js|jsx|mjs|cjs|py)$/i.test(p));
42112
42473
  let episodeId2;
42113
42474
  if (srcPaths.length > 0) {
42114
- const abs = srcPaths.map((p) => join19(opts.workspaceRoot, p));
42475
+ const abs = srcPaths.map((p) => join20(opts.workspaceRoot, p));
42115
42476
  try {
42116
42477
  const r = await runReindexPass(
42117
42478
  `git-reindex:${profile.name} (${abs.length} files)`,
@@ -42142,8 +42503,8 @@ function createWorkspaceEngine(opts) {
42142
42503
  `[errata] git: ${ev.kind} ${ev.newSha.slice(0, 7)} by ${meta3.authorName} \u2014 ${diff.changedPaths.length} file(s), ${diff.renames.length} rename(s)`
42143
42504
  );
42144
42505
  };
42145
- const gitDir = join19(opts.workspaceRoot, ".git");
42146
- if (existsSync14(gitDir)) {
42506
+ const gitDir = join20(opts.workspaceRoot, ".git");
42507
+ if (existsSync15(gitDir)) {
42147
42508
  stopGit = startGitSensor(gitDir, (ev) => {
42148
42509
  void handleGitEvent(ev);
42149
42510
  });
@@ -42209,10 +42570,10 @@ function createWorkspaceEngine(opts) {
42209
42570
  ...pendingUpdate ? { pendingUpdate } : {}
42210
42571
  });
42211
42572
  doneRender?.();
42212
- const target = join19(opts.workspaceRoot, "AGENTS.md");
42573
+ const target = join20(opts.workspaceRoot, "AGENTS.md");
42213
42574
  writeManagedBlock(target, { body: body2 });
42214
42575
  if (elicit) {
42215
- writePrimingHandles(join19(paths.configDir, "priming-handles.json"), [
42576
+ writePrimingHandles(join20(paths.configDir, "priming-handles.json"), [
42216
42577
  ...snapshot.recentProblems.map((r) => r.node),
42217
42578
  // Resolved-band handles: the ✓ problem AND its Solution are citable
42218
42579
  // (a fix tag on an already-resolved problem no-ops idempotently; the
@@ -42382,7 +42743,7 @@ function createWorkspaceEngine(opts) {
42382
42743
  resultSummary: { exitCode: e.exitCode ?? 1, errorTokens: e.errorTokens }
42383
42744
  });
42384
42745
  };
42385
- const turnCursorPath = join19(paths.configDir, "turn-cursors.json");
42746
+ const turnCursorPath = join20(paths.configDir, "turn-cursors.json");
42386
42747
  const lastTurnUuid = loadTurnCursors(turnCursorPath);
42387
42748
  const sessionLastProblem = /* @__PURE__ */ new Map();
42388
42749
  const sessionThreads = /* @__PURE__ */ new Map();
@@ -42405,7 +42766,7 @@ function createWorkspaceEngine(opts) {
42405
42766
  const t = Date.now();
42406
42767
  let processedTurns = 0;
42407
42768
  const elicit = isEdgeElicitationEnabled();
42408
- const handleMap = elicit ? readPrimingHandles(join19(paths.configDir, "priming-handles.json")) : {};
42769
+ const handleMap = elicit ? readPrimingHandles(join20(paths.configDir, "priming-handles.json")) : {};
42409
42770
  const wsRoot = (opts.workspaceRoot ?? "").replace(/\\/g, "/");
42410
42771
  const toRel = (abs) => {
42411
42772
  const p = abs.replace(/\\/g, "/");
@@ -42922,7 +43283,21 @@ function createWorkspaceEngine(opts) {
42922
43283
  return report;
42923
43284
  },
42924
43285
  async nightly() {
42925
- return (await runNightly()).report;
43286
+ const report = (await runNightly()).report;
43287
+ const summarizer = opts.intentSummarizer ?? envIntentSummarizer();
43288
+ if (summarizer) {
43289
+ try {
43290
+ const s = await runSymbolSummarySweep(store, opts.workspaceRoot, paths.configDir, summarizer);
43291
+ if (s.generated > 0 || s.rejected > 0) {
43292
+ console.log(
43293
+ `[errata] symbol summaries: +${s.generated}${s.rejected > 0 ? ` (${s.rejected} rejected by no-verbatim check)` : ""}${s.remaining > 0 ? `, ${s.remaining} pending` : ""}`
43294
+ );
43295
+ }
43296
+ } catch (err2) {
43297
+ console.warn("[errata] symbol summary sweep failed:", err2 instanceof Error ? err2.message : err2);
43298
+ }
43299
+ }
43300
+ return report;
42926
43301
  },
42927
43302
  async embedSettled() {
42928
43303
  try {
@@ -43010,7 +43385,7 @@ function createWorkspaceEngine(opts) {
43010
43385
  console.log(
43011
43386
  "[errata] sync skipped \u2014 cloud sync consent is off (enable with `errata consent sync on`)"
43012
43387
  );
43013
- const pending = existsSync14(paths.outbox) ? readdirSync7(paths.outbox).filter((f) => f.endsWith(".json")).length : 0;
43388
+ const pending = existsSync15(paths.outbox) ? readdirSync7(paths.outbox).filter((f) => f.endsWith(".json")).length : 0;
43014
43389
  return { uploaded: 0, failed: 0, remaining: pending };
43015
43390
  }
43016
43391
  try {
@@ -43097,7 +43472,7 @@ async function startDaemon(opts) {
43097
43472
  reviewUrl: () => webUiUrl + "/review"
43098
43473
  });
43099
43474
  const writeLockFile = (url2) => {
43100
- writeFileSync12(
43475
+ writeFileSync13(
43101
43476
  engine.paths.daemonLock,
43102
43477
  JSON.stringify({ pid: process.pid, webUiUrl: url2, startedAt: Date.now() }),
43103
43478
  "utf8"
@@ -43140,7 +43515,7 @@ async function startDaemon(opts) {
43140
43515
  );
43141
43516
  await engine.stop();
43142
43517
  try {
43143
- if (existsSync15(engine.paths.daemonLock)) {
43518
+ if (existsSync16(engine.paths.daemonLock)) {
43144
43519
  }
43145
43520
  } catch {
43146
43521
  }
@@ -43157,16 +43532,16 @@ async function listenServer(fetchFn, port) {
43157
43532
 
43158
43533
  // src/registry.ts
43159
43534
  init_paths();
43160
- import { existsSync as existsSync16, readFileSync as readFileSync14, writeFileSync as writeFileSync13 } from "node:fs";
43161
- import { join as join20 } from "node:path";
43535
+ import { existsSync as existsSync17, readFileSync as readFileSync15, writeFileSync as writeFileSync14 } from "node:fs";
43536
+ import { join as join21 } from "node:path";
43162
43537
  function registryPath() {
43163
- return process.env["ERRATA_REGISTRY_PATH"] ?? join20(globalDir(), "workspaces.json");
43538
+ return process.env["ERRATA_REGISTRY_PATH"] ?? join21(globalDir(), "workspaces.json");
43164
43539
  }
43165
43540
  function read() {
43166
43541
  const p = registryPath();
43167
- if (!existsSync16(p)) return { version: 1, workspaces: {} };
43542
+ if (!existsSync17(p)) return { version: 1, workspaces: {} };
43168
43543
  try {
43169
- const parsed = JSON.parse(readFileSync14(p, "utf8"));
43544
+ const parsed = JSON.parse(readFileSync15(p, "utf8"));
43170
43545
  return { version: 1, workspaces: parsed.workspaces ?? {} };
43171
43546
  } catch {
43172
43547
  return { version: 1, workspaces: {} };
@@ -43174,7 +43549,7 @@ function read() {
43174
43549
  }
43175
43550
  function write(reg) {
43176
43551
  ensureDir(globalDir());
43177
- writeFileSync13(registryPath(), JSON.stringify(reg, null, 2), "utf8");
43552
+ writeFileSync14(registryPath(), JSON.stringify(reg, null, 2), "utf8");
43178
43553
  }
43179
43554
  function registerWorkspace(profile, root, now = Date.now()) {
43180
43555
  const reg = read();
@@ -43191,7 +43566,7 @@ function pruneMissingWorkspaces() {
43191
43566
  const reg = read();
43192
43567
  const removed = [];
43193
43568
  for (const [id, entry] of Object.entries(reg.workspaces)) {
43194
- if (!existsSync16(entry.path)) {
43569
+ if (!existsSync17(entry.path)) {
43195
43570
  removed.push(entry);
43196
43571
  delete reg.workspaces[id];
43197
43572
  }
@@ -43200,13 +43575,13 @@ function pruneMissingWorkspaces() {
43200
43575
  return removed;
43201
43576
  }
43202
43577
  function workspaceStatus(entry) {
43203
- const missing = !existsSync16(entry.path);
43578
+ const missing = !existsSync17(entry.path);
43204
43579
  const lockPath = workspacePaths(entry.path).daemonLock;
43205
43580
  let running = false;
43206
43581
  let webUiUrl = null;
43207
- if (existsSync16(lockPath)) {
43582
+ if (existsSync17(lockPath)) {
43208
43583
  try {
43209
- const lock = JSON.parse(readFileSync14(lockPath, "utf8"));
43584
+ const lock = JSON.parse(readFileSync15(lockPath, "utf8"));
43210
43585
  if (lock.pid && lock.webUiUrl && pidAlive(lock.pid)) {
43211
43586
  running = true;
43212
43587
  webUiUrl = lock.webUiUrl;
@@ -43234,7 +43609,7 @@ function pidAlive(pid) {
43234
43609
  // src/multi.ts
43235
43610
  init_dist();
43236
43611
  init_src4();
43237
- import { readFileSync as readFileSync17, unlinkSync as unlinkSync3, writeFileSync as writeFileSync14 } from "node:fs";
43612
+ import { readFileSync as readFileSync18, unlinkSync as unlinkSync3, writeFileSync as writeFileSync15 } from "node:fs";
43238
43613
 
43239
43614
  // src/principle-sync.ts
43240
43615
  init_src4();
@@ -43261,8 +43636,8 @@ async function syncPrinciples(store, cloud, opts) {
43261
43636
  init_reconcile();
43262
43637
 
43263
43638
  // src/lockfile-auto.ts
43264
- import { existsSync as existsSync17, readFileSync as readFileSync15 } from "node:fs";
43265
- import { join as join21 } from "node:path";
43639
+ import { existsSync as existsSync18, readFileSync as readFileSync16 } from "node:fs";
43640
+ import { join as join22 } from "node:path";
43266
43641
 
43267
43642
  // src/package-index.ts
43268
43643
  init_src();
@@ -43526,11 +43901,11 @@ function runLockfilePass(opts) {
43526
43901
  { file: "package-lock.json", parse: parsePackageLockJson }
43527
43902
  ];
43528
43903
  for (const c of candidates) {
43529
- const p = join21(opts.root, c.file);
43530
- if (!existsSync17(p)) continue;
43904
+ const p = join22(opts.root, c.file);
43905
+ if (!existsSync18(p)) continue;
43531
43906
  let sbom;
43532
43907
  try {
43533
- sbom = c.parse(readFileSync15(p, "utf8"));
43908
+ sbom = c.parse(readFileSync16(p, "utf8"));
43534
43909
  } catch {
43535
43910
  continue;
43536
43911
  }
@@ -43685,6 +44060,27 @@ function buildInstanceIngest(store, profile, daemonVersion, ignorePatterns = [],
43685
44060
  }
43686
44061
  }
43687
44062
  if (nodes.length === 0 && anchorEdges.length === 0) return null;
44063
+ let symbolSummaries;
44064
+ if (opts.lexicon && opts.lexicon.size > 0 && nodes.length > 0) {
44065
+ const lexicon = opts.lexicon;
44066
+ const isKnown = (tok) => lexicon.has(tok);
44067
+ const sidecar = {};
44068
+ let count = 0;
44069
+ outer: for (const n of nodes) {
44070
+ if (!INSTANCE_LABELS.includes(n.label)) continue;
44071
+ for (const tok of extractIdentifierTokens(n.description)) {
44072
+ if (sidecar[tok]) continue;
44073
+ const entry = lexicon.get(tok);
44074
+ if (!entry?.summary) continue;
44075
+ const scrubbed = generalize(entry.summary, { level }).text.trim();
44076
+ if (!scrubbed || summaryRejectionReason(scrubbed, isKnown) !== null) continue;
44077
+ if (count >= MAX_SIDECAR_SYMBOLS) break outer;
44078
+ sidecar[tok] = { kind: entry.kind, summary: scrubbed };
44079
+ count++;
44080
+ }
44081
+ }
44082
+ if (count > 0) symbolSummaries = sidecar;
44083
+ }
43688
44084
  const edges = [];
43689
44085
  for (const id of seen) {
43690
44086
  for (const e of store.outEdges(id, [...INSTANCE_EDGES])) {
@@ -43699,12 +44095,17 @@ function buildInstanceIngest(store, profile, daemonVersion, ignorePatterns = [],
43699
44095
  // co-locates the few Language/Package stubs with the first instance chunk,
43700
44096
  // maximizing in-payload endpoint resolution.
43701
44097
  nodes: [...contextNodes, ...nodes],
43702
- edges
44098
+ edges,
44099
+ // Spread-if-present: an absent sidecar keeps `base` — and therefore the
44100
+ // payloadDigest — byte-identical to the pre-sidecar batch (backward compat).
44101
+ ...symbolSummaries ? { symbolSummaries } : {}
43703
44102
  };
43704
44103
  return { ...base, payloadDigest: digest(base), anchorDigests };
43705
44104
  }
43706
44105
 
43707
44106
  // src/multi.ts
44107
+ init_generalize_graph();
44108
+ init_symbol_summaries();
43708
44109
  init_webui();
43709
44110
 
43710
44111
  // src/consolidate-worker-client.ts
@@ -43780,7 +44181,7 @@ var ConsolidateWorker = class {
43780
44181
  init_paths();
43781
44182
 
43782
44183
  // src/lock.ts
43783
- import { existsSync as existsSync18, readFileSync as readFileSync16 } from "node:fs";
44184
+ import { existsSync as existsSync19, readFileSync as readFileSync17 } from "node:fs";
43784
44185
  function isProcessAlive(pid) {
43785
44186
  if (!pid || pid <= 0) return false;
43786
44187
  try {
@@ -43791,9 +44192,9 @@ function isProcessAlive(pid) {
43791
44192
  }
43792
44193
  }
43793
44194
  function readDaemonLock(lockPath) {
43794
- if (!existsSync18(lockPath)) return null;
44195
+ if (!existsSync19(lockPath)) return null;
43795
44196
  try {
43796
- const lock = JSON.parse(readFileSync16(lockPath, "utf8"));
44197
+ const lock = JSON.parse(readFileSync17(lockPath, "utf8"));
43797
44198
  return typeof lock.pid === "number" ? lock : null;
43798
44199
  } catch {
43799
44200
  return null;
@@ -44041,7 +44442,7 @@ async function startMultiDaemon(opts = {}) {
44041
44442
  records.push(rec);
44042
44443
  app.route(`/ws/${rec.id}`, rec.webApp);
44043
44444
  try {
44044
- writeFileSync14(
44445
+ writeFileSync15(
44045
44446
  rec.engine.paths.daemonLock,
44046
44447
  JSON.stringify({ pid: process.pid, webUiUrl: `${baseUrl}/ws/${rec.id}`, startedAt: Date.now() }),
44047
44448
  "utf8"
@@ -44224,7 +44625,7 @@ async function startMultiDaemon(opts = {}) {
44224
44625
  baseUrl = `http://127.0.0.1:${port}`;
44225
44626
  try {
44226
44627
  ensureDir(globalDir());
44227
- writeFileSync14(
44628
+ writeFileSync15(
44228
44629
  lockPath,
44229
44630
  JSON.stringify({ pid: process.pid, webUiUrl: baseUrl, startedAt: Date.now() }),
44230
44631
  "utf8"
@@ -44233,7 +44634,7 @@ async function startMultiDaemon(opts = {}) {
44233
44634
  }
44234
44635
  for (const r of records) {
44235
44636
  try {
44236
- writeFileSync14(
44637
+ writeFileSync15(
44237
44638
  r.engine.paths.daemonLock,
44238
44639
  JSON.stringify({ pid: process.pid, webUiUrl: `${baseUrl}/ws/${r.id}`, startedAt: Date.now() }),
44239
44640
  "utf8"
@@ -44445,8 +44846,15 @@ async function startMultiDaemon(opts = {}) {
44445
44846
  const res = await client.ingest(context);
44446
44847
  uploaded += res.accepted;
44447
44848
  }
44849
+ let lexicon;
44850
+ try {
44851
+ const summaries = summariesByBodyHash(loadSymbolSummaryCache(r.engine.paths.configDir));
44852
+ if (summaries.size > 0) lexicon = buildSymbolLexicon(store, summaries);
44853
+ } catch {
44854
+ }
44448
44855
  const instances = buildInstanceIngest(store, r.engine.profile, DAEMON_VERSION, ignore, {
44449
- includePackages: cfg2.consent.contributePackages
44856
+ includePackages: cfg2.consent.contributePackages,
44857
+ ...lexicon ? { lexicon } : {}
44450
44858
  });
44451
44859
  if (instances) {
44452
44860
  const res = await client.ingest(instances);
@@ -44529,7 +44937,7 @@ async function startMultiDaemon(opts = {}) {
44529
44937
  },
44530
44938
  async stop() {
44531
44939
  try {
44532
- const cur = readFileSync17(lockPath, "utf8");
44940
+ const cur = readFileSync18(lockPath, "utf8");
44533
44941
  if (JSON.parse(cur).pid === process.pid) unlinkSync3(lockPath);
44534
44942
  } catch {
44535
44943
  }
@@ -44983,21 +45391,21 @@ async function cmdInit() {
44983
45391
  if (!skipHooks) {
44984
45392
  console.log("");
44985
45393
  console.log("installing harness hooks...");
44986
- const { existsSync: existsSync20 } = await import("node:fs");
44987
- const { join: join23 } = await import("node:path");
45394
+ const { existsSync: existsSync21 } = await import("node:fs");
45395
+ const { join: join24 } = await import("node:path");
44988
45396
  try {
44989
45397
  await installClaudeHooks(port);
44990
45398
  } catch (err2) {
44991
45399
  console.warn(` \u26A0\uFE0F Claude hook install failed: ${err2 instanceof Error ? err2.message : err2}`);
44992
45400
  }
44993
- if (existsSync20(join23(ROOT, ".cursor"))) {
45401
+ if (existsSync21(join24(ROOT, ".cursor"))) {
44994
45402
  try {
44995
45403
  await installCursorMcpConfig();
44996
45404
  } catch (err2) {
44997
45405
  console.warn(` \u26A0\uFE0F Cursor MCP config failed: ${err2 instanceof Error ? err2.message : err2}`);
44998
45406
  }
44999
45407
  }
45000
- if (existsSync20(join23(ROOT, ".codex"))) {
45408
+ if (existsSync21(join24(ROOT, ".codex"))) {
45001
45409
  try {
45002
45410
  await installCodexHooks(port);
45003
45411
  } catch (err2) {
@@ -45114,8 +45522,8 @@ async function cmdStatus() {
45114
45522
  console.log(` stack: ${profile.stack.join(", ") || "(none)"}`);
45115
45523
  console.log(` languages: ${profile.languages.join(", ") || "(none)"}`);
45116
45524
  }
45117
- console.log(` graph db: ${existsSync19(paths.castalia) ? "yes" : "no"} (${paths.castalia})`);
45118
- console.log(` event log: ${existsSync19(paths.eventLog) ? "yes" : "no"} (${paths.eventLog})`);
45525
+ console.log(` graph db: ${existsSync20(paths.castalia) ? "yes" : "no"} (${paths.castalia})`);
45526
+ console.log(` event log: ${existsSync20(paths.eventLog) ? "yes" : "no"} (${paths.eventLog})`);
45119
45527
  const lockPath = globalDaemonLock();
45120
45528
  const running = isDaemonAlive(lockPath) ? readDaemonLock(lockPath) : null;
45121
45529
  console.log(
@@ -45411,11 +45819,11 @@ async function cmdLogout() {
45411
45819
  }
45412
45820
  async function cmdReview() {
45413
45821
  const paths = workspacePaths(ROOT);
45414
- if (!existsSync19(paths.reviewQueue)) {
45822
+ if (!existsSync20(paths.reviewQueue)) {
45415
45823
  console.log("(review queue empty)");
45416
45824
  return;
45417
45825
  }
45418
- const queue = JSON.parse(readFileSync18(paths.reviewQueue, "utf8"));
45826
+ const queue = JSON.parse(readFileSync19(paths.reviewQueue, "utf8"));
45419
45827
  if (queue.length === 0) {
45420
45828
  console.log("(review queue empty)");
45421
45829
  return;
@@ -46045,7 +46453,7 @@ async function gatherRepo(store, ws) {
46045
46453
  };
46046
46454
  }
46047
46455
  async function gatherReportData(generatedAt) {
46048
- const { existsSync: existsSync20 } = await import("node:fs");
46456
+ const { existsSync: existsSync21 } = await import("node:fs");
46049
46457
  const { openGraphStore: openGraphStore2 } = await Promise.resolve().then(() => (init_src4(), src_exports2));
46050
46458
  const cfg = loadConfig();
46051
46459
  const outbound = cfg.consent.sync ? "auto" : "off";
@@ -46053,7 +46461,7 @@ async function gatherReportData(generatedAt) {
46053
46461
  for (const ws of listWorkspaces()) {
46054
46462
  if (ws.missing) continue;
46055
46463
  const dbPath = workspacePaths(ws.path).castalia;
46056
- if (!existsSync20(dbPath)) continue;
46464
+ if (!existsSync21(dbPath)) continue;
46057
46465
  let store = null;
46058
46466
  try {
46059
46467
  store = openGraphStore2({ path: dbPath });
@@ -46084,7 +46492,7 @@ async function gatherReportData(generatedAt) {
46084
46492
  };
46085
46493
  }
46086
46494
  async function cmdReport(args2) {
46087
- const { mkdirSync: mkdirSync6, writeFileSync: writeFileSync15 } = await import("node:fs");
46495
+ const { mkdirSync: mkdirSync6, writeFileSync: writeFileSync16 } = await import("node:fs");
46088
46496
  const { renderReport: renderReport2 } = await Promise.resolve().then(() => (init_report_render(), report_render_exports));
46089
46497
  const includeFutureVerbs = args2.includes("--future-verbs");
46090
46498
  const now = /* @__PURE__ */ new Date();
@@ -46097,8 +46505,8 @@ async function cmdReport(args2) {
46097
46505
  const outDir = workspacePaths(ROOT).configDir;
46098
46506
  mkdirSync6(outDir, { recursive: true });
46099
46507
  const files = renderReport2(data, { includeFutureVerbs });
46100
- for (const f of files) writeFileSync15(join22(outDir, f.name), f.html, "utf8");
46101
- const indexPath = join22(outDir, "report.html");
46508
+ for (const f of files) writeFileSync16(join23(outDir, f.name), f.html, "utf8");
46509
+ const indexPath = join23(outDir, "report.html");
46102
46510
  console.log(`report \u2192 ${indexPath}`);
46103
46511
  console.log(` ${data.repos.length} repo(s) \xB7 ${files.length} file(s) \xB7 ${data.rollup.nodes.toLocaleString("en-US")} nodes`);
46104
46512
  console.log(` open: file://${indexPath.replace(/\\/g, "/")}`);
@@ -46218,15 +46626,15 @@ function hookRelayCommand(port, path2) {
46218
46626
  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 '{}'`;
46219
46627
  }
46220
46628
  async function installClaudeHooks(port) {
46221
- const { mkdirSync: mkdirSync6, existsSync: existsSync20, readFileSync: readFileSync19, writeFileSync: writeFileSync15 } = await import("node:fs");
46222
- const { join: join23 } = await import("node:path");
46223
- const dir = join23(ROOT, ".claude");
46224
- if (!existsSync20(dir)) mkdirSync6(dir, { recursive: true });
46225
- const file2 = join23(dir, "settings.json");
46629
+ const { mkdirSync: mkdirSync6, existsSync: existsSync21, readFileSync: readFileSync20, writeFileSync: writeFileSync16 } = await import("node:fs");
46630
+ const { join: join24 } = await import("node:path");
46631
+ const dir = join24(ROOT, ".claude");
46632
+ if (!existsSync21(dir)) mkdirSync6(dir, { recursive: true });
46633
+ const file2 = join24(dir, "settings.json");
46226
46634
  let settings = {};
46227
- if (existsSync20(file2)) {
46635
+ if (existsSync21(file2)) {
46228
46636
  try {
46229
- settings = JSON.parse(readFileSync19(file2, "utf8"));
46637
+ settings = JSON.parse(readFileSync20(file2, "utf8"));
46230
46638
  } catch {
46231
46639
  console.error(`refusing to overwrite invalid JSON at ${file2}`);
46232
46640
  process.exit(2);
@@ -46271,21 +46679,21 @@ async function installClaudeHooks(port) {
46271
46679
  dropErrata(list);
46272
46680
  list.push({ hooks: [{ type: "command", command: injectCmd }] });
46273
46681
  }
46274
- writeFileSync15(file2, JSON.stringify(settings, null, 2) + "\n", "utf8");
46682
+ writeFileSync16(file2, JSON.stringify(settings, null, 2) + "\n", "utf8");
46275
46683
  console.log(`installed Claude Code hooks \u2192 ${file2}`);
46276
46684
  await installClaudeMcpConfig();
46277
46685
  console.log(` endpoint: http://127.0.0.1:${port}/api/hook`);
46278
46686
  }
46279
46687
  async function installClaudeMcpConfig() {
46280
- const { mkdirSync: mkdirSync6, existsSync: existsSync20, readFileSync: readFileSync19, writeFileSync: writeFileSync15 } = await import("node:fs");
46281
- const { join: join23, dirname: dirname8 } = await import("node:path");
46282
- const file2 = join23(ROOT, ".mcp.json");
46688
+ const { mkdirSync: mkdirSync6, existsSync: existsSync21, readFileSync: readFileSync20, writeFileSync: writeFileSync16 } = await import("node:fs");
46689
+ const { join: join24, dirname: dirname8 } = await import("node:path");
46690
+ const file2 = join24(ROOT, ".mcp.json");
46283
46691
  const dir = dirname8(file2);
46284
- if (!existsSync20(dir)) mkdirSync6(dir, { recursive: true });
46692
+ if (!existsSync21(dir)) mkdirSync6(dir, { recursive: true });
46285
46693
  let cfg = {};
46286
- if (existsSync20(file2)) {
46694
+ if (existsSync21(file2)) {
46287
46695
  try {
46288
- cfg = JSON.parse(readFileSync19(file2, "utf8"));
46696
+ cfg = JSON.parse(readFileSync20(file2, "utf8"));
46289
46697
  } catch {
46290
46698
  console.error(`refusing to overwrite invalid JSON at ${file2}`);
46291
46699
  process.exit(2);
@@ -46293,21 +46701,21 @@ async function installClaudeMcpConfig() {
46293
46701
  }
46294
46702
  cfg.mcpServers ??= {};
46295
46703
  cfg.mcpServers["errata"] = errataMcpInvocation();
46296
- writeFileSync15(file2, JSON.stringify(cfg, null, 2) + "\n", "utf8");
46704
+ writeFileSync16(file2, JSON.stringify(cfg, null, 2) + "\n", "utf8");
46297
46705
  console.log(`installed Claude Code MCP server config \u2192 ${file2}`);
46298
46706
  console.log(` Claude Code will spawn \`errata mcp\` on workspace open.`);
46299
46707
  console.log(` Tools: errata.search / locate / neighbors / callers_of / what_uses / show / similar`);
46300
46708
  }
46301
46709
  async function installCursorMcpConfig() {
46302
- const { mkdirSync: mkdirSync6, existsSync: existsSync20, readFileSync: readFileSync19, writeFileSync: writeFileSync15 } = await import("node:fs");
46303
- const { join: join23 } = await import("node:path");
46304
- const dir = join23(ROOT, ".cursor");
46305
- if (!existsSync20(dir)) mkdirSync6(dir, { recursive: true });
46306
- const file2 = join23(dir, "mcp.json");
46710
+ const { mkdirSync: mkdirSync6, existsSync: existsSync21, readFileSync: readFileSync20, writeFileSync: writeFileSync16 } = await import("node:fs");
46711
+ const { join: join24 } = await import("node:path");
46712
+ const dir = join24(ROOT, ".cursor");
46713
+ if (!existsSync21(dir)) mkdirSync6(dir, { recursive: true });
46714
+ const file2 = join24(dir, "mcp.json");
46307
46715
  let cfg = {};
46308
- if (existsSync20(file2)) {
46716
+ if (existsSync21(file2)) {
46309
46717
  try {
46310
- cfg = JSON.parse(readFileSync19(file2, "utf8"));
46718
+ cfg = JSON.parse(readFileSync20(file2, "utf8"));
46311
46719
  } catch {
46312
46720
  console.error(`refusing to overwrite invalid JSON at ${file2}`);
46313
46721
  process.exit(2);
@@ -46315,7 +46723,7 @@ async function installCursorMcpConfig() {
46315
46723
  }
46316
46724
  cfg.mcpServers ??= {};
46317
46725
  cfg.mcpServers["errata"] = errataMcpInvocation();
46318
- writeFileSync15(file2, JSON.stringify(cfg, null, 2) + "\n", "utf8");
46726
+ writeFileSync16(file2, JSON.stringify(cfg, null, 2) + "\n", "utf8");
46319
46727
  console.log(`installed Cursor MCP server config \u2192 ${file2}`);
46320
46728
  console.log(` Cursor will spawn \`errata mcp\` on workspace open.`);
46321
46729
  console.log(` Tools: errata.search / locate / neighbors / callers_of / what_uses`);
@@ -46323,16 +46731,16 @@ async function installCursorMcpConfig() {
46323
46731
  console.log(` \u26A0\uFE0F reload Cursor (Cmd/Ctrl-Shift-P \u2192 "Reload Window") to pick it up.`);
46324
46732
  }
46325
46733
  async function installCodexHooks(port) {
46326
- const { mkdirSync: mkdirSync6, existsSync: existsSync20, readFileSync: readFileSync19, writeFileSync: writeFileSync15 } = await import("node:fs");
46327
- const { join: join23 } = await import("node:path");
46328
- const dir = join23(ROOT, ".codex");
46329
- if (!existsSync20(dir)) mkdirSync6(dir, { recursive: true });
46330
- const file2 = join23(dir, "config.toml");
46734
+ const { mkdirSync: mkdirSync6, existsSync: existsSync21, readFileSync: readFileSync20, writeFileSync: writeFileSync16 } = await import("node:fs");
46735
+ const { join: join24 } = await import("node:path");
46736
+ const dir = join24(ROOT, ".codex");
46737
+ if (!existsSync21(dir)) mkdirSync6(dir, { recursive: true });
46738
+ const file2 = join24(dir, "config.toml");
46331
46739
  const BEGIN = `# >>> errata hooks (errata-managed)`;
46332
46740
  const END = `# <<< errata hooks`;
46333
46741
  let existing = "";
46334
- if (existsSync20(file2)) {
46335
- existing = readFileSync19(file2, "utf8");
46742
+ if (existsSync21(file2)) {
46743
+ existing = readFileSync20(file2, "utf8");
46336
46744
  const beginIdx = existing.indexOf(BEGIN);
46337
46745
  const endIdx = existing.indexOf(END);
46338
46746
  if (beginIdx >= 0 && endIdx > beginIdx) {
@@ -46361,7 +46769,7 @@ ${END}
46361
46769
  const final = existing.length > 0 && !existing.endsWith("\n") ? `${existing}
46362
46770
 
46363
46771
  ${block}` : existing + (existing.endsWith("\n\n") ? "" : "\n") + block;
46364
- writeFileSync15(file2, final, "utf8");
46772
+ writeFileSync16(file2, final, "utf8");
46365
46773
  console.log(`installed Codex hooks \u2192 ${file2}`);
46366
46774
  console.log(` endpoint: http://127.0.0.1:${port}/api/hook`);
46367
46775
  console.log("");
@@ -46624,7 +47032,7 @@ async function cmdDash(args2) {
46624
47032
  await yieldToLoop2();
46625
47033
  try {
46626
47034
  const items = selectDurableMemory(handle2.sharedStore, r.engine.profile);
46627
- const res = bleedRules(join22(r.root, ".claude", "rules"), items);
47035
+ const res = bleedRules(join23(r.root, ".claude", "rules"), items);
46628
47036
  if (res.written || res.pruned) {
46629
47037
  console.log(
46630
47038
  `[rules:${r.entry.name}] ${res.written} collective principle(s) \u2192 .claude/rules` + (res.pruned ? `, ${res.pruned} pruned` : "")