@kodr/aiwrangler 0.1.1 → 0.1.2
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/CHANGELOG.md +27 -0
- package/README.md +34 -12
- package/dist/{chunk-NQFO47CV.js → chunk-4D4NYPL3.js} +5 -5
- package/dist/{chunk-EAQASAXL.js → chunk-F3YFQ4NW.js} +18 -403
- package/dist/chunk-F3YFQ4NW.js.map +1 -0
- package/dist/{chunk-EDVWHCQV.js → chunk-HT3QDS3C.js} +2 -2
- package/dist/{chunk-2CIV4KGU.js → chunk-RZWCNEZS.js} +408 -21
- package/dist/chunk-RZWCNEZS.js.map +1 -0
- package/dist/cli.js +4 -4
- package/dist/index.d.ts +10 -1
- package/dist/index.js +22 -16
- package/dist/mcp.js +4 -4
- package/dist/plugin.js +184 -5
- package/dist/plugin.js.map +1 -1
- package/dist/tools.js +4 -4
- package/package.json +11 -5
- package/dist/chunk-2CIV4KGU.js.map +0 -1
- package/dist/chunk-EAQASAXL.js.map +0 -1
- /package/dist/{chunk-NQFO47CV.js.map → chunk-4D4NYPL3.js.map} +0 -0
- /package/dist/{chunk-EDVWHCQV.js.map → chunk-HT3QDS3C.js.map} +0 -0
|
@@ -6,10 +6,384 @@ import {
|
|
|
6
6
|
diffFingerprint,
|
|
7
7
|
expandPath,
|
|
8
8
|
formatFindings,
|
|
9
|
+
loadConfig,
|
|
9
10
|
parseCargoJson,
|
|
10
11
|
readRuntimeOverridesFile,
|
|
11
|
-
runDeterministic
|
|
12
|
-
|
|
12
|
+
runDeterministic,
|
|
13
|
+
sha256Hex
|
|
14
|
+
} from "./chunk-F3YFQ4NW.js";
|
|
15
|
+
|
|
16
|
+
// src/types.ts
|
|
17
|
+
var PRECEDENCE = {
|
|
18
|
+
ruling: 0,
|
|
19
|
+
paper: 1,
|
|
20
|
+
door: 1,
|
|
21
|
+
spec: 2,
|
|
22
|
+
doc: 3,
|
|
23
|
+
nonRuling: 4
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
// src/groundtruth/sectionize.ts
|
|
27
|
+
function splitMarkdown(md) {
|
|
28
|
+
const lines = md.split("\n");
|
|
29
|
+
const sections = [];
|
|
30
|
+
let current = null;
|
|
31
|
+
for (let i = 0; i < lines.length; i++) {
|
|
32
|
+
const line = lines[i] ?? "";
|
|
33
|
+
const m = line.match(/^(#{1,6})\s+(.*)$/);
|
|
34
|
+
if (m) {
|
|
35
|
+
if (current) sections.push(current);
|
|
36
|
+
current = { level: m[1].length, title: m[2].trim(), text: "", line: i + 1 };
|
|
37
|
+
} else if (current) {
|
|
38
|
+
current.text += line + "\n";
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
if (current) sections.push(current);
|
|
42
|
+
return sections.map((s) => ({ ...s, text: s.text.trim() }));
|
|
43
|
+
}
|
|
44
|
+
function slug(title) {
|
|
45
|
+
return title.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 40);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// src/groundtruth/parsers.ts
|
|
49
|
+
function section(partial) {
|
|
50
|
+
return { precedence: PRECEDENCE.doc, ...partial };
|
|
51
|
+
}
|
|
52
|
+
var ROMAN_RE = /^[IVX]+(?:-[A-Z])?$/;
|
|
53
|
+
function parseSpec(md, source) {
|
|
54
|
+
const out = [];
|
|
55
|
+
for (const sec of splitMarkdown(md)) {
|
|
56
|
+
const m = sec.title.match(/^(\d+)\.\s+(.*)$/);
|
|
57
|
+
if (!m) continue;
|
|
58
|
+
const title = m[2];
|
|
59
|
+
const ref = title.match(/\(([^)]+)\)\s*$/);
|
|
60
|
+
const paperRef = ref && ROMAN_RE.test(ref[1]) ? ref[1] : void 0;
|
|
61
|
+
out.push(
|
|
62
|
+
section({
|
|
63
|
+
id: `SPEC-${m[1]}`,
|
|
64
|
+
kind: "spec",
|
|
65
|
+
title,
|
|
66
|
+
text: sec.text,
|
|
67
|
+
source,
|
|
68
|
+
status: "info",
|
|
69
|
+
...paperRef ? { paperRef } : {},
|
|
70
|
+
precedence: PRECEDENCE.spec
|
|
71
|
+
})
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
return out;
|
|
75
|
+
}
|
|
76
|
+
function parseRules(md, source) {
|
|
77
|
+
const lines = md.split("\n");
|
|
78
|
+
const out = [];
|
|
79
|
+
let current = null;
|
|
80
|
+
const flush = () => {
|
|
81
|
+
if (!current) return;
|
|
82
|
+
out.push(
|
|
83
|
+
section({
|
|
84
|
+
id: `RULE-${current.n}`,
|
|
85
|
+
kind: "rule",
|
|
86
|
+
title: current.lines[0].trim(),
|
|
87
|
+
text: current.lines.join("\n").trim(),
|
|
88
|
+
source,
|
|
89
|
+
status: "info",
|
|
90
|
+
precedence: PRECEDENCE.spec
|
|
91
|
+
})
|
|
92
|
+
);
|
|
93
|
+
current = null;
|
|
94
|
+
};
|
|
95
|
+
for (const line of lines) {
|
|
96
|
+
const m = line.match(/^(\d+)\.\s+(.*)$/);
|
|
97
|
+
if (m) {
|
|
98
|
+
flush();
|
|
99
|
+
current = { n: m[1], lines: [m[2]] };
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
if (current && (/^\s{2,}/.test(line) || line.trim() === "")) {
|
|
103
|
+
if (line.trim() === "" && current.lines[current.lines.length - 1] === "") continue;
|
|
104
|
+
current.lines.push(line.trim() === "" ? "" : line.trim());
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
flush();
|
|
108
|
+
}
|
|
109
|
+
flush();
|
|
110
|
+
return out;
|
|
111
|
+
}
|
|
112
|
+
function parseDivergences(md, source) {
|
|
113
|
+
const lines = md.split("\n");
|
|
114
|
+
const out = [];
|
|
115
|
+
let topic = "";
|
|
116
|
+
let current = null;
|
|
117
|
+
const flush = () => {
|
|
118
|
+
if (!current) return;
|
|
119
|
+
const body = current.lines.join("\n").trim();
|
|
120
|
+
const marker = body.indexOf("**RULED");
|
|
121
|
+
const ruled = marker >= 0;
|
|
122
|
+
const ruling = ruled ? body.slice(marker).replace(/\*\*/g, "").replace(/\s+/g, " ").trim().slice(0, 800) : void 0;
|
|
123
|
+
out.push(
|
|
124
|
+
section({
|
|
125
|
+
id: `DIV-D-${current.id}`,
|
|
126
|
+
kind: "divergence",
|
|
127
|
+
title: `${current.topic ? current.topic + ": " : ""}${current.lines[0].trim()}`,
|
|
128
|
+
text: body,
|
|
129
|
+
source,
|
|
130
|
+
status: ruled ? "ruled" : "open",
|
|
131
|
+
...ruled && ruling ? { ruling } : {},
|
|
132
|
+
precedence: ruled ? PRECEDENCE.ruling : PRECEDENCE.nonRuling
|
|
133
|
+
})
|
|
134
|
+
);
|
|
135
|
+
current = null;
|
|
136
|
+
};
|
|
137
|
+
for (const line of lines) {
|
|
138
|
+
const h = line.match(/^##\s+(.*)$/);
|
|
139
|
+
if (h) {
|
|
140
|
+
flush();
|
|
141
|
+
topic = h[1].trim();
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
144
|
+
const m = line.match(/^D-(\d+)\s+(.*)$/);
|
|
145
|
+
if (m) {
|
|
146
|
+
flush();
|
|
147
|
+
current = { id: m[1], lines: [m[2]], topic };
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
if (current) current.lines.push(line);
|
|
151
|
+
}
|
|
152
|
+
flush();
|
|
153
|
+
return out;
|
|
154
|
+
}
|
|
155
|
+
function parseQuestions(md, source) {
|
|
156
|
+
const lines = md.split("\n");
|
|
157
|
+
const out = [];
|
|
158
|
+
let heading = "";
|
|
159
|
+
let current = null;
|
|
160
|
+
const flush = () => {
|
|
161
|
+
if (!current) return;
|
|
162
|
+
const body = current.lines.join("\n").trim();
|
|
163
|
+
const marker = body.indexOf("**ANSWERED");
|
|
164
|
+
const answered = marker >= 0;
|
|
165
|
+
const ruling = answered ? body.slice(marker).replace(/\*\*/g, "").replace(/\s+/g, " ").trim().slice(0, 800) : void 0;
|
|
166
|
+
out.push(
|
|
167
|
+
section({
|
|
168
|
+
id: `Q-${current.n}`,
|
|
169
|
+
kind: "question",
|
|
170
|
+
title: current.lines[0].trim(),
|
|
171
|
+
text: body,
|
|
172
|
+
source,
|
|
173
|
+
status: answered ? "answered" : "open",
|
|
174
|
+
...answered && ruling ? { ruling } : {},
|
|
175
|
+
precedence: answered ? PRECEDENCE.ruling : PRECEDENCE.nonRuling
|
|
176
|
+
})
|
|
177
|
+
);
|
|
178
|
+
current = null;
|
|
179
|
+
};
|
|
180
|
+
for (const line of lines) {
|
|
181
|
+
const h = line.match(/^##\s+(.*)$/);
|
|
182
|
+
if (h) {
|
|
183
|
+
flush();
|
|
184
|
+
heading = h[1].trim();
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
const m = line.match(/^(\d+)\.\s+(.*)$/);
|
|
188
|
+
if (m) {
|
|
189
|
+
flush();
|
|
190
|
+
current = { n: m[1], lines: [m[2]], heading };
|
|
191
|
+
continue;
|
|
192
|
+
}
|
|
193
|
+
if (current) current.lines.push(line);
|
|
194
|
+
}
|
|
195
|
+
flush();
|
|
196
|
+
return out;
|
|
197
|
+
}
|
|
198
|
+
function parsePlan(md, source) {
|
|
199
|
+
const out = [];
|
|
200
|
+
for (const sec of splitMarkdown(md)) {
|
|
201
|
+
if (!/one-way door|launch gate/i.test(sec.title)) continue;
|
|
202
|
+
out.push(
|
|
203
|
+
section({
|
|
204
|
+
id: `DOOR-${slug(sec.title) || out.length + 1}`,
|
|
205
|
+
kind: "door",
|
|
206
|
+
title: sec.title,
|
|
207
|
+
text: sec.text,
|
|
208
|
+
source,
|
|
209
|
+
status: "info",
|
|
210
|
+
precedence: PRECEDENCE.door
|
|
211
|
+
})
|
|
212
|
+
);
|
|
213
|
+
}
|
|
214
|
+
return out;
|
|
215
|
+
}
|
|
216
|
+
function parseDoc(md, source, label) {
|
|
217
|
+
return splitMarkdown(md).filter((s) => s.text.length > 0).map(
|
|
218
|
+
(sec, i) => section({
|
|
219
|
+
id: `DOC-${label}-${String(i + 1).padStart(2, "0")}`,
|
|
220
|
+
kind: "doc",
|
|
221
|
+
title: sec.title || "(intro)",
|
|
222
|
+
text: sec.text,
|
|
223
|
+
source,
|
|
224
|
+
status: "info",
|
|
225
|
+
precedence: PRECEDENCE.doc
|
|
226
|
+
})
|
|
227
|
+
);
|
|
228
|
+
}
|
|
229
|
+
var PAPER_HEADING_RE = /^([IVX]+(?:-[A-Z])?)?\.?\s{1,4}(.+)$/;
|
|
230
|
+
var ROMAN_ONLY_RE = /^[IVX]+$/;
|
|
231
|
+
function mergeSpacedCaps(title) {
|
|
232
|
+
const tokens = title.split(/\s+/).filter(Boolean);
|
|
233
|
+
const merged = [];
|
|
234
|
+
let i = 0;
|
|
235
|
+
while (i < tokens.length) {
|
|
236
|
+
const tok = tokens[i];
|
|
237
|
+
const next = tokens[i + 1];
|
|
238
|
+
if (next !== void 0 && /^-?[A-Z]$/.test(tok) && /^[A-Z]/.test(next) && next.length > 1) {
|
|
239
|
+
merged.push((tok.startsWith("-") ? tok : "") + next);
|
|
240
|
+
i += 2;
|
|
241
|
+
continue;
|
|
242
|
+
}
|
|
243
|
+
if (tok.length === 1 && /^[A-Z]$/.test(tok) && next !== void 0 && /^[A-Z]/.test(next)) {
|
|
244
|
+
merged.push(tok + next);
|
|
245
|
+
i += 2;
|
|
246
|
+
continue;
|
|
247
|
+
}
|
|
248
|
+
merged.push(tok);
|
|
249
|
+
i++;
|
|
250
|
+
}
|
|
251
|
+
return merged.join(" ").replace(/ -/g, "-").replace(/\s+,/g, ",");
|
|
252
|
+
}
|
|
253
|
+
function capsRatio(s) {
|
|
254
|
+
const letters = s.replace(/[^A-Za-z]/g, "");
|
|
255
|
+
if (letters.length === 0) return 0;
|
|
256
|
+
const upper = letters.replace(/[^A-Z]/g, "");
|
|
257
|
+
return upper.length / letters.length;
|
|
258
|
+
}
|
|
259
|
+
function parsePaper(text, source) {
|
|
260
|
+
const lines = text.split("\n").map((l) => l.replace(/^\f/, ""));
|
|
261
|
+
const byId = /* @__PURE__ */ new Map();
|
|
262
|
+
let current = null;
|
|
263
|
+
const looksLikeCapsFragment = (line) => {
|
|
264
|
+
const t = line.trim();
|
|
265
|
+
return t.length >= 3 && t.length <= 40 && !/[.:;]$/.test(t) && !/\.\s*\.\s*\./.test(t) && capsRatio(t) >= 0.6;
|
|
266
|
+
};
|
|
267
|
+
const flush = () => {
|
|
268
|
+
if (!current) return;
|
|
269
|
+
const body = current.lines.join("\n").trim();
|
|
270
|
+
const existing = byId.get(current.id);
|
|
271
|
+
if (existing) {
|
|
272
|
+
existing.text = (existing.text + "\n" + body).trim();
|
|
273
|
+
} else {
|
|
274
|
+
byId.set(
|
|
275
|
+
current.id,
|
|
276
|
+
section({
|
|
277
|
+
id: `PAPER-${current.id}`,
|
|
278
|
+
kind: "paper",
|
|
279
|
+
title: current.title,
|
|
280
|
+
text: body,
|
|
281
|
+
source,
|
|
282
|
+
status: "info",
|
|
283
|
+
precedence: PRECEDENCE.paper
|
|
284
|
+
})
|
|
285
|
+
);
|
|
286
|
+
}
|
|
287
|
+
current = null;
|
|
288
|
+
};
|
|
289
|
+
for (let li = 0; li < lines.length; li++) {
|
|
290
|
+
const line = lines[li] ?? "";
|
|
291
|
+
if (/\.\s*\.\s*\./.test(line)) continue;
|
|
292
|
+
const m = line.match(PAPER_HEADING_RE);
|
|
293
|
+
if (m && m[1] && !ROMAN_ONLY_RE.test(m[2] ?? "") && !/^[ivx]+$/.test(m[1])) {
|
|
294
|
+
let title = mergeSpacedCaps(m[2] ?? "");
|
|
295
|
+
let consumed = 1;
|
|
296
|
+
while (li + consumed < lines.length && looksLikeCapsFragment(lines[li + consumed] ?? "") && title.split(/\s+/).length < 10) {
|
|
297
|
+
title = title + " " + mergeSpacedCaps((lines[li + consumed] ?? "").trim());
|
|
298
|
+
consumed++;
|
|
299
|
+
}
|
|
300
|
+
const letters = title.replace(/[^A-Za-z]/g, "");
|
|
301
|
+
if (letters.length >= 4 && capsRatio(title) >= 0.7) {
|
|
302
|
+
flush();
|
|
303
|
+
current = { id: m[1], title: title.replace(/\s{2,}/g, " ").trim(), lines: [] };
|
|
304
|
+
li += consumed - 1;
|
|
305
|
+
continue;
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
if (current) current.lines.push(line);
|
|
309
|
+
}
|
|
310
|
+
flush();
|
|
311
|
+
return [...byId.values()];
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// src/groundtruth/whitepaper.ts
|
|
315
|
+
import { spawnSync } from "child_process";
|
|
316
|
+
import { existsSync, mkdirSync, readFileSync, statSync, writeFileSync } from "fs";
|
|
317
|
+
import { join } from "path";
|
|
318
|
+
function ensurePaperText(config, root) {
|
|
319
|
+
const pdf = expandPath(config.corpus.whitepaper, root);
|
|
320
|
+
const cacheDir = expandPath(config.cache.dir, root);
|
|
321
|
+
const cached = join(cacheDir, "whitepaper.txt");
|
|
322
|
+
const pdfMtime = existsSync(pdf) ? statSync(pdf).mtimeMs : 0;
|
|
323
|
+
if (existsSync(cached) && statSync(cached).mtimeMs >= pdfMtime) {
|
|
324
|
+
return { text: readFileSync(cached, "utf8"), extracted: false };
|
|
325
|
+
}
|
|
326
|
+
if (!existsSync(pdf)) return { text: null, extracted: false };
|
|
327
|
+
const res = spawnSync("pdftotext", [pdf, "-"], { encoding: "utf8", maxBuffer: 32 * 1024 * 1024 });
|
|
328
|
+
if (res.error || res.status !== 0) {
|
|
329
|
+
const reason = res.error ? res.error.message : `pdftotext exit ${res.status}`;
|
|
330
|
+
throw new Error(`whitepaper extraction failed (${reason}); is poppler-utils installed?`);
|
|
331
|
+
}
|
|
332
|
+
const text = res.stdout;
|
|
333
|
+
if (text.split(/\s+/).length < 1e3) throw new Error("whitepaper extraction produced suspiciously little text; refusing to cache");
|
|
334
|
+
mkdirSync(cacheDir, { recursive: true });
|
|
335
|
+
writeFileSync(cached, text, "utf8");
|
|
336
|
+
return { text, extracted: true };
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
// src/groundtruth/corpus.ts
|
|
340
|
+
import { readFileSync as readFileSync2 } from "fs";
|
|
341
|
+
function slugFromPath(rel) {
|
|
342
|
+
return rel.toLowerCase().replace(/\.[a-z0-9]+$/i, "").replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 40);
|
|
343
|
+
}
|
|
344
|
+
function readOr(path, fallback) {
|
|
345
|
+
try {
|
|
346
|
+
return { text: readFileSync2(path, "utf8"), sections: [] };
|
|
347
|
+
} catch {
|
|
348
|
+
return { text: null, sections: fallback };
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
function loadCorpus(config, root) {
|
|
352
|
+
const sections = [];
|
|
353
|
+
const sources = [];
|
|
354
|
+
const addFile = (path, parse) => {
|
|
355
|
+
const resolved = expandPath(path, root);
|
|
356
|
+
const { text } = readOr(resolved, []);
|
|
357
|
+
if (text === null) return;
|
|
358
|
+
sources.push({ path: resolved, hash: sha256Hex(text) });
|
|
359
|
+
sections.push(...parse(text, resolved));
|
|
360
|
+
};
|
|
361
|
+
addFile(config.corpus.spec, parseSpec);
|
|
362
|
+
addFile(config.corpus.rules, parseRules);
|
|
363
|
+
addFile(config.corpus.divergences, parseDivergences);
|
|
364
|
+
addFile(config.corpus.questions, parseQuestions);
|
|
365
|
+
addFile(config.corpus.plan, parsePlan);
|
|
366
|
+
for (const doc of config.corpus.docs) {
|
|
367
|
+
const resolved = expandPath(doc, root);
|
|
368
|
+
let label = doc.split("/").pop()?.replace(/\.[a-z]+$/i, "") ?? "doc";
|
|
369
|
+
const rel = resolved.startsWith(root + "/") ? resolved.slice(root.length + 1) : null;
|
|
370
|
+
if (rel && rel.includes("/")) label = slugFromPath(rel);
|
|
371
|
+
addFile(doc, (md, source) => parseDoc(md, source, label));
|
|
372
|
+
}
|
|
373
|
+
const paper = ensurePaperText(config, root);
|
|
374
|
+
if (paper.text !== null) {
|
|
375
|
+
const paperPath = expandPath(config.corpus.whitepaper, root);
|
|
376
|
+
sources.push({ path: paperPath, hash: sha256Hex(paper.text) });
|
|
377
|
+
sections.push(...parsePaper(paper.text, paperPath));
|
|
378
|
+
}
|
|
379
|
+
const hash = sha256Hex(JSON.stringify({ sources: sources.map((s) => [s.path, s.hash]).sort((a, b) => (a[0] ?? "").localeCompare(b[0] ?? "")), ids: sections.map((s) => s.id).sort() }));
|
|
380
|
+
return { sections, sources, hash, paperText: paper.text ?? "" };
|
|
381
|
+
}
|
|
382
|
+
function loadCorpusFrom(startDir) {
|
|
383
|
+
const loaded = loadConfig(startDir);
|
|
384
|
+
const corpus = loadCorpus(loaded.config, loaded.root);
|
|
385
|
+
return { loaded, corpus };
|
|
386
|
+
}
|
|
13
387
|
|
|
14
388
|
// src/jev/questions.ts
|
|
15
389
|
function noul(instructions, yes, no) {
|
|
@@ -48,9 +422,9 @@ function lexicalScore(index, query) {
|
|
|
48
422
|
const qTerms = tokenize(query);
|
|
49
423
|
const N = Math.max(index.sections.length, 1);
|
|
50
424
|
const scores = [];
|
|
51
|
-
for (const
|
|
52
|
-
const titleTerms = new Set(tokenize(
|
|
53
|
-
const bodyTerms = tokenize(
|
|
425
|
+
for (const section2 of index.sections) {
|
|
426
|
+
const titleTerms = new Set(tokenize(section2.title));
|
|
427
|
+
const bodyTerms = tokenize(section2.text);
|
|
54
428
|
const tf = /* @__PURE__ */ new Map();
|
|
55
429
|
for (const t of bodyTerms) tf.set(t, (tf.get(t) ?? 0) + 1);
|
|
56
430
|
let score2 = 0;
|
|
@@ -62,8 +436,8 @@ function lexicalScore(index, query) {
|
|
|
62
436
|
if (tfCount > 0) score2 += idf * (1 + Math.log(tfCount)) / (1 + Math.log(bodyTerms.length || 1)) * 10;
|
|
63
437
|
if (titleTerms.has(term)) score2 += idf * 3;
|
|
64
438
|
}
|
|
65
|
-
if (
|
|
66
|
-
scores.push({ section, score: score2 });
|
|
439
|
+
if (section2.kind === "door") score2 += 0.5;
|
|
440
|
+
scores.push({ section: section2, score: score2 });
|
|
67
441
|
}
|
|
68
442
|
return scores.sort((a, b) => b.score - a.score);
|
|
69
443
|
}
|
|
@@ -831,12 +1205,12 @@ async function runCheckBattery(config, jev, corpus, input, opts = {}) {
|
|
|
831
1205
|
});
|
|
832
1206
|
return { findings, verdicts, sections: ranked, usage: res.usage, examinedFiles };
|
|
833
1207
|
}
|
|
834
|
-
function overridesFor(
|
|
1208
|
+
function overridesFor(section2, rulings) {
|
|
835
1209
|
const out = [];
|
|
836
1210
|
const sectionTerms = new Set(
|
|
837
|
-
|
|
1211
|
+
section2.title.toLowerCase().split(/[^a-z0-9]+/).filter((t) => t.length > 3)
|
|
838
1212
|
);
|
|
839
|
-
if (
|
|
1213
|
+
if (section2.paperRef) sectionTerms.add(section2.paperRef.toLowerCase());
|
|
840
1214
|
for (const r of rulings) {
|
|
841
1215
|
const text = (r.title + " " + (r.ruling ?? "")).toLowerCase();
|
|
842
1216
|
let hits = 0;
|
|
@@ -903,12 +1277,12 @@ async function selectRootCause(jev, diags) {
|
|
|
903
1277
|
}
|
|
904
1278
|
|
|
905
1279
|
// src/gates/check/snapshot.ts
|
|
906
|
-
import { existsSync, mkdirSync, readdirSync, readFileSync, renameSync, statSync, unlinkSync, writeFileSync } from "fs";
|
|
907
|
-
import { join } from "path";
|
|
1280
|
+
import { existsSync as existsSync2, mkdirSync as mkdirSync2, readdirSync, readFileSync as readFileSync3, renameSync, statSync as statSync2, unlinkSync, writeFileSync as writeFileSync2 } from "fs";
|
|
1281
|
+
import { join as join2 } from "path";
|
|
908
1282
|
var SNAPSHOT_CAP = 2e5;
|
|
909
1283
|
var KEEP_SNAPSHOTS = 20;
|
|
910
1284
|
function snapshotsDir(config, root) {
|
|
911
|
-
return
|
|
1285
|
+
return join2(expandPath(config.cache.dir, root), "diffs");
|
|
912
1286
|
}
|
|
913
1287
|
function renderDiffSnapshot(diffs) {
|
|
914
1288
|
const out = [`snapshot generated ${(/* @__PURE__ */ new Date()).toISOString()}; added lines carry their new-file line number`];
|
|
@@ -946,10 +1320,10 @@ function renderDiffSnapshot(diffs) {
|
|
|
946
1320
|
function writeDiffSnapshot(config, root, diffHash, diffs) {
|
|
947
1321
|
if (diffs.length === 0) return null;
|
|
948
1322
|
const dir = snapshotsDir(config, root);
|
|
949
|
-
|
|
950
|
-
const path =
|
|
1323
|
+
mkdirSync2(dir, { recursive: true });
|
|
1324
|
+
const path = join2(dir, `${diffHash}.txt`);
|
|
951
1325
|
const tmp = path + ".tmp";
|
|
952
|
-
|
|
1326
|
+
writeFileSync2(tmp, renderDiffSnapshot(diffs) + "\n", "utf8");
|
|
953
1327
|
renameSync(tmp, path);
|
|
954
1328
|
pruneSnapshots(dir);
|
|
955
1329
|
return path;
|
|
@@ -964,21 +1338,21 @@ function pruneSnapshots(dir) {
|
|
|
964
1338
|
if (entries.length <= KEEP_SNAPSHOTS) return;
|
|
965
1339
|
const withTimes = entries.map((name) => {
|
|
966
1340
|
try {
|
|
967
|
-
return { name, mtime:
|
|
1341
|
+
return { name, mtime: statSync2(join2(dir, name)).mtimeMs };
|
|
968
1342
|
} catch {
|
|
969
1343
|
return null;
|
|
970
1344
|
}
|
|
971
1345
|
}).filter((e) => e !== null).sort((a, b) => b.mtime - a.mtime);
|
|
972
1346
|
for (const old of withTimes.slice(KEEP_SNAPSHOTS)) {
|
|
973
1347
|
try {
|
|
974
|
-
unlinkSync(
|
|
1348
|
+
unlinkSync(join2(dir, old.name));
|
|
975
1349
|
} catch {
|
|
976
1350
|
}
|
|
977
1351
|
}
|
|
978
1352
|
}
|
|
979
1353
|
|
|
980
1354
|
// src/gates/check/run.ts
|
|
981
|
-
import { join as
|
|
1355
|
+
import { join as join3 } from "path";
|
|
982
1356
|
var SEVERITY_RANK = { review: 1, block: 2, human: 3 };
|
|
983
1357
|
var FILES_SUMMARY_CAP = 200;
|
|
984
1358
|
function fileSummary(diffs) {
|
|
@@ -1042,7 +1416,7 @@ async function runCheck(config, root, corpus, jev, opts) {
|
|
|
1042
1416
|
};
|
|
1043
1417
|
}
|
|
1044
1418
|
const stateDir = expandPath(config.cache.dir, root);
|
|
1045
|
-
const tracker = new LoopTracker(
|
|
1419
|
+
const tracker = new LoopTracker(join3(stateDir, "loop-state.json"));
|
|
1046
1420
|
const diffText = diffs.flatMap((d) => d.files.map((f) => f.path + "\n" + f.hunks.flatMap((h) => h.lines.filter((l) => l.kind === "add").map((l) => l.text)).join("\n"))).join("\n");
|
|
1047
1421
|
const fingerprint = diffFingerprint(diffText);
|
|
1048
1422
|
const files = fileSummary(diffs);
|
|
@@ -1264,6 +1638,19 @@ function overlaps(a, b) {
|
|
|
1264
1638
|
}
|
|
1265
1639
|
|
|
1266
1640
|
export {
|
|
1641
|
+
PRECEDENCE,
|
|
1642
|
+
splitMarkdown,
|
|
1643
|
+
slug,
|
|
1644
|
+
parseSpec,
|
|
1645
|
+
parseRules,
|
|
1646
|
+
parseDivergences,
|
|
1647
|
+
parseQuestions,
|
|
1648
|
+
parsePlan,
|
|
1649
|
+
parseDoc,
|
|
1650
|
+
parsePaper,
|
|
1651
|
+
ensurePaperText,
|
|
1652
|
+
loadCorpus,
|
|
1653
|
+
loadCorpusFrom,
|
|
1267
1654
|
runPlanGate,
|
|
1268
1655
|
runCheck,
|
|
1269
1656
|
formatReport,
|
|
@@ -1273,4 +1660,4 @@ export {
|
|
|
1273
1660
|
paperSectionForSpec,
|
|
1274
1661
|
authoritativeFor
|
|
1275
1662
|
};
|
|
1276
|
-
//# sourceMappingURL=chunk-
|
|
1663
|
+
//# sourceMappingURL=chunk-RZWCNEZS.js.map
|