squadrant 0.27.0 → 0.28.0
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/dist/index.js +1086 -813
- package/dist/index.js.map +1 -1
- package/dist/squadrantd.js +762 -538
- package/dist/squadrantd.js.map +1 -1
- package/package.json +1 -1
- package/plugin/skills/knowledge-extract/SKILL.md +2 -0
- package/plugin/skills/knowledge-review/SKILL.md +5 -0
- package/templates/crew.claude.md +1 -0
- package/templates/crew.generic.md +1 -0
- package/templates/crew.opencode.md +1 -0
package/dist/squadrantd.js
CHANGED
|
@@ -305,7 +305,8 @@ function validateRuleFrontmatter(fm) {
|
|
|
305
305
|
if (fm[k] !== void 0 && !isStrArr(fm[k]))
|
|
306
306
|
p.push(`${k} must be a string array`);
|
|
307
307
|
}
|
|
308
|
-
|
|
308
|
+
const mayBeSourceless = fm.status === "stale" || fm.status === "retired";
|
|
309
|
+
if (!Array.isArray(fm.sources) || fm.sources.length === 0 && !mayBeSourceless) {
|
|
309
310
|
p.push("sources must be a non-empty array");
|
|
310
311
|
} else {
|
|
311
312
|
fm.sources.forEach((s, i) => {
|
|
@@ -339,6 +340,26 @@ function validateSourceEntry(e) {
|
|
|
339
340
|
p.push("domain must be a string");
|
|
340
341
|
if (e.sensitivity !== void 0 && e.sensitivity !== "local-only")
|
|
341
342
|
p.push("sensitivity must be 'local-only' when set");
|
|
343
|
+
if (e.review !== void 0 && e.review !== "required")
|
|
344
|
+
p.push("review must be 'required' when set");
|
|
345
|
+
return p;
|
|
346
|
+
}
|
|
347
|
+
function validateErratum(e) {
|
|
348
|
+
if (!isObj(e))
|
|
349
|
+
return ["erratum must be an object"];
|
|
350
|
+
const p = [];
|
|
351
|
+
if (typeof e.id !== "string" || !RULE_ID_RE.test(e.id))
|
|
352
|
+
p.push(`id must match ${RULE_ID_RE}`);
|
|
353
|
+
for (const k of ["ref", "quote", "reason"]) {
|
|
354
|
+
if (typeof e[k] !== "string" || e[k] === "")
|
|
355
|
+
p.push(`${k} must be a non-empty string`);
|
|
356
|
+
}
|
|
357
|
+
if (e.evidence !== void 0 && !isStrArr(e.evidence))
|
|
358
|
+
p.push("evidence must be a string array");
|
|
359
|
+
for (const k of ["checked", "by", "at", "decision"]) {
|
|
360
|
+
if (e[k] !== void 0 && typeof e[k] !== "string")
|
|
361
|
+
p.push(`${k} must be a string`);
|
|
362
|
+
}
|
|
342
363
|
return p;
|
|
343
364
|
}
|
|
344
365
|
function kbConfigs(cfg) {
|
|
@@ -463,22 +484,22 @@ function defaultCmuxConfigPath() {
|
|
|
463
484
|
return join(homedir(), ".config", "cmux", "cmux.json");
|
|
464
485
|
}
|
|
465
486
|
function ensureSocketAutomation(opts = {}) {
|
|
466
|
-
const
|
|
467
|
-
if (!existsSync(
|
|
468
|
-
mkdirSync(dirname(
|
|
469
|
-
writeFileSync(
|
|
470
|
-
return { path:
|
|
487
|
+
const path43 = opts.path ?? defaultCmuxConfigPath();
|
|
488
|
+
if (!existsSync(path43)) {
|
|
489
|
+
mkdirSync(dirname(path43), { recursive: true });
|
|
490
|
+
writeFileSync(path43, MINIMAL_TEMPLATE);
|
|
491
|
+
return { path: path43, changed: true, alreadySet: false };
|
|
471
492
|
}
|
|
472
|
-
const text = readFileSync(
|
|
493
|
+
const text = readFileSync(path43, "utf-8");
|
|
473
494
|
const current = parse(text)?.automation?.socketControlMode;
|
|
474
495
|
if (current === AUTOMATION_MODE) {
|
|
475
|
-
return { path:
|
|
496
|
+
return { path: path43, changed: false, alreadySet: true };
|
|
476
497
|
}
|
|
477
498
|
const edits = modify(text, [...SOCKET_CONTROL_MODE_PATH], AUTOMATION_MODE, {
|
|
478
499
|
formattingOptions: { insertSpaces: true, tabSize: 2 }
|
|
479
500
|
});
|
|
480
|
-
writeFileSync(
|
|
481
|
-
return { path:
|
|
501
|
+
writeFileSync(path43, applyEdits(text, edits));
|
|
502
|
+
return { path: path43, changed: true, alreadySet: false };
|
|
482
503
|
}
|
|
483
504
|
var SOCKET_CONTROL_MODE_PATH, AUTOMATION_MODE, MINIMAL_TEMPLATE;
|
|
484
505
|
var init_cmux_config = __esm({
|
|
@@ -628,9 +649,9 @@ import { join as join4 } from "path";
|
|
|
628
649
|
function defaultStatePath() {
|
|
629
650
|
return join4(homedir3(), ".config", "squadrant", "state", "cmux-autoconfig.json");
|
|
630
651
|
}
|
|
631
|
-
function readState(
|
|
652
|
+
function readState(path43) {
|
|
632
653
|
try {
|
|
633
|
-
return JSON.parse(readConfigFileSync(
|
|
654
|
+
return JSON.parse(readConfigFileSync(path43));
|
|
634
655
|
} catch {
|
|
635
656
|
return {};
|
|
636
657
|
}
|
|
@@ -2577,10 +2598,10 @@ function detectForeignInstall(parsed, thisEntry, registeredEntryExists) {
|
|
|
2577
2598
|
isUpgrade: isVersionUpgrade(parsed.daemonEntry, thisEntry)
|
|
2578
2599
|
};
|
|
2579
2600
|
}
|
|
2580
|
-
function sanitizePathForPlist(
|
|
2601
|
+
function sanitizePathForPlist(path43) {
|
|
2581
2602
|
const seen = /* @__PURE__ */ new Set();
|
|
2582
2603
|
const stable = [];
|
|
2583
|
-
for (const p of
|
|
2604
|
+
for (const p of path43.split(":")) {
|
|
2584
2605
|
if (!p)
|
|
2585
2606
|
continue;
|
|
2586
2607
|
if (p.includes("/.claude/plugins/"))
|
|
@@ -5120,11 +5141,11 @@ var init_captain_record = __esm({
|
|
|
5120
5141
|
// packages/core/dist/opencode-session.js
|
|
5121
5142
|
import { execFileSync as execFileSync4 } from "child_process";
|
|
5122
5143
|
async function listSessions(port, fetchImpl = fetch, timeoutMs = 5e3) {
|
|
5123
|
-
for (const
|
|
5144
|
+
for (const path43 of ["/session", "/api/session"]) {
|
|
5124
5145
|
const ac = new AbortController();
|
|
5125
5146
|
const t = setTimeout(() => ac.abort(), timeoutMs);
|
|
5126
5147
|
try {
|
|
5127
|
-
const res = await fetchImpl(`http://127.0.0.1:${port}${
|
|
5148
|
+
const res = await fetchImpl(`http://127.0.0.1:${port}${path43}`, { signal: ac.signal });
|
|
5128
5149
|
if (!res.ok)
|
|
5129
5150
|
continue;
|
|
5130
5151
|
const rows = await res.json();
|
|
@@ -5817,10 +5838,10 @@ function distBuiltAt() {
|
|
|
5817
5838
|
return 0;
|
|
5818
5839
|
}
|
|
5819
5840
|
}
|
|
5820
|
-
function gatherLogStats(
|
|
5841
|
+
function gatherLogStats(path43, now, windowMs) {
|
|
5821
5842
|
let sizeBytes = 0;
|
|
5822
5843
|
try {
|
|
5823
|
-
sizeBytes = statSync3(
|
|
5844
|
+
sizeBytes = statSync3(path43).size;
|
|
5824
5845
|
} catch {
|
|
5825
5846
|
return { errorCount: 0, sizeBytes: 0, windowMs };
|
|
5826
5847
|
}
|
|
@@ -5831,7 +5852,7 @@ function gatherLogStats(path42, now, windowMs) {
|
|
|
5831
5852
|
const len = sizeBytes - start;
|
|
5832
5853
|
let text = "";
|
|
5833
5854
|
try {
|
|
5834
|
-
const fd = openSync2(
|
|
5855
|
+
const fd = openSync2(path43, "r");
|
|
5835
5856
|
try {
|
|
5836
5857
|
const buf = Buffer.alloc(len);
|
|
5837
5858
|
readSync(fd, buf, 0, len, start);
|
|
@@ -8077,8 +8098,8 @@ var init_stream = __esm({
|
|
|
8077
8098
|
// packages/core/dist/router/shim.js
|
|
8078
8099
|
import { createServer as createServer3 } from "http";
|
|
8079
8100
|
import { Readable } from "stream";
|
|
8080
|
-
function joinUrl(base,
|
|
8081
|
-
return base.replace(/\/+$/, "") +
|
|
8101
|
+
function joinUrl(base, path43) {
|
|
8102
|
+
return base.replace(/\/+$/, "") + path43;
|
|
8082
8103
|
}
|
|
8083
8104
|
async function readBody(req) {
|
|
8084
8105
|
const chunks = [];
|
|
@@ -8254,8 +8275,8 @@ function createRouterShim(opts) {
|
|
|
8254
8275
|
writeJson(res, 200, { input_tokens: Math.max(1, Math.ceil(text.length / 4)) });
|
|
8255
8276
|
}
|
|
8256
8277
|
function handler(req, res) {
|
|
8257
|
-
const
|
|
8258
|
-
if (req.method === "POST" &&
|
|
8278
|
+
const path43 = pathnameOf(req.url);
|
|
8279
|
+
if (req.method === "POST" && path43 === "/v1/messages") {
|
|
8259
8280
|
void handleMessages(req, res).catch((err) => {
|
|
8260
8281
|
log(`router internal error: ${err instanceof Error ? err.message : String(err)}`);
|
|
8261
8282
|
if (!res.headersSent) {
|
|
@@ -8267,18 +8288,18 @@ function createRouterShim(opts) {
|
|
|
8267
8288
|
});
|
|
8268
8289
|
return;
|
|
8269
8290
|
}
|
|
8270
|
-
if (req.method === "POST" &&
|
|
8291
|
+
if (req.method === "POST" && path43 === "/v1/messages/count_tokens") {
|
|
8271
8292
|
void handleCountTokens(req, res).catch(() => {
|
|
8272
8293
|
if (!res.headersSent)
|
|
8273
8294
|
writeJson(res, 502, anthropicError(502, "api_error", "router internal error").body);
|
|
8274
8295
|
});
|
|
8275
8296
|
return;
|
|
8276
8297
|
}
|
|
8277
|
-
if (req.method === "GET" &&
|
|
8298
|
+
if (req.method === "GET" && path43 === "/v1/models") {
|
|
8278
8299
|
writeJson(res, 200, modelsList([...advertisedModels]));
|
|
8279
8300
|
return;
|
|
8280
8301
|
}
|
|
8281
|
-
if (req.method === "GET" &&
|
|
8302
|
+
if (req.method === "GET" && path43 === "/healthz") {
|
|
8282
8303
|
writeJson(res, 200, { ready: server?.listening === true, upstreamReachable, lastError });
|
|
8283
8304
|
return;
|
|
8284
8305
|
}
|
|
@@ -8547,11 +8568,11 @@ async function probeCaptainChannel(project, opts = {}) {
|
|
|
8547
8568
|
}
|
|
8548
8569
|
}
|
|
8549
8570
|
async function httpReachable(port, fetchImpl, timeoutMs) {
|
|
8550
|
-
for (const
|
|
8571
|
+
for (const path43 of ["/session", "/api/session"]) {
|
|
8551
8572
|
const ac = new AbortController();
|
|
8552
8573
|
const t = setTimeout(() => ac.abort(), timeoutMs);
|
|
8553
8574
|
try {
|
|
8554
|
-
const res = await fetchImpl(`http://127.0.0.1:${port}${
|
|
8575
|
+
const res = await fetchImpl(`http://127.0.0.1:${port}${path43}`, { signal: ac.signal });
|
|
8555
8576
|
if (res.ok)
|
|
8556
8577
|
return true;
|
|
8557
8578
|
} catch {
|
|
@@ -9408,16 +9429,281 @@ var init_paths = __esm({
|
|
|
9408
9429
|
}
|
|
9409
9430
|
});
|
|
9410
9431
|
|
|
9411
|
-
// packages/core/dist/knowledge/
|
|
9432
|
+
// packages/core/dist/knowledge/ingest.js
|
|
9433
|
+
import crypto3 from "crypto";
|
|
9412
9434
|
import fs15 from "fs";
|
|
9413
9435
|
import os7 from "os";
|
|
9414
9436
|
import path16 from "path";
|
|
9437
|
+
import { execFile as execFile2 } from "child_process";
|
|
9438
|
+
import { promisify as promisify2 } from "util";
|
|
9439
|
+
function refFor(kbRoot, file) {
|
|
9440
|
+
const rel = path16.relative(kbRoot, file);
|
|
9441
|
+
if (rel && !rel.startsWith("..") && !path16.isAbsolute(rel))
|
|
9442
|
+
return rel.split(path16.sep).join("/");
|
|
9443
|
+
const home = os7.homedir();
|
|
9444
|
+
return file.startsWith(home + path16.sep) ? `~/${path16.relative(home, file).split(path16.sep).join("/")}` : file;
|
|
9445
|
+
}
|
|
9446
|
+
function readState2(kbRoot, ref) {
|
|
9447
|
+
try {
|
|
9448
|
+
return JSON.parse(fs15.readFileSync(stampFile(kbRoot, ref), "utf8"));
|
|
9449
|
+
} catch {
|
|
9450
|
+
return null;
|
|
9451
|
+
}
|
|
9452
|
+
}
|
|
9453
|
+
function writeState(kbRoot, st) {
|
|
9454
|
+
fs15.mkdirSync(path16.join(kbRoot, CONVERTED_DIR), { recursive: true });
|
|
9455
|
+
fs15.writeFileSync(stampFile(kbRoot, st.ref), JSON.stringify(st) + "\n");
|
|
9456
|
+
}
|
|
9457
|
+
function globToRegExp(glob) {
|
|
9458
|
+
let re = "";
|
|
9459
|
+
for (let i = 0; i < glob.length; i++) {
|
|
9460
|
+
const c = glob[i];
|
|
9461
|
+
if (c === "*") {
|
|
9462
|
+
if (glob[i + 1] === "*") {
|
|
9463
|
+
re += glob[i + 2] === "/" ? "(?:.*/)?" : ".*";
|
|
9464
|
+
i += glob[i + 2] === "/" ? 2 : 1;
|
|
9465
|
+
} else
|
|
9466
|
+
re += "[^/]*";
|
|
9467
|
+
} else if (c === "?")
|
|
9468
|
+
re += "[^/]";
|
|
9469
|
+
else
|
|
9470
|
+
re += c.replace(/[.+^${}()|[\]\\]/g, "\\$&");
|
|
9471
|
+
}
|
|
9472
|
+
return new RegExp(`^${re}$`);
|
|
9473
|
+
}
|
|
9474
|
+
function walkFiles(dir, out = []) {
|
|
9475
|
+
if (!fs15.existsSync(dir))
|
|
9476
|
+
return out;
|
|
9477
|
+
for (const ent of fs15.readdirSync(dir, { withFileTypes: true })) {
|
|
9478
|
+
if (ent.name === ".git" || ent.name === CONVERTED_DIR || ent.name === "node_modules")
|
|
9479
|
+
continue;
|
|
9480
|
+
const full = path16.join(dir, ent.name);
|
|
9481
|
+
if (ent.isDirectory())
|
|
9482
|
+
walkFiles(full, out);
|
|
9483
|
+
else if (ent.isFile())
|
|
9484
|
+
out.push(full);
|
|
9485
|
+
}
|
|
9486
|
+
return out;
|
|
9487
|
+
}
|
|
9488
|
+
function expandSource(kbRoot, entry) {
|
|
9489
|
+
const abs = path16.resolve(kbRoot, expandHome(entry.path));
|
|
9490
|
+
if (!/[*?]/.test(entry.path))
|
|
9491
|
+
return fs15.existsSync(abs) && fs15.statSync(abs).isFile() ? [abs] : [];
|
|
9492
|
+
const base = abs.split(/[*?]/)[0];
|
|
9493
|
+
const root = base.endsWith(path16.sep) ? base : path16.dirname(base);
|
|
9494
|
+
const re = globToRegExp(abs.split(path16.sep).join("/"));
|
|
9495
|
+
return walkFiles(root).filter((f) => re.test(f.split(path16.sep).join("/"))).sort();
|
|
9496
|
+
}
|
|
9497
|
+
function sourceCovers(kbRoot, entry, ref) {
|
|
9498
|
+
const abs = path16.resolve(kbRoot, expandHome(entry.path));
|
|
9499
|
+
const file = fileForRef(kbRoot, ref);
|
|
9500
|
+
return /[*?]/.test(entry.path) ? globToRegExp(abs.split(path16.sep).join("/")).test(file.split(path16.sep).join("/")) : abs === file;
|
|
9501
|
+
}
|
|
9502
|
+
function detectChange(kbRoot, file) {
|
|
9503
|
+
const ref = refFor(kbRoot, file);
|
|
9504
|
+
const st = fs15.statSync(file);
|
|
9505
|
+
const prior = readState2(kbRoot, ref);
|
|
9506
|
+
if (prior && prior.size === st.size && prior.mtimeMs === st.mtimeMs) {
|
|
9507
|
+
return { ref, changed: false, stamp: { sha: prior.sha, size: st.size, mtimeMs: st.mtimeMs }, prior };
|
|
9508
|
+
}
|
|
9509
|
+
const sha = sha256(file);
|
|
9510
|
+
return { ref, changed: !prior || prior.sha !== sha, stamp: { sha, size: st.size, mtimeMs: st.mtimeMs }, prior };
|
|
9511
|
+
}
|
|
9512
|
+
function splitSections(text) {
|
|
9513
|
+
const cuts = [];
|
|
9514
|
+
const re = /^#{1,6}[ \t]+(.+)$/gm;
|
|
9515
|
+
for (let m = re.exec(text); m; m = re.exec(text))
|
|
9516
|
+
cuts.push({ at: m.index, heading: m[1].trim() });
|
|
9517
|
+
if (!cuts.length || cuts[0].at > 0)
|
|
9518
|
+
cuts.unshift({ at: 0 });
|
|
9519
|
+
const spans = [];
|
|
9520
|
+
cuts.forEach((c, i) => {
|
|
9521
|
+
const end = i + 1 < cuts.length ? cuts[i + 1].at : text.length;
|
|
9522
|
+
let start = c.at;
|
|
9523
|
+
while (end - start > SECTION_TARGET_CHARS * 1.5) {
|
|
9524
|
+
const brk = text.indexOf("\n\n", start + SECTION_TARGET_CHARS);
|
|
9525
|
+
if (brk < 0 || brk >= end)
|
|
9526
|
+
break;
|
|
9527
|
+
spans.push({ index: 0, start, end: brk, heading: c.heading });
|
|
9528
|
+
start = brk + 2;
|
|
9529
|
+
}
|
|
9530
|
+
if (text.slice(start, end).trim())
|
|
9531
|
+
spans.push({ index: 0, start, end, heading: c.heading });
|
|
9532
|
+
});
|
|
9533
|
+
return spans.map((s, i) => ({ ...s, index: i }));
|
|
9534
|
+
}
|
|
9535
|
+
async function planIngest(kbRoot, opts) {
|
|
9536
|
+
const converter = opts.converter ?? markitdownConverter;
|
|
9537
|
+
const cap = opts.maxSectionsPerPass ?? DEFAULT_MAX_SECTIONS_PER_PASS;
|
|
9538
|
+
const plan = { sources: [], skipped: [], failed: [], carriedSections: 0, sectionCount: 0, estimatedTokens: 0, existing: opts.existing ?? [] };
|
|
9539
|
+
let budget = cap;
|
|
9540
|
+
const seen = /* @__PURE__ */ new Set();
|
|
9541
|
+
for (const entry of opts.sources) {
|
|
9542
|
+
for (const file of expandSource(kbRoot, entry)) {
|
|
9543
|
+
const { ref, changed, stamp, prior } = detectChange(kbRoot, file);
|
|
9544
|
+
if (seen.has(ref))
|
|
9545
|
+
continue;
|
|
9546
|
+
seen.add(ref);
|
|
9547
|
+
const pending = !!prior && prior.cursor < prior.sections;
|
|
9548
|
+
if (!changed && !pending)
|
|
9549
|
+
continue;
|
|
9550
|
+
if (entry.sensitivity === "local-only" && !opts.localModel) {
|
|
9551
|
+
plan.skipped.push({ ref, reason: "sensitivity: local-only and no local model available" });
|
|
9552
|
+
continue;
|
|
9553
|
+
}
|
|
9554
|
+
if (budget <= 0) {
|
|
9555
|
+
plan.carriedSections += changed ? 1 : prior.sections - prior.cursor;
|
|
9556
|
+
continue;
|
|
9557
|
+
}
|
|
9558
|
+
let text;
|
|
9559
|
+
const conv = convertedFile(kbRoot, ref);
|
|
9560
|
+
try {
|
|
9561
|
+
if (!changed && fs15.existsSync(conv))
|
|
9562
|
+
text = fs15.readFileSync(conv, "utf8");
|
|
9563
|
+
else {
|
|
9564
|
+
text = PASS_THROUGH.has(path16.extname(file).toLowerCase()) ? fs15.readFileSync(file, "utf8") : await converter(file);
|
|
9565
|
+
if (!opts.dryRun) {
|
|
9566
|
+
fs15.mkdirSync(path16.dirname(conv), { recursive: true });
|
|
9567
|
+
fs15.writeFileSync(conv, text);
|
|
9568
|
+
}
|
|
9569
|
+
}
|
|
9570
|
+
} catch (e) {
|
|
9571
|
+
plan.failed.push({ ref, error: e.message.split("\n")[0] });
|
|
9572
|
+
continue;
|
|
9573
|
+
}
|
|
9574
|
+
const all = splitSections(text);
|
|
9575
|
+
const from = changed ? 0 : prior.cursor;
|
|
9576
|
+
const take = all.slice(from, from + budget);
|
|
9577
|
+
budget -= take.length;
|
|
9578
|
+
plan.carriedSections += all.length - from - take.length;
|
|
9579
|
+
plan.sectionCount += take.length;
|
|
9580
|
+
plan.estimatedTokens += Math.ceil(take.reduce((n, s) => n + (s.end - s.start), 0) / CHARS_PER_TOKEN);
|
|
9581
|
+
plan.sources.push({
|
|
9582
|
+
ref,
|
|
9583
|
+
file,
|
|
9584
|
+
converted: conv,
|
|
9585
|
+
sha: stamp.sha,
|
|
9586
|
+
priority: entry.priority,
|
|
9587
|
+
domain: entry.domain,
|
|
9588
|
+
sensitivity: entry.sensitivity,
|
|
9589
|
+
sections: take,
|
|
9590
|
+
totalSections: all.length
|
|
9591
|
+
});
|
|
9592
|
+
if (!opts.dryRun)
|
|
9593
|
+
writeState(kbRoot, { ref, ...stamp, sections: all.length, cursor: from + take.length, priority: entry.priority });
|
|
9594
|
+
}
|
|
9595
|
+
}
|
|
9596
|
+
return plan;
|
|
9597
|
+
}
|
|
9598
|
+
var execFileAsync, CONVERTED_DIR, DEFAULT_MAX_SECTIONS_PER_PASS, CHARS_PER_TOKEN, PASS_THROUGH, SECTION_TARGET_CHARS, markitdownConverter, expandHome, fileForRef, cacheKey, convertedFile, stampFile, isGatedRef, sha256;
|
|
9599
|
+
var init_ingest = __esm({
|
|
9600
|
+
"packages/core/dist/knowledge/ingest.js"() {
|
|
9601
|
+
execFileAsync = promisify2(execFile2);
|
|
9602
|
+
CONVERTED_DIR = ".converted";
|
|
9603
|
+
DEFAULT_MAX_SECTIONS_PER_PASS = 40;
|
|
9604
|
+
CHARS_PER_TOKEN = 4;
|
|
9605
|
+
PASS_THROUGH = /* @__PURE__ */ new Set([".md", ".markdown", ".txt"]);
|
|
9606
|
+
SECTION_TARGET_CHARS = 4e3;
|
|
9607
|
+
markitdownConverter = async (file) => {
|
|
9608
|
+
const { stdout } = await execFileAsync("markitdown", [file], { maxBuffer: 64 * 1024 * 1024 });
|
|
9609
|
+
return stdout;
|
|
9610
|
+
};
|
|
9611
|
+
expandHome = (p) => p === "~" || p.startsWith("~/") ? path16.join(os7.homedir(), p.slice(1)) : p;
|
|
9612
|
+
fileForRef = (kbRoot, ref) => path16.resolve(kbRoot, expandHome(ref));
|
|
9613
|
+
cacheKey = (ref) => `${ref.replace(/[^A-Za-z0-9._-]+/g, "_")}.${crypto3.createHash("sha1").update(ref).digest("hex").slice(0, 6)}`;
|
|
9614
|
+
convertedFile = (kbRoot, ref) => path16.join(kbRoot, CONVERTED_DIR, `${cacheKey(ref)}.md`);
|
|
9615
|
+
stampFile = (kbRoot, ref) => path16.join(kbRoot, CONVERTED_DIR, `${cacheKey(ref)}.sha`);
|
|
9616
|
+
isGatedRef = (kbRoot, sources, ref) => sources.some((e) => e.review === "required" && sourceCovers(kbRoot, e, ref));
|
|
9617
|
+
sha256 = (file) => crypto3.createHash("sha256").update(fs15.readFileSync(file)).digest("hex");
|
|
9618
|
+
}
|
|
9619
|
+
});
|
|
9620
|
+
|
|
9621
|
+
// packages/core/dist/knowledge/verify.js
|
|
9622
|
+
function normalizeWithMap(src, keepBreakHyphen = false) {
|
|
9623
|
+
const out = [];
|
|
9624
|
+
const map2 = [];
|
|
9625
|
+
const push = (s, at) => {
|
|
9626
|
+
for (const ch of s) {
|
|
9627
|
+
out.push(ch);
|
|
9628
|
+
map2.push(at);
|
|
9629
|
+
}
|
|
9630
|
+
};
|
|
9631
|
+
let i = 0;
|
|
9632
|
+
while (i < src.length) {
|
|
9633
|
+
const ch = src[i];
|
|
9634
|
+
if (ch === "-" && /^-[ \t]*\r?\n[ \t]*[a-z]/.test(src.slice(i, i + 40)) && i > 0 && /[A-Za-z]/.test(src[i - 1])) {
|
|
9635
|
+
if (keepBreakHyphen)
|
|
9636
|
+
push("-", i);
|
|
9637
|
+
i++;
|
|
9638
|
+
while (/\s/.test(src[i]))
|
|
9639
|
+
i++;
|
|
9640
|
+
continue;
|
|
9641
|
+
}
|
|
9642
|
+
if (/\s/.test(ch)) {
|
|
9643
|
+
const start = i;
|
|
9644
|
+
while (i < src.length && /\s/.test(src[i]))
|
|
9645
|
+
i++;
|
|
9646
|
+
if (out.length && out[out.length - 1] !== " ")
|
|
9647
|
+
push(" ", start);
|
|
9648
|
+
continue;
|
|
9649
|
+
}
|
|
9650
|
+
if (MARKUP.has(ch)) {
|
|
9651
|
+
i++;
|
|
9652
|
+
continue;
|
|
9653
|
+
}
|
|
9654
|
+
if (LIGATURES[ch])
|
|
9655
|
+
push(LIGATURES[ch], i);
|
|
9656
|
+
else if (QUOTES[ch])
|
|
9657
|
+
push(QUOTES[ch], i);
|
|
9658
|
+
else if (DASHES.has(ch))
|
|
9659
|
+
push("-", i);
|
|
9660
|
+
else
|
|
9661
|
+
push(ch, i);
|
|
9662
|
+
i++;
|
|
9663
|
+
}
|
|
9664
|
+
while (out.length && out[out.length - 1] === " ") {
|
|
9665
|
+
out.pop();
|
|
9666
|
+
map2.pop();
|
|
9667
|
+
}
|
|
9668
|
+
return { text: out.join(""), map: map2 };
|
|
9669
|
+
}
|
|
9670
|
+
function findQuote(source, quote) {
|
|
9671
|
+
const needle = normalizeText(quote);
|
|
9672
|
+
if (!needle)
|
|
9673
|
+
return null;
|
|
9674
|
+
const views = typeof source === "string" ? normalizedViews(source) : source;
|
|
9675
|
+
for (const hay of views) {
|
|
9676
|
+
const at = hay.text.indexOf(needle);
|
|
9677
|
+
if (at >= 0)
|
|
9678
|
+
return [hay.map[at], hay.map[at + needle.length - 1] + 1];
|
|
9679
|
+
}
|
|
9680
|
+
return null;
|
|
9681
|
+
}
|
|
9682
|
+
var LIGATURES, QUOTES, DASHES, MARKUP, normalizeText, normalizedViews, DOCLING_DROP_THRESHOLD, needsDocling, spansOverlap;
|
|
9683
|
+
var init_verify = __esm({
|
|
9684
|
+
"packages/core/dist/knowledge/verify.js"() {
|
|
9685
|
+
LIGATURES = { "\uFB01": "fi", "\uFB02": "fl", "\uFB00": "ff", "\uFB03": "ffi", "\uFB04": "ffl", "\uFB05": "st", "\uFB06": "st" };
|
|
9686
|
+
QUOTES = { "\u2018": "'", "\u2019": "'", "\u201A": "'", "\u201B": "'", "\u201C": '"', "\u201D": '"', "\u201E": '"', "\u201F": '"' };
|
|
9687
|
+
DASHES = /* @__PURE__ */ new Set(["\u2010", "\u2011", "\u2012", "\u2013", "\u2014", "\u2015", "\u2212"]);
|
|
9688
|
+
MARKUP = /* @__PURE__ */ new Set(["*", "_", "`", "\\"]);
|
|
9689
|
+
normalizeText = (s) => normalizeWithMap(s).text;
|
|
9690
|
+
normalizedViews = (src) => [normalizeWithMap(src), normalizeWithMap(src, true)];
|
|
9691
|
+
DOCLING_DROP_THRESHOLD = 0.2;
|
|
9692
|
+
needsDocling = (dropped, total) => total > 0 && dropped / total > DOCLING_DROP_THRESHOLD;
|
|
9693
|
+
spansOverlap = (a, b) => a[0] < b[1] && b[0] < a[1];
|
|
9694
|
+
}
|
|
9695
|
+
});
|
|
9696
|
+
|
|
9697
|
+
// packages/core/dist/knowledge/store.js
|
|
9698
|
+
import fs16 from "fs";
|
|
9699
|
+
import os8 from "os";
|
|
9700
|
+
import path17 from "path";
|
|
9415
9701
|
import matter2 from "gray-matter";
|
|
9416
9702
|
function duplicateIdProblem(id, ignored, used) {
|
|
9417
9703
|
return `duplicate id ${id}: ${ignored} is ignored, ${used} is used (live files win over _proposed, then path order). Fix: rename the id in one file, or delete or move one of them.`;
|
|
9418
9704
|
}
|
|
9419
9705
|
function isPendingProposalDup(e, rulesDir) {
|
|
9420
|
-
return e.problems.every((p) => p.startsWith("duplicate id")) &&
|
|
9706
|
+
return e.problems.every((p) => p.startsWith("duplicate id")) && path17.relative(rulesDir, e.file).split(path17.sep).includes(PROPOSED_DIR);
|
|
9421
9707
|
}
|
|
9422
9708
|
function splitStatement(body) {
|
|
9423
9709
|
const first = body.trim().split(/\n\s*\n/)[0] ?? "";
|
|
@@ -9426,8 +9712,8 @@ function splitStatement(body) {
|
|
|
9426
9712
|
function listMarkdown(dir, includeProposed) {
|
|
9427
9713
|
const out = [];
|
|
9428
9714
|
const walk = (d) => {
|
|
9429
|
-
for (const ent of
|
|
9430
|
-
const full =
|
|
9715
|
+
for (const ent of fs16.readdirSync(d, { withFileTypes: true })) {
|
|
9716
|
+
const full = path17.join(d, ent.name);
|
|
9431
9717
|
if (ent.isDirectory()) {
|
|
9432
9718
|
if (ent.name === PROPOSED_DIR && !includeProposed)
|
|
9433
9719
|
continue;
|
|
@@ -9438,11 +9724,11 @@ function listMarkdown(dir, includeProposed) {
|
|
|
9438
9724
|
}
|
|
9439
9725
|
};
|
|
9440
9726
|
walk(dir);
|
|
9441
|
-
const isProposed = (f) =>
|
|
9727
|
+
const isProposed = (f) => path17.relative(dir, f).split(path17.sep).includes(PROPOSED_DIR);
|
|
9442
9728
|
return out.sort((a, b) => Number(isProposed(a)) - Number(isProposed(b)) || (a < b ? -1 : a > b ? 1 : 0));
|
|
9443
9729
|
}
|
|
9444
9730
|
function loadRulesDir(dir, layer, opts = {}) {
|
|
9445
|
-
if (!
|
|
9731
|
+
if (!fs16.existsSync(dir))
|
|
9446
9732
|
return { rules: [], errors: [] };
|
|
9447
9733
|
const rules = [];
|
|
9448
9734
|
const errors = [];
|
|
@@ -9450,7 +9736,7 @@ function loadRulesDir(dir, layer, opts = {}) {
|
|
|
9450
9736
|
for (const file of listMarkdown(dir, opts.includeProposed ?? false)) {
|
|
9451
9737
|
let parsed;
|
|
9452
9738
|
try {
|
|
9453
|
-
parsed = matter2(
|
|
9739
|
+
parsed = matter2(fs16.readFileSync(file, "utf8"), NO_JS_FRONTMATTER);
|
|
9454
9740
|
} catch (e) {
|
|
9455
9741
|
errors.push({ file, problems: [`frontmatter parse error: ${e.message}`] });
|
|
9456
9742
|
continue;
|
|
@@ -9474,14 +9760,14 @@ function loadRulesDir(dir, layer, opts = {}) {
|
|
|
9474
9760
|
function resolveSourceRef(ref, kbRoot, sources) {
|
|
9475
9761
|
const bases = /* @__PURE__ */ new Set([kbRoot]);
|
|
9476
9762
|
for (const s of sources) {
|
|
9477
|
-
let d =
|
|
9478
|
-
for (let i = 0; i < 6 && d !==
|
|
9479
|
-
d =
|
|
9763
|
+
let d = path17.resolve(kbRoot, expandHome2(s.path.split(/[*?[{]/)[0]));
|
|
9764
|
+
for (let i = 0; i < 6 && d !== path17.dirname(d); i++) {
|
|
9765
|
+
d = path17.dirname(d);
|
|
9480
9766
|
bases.add(d);
|
|
9481
9767
|
}
|
|
9482
9768
|
}
|
|
9483
|
-
const cands = [
|
|
9484
|
-
return cands.find((c) =>
|
|
9769
|
+
const cands = [path17.resolve(kbRoot, expandHome2(ref)), ...[...bases].map((b) => path17.join(b, ref))];
|
|
9770
|
+
return cands.find((c) => fs16.existsSync(c) && fs16.statSync(c).isFile());
|
|
9485
9771
|
}
|
|
9486
9772
|
function validateKb(opts) {
|
|
9487
9773
|
const { rules, errors } = loadRulesDir(opts.rulesDir, "kb", { includeProposed: true });
|
|
@@ -9489,7 +9775,7 @@ function validateKb(opts) {
|
|
|
9489
9775
|
const dups = errors.filter((e) => e.problems.some((p) => p.startsWith("duplicate id")) && !isPendingProposalDup(e, opts.rulesDir));
|
|
9490
9776
|
const pendingDups = errors.filter((e) => isPendingProposalDup(e, opts.rulesDir)).length;
|
|
9491
9777
|
const invalid = errors.filter((e) => !dups.includes(e) && !isPendingProposalDup(e, opts.rulesDir));
|
|
9492
|
-
const proposed = rules.filter((r) =>
|
|
9778
|
+
const proposed = rules.filter((r) => path17.relative(opts.rulesDir, r.file).split(path17.sep).includes(PROPOSED_DIR)).length;
|
|
9493
9779
|
checks.push({ level: "ok", message: `${rules.length + errors.length} rule files read (${rules.length - proposed} live, ${proposed + pendingDups} proposed parsed OK)` });
|
|
9494
9780
|
if (invalid.length)
|
|
9495
9781
|
for (const e of invalid)
|
|
@@ -9502,7 +9788,7 @@ function validateKb(opts) {
|
|
|
9502
9788
|
else
|
|
9503
9789
|
checks.push({ level: "ok", message: "no duplicate ids" });
|
|
9504
9790
|
const cache = /* @__PURE__ */ new Map();
|
|
9505
|
-
let verified = 0, unresolved = 0;
|
|
9791
|
+
let verified = 0, unresolved = 0, notIngested = 0;
|
|
9506
9792
|
for (const r of rules) {
|
|
9507
9793
|
r.sources.forEach((src, i) => {
|
|
9508
9794
|
const file = resolveSourceRef(src.ref, opts.kbRoot, opts.sources);
|
|
@@ -9510,16 +9796,33 @@ function validateKb(opts) {
|
|
|
9510
9796
|
unresolved++;
|
|
9511
9797
|
return;
|
|
9512
9798
|
}
|
|
9513
|
-
|
|
9514
|
-
|
|
9515
|
-
|
|
9799
|
+
const key = `${src.ref}\0${file}`;
|
|
9800
|
+
if (!cache.has(key)) {
|
|
9801
|
+
const conv = readState2(opts.kbRoot, src.ref) ? convertedFile(opts.kbRoot, src.ref) : null;
|
|
9802
|
+
const cached = !!conv && fs16.existsSync(conv);
|
|
9803
|
+
cache.set(key, {
|
|
9804
|
+
hay: normalizedViews(fs16.readFileSync(cached ? conv : file, "utf8")),
|
|
9805
|
+
convertible: !cached && !PASS_THROUGH.has(path17.extname(file).toLowerCase())
|
|
9806
|
+
});
|
|
9807
|
+
}
|
|
9808
|
+
const { hay, convertible } = cache.get(key);
|
|
9809
|
+
const span = findQuote(hay, src.quote);
|
|
9810
|
+
if (span) {
|
|
9516
9811
|
verified++;
|
|
9812
|
+
const active = r.status === "active" && !path17.relative(opts.rulesDir, r.file).split(path17.sep).includes(PROPOSED_DIR);
|
|
9813
|
+
const err = active ? (opts.errata ?? []).find((e) => e.ref === src.ref && ((o) => !!o && spansOverlap(o, span))(findQuote(hay, e.quote))) : void 0;
|
|
9814
|
+
if (err)
|
|
9815
|
+
checks.push({ level: "warn", message: `${r.id}: grounded in erratum ${err.id} (${err.reason}); re-check or retire it (${r.file})` });
|
|
9816
|
+
} else if (convertible)
|
|
9817
|
+
notIngested++;
|
|
9517
9818
|
else
|
|
9518
9819
|
checks.push({ level: "fail", message: `quote not found in ${file}: ${r.id} sources[${i}] (${r.file})` });
|
|
9519
9820
|
});
|
|
9520
9821
|
}
|
|
9521
9822
|
if (!checks.some((c) => c.message.startsWith("quote not found")))
|
|
9522
9823
|
checks.push({ level: "ok", message: `${verified} source quotes found in their source files` });
|
|
9824
|
+
if (notIngested)
|
|
9825
|
+
checks.push({ level: "skip", message: `${notIngested} source refs need conversion but have no .converted cache, quote not checked (run \`squadrant knowledge ingest <kb>\`)` });
|
|
9523
9826
|
if (unresolved)
|
|
9524
9827
|
checks.push({ level: "skip", message: `${unresolved} source refs not resolvable on this machine, quote not checked` });
|
|
9525
9828
|
if (opts.domains) {
|
|
@@ -9530,22 +9833,24 @@ function validateKb(opts) {
|
|
|
9530
9833
|
}
|
|
9531
9834
|
return { checks, ok: !checks.some((c) => c.level === "fail") };
|
|
9532
9835
|
}
|
|
9533
|
-
var NO_JS_FRONTMATTER,
|
|
9836
|
+
var NO_JS_FRONTMATTER, expandHome2;
|
|
9534
9837
|
var init_store2 = __esm({
|
|
9535
9838
|
"packages/core/dist/knowledge/store.js"() {
|
|
9536
9839
|
init_dist();
|
|
9840
|
+
init_ingest();
|
|
9537
9841
|
init_paths();
|
|
9842
|
+
init_verify();
|
|
9538
9843
|
NO_JS_FRONTMATTER = {
|
|
9539
9844
|
engines: { javascript: { parse: () => {
|
|
9540
9845
|
throw new Error("only YAML front matter is allowed");
|
|
9541
9846
|
} } }
|
|
9542
9847
|
};
|
|
9543
|
-
|
|
9848
|
+
expandHome2 = (p) => p === "~" || p.startsWith("~/") ? path17.join(os8.homedir(), p.slice(1)) : p;
|
|
9544
9849
|
}
|
|
9545
9850
|
});
|
|
9546
9851
|
|
|
9547
9852
|
// packages/core/dist/knowledge/layers.js
|
|
9548
|
-
import
|
|
9853
|
+
import fs17 from "fs";
|
|
9549
9854
|
function loadKbRules(cfg, kb, opts = {}) {
|
|
9550
9855
|
return loadRulesDir(kbRulesDir(cfg, kb), `kb:${kb}`, opts);
|
|
9551
9856
|
}
|
|
@@ -9557,7 +9862,7 @@ function resolveProjectRules(cfg, project, opts = {}) {
|
|
|
9557
9862
|
const errors = [];
|
|
9558
9863
|
const warnings = [];
|
|
9559
9864
|
for (const kb of subscribedKbs(cfg, project)) {
|
|
9560
|
-
if (!
|
|
9865
|
+
if (!fs17.existsSync(kbDir(cfg, kb))) {
|
|
9561
9866
|
warnings.push(`knowledge base '${kb}' not found (run: squadrant knowledge init ${kb})`);
|
|
9562
9867
|
continue;
|
|
9563
9868
|
}
|
|
@@ -9595,8 +9900,8 @@ var init_layers = __esm({
|
|
|
9595
9900
|
});
|
|
9596
9901
|
|
|
9597
9902
|
// packages/core/dist/knowledge/index-file.js
|
|
9598
|
-
import
|
|
9599
|
-
import
|
|
9903
|
+
import fs18 from "fs";
|
|
9904
|
+
import path18 from "path";
|
|
9600
9905
|
function compileIndex(kb, rules, now = /* @__PURE__ */ new Date()) {
|
|
9601
9906
|
return {
|
|
9602
9907
|
kb,
|
|
@@ -9605,18 +9910,18 @@ function compileIndex(kb, rules, now = /* @__PURE__ */ new Date()) {
|
|
|
9605
9910
|
};
|
|
9606
9911
|
}
|
|
9607
9912
|
function writeIndex(kbRoot, index) {
|
|
9608
|
-
const file =
|
|
9913
|
+
const file = path18.join(kbRoot, "index.json");
|
|
9609
9914
|
const tmp = `${file}.tmp-${process.pid}`;
|
|
9610
|
-
|
|
9611
|
-
|
|
9915
|
+
fs18.writeFileSync(tmp, JSON.stringify(index, null, 2) + "\n");
|
|
9916
|
+
fs18.renameSync(tmp, file);
|
|
9612
9917
|
return file;
|
|
9613
9918
|
}
|
|
9614
9919
|
function readIndex(kbRoot, kb) {
|
|
9615
|
-
const file =
|
|
9616
|
-
if (!
|
|
9920
|
+
const file = path18.join(kbRoot, "index.json");
|
|
9921
|
+
if (!fs18.existsSync(file))
|
|
9617
9922
|
return { index: null, problem: `index.json missing for kb '${kb}'` };
|
|
9618
9923
|
try {
|
|
9619
|
-
const index = JSON.parse(
|
|
9924
|
+
const index = JSON.parse(fs18.readFileSync(file, "utf8"));
|
|
9620
9925
|
if (!Array.isArray(index.rules))
|
|
9621
9926
|
return { index: null, problem: `index.json corrupt for kb '${kb}' (no rules array)` };
|
|
9622
9927
|
return { index };
|
|
@@ -12711,15 +13016,16 @@ var init_js_yaml = __esm({
|
|
|
12711
13016
|
});
|
|
12712
13017
|
|
|
12713
13018
|
// packages/core/dist/knowledge/sources.js
|
|
12714
|
-
import
|
|
12715
|
-
import
|
|
12716
|
-
|
|
12717
|
-
|
|
12718
|
-
|
|
13019
|
+
import fs19 from "fs";
|
|
13020
|
+
import path19 from "path";
|
|
13021
|
+
import matter3 from "gray-matter";
|
|
13022
|
+
function loadSources(kbRoot) {
|
|
13023
|
+
const file = path19.join(kbRoot, "sources.yaml");
|
|
13024
|
+
if (!fs19.existsSync(file))
|
|
12719
13025
|
return { sources: [], errors: [] };
|
|
12720
13026
|
let data;
|
|
12721
13027
|
try {
|
|
12722
|
-
data = yaml.load(
|
|
13028
|
+
data = yaml.load(fs19.readFileSync(file, "utf8"));
|
|
12723
13029
|
} catch (e) {
|
|
12724
13030
|
return { sources: [], errors: [`YAML parse error: ${e.message.split("\n")[0]}`] };
|
|
12725
13031
|
}
|
|
@@ -12738,208 +13044,82 @@ function loadSources(kbRoot) {
|
|
|
12738
13044
|
});
|
|
12739
13045
|
return { sources, errors };
|
|
12740
13046
|
}
|
|
13047
|
+
function dropEntryBlock(text, entryPath) {
|
|
13048
|
+
const lines = text.split("\n");
|
|
13049
|
+
const q = entryPath.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
13050
|
+
const head = new RegExp(`^-\\s+path:\\s*(['"]?)${q}\\1\\s*(#.*)?$`);
|
|
13051
|
+
const i = lines.findIndex((l) => head.test(l));
|
|
13052
|
+
if (i < 0)
|
|
13053
|
+
return null;
|
|
13054
|
+
let j = i + 1;
|
|
13055
|
+
while (j < lines.length && /^\s+\S/.test(lines[j]))
|
|
13056
|
+
j++;
|
|
13057
|
+
return [...lines.slice(0, i), ...lines.slice(j)].join("\n");
|
|
13058
|
+
}
|
|
13059
|
+
function removeSource(kbRoot, rulesDir, entryPath, opts = {}) {
|
|
13060
|
+
const file = path19.join(kbRoot, "sources.yaml");
|
|
13061
|
+
const { sources } = loadSources(kbRoot);
|
|
13062
|
+
const entry = sources.find((s) => s.path === entryPath);
|
|
13063
|
+
if (!entry)
|
|
13064
|
+
throw new Error(`no sources.yaml entry with path '${entryPath}' (give it exactly as listed by \`knowledge sources\`)`);
|
|
13065
|
+
const edited = dropEntryBlock(fs19.readFileSync(file, "utf8"), entryPath);
|
|
13066
|
+
if (edited === null)
|
|
13067
|
+
throw new Error(`could not edit sources.yaml for '${entryPath}' (not a plain block entry); remove it by hand, then rerun to strip the refs`);
|
|
13068
|
+
const res = { dryRun: !!opts.dryRun, entryRemoved: true, stripped: [], stale: [] };
|
|
13069
|
+
const writes = [];
|
|
13070
|
+
for (const rule of loadRulesDir(rulesDir, "kb").rules) {
|
|
13071
|
+
const kept = rule.sources.filter((s) => !sourceCovers(kbRoot, entry, s.ref));
|
|
13072
|
+
if (kept.length === rule.sources.length)
|
|
13073
|
+
continue;
|
|
13074
|
+
res.stripped.push(rule.id);
|
|
13075
|
+
const parsed = matter3(fs19.readFileSync(rule.file, "utf8"), { engines: { javascript: () => {
|
|
13076
|
+
throw new Error("only YAML front matter is allowed");
|
|
13077
|
+
} } });
|
|
13078
|
+
const fm = { ...parsed.data, sources: kept };
|
|
13079
|
+
if (!kept.length) {
|
|
13080
|
+
res.stale.push(rule.id);
|
|
13081
|
+
if (fm.status === "active")
|
|
13082
|
+
fm.status = "stale";
|
|
13083
|
+
}
|
|
13084
|
+
writes.push({ file: rule.file, text: matter3.stringify(parsed.content, JSON.parse(JSON.stringify(fm))) });
|
|
13085
|
+
}
|
|
13086
|
+
res.stripped.sort();
|
|
13087
|
+
res.stale.sort();
|
|
13088
|
+
if (opts.dryRun)
|
|
13089
|
+
return res;
|
|
13090
|
+
for (const w of writes)
|
|
13091
|
+
fs19.writeFileSync(w.file, w.text);
|
|
13092
|
+
fs19.writeFileSync(file, edited);
|
|
13093
|
+
const name = opts.kbName ?? path19.basename(kbRoot);
|
|
13094
|
+
writeIndex(kbRoot, compileIndex(name, loadRulesDir(rulesDir, `kb:${name}`).rules));
|
|
13095
|
+
return res;
|
|
13096
|
+
}
|
|
12741
13097
|
var SOURCES_TEMPLATE;
|
|
12742
13098
|
var init_sources = __esm({
|
|
12743
13099
|
"packages/core/dist/knowledge/sources.js"() {
|
|
12744
13100
|
init_js_yaml();
|
|
12745
13101
|
init_dist();
|
|
13102
|
+
init_index_file();
|
|
13103
|
+
init_ingest();
|
|
13104
|
+
init_store2();
|
|
12746
13105
|
SOURCES_TEMPLATE = `# Trusted sources for this knowledge base (spec \xA73). Only these can produce rules.
|
|
12747
13106
|
# priority: company > project > agent (decides conflicts).
|
|
12748
13107
|
# sensitivity: local-only \u2192 never sent to a hosted model (D12).
|
|
13108
|
+
# review: required \u2192 new rules from this source wait in rules/_proposed/ for the operator; they never go live on their own.
|
|
12749
13109
|
#
|
|
12750
13110
|
# - path: raw/finance/**
|
|
12751
13111
|
# priority: company
|
|
12752
13112
|
# - path: ~/work/flooros/docs/handbook/**
|
|
12753
13113
|
# priority: project
|
|
12754
13114
|
# domain: coding
|
|
13115
|
+
# - path: raw/**
|
|
13116
|
+
# priority: agent
|
|
13117
|
+
# review: required
|
|
12755
13118
|
[]
|
|
12756
13119
|
`;
|
|
12757
13120
|
}
|
|
12758
13121
|
});
|
|
12759
13122
|
|
|
12760
|
-
// packages/core/dist/knowledge/ingest.js
|
|
12761
|
-
import crypto3 from "crypto";
|
|
12762
|
-
import fs19 from "fs";
|
|
12763
|
-
import os8 from "os";
|
|
12764
|
-
import path19 from "path";
|
|
12765
|
-
import { execFile as execFile2 } from "child_process";
|
|
12766
|
-
import { promisify as promisify2 } from "util";
|
|
12767
|
-
function refFor(kbRoot, file) {
|
|
12768
|
-
const rel = path19.relative(kbRoot, file);
|
|
12769
|
-
if (rel && !rel.startsWith("..") && !path19.isAbsolute(rel))
|
|
12770
|
-
return rel.split(path19.sep).join("/");
|
|
12771
|
-
const home = os8.homedir();
|
|
12772
|
-
return file.startsWith(home + path19.sep) ? `~/${path19.relative(home, file).split(path19.sep).join("/")}` : file;
|
|
12773
|
-
}
|
|
12774
|
-
function readState2(kbRoot, ref) {
|
|
12775
|
-
try {
|
|
12776
|
-
return JSON.parse(fs19.readFileSync(stampFile(kbRoot, ref), "utf8"));
|
|
12777
|
-
} catch {
|
|
12778
|
-
return null;
|
|
12779
|
-
}
|
|
12780
|
-
}
|
|
12781
|
-
function writeState(kbRoot, st) {
|
|
12782
|
-
fs19.mkdirSync(path19.join(kbRoot, CONVERTED_DIR), { recursive: true });
|
|
12783
|
-
fs19.writeFileSync(stampFile(kbRoot, st.ref), JSON.stringify(st) + "\n");
|
|
12784
|
-
}
|
|
12785
|
-
function globToRegExp(glob) {
|
|
12786
|
-
let re = "";
|
|
12787
|
-
for (let i = 0; i < glob.length; i++) {
|
|
12788
|
-
const c = glob[i];
|
|
12789
|
-
if (c === "*") {
|
|
12790
|
-
if (glob[i + 1] === "*") {
|
|
12791
|
-
re += glob[i + 2] === "/" ? "(?:.*/)?" : ".*";
|
|
12792
|
-
i += glob[i + 2] === "/" ? 2 : 1;
|
|
12793
|
-
} else
|
|
12794
|
-
re += "[^/]*";
|
|
12795
|
-
} else if (c === "?")
|
|
12796
|
-
re += "[^/]";
|
|
12797
|
-
else
|
|
12798
|
-
re += c.replace(/[.+^${}()|[\]\\]/g, "\\$&");
|
|
12799
|
-
}
|
|
12800
|
-
return new RegExp(`^${re}$`);
|
|
12801
|
-
}
|
|
12802
|
-
function walkFiles(dir, out = []) {
|
|
12803
|
-
if (!fs19.existsSync(dir))
|
|
12804
|
-
return out;
|
|
12805
|
-
for (const ent of fs19.readdirSync(dir, { withFileTypes: true })) {
|
|
12806
|
-
if (ent.name === ".git" || ent.name === CONVERTED_DIR || ent.name === "node_modules")
|
|
12807
|
-
continue;
|
|
12808
|
-
const full = path19.join(dir, ent.name);
|
|
12809
|
-
if (ent.isDirectory())
|
|
12810
|
-
walkFiles(full, out);
|
|
12811
|
-
else if (ent.isFile())
|
|
12812
|
-
out.push(full);
|
|
12813
|
-
}
|
|
12814
|
-
return out;
|
|
12815
|
-
}
|
|
12816
|
-
function expandSource(kbRoot, entry) {
|
|
12817
|
-
const abs = path19.resolve(kbRoot, expandHome2(entry.path));
|
|
12818
|
-
if (!/[*?]/.test(entry.path))
|
|
12819
|
-
return fs19.existsSync(abs) && fs19.statSync(abs).isFile() ? [abs] : [];
|
|
12820
|
-
const base = abs.split(/[*?]/)[0];
|
|
12821
|
-
const root = base.endsWith(path19.sep) ? base : path19.dirname(base);
|
|
12822
|
-
const re = globToRegExp(abs.split(path19.sep).join("/"));
|
|
12823
|
-
return walkFiles(root).filter((f) => re.test(f.split(path19.sep).join("/"))).sort();
|
|
12824
|
-
}
|
|
12825
|
-
function detectChange(kbRoot, file) {
|
|
12826
|
-
const ref = refFor(kbRoot, file);
|
|
12827
|
-
const st = fs19.statSync(file);
|
|
12828
|
-
const prior = readState2(kbRoot, ref);
|
|
12829
|
-
if (prior && prior.size === st.size && prior.mtimeMs === st.mtimeMs) {
|
|
12830
|
-
return { ref, changed: false, stamp: { sha: prior.sha, size: st.size, mtimeMs: st.mtimeMs }, prior };
|
|
12831
|
-
}
|
|
12832
|
-
const sha = sha256(file);
|
|
12833
|
-
return { ref, changed: !prior || prior.sha !== sha, stamp: { sha, size: st.size, mtimeMs: st.mtimeMs }, prior };
|
|
12834
|
-
}
|
|
12835
|
-
function splitSections(text) {
|
|
12836
|
-
const cuts = [];
|
|
12837
|
-
const re = /^#{1,6}[ \t]+(.+)$/gm;
|
|
12838
|
-
for (let m = re.exec(text); m; m = re.exec(text))
|
|
12839
|
-
cuts.push({ at: m.index, heading: m[1].trim() });
|
|
12840
|
-
if (!cuts.length || cuts[0].at > 0)
|
|
12841
|
-
cuts.unshift({ at: 0 });
|
|
12842
|
-
const spans = [];
|
|
12843
|
-
cuts.forEach((c, i) => {
|
|
12844
|
-
const end = i + 1 < cuts.length ? cuts[i + 1].at : text.length;
|
|
12845
|
-
let start = c.at;
|
|
12846
|
-
while (end - start > SECTION_TARGET_CHARS * 1.5) {
|
|
12847
|
-
const brk = text.indexOf("\n\n", start + SECTION_TARGET_CHARS);
|
|
12848
|
-
if (brk < 0 || brk >= end)
|
|
12849
|
-
break;
|
|
12850
|
-
spans.push({ index: 0, start, end: brk, heading: c.heading });
|
|
12851
|
-
start = brk + 2;
|
|
12852
|
-
}
|
|
12853
|
-
if (text.slice(start, end).trim())
|
|
12854
|
-
spans.push({ index: 0, start, end, heading: c.heading });
|
|
12855
|
-
});
|
|
12856
|
-
return spans.map((s, i) => ({ ...s, index: i }));
|
|
12857
|
-
}
|
|
12858
|
-
async function planIngest(kbRoot, opts) {
|
|
12859
|
-
const converter = opts.converter ?? markitdownConverter;
|
|
12860
|
-
const cap = opts.maxSectionsPerPass ?? DEFAULT_MAX_SECTIONS_PER_PASS;
|
|
12861
|
-
const plan = { sources: [], skipped: [], failed: [], carriedSections: 0, sectionCount: 0, estimatedTokens: 0, existing: opts.existing ?? [] };
|
|
12862
|
-
let budget = cap;
|
|
12863
|
-
const seen = /* @__PURE__ */ new Set();
|
|
12864
|
-
for (const entry of opts.sources) {
|
|
12865
|
-
for (const file of expandSource(kbRoot, entry)) {
|
|
12866
|
-
const { ref, changed, stamp, prior } = detectChange(kbRoot, file);
|
|
12867
|
-
if (seen.has(ref))
|
|
12868
|
-
continue;
|
|
12869
|
-
seen.add(ref);
|
|
12870
|
-
const pending = !!prior && prior.cursor < prior.sections;
|
|
12871
|
-
if (!changed && !pending)
|
|
12872
|
-
continue;
|
|
12873
|
-
if (entry.sensitivity === "local-only" && !opts.localModel) {
|
|
12874
|
-
plan.skipped.push({ ref, reason: "sensitivity: local-only and no local model available" });
|
|
12875
|
-
continue;
|
|
12876
|
-
}
|
|
12877
|
-
if (budget <= 0) {
|
|
12878
|
-
plan.carriedSections += changed ? 1 : prior.sections - prior.cursor;
|
|
12879
|
-
continue;
|
|
12880
|
-
}
|
|
12881
|
-
let text;
|
|
12882
|
-
const conv = convertedFile(kbRoot, ref);
|
|
12883
|
-
try {
|
|
12884
|
-
if (!changed && fs19.existsSync(conv))
|
|
12885
|
-
text = fs19.readFileSync(conv, "utf8");
|
|
12886
|
-
else {
|
|
12887
|
-
text = PASS_THROUGH.has(path19.extname(file).toLowerCase()) ? fs19.readFileSync(file, "utf8") : await converter(file);
|
|
12888
|
-
if (!opts.dryRun) {
|
|
12889
|
-
fs19.mkdirSync(path19.dirname(conv), { recursive: true });
|
|
12890
|
-
fs19.writeFileSync(conv, text);
|
|
12891
|
-
}
|
|
12892
|
-
}
|
|
12893
|
-
} catch (e) {
|
|
12894
|
-
plan.failed.push({ ref, error: e.message.split("\n")[0] });
|
|
12895
|
-
continue;
|
|
12896
|
-
}
|
|
12897
|
-
const all = splitSections(text);
|
|
12898
|
-
const from = changed ? 0 : prior.cursor;
|
|
12899
|
-
const take = all.slice(from, from + budget);
|
|
12900
|
-
budget -= take.length;
|
|
12901
|
-
plan.carriedSections += all.length - from - take.length;
|
|
12902
|
-
plan.sectionCount += take.length;
|
|
12903
|
-
plan.estimatedTokens += Math.ceil(take.reduce((n, s) => n + (s.end - s.start), 0) / CHARS_PER_TOKEN);
|
|
12904
|
-
plan.sources.push({
|
|
12905
|
-
ref,
|
|
12906
|
-
file,
|
|
12907
|
-
converted: conv,
|
|
12908
|
-
sha: stamp.sha,
|
|
12909
|
-
priority: entry.priority,
|
|
12910
|
-
domain: entry.domain,
|
|
12911
|
-
sensitivity: entry.sensitivity,
|
|
12912
|
-
sections: take,
|
|
12913
|
-
totalSections: all.length
|
|
12914
|
-
});
|
|
12915
|
-
if (!opts.dryRun)
|
|
12916
|
-
writeState(kbRoot, { ref, ...stamp, sections: all.length, cursor: from + take.length, priority: entry.priority });
|
|
12917
|
-
}
|
|
12918
|
-
}
|
|
12919
|
-
return plan;
|
|
12920
|
-
}
|
|
12921
|
-
var execFileAsync, CONVERTED_DIR, DEFAULT_MAX_SECTIONS_PER_PASS, CHARS_PER_TOKEN, PASS_THROUGH, SECTION_TARGET_CHARS, markitdownConverter, expandHome2, fileForRef, cacheKey, convertedFile, stampFile, sha256;
|
|
12922
|
-
var init_ingest = __esm({
|
|
12923
|
-
"packages/core/dist/knowledge/ingest.js"() {
|
|
12924
|
-
execFileAsync = promisify2(execFile2);
|
|
12925
|
-
CONVERTED_DIR = ".converted";
|
|
12926
|
-
DEFAULT_MAX_SECTIONS_PER_PASS = 40;
|
|
12927
|
-
CHARS_PER_TOKEN = 4;
|
|
12928
|
-
PASS_THROUGH = /* @__PURE__ */ new Set([".md", ".markdown", ".txt"]);
|
|
12929
|
-
SECTION_TARGET_CHARS = 4e3;
|
|
12930
|
-
markitdownConverter = async (file) => {
|
|
12931
|
-
const { stdout } = await execFileAsync("markitdown", [file], { maxBuffer: 64 * 1024 * 1024 });
|
|
12932
|
-
return stdout;
|
|
12933
|
-
};
|
|
12934
|
-
expandHome2 = (p) => p === "~" || p.startsWith("~/") ? path19.join(os8.homedir(), p.slice(1)) : p;
|
|
12935
|
-
fileForRef = (kbRoot, ref) => path19.resolve(kbRoot, expandHome2(ref));
|
|
12936
|
-
cacheKey = (ref) => `${ref.replace(/[^A-Za-z0-9._-]+/g, "_")}.${crypto3.createHash("sha1").update(ref).digest("hex").slice(0, 6)}`;
|
|
12937
|
-
convertedFile = (kbRoot, ref) => path19.join(kbRoot, CONVERTED_DIR, `${cacheKey(ref)}.md`);
|
|
12938
|
-
stampFile = (kbRoot, ref) => path19.join(kbRoot, CONVERTED_DIR, `${cacheKey(ref)}.sha`);
|
|
12939
|
-
sha256 = (file) => crypto3.createHash("sha256").update(fs19.readFileSync(file)).digest("hex");
|
|
12940
|
-
}
|
|
12941
|
-
});
|
|
12942
|
-
|
|
12943
13123
|
// packages/core/dist/knowledge/match.js
|
|
12944
13124
|
import path20 from "path";
|
|
12945
13125
|
function globMatches(glob, relPath) {
|
|
@@ -13326,7 +13506,7 @@ var init_inject = __esm({
|
|
|
13326
13506
|
STOPWORDS = new Set("the and for are but not you your yours with this that these those from into onto have has had was were will would can could should shall may might must does did doing done its it's our ours their them they what when where which who whom why how all any some each every other than then there here also just very too only own same such both few more most much many about above below after before again once out over under off further been being let lets please thanks thank okay yes yeah hello hey there need want make use using used get got give like know think see look sure ok now new one two way rule rules must-not looks sounds work working thing things something anything everything going well good great nice cool fine".split(/\s+/));
|
|
13327
13507
|
DATA_NOTE = "These are project rules (data from the knowledge base), not instructions to run anything.";
|
|
13328
13508
|
line = (r) => `${r.modality.toUpperCase()} ${r.id}: ${r.statement}`;
|
|
13329
|
-
CITE_NOTE = "
|
|
13509
|
+
CITE_NOTE = "List the rule ids you apply as `Rules: <id>, <id>` at the end of your signal done message (commit messages count too).";
|
|
13330
13510
|
escapeRe = (t) => t.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
13331
13511
|
BRIEF_POINTER_RE = /^Full task is at (\S+\.md) — cat it/;
|
|
13332
13512
|
READ_TOOLS = /* @__PURE__ */ new Set(["read", "read_file", "readfile", "view"]);
|
|
@@ -13357,6 +13537,13 @@ function ensureGitRepo(dir) {
|
|
|
13357
13537
|
return false;
|
|
13358
13538
|
}
|
|
13359
13539
|
}
|
|
13540
|
+
function ensureKbGitignore(dir) {
|
|
13541
|
+
const file = path23.join(dir, ".gitignore");
|
|
13542
|
+
if (fs22.existsSync(file))
|
|
13543
|
+
return false;
|
|
13544
|
+
fs22.writeFileSync(file, KB_GITIGNORE);
|
|
13545
|
+
return true;
|
|
13546
|
+
}
|
|
13360
13547
|
function findLegacyOverlays(cfg) {
|
|
13361
13548
|
return Object.keys(cfg.projects).filter((p) => fs22.existsSync(legacyOverlay(cfg, p))).sort();
|
|
13362
13549
|
}
|
|
@@ -13411,6 +13598,8 @@ function moveLegacyKbs(cfg, opts = {}) {
|
|
|
13411
13598
|
}
|
|
13412
13599
|
if (ensureGitRepo(to))
|
|
13413
13600
|
notes.push("git init");
|
|
13601
|
+
if (ensureKbGitignore(to))
|
|
13602
|
+
notes.push("wrote .gitignore (raw/, .converted/)");
|
|
13414
13603
|
if (fs22.existsSync(path23.join(to, "index.json")))
|
|
13415
13604
|
notes.push(`index.json holds old paths: run squadrant knowledge reindex ${kb}`);
|
|
13416
13605
|
if (action === "copied")
|
|
@@ -13418,90 +13607,74 @@ function moveLegacyKbs(cfg, opts = {}) {
|
|
|
13418
13607
|
return { kb, from, to, action, ...notes.length ? { note: notes.join("; ") } : {} };
|
|
13419
13608
|
});
|
|
13420
13609
|
}
|
|
13421
|
-
var legacyRoot, legacyOverlay;
|
|
13610
|
+
var legacyRoot, KB_GITIGNORE, legacyOverlay;
|
|
13422
13611
|
var init_migrate = __esm({
|
|
13423
13612
|
"packages/core/dist/knowledge/migrate.js"() {
|
|
13424
13613
|
init_dist();
|
|
13425
13614
|
init_paths();
|
|
13426
13615
|
legacyRoot = (cfg) => path23.join(resolveHome(cfg.hubVault), "knowledge");
|
|
13616
|
+
KB_GITIGNORE = "# squadrant KB defaults: source documents stay local\nraw/\n.converted/\n";
|
|
13427
13617
|
legacyOverlay = (cfg, project) => path23.join(resolveHome(cfg.projects[project].spokeVault), "knowledge", "rules");
|
|
13428
13618
|
}
|
|
13429
13619
|
});
|
|
13430
13620
|
|
|
13431
|
-
// packages/core/dist/knowledge/
|
|
13432
|
-
|
|
13621
|
+
// packages/core/dist/knowledge/errata.js
|
|
13622
|
+
import fs23 from "fs";
|
|
13623
|
+
import path24 from "path";
|
|
13624
|
+
function loadErrata(kbRoot) {
|
|
13625
|
+
const file = path24.join(kbRoot, "errata.yaml");
|
|
13626
|
+
if (!fs23.existsSync(file))
|
|
13627
|
+
return { errata: [], errors: [] };
|
|
13628
|
+
let data;
|
|
13629
|
+
try {
|
|
13630
|
+
data = yaml.load(fs23.readFileSync(file, "utf8"), { schema: yaml.JSON_SCHEMA });
|
|
13631
|
+
} catch (e) {
|
|
13632
|
+
return { errata: [], errors: [`YAML parse error: ${e.message.split("\n")[0]}`] };
|
|
13633
|
+
}
|
|
13634
|
+
if (data == null)
|
|
13635
|
+
return { errata: [], errors: [] };
|
|
13636
|
+
if (!Array.isArray(data))
|
|
13637
|
+
return { errata: [], errors: ["errata.yaml must be a YAML list of entries"] };
|
|
13638
|
+
const errata = [];
|
|
13639
|
+
const errors = [];
|
|
13640
|
+
data.forEach((entry, i) => {
|
|
13641
|
+
const problems = validateErratum(entry);
|
|
13642
|
+
if (problems.length)
|
|
13643
|
+
errors.push(...problems.map((p) => `entry ${i}: ${p}`));
|
|
13644
|
+
else
|
|
13645
|
+
errata.push(entry);
|
|
13646
|
+
});
|
|
13647
|
+
return { errata, errors };
|
|
13648
|
+
}
|
|
13649
|
+
function orphanedErrata(kbRoot, errata, refs) {
|
|
13650
|
+
const only = refs ? new Set(refs) : void 0;
|
|
13651
|
+
const hays = /* @__PURE__ */ new Map();
|
|
13433
13652
|
const out = [];
|
|
13434
|
-
const
|
|
13435
|
-
|
|
13436
|
-
for (const ch of s) {
|
|
13437
|
-
out.push(ch);
|
|
13438
|
-
map2.push(at);
|
|
13439
|
-
}
|
|
13440
|
-
};
|
|
13441
|
-
let i = 0;
|
|
13442
|
-
while (i < src.length) {
|
|
13443
|
-
const ch = src[i];
|
|
13444
|
-
if (ch === "-" && /^-[ \t]*\r?\n[ \t]*[a-z]/.test(src.slice(i, i + 40)) && i > 0 && /[A-Za-z]/.test(src[i - 1])) {
|
|
13445
|
-
if (keepBreakHyphen)
|
|
13446
|
-
push("-", i);
|
|
13447
|
-
i++;
|
|
13448
|
-
while (/\s/.test(src[i]))
|
|
13449
|
-
i++;
|
|
13450
|
-
continue;
|
|
13451
|
-
}
|
|
13452
|
-
if (/\s/.test(ch)) {
|
|
13453
|
-
const start = i;
|
|
13454
|
-
while (i < src.length && /\s/.test(src[i]))
|
|
13455
|
-
i++;
|
|
13456
|
-
if (out.length && out[out.length - 1] !== " ")
|
|
13457
|
-
push(" ", start);
|
|
13653
|
+
for (const e of errata) {
|
|
13654
|
+
if (only && !only.has(e.ref))
|
|
13458
13655
|
continue;
|
|
13656
|
+
if (!hays.has(e.ref)) {
|
|
13657
|
+
const conv = readState2(kbRoot, e.ref) ? convertedFile(kbRoot, e.ref) : null;
|
|
13658
|
+
hays.set(e.ref, conv && fs23.existsSync(conv) ? normalizedViews(fs23.readFileSync(conv, "utf8")) : null);
|
|
13459
13659
|
}
|
|
13460
|
-
|
|
13461
|
-
|
|
13462
|
-
|
|
13463
|
-
push(QUOTES[ch], i);
|
|
13464
|
-
else if (DASHES.has(ch))
|
|
13465
|
-
push("-", i);
|
|
13466
|
-
else
|
|
13467
|
-
push(ch, i);
|
|
13468
|
-
i++;
|
|
13469
|
-
}
|
|
13470
|
-
while (out.length && out[out.length - 1] === " ") {
|
|
13471
|
-
out.pop();
|
|
13472
|
-
map2.pop();
|
|
13473
|
-
}
|
|
13474
|
-
return { text: out.join(""), map: map2 };
|
|
13475
|
-
}
|
|
13476
|
-
function findQuote(source, quote) {
|
|
13477
|
-
const needle = normalizeText(quote);
|
|
13478
|
-
if (!needle)
|
|
13479
|
-
return null;
|
|
13480
|
-
const views = typeof source === "string" ? normalizedViews(source) : source;
|
|
13481
|
-
for (const hay of views) {
|
|
13482
|
-
const at = hay.text.indexOf(needle);
|
|
13483
|
-
if (at >= 0)
|
|
13484
|
-
return [hay.map[at], hay.map[at + needle.length - 1] + 1];
|
|
13660
|
+
const hay = hays.get(e.ref);
|
|
13661
|
+
if (hay && !findQuote(hay, e.quote))
|
|
13662
|
+
out.push({ id: e.id, ref: e.ref });
|
|
13485
13663
|
}
|
|
13486
|
-
return
|
|
13664
|
+
return out;
|
|
13487
13665
|
}
|
|
13488
|
-
var
|
|
13489
|
-
|
|
13490
|
-
|
|
13491
|
-
|
|
13492
|
-
|
|
13493
|
-
|
|
13494
|
-
normalizeText = (s) => normalizeWithMap(s).text;
|
|
13495
|
-
normalizedViews = (src) => [normalizeWithMap(src), normalizeWithMap(src, true)];
|
|
13496
|
-
DOCLING_DROP_THRESHOLD = 0.2;
|
|
13497
|
-
needsDocling = (dropped, total) => total > 0 && dropped / total > DOCLING_DROP_THRESHOLD;
|
|
13498
|
-
spansOverlap = (a, b) => a[0] < b[1] && b[0] < a[1];
|
|
13666
|
+
var init_errata = __esm({
|
|
13667
|
+
"packages/core/dist/knowledge/errata.js"() {
|
|
13668
|
+
init_js_yaml();
|
|
13669
|
+
init_dist();
|
|
13670
|
+
init_ingest();
|
|
13671
|
+
init_verify();
|
|
13499
13672
|
}
|
|
13500
13673
|
});
|
|
13501
13674
|
|
|
13502
13675
|
// packages/core/dist/knowledge/anchor.js
|
|
13503
|
-
import
|
|
13504
|
-
import
|
|
13676
|
+
import fs24 from "fs";
|
|
13677
|
+
import path25 from "path";
|
|
13505
13678
|
function* repoFiles(root) {
|
|
13506
13679
|
let count = 0;
|
|
13507
13680
|
const stack = [root];
|
|
@@ -13509,43 +13682,43 @@ function* repoFiles(root) {
|
|
|
13509
13682
|
const dir = stack.pop();
|
|
13510
13683
|
let ents;
|
|
13511
13684
|
try {
|
|
13512
|
-
ents =
|
|
13685
|
+
ents = fs24.readdirSync(dir, { withFileTypes: true }).sort((a, b) => a.name < b.name ? 1 : -1);
|
|
13513
13686
|
} catch {
|
|
13514
13687
|
continue;
|
|
13515
13688
|
}
|
|
13516
13689
|
for (const ent of ents) {
|
|
13517
13690
|
if (ent.isDirectory()) {
|
|
13518
13691
|
if (!SKIP_DIRS.has(ent.name))
|
|
13519
|
-
stack.push(
|
|
13520
|
-
} else if (ent.isFile() && CODE_EXT.has(
|
|
13692
|
+
stack.push(path25.join(dir, ent.name));
|
|
13693
|
+
} else if (ent.isFile() && CODE_EXT.has(path25.extname(ent.name))) {
|
|
13521
13694
|
if (++count > MAX_FILES)
|
|
13522
13695
|
return;
|
|
13523
|
-
yield
|
|
13696
|
+
yield path25.join(dir, ent.name);
|
|
13524
13697
|
}
|
|
13525
13698
|
}
|
|
13526
13699
|
}
|
|
13527
13700
|
}
|
|
13528
13701
|
function computeAnchor(repoRoot, triggers) {
|
|
13529
13702
|
const terms2 = anchorTerms(triggers);
|
|
13530
|
-
if (!terms2.length || !
|
|
13703
|
+
if (!terms2.length || !fs24.existsSync(repoRoot))
|
|
13531
13704
|
return null;
|
|
13532
13705
|
const hits = [];
|
|
13533
13706
|
for (const file of repoFiles(repoRoot)) {
|
|
13534
13707
|
let text;
|
|
13535
13708
|
try {
|
|
13536
|
-
if (
|
|
13709
|
+
if (fs24.statSync(file).size > MAX_FILE_BYTES)
|
|
13537
13710
|
continue;
|
|
13538
|
-
text =
|
|
13711
|
+
text = fs24.readFileSync(file, "utf8");
|
|
13539
13712
|
} catch {
|
|
13540
13713
|
continue;
|
|
13541
13714
|
}
|
|
13542
|
-
const hay = `${
|
|
13715
|
+
const hay = `${path25.relative(repoRoot, file)}
|
|
13543
13716
|
${text}`.toLowerCase();
|
|
13544
13717
|
const score = terms2.filter((t) => hay.includes(t)).length;
|
|
13545
13718
|
if (!score)
|
|
13546
13719
|
continue;
|
|
13547
13720
|
const symbols2 = [...text.matchAll(SYMBOL_RE)].map((m) => m[1]).filter((s) => terms2.some((t) => s.toLowerCase().includes(t)));
|
|
13548
|
-
hits.push({ rel:
|
|
13721
|
+
hits.push({ rel: path25.relative(repoRoot, file).split(path25.sep).join("/"), score, symbols: symbols2 });
|
|
13549
13722
|
}
|
|
13550
13723
|
if (!hits.length)
|
|
13551
13724
|
return null;
|
|
@@ -13569,11 +13742,11 @@ var init_anchor = __esm({
|
|
|
13569
13742
|
});
|
|
13570
13743
|
|
|
13571
13744
|
// packages/core/dist/knowledge/extract.js
|
|
13572
|
-
import
|
|
13573
|
-
import
|
|
13574
|
-
import
|
|
13745
|
+
import fs25 from "fs";
|
|
13746
|
+
import path26 from "path";
|
|
13747
|
+
import matter4 from "gray-matter";
|
|
13575
13748
|
function serialize(fm, body) {
|
|
13576
|
-
return
|
|
13749
|
+
return matter4.stringify(body.trim() + "\n", clean(fm));
|
|
13577
13750
|
}
|
|
13578
13751
|
function validateCandidate(c) {
|
|
13579
13752
|
const p = [];
|
|
@@ -13616,9 +13789,9 @@ function upsertSource(fm, src) {
|
|
|
13616
13789
|
}
|
|
13617
13790
|
function applyCandidates(input, opts) {
|
|
13618
13791
|
const { kb, kbRoot, rulesDir } = opts;
|
|
13619
|
-
const res = { created: [], merged: [], proposed: [], superseded: [], stale: [], rejected: [], doclingFlags: [], idOverrides: [] };
|
|
13792
|
+
const res = { created: [], merged: [], proposed: [], superseded: [], stale: [], rejected: [], doclingFlags: [], idOverrides: [], orphanedErrata: [] };
|
|
13620
13793
|
const events = [];
|
|
13621
|
-
const ev2 = (event, itemId,
|
|
13794
|
+
const ev2 = (event, itemId, extra = {}) => events.push({ kb, level: "group", project: "", domain: "rules", itemId, event, ...extra });
|
|
13622
13795
|
const loaded = loadRulesDir(rulesDir, `kb:${kb}`);
|
|
13623
13796
|
const work = /* @__PURE__ */ new Map();
|
|
13624
13797
|
for (const r of loaded.rules) {
|
|
@@ -13637,13 +13810,13 @@ function applyCandidates(input, opts) {
|
|
|
13637
13810
|
}
|
|
13638
13811
|
const st = readState2(kbRoot, cand.source);
|
|
13639
13812
|
const convFile = st ? convertedFile(kbRoot, cand.source) : null;
|
|
13640
|
-
if (!st || !
|
|
13813
|
+
if (!st || !fs25.existsSync(convFile)) {
|
|
13641
13814
|
res.rejected.push({ id: cand.id, source: cand.source, reason: "unknown source (not ingested)" });
|
|
13642
13815
|
continue;
|
|
13643
13816
|
}
|
|
13644
13817
|
let hay = norm.get(cand.source);
|
|
13645
13818
|
if (!hay) {
|
|
13646
|
-
hay = normalizedViews(
|
|
13819
|
+
hay = normalizedViews(fs25.readFileSync(convFile, "utf8"));
|
|
13647
13820
|
norm.set(cand.source, hay);
|
|
13648
13821
|
}
|
|
13649
13822
|
const tot = totals.get(cand.source) ?? { total: 0, dropped: 0 };
|
|
@@ -13653,7 +13826,14 @@ function applyCandidates(input, opts) {
|
|
|
13653
13826
|
if (!offset) {
|
|
13654
13827
|
tot.dropped++;
|
|
13655
13828
|
res.rejected.push({ id: cand.id, source: cand.source, reason: "ungrounded" });
|
|
13656
|
-
ev2("item.rejected", cand.id,
|
|
13829
|
+
ev2("item.rejected", cand.id, { reason: "ungrounded" });
|
|
13830
|
+
continue;
|
|
13831
|
+
}
|
|
13832
|
+
const hit = (opts.errata ?? []).find((e) => e.ref === cand.source && ((o) => !!o && spansOverlap(o, offset))(findQuote(hay, e.quote)));
|
|
13833
|
+
if (hit) {
|
|
13834
|
+
tot.total--;
|
|
13835
|
+
res.rejected.push({ id: cand.id, source: cand.source, reason: `errata:${hit.id}` });
|
|
13836
|
+
ev2("item.rejected", cand.id, { reason: `errata:${hit.id}` });
|
|
13657
13837
|
continue;
|
|
13658
13838
|
}
|
|
13659
13839
|
let id = cand.id;
|
|
@@ -13685,7 +13865,7 @@ ${cand.rationale.trim()}` : "");
|
|
|
13685
13865
|
}
|
|
13686
13866
|
continue;
|
|
13687
13867
|
}
|
|
13688
|
-
if (!target && contradicted.length === 0) {
|
|
13868
|
+
if (!target && contradicted.length === 0 && !isGatedRef(kbRoot, opts.sources ?? [], cand.source)) {
|
|
13689
13869
|
const fm2 = {
|
|
13690
13870
|
id,
|
|
13691
13871
|
domain: cand.domain,
|
|
@@ -13698,9 +13878,9 @@ ${cand.rationale.trim()}` : "");
|
|
|
13698
13878
|
supersedes: [],
|
|
13699
13879
|
conflictsWith: []
|
|
13700
13880
|
};
|
|
13701
|
-
work.set(id, { fm: fm2, body: bodyOf(), file:
|
|
13881
|
+
work.set(id, { fm: fm2, body: bodyOf(), file: path26.join(rulesDir, cand.domain, `${id}.md`), dirty: true, isNew: true });
|
|
13702
13882
|
res.created.push(id);
|
|
13703
|
-
ev2("item.applied", id
|
|
13883
|
+
ev2("item.applied", id);
|
|
13704
13884
|
continue;
|
|
13705
13885
|
}
|
|
13706
13886
|
const fm = {
|
|
@@ -13715,26 +13895,26 @@ ${cand.rationale.trim()}` : "");
|
|
|
13715
13895
|
supersedes: [],
|
|
13716
13896
|
conflictsWith: contradicted
|
|
13717
13897
|
};
|
|
13718
|
-
const dir =
|
|
13719
|
-
const file =
|
|
13898
|
+
const dir = path26.join(rulesDir, PROPOSED_DIR);
|
|
13899
|
+
const file = path26.join(dir, `${id}@${st.sha.slice(0, SHA_LEN)}.md`);
|
|
13720
13900
|
const text = serialize(fm, bodyOf());
|
|
13721
|
-
if (
|
|
13901
|
+
if (fs25.existsSync(file) && fs25.readFileSync(file, "utf8") === text)
|
|
13722
13902
|
continue;
|
|
13723
|
-
|
|
13724
|
-
for (const other of
|
|
13725
|
-
if (!other.startsWith(`${id}@`) || !other.endsWith(".md") ||
|
|
13903
|
+
fs25.mkdirSync(dir, { recursive: true });
|
|
13904
|
+
for (const other of fs25.readdirSync(dir)) {
|
|
13905
|
+
if (!other.startsWith(`${id}@`) || !other.endsWith(".md") || path26.join(dir, other) === file)
|
|
13726
13906
|
continue;
|
|
13727
|
-
const old =
|
|
13907
|
+
const old = matter4(fs25.readFileSync(path26.join(dir, other), "utf8"));
|
|
13728
13908
|
if (!old.data.sources?.some((s) => s.ref === cand.source))
|
|
13729
13909
|
continue;
|
|
13730
|
-
|
|
13731
|
-
|
|
13910
|
+
fs25.writeFileSync(path26.join(dir, other.replace(/\.md$/, ".superseded")), matter4.stringify(old.content, { ...old.data, supersededBy: path26.basename(file) }));
|
|
13911
|
+
fs25.rmSync(path26.join(dir, other));
|
|
13732
13912
|
res.superseded.push(other.replace(/\.md$/, ""));
|
|
13733
|
-
ev2("item.superseded", id
|
|
13913
|
+
ev2("item.superseded", id);
|
|
13734
13914
|
}
|
|
13735
|
-
|
|
13915
|
+
fs25.writeFileSync(file, text);
|
|
13736
13916
|
res.proposed.push(`${id}@${st.sha.slice(0, SHA_LEN)}`);
|
|
13737
|
-
ev2("item.proposed", id
|
|
13917
|
+
ev2("item.proposed", id);
|
|
13738
13918
|
}
|
|
13739
13919
|
for (const [id, w] of work) {
|
|
13740
13920
|
if (touched.has(id) || w.fm.status !== "active" || w.isNew)
|
|
@@ -13760,11 +13940,12 @@ ${cand.rationale.trim()}` : "");
|
|
|
13760
13940
|
for (const w of work.values()) {
|
|
13761
13941
|
if (!w.dirty)
|
|
13762
13942
|
continue;
|
|
13763
|
-
|
|
13943
|
+
fs25.mkdirSync(path26.dirname(w.file), { recursive: true });
|
|
13764
13944
|
const text = serialize(w.fm, w.body);
|
|
13765
|
-
if (!
|
|
13766
|
-
|
|
13945
|
+
if (!fs25.existsSync(w.file) || fs25.readFileSync(w.file, "utf8") !== text)
|
|
13946
|
+
fs25.writeFileSync(w.file, text);
|
|
13767
13947
|
}
|
|
13948
|
+
res.orphanedErrata = orphanedErrata(kbRoot, opts.errata ?? [], totals.keys());
|
|
13768
13949
|
for (const [ref, t] of totals)
|
|
13769
13950
|
if (needsDocling(t.dropped, t.total))
|
|
13770
13951
|
res.doclingFlags.push({ ref, ...t });
|
|
@@ -13781,6 +13962,7 @@ var init_extract = __esm({
|
|
|
13781
13962
|
init_anchor();
|
|
13782
13963
|
init_index_file();
|
|
13783
13964
|
init_ingest();
|
|
13965
|
+
init_errata();
|
|
13784
13966
|
init_paths();
|
|
13785
13967
|
init_store2();
|
|
13786
13968
|
init_verify();
|
|
@@ -13797,20 +13979,20 @@ var init_extract = __esm({
|
|
|
13797
13979
|
});
|
|
13798
13980
|
|
|
13799
13981
|
// packages/core/dist/knowledge/schedule.js
|
|
13800
|
-
import
|
|
13801
|
-
import
|
|
13982
|
+
import fs26 from "fs";
|
|
13983
|
+
import path27 from "path";
|
|
13802
13984
|
function readSchedule(stateRoot) {
|
|
13803
13985
|
try {
|
|
13804
|
-
return JSON.parse(
|
|
13986
|
+
return JSON.parse(fs26.readFileSync(scheduleFile(stateRoot), "utf8"));
|
|
13805
13987
|
} catch {
|
|
13806
13988
|
return {};
|
|
13807
13989
|
}
|
|
13808
13990
|
}
|
|
13809
13991
|
function writeSchedule(stateRoot, s) {
|
|
13810
|
-
|
|
13992
|
+
fs26.mkdirSync(stateRoot, { recursive: true });
|
|
13811
13993
|
const tmp = `${scheduleFile(stateRoot)}.${process.pid}.tmp`;
|
|
13812
|
-
|
|
13813
|
-
|
|
13994
|
+
fs26.writeFileSync(tmp, JSON.stringify(s, null, 2) + "\n");
|
|
13995
|
+
fs26.renameSync(tmp, scheduleFile(stateRoot));
|
|
13814
13996
|
}
|
|
13815
13997
|
function snapshotSources(kbRoot, sources) {
|
|
13816
13998
|
const out = {};
|
|
@@ -13890,7 +14072,7 @@ async function tickKnowledgeSchedule(d) {
|
|
|
13890
14072
|
continue;
|
|
13891
14073
|
try {
|
|
13892
14074
|
const root = kbDir(d.cfg, kb);
|
|
13893
|
-
if (!
|
|
14075
|
+
if (!fs26.existsSync(root))
|
|
13894
14076
|
continue;
|
|
13895
14077
|
const { sources } = loadSources(root);
|
|
13896
14078
|
if (!sources.length)
|
|
@@ -13955,7 +14137,7 @@ var init_schedule = __esm({
|
|
|
13955
14137
|
init_sources();
|
|
13956
14138
|
RUNNING_STALE_MS = 6 * 60 * 60 * 1e3;
|
|
13957
14139
|
DAY_MS = 24 * 60 * 60 * 1e3;
|
|
13958
|
-
scheduleFile = (stateRoot) =>
|
|
14140
|
+
scheduleFile = (stateRoot) => path27.join(stateRoot, "knowledge-schedule.json");
|
|
13959
14141
|
reconcileConfig = (cfg, kb) => ({ ...DEFAULT_RECONCILE, ...kbConfigs(cfg)[kb]?.reconcile });
|
|
13960
14142
|
}
|
|
13961
14143
|
});
|
|
@@ -13963,19 +14145,19 @@ var init_schedule = __esm({
|
|
|
13963
14145
|
// packages/core/dist/knowledge/review.js
|
|
13964
14146
|
import crypto4 from "crypto";
|
|
13965
14147
|
import { execFileSync as execFileSync7 } from "child_process";
|
|
13966
|
-
import
|
|
13967
|
-
import
|
|
13968
|
-
import
|
|
14148
|
+
import fs27 from "fs";
|
|
14149
|
+
import path28 from "path";
|
|
14150
|
+
import matter5 from "gray-matter";
|
|
13969
14151
|
function readEscalations(kbRoot) {
|
|
13970
14152
|
try {
|
|
13971
|
-
return JSON.parse(
|
|
14153
|
+
return JSON.parse(fs27.readFileSync(escalationsFile(kbRoot), "utf8")).items;
|
|
13972
14154
|
} catch {
|
|
13973
14155
|
return [];
|
|
13974
14156
|
}
|
|
13975
14157
|
}
|
|
13976
14158
|
function writeEscalations(kbRoot, items) {
|
|
13977
|
-
|
|
13978
|
-
|
|
14159
|
+
fs27.mkdirSync(kbRoot, { recursive: true });
|
|
14160
|
+
fs27.writeFileSync(escalationsFile(kbRoot), JSON.stringify({ items }, null, 2) + "\n");
|
|
13979
14161
|
}
|
|
13980
14162
|
function addEscalation(kbRoot, e) {
|
|
13981
14163
|
const items = readEscalations(kbRoot);
|
|
@@ -13985,8 +14167,8 @@ function addEscalation(kbRoot, e) {
|
|
|
13985
14167
|
return true;
|
|
13986
14168
|
}
|
|
13987
14169
|
function appendVerdict(kbRoot, v2, now) {
|
|
13988
|
-
|
|
13989
|
-
|
|
14170
|
+
fs27.mkdirSync(kbRoot, { recursive: true });
|
|
14171
|
+
fs27.appendFileSync(verdictsFile(kbRoot), JSON.stringify({ ts: now.toISOString(), ...v2 }) + "\n");
|
|
13990
14172
|
}
|
|
13991
14173
|
function priorityOfRef(c, ref) {
|
|
13992
14174
|
if (ref.startsWith("agent:"))
|
|
@@ -14007,20 +14189,20 @@ function loadProposals(c) {
|
|
|
14007
14189
|
const byId = new Map(live.map((r) => [r.id, r]));
|
|
14008
14190
|
const proposals = [];
|
|
14009
14191
|
const pdirs = /* @__PURE__ */ new Set();
|
|
14010
|
-
for (const f of
|
|
14011
|
-
if (
|
|
14192
|
+
for (const f of fs27.existsSync(dir) ? walkDirs(dir) : [])
|
|
14193
|
+
if (path28.basename(f) === PROPOSED_DIR)
|
|
14012
14194
|
pdirs.add(f);
|
|
14013
14195
|
for (const pd of pdirs) {
|
|
14014
14196
|
for (const rule of loadRulesDir(pd, `kb:${c.kb}`, { includeProposed: true }).rules) {
|
|
14015
|
-
proposals.push({ key:
|
|
14197
|
+
proposals.push({ key: path28.basename(rule.file).replace(/\.md$/, ""), rule, live: byId.get(rule.id) });
|
|
14016
14198
|
}
|
|
14017
14199
|
}
|
|
14018
14200
|
return { proposals, live };
|
|
14019
14201
|
}
|
|
14020
14202
|
function walkDirs(dir, out = []) {
|
|
14021
|
-
for (const e of
|
|
14203
|
+
for (const e of fs27.readdirSync(dir, { withFileTypes: true }))
|
|
14022
14204
|
if (e.isDirectory()) {
|
|
14023
|
-
const f =
|
|
14205
|
+
const f = path28.join(dir, e.name);
|
|
14024
14206
|
out.push(f);
|
|
14025
14207
|
walkDirs(f, out);
|
|
14026
14208
|
}
|
|
@@ -14049,9 +14231,9 @@ function promoteProposal(c, p, by, justification, events) {
|
|
|
14049
14231
|
continue;
|
|
14050
14232
|
const o = readFm(other.file);
|
|
14051
14233
|
o.fm.status = "retired";
|
|
14052
|
-
|
|
14234
|
+
fs27.writeFileSync(other.file, fileText(o.fm, o.body));
|
|
14053
14235
|
retired.push(id);
|
|
14054
|
-
events.push(ev(c, "item.superseded", id
|
|
14236
|
+
events.push(ev(c, "item.superseded", id));
|
|
14055
14237
|
}
|
|
14056
14238
|
const next = { ...fm, status: "active", approvedBy: by, justification, supersedes: [.../* @__PURE__ */ new Set([...fm.supersedes ?? [], ...retired])], conflictsWith: [] };
|
|
14057
14239
|
if (p.live?.decision)
|
|
@@ -14059,17 +14241,17 @@ function promoteProposal(c, p, by, justification, events) {
|
|
|
14059
14241
|
const anchors = anchorsFor(c, { ...next, anchors: p.live?.anchors ?? fm.anchors });
|
|
14060
14242
|
if (anchors)
|
|
14061
14243
|
next.anchors = anchors;
|
|
14062
|
-
const target = p.live?.file ??
|
|
14063
|
-
|
|
14064
|
-
|
|
14065
|
-
|
|
14066
|
-
events.push(ev(c, "item.approved", next.id
|
|
14244
|
+
const target = p.live?.file ?? path28.join(dir, next.domain, `${next.id}.md`);
|
|
14245
|
+
fs27.mkdirSync(path28.dirname(target), { recursive: true });
|
|
14246
|
+
fs27.writeFileSync(target, fileText(next, body));
|
|
14247
|
+
fs27.rmSync(p.rule.file);
|
|
14248
|
+
events.push(ev(c, "item.approved", next.id), ev(c, "item.applied", next.id));
|
|
14067
14249
|
if (p.live)
|
|
14068
|
-
events.push(ev(c, "item.superseded", next.id
|
|
14250
|
+
events.push(ev(c, "item.superseded", next.id));
|
|
14069
14251
|
}
|
|
14070
14252
|
function dropProposal(c, p, events) {
|
|
14071
|
-
|
|
14072
|
-
events.push(ev(c, "item.rejected", p.rule.id,
|
|
14253
|
+
fs27.rmSync(p.rule.file);
|
|
14254
|
+
events.push(ev(c, "item.rejected", p.rule.id, { reason: "reviewer" }));
|
|
14073
14255
|
}
|
|
14074
14256
|
function mergeInto(c, p, targetId, live, events) {
|
|
14075
14257
|
const t = live.find((r) => r.id === targetId);
|
|
@@ -14079,9 +14261,9 @@ function mergeInto(c, p, targetId, live, events) {
|
|
|
14079
14261
|
for (const s of p.rule.sources)
|
|
14080
14262
|
if (!tf.fm.sources.some((x) => x.ref === s.ref))
|
|
14081
14263
|
tf.fm.sources.push(s);
|
|
14082
|
-
|
|
14083
|
-
|
|
14084
|
-
events.push(ev(c, "item.superseded", p.rule.id
|
|
14264
|
+
fs27.writeFileSync(t.file, fileText(tf.fm, tf.body));
|
|
14265
|
+
fs27.rmSync(p.rule.file);
|
|
14266
|
+
events.push(ev(c, "item.superseded", p.rule.id), ev(c, "item.applied", targetId));
|
|
14085
14267
|
return true;
|
|
14086
14268
|
}
|
|
14087
14269
|
function evaluateCodeConflict(c, rule, cc) {
|
|
@@ -14155,14 +14337,15 @@ function applyDecisions(file, c) {
|
|
|
14155
14337
|
f.fm.status = "active";
|
|
14156
14338
|
if (d.loc && f.fm.sources[0])
|
|
14157
14339
|
f.fm.sources[0].loc = d.loc;
|
|
14158
|
-
|
|
14159
|
-
|
|
14340
|
+
const noSource = !rule.sources.length;
|
|
14341
|
+
if (conf >= threshold && !d.flag && !reasons.length && !noSource) {
|
|
14342
|
+
fs27.writeFileSync(rule.file, fileText(f.fm, f.body));
|
|
14160
14343
|
res.applied.push(d.item);
|
|
14161
|
-
events.push(ev(c, "item.applied", rule.id
|
|
14344
|
+
events.push(ev(c, "item.applied", rule.id));
|
|
14162
14345
|
verdict(d, "applied", { confidence: conf });
|
|
14163
14346
|
continue;
|
|
14164
14347
|
}
|
|
14165
|
-
reasons.push(conf < threshold ? "low-confidence" : "reviewer-flagged");
|
|
14348
|
+
reasons.push(noSource ? "no-source" : conf < threshold ? "low-confidence" : "reviewer-flagged");
|
|
14166
14349
|
} else if (d.decision === "approve") {
|
|
14167
14350
|
if (strong(rule.modality))
|
|
14168
14351
|
reasons.push("retiring must/must-not");
|
|
@@ -14173,9 +14356,9 @@ function applyDecisions(file, c) {
|
|
|
14173
14356
|
if (!reasons.length) {
|
|
14174
14357
|
const f = readFm(rule.file);
|
|
14175
14358
|
f.fm.status = "retired";
|
|
14176
|
-
|
|
14359
|
+
fs27.writeFileSync(rule.file, fileText(f.fm, f.body));
|
|
14177
14360
|
res.applied.push(d.item);
|
|
14178
|
-
events.push(ev(c, "item.archived", rule.id
|
|
14361
|
+
events.push(ev(c, "item.archived", rule.id));
|
|
14179
14362
|
verdict(d, "applied", { confidence: conf });
|
|
14180
14363
|
continue;
|
|
14181
14364
|
}
|
|
@@ -14190,6 +14373,8 @@ function applyDecisions(file, c) {
|
|
|
14190
14373
|
reasons.push("reviewer-flagged");
|
|
14191
14374
|
if (conf < threshold)
|
|
14192
14375
|
reasons.push("low-confidence");
|
|
14376
|
+
if (p.rule.sources.some((s) => isGatedRef(kbRoot, c.sources, s.ref)))
|
|
14377
|
+
reasons.push("review-required");
|
|
14193
14378
|
if (d.decision === "approve") {
|
|
14194
14379
|
const myPri = priorityOfRule(c, p.rule);
|
|
14195
14380
|
const conflicted = (p.rule.conflictsWith ?? []).map((id) => live.find((r) => r.id === id)).filter((r) => !!r);
|
|
@@ -14251,7 +14436,7 @@ function applyPair(pd, c, res, threshold, events, kbRoot, now) {
|
|
|
14251
14436
|
for (const [x, y] of [[a, b], [b, a]]) {
|
|
14252
14437
|
const f = readFm(x.file);
|
|
14253
14438
|
f.fm.conflictsWith = [.../* @__PURE__ */ new Set([...f.fm.conflictsWith ?? [], y.id])];
|
|
14254
|
-
|
|
14439
|
+
fs27.writeFileSync(x.file, fileText(f.fm, f.body));
|
|
14255
14440
|
}
|
|
14256
14441
|
return;
|
|
14257
14442
|
}
|
|
@@ -14266,11 +14451,11 @@ function applyPair(pd, c, res, threshold, events, kbRoot, now) {
|
|
|
14266
14451
|
if (!kf.fm.sources.some((x) => x.ref === s.ref))
|
|
14267
14452
|
kf.fm.sources.push(s);
|
|
14268
14453
|
kf.fm.supersedes = [.../* @__PURE__ */ new Set([...kf.fm.supersedes ?? [], drop.id])];
|
|
14269
|
-
|
|
14454
|
+
fs27.writeFileSync(keep.file, fileText(kf.fm, kf.body));
|
|
14270
14455
|
const df = readFm(drop.file);
|
|
14271
14456
|
df.fm.status = "retired";
|
|
14272
|
-
|
|
14273
|
-
events.push(ev(c, "item.superseded", drop.id
|
|
14457
|
+
fs27.writeFileSync(drop.file, fileText(df.fm, df.body));
|
|
14458
|
+
events.push(ev(c, "item.superseded", drop.id), ev(c, "item.applied", keep.id));
|
|
14274
14459
|
res.applied.push(key);
|
|
14275
14460
|
}
|
|
14276
14461
|
function resolveEscalation(c, key, r, by, reason) {
|
|
@@ -14300,9 +14485,9 @@ function resolveEscalation(c, key, r, by, reason) {
|
|
|
14300
14485
|
f.fm.decision = decision;
|
|
14301
14486
|
if (r.verdict === "supersede-with-code") {
|
|
14302
14487
|
f.fm.status = "retired";
|
|
14303
|
-
events.push(ev(c, "item.superseded", rule.id
|
|
14488
|
+
events.push(ev(c, "item.superseded", rule.id));
|
|
14304
14489
|
}
|
|
14305
|
-
|
|
14490
|
+
fs27.writeFileSync(rule.file, fileText(f.fm, f.body));
|
|
14306
14491
|
return done(`${rule.id}: ${r.verdict}`);
|
|
14307
14492
|
}
|
|
14308
14493
|
if (esc.kind === "proposal") {
|
|
@@ -14319,23 +14504,26 @@ function resolveEscalation(c, key, r, by, reason) {
|
|
|
14319
14504
|
}
|
|
14320
14505
|
if (esc.kind === "stale-retire") {
|
|
14321
14506
|
const rule = live.find((x) => x.id === esc.ruleId);
|
|
14507
|
+
if (rule && r.kind !== "approve" && !rule.sources.length) {
|
|
14508
|
+
throw new Error(`Rule ${rule.id} has no source, so it cannot be kept active. Add a source to the rule (or re-extract it), or retire it with --approve.`);
|
|
14509
|
+
}
|
|
14322
14510
|
if (rule) {
|
|
14323
14511
|
const f = readFm(rule.file);
|
|
14324
14512
|
f.fm.status = r.kind === "approve" ? "retired" : "active";
|
|
14325
|
-
|
|
14326
|
-
events.push(ev(c, r.kind === "approve" ? "item.archived" : "item.applied", rule.id
|
|
14513
|
+
fs27.writeFileSync(rule.file, fileText(f.fm, f.body));
|
|
14514
|
+
events.push(ev(c, r.kind === "approve" ? "item.archived" : "item.applied", rule.id));
|
|
14327
14515
|
}
|
|
14328
14516
|
return done(`${esc.ruleId}: ${r.kind === "approve" ? "retired" : "kept"}`);
|
|
14329
14517
|
}
|
|
14330
14518
|
if (esc.kind === "override-base-changed") {
|
|
14331
|
-
const ov = esc.item &&
|
|
14519
|
+
const ov = esc.item && fs27.existsSync(esc.item) ? esc.item : void 0;
|
|
14332
14520
|
if (ov) {
|
|
14333
14521
|
if (r.kind === "reject")
|
|
14334
|
-
|
|
14522
|
+
fs27.rmSync(ov);
|
|
14335
14523
|
else {
|
|
14336
14524
|
const f = readFm(ov);
|
|
14337
14525
|
f.fm.overridesBase = esc.evidence?.docRev;
|
|
14338
|
-
|
|
14526
|
+
fs27.writeFileSync(ov, fileText(f.fm, f.body));
|
|
14339
14527
|
}
|
|
14340
14528
|
}
|
|
14341
14529
|
return done(`${esc.ruleId}: override ${r.kind === "reject" ? "dropped" : "kept"}`);
|
|
@@ -14359,11 +14547,11 @@ ${o.evidence}`).digest("hex");
|
|
|
14359
14547
|
supersedes: [],
|
|
14360
14548
|
conflictsWith: []
|
|
14361
14549
|
};
|
|
14362
|
-
const dir =
|
|
14363
|
-
|
|
14364
|
-
const file =
|
|
14365
|
-
|
|
14366
|
-
appendAudit([ev(c, "item.proposed", id
|
|
14550
|
+
const dir = path28.join(kbRulesDir(c.cfg, c.kb), PROPOSED_DIR);
|
|
14551
|
+
fs27.mkdirSync(dir, { recursive: true });
|
|
14552
|
+
const file = path28.join(dir, `${id}@${sha.slice(0, SHA_LEN2)}.md`);
|
|
14553
|
+
fs27.writeFileSync(file, fileText(fm, o.statement));
|
|
14554
|
+
appendAudit([ev(c, "item.proposed", id)], c.audit);
|
|
14367
14555
|
return file;
|
|
14368
14556
|
}
|
|
14369
14557
|
function buildReviewPacket(c) {
|
|
@@ -14403,8 +14591,8 @@ var init_review = __esm({
|
|
|
14403
14591
|
PRIORITY_RANK = { company: 3, project: 2, agent: 1 };
|
|
14404
14592
|
SHA_LEN2 = 12;
|
|
14405
14593
|
strong = (m) => m === "must" || m === "must-not";
|
|
14406
|
-
escalationsFile = (kbRoot) =>
|
|
14407
|
-
verdictsFile = (kbRoot) =>
|
|
14594
|
+
escalationsFile = (kbRoot) => path28.join(kbRoot, "escalations.json");
|
|
14595
|
+
verdictsFile = (kbRoot) => path28.join(kbRoot, "verdicts.jsonl");
|
|
14408
14596
|
needsYouCount = (kbRoot) => readEscalations(kbRoot).filter((e) => e.needsYou).length;
|
|
14409
14597
|
git = (root, args) => execFileSync7("git", ["-C", root, ...args], { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] }).trim();
|
|
14410
14598
|
realGit = {
|
|
@@ -14425,34 +14613,34 @@ var init_review = __esm({
|
|
|
14425
14613
|
},
|
|
14426
14614
|
docDate(file) {
|
|
14427
14615
|
try {
|
|
14428
|
-
const d = git(
|
|
14616
|
+
const d = git(path28.dirname(file), ["log", "-1", "--format=%cI", "--", path28.basename(file)]);
|
|
14429
14617
|
if (d)
|
|
14430
14618
|
return d;
|
|
14431
14619
|
} catch {
|
|
14432
14620
|
}
|
|
14433
14621
|
try {
|
|
14434
|
-
return
|
|
14622
|
+
return fs27.statSync(file).mtime.toISOString();
|
|
14435
14623
|
} catch {
|
|
14436
14624
|
return null;
|
|
14437
14625
|
}
|
|
14438
14626
|
}
|
|
14439
14627
|
};
|
|
14440
14628
|
nowOf = (c) => c.now?.() ?? /* @__PURE__ */ new Date();
|
|
14441
|
-
fileText = (fm, body) =>
|
|
14629
|
+
fileText = (fm, body) => matter5.stringify(body.trim() + "\n", JSON.parse(JSON.stringify(fm)));
|
|
14442
14630
|
readFm = (file) => {
|
|
14443
|
-
const m =
|
|
14631
|
+
const m = matter5(fs27.readFileSync(file, "utf8"));
|
|
14444
14632
|
return { fm: m.data, body: m.content };
|
|
14445
14633
|
};
|
|
14446
|
-
ev = (c, event, itemId,
|
|
14634
|
+
ev = (c, event, itemId, extra = {}) => ({ kb: c.kb, level: "group", project: "", domain: "rules", itemId, event, ...extra });
|
|
14447
14635
|
docRevOf = (r) => r.sources.map((s) => `${s.ref}@${s.sha.slice(0, SHA_LEN2)}`).join(",");
|
|
14448
14636
|
}
|
|
14449
14637
|
});
|
|
14450
14638
|
|
|
14451
14639
|
// packages/core/dist/knowledge/fullpass.js
|
|
14452
14640
|
import crypto5 from "crypto";
|
|
14453
|
-
import
|
|
14454
|
-
import
|
|
14455
|
-
import
|
|
14641
|
+
import fs28 from "fs";
|
|
14642
|
+
import path29 from "path";
|
|
14643
|
+
import matter6 from "gray-matter";
|
|
14456
14644
|
function dedupPairs(rules) {
|
|
14457
14645
|
const active = rules.filter((r) => r.status === "active").sort((x, y) => x.id.localeCompare(y.id));
|
|
14458
14646
|
const out = [];
|
|
@@ -14468,12 +14656,12 @@ function dedupPairs(rules) {
|
|
|
14468
14656
|
return out.slice(0, MAX_DEDUP_PAIRS);
|
|
14469
14657
|
}
|
|
14470
14658
|
function readAuditRecords(kb, since, dir = defaultAuditDir()) {
|
|
14471
|
-
if (!
|
|
14659
|
+
if (!fs28.existsSync(dir))
|
|
14472
14660
|
return [];
|
|
14473
14661
|
const sinceMonth = since.toISOString().slice(0, 7);
|
|
14474
14662
|
const out = [];
|
|
14475
|
-
for (const f of
|
|
14476
|
-
for (const line2 of
|
|
14663
|
+
for (const f of fs28.readdirSync(dir).filter((n) => n.endsWith(".jsonl") && n.slice(0, 7) >= sinceMonth).sort()) {
|
|
14664
|
+
for (const line2 of fs28.readFileSync(path29.join(dir, f), "utf8").split("\n")) {
|
|
14477
14665
|
if (!line2.trim())
|
|
14478
14666
|
continue;
|
|
14479
14667
|
try {
|
|
@@ -14536,8 +14724,8 @@ function checkOverrides(cfg, kb) {
|
|
|
14536
14724
|
continue;
|
|
14537
14725
|
const h = baseHash(b);
|
|
14538
14726
|
if (!o.overridesBase) {
|
|
14539
|
-
const m =
|
|
14540
|
-
|
|
14727
|
+
const m = matter6(fs28.readFileSync(o.file, "utf8"));
|
|
14728
|
+
fs28.writeFileSync(o.file, matter6.stringify(m.content, { ...m.data, overridesBase: h }));
|
|
14541
14729
|
continue;
|
|
14542
14730
|
}
|
|
14543
14731
|
out.push({ project, ruleId: o.id, file: o.file, baseHash: h, changed: o.overridesBase !== h });
|
|
@@ -14580,8 +14768,8 @@ var init_fullpass = __esm({
|
|
|
14580
14768
|
});
|
|
14581
14769
|
|
|
14582
14770
|
// packages/core/dist/knowledge/scores.js
|
|
14583
|
-
import
|
|
14584
|
-
import
|
|
14771
|
+
import fs29 from "fs";
|
|
14772
|
+
import path30 from "path";
|
|
14585
14773
|
function tally(records, into = emptyTally()) {
|
|
14586
14774
|
for (const e of records) {
|
|
14587
14775
|
const domain = typeof e.domain === "string" && e.domain ? e.domain : "rules";
|
|
@@ -14590,7 +14778,7 @@ function tally(records, into = emptyTally()) {
|
|
|
14590
14778
|
d.writes++;
|
|
14591
14779
|
if (READ_EVENTS.has(e.event ?? ""))
|
|
14592
14780
|
d.reads++;
|
|
14593
|
-
if (!e.itemId)
|
|
14781
|
+
if (!e.itemId || WRITE_EVENTS.has(e.event ?? ""))
|
|
14594
14782
|
continue;
|
|
14595
14783
|
const c = into.items[`${domain}|${e.itemId}`] ??= { ...zero(), domain, itemId: e.itemId };
|
|
14596
14784
|
switch (e.event) {
|
|
@@ -14627,7 +14815,7 @@ function tally(records, into = emptyTally()) {
|
|
|
14627
14815
|
}
|
|
14628
14816
|
function parseLines(file) {
|
|
14629
14817
|
const out = [];
|
|
14630
|
-
for (const line2 of
|
|
14818
|
+
for (const line2 of fs29.readFileSync(file, "utf8").split("\n")) {
|
|
14631
14819
|
if (!line2.trim())
|
|
14632
14820
|
continue;
|
|
14633
14821
|
try {
|
|
@@ -14639,37 +14827,37 @@ function parseLines(file) {
|
|
|
14639
14827
|
}
|
|
14640
14828
|
function compactAudit(o) {
|
|
14641
14829
|
const dir = o.dir ?? defaultAuditDir();
|
|
14642
|
-
if (!
|
|
14830
|
+
if (!fs29.existsSync(dir))
|
|
14643
14831
|
return [];
|
|
14644
14832
|
const cutoffMonth = new Date(o.now.getTime() - SCORE_WINDOW_DAYS * DAY_MS3).toISOString().slice(0, 7);
|
|
14645
14833
|
const done = [];
|
|
14646
|
-
for (const f of
|
|
14834
|
+
for (const f of fs29.readdirSync(dir).sort()) {
|
|
14647
14835
|
const m = MONTH_FILE_RE.exec(f);
|
|
14648
14836
|
if (!m || m[1] >= cutoffMonth)
|
|
14649
14837
|
continue;
|
|
14650
14838
|
const [, month, machine] = m;
|
|
14651
14839
|
const byKb = /* @__PURE__ */ new Map();
|
|
14652
|
-
for (const r of parseLines(
|
|
14840
|
+
for (const r of parseLines(path30.join(dir, f)))
|
|
14653
14841
|
byKb.set(r.kb ?? "", [...byKb.get(r.kb ?? "") ?? [], r]);
|
|
14654
|
-
const statsPath =
|
|
14655
|
-
const prior =
|
|
14842
|
+
const statsPath = path30.join(dir, statsFileName(month, machine));
|
|
14843
|
+
const prior = fs29.existsSync(statsPath) ? JSON.parse(fs29.readFileSync(statsPath, "utf8")) : null;
|
|
14656
14844
|
const kbs = prior?.kbs ?? {};
|
|
14657
14845
|
for (const [kb, recs] of byKb)
|
|
14658
14846
|
kbs[kb] = tally(recs, kbs[kb]);
|
|
14659
|
-
|
|
14660
|
-
|
|
14661
|
-
|
|
14847
|
+
fs29.writeFileSync(`${statsPath}.tmp`, JSON.stringify({ month, machine, kbs }));
|
|
14848
|
+
fs29.renameSync(`${statsPath}.tmp`, statsPath);
|
|
14849
|
+
fs29.unlinkSync(path30.join(dir, f));
|
|
14662
14850
|
done.push(month);
|
|
14663
14851
|
}
|
|
14664
14852
|
return done;
|
|
14665
14853
|
}
|
|
14666
14854
|
function readCompacted(kb, dir) {
|
|
14667
14855
|
const t = emptyTally();
|
|
14668
|
-
if (!
|
|
14856
|
+
if (!fs29.existsSync(dir))
|
|
14669
14857
|
return t;
|
|
14670
|
-
for (const f of
|
|
14858
|
+
for (const f of fs29.readdirSync(dir).filter((n) => n.endsWith(".stats.json"))) {
|
|
14671
14859
|
try {
|
|
14672
|
-
const k = JSON.parse(
|
|
14860
|
+
const k = JSON.parse(fs29.readFileSync(path30.join(dir, f), "utf8")).kbs[kb];
|
|
14673
14861
|
if (k)
|
|
14674
14862
|
mergeTally(t, k);
|
|
14675
14863
|
} catch {
|
|
@@ -14719,7 +14907,7 @@ function computeScores(i) {
|
|
|
14719
14907
|
noise: w.noise,
|
|
14720
14908
|
wrong: w.wrong,
|
|
14721
14909
|
fireRate: w.surfaced,
|
|
14722
|
-
pullRate: w.shown,
|
|
14910
|
+
pullRate: w.shown + w.searched,
|
|
14723
14911
|
useRate: ratio(w.cited, w.surfaced),
|
|
14724
14912
|
noiseRate: ratio(w.noise, w.surfaced),
|
|
14725
14913
|
violationRate: ratio(w.violated, w.surfaced),
|
|
@@ -14761,21 +14949,21 @@ function computeScores(i) {
|
|
|
14761
14949
|
function scoreKb(o) {
|
|
14762
14950
|
const dir = o.auditDir ?? defaultAuditDir();
|
|
14763
14951
|
const records = [];
|
|
14764
|
-
if (
|
|
14765
|
-
for (const f of
|
|
14766
|
-
records.push(...parseLines(
|
|
14952
|
+
if (fs29.existsSync(dir)) {
|
|
14953
|
+
for (const f of fs29.readdirSync(dir).filter((n) => MONTH_FILE_RE.test(n)).sort()) {
|
|
14954
|
+
records.push(...parseLines(path30.join(dir, f)).filter((r) => r.kb === o.kb));
|
|
14767
14955
|
}
|
|
14768
14956
|
}
|
|
14769
14957
|
let verdicts = [];
|
|
14770
14958
|
try {
|
|
14771
|
-
verdicts =
|
|
14959
|
+
verdicts = fs29.readFileSync(path30.join(o.kbRoot, "verdicts.jsonl"), "utf8").split("\n").filter(Boolean).map((l) => JSON.parse(l));
|
|
14772
14960
|
} catch {
|
|
14773
14961
|
}
|
|
14774
14962
|
return computeScores({ kb: o.kb, records, now: o.now, known: o.known, compacted: readCompacted(o.kb, dir), verdicts });
|
|
14775
14963
|
}
|
|
14776
14964
|
function writeScores(kbRoot, s) {
|
|
14777
|
-
|
|
14778
|
-
|
|
14965
|
+
fs29.mkdirSync(kbRoot, { recursive: true });
|
|
14966
|
+
fs29.writeFileSync(scoresFile(kbRoot), JSON.stringify(s, null, 2) + "\n");
|
|
14779
14967
|
}
|
|
14780
14968
|
function renderScoresSection(s) {
|
|
14781
14969
|
const pct = (x) => x === null ? "n/a" : `${Math.round(x * 100)}%`;
|
|
@@ -14788,7 +14976,7 @@ function renderScoresSection(s) {
|
|
|
14788
14976
|
...used.length ? [
|
|
14789
14977
|
"| Item | Surfaced | Pulled | Cited | Use | Noise | Violated |",
|
|
14790
14978
|
"|---|---|---|---|---|---|---|",
|
|
14791
|
-
...used.map((x) => `| ${x.itemId} | ${x.surfaced} | ${x.
|
|
14979
|
+
...used.map((x) => `| ${x.itemId} | ${x.surfaced} | ${x.pullRate} | ${x.cited} | ${pct(x.useRate)} | ${pct(x.noiseRate)} | ${pct(x.violationRate)} |`)
|
|
14792
14980
|
] : ["No items surfaced."],
|
|
14793
14981
|
"",
|
|
14794
14982
|
`- Never fired (${never.length}): ${never.slice(0, 20).join(", ") || "none"}${never.length > 20 ? ", \u2026" : ""}`,
|
|
@@ -14816,13 +15004,13 @@ var init_scores = __esm({
|
|
|
14816
15004
|
MONTH_FILE_RE = /^(\d{4}-\d{2})\.(.+)\.jsonl$/;
|
|
14817
15005
|
statsFileName = (month, machine) => `${month}.${machine}.stats.json`;
|
|
14818
15006
|
ratio = (n, d) => d ? Math.round(n / d * 1e3) / 1e3 : null;
|
|
14819
|
-
scoresFile = (kbRoot) =>
|
|
15007
|
+
scoresFile = (kbRoot) => path30.join(kbRoot, "scores.json");
|
|
14820
15008
|
}
|
|
14821
15009
|
});
|
|
14822
15010
|
|
|
14823
15011
|
// packages/core/dist/knowledge/report.js
|
|
14824
|
-
import
|
|
14825
|
-
import
|
|
15012
|
+
import fs30 from "fs";
|
|
15013
|
+
import path31 from "path";
|
|
14826
15014
|
function renderReport(cfg, kb, o) {
|
|
14827
15015
|
const { rules } = loadKbRules(cfg, kb, { includeProposed: true });
|
|
14828
15016
|
const count = (s) => rules.filter((r) => r.status === s).length;
|
|
@@ -14844,6 +15032,11 @@ function renderReport(cfg, kb, o) {
|
|
|
14844
15032
|
const info = esc.filter((e) => !e.needsYou);
|
|
14845
15033
|
if (info.length)
|
|
14846
15034
|
L.push("", `## For information (${info.length})`, "", ...info.map((e) => `- **${e.key}**: ${e.explanation}`));
|
|
15035
|
+
const { errata, errors: errataErrors } = loadErrata(kbDir(cfg, kb));
|
|
15036
|
+
const orphans = orphanedErrata(kbDir(cfg, kb), errata);
|
|
15037
|
+
if (orphans.length || errataErrors.length) {
|
|
15038
|
+
L.push("", `## Errata to re-check (${orphans.length + errataErrors.length})`, "", ...orphans.map((e) => `- **${e.id}** (${e.ref}): quote no longer found in the source; the raw file changed. Re-check it in errata.yaml.`), ...errataErrors.map((e) => `- errata.yaml: ${e}`));
|
|
15039
|
+
}
|
|
14847
15040
|
if (o.full) {
|
|
14848
15041
|
const { usage: usage2, caps } = o.full;
|
|
14849
15042
|
L.push("", "## Usage (30 days)", "", `- Surfaced: ${Object.values(usage2.surfaced).reduce((a, b) => a + b, 0)} times across ${Object.keys(usage2.surfaced).length} rules.`, `- Never surfaced (re-check triggers): ${usage2.neverSurfaced.join(", ") || "none"}`, `- Noisy (narrow triggers): ${usage2.noisy.join(", ") || "none"}`, `- Violation feedback (reword): ${usage2.violated.join(", ") || "none"}`, `- Domains over cap: ${caps.map((c) => `${c.domain} (${c.count}/${c.cap})`).join(", ") || "none"}`);
|
|
@@ -14853,12 +15046,13 @@ function renderReport(cfg, kb, o) {
|
|
|
14853
15046
|
return L.join("\n") + "\n";
|
|
14854
15047
|
}
|
|
14855
15048
|
function writeReport(cfg, kb, o) {
|
|
14856
|
-
const file =
|
|
14857
|
-
|
|
15049
|
+
const file = path31.join(kbDir(cfg, kb), "REPORT.md");
|
|
15050
|
+
fs30.writeFileSync(file, renderReport(cfg, kb, o));
|
|
14858
15051
|
return file;
|
|
14859
15052
|
}
|
|
14860
15053
|
var init_report = __esm({
|
|
14861
15054
|
"packages/core/dist/knowledge/report.js"() {
|
|
15055
|
+
init_errata();
|
|
14862
15056
|
init_layers();
|
|
14863
15057
|
init_paths();
|
|
14864
15058
|
init_review();
|
|
@@ -14902,44 +15096,63 @@ var init_reconcile = __esm({
|
|
|
14902
15096
|
|
|
14903
15097
|
// packages/core/dist/knowledge/cite.js
|
|
14904
15098
|
function scanAndLogCitations(i) {
|
|
14905
|
-
|
|
14906
|
-
|
|
14907
|
-
|
|
14908
|
-
|
|
14909
|
-
|
|
14910
|
-
|
|
14911
|
-
|
|
14912
|
-
|
|
14913
|
-
|
|
14914
|
-
|
|
14915
|
-
|
|
14916
|
-
|
|
14917
|
-
|
|
14918
|
-
|
|
14919
|
-
delivered
|
|
14920
|
-
|
|
14921
|
-
|
|
14922
|
-
|
|
14923
|
-
|
|
14924
|
-
|
|
14925
|
-
|
|
14926
|
-
|
|
14927
|
-
|
|
14928
|
-
|
|
14929
|
-
|
|
14930
|
-
|
|
14931
|
-
|
|
14932
|
-
|
|
14933
|
-
|
|
15099
|
+
return scanCitations([i], i);
|
|
15100
|
+
}
|
|
15101
|
+
function scanCitations(texts, o) {
|
|
15102
|
+
if (!texts.length)
|
|
15103
|
+
return [];
|
|
15104
|
+
const now = o.sink?.now?.() ?? /* @__PURE__ */ new Date();
|
|
15105
|
+
const lookbackMs = (o.lookbackDays ?? CITE_LOOKBACK_DAYS) * DAY_MS4;
|
|
15106
|
+
const ats = texts.map((t) => (t.at ?? now).getTime());
|
|
15107
|
+
const records = readAuditRecords(void 0, new Date(Math.min(...ats) - lookbackMs), o.sink?.dir ?? defaultAuditDir()).filter((r) => r.itemId && r.project === o.project);
|
|
15108
|
+
const already = new Set(records.filter((r) => r.event === "item.cited").map((r) => `${r.ref}|${r.itemId}`));
|
|
15109
|
+
const deliveries = records.filter((r) => (r.event === "item.surfaced" || r.event === "item.shown" || r.event === "item.searched") && !(o.session && r.session && r.session !== o.session));
|
|
15110
|
+
const events = [];
|
|
15111
|
+
texts.forEach((t, n) => {
|
|
15112
|
+
const at = ats[n];
|
|
15113
|
+
const delivered = /* @__PURE__ */ new Map();
|
|
15114
|
+
for (const r of deliveries) {
|
|
15115
|
+
const ts = Date.parse(r.ts);
|
|
15116
|
+
if (ts <= at && ts >= at - lookbackMs)
|
|
15117
|
+
delivered.set(r.itemId, r);
|
|
15118
|
+
}
|
|
15119
|
+
for (const [itemId, r] of delivered) {
|
|
15120
|
+
if (already.has(`${t.ref}|${itemId}`) || !mentionsId(t.text, itemId))
|
|
15121
|
+
continue;
|
|
15122
|
+
already.add(`${t.ref}|${itemId}`);
|
|
15123
|
+
events.push({
|
|
15124
|
+
kb: String(r.kb ?? ""),
|
|
15125
|
+
level: String(r.level ?? "project"),
|
|
15126
|
+
project: o.project,
|
|
15127
|
+
domain: String(r.domain ?? "rules"),
|
|
15128
|
+
itemId,
|
|
15129
|
+
event: "item.cited",
|
|
15130
|
+
ref: t.ref,
|
|
15131
|
+
...o.agent ? { agent: o.agent } : {},
|
|
15132
|
+
...o.session ? { session: o.session } : {}
|
|
15133
|
+
});
|
|
15134
|
+
}
|
|
15135
|
+
});
|
|
15136
|
+
appendAudit(events, o.sink);
|
|
15137
|
+
return events.map((e) => e.itemId);
|
|
14934
15138
|
}
|
|
14935
15139
|
function readGitMessages(repo, since, run) {
|
|
14936
|
-
|
|
15140
|
+
return parseLog(run(["-C", repo, "log", "--all", `--since=${since.toISOString()}`, LOG_FORMAT]));
|
|
15141
|
+
}
|
|
15142
|
+
function readBranchOnlyMessages(repo, run, max = 200) {
|
|
15143
|
+
const branch = run(["-C", repo, "rev-parse", "--abbrev-ref", "HEAD"]).trim();
|
|
15144
|
+
if (!branch)
|
|
15145
|
+
return [];
|
|
15146
|
+
const own = branch === "HEAD" ? [] : [`--exclude=${branch}`];
|
|
15147
|
+
return parseLog(run(["-C", repo, "log", `--max-count=${max}`, "HEAD", "--not", ...own, "--branches", ...own.length ? [`--exclude=*/${branch}`] : [], "--remotes", LOG_FORMAT]));
|
|
15148
|
+
}
|
|
15149
|
+
function parseLog(out) {
|
|
14937
15150
|
return out.split("").filter((c) => c.trim()).map((c) => {
|
|
14938
15151
|
const [sha, at, ...rest] = c.split("");
|
|
14939
15152
|
return { sha: sha.trim(), at: new Date(at), text: rest.join("") };
|
|
14940
15153
|
});
|
|
14941
15154
|
}
|
|
14942
|
-
var DAY_MS4, CITE_LOOKBACK_DAYS, escapeRe2, mentionsId;
|
|
15155
|
+
var DAY_MS4, CITE_LOOKBACK_DAYS, escapeRe2, mentionsId, LOG_FORMAT;
|
|
14943
15156
|
var init_cite = __esm({
|
|
14944
15157
|
"packages/core/dist/knowledge/cite.js"() {
|
|
14945
15158
|
init_audit();
|
|
@@ -14948,6 +15161,7 @@ var init_cite = __esm({
|
|
|
14948
15161
|
CITE_LOOKBACK_DAYS = 7;
|
|
14949
15162
|
escapeRe2 = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
14950
15163
|
mentionsId = (text, id) => new RegExp(`(?<![\\w.-])${escapeRe2(id)}(?![\\w-])`).test(text);
|
|
15164
|
+
LOG_FORMAT = "--format=%x1e%H%x1f%cI%x1f%B";
|
|
14951
15165
|
}
|
|
14952
15166
|
});
|
|
14953
15167
|
|
|
@@ -14965,6 +15179,7 @@ var init_knowledge2 = __esm({
|
|
|
14965
15179
|
init_migrate();
|
|
14966
15180
|
init_verify();
|
|
14967
15181
|
init_ingest();
|
|
15182
|
+
init_errata();
|
|
14968
15183
|
init_anchor();
|
|
14969
15184
|
init_extract();
|
|
14970
15185
|
init_match();
|
|
@@ -15024,6 +15239,7 @@ __export(dist_exports, {
|
|
|
15024
15239
|
NOISY_RATE: () => NOISY_RATE,
|
|
15025
15240
|
OPERATOR_INITIATED_COMMANDS: () => OPERATOR_INITIATED_COMMANDS,
|
|
15026
15241
|
PANE_IDLE_AFTER_MS: () => PANE_IDLE_AFTER_MS,
|
|
15242
|
+
PASS_THROUGH: () => PASS_THROUGH,
|
|
15027
15243
|
PROBE_QUIET_MS: () => PROBE_QUIET_MS,
|
|
15028
15244
|
PROMPT_MIN_SCORE: () => PROMPT_MIN_SCORE,
|
|
15029
15245
|
PROMPT_RULE_CAP: () => PROMPT_RULE_CAP,
|
|
@@ -15163,6 +15379,7 @@ __export(dist_exports, {
|
|
|
15163
15379
|
encodeMsg: () => encodeMsg,
|
|
15164
15380
|
ensureDaemon: () => ensureDaemon,
|
|
15165
15381
|
ensureGitRepo: () => ensureGitRepo,
|
|
15382
|
+
ensureKbGitignore: () => ensureKbGitignore,
|
|
15166
15383
|
ensureSocksDir: () => ensureSocksDir,
|
|
15167
15384
|
escalationsFile: () => escalationsFile,
|
|
15168
15385
|
evaluateCodeConflict: () => evaluateCodeConflict,
|
|
@@ -15213,6 +15430,7 @@ __export(dist_exports, {
|
|
|
15213
15430
|
isDaemonSocketLive: () => isDaemonSocketLive,
|
|
15214
15431
|
isGateCacheEnabled: () => isGateCacheEnabled,
|
|
15215
15432
|
isGateSession: () => isGateSession,
|
|
15433
|
+
isGatedRef: () => isGatedRef,
|
|
15216
15434
|
isNotifyActive: () => isNotifyActive,
|
|
15217
15435
|
isOperatorInitiatedCommand: () => isOperatorInitiatedCommand,
|
|
15218
15436
|
isPendingProposalDup: () => isPendingProposalDup,
|
|
@@ -15230,6 +15448,7 @@ __export(dist_exports, {
|
|
|
15230
15448
|
launchOneWorkspace: () => launchOneWorkspace,
|
|
15231
15449
|
legacyKbDir: () => legacyKbDir,
|
|
15232
15450
|
listSessions: () => listSessions,
|
|
15451
|
+
loadErrata: () => loadErrata,
|
|
15233
15452
|
loadKbRules: () => loadKbRules,
|
|
15234
15453
|
loadPending: () => loadPending,
|
|
15235
15454
|
loadProposals: () => loadProposals,
|
|
@@ -15264,6 +15483,7 @@ __export(dist_exports, {
|
|
|
15264
15483
|
normalizedViews: () => normalizedViews,
|
|
15265
15484
|
notePaneScreen: () => notePaneScreen,
|
|
15266
15485
|
notifyToggle: () => notifyToggle,
|
|
15486
|
+
orphanedErrata: () => orphanedErrata,
|
|
15267
15487
|
parseBearer: () => parseBearer,
|
|
15268
15488
|
parseClassifierVerdict: () => parseClassifierVerdict,
|
|
15269
15489
|
parseCommand: () => parseCommand,
|
|
@@ -15288,6 +15508,7 @@ __export(dist_exports, {
|
|
|
15288
15508
|
pruneTopics: () => pruneTopics,
|
|
15289
15509
|
purgeExpiredWorkItems: () => purgeExpiredWorkItems,
|
|
15290
15510
|
readAuditRecords: () => readAuditRecords,
|
|
15511
|
+
readBranchOnlyMessages: () => readBranchOnlyMessages,
|
|
15291
15512
|
readCaptainAddress: () => readCaptainAddress,
|
|
15292
15513
|
readCursor: () => readCursor,
|
|
15293
15514
|
readEscalations: () => readEscalations,
|
|
@@ -15314,6 +15535,7 @@ __export(dist_exports, {
|
|
|
15314
15535
|
refFor: () => refFor,
|
|
15315
15536
|
releaseDaemonLock: () => releaseDaemonLock,
|
|
15316
15537
|
removeRunningMarker: () => removeRunningMarker,
|
|
15538
|
+
removeSource: () => removeSource,
|
|
15317
15539
|
renderEnvAssignments: () => renderEnvAssignments,
|
|
15318
15540
|
renderPlist: () => renderPlist,
|
|
15319
15541
|
renderReport: () => renderReport,
|
|
@@ -15376,6 +15598,7 @@ __export(dist_exports, {
|
|
|
15376
15598
|
saveSessions: () => saveSessions,
|
|
15377
15599
|
saveState: () => saveState,
|
|
15378
15600
|
scanAndLogCitations: () => scanAndLogCitations,
|
|
15601
|
+
scanCitations: () => scanCitations,
|
|
15379
15602
|
scheduleFile: () => scheduleFile,
|
|
15380
15603
|
scoreKb: () => scoreKb,
|
|
15381
15604
|
scoresFile: () => scoresFile,
|
|
@@ -15396,6 +15619,7 @@ __export(dist_exports, {
|
|
|
15396
15619
|
sideNextAutoName: () => sideNextAutoName,
|
|
15397
15620
|
sideTitleFor: () => sideTitleFor,
|
|
15398
15621
|
snapshotSources: () => snapshotSources,
|
|
15622
|
+
sourceCovers: () => sourceCovers,
|
|
15399
15623
|
spansOverlap: () => spansOverlap,
|
|
15400
15624
|
splitSections: () => splitSections,
|
|
15401
15625
|
splitStatement: () => splitStatement,
|
|
@@ -15530,7 +15754,7 @@ import { readdirSync as readdirSync4, readFileSync as readFileSync12 } from "fs"
|
|
|
15530
15754
|
import { join as join18 } from "path";
|
|
15531
15755
|
|
|
15532
15756
|
// packages/agents/dist/claude/registry.js
|
|
15533
|
-
import
|
|
15757
|
+
import fs31 from "fs";
|
|
15534
15758
|
import { join as join17 } from "path";
|
|
15535
15759
|
import { homedir as homedir7 } from "os";
|
|
15536
15760
|
var CLAUDE_SESSIONS_DIR = join17(homedir7(), ".claude", "sessions");
|
|
@@ -15575,11 +15799,11 @@ function toLifecycleSnapshot(entry, taskId, alive, now) {
|
|
|
15575
15799
|
function readClaudeStatusBySocketPath(socketPath) {
|
|
15576
15800
|
let files;
|
|
15577
15801
|
try {
|
|
15578
|
-
files =
|
|
15802
|
+
files = fs31.readdirSync(CLAUDE_SESSIONS_DIR);
|
|
15579
15803
|
} catch {
|
|
15580
15804
|
return void 0;
|
|
15581
15805
|
}
|
|
15582
|
-
const entries = parseRegistryDir(files, (name) =>
|
|
15806
|
+
const entries = parseRegistryDir(files, (name) => fs31.readFileSync(join17(CLAUDE_SESSIONS_DIR, name), "utf8"));
|
|
15583
15807
|
const entry = entries.find((e) => e.messagingSocketPath === socketPath);
|
|
15584
15808
|
if (!entry)
|
|
15585
15809
|
return void 0;
|
|
@@ -15602,38 +15826,38 @@ import { homedir as homedir8 } from "os";
|
|
|
15602
15826
|
var SQUADRANT_STATE_DIR = join19(homedir8(), ".config", "squadrant", "state");
|
|
15603
15827
|
|
|
15604
15828
|
// packages/agents/dist/drivers/launch-cmd.js
|
|
15605
|
-
import
|
|
15606
|
-
import
|
|
15829
|
+
import fs32 from "fs";
|
|
15830
|
+
import path32 from "path";
|
|
15607
15831
|
|
|
15608
15832
|
// packages/agents/dist/projection/cursor.js
|
|
15609
15833
|
import { mkdir, readFile, writeFile } from "fs/promises";
|
|
15610
|
-
import
|
|
15834
|
+
import path33 from "path";
|
|
15611
15835
|
import os10 from "os";
|
|
15612
15836
|
|
|
15613
15837
|
// packages/agents/dist/projection/codex.js
|
|
15614
15838
|
import { mkdir as mkdir2, readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
|
|
15615
|
-
import
|
|
15839
|
+
import path34 from "path";
|
|
15616
15840
|
import os11 from "os";
|
|
15617
15841
|
|
|
15618
15842
|
// packages/agents/dist/projection/gemini.js
|
|
15619
15843
|
import { mkdir as mkdir3, readFile as readFile3, writeFile as writeFile3 } from "fs/promises";
|
|
15620
|
-
import
|
|
15844
|
+
import path35 from "path";
|
|
15621
15845
|
import os12 from "os";
|
|
15622
15846
|
|
|
15623
15847
|
// packages/agents/dist/projection/opencode.js
|
|
15624
15848
|
import { mkdir as mkdir4, readFile as readFile4, writeFile as writeFile4 } from "fs/promises";
|
|
15625
|
-
import
|
|
15849
|
+
import path36 from "path";
|
|
15626
15850
|
import os13 from "os";
|
|
15627
15851
|
|
|
15628
15852
|
// packages/agents/dist/projection/opencode-skills.js
|
|
15629
|
-
import
|
|
15853
|
+
import fs33 from "fs";
|
|
15630
15854
|
import os14 from "os";
|
|
15631
|
-
import
|
|
15855
|
+
import path37 from "path";
|
|
15632
15856
|
var OPENCODE_SKILL_MARKER = ".squadrant-managed";
|
|
15633
15857
|
var MARKER_BODY = "squadrant\n";
|
|
15634
15858
|
function defaultOpencodeSkillsRoot(env = process.env) {
|
|
15635
|
-
const configHome = env.XDG_CONFIG_HOME ||
|
|
15636
|
-
return
|
|
15859
|
+
const configHome = env.XDG_CONFIG_HOME || path37.join(os14.homedir(), ".config");
|
|
15860
|
+
return path37.join(configHome, "opencode", "skills");
|
|
15637
15861
|
}
|
|
15638
15862
|
var SAFE_NAME = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
|
|
15639
15863
|
function parseSkillName(raw) {
|
|
@@ -15648,62 +15872,62 @@ function parseSkillName(raw) {
|
|
|
15648
15872
|
}
|
|
15649
15873
|
function listSourceSkills(sourceSkillsDir) {
|
|
15650
15874
|
const out = /* @__PURE__ */ new Map();
|
|
15651
|
-
if (!
|
|
15875
|
+
if (!fs33.existsSync(sourceSkillsDir))
|
|
15652
15876
|
return out;
|
|
15653
|
-
for (const entry of
|
|
15877
|
+
for (const entry of fs33.readdirSync(sourceSkillsDir, { withFileTypes: true })) {
|
|
15654
15878
|
if (!entry.isDirectory())
|
|
15655
15879
|
continue;
|
|
15656
|
-
const skillPath =
|
|
15657
|
-
if (!
|
|
15880
|
+
const skillPath = path37.join(sourceSkillsDir, entry.name, "SKILL.md");
|
|
15881
|
+
if (!fs33.existsSync(skillPath))
|
|
15658
15882
|
continue;
|
|
15659
|
-
const name = parseSkillName(
|
|
15883
|
+
const name = parseSkillName(fs33.readFileSync(skillPath, "utf-8"));
|
|
15660
15884
|
if (name && SAFE_NAME.test(name))
|
|
15661
15885
|
out.set(name, skillPath);
|
|
15662
15886
|
}
|
|
15663
15887
|
return out;
|
|
15664
15888
|
}
|
|
15665
15889
|
function hasMarker(dir) {
|
|
15666
|
-
return
|
|
15890
|
+
return fs33.existsSync(path37.join(dir, OPENCODE_SKILL_MARKER));
|
|
15667
15891
|
}
|
|
15668
15892
|
function syncOpencodeSkills(opts) {
|
|
15669
15893
|
const result = { written: [], unchanged: [], removed: [], skipped: [] };
|
|
15670
15894
|
const wanted = listSourceSkills(opts.sourceSkillsDir);
|
|
15671
|
-
if (wanted.size === 0 && !
|
|
15895
|
+
if (wanted.size === 0 && !fs33.existsSync(opts.sourceSkillsDir))
|
|
15672
15896
|
return result;
|
|
15673
15897
|
if (!opts.dryRun)
|
|
15674
|
-
|
|
15898
|
+
fs33.mkdirSync(opts.skillsRoot, { recursive: true });
|
|
15675
15899
|
for (const [name, srcPath] of wanted) {
|
|
15676
|
-
const targetDir =
|
|
15677
|
-
const targetSkill =
|
|
15900
|
+
const targetDir = path37.join(opts.skillsRoot, name);
|
|
15901
|
+
const targetSkill = path37.join(targetDir, "SKILL.md");
|
|
15678
15902
|
const managed = hasMarker(targetDir);
|
|
15679
|
-
if (
|
|
15903
|
+
if (fs33.existsSync(targetSkill) && !managed) {
|
|
15680
15904
|
result.skipped.push({ name, reason: "foreign-collision" });
|
|
15681
15905
|
continue;
|
|
15682
15906
|
}
|
|
15683
|
-
const current =
|
|
15684
|
-
if (current && current.equals(
|
|
15907
|
+
const current = fs33.existsSync(targetSkill) ? fs33.readFileSync(targetSkill) : null;
|
|
15908
|
+
if (current && current.equals(fs33.readFileSync(srcPath))) {
|
|
15685
15909
|
if (!managed && !opts.dryRun) {
|
|
15686
|
-
|
|
15910
|
+
fs33.writeFileSync(path37.join(targetDir, OPENCODE_SKILL_MARKER), MARKER_BODY);
|
|
15687
15911
|
}
|
|
15688
15912
|
result.unchanged.push(name);
|
|
15689
15913
|
continue;
|
|
15690
15914
|
}
|
|
15691
15915
|
if (!opts.dryRun) {
|
|
15692
|
-
|
|
15693
|
-
|
|
15694
|
-
|
|
15916
|
+
fs33.mkdirSync(targetDir, { recursive: true });
|
|
15917
|
+
fs33.copyFileSync(srcPath, targetSkill);
|
|
15918
|
+
fs33.writeFileSync(path37.join(targetDir, OPENCODE_SKILL_MARKER), MARKER_BODY);
|
|
15695
15919
|
}
|
|
15696
15920
|
result.written.push(name);
|
|
15697
15921
|
}
|
|
15698
|
-
if (
|
|
15699
|
-
for (const entry of
|
|
15922
|
+
if (fs33.existsSync(opts.skillsRoot)) {
|
|
15923
|
+
for (const entry of fs33.readdirSync(opts.skillsRoot, { withFileTypes: true })) {
|
|
15700
15924
|
if (!entry.isDirectory() || wanted.has(entry.name))
|
|
15701
15925
|
continue;
|
|
15702
|
-
const dir =
|
|
15926
|
+
const dir = path37.join(opts.skillsRoot, entry.name);
|
|
15703
15927
|
if (!hasMarker(dir))
|
|
15704
15928
|
continue;
|
|
15705
15929
|
if (!opts.dryRun)
|
|
15706
|
-
|
|
15930
|
+
fs33.rmSync(dir, { recursive: true, force: true });
|
|
15707
15931
|
result.removed.push(entry.name);
|
|
15708
15932
|
}
|
|
15709
15933
|
}
|
|
@@ -15711,7 +15935,7 @@ function syncOpencodeSkills(opts) {
|
|
|
15711
15935
|
}
|
|
15712
15936
|
function syncShippedOpencodeSkills(opts) {
|
|
15713
15937
|
return syncOpencodeSkills({
|
|
15714
|
-
sourceSkillsDir:
|
|
15938
|
+
sourceSkillsDir: path37.join(opts.pkgRoot, "plugin", "skills"),
|
|
15715
15939
|
skillsRoot: opts.skillsRoot ?? defaultOpencodeSkillsRoot(),
|
|
15716
15940
|
dryRun: opts.dryRun
|
|
15717
15941
|
});
|
|
@@ -15719,7 +15943,7 @@ function syncShippedOpencodeSkills(opts) {
|
|
|
15719
15943
|
|
|
15720
15944
|
// packages/agents/dist/projection/claude.js
|
|
15721
15945
|
import { mkdir as mkdir5, readFile as readFile5, writeFile as writeFile5 } from "fs/promises";
|
|
15722
|
-
import
|
|
15946
|
+
import path38 from "path";
|
|
15723
15947
|
import os15 from "os";
|
|
15724
15948
|
|
|
15725
15949
|
// packages/agents/dist/codex/app-server-client.js
|
|
@@ -17064,9 +17288,9 @@ var ClaudeReceiptListener = class {
|
|
|
17064
17288
|
};
|
|
17065
17289
|
|
|
17066
17290
|
// packages/agents/dist/claude/api-key-approval.js
|
|
17067
|
-
import
|
|
17291
|
+
import fs34 from "fs";
|
|
17068
17292
|
import os16 from "os";
|
|
17069
|
-
import
|
|
17293
|
+
import path39 from "path";
|
|
17070
17294
|
|
|
17071
17295
|
// packages/agents/dist/opencode/http-channel.js
|
|
17072
17296
|
init_dist2();
|
|
@@ -17158,10 +17382,10 @@ var OpencodeHttpChannel = class {
|
|
|
17158
17382
|
return cached;
|
|
17159
17383
|
const directory = this.directoryFor?.(taskId);
|
|
17160
17384
|
const createdAfterMs = this.createdAfterFor?.(taskId);
|
|
17161
|
-
for (const
|
|
17385
|
+
for (const path43 of ["/session?", "/api/session?"]) {
|
|
17162
17386
|
let res;
|
|
17163
17387
|
try {
|
|
17164
|
-
res = await this.request(`http://127.0.0.1:${port}${
|
|
17388
|
+
res = await this.request(`http://127.0.0.1:${port}${path43}`, { method: "GET" });
|
|
17165
17389
|
} catch {
|
|
17166
17390
|
return void 0;
|
|
17167
17391
|
}
|
|
@@ -17235,9 +17459,9 @@ function createOpencodeFactAdapter(deps) {
|
|
|
17235
17459
|
}
|
|
17236
17460
|
|
|
17237
17461
|
// packages/agents/dist/rules-hooks/install.js
|
|
17238
|
-
import
|
|
17462
|
+
import fs35 from "fs";
|
|
17239
17463
|
import os17 from "os";
|
|
17240
|
-
import
|
|
17464
|
+
import path40 from "path";
|
|
17241
17465
|
|
|
17242
17466
|
// packages/workspaces/dist/runtimes/cmux.js
|
|
17243
17467
|
init_dist();
|
|
@@ -17975,9 +18199,9 @@ var NotifierRegistry = class {
|
|
|
17975
18199
|
};
|
|
17976
18200
|
|
|
17977
18201
|
// packages/workspaces/dist/workspaces/obsidian.js
|
|
17978
|
-
import
|
|
18202
|
+
import fs36 from "fs/promises";
|
|
17979
18203
|
import { existsSync as existsSync11 } from "fs";
|
|
17980
|
-
import
|
|
18204
|
+
import path41 from "path";
|
|
17981
18205
|
|
|
17982
18206
|
// packages/workspaces/dist/workspaces/registry.js
|
|
17983
18207
|
init_dist();
|
|
@@ -18527,9 +18751,9 @@ function defaultListFiles(dir) {
|
|
|
18527
18751
|
return [];
|
|
18528
18752
|
}
|
|
18529
18753
|
}
|
|
18530
|
-
function defaultReadFile(
|
|
18754
|
+
function defaultReadFile(path43) {
|
|
18531
18755
|
try {
|
|
18532
|
-
return readFileSync17(
|
|
18756
|
+
return readFileSync17(path43, "utf-8");
|
|
18533
18757
|
} catch {
|
|
18534
18758
|
return void 0;
|
|
18535
18759
|
}
|
|
@@ -18909,16 +19133,16 @@ function extractDetail(sub, payload) {
|
|
|
18909
19133
|
}
|
|
18910
19134
|
return void 0;
|
|
18911
19135
|
}
|
|
18912
|
-
function defaultReadFile2(
|
|
19136
|
+
function defaultReadFile2(path43) {
|
|
18913
19137
|
try {
|
|
18914
|
-
return readFileSync18(
|
|
19138
|
+
return readFileSync18(path43, "utf-8");
|
|
18915
19139
|
} catch {
|
|
18916
19140
|
return void 0;
|
|
18917
19141
|
}
|
|
18918
19142
|
}
|
|
18919
|
-
function defaultWriteFile(
|
|
18920
|
-
mkdirSync8(
|
|
18921
|
-
writeFileSync11(
|
|
19143
|
+
function defaultWriteFile(path43, content) {
|
|
19144
|
+
mkdirSync8(path43.replace(/\/[^/]+$/, ""), { recursive: true });
|
|
19145
|
+
writeFileSync11(path43, content, "utf-8");
|
|
18922
19146
|
}
|
|
18923
19147
|
|
|
18924
19148
|
// packages/workspaces/dist/crew-pane.js
|
|
@@ -19003,9 +19227,9 @@ init_dist();
|
|
|
19003
19227
|
|
|
19004
19228
|
// packages/cli/src/lib/daemon-restart-broadcast.ts
|
|
19005
19229
|
init_dist();
|
|
19006
|
-
import
|
|
19230
|
+
import path42 from "path";
|
|
19007
19231
|
function statePath2(stateRoot) {
|
|
19008
|
-
return
|
|
19232
|
+
return path42.join(stateRoot, "daemon-restart-state.json");
|
|
19009
19233
|
}
|
|
19010
19234
|
function computeRestartSignature(version, buildMtimeMs) {
|
|
19011
19235
|
return `${version}::${buildMtimeMs}`;
|
|
@@ -19054,7 +19278,7 @@ async function maybeBroadcastDaemonRestart(opts) {
|
|
|
19054
19278
|
|
|
19055
19279
|
// packages/cli/src/lib/captain-channel-factory.ts
|
|
19056
19280
|
import { createServer as createServer4, connect as netConnect } from "net";
|
|
19057
|
-
import
|
|
19281
|
+
import fs37 from "fs";
|
|
19058
19282
|
import { join as join26 } from "path";
|
|
19059
19283
|
import { randomUUID as randomUUID5 } from "crypto";
|
|
19060
19284
|
import chalk2 from "chalk";
|
|
@@ -19063,15 +19287,15 @@ var shared;
|
|
|
19063
19287
|
var registryEntryPath = () => join26(CLAUDE_SESSIONS_DIR, `${process.pid}.json`);
|
|
19064
19288
|
function unregisterSenderIdentity() {
|
|
19065
19289
|
try {
|
|
19066
|
-
|
|
19290
|
+
fs37.unlinkSync(registryEntryPath());
|
|
19067
19291
|
} catch {
|
|
19068
19292
|
}
|
|
19069
19293
|
}
|
|
19070
19294
|
function registerSenderIdentity(socketPath) {
|
|
19071
19295
|
try {
|
|
19072
19296
|
unregisterSenderIdentity();
|
|
19073
|
-
|
|
19074
|
-
|
|
19297
|
+
fs37.mkdirSync(CLAUDE_SESSIONS_DIR, { recursive: true });
|
|
19298
|
+
fs37.writeFileSync(
|
|
19075
19299
|
registryEntryPath(),
|
|
19076
19300
|
JSON.stringify({
|
|
19077
19301
|
pid: process.pid,
|
|
@@ -19097,7 +19321,7 @@ async function sharedReceiptListener() {
|
|
|
19097
19321
|
// must never be the reason we refuse to start.
|
|
19098
19322
|
unlinkStale: (p) => {
|
|
19099
19323
|
try {
|
|
19100
|
-
|
|
19324
|
+
fs37.unlinkSync(p);
|
|
19101
19325
|
} catch {
|
|
19102
19326
|
}
|
|
19103
19327
|
},
|
|
@@ -19122,7 +19346,7 @@ async function buildCaptainChannel() {
|
|
|
19122
19346
|
// in /tmp/x registers cwd "/private/tmp/x" on macOS, so cwd matching silently
|
|
19123
19347
|
// missed and every captain ping reported accepted-unconfirmed.
|
|
19124
19348
|
statusFor: (taskId) => readClaudeStatusBySocketPath(captainSocketPath(taskId)),
|
|
19125
|
-
wire: (p, e) => writeLine(p, e, { connect: (
|
|
19349
|
+
wire: (p, e) => writeLine(p, e, { connect: (path43) => netConnect(path43) }),
|
|
19126
19350
|
receipts,
|
|
19127
19351
|
newMsgId: () => randomUUID5(),
|
|
19128
19352
|
sleep: (ms) => new Promise((r) => setTimeout(r, ms)),
|