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