@inerrata-corporation/errata 2.0.0-dev.34 → 2.0.0-dev.36
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/consolidate-worker.mjs +33 -2
- package/errata.mjs +708 -265
- package/package.json +1 -1
- package/pass-worker.mjs +33 -2
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
|
|
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 =
|
|
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);
|
|
@@ -20057,6 +20158,13 @@ function renderSnapshot(s) {
|
|
|
20057
20158
|
lines.push(`- **Goals:** ${s.profile.goals.join("; ")}`);
|
|
20058
20159
|
}
|
|
20059
20160
|
lines.push("");
|
|
20161
|
+
if (s.pendingUpdate) {
|
|
20162
|
+
lines.push("### \u26A1 errata update available");
|
|
20163
|
+
lines.push(
|
|
20164
|
+
`\`${s.pendingUpdate.current}\` \u2192 \`${s.pendingUpdate.latest}\` on the \`${s.pendingUpdate.channel}\` channel. Tell your user \u2014 or run \`errata update\` yourself if they've asked you to keep errata current. It restarts the daemon; that's safe mid-session (hooks fail open, MCP reconnects).`
|
|
20165
|
+
);
|
|
20166
|
+
lines.push("");
|
|
20167
|
+
}
|
|
20060
20168
|
if (s.needsRevisit.length > 0) {
|
|
20061
20169
|
lines.push("### \u26A0\uFE0F Needs revisit \u2014 a fact these rested on changed");
|
|
20062
20170
|
lines.push(
|
|
@@ -20227,6 +20335,7 @@ function assembleAgentContext(opts) {
|
|
|
20227
20335
|
now: opts.now
|
|
20228
20336
|
});
|
|
20229
20337
|
if (opts.edgeElicitation) snapshot.edgeElicitation = opts.edgeElicitation;
|
|
20338
|
+
if (opts.pendingUpdate) snapshot.pendingUpdate = opts.pendingUpdate;
|
|
20230
20339
|
if (opts.remote && opts.remote.length > 0) {
|
|
20231
20340
|
const seen = /* @__PURE__ */ new Set();
|
|
20232
20341
|
const remote = opts.remote.filter((n) => {
|
|
@@ -20499,6 +20608,20 @@ var init_oauth = __esm({
|
|
|
20499
20608
|
|
|
20500
20609
|
// ../../packages/cloud-client/src/client.ts
|
|
20501
20610
|
import { randomUUID } from "node:crypto";
|
|
20611
|
+
function sidecarForNodes(sidecar, nodes) {
|
|
20612
|
+
if (!sidecar) return void 0;
|
|
20613
|
+
const present = /* @__PURE__ */ new Set();
|
|
20614
|
+
for (const n of nodes) for (const tok of extractIdentifierTokens(n.description)) present.add(tok);
|
|
20615
|
+
const filtered = {};
|
|
20616
|
+
let count = 0;
|
|
20617
|
+
for (const [symbol2, entry] of Object.entries(sidecar)) {
|
|
20618
|
+
if (present.has(symbol2)) {
|
|
20619
|
+
filtered[symbol2] = entry;
|
|
20620
|
+
count++;
|
|
20621
|
+
}
|
|
20622
|
+
}
|
|
20623
|
+
return count > 0 ? filtered : void 0;
|
|
20624
|
+
}
|
|
20502
20625
|
function toWirePayload(batch, runId) {
|
|
20503
20626
|
const nodes = batch.nodes.map((n) => ({
|
|
20504
20627
|
canonicalId: n.id,
|
|
@@ -20517,7 +20640,8 @@ function toWirePayload(batch, runId) {
|
|
|
20517
20640
|
...typeof e.confidence === "number" ? { confidence: clamp012(e.confidence) } : {}
|
|
20518
20641
|
}
|
|
20519
20642
|
}));
|
|
20520
|
-
|
|
20643
|
+
const symbolSummaries = sidecarForNodes(batch.symbolSummaries, nodes);
|
|
20644
|
+
return { runId, source: "daemon", nodes, edges, ...symbolSummaries ? { symbolSummaries } : {} };
|
|
20521
20645
|
}
|
|
20522
20646
|
function clamp012(x) {
|
|
20523
20647
|
return Math.max(0, Math.min(1, x));
|
|
@@ -23931,21 +24055,32 @@ function isDistinctiveIdentifier(name2) {
|
|
|
23931
24055
|
if (/^[A-Z]/.test(name2) && name2.length >= 4) return true;
|
|
23932
24056
|
return name2.length >= 8;
|
|
23933
24057
|
}
|
|
23934
|
-
function buildSymbolLexicon(store) {
|
|
24058
|
+
function buildSymbolLexicon(store, summariesByBodyHash2) {
|
|
23935
24059
|
const lex = /* @__PURE__ */ new Map();
|
|
24060
|
+
const candidates = [];
|
|
23936
24061
|
for (const [label, kind] of SYMBOL_LABELS) {
|
|
23937
24062
|
for (const n of store.findNodesByLabel(label)) {
|
|
24063
|
+
const bodyHash = typeof n.attrs["bodyHash"] === "string" ? n.attrs["bodyHash"] : void 0;
|
|
24064
|
+
const summary = bodyHash ? summariesByBodyHash2?.get(bodyHash) : void 0;
|
|
23938
24065
|
for (const name2 of [n.description, String(n.attrs["qname"] ?? "")]) {
|
|
23939
|
-
if (name2 && isDistinctiveIdentifier(name2))
|
|
24066
|
+
if (name2 && isDistinctiveIdentifier(name2)) {
|
|
24067
|
+
if (!lex.has(name2)) lex.set(name2, { kind });
|
|
24068
|
+
if (summary) candidates.push([name2, summary]);
|
|
24069
|
+
}
|
|
23940
24070
|
}
|
|
23941
24071
|
}
|
|
23942
24072
|
}
|
|
24073
|
+
for (const [name2, summary] of candidates) {
|
|
24074
|
+
if (summaryRejectionReason(summary, (tok) => lex.has(tok)) === null) {
|
|
24075
|
+
lex.get(name2).summary = summary;
|
|
24076
|
+
}
|
|
24077
|
+
}
|
|
23943
24078
|
return lex;
|
|
23944
24079
|
}
|
|
23945
24080
|
function generalizeSymbols(text, lexicon, level = 1) {
|
|
23946
24081
|
const present = [];
|
|
23947
24082
|
const seen = /* @__PURE__ */ new Set();
|
|
23948
|
-
for (const m of text.matchAll(
|
|
24083
|
+
for (const m of text.matchAll(TOKEN_RE3)) {
|
|
23949
24084
|
const tok = m[0];
|
|
23950
24085
|
if (!seen.has(tok) && lexicon.has(tok)) {
|
|
23951
24086
|
seen.add(tok);
|
|
@@ -23955,17 +24090,19 @@ function generalizeSymbols(text, lexicon, level = 1) {
|
|
|
23955
24090
|
present.sort((a, b) => b.length - a.length);
|
|
23956
24091
|
let out2 = text;
|
|
23957
24092
|
for (const key of present) {
|
|
23958
|
-
const
|
|
23959
|
-
const
|
|
24093
|
+
const entry = lexicon.get(key);
|
|
24094
|
+
const phrase = level === 1 && entry.summary ? entry.summary : KIND_PHRASE[entry.kind][level === 1 ? "l1" : "l2"];
|
|
24095
|
+
const re = new RegExp(`(?<![A-Za-z0-9_$.])${escapeRe4(key)}(?![A-Za-z0-9_$])`, "g");
|
|
23960
24096
|
out2 = out2.replace(re, phrase);
|
|
23961
24097
|
}
|
|
23962
24098
|
return generalize(out2, { level }).text;
|
|
23963
24099
|
}
|
|
23964
|
-
var SYMBOL_LABELS, KIND_PHRASE,
|
|
24100
|
+
var SYMBOL_LABELS, KIND_PHRASE, RE_RESERVED2, escapeRe4, TOKEN_RE3;
|
|
23965
24101
|
var init_generalize_graph = __esm({
|
|
23966
24102
|
"src/generalize-graph.ts"() {
|
|
23967
24103
|
"use strict";
|
|
23968
24104
|
init_src8();
|
|
24105
|
+
init_src();
|
|
23969
24106
|
SYMBOL_LABELS = [
|
|
23970
24107
|
["Function", "function"],
|
|
23971
24108
|
["Method", "method"],
|
|
@@ -23980,9 +24117,9 @@ var init_generalize_graph = __esm({
|
|
|
23980
24117
|
interface: { l1: "an interface", l2: "an interface" },
|
|
23981
24118
|
constant: { l1: "a constant", l2: "a value" }
|
|
23982
24119
|
};
|
|
23983
|
-
|
|
23984
|
-
|
|
23985
|
-
|
|
24120
|
+
RE_RESERVED2 = /[.*+?^${}()|[\]\\]/g;
|
|
24121
|
+
escapeRe4 = (s) => s.replace(RE_RESERVED2, "\\$&");
|
|
24122
|
+
TOKEN_RE3 = /[A-Za-z_$][A-Za-z0-9_$]*(?:\.[A-Za-z_$][A-Za-z0-9_$]*)*/g;
|
|
23986
24123
|
}
|
|
23987
24124
|
});
|
|
23988
24125
|
|
|
@@ -24087,7 +24224,7 @@ async function dualAugment(opts) {
|
|
|
24087
24224
|
let seedProvenance = "local";
|
|
24088
24225
|
const calls = [];
|
|
24089
24226
|
try {
|
|
24090
|
-
const lexicon = buildSymbolLexicon(store);
|
|
24227
|
+
const lexicon = buildSymbolLexicon(store, opts.summaries);
|
|
24091
24228
|
const hardIds = [.../* @__PURE__ */ new Set([...seedNode ? [seedNode.id] : [], ...localHits.map((h) => h.id)])].filter((nid) => {
|
|
24092
24229
|
const n = seedNode && nid === seedNode.id ? seedNode : store.getNode(nid);
|
|
24093
24230
|
return !!n && isHardBridge(n);
|
|
@@ -25912,6 +26049,177 @@ var init_src10 = __esm({
|
|
|
25912
26049
|
}
|
|
25913
26050
|
});
|
|
25914
26051
|
|
|
26052
|
+
// src/symbol-summaries.ts
|
|
26053
|
+
import { existsSync as existsSync7, readFileSync as readFileSync5, writeFileSync as writeFileSync6 } from "node:fs";
|
|
26054
|
+
import { join as join6 } from "node:path";
|
|
26055
|
+
function symbolSummariesPath(configDir) {
|
|
26056
|
+
return join6(configDir, "symbol-summaries.json");
|
|
26057
|
+
}
|
|
26058
|
+
function loadSymbolSummaryCache(configDir) {
|
|
26059
|
+
const p = symbolSummariesPath(configDir);
|
|
26060
|
+
if (existsSync7(p)) {
|
|
26061
|
+
try {
|
|
26062
|
+
const raw2 = JSON.parse(readFileSync5(p, "utf8"));
|
|
26063
|
+
if (raw2 && raw2.version === 1 && raw2.entries && typeof raw2.entries === "object") {
|
|
26064
|
+
return { version: 1, entries: raw2.entries };
|
|
26065
|
+
}
|
|
26066
|
+
} catch {
|
|
26067
|
+
}
|
|
26068
|
+
}
|
|
26069
|
+
return { version: 1, entries: {} };
|
|
26070
|
+
}
|
|
26071
|
+
function saveSymbolSummaryCache(configDir, cache) {
|
|
26072
|
+
writeFileSync6(symbolSummariesPath(configDir), JSON.stringify(cache, null, 2), "utf8");
|
|
26073
|
+
}
|
|
26074
|
+
function summariesByBodyHash(cache) {
|
|
26075
|
+
const m = /* @__PURE__ */ new Map();
|
|
26076
|
+
for (const [bodyHash, e] of Object.entries(cache.entries)) {
|
|
26077
|
+
if (!e.rejected && typeof e.summary === "string" && e.summary.trim()) m.set(bodyHash, e.summary);
|
|
26078
|
+
}
|
|
26079
|
+
return m;
|
|
26080
|
+
}
|
|
26081
|
+
function parseSummaryJson(text, expected) {
|
|
26082
|
+
const start2 = text.indexOf("[");
|
|
26083
|
+
const end = text.lastIndexOf("]");
|
|
26084
|
+
if (start2 < 0 || end <= start2) return new Array(expected).fill(null);
|
|
26085
|
+
let arr;
|
|
26086
|
+
try {
|
|
26087
|
+
arr = JSON.parse(text.slice(start2, end + 1));
|
|
26088
|
+
} catch {
|
|
26089
|
+
return new Array(expected).fill(null);
|
|
26090
|
+
}
|
|
26091
|
+
if (!Array.isArray(arr)) return new Array(expected).fill(null);
|
|
26092
|
+
const out2 = [];
|
|
26093
|
+
for (let i2 = 0; i2 < expected; i2++) {
|
|
26094
|
+
const v = arr[i2];
|
|
26095
|
+
out2.push(typeof v === "string" && v.trim() ? v.trim().slice(0, MAX_SYMBOL_SUMMARY_CHARS) : null);
|
|
26096
|
+
}
|
|
26097
|
+
return out2;
|
|
26098
|
+
}
|
|
26099
|
+
function haikuIntentSummarizer(apiKey) {
|
|
26100
|
+
if (!apiKey) return void 0;
|
|
26101
|
+
return async (symbols) => {
|
|
26102
|
+
try {
|
|
26103
|
+
const listing = symbols.map(
|
|
26104
|
+
(s, i2) => `### ${i2 + 1}. kind: ${s.kind}
|
|
26105
|
+
name: ${s.name}
|
|
26106
|
+
${s.snippet ? `\`\`\`
|
|
26107
|
+
${s.snippet}
|
|
26108
|
+
\`\`\`` : "(no source available \u2014 describe from the name)"}`
|
|
26109
|
+
).join("\n\n");
|
|
26110
|
+
const resp = await fetch("https://api.anthropic.com/v1/messages", {
|
|
26111
|
+
method: "POST",
|
|
26112
|
+
headers: {
|
|
26113
|
+
"x-api-key": apiKey,
|
|
26114
|
+
"anthropic-version": "2023-06-01",
|
|
26115
|
+
"content-type": "application/json"
|
|
26116
|
+
},
|
|
26117
|
+
body: JSON.stringify({
|
|
26118
|
+
model: SUMMARY_MODEL,
|
|
26119
|
+
max_tokens: 2e3,
|
|
26120
|
+
messages: [{ role: "user", content: `${SUMMARY_PROMPT}
|
|
26121
|
+
|
|
26122
|
+
SYMBOLS:
|
|
26123
|
+
${listing}` }]
|
|
26124
|
+
})
|
|
26125
|
+
});
|
|
26126
|
+
if (!resp.ok) return symbols.map(() => null);
|
|
26127
|
+
const json2 = await resp.json();
|
|
26128
|
+
return parseSummaryJson(json2.content?.find((c) => c.type === "text")?.text ?? "", symbols.length);
|
|
26129
|
+
} catch {
|
|
26130
|
+
return symbols.map(() => null);
|
|
26131
|
+
}
|
|
26132
|
+
};
|
|
26133
|
+
}
|
|
26134
|
+
function envIntentSummarizer() {
|
|
26135
|
+
if (process.env["ERRATA_SYMBOL_SUMMARIES"] !== "1") return void 0;
|
|
26136
|
+
return haikuIntentSummarizer(process.env["ANTHROPIC_API_KEY"] ?? null);
|
|
26137
|
+
}
|
|
26138
|
+
function readSnippet(workspaceRoot, attrs) {
|
|
26139
|
+
const relPath = attrs["relPath"];
|
|
26140
|
+
const startByte = attrs["startByte"];
|
|
26141
|
+
const endByte = attrs["endByte"];
|
|
26142
|
+
if (typeof relPath !== "string" || typeof startByte !== "number" || typeof endByte !== "number") {
|
|
26143
|
+
return void 0;
|
|
26144
|
+
}
|
|
26145
|
+
try {
|
|
26146
|
+
const buf = readFileSync5(join6(workspaceRoot, ...relPath.split("/")));
|
|
26147
|
+
const slice = buf.subarray(Math.max(0, startByte), Math.min(buf.length, endByte));
|
|
26148
|
+
const text = slice.toString("utf8");
|
|
26149
|
+
return text.length > MAX_SNIPPET_CHARS ? text.slice(0, MAX_SNIPPET_CHARS) : text;
|
|
26150
|
+
} catch {
|
|
26151
|
+
return void 0;
|
|
26152
|
+
}
|
|
26153
|
+
}
|
|
26154
|
+
async function runSymbolSummarySweep(store, workspaceRoot, configDir, summarizer, opts = {}) {
|
|
26155
|
+
const maxSymbols = opts.maxSymbols ?? DEFAULT_MAX_SYMBOLS_PER_SWEEP;
|
|
26156
|
+
const batchSize = Math.max(1, opts.batchSize ?? DEFAULT_BATCH_SIZE);
|
|
26157
|
+
const cache = loadSymbolSummaryCache(configDir);
|
|
26158
|
+
const candidates = [];
|
|
26159
|
+
const seen = /* @__PURE__ */ new Set();
|
|
26160
|
+
for (const [label, kind] of SUMMARY_LABELS) {
|
|
26161
|
+
for (const n of store.findNodesByLabel(label)) {
|
|
26162
|
+
const bodyHash = n.attrs["bodyHash"];
|
|
26163
|
+
if (typeof bodyHash !== "string" || !bodyHash || seen.has(bodyHash)) continue;
|
|
26164
|
+
if (cache.entries[bodyHash]) continue;
|
|
26165
|
+
const name2 = n.description;
|
|
26166
|
+
if (!name2 || !isDistinctiveIdentifier(name2)) continue;
|
|
26167
|
+
seen.add(bodyHash);
|
|
26168
|
+
const snippet = readSnippet(workspaceRoot, n.attrs);
|
|
26169
|
+
candidates.push({ bodyHash, name: name2, kind, ...snippet ? { snippet } : {} });
|
|
26170
|
+
}
|
|
26171
|
+
}
|
|
26172
|
+
const todo = candidates.slice(0, maxSymbols);
|
|
26173
|
+
const remaining = candidates.length - todo.length;
|
|
26174
|
+
if (todo.length === 0) return { generated: 0, rejected: 0, remaining };
|
|
26175
|
+
const lexicon = buildSymbolLexicon(store);
|
|
26176
|
+
const isKnown = (tok) => lexicon.has(tok);
|
|
26177
|
+
let generated = 0;
|
|
26178
|
+
let rejected = 0;
|
|
26179
|
+
for (let i2 = 0; i2 < todo.length; i2 += batchSize) {
|
|
26180
|
+
const batch = todo.slice(i2, i2 + batchSize);
|
|
26181
|
+
const phrases = await summarizer(batch);
|
|
26182
|
+
const now = Date.now();
|
|
26183
|
+
for (let j = 0; j < batch.length; j++) {
|
|
26184
|
+
const sym = batch[j];
|
|
26185
|
+
const phrase = phrases[j];
|
|
26186
|
+
if (phrase == null) continue;
|
|
26187
|
+
if (summaryRejectionReason(phrase, isKnown) === null) {
|
|
26188
|
+
cache.entries[sym.bodyHash] = { summary: phrase, model: SUMMARY_MODEL, createdAt: now };
|
|
26189
|
+
generated++;
|
|
26190
|
+
} else {
|
|
26191
|
+
cache.entries[sym.bodyHash] = { rejected: true, model: SUMMARY_MODEL, createdAt: now };
|
|
26192
|
+
rejected++;
|
|
26193
|
+
}
|
|
26194
|
+
}
|
|
26195
|
+
saveSymbolSummaryCache(configDir, cache);
|
|
26196
|
+
}
|
|
26197
|
+
return { generated, rejected, remaining };
|
|
26198
|
+
}
|
|
26199
|
+
var SUMMARY_LABELS, MAX_SNIPPET_CHARS, DEFAULT_MAX_SYMBOLS_PER_SWEEP, DEFAULT_BATCH_SIZE, SUMMARY_MODEL, SUMMARY_PROMPT;
|
|
26200
|
+
var init_symbol_summaries = __esm({
|
|
26201
|
+
"src/symbol-summaries.ts"() {
|
|
26202
|
+
"use strict";
|
|
26203
|
+
init_src();
|
|
26204
|
+
init_generalize_graph();
|
|
26205
|
+
SUMMARY_LABELS = [
|
|
26206
|
+
["Function", "function"],
|
|
26207
|
+
["Method", "method"],
|
|
26208
|
+
["Class", "class"]
|
|
26209
|
+
];
|
|
26210
|
+
MAX_SNIPPET_CHARS = 1500;
|
|
26211
|
+
DEFAULT_MAX_SYMBOLS_PER_SWEEP = 64;
|
|
26212
|
+
DEFAULT_BATCH_SIZE = 16;
|
|
26213
|
+
SUMMARY_MODEL = "claude-haiku-4-5-20251001";
|
|
26214
|
+
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").
|
|
26215
|
+
HARD RULES \u2014 a violating phrase is discarded:
|
|
26216
|
+
- 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.
|
|
26217
|
+
- NEVER include quoted strings, literals, numbers copied from the code, or code syntax.
|
|
26218
|
+
- One phrase per symbol, under 200 characters, lowercase start, no trailing period.
|
|
26219
|
+
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.`;
|
|
26220
|
+
}
|
|
26221
|
+
});
|
|
26222
|
+
|
|
25915
26223
|
// ../../packages/indexer/src/simhash.ts
|
|
25916
26224
|
function fnv1a64(s) {
|
|
25917
26225
|
let h = FNV_OFFSET;
|
|
@@ -26135,9 +26443,9 @@ var init_identity2 = __esm({
|
|
|
26135
26443
|
});
|
|
26136
26444
|
|
|
26137
26445
|
// ../../packages/indexer/src/pipeline.ts
|
|
26138
|
-
import { appendFileSync, readFileSync as
|
|
26446
|
+
import { appendFileSync, readFileSync as readFileSync6, statSync } from "node:fs";
|
|
26139
26447
|
import { readdir } from "node:fs/promises";
|
|
26140
|
-
import { extname, join as
|
|
26448
|
+
import { extname, join as join7, relative as relative2, sep } from "node:path";
|
|
26141
26449
|
import { createHash as createHash3 } from "node:crypto";
|
|
26142
26450
|
import { execFileSync } from "node:child_process";
|
|
26143
26451
|
function nowTs() {
|
|
@@ -26253,7 +26561,7 @@ async function incrementalReindex(store, rootPath, workspaceId2, changedAbsPaths
|
|
|
26253
26561
|
for (const rel of [...changedRelPaths]) {
|
|
26254
26562
|
let h;
|
|
26255
26563
|
try {
|
|
26256
|
-
h = createHash3("sha256").update(
|
|
26564
|
+
h = createHash3("sha256").update(readFileSync6(join7(rootPath, rel))).digest("hex");
|
|
26257
26565
|
} catch {
|
|
26258
26566
|
continue;
|
|
26259
26567
|
}
|
|
@@ -26300,13 +26608,13 @@ async function incrementalReindex(store, rootPath, workspaceId2, changedAbsPaths
|
|
|
26300
26608
|
let parsedFiles = 0;
|
|
26301
26609
|
for (const rel of changedRelPaths) {
|
|
26302
26610
|
if (parsedFiles++ > 0) await new Promise((r2) => setImmediate(r2));
|
|
26303
|
-
const abs =
|
|
26611
|
+
const abs = join7(rootPath, ...rel.split("/"));
|
|
26304
26612
|
const ext = extname(abs).toLowerCase();
|
|
26305
26613
|
const provider = providers.find((p) => p.fileExtensions.includes(ext));
|
|
26306
26614
|
if (!provider) continue;
|
|
26307
26615
|
let symbols;
|
|
26308
26616
|
try {
|
|
26309
|
-
symbols = provider.extractSymbols(
|
|
26617
|
+
symbols = provider.extractSymbols(readFileSync6(abs, "utf8"), abs);
|
|
26310
26618
|
} catch {
|
|
26311
26619
|
continue;
|
|
26312
26620
|
}
|
|
@@ -26606,7 +26914,7 @@ async function runIndexer(store, opts) {
|
|
|
26606
26914
|
report.filesSkipped++;
|
|
26607
26915
|
continue;
|
|
26608
26916
|
}
|
|
26609
|
-
source =
|
|
26917
|
+
source = readFileSync6(f.absPath, "utf8");
|
|
26610
26918
|
} catch {
|
|
26611
26919
|
report.filesSkipped++;
|
|
26612
26920
|
continue;
|
|
@@ -26658,7 +26966,7 @@ async function runIndexer(store, opts) {
|
|
|
26658
26966
|
const depth = fileNode.relPath.split("/").length;
|
|
26659
26967
|
if (depth !== 3) continue;
|
|
26660
26968
|
try {
|
|
26661
|
-
const pkg = JSON.parse(
|
|
26969
|
+
const pkg = JSON.parse(readFileSync6(fileNode.absPath, "utf8"));
|
|
26662
26970
|
if (!pkg.name) continue;
|
|
26663
26971
|
const pkgDir = fileNode.relPath.replace(/\/package\.json$/, "");
|
|
26664
26972
|
const candidates = [
|
|
@@ -27040,7 +27348,7 @@ async function scan(root, current, ignores, providers, out2) {
|
|
|
27040
27348
|
for (const ent of entries) {
|
|
27041
27349
|
if (ignores.has(ent.name)) continue;
|
|
27042
27350
|
if (ent.name.startsWith(".") && ent.name !== ".") continue;
|
|
27043
|
-
const abs =
|
|
27351
|
+
const abs = join7(current, ent.name);
|
|
27044
27352
|
if (ent.isDirectory()) {
|
|
27045
27353
|
await scan(root, abs, ignores, providers, out2);
|
|
27046
27354
|
} else if (ent.isFile()) {
|
|
@@ -27086,7 +27394,7 @@ function gitListFiles(root, ignores, providers) {
|
|
|
27086
27394
|
if (segs.some((s) => ignores.has(s) || s.startsWith(".") && s.length > 1)) {
|
|
27087
27395
|
continue;
|
|
27088
27396
|
}
|
|
27089
|
-
const abs =
|
|
27397
|
+
const abs = join7(root, rel);
|
|
27090
27398
|
let size;
|
|
27091
27399
|
try {
|
|
27092
27400
|
size = statSync(abs).size;
|
|
@@ -27109,7 +27417,7 @@ function upsertFile(store, id, f, workspaceId2) {
|
|
|
27109
27417
|
const now = nowTs();
|
|
27110
27418
|
let contentHash;
|
|
27111
27419
|
try {
|
|
27112
|
-
contentHash = createHash3("sha256").update(
|
|
27420
|
+
contentHash = createHash3("sha256").update(readFileSync6(f.absPath)).digest("hex");
|
|
27113
27421
|
} catch {
|
|
27114
27422
|
}
|
|
27115
27423
|
const node2 = {
|
|
@@ -31471,8 +31779,8 @@ ${JSON.stringify(symbolNames, null, 2)}`);
|
|
|
31471
31779
|
|
|
31472
31780
|
// ../../packages/indexer/src/languages/tree-sitter-loader.ts
|
|
31473
31781
|
import { fileURLToPath } from "node:url";
|
|
31474
|
-
import { dirname as dirname4, join as
|
|
31475
|
-
import { existsSync as
|
|
31782
|
+
import { dirname as dirname4, join as join8 } from "node:path";
|
|
31783
|
+
import { existsSync as existsSync8, readdirSync as readdirSync2 } from "node:fs";
|
|
31476
31784
|
import { createRequire as createRequire2 } from "node:module";
|
|
31477
31785
|
function entryDir() {
|
|
31478
31786
|
try {
|
|
@@ -31486,27 +31794,27 @@ function entryDir() {
|
|
|
31486
31794
|
}
|
|
31487
31795
|
function findWasmDir() {
|
|
31488
31796
|
const here = entryDir();
|
|
31489
|
-
const seaWasm =
|
|
31490
|
-
if (
|
|
31797
|
+
const seaWasm = join8(here, "resources", "wasm");
|
|
31798
|
+
if (existsSync8(join8(seaWasm, "tree-sitter-typescript.wasm"))) return seaWasm;
|
|
31491
31799
|
let dir = here;
|
|
31492
31800
|
for (let i2 = 0; i2 < 6; i2++) {
|
|
31493
|
-
const flat =
|
|
31801
|
+
const flat = join8(
|
|
31494
31802
|
dir,
|
|
31495
31803
|
"node_modules",
|
|
31496
31804
|
"@vscode",
|
|
31497
31805
|
"tree-sitter-wasm",
|
|
31498
31806
|
"wasm"
|
|
31499
31807
|
);
|
|
31500
|
-
if (
|
|
31808
|
+
if (existsSync8(join8(flat, "tree-sitter-typescript.wasm"))) return flat;
|
|
31501
31809
|
dir = dirname4(dir);
|
|
31502
31810
|
}
|
|
31503
31811
|
let root = here;
|
|
31504
31812
|
for (let i2 = 0; i2 < 6; i2++) {
|
|
31505
|
-
const pnpmDir =
|
|
31506
|
-
if (
|
|
31813
|
+
const pnpmDir = join8(root, "node_modules", ".pnpm");
|
|
31814
|
+
if (existsSync8(pnpmDir)) {
|
|
31507
31815
|
for (const entry of readdirSync2(pnpmDir)) {
|
|
31508
31816
|
if (entry.startsWith("@vscode+tree-sitter-wasm@")) {
|
|
31509
|
-
const candidate =
|
|
31817
|
+
const candidate = join8(
|
|
31510
31818
|
pnpmDir,
|
|
31511
31819
|
entry,
|
|
31512
31820
|
"node_modules",
|
|
@@ -31514,7 +31822,7 @@ function findWasmDir() {
|
|
|
31514
31822
|
"tree-sitter-wasm",
|
|
31515
31823
|
"wasm"
|
|
31516
31824
|
);
|
|
31517
|
-
if (
|
|
31825
|
+
if (existsSync8(join8(candidate, "tree-sitter-typescript.wasm"))) {
|
|
31518
31826
|
return candidate;
|
|
31519
31827
|
}
|
|
31520
31828
|
}
|
|
@@ -31528,27 +31836,27 @@ function findWasmDir() {
|
|
|
31528
31836
|
}
|
|
31529
31837
|
function findRuntimeDir() {
|
|
31530
31838
|
const here = entryDir();
|
|
31531
|
-
const seaRuntime =
|
|
31532
|
-
if (
|
|
31839
|
+
const seaRuntime = join8(here, "resources", "wasm");
|
|
31840
|
+
if (existsSync8(join8(seaRuntime, "web-tree-sitter.wasm"))) return seaRuntime;
|
|
31533
31841
|
let dir = here;
|
|
31534
31842
|
for (let i2 = 0; i2 < 6; i2++) {
|
|
31535
|
-
const flat =
|
|
31536
|
-
if (
|
|
31843
|
+
const flat = join8(dir, "node_modules", "web-tree-sitter");
|
|
31844
|
+
if (existsSync8(join8(flat, "web-tree-sitter.wasm"))) return flat;
|
|
31537
31845
|
dir = dirname4(dir);
|
|
31538
31846
|
}
|
|
31539
31847
|
let root = here;
|
|
31540
31848
|
for (let i2 = 0; i2 < 6; i2++) {
|
|
31541
|
-
const pnpmDir =
|
|
31542
|
-
if (
|
|
31849
|
+
const pnpmDir = join8(root, "node_modules", ".pnpm");
|
|
31850
|
+
if (existsSync8(pnpmDir)) {
|
|
31543
31851
|
for (const entry of readdirSync2(pnpmDir)) {
|
|
31544
31852
|
if (entry.startsWith("web-tree-sitter@")) {
|
|
31545
|
-
const candidate =
|
|
31853
|
+
const candidate = join8(
|
|
31546
31854
|
pnpmDir,
|
|
31547
31855
|
entry,
|
|
31548
31856
|
"node_modules",
|
|
31549
31857
|
"web-tree-sitter"
|
|
31550
31858
|
);
|
|
31551
|
-
if (
|
|
31859
|
+
if (existsSync8(join8(candidate, "web-tree-sitter.wasm"))) {
|
|
31552
31860
|
return candidate;
|
|
31553
31861
|
}
|
|
31554
31862
|
}
|
|
@@ -31565,7 +31873,7 @@ async function loadWebTreeSitter() {
|
|
|
31565
31873
|
void err2;
|
|
31566
31874
|
}
|
|
31567
31875
|
const here = entryDir();
|
|
31568
|
-
const seaResourceBase =
|
|
31876
|
+
const seaResourceBase = join8(here, "resources", "_resolve.js");
|
|
31569
31877
|
const resourceRequire = createRequire2(seaResourceBase);
|
|
31570
31878
|
return resourceRequire("web-tree-sitter");
|
|
31571
31879
|
}
|
|
@@ -31580,9 +31888,9 @@ async function ensureTreeSitterReady() {
|
|
|
31580
31888
|
await Parser2.init({
|
|
31581
31889
|
locateFile: (name2) => {
|
|
31582
31890
|
if (name2 === "tree-sitter.wasm" || name2 === "web-tree-sitter.wasm") {
|
|
31583
|
-
return
|
|
31891
|
+
return join8(runtime, name2);
|
|
31584
31892
|
}
|
|
31585
|
-
return
|
|
31893
|
+
return join8(grammars, name2);
|
|
31586
31894
|
}
|
|
31587
31895
|
});
|
|
31588
31896
|
})();
|
|
@@ -31594,7 +31902,7 @@ async function loadGrammar(name2) {
|
|
|
31594
31902
|
if (cached2) return cached2;
|
|
31595
31903
|
if (!languageClass) throw new Error("tree-sitter not initialized");
|
|
31596
31904
|
const grammars = findWasmDir();
|
|
31597
|
-
const lang = await languageClass.load(
|
|
31905
|
+
const lang = await languageClass.load(join8(grammars, `${name2}.wasm`));
|
|
31598
31906
|
grammarCache.set(name2, lang);
|
|
31599
31907
|
return lang;
|
|
31600
31908
|
}
|
|
@@ -34496,7 +34804,7 @@ var init_src11 = __esm({
|
|
|
34496
34804
|
// src/reconcile.ts
|
|
34497
34805
|
import { execFileSync as execFileSync2 } from "node:child_process";
|
|
34498
34806
|
import { readdirSync as readdirSync3, statSync as statSync2 } from "node:fs";
|
|
34499
|
-
import { join as
|
|
34807
|
+
import { join as join9, relative as relative3, sep as sep2 } from "node:path";
|
|
34500
34808
|
function gitSourceFiles(root) {
|
|
34501
34809
|
let stdout;
|
|
34502
34810
|
try {
|
|
@@ -34511,7 +34819,7 @@ function gitSourceFiles(root) {
|
|
|
34511
34819
|
const out2 = [];
|
|
34512
34820
|
for (const rel of stdout.split("\0")) {
|
|
34513
34821
|
if (!rel || !SOURCE_RE.test(rel)) continue;
|
|
34514
|
-
const abs =
|
|
34822
|
+
const abs = join9(root, rel);
|
|
34515
34823
|
if (IGNORED.test(abs)) continue;
|
|
34516
34824
|
out2.push(abs);
|
|
34517
34825
|
}
|
|
@@ -34526,7 +34834,7 @@ function* walkSource(dir) {
|
|
|
34526
34834
|
}
|
|
34527
34835
|
for (const e of entries) {
|
|
34528
34836
|
const name2 = String(e.name);
|
|
34529
|
-
const full =
|
|
34837
|
+
const full = join9(dir, name2);
|
|
34530
34838
|
if (IGNORED.test(full)) continue;
|
|
34531
34839
|
if (e.isDirectory()) yield* walkSource(full);
|
|
34532
34840
|
else if (SOURCE_RE.test(name2)) yield full;
|
|
@@ -34604,7 +34912,7 @@ __export(mcp_exports, {
|
|
|
34604
34912
|
runTool: () => runTool,
|
|
34605
34913
|
searchGraph: () => searchGraph
|
|
34606
34914
|
});
|
|
34607
|
-
import { existsSync as
|
|
34915
|
+
import { existsSync as existsSync9, readFileSync as readFileSync7 } from "node:fs";
|
|
34608
34916
|
import { resolve } from "node:path";
|
|
34609
34917
|
function collectEnrichmentPulls(store, opts = {}) {
|
|
34610
34918
|
const pending = store.findNodesByLabel("Solution").filter((s) => s.attrs["enrichmentPending"] === true).filter((s) => !opts.onlyUnsurfaced || s.attrs["enrichmentSurfaced"] !== true);
|
|
@@ -34717,10 +35025,10 @@ function showNode(store, node2, maxLines) {
|
|
|
34717
35025
|
if (!relPath) return { found: false, reason: "no file owner for node" };
|
|
34718
35026
|
const workspaceRoot = process.cwd();
|
|
34719
35027
|
const absPath = resolve(workspaceRoot, relPath);
|
|
34720
|
-
if (!
|
|
35028
|
+
if (!existsSync9(absPath)) {
|
|
34721
35029
|
return { found: false, reason: `file not found on disk: ${absPath}` };
|
|
34722
35030
|
}
|
|
34723
|
-
const source =
|
|
35031
|
+
const source = readFileSync7(absPath, "utf8");
|
|
34724
35032
|
const attrs = node2.attrs;
|
|
34725
35033
|
let startByte = attrs["bodyStartByte"] ?? attrs["startByte"];
|
|
34726
35034
|
let endByte = attrs["bodyEndByte"] ?? attrs["endByte"];
|
|
@@ -34933,7 +35241,20 @@ function buildToolContext() {
|
|
|
34933
35241
|
async function runMcpServer(workspaceRoot) {
|
|
34934
35242
|
const paths = workspacePaths(workspaceRoot);
|
|
34935
35243
|
const store = openGraphStore({ path: paths.castalia });
|
|
34936
|
-
|
|
35244
|
+
let summariesMemo = null;
|
|
35245
|
+
const symbolSummaries = () => {
|
|
35246
|
+
const now = Date.now();
|
|
35247
|
+
if (!summariesMemo || now - summariesMemo.at > 6e4) {
|
|
35248
|
+
let map2 = /* @__PURE__ */ new Map();
|
|
35249
|
+
try {
|
|
35250
|
+
map2 = summariesByBodyHash(loadSymbolSummaryCache(paths.configDir));
|
|
35251
|
+
} catch {
|
|
35252
|
+
}
|
|
35253
|
+
summariesMemo = { at: now, map: map2 };
|
|
35254
|
+
}
|
|
35255
|
+
return summariesMemo.map;
|
|
35256
|
+
};
|
|
35257
|
+
const handle2 = createMcpHandler(store, { ...buildToolContext(), symbolSummaries });
|
|
34937
35258
|
process.stdin.setEncoding("utf8");
|
|
34938
35259
|
let buffer = "";
|
|
34939
35260
|
process.stdin.on("data", (chunk) => {
|
|
@@ -34972,6 +35293,7 @@ var init_mcp = __esm({
|
|
|
34972
35293
|
init_src2();
|
|
34973
35294
|
init_src10();
|
|
34974
35295
|
init_paths();
|
|
35296
|
+
init_symbol_summaries();
|
|
34975
35297
|
init_webui();
|
|
34976
35298
|
init_reconcile();
|
|
34977
35299
|
init_agent_signals();
|
|
@@ -35044,7 +35366,14 @@ var init_mcp = __esm({
|
|
|
35044
35366
|
score: h.pageRank,
|
|
35045
35367
|
hops: 0
|
|
35046
35368
|
}));
|
|
35047
|
-
const dual = await dualAugment({
|
|
35369
|
+
const dual = await dualAugment({
|
|
35370
|
+
store,
|
|
35371
|
+
cloud: ctx.cloud,
|
|
35372
|
+
localHits,
|
|
35373
|
+
queryText: query,
|
|
35374
|
+
limit,
|
|
35375
|
+
...ctx.symbolSummaries ? { summaries: ctx.symbolSummaries() } : {}
|
|
35376
|
+
});
|
|
35048
35377
|
if (dual.status === "merged") {
|
|
35049
35378
|
return {
|
|
35050
35379
|
query,
|
|
@@ -35209,7 +35538,8 @@ var init_mcp = __esm({
|
|
|
35209
35538
|
cloud: ctx.cloud,
|
|
35210
35539
|
localHits,
|
|
35211
35540
|
seedNode,
|
|
35212
|
-
limit: args2["limit"] != null ? Number(args2["limit"]) : 20
|
|
35541
|
+
limit: args2["limit"] != null ? Number(args2["limit"]) : 20,
|
|
35542
|
+
...ctx.symbolSummaries ? { summaries: ctx.symbolSummaries() } : {}
|
|
35213
35543
|
});
|
|
35214
35544
|
if (dual.status === "merged") {
|
|
35215
35545
|
return {
|
|
@@ -35724,7 +36054,14 @@ var init_mcp = __esm({
|
|
|
35724
36054
|
score: h.score,
|
|
35725
36055
|
hops: 0
|
|
35726
36056
|
}));
|
|
35727
|
-
const dual = await dualAugment({
|
|
36057
|
+
const dual = await dualAugment({
|
|
36058
|
+
store,
|
|
36059
|
+
cloud: ctx.cloud,
|
|
36060
|
+
localHits,
|
|
36061
|
+
seedNode: node2,
|
|
36062
|
+
limit,
|
|
36063
|
+
...ctx.symbolSummaries ? { summaries: ctx.symbolSummaries() } : {}
|
|
36064
|
+
});
|
|
35728
36065
|
if (dual.status === "merged") {
|
|
35729
36066
|
return {
|
|
35730
36067
|
seedId: id,
|
|
@@ -35915,7 +36252,7 @@ var init_mcp = __esm({
|
|
|
35915
36252
|
inputSchema: { type: "object", properties: {} },
|
|
35916
36253
|
handler: () => {
|
|
35917
36254
|
const path2 = sharedStorePath();
|
|
35918
|
-
if (!
|
|
36255
|
+
if (!existsSync9(path2)) return { count: 0, pending: [] };
|
|
35919
36256
|
const shared = openGraphStore({ path: path2 });
|
|
35920
36257
|
try {
|
|
35921
36258
|
const pending = pendingAbstractions(shared);
|
|
@@ -35946,7 +36283,7 @@ var init_mcp = __esm({
|
|
|
35946
36283
|
},
|
|
35947
36284
|
handler: (args2) => {
|
|
35948
36285
|
const path2 = sharedStorePath();
|
|
35949
|
-
if (!
|
|
36286
|
+
if (!existsSync9(path2)) return { count: 0, routes: [] };
|
|
35950
36287
|
const shared = openGraphStore({ path: path2 });
|
|
35951
36288
|
try {
|
|
35952
36289
|
const result = triageOf(shared, {
|
|
@@ -36331,8 +36668,8 @@ __export(vfile_exports, {
|
|
|
36331
36668
|
resolvePath: () => resolvePath,
|
|
36332
36669
|
segmentsOf: () => segmentsOf
|
|
36333
36670
|
});
|
|
36334
|
-
import { writeFileSync as
|
|
36335
|
-
import { join as
|
|
36671
|
+
import { writeFileSync as writeFileSync7 } from "node:fs";
|
|
36672
|
+
import { join as join10, resolve as resolve2, sep as sep3 } from "node:path";
|
|
36336
36673
|
function segmentsOf(rawPath) {
|
|
36337
36674
|
let p = rawPath.replace(/\\/g, "/");
|
|
36338
36675
|
p = p.replace(/^.*\.errata\/g\//, "").replace(/^\/?g\//, "").replace(/^\/+/, "");
|
|
@@ -36406,14 +36743,14 @@ async function renderVFile(rawPath, store, ctx = {}) {
|
|
|
36406
36743
|
}
|
|
36407
36744
|
async function materializeVFile(rawPath, workspaceRoot, store, ctx = {}) {
|
|
36408
36745
|
const segs = segmentsOf(rawPath);
|
|
36409
|
-
const gRoot =
|
|
36746
|
+
const gRoot = join10(workspaceRoot, ".errata", "g");
|
|
36410
36747
|
const abs = resolve2(gRoot, ...segs.length ? segs : ["index"]);
|
|
36411
36748
|
if (abs !== gRoot && !abs.startsWith(gRoot + sep3)) {
|
|
36412
36749
|
throw new Error(`refusing to materialize outside .errata/g: ${rawPath}`);
|
|
36413
36750
|
}
|
|
36414
36751
|
const text = await renderVFile(rawPath, store, ctx);
|
|
36415
36752
|
ensureParent(abs);
|
|
36416
|
-
|
|
36753
|
+
writeFileSync7(abs, text, "utf8");
|
|
36417
36754
|
return abs;
|
|
36418
36755
|
}
|
|
36419
36756
|
async function materializeOverview(workspaceRoot, store, ctx = {}) {
|
|
@@ -36498,25 +36835,25 @@ the tool surface; the path is the thin, composable channel.
|
|
|
36498
36835
|
|
|
36499
36836
|
// src/outbox.ts
|
|
36500
36837
|
import {
|
|
36501
|
-
existsSync as
|
|
36838
|
+
existsSync as existsSync10,
|
|
36502
36839
|
readdirSync as readdirSync4,
|
|
36503
|
-
readFileSync as
|
|
36840
|
+
readFileSync as readFileSync8,
|
|
36504
36841
|
renameSync,
|
|
36505
36842
|
unlinkSync,
|
|
36506
|
-
writeFileSync as
|
|
36843
|
+
writeFileSync as writeFileSync8
|
|
36507
36844
|
} from "node:fs";
|
|
36508
|
-
import { join as
|
|
36845
|
+
import { join as join11 } from "node:path";
|
|
36509
36846
|
import { createHash as createHash11 } from "node:crypto";
|
|
36510
36847
|
function enqueueOutbox(paths, payload) {
|
|
36511
36848
|
ensureDir(paths.outbox);
|
|
36512
36849
|
const id = createHash11("sha256").update(JSON.stringify(payload)).digest("hex").slice(0, 16);
|
|
36513
|
-
const file2 =
|
|
36514
|
-
|
|
36850
|
+
const file2 = join11(paths.outbox, `${Date.now()}-${id}.json`);
|
|
36851
|
+
writeFileSync8(file2, JSON.stringify(payload, null, 2), "utf8");
|
|
36515
36852
|
return file2;
|
|
36516
36853
|
}
|
|
36517
36854
|
async function flushOutbox(paths, client, store) {
|
|
36518
36855
|
ensureDir(paths.outbox);
|
|
36519
|
-
const entries =
|
|
36856
|
+
const entries = existsSync10(paths.outbox) ? readdirSync4(paths.outbox) : [];
|
|
36520
36857
|
let uploaded = 0;
|
|
36521
36858
|
let failed = 0;
|
|
36522
36859
|
const quarantine = (abs, reason) => {
|
|
@@ -36527,10 +36864,10 @@ async function flushOutbox(paths, client, store) {
|
|
|
36527
36864
|
}
|
|
36528
36865
|
};
|
|
36529
36866
|
for (const f of entries.filter((e) => e.endsWith(".json")).sort()) {
|
|
36530
|
-
const abs =
|
|
36867
|
+
const abs = join11(paths.outbox, f);
|
|
36531
36868
|
let payload;
|
|
36532
36869
|
try {
|
|
36533
|
-
payload = JSON.parse(
|
|
36870
|
+
payload = JSON.parse(readFileSync8(abs, "utf8"));
|
|
36534
36871
|
} catch {
|
|
36535
36872
|
failed++;
|
|
36536
36873
|
quarantine(abs, "unparseable JSON");
|
|
@@ -36558,7 +36895,7 @@ async function flushOutbox(paths, client, store) {
|
|
|
36558
36895
|
}
|
|
36559
36896
|
}
|
|
36560
36897
|
}
|
|
36561
|
-
const remainingFiles =
|
|
36898
|
+
const remainingFiles = existsSync10(paths.outbox) ? readdirSync4(paths.outbox).filter((e) => e.endsWith(".json")) : [];
|
|
36562
36899
|
return { uploaded, failed, remaining: remainingFiles.length };
|
|
36563
36900
|
}
|
|
36564
36901
|
var init_outbox = __esm({
|
|
@@ -36577,7 +36914,7 @@ __export(webui_exports, {
|
|
|
36577
36914
|
findFileByPath: () => findFileByPath,
|
|
36578
36915
|
recallForFile: () => recallForFile
|
|
36579
36916
|
});
|
|
36580
|
-
import { join as
|
|
36917
|
+
import { join as join12 } from "node:path";
|
|
36581
36918
|
function fileUriToFsPath(raw2) {
|
|
36582
36919
|
let p = raw2.replace(/^file:\/\//, "").replace(/\\/g, "/");
|
|
36583
36920
|
if (/^\/[A-Za-z]:/.test(p)) p = p.slice(1);
|
|
@@ -36938,7 +37275,7 @@ function buildWebUi(deps) {
|
|
|
36938
37275
|
} catch {
|
|
36939
37276
|
return c.json({});
|
|
36940
37277
|
}
|
|
36941
|
-
const block = readManagedBlockWithHash(
|
|
37278
|
+
const block = readManagedBlockWithHash(join12(deps.paths.root, "AGENTS.md"));
|
|
36942
37279
|
const decision = decideContextInject({
|
|
36943
37280
|
event: String(body2["hook_event_name"] ?? "UserPromptSubmit"),
|
|
36944
37281
|
source: String(body2["source"] ?? ""),
|
|
@@ -37540,12 +37877,12 @@ var init_report_render = __esm({
|
|
|
37540
37877
|
|
|
37541
37878
|
// src/cli.ts
|
|
37542
37879
|
init_src5();
|
|
37543
|
-
import { closeSync as closeSync2, existsSync as
|
|
37544
|
-
import { join as
|
|
37880
|
+
import { closeSync as closeSync2, existsSync as existsSync20, openSync as openSync2, readFileSync as readFileSync19, renameSync as renameSync3, statSync as statSync5 } from "node:fs";
|
|
37881
|
+
import { join as join23 } from "node:path";
|
|
37545
37882
|
import { spawn as spawn3 } from "node:child_process";
|
|
37546
37883
|
|
|
37547
37884
|
// src/daemon.ts
|
|
37548
|
-
import { existsSync as
|
|
37885
|
+
import { existsSync as existsSync16, writeFileSync as writeFileSync13 } from "node:fs";
|
|
37549
37886
|
|
|
37550
37887
|
// ../../node_modules/.pnpm/@hono+node-server@1.19.11_hono@4.12.8/node_modules/@hono/node-server/dist/index.mjs
|
|
37551
37888
|
import { createServer as createServerHTTP } from "http";
|
|
@@ -38125,8 +38462,8 @@ init_config();
|
|
|
38125
38462
|
|
|
38126
38463
|
// src/engine.ts
|
|
38127
38464
|
import { execFileSync as execFileSync3 } from "node:child_process";
|
|
38128
|
-
import { existsSync as
|
|
38129
|
-
import { join as
|
|
38465
|
+
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";
|
|
38466
|
+
import { join as join20, relative as relative6, sep as sep4 } from "node:path";
|
|
38130
38467
|
|
|
38131
38468
|
// ../../node_modules/.pnpm/chokidar@4.0.3/node_modules/chokidar/esm/index.js
|
|
38132
38469
|
import { stat as statcb } from "fs";
|
|
@@ -39988,8 +40325,8 @@ init_src10();
|
|
|
39988
40325
|
init_review2();
|
|
39989
40326
|
|
|
39990
40327
|
// src/turn.ts
|
|
39991
|
-
import { closeSync, existsSync as
|
|
39992
|
-
import { basename as basename3, dirname as dirname7, join as
|
|
40328
|
+
import { closeSync, existsSync as existsSync11, fstatSync, openSync, readdirSync as readdirSync5, readSync, statSync as statSync3 } from "node:fs";
|
|
40329
|
+
import { basename as basename3, dirname as dirname7, join as join15 } from "node:path";
|
|
39993
40330
|
import { homedir as homedir3 } from "node:os";
|
|
39994
40331
|
function readTail(path2, maxBytes) {
|
|
39995
40332
|
let fd;
|
|
@@ -40098,11 +40435,11 @@ function turnsSince(turns, mark) {
|
|
|
40098
40435
|
return at >= 0 ? turns.slice(at + 1) : turns;
|
|
40099
40436
|
}
|
|
40100
40437
|
function claudeProjectDir(cwd, home = homedir3()) {
|
|
40101
|
-
return
|
|
40438
|
+
return join15(home, ".claude", "projects", cwd.replace(/[\\/:.]/g, "-"));
|
|
40102
40439
|
}
|
|
40103
40440
|
function recentTranscripts(cwd, opts = {}) {
|
|
40104
40441
|
const dir = claudeProjectDir(cwd, opts.home ?? homedir3());
|
|
40105
|
-
if (!
|
|
40442
|
+
if (!existsSync11(dir)) return [];
|
|
40106
40443
|
let names;
|
|
40107
40444
|
try {
|
|
40108
40445
|
names = readdirSync5(dir);
|
|
@@ -40113,7 +40450,7 @@ function recentTranscripts(cwd, opts = {}) {
|
|
|
40113
40450
|
const refs = [];
|
|
40114
40451
|
for (const name2 of names) {
|
|
40115
40452
|
if (!name2.endsWith(".jsonl")) continue;
|
|
40116
|
-
const path2 =
|
|
40453
|
+
const path2 = join15(dir, name2);
|
|
40117
40454
|
let mtimeMs;
|
|
40118
40455
|
try {
|
|
40119
40456
|
mtimeMs = statSync3(path2).mtimeMs;
|
|
@@ -40128,8 +40465,8 @@ function recentTranscripts(cwd, opts = {}) {
|
|
|
40128
40465
|
}
|
|
40129
40466
|
function subagentTranscripts(mainTranscriptPath, sessionId) {
|
|
40130
40467
|
if (!mainTranscriptPath || !sessionId) return [];
|
|
40131
|
-
const dir =
|
|
40132
|
-
if (!
|
|
40468
|
+
const dir = join15(dirname7(mainTranscriptPath), sessionId, "subagents");
|
|
40469
|
+
if (!existsSync11(dir)) return [];
|
|
40133
40470
|
let names;
|
|
40134
40471
|
try {
|
|
40135
40472
|
names = readdirSync5(dir);
|
|
@@ -40139,7 +40476,7 @@ function subagentTranscripts(mainTranscriptPath, sessionId) {
|
|
|
40139
40476
|
const refs = [];
|
|
40140
40477
|
for (const name2 of names) {
|
|
40141
40478
|
if (!name2.endsWith(".jsonl")) continue;
|
|
40142
|
-
const path2 =
|
|
40479
|
+
const path2 = join15(dir, name2);
|
|
40143
40480
|
let mtimeMs;
|
|
40144
40481
|
try {
|
|
40145
40482
|
mtimeMs = statSync3(path2).mtimeMs;
|
|
@@ -40156,7 +40493,7 @@ function subagentTranscripts(mainTranscriptPath, sessionId) {
|
|
|
40156
40493
|
init_src();
|
|
40157
40494
|
init_src2();
|
|
40158
40495
|
init_agent_signals();
|
|
40159
|
-
import { readFileSync as
|
|
40496
|
+
import { readFileSync as readFileSync9, writeFileSync as writeFileSync9 } from "node:fs";
|
|
40160
40497
|
var NEG = /n['']t|\b(?:not|never|no|none|neither|nor|unrelated|irrelevant|would|might|could|if)\b/i;
|
|
40161
40498
|
var CITE_GROUP_RE = /\(((?:[^()\n]|\([^()\n]*\)){1,200})\)/g;
|
|
40162
40499
|
var HANDLE_RE = /\[([a-z0-9][\w-]{0,40})\]|((?:pat|sol|drc|dcause|dfix|dprob|prob|claim|err)_[0-9a-f]{6,})/gi;
|
|
@@ -40406,13 +40743,13 @@ function writePrimingHandles(path2, nodes, now = Date.now()) {
|
|
|
40406
40743
|
entries.sort((a, b) => (b[1].seenAt ?? 0) - (a[1].seenAt ?? 0));
|
|
40407
40744
|
entries.length = HANDLE_MAP_MAX;
|
|
40408
40745
|
}
|
|
40409
|
-
|
|
40746
|
+
writeFileSync9(path2, JSON.stringify(Object.fromEntries(entries)));
|
|
40410
40747
|
} catch {
|
|
40411
40748
|
}
|
|
40412
40749
|
}
|
|
40413
40750
|
function readPrimingHandles(path2) {
|
|
40414
40751
|
try {
|
|
40415
|
-
return JSON.parse(
|
|
40752
|
+
return JSON.parse(readFileSync9(path2, "utf8"));
|
|
40416
40753
|
} catch {
|
|
40417
40754
|
return {};
|
|
40418
40755
|
}
|
|
@@ -40668,6 +41005,7 @@ ${conversation}` }]
|
|
|
40668
41005
|
}
|
|
40669
41006
|
|
|
40670
41007
|
// src/engine.ts
|
|
41008
|
+
init_symbol_summaries();
|
|
40671
41009
|
init_reconcile();
|
|
40672
41010
|
|
|
40673
41011
|
// src/episode.ts
|
|
@@ -40864,11 +41202,11 @@ init_outbox();
|
|
|
40864
41202
|
init_src8();
|
|
40865
41203
|
init_src();
|
|
40866
41204
|
init_src2();
|
|
40867
|
-
import { readFileSync as
|
|
40868
|
-
import { join as
|
|
41205
|
+
import { readFileSync as readFileSync10 } from "node:fs";
|
|
41206
|
+
import { join as join16 } from "node:path";
|
|
40869
41207
|
function loadClaimIgnorePatterns(workspaceRoot) {
|
|
40870
41208
|
try {
|
|
40871
|
-
return
|
|
41209
|
+
return readFileSync10(join16(workspaceRoot, ".errataignore"), "utf8").split(/\r?\n/).map((l) => l.trim()).filter((l) => l.length > 0 && !l.startsWith("#")).map((l) => l.toLowerCase());
|
|
40872
41210
|
} catch {
|
|
40873
41211
|
return [];
|
|
40874
41212
|
}
|
|
@@ -41160,22 +41498,22 @@ async function pullCloudTriage(shared, cloud, profile, limit = 50) {
|
|
|
41160
41498
|
}
|
|
41161
41499
|
|
|
41162
41500
|
// src/git-sensor.ts
|
|
41163
|
-
import { existsSync as
|
|
41164
|
-
import { join as
|
|
41501
|
+
import { existsSync as existsSync12, readFileSync as readFileSync11, watch as fsWatch } from "node:fs";
|
|
41502
|
+
import { join as join17 } from "node:path";
|
|
41165
41503
|
function readFirstLine(path2) {
|
|
41166
41504
|
try {
|
|
41167
|
-
return
|
|
41505
|
+
return readFileSync11(path2, "utf8").split(/\r?\n/, 1)[0].trim();
|
|
41168
41506
|
} catch {
|
|
41169
41507
|
return null;
|
|
41170
41508
|
}
|
|
41171
41509
|
}
|
|
41172
41510
|
function readGitRefState(gitDir) {
|
|
41173
|
-
const head2 = readFirstLine(
|
|
41511
|
+
const head2 = readFirstLine(join17(gitDir, "HEAD"));
|
|
41174
41512
|
const m = head2 ? /^ref:\s*refs\/heads\/(.+)$/.exec(head2) : null;
|
|
41175
41513
|
const branch = m ? m[1] : null;
|
|
41176
41514
|
let sha2 = null;
|
|
41177
41515
|
if (branch) {
|
|
41178
|
-
sha2 = readFirstLine(
|
|
41516
|
+
sha2 = readFirstLine(join17(gitDir, "refs", "heads", branch));
|
|
41179
41517
|
if (!sha2) sha2 = shaFromPackedRefs(gitDir, `refs/heads/${branch}`);
|
|
41180
41518
|
} else if (head2 && /^[0-9a-f]{7,40}$/i.test(head2)) {
|
|
41181
41519
|
sha2 = head2;
|
|
@@ -41183,13 +41521,13 @@ function readGitRefState(gitDir) {
|
|
|
41183
41521
|
return {
|
|
41184
41522
|
branch,
|
|
41185
41523
|
sha: sha2,
|
|
41186
|
-
mergeHeadExists:
|
|
41187
|
-
origHeadExists:
|
|
41524
|
+
mergeHeadExists: existsSync12(join17(gitDir, "MERGE_HEAD")),
|
|
41525
|
+
origHeadExists: existsSync12(join17(gitDir, "ORIG_HEAD"))
|
|
41188
41526
|
};
|
|
41189
41527
|
}
|
|
41190
41528
|
function shaFromPackedRefs(gitDir, ref) {
|
|
41191
41529
|
try {
|
|
41192
|
-
for (const line of
|
|
41530
|
+
for (const line of readFileSync11(join17(gitDir, "packed-refs"), "utf8").split(/\r?\n/)) {
|
|
41193
41531
|
const [sha2, name2] = line.split(/\s+/);
|
|
41194
41532
|
if (name2 === ref && sha2) return sha2;
|
|
41195
41533
|
}
|
|
@@ -41223,7 +41561,7 @@ function startGitSensor(gitDir, onEvent, opts = {}) {
|
|
|
41223
41561
|
const settle = () => {
|
|
41224
41562
|
if (timer) clearTimeout(timer);
|
|
41225
41563
|
timer = setTimeout(() => {
|
|
41226
|
-
if (
|
|
41564
|
+
if (existsSync12(join17(gitDir, "index.lock"))) {
|
|
41227
41565
|
settle();
|
|
41228
41566
|
return;
|
|
41229
41567
|
}
|
|
@@ -41234,7 +41572,7 @@ function startGitSensor(gitDir, onEvent, opts = {}) {
|
|
|
41234
41572
|
}, debounceMs);
|
|
41235
41573
|
};
|
|
41236
41574
|
for (const sub of ["HEAD", "logs/HEAD", "MERGE_HEAD", "ORIG_HEAD"]) {
|
|
41237
|
-
const p =
|
|
41575
|
+
const p = join17(gitDir, sub);
|
|
41238
41576
|
try {
|
|
41239
41577
|
watchers.push(fsWatch(p, settle));
|
|
41240
41578
|
} catch {
|
|
@@ -41459,21 +41797,21 @@ var TelemetryRecorder = class {
|
|
|
41459
41797
|
|
|
41460
41798
|
// src/skills.ts
|
|
41461
41799
|
import {
|
|
41462
|
-
existsSync as
|
|
41800
|
+
existsSync as existsSync13,
|
|
41463
41801
|
mkdirSync as mkdirSync5,
|
|
41464
|
-
readFileSync as
|
|
41802
|
+
readFileSync as readFileSync12,
|
|
41465
41803
|
readdirSync as readdirSync6,
|
|
41466
41804
|
unlinkSync as unlinkSync2,
|
|
41467
|
-
writeFileSync as
|
|
41805
|
+
writeFileSync as writeFileSync10
|
|
41468
41806
|
} from "node:fs";
|
|
41469
|
-
import { basename as basename4, join as
|
|
41807
|
+
import { basename as basename4, join as join18 } from "node:path";
|
|
41470
41808
|
function skillFileName(id) {
|
|
41471
41809
|
return `${id.replace(/[^A-Za-z0-9_.-]/g, "_")}.md`;
|
|
41472
41810
|
}
|
|
41473
41811
|
function readSkillManifest(manifestPath) {
|
|
41474
|
-
if (!
|
|
41812
|
+
if (!existsSync13(manifestPath)) return [];
|
|
41475
41813
|
try {
|
|
41476
|
-
const parsed = JSON.parse(
|
|
41814
|
+
const parsed = JSON.parse(readFileSync12(manifestPath, "utf8"));
|
|
41477
41815
|
return (parsed.skills ?? []).map((s) => ({
|
|
41478
41816
|
title: s.title ?? "",
|
|
41479
41817
|
layer: s.layer ?? "technique",
|
|
@@ -41496,7 +41834,7 @@ async function syncSkills(paths, client, seed) {
|
|
|
41496
41834
|
for (const s of res.skills) {
|
|
41497
41835
|
const fileName = skillFileName(s.id);
|
|
41498
41836
|
keep.add(fileName);
|
|
41499
|
-
|
|
41837
|
+
writeFileSync10(join18(paths.skillsDir, fileName), s.markdown, "utf8");
|
|
41500
41838
|
rows.push({
|
|
41501
41839
|
id: s.id,
|
|
41502
41840
|
title: s.title,
|
|
@@ -41510,13 +41848,13 @@ async function syncSkills(paths, client, seed) {
|
|
|
41510
41848
|
if (!f.endsWith(".md")) continue;
|
|
41511
41849
|
if (keep.has(basename4(f))) continue;
|
|
41512
41850
|
try {
|
|
41513
|
-
unlinkSync2(
|
|
41851
|
+
unlinkSync2(join18(paths.skillsDir, f));
|
|
41514
41852
|
pruned++;
|
|
41515
41853
|
} catch {
|
|
41516
41854
|
}
|
|
41517
41855
|
}
|
|
41518
41856
|
rows.sort((a, b) => a.id.localeCompare(b.id));
|
|
41519
|
-
|
|
41857
|
+
writeFileSync10(
|
|
41520
41858
|
paths.skillsManifest,
|
|
41521
41859
|
JSON.stringify({ generatedAt: Date.now(), skills: rows }, null, 2),
|
|
41522
41860
|
"utf8"
|
|
@@ -41653,30 +41991,30 @@ var CausalBuffer = class {
|
|
|
41653
41991
|
// src/profile.ts
|
|
41654
41992
|
init_src2();
|
|
41655
41993
|
init_paths();
|
|
41656
|
-
import { existsSync as
|
|
41994
|
+
import { existsSync as existsSync14, readFileSync as readFileSync13, writeFileSync as writeFileSync11 } from "node:fs";
|
|
41657
41995
|
import { createHash as createHash12 } from "node:crypto";
|
|
41658
|
-
import { join as
|
|
41996
|
+
import { join as join19 } from "node:path";
|
|
41659
41997
|
function workspaceId(root) {
|
|
41660
41998
|
return "wp_" + createHash12("sha256").update(root).digest("hex").slice(0, 12);
|
|
41661
41999
|
}
|
|
41662
42000
|
function loadProfile(root) {
|
|
41663
42001
|
const p = workspacePaths(root);
|
|
41664
|
-
if (!
|
|
41665
|
-
return JSON.parse(
|
|
42002
|
+
if (!existsSync14(p.workspaceJson)) return null;
|
|
42003
|
+
return JSON.parse(readFileSync13(p.workspaceJson, "utf8"));
|
|
41666
42004
|
}
|
|
41667
42005
|
function saveProfile(root, profile) {
|
|
41668
42006
|
const p = workspacePaths(root);
|
|
41669
42007
|
ensureDir(p.configDir);
|
|
41670
|
-
|
|
42008
|
+
writeFileSync11(p.workspaceJson, JSON.stringify(profile, null, 2), "utf8");
|
|
41671
42009
|
}
|
|
41672
42010
|
function autodetectProfile(root) {
|
|
41673
42011
|
const id = workspaceId(root);
|
|
41674
42012
|
const name2 = root.split(/[\\/]/).filter(Boolean).pop() ?? "workspace";
|
|
41675
42013
|
const p = emptyProfile(id, name2);
|
|
41676
|
-
const pkgPath =
|
|
41677
|
-
if (
|
|
42014
|
+
const pkgPath = join19(root, "package.json");
|
|
42015
|
+
if (existsSync14(pkgPath)) {
|
|
41678
42016
|
try {
|
|
41679
|
-
const pkg = JSON.parse(
|
|
42017
|
+
const pkg = JSON.parse(readFileSync13(pkgPath, "utf8"));
|
|
41680
42018
|
p.languages.push("typescript", "javascript");
|
|
41681
42019
|
const nodeVer = pkg.engines?.node ?? "node";
|
|
41682
42020
|
p.stack.push(`node@${nodeVer}`);
|
|
@@ -41697,10 +42035,10 @@ function autodetectProfile(root) {
|
|
|
41697
42035
|
} catch {
|
|
41698
42036
|
}
|
|
41699
42037
|
}
|
|
41700
|
-
const pyproject =
|
|
41701
|
-
if (
|
|
42038
|
+
const pyproject = join19(root, "pyproject.toml");
|
|
42039
|
+
if (existsSync14(pyproject)) {
|
|
41702
42040
|
try {
|
|
41703
|
-
const txt =
|
|
42041
|
+
const txt = readFileSync13(pyproject, "utf8");
|
|
41704
42042
|
const py = /python\s*=\s*"([^"]+)"/.exec(txt)?.[1];
|
|
41705
42043
|
p.languages.push("python");
|
|
41706
42044
|
p.stack.push(`python@${py ?? "3"}`);
|
|
@@ -41711,16 +42049,16 @@ function autodetectProfile(root) {
|
|
|
41711
42049
|
} catch {
|
|
41712
42050
|
}
|
|
41713
42051
|
}
|
|
41714
|
-
const reqs =
|
|
41715
|
-
if (
|
|
42052
|
+
const reqs = join19(root, "requirements.txt");
|
|
42053
|
+
if (existsSync14(reqs)) {
|
|
41716
42054
|
if (!p.languages.includes("python")) p.languages.push("python");
|
|
41717
42055
|
if (!p.stack.includes("python@3")) p.stack.push("python@3");
|
|
41718
42056
|
}
|
|
41719
|
-
if (
|
|
42057
|
+
if (existsSync14(join19(root, "go.mod"))) {
|
|
41720
42058
|
p.languages.push("go");
|
|
41721
42059
|
p.stack.push("go");
|
|
41722
42060
|
}
|
|
41723
|
-
if (
|
|
42061
|
+
if (existsSync14(join19(root, "Cargo.toml"))) {
|
|
41724
42062
|
p.languages.push("rust");
|
|
41725
42063
|
p.stack.push("rust");
|
|
41726
42064
|
}
|
|
@@ -41878,7 +42216,7 @@ function startLoopLagMonitor(thresholdMs = 1e3) {
|
|
|
41878
42216
|
}
|
|
41879
42217
|
|
|
41880
42218
|
// src/engine.ts
|
|
41881
|
-
var DAEMON_VERSION = true ? "2.0.0-dev.
|
|
42219
|
+
var DAEMON_VERSION = true ? "2.0.0-dev.36" : "2.0.0-alpha.0";
|
|
41882
42220
|
var IGNORED_PATH = /[\\/](?:\.git|node_modules|\.errata|\.claude|\.codex|\.cursor|\.turbo|\.next|dist|coverage|test-results|playwright-report|__pycache__)(?:[\\/]|$)/;
|
|
41883
42221
|
var IGNORED_NOISE = /castalia\.db|eventlog\.sqlite|turn-cursors/;
|
|
41884
42222
|
var GIT_OP_MUTE_MS = 4e3;
|
|
@@ -41888,7 +42226,7 @@ var TURN_REPLAY_LOOKBACK_MS = 7 * 24 * 60 * 6e4;
|
|
|
41888
42226
|
function appendIdentityAudit(path2, record2, line) {
|
|
41889
42227
|
if (!record2.accepted && record2.score <= 0) return;
|
|
41890
42228
|
try {
|
|
41891
|
-
if (
|
|
42229
|
+
if (existsSync15(path2) && statSync4(path2).size >= IDENTITY_AUDIT_MAX_BYTES) {
|
|
41892
42230
|
renameSync2(path2, `${path2}.1`);
|
|
41893
42231
|
}
|
|
41894
42232
|
appendFileSync2(path2, line);
|
|
@@ -41898,14 +42236,14 @@ function appendIdentityAudit(path2, record2, line) {
|
|
|
41898
42236
|
var yieldToLoop = () => new Promise((r) => setImmediate(r));
|
|
41899
42237
|
function loadTurnCursors(path2) {
|
|
41900
42238
|
try {
|
|
41901
|
-
return new Map(Object.entries(JSON.parse(
|
|
42239
|
+
return new Map(Object.entries(JSON.parse(readFileSync14(path2, "utf8"))));
|
|
41902
42240
|
} catch {
|
|
41903
42241
|
return /* @__PURE__ */ new Map();
|
|
41904
42242
|
}
|
|
41905
42243
|
}
|
|
41906
42244
|
function saveTurnCursors(path2, cursors) {
|
|
41907
42245
|
try {
|
|
41908
|
-
|
|
42246
|
+
writeFileSync12(path2, JSON.stringify(Object.fromEntries(cursors)), "utf8");
|
|
41909
42247
|
} catch {
|
|
41910
42248
|
}
|
|
41911
42249
|
}
|
|
@@ -41927,7 +42265,7 @@ function gitSourceWatchTargets(root) {
|
|
|
41927
42265
|
["-C", root, "ls-files", "--others", "--ignored", "--exclude-standard", "--directory", "-z"],
|
|
41928
42266
|
{ encoding: "utf8", maxBuffer: 256 * 1024 * 1024, windowsHide: true, stdio: ["ignore", "pipe", "ignore"] }
|
|
41929
42267
|
);
|
|
41930
|
-
ignoredDirs = igOut.split("\0").filter(Boolean).map((d) => d.replace(/\/+$/, "")).filter((d) => !IGNORED_PATH.test(
|
|
42268
|
+
ignoredDirs = igOut.split("\0").filter(Boolean).map((d) => d.replace(/\/+$/, "")).filter((d) => !IGNORED_PATH.test(join20(root, d) + sep4));
|
|
41931
42269
|
} catch {
|
|
41932
42270
|
}
|
|
41933
42271
|
const hasIgnoredChild = (dir) => ignoredDirs.some((ig) => ig.startsWith(dir + "/"));
|
|
@@ -41939,19 +42277,19 @@ function gitSourceWatchTargets(root) {
|
|
|
41939
42277
|
if (!f.startsWith(prefix)) continue;
|
|
41940
42278
|
const rest2 = f.slice(prefix.length);
|
|
41941
42279
|
if (rest2.includes("/")) children.add(dir === "" ? rest2.slice(0, rest2.indexOf("/")) : dir + "/" + rest2.slice(0, rest2.indexOf("/")));
|
|
41942
|
-
else targets.add(
|
|
42280
|
+
else targets.add(join20(root, f));
|
|
41943
42281
|
}
|
|
41944
42282
|
for (const c of children) {
|
|
41945
|
-
if (IGNORED_PATH.test(
|
|
42283
|
+
if (IGNORED_PATH.test(join20(root, c) + sep4)) continue;
|
|
41946
42284
|
if (hasIgnoredChild(c)) addUnder(c);
|
|
41947
|
-
else targets.add(
|
|
42285
|
+
else targets.add(join20(root, c));
|
|
41948
42286
|
}
|
|
41949
42287
|
};
|
|
41950
42288
|
addUnder("");
|
|
41951
42289
|
if (targets.size > 0) return [...targets];
|
|
41952
42290
|
} catch {
|
|
41953
42291
|
}
|
|
41954
|
-
return readdirSync7(root, { withFileTypes: true }).filter((e) => e.isDirectory() && !IGNORED_PATH.test(
|
|
42292
|
+
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)));
|
|
41955
42293
|
}
|
|
41956
42294
|
function createWorkspaceEngine(opts) {
|
|
41957
42295
|
const paths = workspacePaths(opts.workspaceRoot);
|
|
@@ -42103,7 +42441,7 @@ function createWorkspaceEngine(opts) {
|
|
|
42103
42441
|
const srcPaths = diff.changedPaths.filter((p) => /\.(ts|tsx|js|jsx|mjs|cjs|py)$/i.test(p));
|
|
42104
42442
|
let episodeId2;
|
|
42105
42443
|
if (srcPaths.length > 0) {
|
|
42106
|
-
const abs = srcPaths.map((p) =>
|
|
42444
|
+
const abs = srcPaths.map((p) => join20(opts.workspaceRoot, p));
|
|
42107
42445
|
try {
|
|
42108
42446
|
const r = await runReindexPass(
|
|
42109
42447
|
`git-reindex:${profile.name} (${abs.length} files)`,
|
|
@@ -42134,8 +42472,8 @@ function createWorkspaceEngine(opts) {
|
|
|
42134
42472
|
`[errata] git: ${ev.kind} ${ev.newSha.slice(0, 7)} by ${meta3.authorName} \u2014 ${diff.changedPaths.length} file(s), ${diff.renames.length} rename(s)`
|
|
42135
42473
|
);
|
|
42136
42474
|
};
|
|
42137
|
-
const gitDir =
|
|
42138
|
-
if (
|
|
42475
|
+
const gitDir = join20(opts.workspaceRoot, ".git");
|
|
42476
|
+
if (existsSync15(gitDir)) {
|
|
42139
42477
|
stopGit = startGitSensor(gitDir, (ev) => {
|
|
42140
42478
|
void handleGitEvent(ev);
|
|
42141
42479
|
});
|
|
@@ -42191,18 +42529,20 @@ function createWorkspaceEngine(opts) {
|
|
|
42191
42529
|
};
|
|
42192
42530
|
const prebuilt = passWorker ? await passWorker.snapshot(snapOpts).catch(() => null) : null;
|
|
42193
42531
|
const doneRender = prebuilt ? null : markPass(`context-render-inline:${profile.name}`);
|
|
42532
|
+
const pendingUpdate = opts.pendingUpdate?.() ?? null;
|
|
42194
42533
|
const { body: body2, snapshot } = assembleAgentContext({
|
|
42195
42534
|
store,
|
|
42196
42535
|
...snapOpts,
|
|
42197
42536
|
remote: remotePriors,
|
|
42198
42537
|
...elicit ? { edgeElicitation: { instruction: PRIOR_TAG_INSTRUCTION } } : {},
|
|
42199
|
-
...prebuilt ? { snapshot: prebuilt } : {}
|
|
42538
|
+
...prebuilt ? { snapshot: prebuilt } : {},
|
|
42539
|
+
...pendingUpdate ? { pendingUpdate } : {}
|
|
42200
42540
|
});
|
|
42201
42541
|
doneRender?.();
|
|
42202
|
-
const target =
|
|
42542
|
+
const target = join20(opts.workspaceRoot, "AGENTS.md");
|
|
42203
42543
|
writeManagedBlock(target, { body: body2 });
|
|
42204
42544
|
if (elicit) {
|
|
42205
|
-
writePrimingHandles(
|
|
42545
|
+
writePrimingHandles(join20(paths.configDir, "priming-handles.json"), [
|
|
42206
42546
|
...snapshot.recentProblems.map((r) => r.node),
|
|
42207
42547
|
// Resolved-band handles: the ✓ problem AND its Solution are citable
|
|
42208
42548
|
// (a fix tag on an already-resolved problem no-ops idempotently; the
|
|
@@ -42372,7 +42712,7 @@ function createWorkspaceEngine(opts) {
|
|
|
42372
42712
|
resultSummary: { exitCode: e.exitCode ?? 1, errorTokens: e.errorTokens }
|
|
42373
42713
|
});
|
|
42374
42714
|
};
|
|
42375
|
-
const turnCursorPath =
|
|
42715
|
+
const turnCursorPath = join20(paths.configDir, "turn-cursors.json");
|
|
42376
42716
|
const lastTurnUuid = loadTurnCursors(turnCursorPath);
|
|
42377
42717
|
const sessionLastProblem = /* @__PURE__ */ new Map();
|
|
42378
42718
|
const sessionThreads = /* @__PURE__ */ new Map();
|
|
@@ -42395,7 +42735,7 @@ function createWorkspaceEngine(opts) {
|
|
|
42395
42735
|
const t = Date.now();
|
|
42396
42736
|
let processedTurns = 0;
|
|
42397
42737
|
const elicit = isEdgeElicitationEnabled();
|
|
42398
|
-
const handleMap = elicit ? readPrimingHandles(
|
|
42738
|
+
const handleMap = elicit ? readPrimingHandles(join20(paths.configDir, "priming-handles.json")) : {};
|
|
42399
42739
|
const wsRoot = (opts.workspaceRoot ?? "").replace(/\\/g, "/");
|
|
42400
42740
|
const toRel = (abs) => {
|
|
42401
42741
|
const p = abs.replace(/\\/g, "/");
|
|
@@ -42864,6 +43204,10 @@ function createWorkspaceEngine(opts) {
|
|
|
42864
43204
|
emitEvent(ev) {
|
|
42865
43205
|
log.append(ev);
|
|
42866
43206
|
},
|
|
43207
|
+
markContextDirty() {
|
|
43208
|
+
contextDirty = true;
|
|
43209
|
+
refreshContextNow();
|
|
43210
|
+
},
|
|
42867
43211
|
async tick() {
|
|
42868
43212
|
maybeRefreshRemotePriors();
|
|
42869
43213
|
const report = {
|
|
@@ -42908,7 +43252,21 @@ function createWorkspaceEngine(opts) {
|
|
|
42908
43252
|
return report;
|
|
42909
43253
|
},
|
|
42910
43254
|
async nightly() {
|
|
42911
|
-
|
|
43255
|
+
const report = (await runNightly()).report;
|
|
43256
|
+
const summarizer = opts.intentSummarizer ?? envIntentSummarizer();
|
|
43257
|
+
if (summarizer) {
|
|
43258
|
+
try {
|
|
43259
|
+
const s = await runSymbolSummarySweep(store, opts.workspaceRoot, paths.configDir, summarizer);
|
|
43260
|
+
if (s.generated > 0 || s.rejected > 0) {
|
|
43261
|
+
console.log(
|
|
43262
|
+
`[errata] symbol summaries: +${s.generated}${s.rejected > 0 ? ` (${s.rejected} rejected by no-verbatim check)` : ""}${s.remaining > 0 ? `, ${s.remaining} pending` : ""}`
|
|
43263
|
+
);
|
|
43264
|
+
}
|
|
43265
|
+
} catch (err2) {
|
|
43266
|
+
console.warn("[errata] symbol summary sweep failed:", err2 instanceof Error ? err2.message : err2);
|
|
43267
|
+
}
|
|
43268
|
+
}
|
|
43269
|
+
return report;
|
|
42912
43270
|
},
|
|
42913
43271
|
async embedSettled() {
|
|
42914
43272
|
try {
|
|
@@ -42996,7 +43354,7 @@ function createWorkspaceEngine(opts) {
|
|
|
42996
43354
|
console.log(
|
|
42997
43355
|
"[errata] sync skipped \u2014 cloud sync consent is off (enable with `errata consent sync on`)"
|
|
42998
43356
|
);
|
|
42999
|
-
const pending =
|
|
43357
|
+
const pending = existsSync15(paths.outbox) ? readdirSync7(paths.outbox).filter((f) => f.endsWith(".json")).length : 0;
|
|
43000
43358
|
return { uploaded: 0, failed: 0, remaining: pending };
|
|
43001
43359
|
}
|
|
43002
43360
|
try {
|
|
@@ -43083,7 +43441,7 @@ async function startDaemon(opts) {
|
|
|
43083
43441
|
reviewUrl: () => webUiUrl + "/review"
|
|
43084
43442
|
});
|
|
43085
43443
|
const writeLockFile = (url2) => {
|
|
43086
|
-
|
|
43444
|
+
writeFileSync13(
|
|
43087
43445
|
engine.paths.daemonLock,
|
|
43088
43446
|
JSON.stringify({ pid: process.pid, webUiUrl: url2, startedAt: Date.now() }),
|
|
43089
43447
|
"utf8"
|
|
@@ -43126,7 +43484,7 @@ async function startDaemon(opts) {
|
|
|
43126
43484
|
);
|
|
43127
43485
|
await engine.stop();
|
|
43128
43486
|
try {
|
|
43129
|
-
if (
|
|
43487
|
+
if (existsSync16(engine.paths.daemonLock)) {
|
|
43130
43488
|
}
|
|
43131
43489
|
} catch {
|
|
43132
43490
|
}
|
|
@@ -43143,16 +43501,16 @@ async function listenServer(fetchFn, port) {
|
|
|
43143
43501
|
|
|
43144
43502
|
// src/registry.ts
|
|
43145
43503
|
init_paths();
|
|
43146
|
-
import { existsSync as
|
|
43147
|
-
import { join as
|
|
43504
|
+
import { existsSync as existsSync17, readFileSync as readFileSync15, writeFileSync as writeFileSync14 } from "node:fs";
|
|
43505
|
+
import { join as join21 } from "node:path";
|
|
43148
43506
|
function registryPath() {
|
|
43149
|
-
return process.env["ERRATA_REGISTRY_PATH"] ??
|
|
43507
|
+
return process.env["ERRATA_REGISTRY_PATH"] ?? join21(globalDir(), "workspaces.json");
|
|
43150
43508
|
}
|
|
43151
43509
|
function read() {
|
|
43152
43510
|
const p = registryPath();
|
|
43153
|
-
if (!
|
|
43511
|
+
if (!existsSync17(p)) return { version: 1, workspaces: {} };
|
|
43154
43512
|
try {
|
|
43155
|
-
const parsed = JSON.parse(
|
|
43513
|
+
const parsed = JSON.parse(readFileSync15(p, "utf8"));
|
|
43156
43514
|
return { version: 1, workspaces: parsed.workspaces ?? {} };
|
|
43157
43515
|
} catch {
|
|
43158
43516
|
return { version: 1, workspaces: {} };
|
|
@@ -43160,7 +43518,7 @@ function read() {
|
|
|
43160
43518
|
}
|
|
43161
43519
|
function write(reg) {
|
|
43162
43520
|
ensureDir(globalDir());
|
|
43163
|
-
|
|
43521
|
+
writeFileSync14(registryPath(), JSON.stringify(reg, null, 2), "utf8");
|
|
43164
43522
|
}
|
|
43165
43523
|
function registerWorkspace(profile, root, now = Date.now()) {
|
|
43166
43524
|
const reg = read();
|
|
@@ -43177,7 +43535,7 @@ function pruneMissingWorkspaces() {
|
|
|
43177
43535
|
const reg = read();
|
|
43178
43536
|
const removed = [];
|
|
43179
43537
|
for (const [id, entry] of Object.entries(reg.workspaces)) {
|
|
43180
|
-
if (!
|
|
43538
|
+
if (!existsSync17(entry.path)) {
|
|
43181
43539
|
removed.push(entry);
|
|
43182
43540
|
delete reg.workspaces[id];
|
|
43183
43541
|
}
|
|
@@ -43186,13 +43544,13 @@ function pruneMissingWorkspaces() {
|
|
|
43186
43544
|
return removed;
|
|
43187
43545
|
}
|
|
43188
43546
|
function workspaceStatus(entry) {
|
|
43189
|
-
const missing = !
|
|
43547
|
+
const missing = !existsSync17(entry.path);
|
|
43190
43548
|
const lockPath = workspacePaths(entry.path).daemonLock;
|
|
43191
43549
|
let running = false;
|
|
43192
43550
|
let webUiUrl = null;
|
|
43193
|
-
if (
|
|
43551
|
+
if (existsSync17(lockPath)) {
|
|
43194
43552
|
try {
|
|
43195
|
-
const lock = JSON.parse(
|
|
43553
|
+
const lock = JSON.parse(readFileSync15(lockPath, "utf8"));
|
|
43196
43554
|
if (lock.pid && lock.webUiUrl && pidAlive(lock.pid)) {
|
|
43197
43555
|
running = true;
|
|
43198
43556
|
webUiUrl = lock.webUiUrl;
|
|
@@ -43220,7 +43578,7 @@ function pidAlive(pid) {
|
|
|
43220
43578
|
// src/multi.ts
|
|
43221
43579
|
init_dist();
|
|
43222
43580
|
init_src4();
|
|
43223
|
-
import { readFileSync as
|
|
43581
|
+
import { readFileSync as readFileSync18, unlinkSync as unlinkSync3, writeFileSync as writeFileSync15 } from "node:fs";
|
|
43224
43582
|
|
|
43225
43583
|
// src/principle-sync.ts
|
|
43226
43584
|
init_src4();
|
|
@@ -43247,8 +43605,8 @@ async function syncPrinciples(store, cloud, opts) {
|
|
|
43247
43605
|
init_reconcile();
|
|
43248
43606
|
|
|
43249
43607
|
// src/lockfile-auto.ts
|
|
43250
|
-
import { existsSync as
|
|
43251
|
-
import { join as
|
|
43608
|
+
import { existsSync as existsSync18, readFileSync as readFileSync16 } from "node:fs";
|
|
43609
|
+
import { join as join22 } from "node:path";
|
|
43252
43610
|
|
|
43253
43611
|
// src/package-index.ts
|
|
43254
43612
|
init_src();
|
|
@@ -43512,11 +43870,11 @@ function runLockfilePass(opts) {
|
|
|
43512
43870
|
{ file: "package-lock.json", parse: parsePackageLockJson }
|
|
43513
43871
|
];
|
|
43514
43872
|
for (const c of candidates) {
|
|
43515
|
-
const p =
|
|
43516
|
-
if (!
|
|
43873
|
+
const p = join22(opts.root, c.file);
|
|
43874
|
+
if (!existsSync18(p)) continue;
|
|
43517
43875
|
let sbom;
|
|
43518
43876
|
try {
|
|
43519
|
-
sbom = c.parse(
|
|
43877
|
+
sbom = c.parse(readFileSync16(p, "utf8"));
|
|
43520
43878
|
} catch {
|
|
43521
43879
|
continue;
|
|
43522
43880
|
}
|
|
@@ -43671,6 +44029,27 @@ function buildInstanceIngest(store, profile, daemonVersion, ignorePatterns = [],
|
|
|
43671
44029
|
}
|
|
43672
44030
|
}
|
|
43673
44031
|
if (nodes.length === 0 && anchorEdges.length === 0) return null;
|
|
44032
|
+
let symbolSummaries;
|
|
44033
|
+
if (opts.lexicon && opts.lexicon.size > 0 && nodes.length > 0) {
|
|
44034
|
+
const lexicon = opts.lexicon;
|
|
44035
|
+
const isKnown = (tok) => lexicon.has(tok);
|
|
44036
|
+
const sidecar = {};
|
|
44037
|
+
let count = 0;
|
|
44038
|
+
outer: for (const n of nodes) {
|
|
44039
|
+
if (!INSTANCE_LABELS.includes(n.label)) continue;
|
|
44040
|
+
for (const tok of extractIdentifierTokens(n.description)) {
|
|
44041
|
+
if (sidecar[tok]) continue;
|
|
44042
|
+
const entry = lexicon.get(tok);
|
|
44043
|
+
if (!entry?.summary) continue;
|
|
44044
|
+
const scrubbed = generalize(entry.summary, { level }).text.trim();
|
|
44045
|
+
if (!scrubbed || summaryRejectionReason(scrubbed, isKnown) !== null) continue;
|
|
44046
|
+
if (count >= MAX_SIDECAR_SYMBOLS) break outer;
|
|
44047
|
+
sidecar[tok] = { kind: entry.kind, summary: scrubbed };
|
|
44048
|
+
count++;
|
|
44049
|
+
}
|
|
44050
|
+
}
|
|
44051
|
+
if (count > 0) symbolSummaries = sidecar;
|
|
44052
|
+
}
|
|
43674
44053
|
const edges = [];
|
|
43675
44054
|
for (const id of seen) {
|
|
43676
44055
|
for (const e of store.outEdges(id, [...INSTANCE_EDGES])) {
|
|
@@ -43685,12 +44064,17 @@ function buildInstanceIngest(store, profile, daemonVersion, ignorePatterns = [],
|
|
|
43685
44064
|
// co-locates the few Language/Package stubs with the first instance chunk,
|
|
43686
44065
|
// maximizing in-payload endpoint resolution.
|
|
43687
44066
|
nodes: [...contextNodes, ...nodes],
|
|
43688
|
-
edges
|
|
44067
|
+
edges,
|
|
44068
|
+
// Spread-if-present: an absent sidecar keeps `base` — and therefore the
|
|
44069
|
+
// payloadDigest — byte-identical to the pre-sidecar batch (backward compat).
|
|
44070
|
+
...symbolSummaries ? { symbolSummaries } : {}
|
|
43689
44071
|
};
|
|
43690
44072
|
return { ...base, payloadDigest: digest(base), anchorDigests };
|
|
43691
44073
|
}
|
|
43692
44074
|
|
|
43693
44075
|
// src/multi.ts
|
|
44076
|
+
init_generalize_graph();
|
|
44077
|
+
init_symbol_summaries();
|
|
43694
44078
|
init_webui();
|
|
43695
44079
|
|
|
43696
44080
|
// src/consolidate-worker-client.ts
|
|
@@ -43766,7 +44150,7 @@ var ConsolidateWorker = class {
|
|
|
43766
44150
|
init_paths();
|
|
43767
44151
|
|
|
43768
44152
|
// src/lock.ts
|
|
43769
|
-
import { existsSync as
|
|
44153
|
+
import { existsSync as existsSync19, readFileSync as readFileSync17 } from "node:fs";
|
|
43770
44154
|
function isProcessAlive(pid) {
|
|
43771
44155
|
if (!pid || pid <= 0) return false;
|
|
43772
44156
|
try {
|
|
@@ -43777,9 +44161,9 @@ function isProcessAlive(pid) {
|
|
|
43777
44161
|
}
|
|
43778
44162
|
}
|
|
43779
44163
|
function readDaemonLock(lockPath) {
|
|
43780
|
-
if (!
|
|
44164
|
+
if (!existsSync19(lockPath)) return null;
|
|
43781
44165
|
try {
|
|
43782
|
-
const lock = JSON.parse(
|
|
44166
|
+
const lock = JSON.parse(readFileSync17(lockPath, "utf8"));
|
|
43783
44167
|
return typeof lock.pid === "number" ? lock : null;
|
|
43784
44168
|
} catch {
|
|
43785
44169
|
return null;
|
|
@@ -43792,6 +44176,90 @@ function isDaemonAlive(lockPath) {
|
|
|
43792
44176
|
|
|
43793
44177
|
// src/multi.ts
|
|
43794
44178
|
init_config();
|
|
44179
|
+
|
|
44180
|
+
// src/update.ts
|
|
44181
|
+
import { spawn as spawn2 } from "node:child_process";
|
|
44182
|
+
var PACKAGE_NAME = "@inerrata-corporation/errata";
|
|
44183
|
+
async function latestPublished(channel, timeoutMs = 4e3) {
|
|
44184
|
+
const ctrl = new AbortController();
|
|
44185
|
+
const timer = setTimeout(() => ctrl.abort(), timeoutMs);
|
|
44186
|
+
try {
|
|
44187
|
+
const res = await fetch(`https://registry.npmjs.org/${PACKAGE_NAME}`, {
|
|
44188
|
+
headers: { accept: "application/vnd.npm.install-v1+json" },
|
|
44189
|
+
signal: ctrl.signal
|
|
44190
|
+
});
|
|
44191
|
+
if (!res.ok) return null;
|
|
44192
|
+
const body2 = await res.json();
|
|
44193
|
+
return body2["dist-tags"]?.[channel] ?? null;
|
|
44194
|
+
} catch {
|
|
44195
|
+
return null;
|
|
44196
|
+
} finally {
|
|
44197
|
+
clearTimeout(timer);
|
|
44198
|
+
}
|
|
44199
|
+
}
|
|
44200
|
+
async function checkForUpdate(channel) {
|
|
44201
|
+
const latest = await latestPublished(channel);
|
|
44202
|
+
return {
|
|
44203
|
+
current: DAEMON_VERSION,
|
|
44204
|
+
latest,
|
|
44205
|
+
updateAvailable: latest !== null && latest !== DAEMON_VERSION
|
|
44206
|
+
};
|
|
44207
|
+
}
|
|
44208
|
+
var POLL_INTERVAL_MS = {
|
|
44209
|
+
dev: 6 * 60 * 6e4,
|
|
44210
|
+
latest: 24 * 60 * 6e4
|
|
44211
|
+
};
|
|
44212
|
+
function startUpdatePoller(opts) {
|
|
44213
|
+
const check2 = opts.check ?? (() => checkForUpdate(opts.channel));
|
|
44214
|
+
const base = opts.intervalMs ?? POLL_INTERVAL_MS[opts.channel];
|
|
44215
|
+
let pending = null;
|
|
44216
|
+
let inFlight = false;
|
|
44217
|
+
let timer = null;
|
|
44218
|
+
let stopped = false;
|
|
44219
|
+
const runOnce = async () => {
|
|
44220
|
+
if (inFlight) return;
|
|
44221
|
+
inFlight = true;
|
|
44222
|
+
try {
|
|
44223
|
+
const status = await check2();
|
|
44224
|
+
if (status.latest === null) return;
|
|
44225
|
+
const next = status.updateAvailable ? { current: status.current, latest: status.latest, channel: opts.channel } : null;
|
|
44226
|
+
const changed = (next?.latest ?? null) !== (pending?.latest ?? null);
|
|
44227
|
+
pending = next;
|
|
44228
|
+
if (changed) opts.onChange?.(pending);
|
|
44229
|
+
} catch {
|
|
44230
|
+
} finally {
|
|
44231
|
+
inFlight = false;
|
|
44232
|
+
}
|
|
44233
|
+
};
|
|
44234
|
+
const schedule = () => {
|
|
44235
|
+
if (stopped) return;
|
|
44236
|
+
const jitter = 1 + (Math.random() - 0.5) * 0.2;
|
|
44237
|
+
timer = setTimeout(() => {
|
|
44238
|
+
void runOnce().finally(schedule);
|
|
44239
|
+
}, base * jitter);
|
|
44240
|
+
timer.unref?.();
|
|
44241
|
+
};
|
|
44242
|
+
void runOnce().finally(schedule);
|
|
44243
|
+
return {
|
|
44244
|
+
current: () => pending,
|
|
44245
|
+
stop: () => {
|
|
44246
|
+
stopped = true;
|
|
44247
|
+
if (timer) clearTimeout(timer);
|
|
44248
|
+
}
|
|
44249
|
+
};
|
|
44250
|
+
}
|
|
44251
|
+
function runNpmInstall(channel) {
|
|
44252
|
+
return new Promise((resolve5) => {
|
|
44253
|
+
const child = spawn2("npm", ["install", "-g", `${PACKAGE_NAME}@${channel}`], {
|
|
44254
|
+
stdio: "inherit",
|
|
44255
|
+
shell: true
|
|
44256
|
+
});
|
|
44257
|
+
child.on("close", (code) => resolve5(code ?? 1));
|
|
44258
|
+
child.on("error", () => resolve5(1));
|
|
44259
|
+
});
|
|
44260
|
+
}
|
|
44261
|
+
|
|
44262
|
+
// src/multi.ts
|
|
43795
44263
|
init_cloud_endpoint_policy();
|
|
43796
44264
|
init_cloud_auth();
|
|
43797
44265
|
function normPath(p) {
|
|
@@ -43858,6 +44326,15 @@ async function startMultiDaemon(opts = {}) {
|
|
|
43858
44326
|
startLoopLagMonitor();
|
|
43859
44327
|
let baseUrl = "";
|
|
43860
44328
|
const records = [];
|
|
44329
|
+
const updatePoller = opts.updateCheck ? startUpdatePoller({
|
|
44330
|
+
channel: loadConfig().updateChannel,
|
|
44331
|
+
onChange: (pending) => {
|
|
44332
|
+
if (pending) {
|
|
44333
|
+
console.log(`\u26A1 errata update available: ${pending.current} \u2192 ${pending.latest} \u2014 run: errata update`);
|
|
44334
|
+
}
|
|
44335
|
+
for (const r of records) r.engine.markContextDirty();
|
|
44336
|
+
}
|
|
44337
|
+
}) : null;
|
|
43861
44338
|
const boundaryListeners = [];
|
|
43862
44339
|
let boundaryFlushing = false;
|
|
43863
44340
|
const fireBoundary = () => {
|
|
@@ -43876,6 +44353,7 @@ async function startMultiDaemon(opts = {}) {
|
|
|
43876
44353
|
apiKey: opts.apiKey,
|
|
43877
44354
|
reviewUrl: () => `${baseUrl}/ws/${id}/review`,
|
|
43878
44355
|
sharedStore,
|
|
44356
|
+
pendingUpdate: () => updatePoller?.current() ?? null,
|
|
43879
44357
|
...opts.skipWatchers ? { skipWatchers: true } : {}
|
|
43880
44358
|
});
|
|
43881
44359
|
const webApp = buildWebUi({
|
|
@@ -43933,7 +44411,7 @@ async function startMultiDaemon(opts = {}) {
|
|
|
43933
44411
|
records.push(rec);
|
|
43934
44412
|
app.route(`/ws/${rec.id}`, rec.webApp);
|
|
43935
44413
|
try {
|
|
43936
|
-
|
|
44414
|
+
writeFileSync15(
|
|
43937
44415
|
rec.engine.paths.daemonLock,
|
|
43938
44416
|
JSON.stringify({ pid: process.pid, webUiUrl: `${baseUrl}/ws/${rec.id}`, startedAt: Date.now() }),
|
|
43939
44417
|
"utf8"
|
|
@@ -43965,6 +44443,7 @@ async function startMultiDaemon(opts = {}) {
|
|
|
43965
44443
|
"/",
|
|
43966
44444
|
(c) => c.json({
|
|
43967
44445
|
daemonVersion: DAEMON_VERSION,
|
|
44446
|
+
pendingUpdate: updatePoller?.current() ?? null,
|
|
43968
44447
|
projects: records.map((r) => ({
|
|
43969
44448
|
id: r.id,
|
|
43970
44449
|
name: r.entry.name,
|
|
@@ -44115,7 +44594,7 @@ async function startMultiDaemon(opts = {}) {
|
|
|
44115
44594
|
baseUrl = `http://127.0.0.1:${port}`;
|
|
44116
44595
|
try {
|
|
44117
44596
|
ensureDir(globalDir());
|
|
44118
|
-
|
|
44597
|
+
writeFileSync15(
|
|
44119
44598
|
lockPath,
|
|
44120
44599
|
JSON.stringify({ pid: process.pid, webUiUrl: baseUrl, startedAt: Date.now() }),
|
|
44121
44600
|
"utf8"
|
|
@@ -44124,7 +44603,7 @@ async function startMultiDaemon(opts = {}) {
|
|
|
44124
44603
|
}
|
|
44125
44604
|
for (const r of records) {
|
|
44126
44605
|
try {
|
|
44127
|
-
|
|
44606
|
+
writeFileSync15(
|
|
44128
44607
|
r.engine.paths.daemonLock,
|
|
44129
44608
|
JSON.stringify({ pid: process.pid, webUiUrl: `${baseUrl}/ws/${r.id}`, startedAt: Date.now() }),
|
|
44130
44609
|
"utf8"
|
|
@@ -44336,8 +44815,15 @@ async function startMultiDaemon(opts = {}) {
|
|
|
44336
44815
|
const res = await client.ingest(context);
|
|
44337
44816
|
uploaded += res.accepted;
|
|
44338
44817
|
}
|
|
44818
|
+
let lexicon;
|
|
44819
|
+
try {
|
|
44820
|
+
const summaries = summariesByBodyHash(loadSymbolSummaryCache(r.engine.paths.configDir));
|
|
44821
|
+
if (summaries.size > 0) lexicon = buildSymbolLexicon(store, summaries);
|
|
44822
|
+
} catch {
|
|
44823
|
+
}
|
|
44339
44824
|
const instances = buildInstanceIngest(store, r.engine.profile, DAEMON_VERSION, ignore, {
|
|
44340
|
-
includePackages: cfg2.consent.contributePackages
|
|
44825
|
+
includePackages: cfg2.consent.contributePackages,
|
|
44826
|
+
...lexicon ? { lexicon } : {}
|
|
44341
44827
|
});
|
|
44342
44828
|
if (instances) {
|
|
44343
44829
|
const res = await client.ingest(instances);
|
|
@@ -44420,13 +44906,14 @@ async function startMultiDaemon(opts = {}) {
|
|
|
44420
44906
|
},
|
|
44421
44907
|
async stop() {
|
|
44422
44908
|
try {
|
|
44423
|
-
const cur =
|
|
44909
|
+
const cur = readFileSync18(lockPath, "utf8");
|
|
44424
44910
|
if (JSON.parse(cur).pid === process.pid) unlinkSync3(lockPath);
|
|
44425
44911
|
} catch {
|
|
44426
44912
|
}
|
|
44427
44913
|
await new Promise(
|
|
44428
44914
|
(res) => server.close(res)
|
|
44429
44915
|
);
|
|
44916
|
+
updatePoller?.stop();
|
|
44430
44917
|
for (const r of records) await r.engine.stop();
|
|
44431
44918
|
if (consolidateWorker) await consolidateWorker.stop();
|
|
44432
44919
|
try {
|
|
@@ -44584,45 +45071,6 @@ async function loginOAuthLoopback(opts) {
|
|
|
44584
45071
|
return { tokens, tokenEndpoint: endpoints.tokenEndpoint, clientId };
|
|
44585
45072
|
}
|
|
44586
45073
|
|
|
44587
|
-
// src/update.ts
|
|
44588
|
-
import { spawn as spawn2 } from "node:child_process";
|
|
44589
|
-
var PACKAGE_NAME = "@inerrata-corporation/errata";
|
|
44590
|
-
async function latestPublished(channel, timeoutMs = 4e3) {
|
|
44591
|
-
const ctrl = new AbortController();
|
|
44592
|
-
const timer = setTimeout(() => ctrl.abort(), timeoutMs);
|
|
44593
|
-
try {
|
|
44594
|
-
const res = await fetch(`https://registry.npmjs.org/${PACKAGE_NAME}`, {
|
|
44595
|
-
headers: { accept: "application/vnd.npm.install-v1+json" },
|
|
44596
|
-
signal: ctrl.signal
|
|
44597
|
-
});
|
|
44598
|
-
if (!res.ok) return null;
|
|
44599
|
-
const body2 = await res.json();
|
|
44600
|
-
return body2["dist-tags"]?.[channel] ?? null;
|
|
44601
|
-
} catch {
|
|
44602
|
-
return null;
|
|
44603
|
-
} finally {
|
|
44604
|
-
clearTimeout(timer);
|
|
44605
|
-
}
|
|
44606
|
-
}
|
|
44607
|
-
async function checkForUpdate(channel) {
|
|
44608
|
-
const latest = await latestPublished(channel);
|
|
44609
|
-
return {
|
|
44610
|
-
current: DAEMON_VERSION,
|
|
44611
|
-
latest,
|
|
44612
|
-
updateAvailable: latest !== null && latest !== DAEMON_VERSION
|
|
44613
|
-
};
|
|
44614
|
-
}
|
|
44615
|
-
function runNpmInstall(channel) {
|
|
44616
|
-
return new Promise((resolve5) => {
|
|
44617
|
-
const child = spawn2("npm", ["install", "-g", `${PACKAGE_NAME}@${channel}`], {
|
|
44618
|
-
stdio: "inherit",
|
|
44619
|
-
shell: true
|
|
44620
|
-
});
|
|
44621
|
-
child.on("close", (code) => resolve5(code ?? 1));
|
|
44622
|
-
child.on("error", () => resolve5(1));
|
|
44623
|
-
});
|
|
44624
|
-
}
|
|
44625
|
-
|
|
44626
45074
|
// src/cli.ts
|
|
44627
45075
|
init_paths();
|
|
44628
45076
|
|
|
@@ -44912,21 +45360,21 @@ async function cmdInit() {
|
|
|
44912
45360
|
if (!skipHooks) {
|
|
44913
45361
|
console.log("");
|
|
44914
45362
|
console.log("installing harness hooks...");
|
|
44915
|
-
const { existsSync:
|
|
44916
|
-
const { join:
|
|
45363
|
+
const { existsSync: existsSync21 } = await import("node:fs");
|
|
45364
|
+
const { join: join24 } = await import("node:path");
|
|
44917
45365
|
try {
|
|
44918
45366
|
await installClaudeHooks(port);
|
|
44919
45367
|
} catch (err2) {
|
|
44920
45368
|
console.warn(` \u26A0\uFE0F Claude hook install failed: ${err2 instanceof Error ? err2.message : err2}`);
|
|
44921
45369
|
}
|
|
44922
|
-
if (
|
|
45370
|
+
if (existsSync21(join24(ROOT, ".cursor"))) {
|
|
44923
45371
|
try {
|
|
44924
45372
|
await installCursorMcpConfig();
|
|
44925
45373
|
} catch (err2) {
|
|
44926
45374
|
console.warn(` \u26A0\uFE0F Cursor MCP config failed: ${err2 instanceof Error ? err2.message : err2}`);
|
|
44927
45375
|
}
|
|
44928
45376
|
}
|
|
44929
|
-
if (
|
|
45377
|
+
if (existsSync21(join24(ROOT, ".codex"))) {
|
|
44930
45378
|
try {
|
|
44931
45379
|
await installCodexHooks(port);
|
|
44932
45380
|
} catch (err2) {
|
|
@@ -45043,8 +45491,8 @@ async function cmdStatus() {
|
|
|
45043
45491
|
console.log(` stack: ${profile.stack.join(", ") || "(none)"}`);
|
|
45044
45492
|
console.log(` languages: ${profile.languages.join(", ") || "(none)"}`);
|
|
45045
45493
|
}
|
|
45046
|
-
console.log(` graph db: ${
|
|
45047
|
-
console.log(` event log: ${
|
|
45494
|
+
console.log(` graph db: ${existsSync20(paths.castalia) ? "yes" : "no"} (${paths.castalia})`);
|
|
45495
|
+
console.log(` event log: ${existsSync20(paths.eventLog) ? "yes" : "no"} (${paths.eventLog})`);
|
|
45048
45496
|
const lockPath = globalDaemonLock();
|
|
45049
45497
|
const running = isDaemonAlive(lockPath) ? readDaemonLock(lockPath) : null;
|
|
45050
45498
|
console.log(
|
|
@@ -45340,11 +45788,11 @@ async function cmdLogout() {
|
|
|
45340
45788
|
}
|
|
45341
45789
|
async function cmdReview() {
|
|
45342
45790
|
const paths = workspacePaths(ROOT);
|
|
45343
|
-
if (!
|
|
45791
|
+
if (!existsSync20(paths.reviewQueue)) {
|
|
45344
45792
|
console.log("(review queue empty)");
|
|
45345
45793
|
return;
|
|
45346
45794
|
}
|
|
45347
|
-
const queue = JSON.parse(
|
|
45795
|
+
const queue = JSON.parse(readFileSync19(paths.reviewQueue, "utf8"));
|
|
45348
45796
|
if (queue.length === 0) {
|
|
45349
45797
|
console.log("(review queue empty)");
|
|
45350
45798
|
return;
|
|
@@ -45974,7 +46422,7 @@ async function gatherRepo(store, ws) {
|
|
|
45974
46422
|
};
|
|
45975
46423
|
}
|
|
45976
46424
|
async function gatherReportData(generatedAt) {
|
|
45977
|
-
const { existsSync:
|
|
46425
|
+
const { existsSync: existsSync21 } = await import("node:fs");
|
|
45978
46426
|
const { openGraphStore: openGraphStore2 } = await Promise.resolve().then(() => (init_src4(), src_exports2));
|
|
45979
46427
|
const cfg = loadConfig();
|
|
45980
46428
|
const outbound = cfg.consent.sync ? "auto" : "off";
|
|
@@ -45982,7 +46430,7 @@ async function gatherReportData(generatedAt) {
|
|
|
45982
46430
|
for (const ws of listWorkspaces()) {
|
|
45983
46431
|
if (ws.missing) continue;
|
|
45984
46432
|
const dbPath = workspacePaths(ws.path).castalia;
|
|
45985
|
-
if (!
|
|
46433
|
+
if (!existsSync21(dbPath)) continue;
|
|
45986
46434
|
let store = null;
|
|
45987
46435
|
try {
|
|
45988
46436
|
store = openGraphStore2({ path: dbPath });
|
|
@@ -46013,7 +46461,7 @@ async function gatherReportData(generatedAt) {
|
|
|
46013
46461
|
};
|
|
46014
46462
|
}
|
|
46015
46463
|
async function cmdReport(args2) {
|
|
46016
|
-
const { mkdirSync: mkdirSync6, writeFileSync:
|
|
46464
|
+
const { mkdirSync: mkdirSync6, writeFileSync: writeFileSync16 } = await import("node:fs");
|
|
46017
46465
|
const { renderReport: renderReport2 } = await Promise.resolve().then(() => (init_report_render(), report_render_exports));
|
|
46018
46466
|
const includeFutureVerbs = args2.includes("--future-verbs");
|
|
46019
46467
|
const now = /* @__PURE__ */ new Date();
|
|
@@ -46026,8 +46474,8 @@ async function cmdReport(args2) {
|
|
|
46026
46474
|
const outDir = workspacePaths(ROOT).configDir;
|
|
46027
46475
|
mkdirSync6(outDir, { recursive: true });
|
|
46028
46476
|
const files = renderReport2(data, { includeFutureVerbs });
|
|
46029
|
-
for (const f of files)
|
|
46030
|
-
const indexPath =
|
|
46477
|
+
for (const f of files) writeFileSync16(join23(outDir, f.name), f.html, "utf8");
|
|
46478
|
+
const indexPath = join23(outDir, "report.html");
|
|
46031
46479
|
console.log(`report \u2192 ${indexPath}`);
|
|
46032
46480
|
console.log(` ${data.repos.length} repo(s) \xB7 ${files.length} file(s) \xB7 ${data.rollup.nodes.toLocaleString("en-US")} nodes`);
|
|
46033
46481
|
console.log(` open: file://${indexPath.replace(/\\/g, "/")}`);
|
|
@@ -46147,15 +46595,15 @@ function hookRelayCommand(port, path2) {
|
|
|
46147
46595
|
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 '{}'`;
|
|
46148
46596
|
}
|
|
46149
46597
|
async function installClaudeHooks(port) {
|
|
46150
|
-
const { mkdirSync: mkdirSync6, existsSync:
|
|
46151
|
-
const { join:
|
|
46152
|
-
const dir =
|
|
46153
|
-
if (!
|
|
46154
|
-
const file2 =
|
|
46598
|
+
const { mkdirSync: mkdirSync6, existsSync: existsSync21, readFileSync: readFileSync20, writeFileSync: writeFileSync16 } = await import("node:fs");
|
|
46599
|
+
const { join: join24 } = await import("node:path");
|
|
46600
|
+
const dir = join24(ROOT, ".claude");
|
|
46601
|
+
if (!existsSync21(dir)) mkdirSync6(dir, { recursive: true });
|
|
46602
|
+
const file2 = join24(dir, "settings.json");
|
|
46155
46603
|
let settings = {};
|
|
46156
|
-
if (
|
|
46604
|
+
if (existsSync21(file2)) {
|
|
46157
46605
|
try {
|
|
46158
|
-
settings = JSON.parse(
|
|
46606
|
+
settings = JSON.parse(readFileSync20(file2, "utf8"));
|
|
46159
46607
|
} catch {
|
|
46160
46608
|
console.error(`refusing to overwrite invalid JSON at ${file2}`);
|
|
46161
46609
|
process.exit(2);
|
|
@@ -46200,21 +46648,21 @@ async function installClaudeHooks(port) {
|
|
|
46200
46648
|
dropErrata(list);
|
|
46201
46649
|
list.push({ hooks: [{ type: "command", command: injectCmd }] });
|
|
46202
46650
|
}
|
|
46203
|
-
|
|
46651
|
+
writeFileSync16(file2, JSON.stringify(settings, null, 2) + "\n", "utf8");
|
|
46204
46652
|
console.log(`installed Claude Code hooks \u2192 ${file2}`);
|
|
46205
46653
|
await installClaudeMcpConfig();
|
|
46206
46654
|
console.log(` endpoint: http://127.0.0.1:${port}/api/hook`);
|
|
46207
46655
|
}
|
|
46208
46656
|
async function installClaudeMcpConfig() {
|
|
46209
|
-
const { mkdirSync: mkdirSync6, existsSync:
|
|
46210
|
-
const { join:
|
|
46211
|
-
const file2 =
|
|
46657
|
+
const { mkdirSync: mkdirSync6, existsSync: existsSync21, readFileSync: readFileSync20, writeFileSync: writeFileSync16 } = await import("node:fs");
|
|
46658
|
+
const { join: join24, dirname: dirname8 } = await import("node:path");
|
|
46659
|
+
const file2 = join24(ROOT, ".mcp.json");
|
|
46212
46660
|
const dir = dirname8(file2);
|
|
46213
|
-
if (!
|
|
46661
|
+
if (!existsSync21(dir)) mkdirSync6(dir, { recursive: true });
|
|
46214
46662
|
let cfg = {};
|
|
46215
|
-
if (
|
|
46663
|
+
if (existsSync21(file2)) {
|
|
46216
46664
|
try {
|
|
46217
|
-
cfg = JSON.parse(
|
|
46665
|
+
cfg = JSON.parse(readFileSync20(file2, "utf8"));
|
|
46218
46666
|
} catch {
|
|
46219
46667
|
console.error(`refusing to overwrite invalid JSON at ${file2}`);
|
|
46220
46668
|
process.exit(2);
|
|
@@ -46222,21 +46670,21 @@ async function installClaudeMcpConfig() {
|
|
|
46222
46670
|
}
|
|
46223
46671
|
cfg.mcpServers ??= {};
|
|
46224
46672
|
cfg.mcpServers["errata"] = errataMcpInvocation();
|
|
46225
|
-
|
|
46673
|
+
writeFileSync16(file2, JSON.stringify(cfg, null, 2) + "\n", "utf8");
|
|
46226
46674
|
console.log(`installed Claude Code MCP server config \u2192 ${file2}`);
|
|
46227
46675
|
console.log(` Claude Code will spawn \`errata mcp\` on workspace open.`);
|
|
46228
46676
|
console.log(` Tools: errata.search / locate / neighbors / callers_of / what_uses / show / similar`);
|
|
46229
46677
|
}
|
|
46230
46678
|
async function installCursorMcpConfig() {
|
|
46231
|
-
const { mkdirSync: mkdirSync6, existsSync:
|
|
46232
|
-
const { join:
|
|
46233
|
-
const dir =
|
|
46234
|
-
if (!
|
|
46235
|
-
const file2 =
|
|
46679
|
+
const { mkdirSync: mkdirSync6, existsSync: existsSync21, readFileSync: readFileSync20, writeFileSync: writeFileSync16 } = await import("node:fs");
|
|
46680
|
+
const { join: join24 } = await import("node:path");
|
|
46681
|
+
const dir = join24(ROOT, ".cursor");
|
|
46682
|
+
if (!existsSync21(dir)) mkdirSync6(dir, { recursive: true });
|
|
46683
|
+
const file2 = join24(dir, "mcp.json");
|
|
46236
46684
|
let cfg = {};
|
|
46237
|
-
if (
|
|
46685
|
+
if (existsSync21(file2)) {
|
|
46238
46686
|
try {
|
|
46239
|
-
cfg = JSON.parse(
|
|
46687
|
+
cfg = JSON.parse(readFileSync20(file2, "utf8"));
|
|
46240
46688
|
} catch {
|
|
46241
46689
|
console.error(`refusing to overwrite invalid JSON at ${file2}`);
|
|
46242
46690
|
process.exit(2);
|
|
@@ -46244,7 +46692,7 @@ async function installCursorMcpConfig() {
|
|
|
46244
46692
|
}
|
|
46245
46693
|
cfg.mcpServers ??= {};
|
|
46246
46694
|
cfg.mcpServers["errata"] = errataMcpInvocation();
|
|
46247
|
-
|
|
46695
|
+
writeFileSync16(file2, JSON.stringify(cfg, null, 2) + "\n", "utf8");
|
|
46248
46696
|
console.log(`installed Cursor MCP server config \u2192 ${file2}`);
|
|
46249
46697
|
console.log(` Cursor will spawn \`errata mcp\` on workspace open.`);
|
|
46250
46698
|
console.log(` Tools: errata.search / locate / neighbors / callers_of / what_uses`);
|
|
@@ -46252,16 +46700,16 @@ async function installCursorMcpConfig() {
|
|
|
46252
46700
|
console.log(` \u26A0\uFE0F reload Cursor (Cmd/Ctrl-Shift-P \u2192 "Reload Window") to pick it up.`);
|
|
46253
46701
|
}
|
|
46254
46702
|
async function installCodexHooks(port) {
|
|
46255
|
-
const { mkdirSync: mkdirSync6, existsSync:
|
|
46256
|
-
const { join:
|
|
46257
|
-
const dir =
|
|
46258
|
-
if (!
|
|
46259
|
-
const file2 =
|
|
46703
|
+
const { mkdirSync: mkdirSync6, existsSync: existsSync21, readFileSync: readFileSync20, writeFileSync: writeFileSync16 } = await import("node:fs");
|
|
46704
|
+
const { join: join24 } = await import("node:path");
|
|
46705
|
+
const dir = join24(ROOT, ".codex");
|
|
46706
|
+
if (!existsSync21(dir)) mkdirSync6(dir, { recursive: true });
|
|
46707
|
+
const file2 = join24(dir, "config.toml");
|
|
46260
46708
|
const BEGIN = `# >>> errata hooks (errata-managed)`;
|
|
46261
46709
|
const END = `# <<< errata hooks`;
|
|
46262
46710
|
let existing = "";
|
|
46263
|
-
if (
|
|
46264
|
-
existing =
|
|
46711
|
+
if (existsSync21(file2)) {
|
|
46712
|
+
existing = readFileSync20(file2, "utf8");
|
|
46265
46713
|
const beginIdx = existing.indexOf(BEGIN);
|
|
46266
46714
|
const endIdx = existing.indexOf(END);
|
|
46267
46715
|
if (beginIdx >= 0 && endIdx > beginIdx) {
|
|
@@ -46290,7 +46738,7 @@ ${END}
|
|
|
46290
46738
|
const final = existing.length > 0 && !existing.endsWith("\n") ? `${existing}
|
|
46291
46739
|
|
|
46292
46740
|
${block}` : existing + (existing.endsWith("\n\n") ? "" : "\n") + block;
|
|
46293
|
-
|
|
46741
|
+
writeFileSync16(file2, final, "utf8");
|
|
46294
46742
|
console.log(`installed Codex hooks \u2192 ${file2}`);
|
|
46295
46743
|
console.log(` endpoint: http://127.0.0.1:${port}/api/hook`);
|
|
46296
46744
|
console.log("");
|
|
@@ -46409,7 +46857,7 @@ async function cmdDash(args2) {
|
|
|
46409
46857
|
const reindexOnStart = !args2.includes("--no-reindex");
|
|
46410
46858
|
const skipEmbed = !args2.includes("--embed");
|
|
46411
46859
|
const skipWatchers = args2.includes("--no-watch");
|
|
46412
|
-
const handle2 = await startMultiDaemon({ webPort: port, reindexOnStart, skipEmbed, skipWatchers });
|
|
46860
|
+
const handle2 = await startMultiDaemon({ webPort: port, reindexOnStart, skipEmbed, skipWatchers, updateCheck: true });
|
|
46413
46861
|
console.log(`errata multi-daemon running`);
|
|
46414
46862
|
console.log(` endpoint: ${handle2.url} (JSON \u2014 the human view is \`errata report\`)`);
|
|
46415
46863
|
console.log(` projects: ${handle2.records.length}`);
|
|
@@ -46422,11 +46870,6 @@ async function cmdDash(args2) {
|
|
|
46422
46870
|
console.log(` indexing all projects in the background${skipEmbed ? " (--no-embed)" : ""}\u2026`);
|
|
46423
46871
|
}
|
|
46424
46872
|
console.log(`Press Ctrl-C to stop.`);
|
|
46425
|
-
void checkForUpdate(loadConfig().updateChannel).then((u) => {
|
|
46426
|
-
if (u.updateAvailable) {
|
|
46427
|
-
console.log(`\u26A1 errata update available: ${u.current} \u2192 ${u.latest} \u2014 run: errata update`);
|
|
46428
|
-
}
|
|
46429
|
-
});
|
|
46430
46873
|
const notifyEnabled = loadConfig().notifications && !process.env["ERRATA_NO_NOTIFY"];
|
|
46431
46874
|
const QUIESCENCE_MS = 9e4;
|
|
46432
46875
|
let quiesceTimer = null;
|
|
@@ -46558,7 +47001,7 @@ async function cmdDash(args2) {
|
|
|
46558
47001
|
await yieldToLoop2();
|
|
46559
47002
|
try {
|
|
46560
47003
|
const items = selectDurableMemory(handle2.sharedStore, r.engine.profile);
|
|
46561
|
-
const res = bleedRules(
|
|
47004
|
+
const res = bleedRules(join23(r.root, ".claude", "rules"), items);
|
|
46562
47005
|
if (res.written || res.pruned) {
|
|
46563
47006
|
console.log(
|
|
46564
47007
|
`[rules:${r.entry.name}] ${res.written} collective principle(s) \u2192 .claude/rules` + (res.pruned ? `, ${res.pruned} pruned` : "")
|