squadrant 0.27.1 → 0.28.1
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 +906 -608
- package/dist/index.js.map +1 -1
- package/dist/squadrantd.js +576 -325
- 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 {
|
|
@@ -9473,6 +9494,35 @@ function expandSource(kbRoot, entry) {
|
|
|
9473
9494
|
const re = globToRegExp(abs.split(path16.sep).join("/"));
|
|
9474
9495
|
return walkFiles(root).filter((f) => re.test(f.split(path16.sep).join("/"))).sort();
|
|
9475
9496
|
}
|
|
9497
|
+
function refCandidates(kbRoot, sources, ref) {
|
|
9498
|
+
const asIs = path16.resolve(kbRoot, expandHome(ref));
|
|
9499
|
+
if (path16.isAbsolute(expandHome(ref)))
|
|
9500
|
+
return [asIs];
|
|
9501
|
+
const bases = /* @__PURE__ */ new Set([kbRoot]);
|
|
9502
|
+
for (const s of sources) {
|
|
9503
|
+
let d = path16.resolve(kbRoot, expandHome(s.path.split(/[*?[{]/)[0]));
|
|
9504
|
+
for (let i = 0; i < 6 && d !== path16.dirname(d); i++) {
|
|
9505
|
+
d = path16.dirname(d);
|
|
9506
|
+
bases.add(d);
|
|
9507
|
+
}
|
|
9508
|
+
}
|
|
9509
|
+
return [.../* @__PURE__ */ new Set([asIs, ...[...bases].map((b) => path16.join(b, ref))])];
|
|
9510
|
+
}
|
|
9511
|
+
function refPath(kbRoot, sources, ref) {
|
|
9512
|
+
const cands = refCandidates(kbRoot, sources, ref);
|
|
9513
|
+
return cands.find(isFile) ?? cands.find((f) => sources.some((e) => entryCovers(kbRoot, e, f))) ?? cands[0];
|
|
9514
|
+
}
|
|
9515
|
+
function refCanon(kbRoot, sources) {
|
|
9516
|
+
const memo = /* @__PURE__ */ new Map();
|
|
9517
|
+
return (ref) => {
|
|
9518
|
+
let c = memo.get(ref);
|
|
9519
|
+
if (c === void 0) {
|
|
9520
|
+
c = refFor(kbRoot, refPath(kbRoot, sources, ref));
|
|
9521
|
+
memo.set(ref, c);
|
|
9522
|
+
}
|
|
9523
|
+
return c;
|
|
9524
|
+
};
|
|
9525
|
+
}
|
|
9476
9526
|
function detectChange(kbRoot, file) {
|
|
9477
9527
|
const ref = refFor(kbRoot, file);
|
|
9478
9528
|
const st = fs15.statSync(file);
|
|
@@ -9569,7 +9619,7 @@ async function planIngest(kbRoot, opts) {
|
|
|
9569
9619
|
}
|
|
9570
9620
|
return plan;
|
|
9571
9621
|
}
|
|
9572
|
-
var execFileAsync, CONVERTED_DIR, DEFAULT_MAX_SECTIONS_PER_PASS, CHARS_PER_TOKEN, PASS_THROUGH, SECTION_TARGET_CHARS, markitdownConverter, expandHome,
|
|
9622
|
+
var execFileAsync, CONVERTED_DIR, DEFAULT_MAX_SECTIONS_PER_PASS, CHARS_PER_TOKEN, PASS_THROUGH, SECTION_TARGET_CHARS, markitdownConverter, expandHome, cacheKey, convertedFile, stampFile, isFile, resolveSourceRef, entryCovers, sourceCovers, isGatedRef, sha256;
|
|
9573
9623
|
var init_ingest = __esm({
|
|
9574
9624
|
"packages/core/dist/knowledge/ingest.js"() {
|
|
9575
9625
|
execFileAsync = promisify2(execFile2);
|
|
@@ -9583,10 +9633,17 @@ var init_ingest = __esm({
|
|
|
9583
9633
|
return stdout;
|
|
9584
9634
|
};
|
|
9585
9635
|
expandHome = (p) => p === "~" || p.startsWith("~/") ? path16.join(os7.homedir(), p.slice(1)) : p;
|
|
9586
|
-
fileForRef = (kbRoot, ref) => path16.resolve(kbRoot, expandHome(ref));
|
|
9587
9636
|
cacheKey = (ref) => `${ref.replace(/[^A-Za-z0-9._-]+/g, "_")}.${crypto3.createHash("sha1").update(ref).digest("hex").slice(0, 6)}`;
|
|
9588
9637
|
convertedFile = (kbRoot, ref) => path16.join(kbRoot, CONVERTED_DIR, `${cacheKey(ref)}.md`);
|
|
9589
9638
|
stampFile = (kbRoot, ref) => path16.join(kbRoot, CONVERTED_DIR, `${cacheKey(ref)}.sha`);
|
|
9639
|
+
isFile = (f) => fs15.existsSync(f) && fs15.statSync(f).isFile();
|
|
9640
|
+
resolveSourceRef = (kbRoot, sources, ref) => refCandidates(kbRoot, sources, ref).find(isFile);
|
|
9641
|
+
entryCovers = (kbRoot, entry, file) => {
|
|
9642
|
+
const abs = path16.resolve(kbRoot, expandHome(entry.path));
|
|
9643
|
+
return /[*?]/.test(entry.path) ? globToRegExp(abs.split(path16.sep).join("/")).test(file.split(path16.sep).join("/")) : abs === file;
|
|
9644
|
+
};
|
|
9645
|
+
sourceCovers = (kbRoot, sources, entry, ref) => entryCovers(kbRoot, entry, refPath(kbRoot, sources, ref));
|
|
9646
|
+
isGatedRef = (kbRoot, sources, ref) => sources.some((e) => e.review === "required" && sourceCovers(kbRoot, sources, e, ref));
|
|
9590
9647
|
sha256 = (file) => crypto3.createHash("sha256").update(fs15.readFileSync(file)).digest("hex");
|
|
9591
9648
|
}
|
|
9592
9649
|
});
|
|
@@ -9669,7 +9726,6 @@ var init_verify = __esm({
|
|
|
9669
9726
|
|
|
9670
9727
|
// packages/core/dist/knowledge/store.js
|
|
9671
9728
|
import fs16 from "fs";
|
|
9672
|
-
import os8 from "os";
|
|
9673
9729
|
import path17 from "path";
|
|
9674
9730
|
import matter2 from "gray-matter";
|
|
9675
9731
|
function duplicateIdProblem(id, ignored, used) {
|
|
@@ -9730,18 +9786,6 @@ function loadRulesDir(dir, layer, opts = {}) {
|
|
|
9730
9786
|
}
|
|
9731
9787
|
return { rules, errors };
|
|
9732
9788
|
}
|
|
9733
|
-
function resolveSourceRef(ref, kbRoot, sources) {
|
|
9734
|
-
const bases = /* @__PURE__ */ new Set([kbRoot]);
|
|
9735
|
-
for (const s of sources) {
|
|
9736
|
-
let d = path17.resolve(kbRoot, expandHome2(s.path.split(/[*?[{]/)[0]));
|
|
9737
|
-
for (let i = 0; i < 6 && d !== path17.dirname(d); i++) {
|
|
9738
|
-
d = path17.dirname(d);
|
|
9739
|
-
bases.add(d);
|
|
9740
|
-
}
|
|
9741
|
-
}
|
|
9742
|
-
const cands = [path17.resolve(kbRoot, expandHome2(ref)), ...[...bases].map((b) => path17.join(b, ref))];
|
|
9743
|
-
return cands.find((c) => fs16.existsSync(c) && fs16.statSync(c).isFile());
|
|
9744
|
-
}
|
|
9745
9789
|
function validateKb(opts) {
|
|
9746
9790
|
const { rules, errors } = loadRulesDir(opts.rulesDir, "kb", { includeProposed: true });
|
|
9747
9791
|
const checks = [];
|
|
@@ -9761,17 +9805,18 @@ function validateKb(opts) {
|
|
|
9761
9805
|
else
|
|
9762
9806
|
checks.push({ level: "ok", message: "no duplicate ids" });
|
|
9763
9807
|
const cache = /* @__PURE__ */ new Map();
|
|
9808
|
+
const canon = refCanon(opts.kbRoot, opts.sources);
|
|
9764
9809
|
let verified = 0, unresolved = 0, notIngested = 0;
|
|
9765
9810
|
for (const r of rules) {
|
|
9766
9811
|
r.sources.forEach((src, i) => {
|
|
9767
|
-
const file = resolveSourceRef(
|
|
9812
|
+
const file = resolveSourceRef(opts.kbRoot, opts.sources, src.ref);
|
|
9768
9813
|
if (!file) {
|
|
9769
9814
|
unresolved++;
|
|
9770
9815
|
return;
|
|
9771
9816
|
}
|
|
9772
9817
|
const key = `${src.ref}\0${file}`;
|
|
9773
9818
|
if (!cache.has(key)) {
|
|
9774
|
-
const conv = readState2(opts.kbRoot, src.ref) ? convertedFile(opts.kbRoot, src.ref) : null;
|
|
9819
|
+
const conv = readState2(opts.kbRoot, canon(src.ref)) ? convertedFile(opts.kbRoot, canon(src.ref)) : null;
|
|
9775
9820
|
const cached = !!conv && fs16.existsSync(conv);
|
|
9776
9821
|
cache.set(key, {
|
|
9777
9822
|
hay: normalizedViews(fs16.readFileSync(cached ? conv : file, "utf8")),
|
|
@@ -9779,9 +9824,14 @@ function validateKb(opts) {
|
|
|
9779
9824
|
});
|
|
9780
9825
|
}
|
|
9781
9826
|
const { hay, convertible } = cache.get(key);
|
|
9782
|
-
|
|
9827
|
+
const span = findQuote(hay, src.quote);
|
|
9828
|
+
if (span) {
|
|
9783
9829
|
verified++;
|
|
9784
|
-
|
|
9830
|
+
const active = r.status === "active" && !path17.relative(opts.rulesDir, r.file).split(path17.sep).includes(PROPOSED_DIR);
|
|
9831
|
+
const err = active ? (opts.errata ?? []).find((e) => canon(e.ref) === canon(src.ref) && ((o) => !!o && spansOverlap(o, span))(findQuote(hay, e.quote))) : void 0;
|
|
9832
|
+
if (err)
|
|
9833
|
+
checks.push({ level: "warn", message: `${r.id}: grounded in erratum ${err.id} (${err.reason}); re-check or retire it (${r.file})` });
|
|
9834
|
+
} else if (convertible)
|
|
9785
9835
|
notIngested++;
|
|
9786
9836
|
else
|
|
9787
9837
|
checks.push({ level: "fail", message: `quote not found in ${file}: ${r.id} sources[${i}] (${r.file})` });
|
|
@@ -9801,7 +9851,7 @@ function validateKb(opts) {
|
|
|
9801
9851
|
}
|
|
9802
9852
|
return { checks, ok: !checks.some((c) => c.level === "fail") };
|
|
9803
9853
|
}
|
|
9804
|
-
var NO_JS_FRONTMATTER
|
|
9854
|
+
var NO_JS_FRONTMATTER;
|
|
9805
9855
|
var init_store2 = __esm({
|
|
9806
9856
|
"packages/core/dist/knowledge/store.js"() {
|
|
9807
9857
|
init_dist();
|
|
@@ -9813,7 +9863,6 @@ var init_store2 = __esm({
|
|
|
9813
9863
|
throw new Error("only YAML front matter is allowed");
|
|
9814
9864
|
} } }
|
|
9815
9865
|
};
|
|
9816
|
-
expandHome2 = (p) => p === "~" || p.startsWith("~/") ? path17.join(os8.homedir(), p.slice(1)) : p;
|
|
9817
9866
|
}
|
|
9818
9867
|
});
|
|
9819
9868
|
|
|
@@ -12986,6 +13035,7 @@ var init_js_yaml = __esm({
|
|
|
12986
13035
|
// packages/core/dist/knowledge/sources.js
|
|
12987
13036
|
import fs19 from "fs";
|
|
12988
13037
|
import path19 from "path";
|
|
13038
|
+
import matter3 from "gray-matter";
|
|
12989
13039
|
function loadSources(kbRoot) {
|
|
12990
13040
|
const file = path19.join(kbRoot, "sources.yaml");
|
|
12991
13041
|
if (!fs19.existsSync(file))
|
|
@@ -13011,20 +13061,77 @@ function loadSources(kbRoot) {
|
|
|
13011
13061
|
});
|
|
13012
13062
|
return { sources, errors };
|
|
13013
13063
|
}
|
|
13064
|
+
function dropEntryBlock(text, entryPath) {
|
|
13065
|
+
const lines = text.split("\n");
|
|
13066
|
+
const q = entryPath.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
13067
|
+
const head = new RegExp(`^-\\s+path:\\s*(['"]?)${q}\\1\\s*(#.*)?$`);
|
|
13068
|
+
const i = lines.findIndex((l) => head.test(l));
|
|
13069
|
+
if (i < 0)
|
|
13070
|
+
return null;
|
|
13071
|
+
let j = i + 1;
|
|
13072
|
+
while (j < lines.length && /^\s+\S/.test(lines[j]))
|
|
13073
|
+
j++;
|
|
13074
|
+
return [...lines.slice(0, i), ...lines.slice(j)].join("\n");
|
|
13075
|
+
}
|
|
13076
|
+
function removeSource(kbRoot, rulesDir, entryPath, opts = {}) {
|
|
13077
|
+
const file = path19.join(kbRoot, "sources.yaml");
|
|
13078
|
+
const { sources } = loadSources(kbRoot);
|
|
13079
|
+
const entry = sources.find((s) => s.path === entryPath);
|
|
13080
|
+
if (!entry)
|
|
13081
|
+
throw new Error(`no sources.yaml entry with path '${entryPath}' (give it exactly as listed by \`knowledge sources\`)`);
|
|
13082
|
+
const edited = dropEntryBlock(fs19.readFileSync(file, "utf8"), entryPath);
|
|
13083
|
+
if (edited === null)
|
|
13084
|
+
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`);
|
|
13085
|
+
const res = { dryRun: !!opts.dryRun, entryRemoved: true, stripped: [], stale: [] };
|
|
13086
|
+
const writes = [];
|
|
13087
|
+
for (const rule of loadRulesDir(rulesDir, "kb").rules) {
|
|
13088
|
+
const kept = rule.sources.filter((s) => !sourceCovers(kbRoot, sources, entry, s.ref));
|
|
13089
|
+
if (kept.length === rule.sources.length)
|
|
13090
|
+
continue;
|
|
13091
|
+
res.stripped.push(rule.id);
|
|
13092
|
+
const parsed = matter3(fs19.readFileSync(rule.file, "utf8"), { engines: { javascript: () => {
|
|
13093
|
+
throw new Error("only YAML front matter is allowed");
|
|
13094
|
+
} } });
|
|
13095
|
+
const fm = { ...parsed.data, sources: kept };
|
|
13096
|
+
if (!kept.length) {
|
|
13097
|
+
res.stale.push(rule.id);
|
|
13098
|
+
if (fm.status === "active")
|
|
13099
|
+
fm.status = "stale";
|
|
13100
|
+
}
|
|
13101
|
+
writes.push({ file: rule.file, text: matter3.stringify(parsed.content, JSON.parse(JSON.stringify(fm))) });
|
|
13102
|
+
}
|
|
13103
|
+
res.stripped.sort();
|
|
13104
|
+
res.stale.sort();
|
|
13105
|
+
if (opts.dryRun)
|
|
13106
|
+
return res;
|
|
13107
|
+
for (const w of writes)
|
|
13108
|
+
fs19.writeFileSync(w.file, w.text);
|
|
13109
|
+
fs19.writeFileSync(file, edited);
|
|
13110
|
+
const name = opts.kbName ?? path19.basename(kbRoot);
|
|
13111
|
+
writeIndex(kbRoot, compileIndex(name, loadRulesDir(rulesDir, `kb:${name}`).rules));
|
|
13112
|
+
return res;
|
|
13113
|
+
}
|
|
13014
13114
|
var SOURCES_TEMPLATE;
|
|
13015
13115
|
var init_sources = __esm({
|
|
13016
13116
|
"packages/core/dist/knowledge/sources.js"() {
|
|
13017
13117
|
init_js_yaml();
|
|
13018
13118
|
init_dist();
|
|
13119
|
+
init_index_file();
|
|
13120
|
+
init_ingest();
|
|
13121
|
+
init_store2();
|
|
13019
13122
|
SOURCES_TEMPLATE = `# Trusted sources for this knowledge base (spec \xA73). Only these can produce rules.
|
|
13020
13123
|
# priority: company > project > agent (decides conflicts).
|
|
13021
13124
|
# sensitivity: local-only \u2192 never sent to a hosted model (D12).
|
|
13125
|
+
# review: required \u2192 new rules from this source wait in rules/_proposed/ for the operator; they never go live on their own.
|
|
13022
13126
|
#
|
|
13023
13127
|
# - path: raw/finance/**
|
|
13024
13128
|
# priority: company
|
|
13025
13129
|
# - path: ~/work/flooros/docs/handbook/**
|
|
13026
13130
|
# priority: project
|
|
13027
13131
|
# domain: coding
|
|
13132
|
+
# - path: raw/**
|
|
13133
|
+
# priority: agent
|
|
13134
|
+
# review: required
|
|
13028
13135
|
[]
|
|
13029
13136
|
`;
|
|
13030
13137
|
}
|
|
@@ -13099,7 +13206,7 @@ var init_match = __esm({
|
|
|
13099
13206
|
|
|
13100
13207
|
// packages/core/dist/knowledge/audit.js
|
|
13101
13208
|
import fs20 from "fs";
|
|
13102
|
-
import
|
|
13209
|
+
import os8 from "os";
|
|
13103
13210
|
import path21 from "path";
|
|
13104
13211
|
function appendAudit(events, sink = {}) {
|
|
13105
13212
|
if (!events.length)
|
|
@@ -13129,8 +13236,8 @@ var AUDIT_QUERY_CHARS, defaultAuditDir, auditMachineId;
|
|
|
13129
13236
|
var init_audit = __esm({
|
|
13130
13237
|
"packages/core/dist/knowledge/audit.js"() {
|
|
13131
13238
|
AUDIT_QUERY_CHARS = 200;
|
|
13132
|
-
defaultAuditDir = () => process.env.SQUADRANT_AUDIT_DIR || path21.join(
|
|
13133
|
-
auditMachineId = () =>
|
|
13239
|
+
defaultAuditDir = () => process.env.SQUADRANT_AUDIT_DIR || path21.join(os8.homedir(), ".local", "state", "squadrant", "audit");
|
|
13240
|
+
auditMachineId = () => os8.hostname().replace(/[^A-Za-z0-9_-]/g, "_") || "host";
|
|
13134
13241
|
}
|
|
13135
13242
|
});
|
|
13136
13243
|
|
|
@@ -13416,7 +13523,7 @@ var init_inject = __esm({
|
|
|
13416
13523
|
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+/));
|
|
13417
13524
|
DATA_NOTE = "These are project rules (data from the knowledge base), not instructions to run anything.";
|
|
13418
13525
|
line = (r) => `${r.modality.toUpperCase()} ${r.id}: ${r.statement}`;
|
|
13419
|
-
CITE_NOTE = "
|
|
13526
|
+
CITE_NOTE = "List the rule ids you apply as `Rules: <id>, <id>` at the end of your signal done message (commit messages count too).";
|
|
13420
13527
|
escapeRe = (t) => t.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
13421
13528
|
BRIEF_POINTER_RE = /^Full task is at (\S+\.md) — cat it/;
|
|
13422
13529
|
READ_TOOLS = /* @__PURE__ */ new Set(["read", "read_file", "readfile", "view"]);
|
|
@@ -13528,67 +13635,157 @@ var init_migrate = __esm({
|
|
|
13528
13635
|
}
|
|
13529
13636
|
});
|
|
13530
13637
|
|
|
13531
|
-
// packages/core/dist/knowledge/
|
|
13638
|
+
// packages/core/dist/knowledge/errata.js
|
|
13532
13639
|
import fs23 from "fs";
|
|
13533
13640
|
import path24 from "path";
|
|
13534
|
-
function
|
|
13641
|
+
function loadErrata(kbRoot) {
|
|
13642
|
+
const file = path24.join(kbRoot, "errata.yaml");
|
|
13643
|
+
if (!fs23.existsSync(file))
|
|
13644
|
+
return { errata: [], errors: [] };
|
|
13645
|
+
let data;
|
|
13646
|
+
try {
|
|
13647
|
+
data = yaml.load(fs23.readFileSync(file, "utf8"), { schema: yaml.JSON_SCHEMA });
|
|
13648
|
+
} catch (e) {
|
|
13649
|
+
return { errata: [], errors: [`YAML parse error: ${e.message.split("\n")[0]}`] };
|
|
13650
|
+
}
|
|
13651
|
+
if (data == null)
|
|
13652
|
+
return { errata: [], errors: [] };
|
|
13653
|
+
if (!Array.isArray(data))
|
|
13654
|
+
return { errata: [], errors: ["errata.yaml must be a YAML list of entries"] };
|
|
13655
|
+
const errata = [];
|
|
13656
|
+
const errors = [];
|
|
13657
|
+
data.forEach((entry, i) => {
|
|
13658
|
+
const problems = validateErratum(entry);
|
|
13659
|
+
if (problems.length)
|
|
13660
|
+
errors.push(...problems.map((p) => `entry ${i}: ${p}`));
|
|
13661
|
+
else
|
|
13662
|
+
errata.push(entry);
|
|
13663
|
+
});
|
|
13664
|
+
return { errata, errors };
|
|
13665
|
+
}
|
|
13666
|
+
function orphanedErrata(kbRoot, sources, errata, refs) {
|
|
13667
|
+
const canon = refCanon(kbRoot, sources);
|
|
13668
|
+
const only = refs ? new Set([...refs].map(canon)) : void 0;
|
|
13669
|
+
const hays = /* @__PURE__ */ new Map();
|
|
13670
|
+
const out = [];
|
|
13671
|
+
for (const e of errata) {
|
|
13672
|
+
const ref = canon(e.ref);
|
|
13673
|
+
if (only && !only.has(ref))
|
|
13674
|
+
continue;
|
|
13675
|
+
if (!hays.has(ref)) {
|
|
13676
|
+
const conv = readState2(kbRoot, ref) ? convertedFile(kbRoot, ref) : null;
|
|
13677
|
+
hays.set(ref, conv && fs23.existsSync(conv) ? normalizedViews(fs23.readFileSync(conv, "utf8")) : null);
|
|
13678
|
+
}
|
|
13679
|
+
const hay = hays.get(ref);
|
|
13680
|
+
if (hay && !findQuote(hay, e.quote))
|
|
13681
|
+
out.push({ id: e.id, ref: e.ref });
|
|
13682
|
+
}
|
|
13683
|
+
return out;
|
|
13684
|
+
}
|
|
13685
|
+
var init_errata = __esm({
|
|
13686
|
+
"packages/core/dist/knowledge/errata.js"() {
|
|
13687
|
+
init_js_yaml();
|
|
13688
|
+
init_dist();
|
|
13689
|
+
init_ingest();
|
|
13690
|
+
init_verify();
|
|
13691
|
+
}
|
|
13692
|
+
});
|
|
13693
|
+
|
|
13694
|
+
// packages/core/dist/knowledge/anchor.js
|
|
13695
|
+
import fs24 from "fs";
|
|
13696
|
+
import { execFileSync as execFileSync7 } from "child_process";
|
|
13697
|
+
import path25 from "path";
|
|
13698
|
+
function gitFiles(root) {
|
|
13699
|
+
try {
|
|
13700
|
+
const out = execFileSync7("git", ["ls-files", "-co", "--exclude-standard", "-z"], { cwd: root, encoding: "utf8", stdio: ["ignore", "pipe", "ignore"], maxBuffer: 64 * 1024 * 1024 });
|
|
13701
|
+
return out.split("\0").filter(Boolean).sort();
|
|
13702
|
+
} catch {
|
|
13703
|
+
return null;
|
|
13704
|
+
}
|
|
13705
|
+
}
|
|
13706
|
+
function* repoFiles(root, maxFiles) {
|
|
13535
13707
|
let count = 0;
|
|
13708
|
+
const listed = gitFiles(root);
|
|
13709
|
+
if (listed) {
|
|
13710
|
+
for (const rel of listed) {
|
|
13711
|
+
if (!CODE_EXT.has(path25.extname(rel)) || rel.split("/").slice(0, -1).some((d) => SKIP_DIRS.has(d)))
|
|
13712
|
+
continue;
|
|
13713
|
+
if (++count > maxFiles) {
|
|
13714
|
+
console.warn(`anchor: ${root} has more than ${maxFiles} code files; anchors cover only the first ${maxFiles}`);
|
|
13715
|
+
return;
|
|
13716
|
+
}
|
|
13717
|
+
yield path25.join(root, rel);
|
|
13718
|
+
}
|
|
13719
|
+
return;
|
|
13720
|
+
}
|
|
13536
13721
|
const stack = [root];
|
|
13537
13722
|
while (stack.length) {
|
|
13538
13723
|
const dir = stack.pop();
|
|
13539
13724
|
let ents;
|
|
13540
13725
|
try {
|
|
13541
|
-
ents =
|
|
13726
|
+
ents = fs24.readdirSync(dir, { withFileTypes: true }).sort((a, b) => a.name < b.name ? 1 : -1);
|
|
13542
13727
|
} catch {
|
|
13543
13728
|
continue;
|
|
13544
13729
|
}
|
|
13545
13730
|
for (const ent of ents) {
|
|
13546
13731
|
if (ent.isDirectory()) {
|
|
13547
13732
|
if (!SKIP_DIRS.has(ent.name))
|
|
13548
|
-
stack.push(
|
|
13549
|
-
} else if (ent.isFile() && CODE_EXT.has(
|
|
13550
|
-
if (++count >
|
|
13733
|
+
stack.push(path25.join(dir, ent.name));
|
|
13734
|
+
} else if (ent.isFile() && CODE_EXT.has(path25.extname(ent.name))) {
|
|
13735
|
+
if (++count > maxFiles) {
|
|
13736
|
+
console.warn(`anchor: ${root} has more than ${maxFiles} code files; anchors cover only the first ${maxFiles}`);
|
|
13551
13737
|
return;
|
|
13552
|
-
|
|
13738
|
+
}
|
|
13739
|
+
yield path25.join(dir, ent.name);
|
|
13553
13740
|
}
|
|
13554
13741
|
}
|
|
13555
13742
|
}
|
|
13556
13743
|
}
|
|
13557
|
-
function
|
|
13558
|
-
const
|
|
13559
|
-
|
|
13560
|
-
return null;
|
|
13561
|
-
const hits = [];
|
|
13562
|
-
for (const file of repoFiles(repoRoot)) {
|
|
13563
|
-
let text;
|
|
13744
|
+
function scanRepo(root, maxFiles) {
|
|
13745
|
+
const out = [];
|
|
13746
|
+
for (const file of repoFiles(root, maxFiles)) {
|
|
13564
13747
|
try {
|
|
13565
|
-
if (
|
|
13748
|
+
if (fs24.statSync(file).size > MAX_FILE_BYTES)
|
|
13566
13749
|
continue;
|
|
13567
|
-
text =
|
|
13750
|
+
const text = fs24.readFileSync(file, "utf8");
|
|
13751
|
+
const rel = path25.relative(root, file).split(path25.sep).join("/");
|
|
13752
|
+
out.push({ rel, text, hay: `${path25.relative(root, file)}
|
|
13753
|
+
${text}`.toLowerCase() });
|
|
13568
13754
|
} catch {
|
|
13569
13755
|
continue;
|
|
13570
13756
|
}
|
|
13571
|
-
|
|
13572
|
-
|
|
13757
|
+
}
|
|
13758
|
+
return out;
|
|
13759
|
+
}
|
|
13760
|
+
function computeAnchor(repoRoot, triggers, cache, maxFiles = MAX_FILES) {
|
|
13761
|
+
const terms2 = anchorTerms(triggers);
|
|
13762
|
+
if (!terms2.length || !fs24.existsSync(repoRoot))
|
|
13763
|
+
return null;
|
|
13764
|
+
let files = cache?.get(repoRoot);
|
|
13765
|
+
if (!files) {
|
|
13766
|
+
files = scanRepo(repoRoot, maxFiles);
|
|
13767
|
+
cache?.set(repoRoot, files);
|
|
13768
|
+
}
|
|
13769
|
+
const hits = [];
|
|
13770
|
+
for (const { rel, text, hay } of files) {
|
|
13573
13771
|
const score = terms2.filter((t) => hay.includes(t)).length;
|
|
13574
13772
|
if (!score)
|
|
13575
13773
|
continue;
|
|
13576
|
-
|
|
13577
|
-
hits.push({ rel: path24.relative(repoRoot, file).split(path24.sep).join("/"), score, symbols: symbols2 });
|
|
13774
|
+
hits.push({ rel, score, text });
|
|
13578
13775
|
}
|
|
13579
13776
|
if (!hits.length)
|
|
13580
13777
|
return null;
|
|
13581
13778
|
hits.sort((a, b) => b.score - a.score || (a.rel < b.rel ? -1 : 1));
|
|
13582
13779
|
const top = hits.slice(0, MAX_PATHS);
|
|
13583
|
-
const symbols = [...new Set(top.flatMap((h) => h.
|
|
13780
|
+
const symbols = [...new Set(top.flatMap((h) => [...h.text.matchAll(SYMBOL_RE)].map((m) => m[1]).filter((s) => terms2.some((t) => s.toLowerCase().includes(t)))))].sort().slice(0, MAX_SYMBOLS);
|
|
13584
13781
|
return { paths: top.map((h) => h.rel).sort(), ...symbols.length ? { symbols } : {} };
|
|
13585
13782
|
}
|
|
13586
13783
|
var SKIP_DIRS, CODE_EXT, MAX_FILES, MAX_FILE_BYTES, MAX_PATHS, MAX_SYMBOLS, SYMBOL_RE, anchorTerms;
|
|
13587
13784
|
var init_anchor = __esm({
|
|
13588
13785
|
"packages/core/dist/knowledge/anchor.js"() {
|
|
13589
|
-
SKIP_DIRS = /* @__PURE__ */ new Set([".git", "node_modules", "dist", "build", "coverage", ".next", ".worktrees", ".planning", ".converted"]);
|
|
13786
|
+
SKIP_DIRS = /* @__PURE__ */ new Set([".git", "node_modules", "dist", "build", "coverage", ".next", ".worktrees", ".planning", ".converted", ".venv", "venv", "__pycache__"]);
|
|
13590
13787
|
CODE_EXT = /* @__PURE__ */ new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".py", ".go", ".rs", ".java", ".kt", ".swift", ".rb", ".php", ".cs", ".sol", ".sql", ".md"]);
|
|
13591
|
-
MAX_FILES =
|
|
13788
|
+
MAX_FILES = 2e4;
|
|
13592
13789
|
MAX_FILE_BYTES = 256 * 1024;
|
|
13593
13790
|
MAX_PATHS = 5;
|
|
13594
13791
|
MAX_SYMBOLS = 10;
|
|
@@ -13598,11 +13795,11 @@ var init_anchor = __esm({
|
|
|
13598
13795
|
});
|
|
13599
13796
|
|
|
13600
13797
|
// packages/core/dist/knowledge/extract.js
|
|
13601
|
-
import
|
|
13602
|
-
import
|
|
13603
|
-
import
|
|
13798
|
+
import fs25 from "fs";
|
|
13799
|
+
import path26 from "path";
|
|
13800
|
+
import matter4 from "gray-matter";
|
|
13604
13801
|
function serialize(fm, body) {
|
|
13605
|
-
return
|
|
13802
|
+
return matter4.stringify(body.trim() + "\n", clean(fm));
|
|
13606
13803
|
}
|
|
13607
13804
|
function validateCandidate(c) {
|
|
13608
13805
|
const p = [];
|
|
@@ -13632,8 +13829,8 @@ function validateCandidate(c) {
|
|
|
13632
13829
|
}
|
|
13633
13830
|
return p;
|
|
13634
13831
|
}
|
|
13635
|
-
function upsertSource(fm, src) {
|
|
13636
|
-
const i = fm.sources.findIndex((s) => s.ref === src.ref);
|
|
13832
|
+
function upsertSource(fm, src, canon) {
|
|
13833
|
+
const i = fm.sources.findIndex((s) => canon(s.ref) === canon(src.ref));
|
|
13637
13834
|
if (i < 0) {
|
|
13638
13835
|
fm.sources.push(src);
|
|
13639
13836
|
return true;
|
|
@@ -13645,9 +13842,9 @@ function upsertSource(fm, src) {
|
|
|
13645
13842
|
}
|
|
13646
13843
|
function applyCandidates(input, opts) {
|
|
13647
13844
|
const { kb, kbRoot, rulesDir } = opts;
|
|
13648
|
-
const res = { created: [], merged: [], proposed: [], superseded: [], stale: [], rejected: [], doclingFlags: [], idOverrides: [] };
|
|
13845
|
+
const res = { created: [], merged: [], proposed: [], superseded: [], stale: [], rejected: [], doclingFlags: [], idOverrides: [], orphanedErrata: [] };
|
|
13649
13846
|
const events = [];
|
|
13650
|
-
const ev2 = (event, itemId,
|
|
13847
|
+
const ev2 = (event, itemId, extra = {}) => events.push({ kb, level: "group", project: "", domain: "rules", itemId, event, ...extra });
|
|
13651
13848
|
const loaded = loadRulesDir(rulesDir, `kb:${kb}`);
|
|
13652
13849
|
const work = /* @__PURE__ */ new Map();
|
|
13653
13850
|
for (const r of loaded.rules) {
|
|
@@ -13657,7 +13854,8 @@ function applyCandidates(input, opts) {
|
|
|
13657
13854
|
const norm = /* @__PURE__ */ new Map();
|
|
13658
13855
|
const totals = /* @__PURE__ */ new Map();
|
|
13659
13856
|
const touched = /* @__PURE__ */ new Set();
|
|
13660
|
-
const
|
|
13857
|
+
const canon = refCanon(kbRoot, opts.sources ?? []);
|
|
13858
|
+
const complete = new Set((input.complete ?? []).map(canon));
|
|
13661
13859
|
for (const cand of input.candidates) {
|
|
13662
13860
|
const problems = validateCandidate(cand);
|
|
13663
13861
|
if (problems.length) {
|
|
@@ -13666,13 +13864,13 @@ function applyCandidates(input, opts) {
|
|
|
13666
13864
|
}
|
|
13667
13865
|
const st = readState2(kbRoot, cand.source);
|
|
13668
13866
|
const convFile = st ? convertedFile(kbRoot, cand.source) : null;
|
|
13669
|
-
if (!st || !
|
|
13867
|
+
if (!st || !fs25.existsSync(convFile)) {
|
|
13670
13868
|
res.rejected.push({ id: cand.id, source: cand.source, reason: "unknown source (not ingested)" });
|
|
13671
13869
|
continue;
|
|
13672
13870
|
}
|
|
13673
13871
|
let hay = norm.get(cand.source);
|
|
13674
13872
|
if (!hay) {
|
|
13675
|
-
hay = normalizedViews(
|
|
13873
|
+
hay = normalizedViews(fs25.readFileSync(convFile, "utf8"));
|
|
13676
13874
|
norm.set(cand.source, hay);
|
|
13677
13875
|
}
|
|
13678
13876
|
const tot = totals.get(cand.source) ?? { total: 0, dropped: 0 };
|
|
@@ -13682,13 +13880,20 @@ function applyCandidates(input, opts) {
|
|
|
13682
13880
|
if (!offset) {
|
|
13683
13881
|
tot.dropped++;
|
|
13684
13882
|
res.rejected.push({ id: cand.id, source: cand.source, reason: "ungrounded" });
|
|
13685
|
-
ev2("item.rejected", cand.id,
|
|
13883
|
+
ev2("item.rejected", cand.id, { reason: "ungrounded" });
|
|
13884
|
+
continue;
|
|
13885
|
+
}
|
|
13886
|
+
const hit = (opts.errata ?? []).find((e) => canon(e.ref) === canon(cand.source) && ((o) => !!o && spansOverlap(o, offset))(findQuote(hay, e.quote)));
|
|
13887
|
+
if (hit) {
|
|
13888
|
+
tot.total--;
|
|
13889
|
+
res.rejected.push({ id: cand.id, source: cand.source, reason: `errata:${hit.id}` });
|
|
13890
|
+
ev2("item.rejected", cand.id, { reason: `errata:${hit.id}` });
|
|
13686
13891
|
continue;
|
|
13687
13892
|
}
|
|
13688
13893
|
let id = cand.id;
|
|
13689
13894
|
for (const [wid, w] of work) {
|
|
13690
13895
|
const span = (s) => s.sha === st.sha ? s.offset : findQuote(hay, s.quote) ?? s.offset;
|
|
13691
|
-
if (w.fm.sources.some((s) => s.ref === cand.source && s.offset && ((o) => !!o && spansOverlap(o, offset))(span(s)))) {
|
|
13896
|
+
if (w.fm.sources.some((s) => canon(s.ref) === canon(cand.source) && s.offset && ((o) => !!o && spansOverlap(o, offset))(span(s)))) {
|
|
13692
13897
|
id = wid;
|
|
13693
13898
|
break;
|
|
13694
13899
|
}
|
|
@@ -13703,7 +13908,7 @@ function applyCandidates(input, opts) {
|
|
|
13703
13908
|
|
|
13704
13909
|
${cand.rationale.trim()}` : "");
|
|
13705
13910
|
if (target && contradicted.length === 0 && sameMeaning(target, cand)) {
|
|
13706
|
-
let changed = upsertSource(target.fm, src);
|
|
13911
|
+
let changed = upsertSource(target.fm, src, canon);
|
|
13707
13912
|
if (target.fm.status === "stale") {
|
|
13708
13913
|
target.fm.status = "active";
|
|
13709
13914
|
changed = true;
|
|
@@ -13714,7 +13919,7 @@ ${cand.rationale.trim()}` : "");
|
|
|
13714
13919
|
}
|
|
13715
13920
|
continue;
|
|
13716
13921
|
}
|
|
13717
|
-
if (!target && contradicted.length === 0) {
|
|
13922
|
+
if (!target && contradicted.length === 0 && !isGatedRef(kbRoot, opts.sources ?? [], cand.source)) {
|
|
13718
13923
|
const fm2 = {
|
|
13719
13924
|
id,
|
|
13720
13925
|
domain: cand.domain,
|
|
@@ -13727,9 +13932,9 @@ ${cand.rationale.trim()}` : "");
|
|
|
13727
13932
|
supersedes: [],
|
|
13728
13933
|
conflictsWith: []
|
|
13729
13934
|
};
|
|
13730
|
-
work.set(id, { fm: fm2, body: bodyOf(), file:
|
|
13935
|
+
work.set(id, { fm: fm2, body: bodyOf(), file: path26.join(rulesDir, cand.domain, `${id}.md`), dirty: true, isNew: true });
|
|
13731
13936
|
res.created.push(id);
|
|
13732
|
-
ev2("item.applied", id
|
|
13937
|
+
ev2("item.applied", id);
|
|
13733
13938
|
continue;
|
|
13734
13939
|
}
|
|
13735
13940
|
const fm = {
|
|
@@ -13744,42 +13949,43 @@ ${cand.rationale.trim()}` : "");
|
|
|
13744
13949
|
supersedes: [],
|
|
13745
13950
|
conflictsWith: contradicted
|
|
13746
13951
|
};
|
|
13747
|
-
const dir =
|
|
13748
|
-
const file =
|
|
13952
|
+
const dir = path26.join(rulesDir, PROPOSED_DIR);
|
|
13953
|
+
const file = path26.join(dir, `${id}@${st.sha.slice(0, SHA_LEN)}.md`);
|
|
13749
13954
|
const text = serialize(fm, bodyOf());
|
|
13750
|
-
if (
|
|
13955
|
+
if (fs25.existsSync(file) && fs25.readFileSync(file, "utf8") === text)
|
|
13751
13956
|
continue;
|
|
13752
|
-
|
|
13753
|
-
for (const other of
|
|
13754
|
-
if (!other.startsWith(`${id}@`) || !other.endsWith(".md") ||
|
|
13957
|
+
fs25.mkdirSync(dir, { recursive: true });
|
|
13958
|
+
for (const other of fs25.readdirSync(dir)) {
|
|
13959
|
+
if (!other.startsWith(`${id}@`) || !other.endsWith(".md") || path26.join(dir, other) === file)
|
|
13755
13960
|
continue;
|
|
13756
|
-
const old =
|
|
13757
|
-
if (!old.data.sources?.some((s) => s.ref === cand.source))
|
|
13961
|
+
const old = matter4(fs25.readFileSync(path26.join(dir, other), "utf8"));
|
|
13962
|
+
if (!old.data.sources?.some((s) => canon(s.ref) === canon(cand.source)))
|
|
13758
13963
|
continue;
|
|
13759
|
-
|
|
13760
|
-
|
|
13964
|
+
fs25.writeFileSync(path26.join(dir, other.replace(/\.md$/, ".superseded")), matter4.stringify(old.content, { ...old.data, supersededBy: path26.basename(file) }));
|
|
13965
|
+
fs25.rmSync(path26.join(dir, other));
|
|
13761
13966
|
res.superseded.push(other.replace(/\.md$/, ""));
|
|
13762
|
-
ev2("item.superseded", id
|
|
13967
|
+
ev2("item.superseded", id);
|
|
13763
13968
|
}
|
|
13764
|
-
|
|
13969
|
+
fs25.writeFileSync(file, text);
|
|
13765
13970
|
res.proposed.push(`${id}@${st.sha.slice(0, SHA_LEN)}`);
|
|
13766
|
-
ev2("item.proposed", id
|
|
13971
|
+
ev2("item.proposed", id);
|
|
13767
13972
|
}
|
|
13768
13973
|
for (const [id, w] of work) {
|
|
13769
13974
|
if (touched.has(id) || w.fm.status !== "active" || w.isNew)
|
|
13770
13975
|
continue;
|
|
13771
|
-
if (w.fm.sources.length && w.fm.sources.every((s) => complete.has(s.ref))) {
|
|
13976
|
+
if (w.fm.sources.length && w.fm.sources.every((s) => complete.has(canon(s.ref)))) {
|
|
13772
13977
|
w.fm.status = "stale";
|
|
13773
13978
|
w.dirty = true;
|
|
13774
13979
|
res.stale.push(id);
|
|
13775
13980
|
}
|
|
13776
13981
|
}
|
|
13982
|
+
const anchorCache = /* @__PURE__ */ new Map();
|
|
13777
13983
|
for (const w of work.values()) {
|
|
13778
13984
|
if (!w.dirty || !opts.projects?.length)
|
|
13779
13985
|
continue;
|
|
13780
13986
|
const anchors = { ...w.fm.anchors ?? {} };
|
|
13781
13987
|
for (const p of opts.projects) {
|
|
13782
|
-
const a = computeAnchor(p.root, w.fm.triggers);
|
|
13988
|
+
const a = computeAnchor(p.root, w.fm.triggers, anchorCache);
|
|
13783
13989
|
if (a)
|
|
13784
13990
|
anchors[p.name] = a;
|
|
13785
13991
|
}
|
|
@@ -13789,11 +13995,12 @@ ${cand.rationale.trim()}` : "");
|
|
|
13789
13995
|
for (const w of work.values()) {
|
|
13790
13996
|
if (!w.dirty)
|
|
13791
13997
|
continue;
|
|
13792
|
-
|
|
13998
|
+
fs25.mkdirSync(path26.dirname(w.file), { recursive: true });
|
|
13793
13999
|
const text = serialize(w.fm, w.body);
|
|
13794
|
-
if (!
|
|
13795
|
-
|
|
14000
|
+
if (!fs25.existsSync(w.file) || fs25.readFileSync(w.file, "utf8") !== text)
|
|
14001
|
+
fs25.writeFileSync(w.file, text);
|
|
13796
14002
|
}
|
|
14003
|
+
res.orphanedErrata = orphanedErrata(kbRoot, opts.sources ?? [], opts.errata ?? [], totals.keys());
|
|
13797
14004
|
for (const [ref, t] of totals)
|
|
13798
14005
|
if (needsDocling(t.dropped, t.total))
|
|
13799
14006
|
res.doclingFlags.push({ ref, ...t });
|
|
@@ -13810,6 +14017,7 @@ var init_extract = __esm({
|
|
|
13810
14017
|
init_anchor();
|
|
13811
14018
|
init_index_file();
|
|
13812
14019
|
init_ingest();
|
|
14020
|
+
init_errata();
|
|
13813
14021
|
init_paths();
|
|
13814
14022
|
init_store2();
|
|
13815
14023
|
init_verify();
|
|
@@ -13826,20 +14034,20 @@ var init_extract = __esm({
|
|
|
13826
14034
|
});
|
|
13827
14035
|
|
|
13828
14036
|
// packages/core/dist/knowledge/schedule.js
|
|
13829
|
-
import
|
|
13830
|
-
import
|
|
14037
|
+
import fs26 from "fs";
|
|
14038
|
+
import path27 from "path";
|
|
13831
14039
|
function readSchedule(stateRoot) {
|
|
13832
14040
|
try {
|
|
13833
|
-
return JSON.parse(
|
|
14041
|
+
return JSON.parse(fs26.readFileSync(scheduleFile(stateRoot), "utf8"));
|
|
13834
14042
|
} catch {
|
|
13835
14043
|
return {};
|
|
13836
14044
|
}
|
|
13837
14045
|
}
|
|
13838
14046
|
function writeSchedule(stateRoot, s) {
|
|
13839
|
-
|
|
14047
|
+
fs26.mkdirSync(stateRoot, { recursive: true });
|
|
13840
14048
|
const tmp = `${scheduleFile(stateRoot)}.${process.pid}.tmp`;
|
|
13841
|
-
|
|
13842
|
-
|
|
14049
|
+
fs26.writeFileSync(tmp, JSON.stringify(s, null, 2) + "\n");
|
|
14050
|
+
fs26.renameSync(tmp, scheduleFile(stateRoot));
|
|
13843
14051
|
}
|
|
13844
14052
|
function snapshotSources(kbRoot, sources) {
|
|
13845
14053
|
const out = {};
|
|
@@ -13919,7 +14127,7 @@ async function tickKnowledgeSchedule(d) {
|
|
|
13919
14127
|
continue;
|
|
13920
14128
|
try {
|
|
13921
14129
|
const root = kbDir(d.cfg, kb);
|
|
13922
|
-
if (!
|
|
14130
|
+
if (!fs26.existsSync(root))
|
|
13923
14131
|
continue;
|
|
13924
14132
|
const { sources } = loadSources(root);
|
|
13925
14133
|
if (!sources.length)
|
|
@@ -13984,27 +14192,27 @@ var init_schedule = __esm({
|
|
|
13984
14192
|
init_sources();
|
|
13985
14193
|
RUNNING_STALE_MS = 6 * 60 * 60 * 1e3;
|
|
13986
14194
|
DAY_MS = 24 * 60 * 60 * 1e3;
|
|
13987
|
-
scheduleFile = (stateRoot) =>
|
|
14195
|
+
scheduleFile = (stateRoot) => path27.join(stateRoot, "knowledge-schedule.json");
|
|
13988
14196
|
reconcileConfig = (cfg, kb) => ({ ...DEFAULT_RECONCILE, ...kbConfigs(cfg)[kb]?.reconcile });
|
|
13989
14197
|
}
|
|
13990
14198
|
});
|
|
13991
14199
|
|
|
13992
14200
|
// packages/core/dist/knowledge/review.js
|
|
13993
14201
|
import crypto4 from "crypto";
|
|
13994
|
-
import { execFileSync as
|
|
13995
|
-
import
|
|
13996
|
-
import
|
|
13997
|
-
import
|
|
14202
|
+
import { execFileSync as execFileSync8 } from "child_process";
|
|
14203
|
+
import fs27 from "fs";
|
|
14204
|
+
import path28 from "path";
|
|
14205
|
+
import matter5 from "gray-matter";
|
|
13998
14206
|
function readEscalations(kbRoot) {
|
|
13999
14207
|
try {
|
|
14000
|
-
return JSON.parse(
|
|
14208
|
+
return JSON.parse(fs27.readFileSync(escalationsFile(kbRoot), "utf8")).items;
|
|
14001
14209
|
} catch {
|
|
14002
14210
|
return [];
|
|
14003
14211
|
}
|
|
14004
14212
|
}
|
|
14005
14213
|
function writeEscalations(kbRoot, items) {
|
|
14006
|
-
|
|
14007
|
-
|
|
14214
|
+
fs27.mkdirSync(kbRoot, { recursive: true });
|
|
14215
|
+
fs27.writeFileSync(escalationsFile(kbRoot), JSON.stringify({ items }, null, 2) + "\n");
|
|
14008
14216
|
}
|
|
14009
14217
|
function addEscalation(kbRoot, e) {
|
|
14010
14218
|
const items = readEscalations(kbRoot);
|
|
@@ -14014,18 +14222,14 @@ function addEscalation(kbRoot, e) {
|
|
|
14014
14222
|
return true;
|
|
14015
14223
|
}
|
|
14016
14224
|
function appendVerdict(kbRoot, v2, now) {
|
|
14017
|
-
|
|
14018
|
-
|
|
14225
|
+
fs27.mkdirSync(kbRoot, { recursive: true });
|
|
14226
|
+
fs27.appendFileSync(verdictsFile(kbRoot), JSON.stringify({ ts: now.toISOString(), ...v2 }) + "\n");
|
|
14019
14227
|
}
|
|
14020
14228
|
function priorityOfRef(c, ref) {
|
|
14021
14229
|
if (ref.startsWith("agent:"))
|
|
14022
14230
|
return "agent";
|
|
14023
14231
|
const root = kbDir(c.cfg, c.kb);
|
|
14024
|
-
|
|
14025
|
-
for (const f of expandSource(root, e))
|
|
14026
|
-
if (refFor(root, f) === ref)
|
|
14027
|
-
return e.priority;
|
|
14028
|
-
return "project";
|
|
14232
|
+
return c.sources.find((e) => sourceCovers(root, c.sources, e, ref))?.priority ?? "project";
|
|
14029
14233
|
}
|
|
14030
14234
|
function priorityOfRule(c, r) {
|
|
14031
14235
|
return r.sources.map((s) => priorityOfRef(c, s.ref)).sort((a, b) => PRIORITY_RANK[b] - PRIORITY_RANK[a])[0] ?? "project";
|
|
@@ -14036,20 +14240,20 @@ function loadProposals(c) {
|
|
|
14036
14240
|
const byId = new Map(live.map((r) => [r.id, r]));
|
|
14037
14241
|
const proposals = [];
|
|
14038
14242
|
const pdirs = /* @__PURE__ */ new Set();
|
|
14039
|
-
for (const f of
|
|
14040
|
-
if (
|
|
14243
|
+
for (const f of fs27.existsSync(dir) ? walkDirs(dir) : [])
|
|
14244
|
+
if (path28.basename(f) === PROPOSED_DIR)
|
|
14041
14245
|
pdirs.add(f);
|
|
14042
14246
|
for (const pd of pdirs) {
|
|
14043
14247
|
for (const rule of loadRulesDir(pd, `kb:${c.kb}`, { includeProposed: true }).rules) {
|
|
14044
|
-
proposals.push({ key:
|
|
14248
|
+
proposals.push({ key: path28.basename(rule.file).replace(/\.md$/, ""), rule, live: byId.get(rule.id) });
|
|
14045
14249
|
}
|
|
14046
14250
|
}
|
|
14047
14251
|
return { proposals, live };
|
|
14048
14252
|
}
|
|
14049
14253
|
function walkDirs(dir, out = []) {
|
|
14050
|
-
for (const e of
|
|
14254
|
+
for (const e of fs27.readdirSync(dir, { withFileTypes: true }))
|
|
14051
14255
|
if (e.isDirectory()) {
|
|
14052
|
-
const f =
|
|
14256
|
+
const f = path28.join(dir, e.name);
|
|
14053
14257
|
out.push(f);
|
|
14054
14258
|
walkDirs(f, out);
|
|
14055
14259
|
}
|
|
@@ -14062,7 +14266,7 @@ function reindex(c) {
|
|
|
14062
14266
|
function anchorsFor(c, fm) {
|
|
14063
14267
|
const anchors = { ...fm.anchors ?? {} };
|
|
14064
14268
|
for (const p of c.projects ?? []) {
|
|
14065
|
-
const a = computeAnchor(p.root, fm.triggers);
|
|
14269
|
+
const a = computeAnchor(p.root, fm.triggers, c.anchorCache);
|
|
14066
14270
|
if (a)
|
|
14067
14271
|
anchors[p.name] = a;
|
|
14068
14272
|
}
|
|
@@ -14078,9 +14282,9 @@ function promoteProposal(c, p, by, justification, events) {
|
|
|
14078
14282
|
continue;
|
|
14079
14283
|
const o = readFm(other.file);
|
|
14080
14284
|
o.fm.status = "retired";
|
|
14081
|
-
|
|
14285
|
+
fs27.writeFileSync(other.file, fileText(o.fm, o.body));
|
|
14082
14286
|
retired.push(id);
|
|
14083
|
-
events.push(ev(c, "item.superseded", id
|
|
14287
|
+
events.push(ev(c, "item.superseded", id));
|
|
14084
14288
|
}
|
|
14085
14289
|
const next = { ...fm, status: "active", approvedBy: by, justification, supersedes: [.../* @__PURE__ */ new Set([...fm.supersedes ?? [], ...retired])], conflictsWith: [] };
|
|
14086
14290
|
if (p.live?.decision)
|
|
@@ -14088,29 +14292,30 @@ function promoteProposal(c, p, by, justification, events) {
|
|
|
14088
14292
|
const anchors = anchorsFor(c, { ...next, anchors: p.live?.anchors ?? fm.anchors });
|
|
14089
14293
|
if (anchors)
|
|
14090
14294
|
next.anchors = anchors;
|
|
14091
|
-
const target = p.live?.file ??
|
|
14092
|
-
|
|
14093
|
-
|
|
14094
|
-
|
|
14095
|
-
events.push(ev(c, "item.approved", next.id
|
|
14295
|
+
const target = p.live?.file ?? path28.join(dir, next.domain, `${next.id}.md`);
|
|
14296
|
+
fs27.mkdirSync(path28.dirname(target), { recursive: true });
|
|
14297
|
+
fs27.writeFileSync(target, fileText(next, body));
|
|
14298
|
+
fs27.rmSync(p.rule.file);
|
|
14299
|
+
events.push(ev(c, "item.approved", next.id), ev(c, "item.applied", next.id));
|
|
14096
14300
|
if (p.live)
|
|
14097
|
-
events.push(ev(c, "item.superseded", next.id
|
|
14301
|
+
events.push(ev(c, "item.superseded", next.id));
|
|
14098
14302
|
}
|
|
14099
14303
|
function dropProposal(c, p, events) {
|
|
14100
|
-
|
|
14101
|
-
events.push(ev(c, "item.rejected", p.rule.id,
|
|
14304
|
+
fs27.rmSync(p.rule.file);
|
|
14305
|
+
events.push(ev(c, "item.rejected", p.rule.id, { reason: "reviewer" }));
|
|
14102
14306
|
}
|
|
14103
14307
|
function mergeInto(c, p, targetId, live, events) {
|
|
14104
14308
|
const t = live.find((r) => r.id === targetId);
|
|
14105
14309
|
if (!t)
|
|
14106
14310
|
return false;
|
|
14107
14311
|
const tf = readFm(t.file);
|
|
14312
|
+
const canon = refCanon(kbDir(c.cfg, c.kb), c.sources);
|
|
14108
14313
|
for (const s of p.rule.sources)
|
|
14109
|
-
if (!tf.fm.sources.some((x) => x.ref === s.ref))
|
|
14314
|
+
if (!tf.fm.sources.some((x) => canon(x.ref) === canon(s.ref)))
|
|
14110
14315
|
tf.fm.sources.push(s);
|
|
14111
|
-
|
|
14112
|
-
|
|
14113
|
-
events.push(ev(c, "item.superseded", p.rule.id
|
|
14316
|
+
fs27.writeFileSync(t.file, fileText(tf.fm, tf.body));
|
|
14317
|
+
fs27.rmSync(p.rule.file);
|
|
14318
|
+
events.push(ev(c, "item.superseded", p.rule.id), ev(c, "item.applied", targetId));
|
|
14114
14319
|
return true;
|
|
14115
14320
|
}
|
|
14116
14321
|
function evaluateCodeConflict(c, rule, cc) {
|
|
@@ -14119,7 +14324,7 @@ function evaluateCodeConflict(c, rule, cc) {
|
|
|
14119
14324
|
const root = proj?.root;
|
|
14120
14325
|
const code = root ? g.lastCommit(root, cc.files) : null;
|
|
14121
14326
|
const kbRoot = kbDir(c.cfg, c.kb);
|
|
14122
|
-
const docDates = rule.sources.map((s) => g.docDate(
|
|
14327
|
+
const docDates = rule.sources.map((s) => g.docDate(refPath(kbRoot, c.sources, s.ref))).filter((d2) => !!d2).sort();
|
|
14123
14328
|
const docDate = docDates[docDates.length - 1];
|
|
14124
14329
|
const docRev = docRevOf(rule);
|
|
14125
14330
|
const evidence = { docRev, codeRev: code?.rev ?? "unknown", files: cc.files, project: cc.project };
|
|
@@ -14141,6 +14346,7 @@ function evaluateCodeConflict(c, rule, cc) {
|
|
|
14141
14346
|
};
|
|
14142
14347
|
}
|
|
14143
14348
|
function applyDecisions(file, c) {
|
|
14349
|
+
c = { ...c, anchorCache: /* @__PURE__ */ new Map() };
|
|
14144
14350
|
const now = nowOf(c);
|
|
14145
14351
|
const kbRoot = kbDir(c.cfg, c.kb);
|
|
14146
14352
|
const threshold = reconcileConfig(c.cfg, c.kb).autoApproveConfidence;
|
|
@@ -14184,14 +14390,15 @@ function applyDecisions(file, c) {
|
|
|
14184
14390
|
f.fm.status = "active";
|
|
14185
14391
|
if (d.loc && f.fm.sources[0])
|
|
14186
14392
|
f.fm.sources[0].loc = d.loc;
|
|
14187
|
-
|
|
14188
|
-
|
|
14393
|
+
const noSource = !rule.sources.length;
|
|
14394
|
+
if (conf >= threshold && !d.flag && !reasons.length && !noSource) {
|
|
14395
|
+
fs27.writeFileSync(rule.file, fileText(f.fm, f.body));
|
|
14189
14396
|
res.applied.push(d.item);
|
|
14190
|
-
events.push(ev(c, "item.applied", rule.id
|
|
14397
|
+
events.push(ev(c, "item.applied", rule.id));
|
|
14191
14398
|
verdict(d, "applied", { confidence: conf });
|
|
14192
14399
|
continue;
|
|
14193
14400
|
}
|
|
14194
|
-
reasons.push(conf < threshold ? "low-confidence" : "reviewer-flagged");
|
|
14401
|
+
reasons.push(noSource ? "no-source" : conf < threshold ? "low-confidence" : "reviewer-flagged");
|
|
14195
14402
|
} else if (d.decision === "approve") {
|
|
14196
14403
|
if (strong(rule.modality))
|
|
14197
14404
|
reasons.push("retiring must/must-not");
|
|
@@ -14202,9 +14409,9 @@ function applyDecisions(file, c) {
|
|
|
14202
14409
|
if (!reasons.length) {
|
|
14203
14410
|
const f = readFm(rule.file);
|
|
14204
14411
|
f.fm.status = "retired";
|
|
14205
|
-
|
|
14412
|
+
fs27.writeFileSync(rule.file, fileText(f.fm, f.body));
|
|
14206
14413
|
res.applied.push(d.item);
|
|
14207
|
-
events.push(ev(c, "item.archived", rule.id
|
|
14414
|
+
events.push(ev(c, "item.archived", rule.id));
|
|
14208
14415
|
verdict(d, "applied", { confidence: conf });
|
|
14209
14416
|
continue;
|
|
14210
14417
|
}
|
|
@@ -14219,6 +14426,8 @@ function applyDecisions(file, c) {
|
|
|
14219
14426
|
reasons.push("reviewer-flagged");
|
|
14220
14427
|
if (conf < threshold)
|
|
14221
14428
|
reasons.push("low-confidence");
|
|
14429
|
+
if (p.rule.sources.some((s) => isGatedRef(kbRoot, c.sources, s.ref)))
|
|
14430
|
+
reasons.push("review-required");
|
|
14222
14431
|
if (d.decision === "approve") {
|
|
14223
14432
|
const myPri = priorityOfRule(c, p.rule);
|
|
14224
14433
|
const conflicted = (p.rule.conflictsWith ?? []).map((id) => live.find((r) => r.id === id)).filter((r) => !!r);
|
|
@@ -14280,7 +14489,7 @@ function applyPair(pd, c, res, threshold, events, kbRoot, now) {
|
|
|
14280
14489
|
for (const [x, y] of [[a, b], [b, a]]) {
|
|
14281
14490
|
const f = readFm(x.file);
|
|
14282
14491
|
f.fm.conflictsWith = [.../* @__PURE__ */ new Set([...f.fm.conflictsWith ?? [], y.id])];
|
|
14283
|
-
|
|
14492
|
+
fs27.writeFileSync(x.file, fileText(f.fm, f.body));
|
|
14284
14493
|
}
|
|
14285
14494
|
return;
|
|
14286
14495
|
}
|
|
@@ -14291,15 +14500,16 @@ function applyPair(pd, c, res, threshold, events, kbRoot, now) {
|
|
|
14291
14500
|
return;
|
|
14292
14501
|
}
|
|
14293
14502
|
const kf = readFm(keep.file);
|
|
14503
|
+
const canon = refCanon(kbRoot, c.sources);
|
|
14294
14504
|
for (const s of drop.sources)
|
|
14295
|
-
if (!kf.fm.sources.some((x) => x.ref === s.ref))
|
|
14505
|
+
if (!kf.fm.sources.some((x) => canon(x.ref) === canon(s.ref)))
|
|
14296
14506
|
kf.fm.sources.push(s);
|
|
14297
14507
|
kf.fm.supersedes = [.../* @__PURE__ */ new Set([...kf.fm.supersedes ?? [], drop.id])];
|
|
14298
|
-
|
|
14508
|
+
fs27.writeFileSync(keep.file, fileText(kf.fm, kf.body));
|
|
14299
14509
|
const df = readFm(drop.file);
|
|
14300
14510
|
df.fm.status = "retired";
|
|
14301
|
-
|
|
14302
|
-
events.push(ev(c, "item.superseded", drop.id
|
|
14511
|
+
fs27.writeFileSync(drop.file, fileText(df.fm, df.body));
|
|
14512
|
+
events.push(ev(c, "item.superseded", drop.id), ev(c, "item.applied", keep.id));
|
|
14303
14513
|
res.applied.push(key);
|
|
14304
14514
|
}
|
|
14305
14515
|
function resolveEscalation(c, key, r, by, reason) {
|
|
@@ -14329,9 +14539,9 @@ function resolveEscalation(c, key, r, by, reason) {
|
|
|
14329
14539
|
f.fm.decision = decision;
|
|
14330
14540
|
if (r.verdict === "supersede-with-code") {
|
|
14331
14541
|
f.fm.status = "retired";
|
|
14332
|
-
events.push(ev(c, "item.superseded", rule.id
|
|
14542
|
+
events.push(ev(c, "item.superseded", rule.id));
|
|
14333
14543
|
}
|
|
14334
|
-
|
|
14544
|
+
fs27.writeFileSync(rule.file, fileText(f.fm, f.body));
|
|
14335
14545
|
return done(`${rule.id}: ${r.verdict}`);
|
|
14336
14546
|
}
|
|
14337
14547
|
if (esc.kind === "proposal") {
|
|
@@ -14348,23 +14558,26 @@ function resolveEscalation(c, key, r, by, reason) {
|
|
|
14348
14558
|
}
|
|
14349
14559
|
if (esc.kind === "stale-retire") {
|
|
14350
14560
|
const rule = live.find((x) => x.id === esc.ruleId);
|
|
14561
|
+
if (rule && r.kind !== "approve" && !rule.sources.length) {
|
|
14562
|
+
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.`);
|
|
14563
|
+
}
|
|
14351
14564
|
if (rule) {
|
|
14352
14565
|
const f = readFm(rule.file);
|
|
14353
14566
|
f.fm.status = r.kind === "approve" ? "retired" : "active";
|
|
14354
|
-
|
|
14355
|
-
events.push(ev(c, r.kind === "approve" ? "item.archived" : "item.applied", rule.id
|
|
14567
|
+
fs27.writeFileSync(rule.file, fileText(f.fm, f.body));
|
|
14568
|
+
events.push(ev(c, r.kind === "approve" ? "item.archived" : "item.applied", rule.id));
|
|
14356
14569
|
}
|
|
14357
14570
|
return done(`${esc.ruleId}: ${r.kind === "approve" ? "retired" : "kept"}`);
|
|
14358
14571
|
}
|
|
14359
14572
|
if (esc.kind === "override-base-changed") {
|
|
14360
|
-
const ov = esc.item &&
|
|
14573
|
+
const ov = esc.item && fs27.existsSync(esc.item) ? esc.item : void 0;
|
|
14361
14574
|
if (ov) {
|
|
14362
14575
|
if (r.kind === "reject")
|
|
14363
|
-
|
|
14576
|
+
fs27.rmSync(ov);
|
|
14364
14577
|
else {
|
|
14365
14578
|
const f = readFm(ov);
|
|
14366
14579
|
f.fm.overridesBase = esc.evidence?.docRev;
|
|
14367
|
-
|
|
14580
|
+
fs27.writeFileSync(ov, fileText(f.fm, f.body));
|
|
14368
14581
|
}
|
|
14369
14582
|
}
|
|
14370
14583
|
return done(`${esc.ruleId}: override ${r.kind === "reject" ? "dropped" : "kept"}`);
|
|
@@ -14388,11 +14601,11 @@ ${o.evidence}`).digest("hex");
|
|
|
14388
14601
|
supersedes: [],
|
|
14389
14602
|
conflictsWith: []
|
|
14390
14603
|
};
|
|
14391
|
-
const dir =
|
|
14392
|
-
|
|
14393
|
-
const file =
|
|
14394
|
-
|
|
14395
|
-
appendAudit([ev(c, "item.proposed", id
|
|
14604
|
+
const dir = path28.join(kbRulesDir(c.cfg, c.kb), PROPOSED_DIR);
|
|
14605
|
+
fs27.mkdirSync(dir, { recursive: true });
|
|
14606
|
+
const file = path28.join(dir, `${id}@${sha.slice(0, SHA_LEN2)}.md`);
|
|
14607
|
+
fs27.writeFileSync(file, fileText(fm, o.statement));
|
|
14608
|
+
appendAudit([ev(c, "item.proposed", id)], c.audit);
|
|
14396
14609
|
return file;
|
|
14397
14610
|
}
|
|
14398
14611
|
function buildReviewPacket(c) {
|
|
@@ -14432,10 +14645,10 @@ var init_review = __esm({
|
|
|
14432
14645
|
PRIORITY_RANK = { company: 3, project: 2, agent: 1 };
|
|
14433
14646
|
SHA_LEN2 = 12;
|
|
14434
14647
|
strong = (m) => m === "must" || m === "must-not";
|
|
14435
|
-
escalationsFile = (kbRoot) =>
|
|
14436
|
-
verdictsFile = (kbRoot) =>
|
|
14648
|
+
escalationsFile = (kbRoot) => path28.join(kbRoot, "escalations.json");
|
|
14649
|
+
verdictsFile = (kbRoot) => path28.join(kbRoot, "verdicts.jsonl");
|
|
14437
14650
|
needsYouCount = (kbRoot) => readEscalations(kbRoot).filter((e) => e.needsYou).length;
|
|
14438
|
-
git = (root, args) =>
|
|
14651
|
+
git = (root, args) => execFileSync8("git", ["-C", root, ...args], { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] }).trim();
|
|
14439
14652
|
realGit = {
|
|
14440
14653
|
lastCommit(root, files) {
|
|
14441
14654
|
try {
|
|
@@ -14454,34 +14667,34 @@ var init_review = __esm({
|
|
|
14454
14667
|
},
|
|
14455
14668
|
docDate(file) {
|
|
14456
14669
|
try {
|
|
14457
|
-
const d = git(
|
|
14670
|
+
const d = git(path28.dirname(file), ["log", "-1", "--format=%cI", "--", path28.basename(file)]);
|
|
14458
14671
|
if (d)
|
|
14459
14672
|
return d;
|
|
14460
14673
|
} catch {
|
|
14461
14674
|
}
|
|
14462
14675
|
try {
|
|
14463
|
-
return
|
|
14676
|
+
return fs27.statSync(file).mtime.toISOString();
|
|
14464
14677
|
} catch {
|
|
14465
14678
|
return null;
|
|
14466
14679
|
}
|
|
14467
14680
|
}
|
|
14468
14681
|
};
|
|
14469
14682
|
nowOf = (c) => c.now?.() ?? /* @__PURE__ */ new Date();
|
|
14470
|
-
fileText = (fm, body) =>
|
|
14683
|
+
fileText = (fm, body) => matter5.stringify(body.trim() + "\n", JSON.parse(JSON.stringify(fm)));
|
|
14471
14684
|
readFm = (file) => {
|
|
14472
|
-
const m =
|
|
14685
|
+
const m = matter5(fs27.readFileSync(file, "utf8"));
|
|
14473
14686
|
return { fm: m.data, body: m.content };
|
|
14474
14687
|
};
|
|
14475
|
-
ev = (c, event, itemId,
|
|
14688
|
+
ev = (c, event, itemId, extra = {}) => ({ kb: c.kb, level: "group", project: "", domain: "rules", itemId, event, ...extra });
|
|
14476
14689
|
docRevOf = (r) => r.sources.map((s) => `${s.ref}@${s.sha.slice(0, SHA_LEN2)}`).join(",");
|
|
14477
14690
|
}
|
|
14478
14691
|
});
|
|
14479
14692
|
|
|
14480
14693
|
// packages/core/dist/knowledge/fullpass.js
|
|
14481
14694
|
import crypto5 from "crypto";
|
|
14482
|
-
import
|
|
14483
|
-
import
|
|
14484
|
-
import
|
|
14695
|
+
import fs28 from "fs";
|
|
14696
|
+
import path29 from "path";
|
|
14697
|
+
import matter6 from "gray-matter";
|
|
14485
14698
|
function dedupPairs(rules) {
|
|
14486
14699
|
const active = rules.filter((r) => r.status === "active").sort((x, y) => x.id.localeCompare(y.id));
|
|
14487
14700
|
const out = [];
|
|
@@ -14497,12 +14710,12 @@ function dedupPairs(rules) {
|
|
|
14497
14710
|
return out.slice(0, MAX_DEDUP_PAIRS);
|
|
14498
14711
|
}
|
|
14499
14712
|
function readAuditRecords(kb, since, dir = defaultAuditDir()) {
|
|
14500
|
-
if (!
|
|
14713
|
+
if (!fs28.existsSync(dir))
|
|
14501
14714
|
return [];
|
|
14502
14715
|
const sinceMonth = since.toISOString().slice(0, 7);
|
|
14503
14716
|
const out = [];
|
|
14504
|
-
for (const f of
|
|
14505
|
-
for (const line2 of
|
|
14717
|
+
for (const f of fs28.readdirSync(dir).filter((n) => n.endsWith(".jsonl") && n.slice(0, 7) >= sinceMonth).sort()) {
|
|
14718
|
+
for (const line2 of fs28.readFileSync(path29.join(dir, f), "utf8").split("\n")) {
|
|
14506
14719
|
if (!line2.trim())
|
|
14507
14720
|
continue;
|
|
14508
14721
|
try {
|
|
@@ -14565,8 +14778,8 @@ function checkOverrides(cfg, kb) {
|
|
|
14565
14778
|
continue;
|
|
14566
14779
|
const h = baseHash(b);
|
|
14567
14780
|
if (!o.overridesBase) {
|
|
14568
|
-
const m =
|
|
14569
|
-
|
|
14781
|
+
const m = matter6(fs28.readFileSync(o.file, "utf8"));
|
|
14782
|
+
fs28.writeFileSync(o.file, matter6.stringify(m.content, { ...m.data, overridesBase: h }));
|
|
14570
14783
|
continue;
|
|
14571
14784
|
}
|
|
14572
14785
|
out.push({ project, ruleId: o.id, file: o.file, baseHash: h, changed: o.overridesBase !== h });
|
|
@@ -14609,8 +14822,8 @@ var init_fullpass = __esm({
|
|
|
14609
14822
|
});
|
|
14610
14823
|
|
|
14611
14824
|
// packages/core/dist/knowledge/scores.js
|
|
14612
|
-
import
|
|
14613
|
-
import
|
|
14825
|
+
import fs29 from "fs";
|
|
14826
|
+
import path30 from "path";
|
|
14614
14827
|
function tally(records, into = emptyTally()) {
|
|
14615
14828
|
for (const e of records) {
|
|
14616
14829
|
const domain = typeof e.domain === "string" && e.domain ? e.domain : "rules";
|
|
@@ -14619,7 +14832,7 @@ function tally(records, into = emptyTally()) {
|
|
|
14619
14832
|
d.writes++;
|
|
14620
14833
|
if (READ_EVENTS.has(e.event ?? ""))
|
|
14621
14834
|
d.reads++;
|
|
14622
|
-
if (!e.itemId)
|
|
14835
|
+
if (!e.itemId || WRITE_EVENTS.has(e.event ?? ""))
|
|
14623
14836
|
continue;
|
|
14624
14837
|
const c = into.items[`${domain}|${e.itemId}`] ??= { ...zero(), domain, itemId: e.itemId };
|
|
14625
14838
|
switch (e.event) {
|
|
@@ -14656,7 +14869,7 @@ function tally(records, into = emptyTally()) {
|
|
|
14656
14869
|
}
|
|
14657
14870
|
function parseLines(file) {
|
|
14658
14871
|
const out = [];
|
|
14659
|
-
for (const line2 of
|
|
14872
|
+
for (const line2 of fs29.readFileSync(file, "utf8").split("\n")) {
|
|
14660
14873
|
if (!line2.trim())
|
|
14661
14874
|
continue;
|
|
14662
14875
|
try {
|
|
@@ -14668,37 +14881,37 @@ function parseLines(file) {
|
|
|
14668
14881
|
}
|
|
14669
14882
|
function compactAudit(o) {
|
|
14670
14883
|
const dir = o.dir ?? defaultAuditDir();
|
|
14671
|
-
if (!
|
|
14884
|
+
if (!fs29.existsSync(dir))
|
|
14672
14885
|
return [];
|
|
14673
14886
|
const cutoffMonth = new Date(o.now.getTime() - SCORE_WINDOW_DAYS * DAY_MS3).toISOString().slice(0, 7);
|
|
14674
14887
|
const done = [];
|
|
14675
|
-
for (const f of
|
|
14888
|
+
for (const f of fs29.readdirSync(dir).sort()) {
|
|
14676
14889
|
const m = MONTH_FILE_RE.exec(f);
|
|
14677
14890
|
if (!m || m[1] >= cutoffMonth)
|
|
14678
14891
|
continue;
|
|
14679
14892
|
const [, month, machine] = m;
|
|
14680
14893
|
const byKb = /* @__PURE__ */ new Map();
|
|
14681
|
-
for (const r of parseLines(
|
|
14894
|
+
for (const r of parseLines(path30.join(dir, f)))
|
|
14682
14895
|
byKb.set(r.kb ?? "", [...byKb.get(r.kb ?? "") ?? [], r]);
|
|
14683
|
-
const statsPath =
|
|
14684
|
-
const prior =
|
|
14896
|
+
const statsPath = path30.join(dir, statsFileName(month, machine));
|
|
14897
|
+
const prior = fs29.existsSync(statsPath) ? JSON.parse(fs29.readFileSync(statsPath, "utf8")) : null;
|
|
14685
14898
|
const kbs = prior?.kbs ?? {};
|
|
14686
14899
|
for (const [kb, recs] of byKb)
|
|
14687
14900
|
kbs[kb] = tally(recs, kbs[kb]);
|
|
14688
|
-
|
|
14689
|
-
|
|
14690
|
-
|
|
14901
|
+
fs29.writeFileSync(`${statsPath}.tmp`, JSON.stringify({ month, machine, kbs }));
|
|
14902
|
+
fs29.renameSync(`${statsPath}.tmp`, statsPath);
|
|
14903
|
+
fs29.unlinkSync(path30.join(dir, f));
|
|
14691
14904
|
done.push(month);
|
|
14692
14905
|
}
|
|
14693
14906
|
return done;
|
|
14694
14907
|
}
|
|
14695
14908
|
function readCompacted(kb, dir) {
|
|
14696
14909
|
const t = emptyTally();
|
|
14697
|
-
if (!
|
|
14910
|
+
if (!fs29.existsSync(dir))
|
|
14698
14911
|
return t;
|
|
14699
|
-
for (const f of
|
|
14912
|
+
for (const f of fs29.readdirSync(dir).filter((n) => n.endsWith(".stats.json"))) {
|
|
14700
14913
|
try {
|
|
14701
|
-
const k = JSON.parse(
|
|
14914
|
+
const k = JSON.parse(fs29.readFileSync(path30.join(dir, f), "utf8")).kbs[kb];
|
|
14702
14915
|
if (k)
|
|
14703
14916
|
mergeTally(t, k);
|
|
14704
14917
|
} catch {
|
|
@@ -14748,7 +14961,7 @@ function computeScores(i) {
|
|
|
14748
14961
|
noise: w.noise,
|
|
14749
14962
|
wrong: w.wrong,
|
|
14750
14963
|
fireRate: w.surfaced,
|
|
14751
|
-
pullRate: w.shown,
|
|
14964
|
+
pullRate: w.shown + w.searched,
|
|
14752
14965
|
useRate: ratio(w.cited, w.surfaced),
|
|
14753
14966
|
noiseRate: ratio(w.noise, w.surfaced),
|
|
14754
14967
|
violationRate: ratio(w.violated, w.surfaced),
|
|
@@ -14790,21 +15003,21 @@ function computeScores(i) {
|
|
|
14790
15003
|
function scoreKb(o) {
|
|
14791
15004
|
const dir = o.auditDir ?? defaultAuditDir();
|
|
14792
15005
|
const records = [];
|
|
14793
|
-
if (
|
|
14794
|
-
for (const f of
|
|
14795
|
-
records.push(...parseLines(
|
|
15006
|
+
if (fs29.existsSync(dir)) {
|
|
15007
|
+
for (const f of fs29.readdirSync(dir).filter((n) => MONTH_FILE_RE.test(n)).sort()) {
|
|
15008
|
+
records.push(...parseLines(path30.join(dir, f)).filter((r) => r.kb === o.kb));
|
|
14796
15009
|
}
|
|
14797
15010
|
}
|
|
14798
15011
|
let verdicts = [];
|
|
14799
15012
|
try {
|
|
14800
|
-
verdicts =
|
|
15013
|
+
verdicts = fs29.readFileSync(path30.join(o.kbRoot, "verdicts.jsonl"), "utf8").split("\n").filter(Boolean).map((l) => JSON.parse(l));
|
|
14801
15014
|
} catch {
|
|
14802
15015
|
}
|
|
14803
15016
|
return computeScores({ kb: o.kb, records, now: o.now, known: o.known, compacted: readCompacted(o.kb, dir), verdicts });
|
|
14804
15017
|
}
|
|
14805
15018
|
function writeScores(kbRoot, s) {
|
|
14806
|
-
|
|
14807
|
-
|
|
15019
|
+
fs29.mkdirSync(kbRoot, { recursive: true });
|
|
15020
|
+
fs29.writeFileSync(scoresFile(kbRoot), JSON.stringify(s, null, 2) + "\n");
|
|
14808
15021
|
}
|
|
14809
15022
|
function renderScoresSection(s) {
|
|
14810
15023
|
const pct = (x) => x === null ? "n/a" : `${Math.round(x * 100)}%`;
|
|
@@ -14817,7 +15030,7 @@ function renderScoresSection(s) {
|
|
|
14817
15030
|
...used.length ? [
|
|
14818
15031
|
"| Item | Surfaced | Pulled | Cited | Use | Noise | Violated |",
|
|
14819
15032
|
"|---|---|---|---|---|---|---|",
|
|
14820
|
-
...used.map((x) => `| ${x.itemId} | ${x.surfaced} | ${x.
|
|
15033
|
+
...used.map((x) => `| ${x.itemId} | ${x.surfaced} | ${x.pullRate} | ${x.cited} | ${pct(x.useRate)} | ${pct(x.noiseRate)} | ${pct(x.violationRate)} |`)
|
|
14821
15034
|
] : ["No items surfaced."],
|
|
14822
15035
|
"",
|
|
14823
15036
|
`- Never fired (${never.length}): ${never.slice(0, 20).join(", ") || "none"}${never.length > 20 ? ", \u2026" : ""}`,
|
|
@@ -14845,13 +15058,13 @@ var init_scores = __esm({
|
|
|
14845
15058
|
MONTH_FILE_RE = /^(\d{4}-\d{2})\.(.+)\.jsonl$/;
|
|
14846
15059
|
statsFileName = (month, machine) => `${month}.${machine}.stats.json`;
|
|
14847
15060
|
ratio = (n, d) => d ? Math.round(n / d * 1e3) / 1e3 : null;
|
|
14848
|
-
scoresFile = (kbRoot) =>
|
|
15061
|
+
scoresFile = (kbRoot) => path30.join(kbRoot, "scores.json");
|
|
14849
15062
|
}
|
|
14850
15063
|
});
|
|
14851
15064
|
|
|
14852
15065
|
// packages/core/dist/knowledge/report.js
|
|
14853
|
-
import
|
|
14854
|
-
import
|
|
15066
|
+
import fs30 from "fs";
|
|
15067
|
+
import path31 from "path";
|
|
14855
15068
|
function renderReport(cfg, kb, o) {
|
|
14856
15069
|
const { rules } = loadKbRules(cfg, kb, { includeProposed: true });
|
|
14857
15070
|
const count = (s) => rules.filter((r) => r.status === s).length;
|
|
@@ -14873,6 +15086,11 @@ function renderReport(cfg, kb, o) {
|
|
|
14873
15086
|
const info = esc.filter((e) => !e.needsYou);
|
|
14874
15087
|
if (info.length)
|
|
14875
15088
|
L.push("", `## For information (${info.length})`, "", ...info.map((e) => `- **${e.key}**: ${e.explanation}`));
|
|
15089
|
+
const { errata, errors: errataErrors } = loadErrata(kbDir(cfg, kb));
|
|
15090
|
+
const orphans = orphanedErrata(kbDir(cfg, kb), loadSources(kbDir(cfg, kb)).sources, errata);
|
|
15091
|
+
if (orphans.length || errataErrors.length) {
|
|
15092
|
+
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}`));
|
|
15093
|
+
}
|
|
14876
15094
|
if (o.full) {
|
|
14877
15095
|
const { usage: usage2, caps } = o.full;
|
|
14878
15096
|
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"}`);
|
|
@@ -14882,14 +15100,16 @@ function renderReport(cfg, kb, o) {
|
|
|
14882
15100
|
return L.join("\n") + "\n";
|
|
14883
15101
|
}
|
|
14884
15102
|
function writeReport(cfg, kb, o) {
|
|
14885
|
-
const file =
|
|
14886
|
-
|
|
15103
|
+
const file = path31.join(kbDir(cfg, kb), "REPORT.md");
|
|
15104
|
+
fs30.writeFileSync(file, renderReport(cfg, kb, o));
|
|
14887
15105
|
return file;
|
|
14888
15106
|
}
|
|
14889
15107
|
var init_report = __esm({
|
|
14890
15108
|
"packages/core/dist/knowledge/report.js"() {
|
|
15109
|
+
init_errata();
|
|
14891
15110
|
init_layers();
|
|
14892
15111
|
init_paths();
|
|
15112
|
+
init_sources();
|
|
14893
15113
|
init_review();
|
|
14894
15114
|
init_scores();
|
|
14895
15115
|
}
|
|
@@ -14931,44 +15151,63 @@ var init_reconcile = __esm({
|
|
|
14931
15151
|
|
|
14932
15152
|
// packages/core/dist/knowledge/cite.js
|
|
14933
15153
|
function scanAndLogCitations(i) {
|
|
14934
|
-
|
|
14935
|
-
|
|
14936
|
-
|
|
14937
|
-
|
|
14938
|
-
|
|
14939
|
-
|
|
14940
|
-
|
|
14941
|
-
|
|
14942
|
-
|
|
14943
|
-
|
|
14944
|
-
|
|
14945
|
-
|
|
14946
|
-
|
|
14947
|
-
|
|
14948
|
-
delivered
|
|
14949
|
-
|
|
14950
|
-
|
|
14951
|
-
|
|
14952
|
-
|
|
14953
|
-
|
|
14954
|
-
|
|
14955
|
-
|
|
14956
|
-
|
|
14957
|
-
|
|
14958
|
-
|
|
14959
|
-
|
|
14960
|
-
|
|
14961
|
-
|
|
14962
|
-
|
|
15154
|
+
return scanCitations([i], i);
|
|
15155
|
+
}
|
|
15156
|
+
function scanCitations(texts, o) {
|
|
15157
|
+
if (!texts.length)
|
|
15158
|
+
return [];
|
|
15159
|
+
const now = o.sink?.now?.() ?? /* @__PURE__ */ new Date();
|
|
15160
|
+
const lookbackMs = (o.lookbackDays ?? CITE_LOOKBACK_DAYS) * DAY_MS4;
|
|
15161
|
+
const ats = texts.map((t) => (t.at ?? now).getTime());
|
|
15162
|
+
const records = readAuditRecords(void 0, new Date(Math.min(...ats) - lookbackMs), o.sink?.dir ?? defaultAuditDir()).filter((r) => r.itemId && r.project === o.project);
|
|
15163
|
+
const already = new Set(records.filter((r) => r.event === "item.cited").map((r) => `${r.ref}|${r.itemId}`));
|
|
15164
|
+
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));
|
|
15165
|
+
const events = [];
|
|
15166
|
+
texts.forEach((t, n) => {
|
|
15167
|
+
const at = ats[n];
|
|
15168
|
+
const delivered = /* @__PURE__ */ new Map();
|
|
15169
|
+
for (const r of deliveries) {
|
|
15170
|
+
const ts = Date.parse(r.ts);
|
|
15171
|
+
if (ts <= at && ts >= at - lookbackMs)
|
|
15172
|
+
delivered.set(r.itemId, r);
|
|
15173
|
+
}
|
|
15174
|
+
for (const [itemId, r] of delivered) {
|
|
15175
|
+
if (already.has(`${t.ref}|${itemId}`) || !mentionsId(t.text, itemId))
|
|
15176
|
+
continue;
|
|
15177
|
+
already.add(`${t.ref}|${itemId}`);
|
|
15178
|
+
events.push({
|
|
15179
|
+
kb: String(r.kb ?? ""),
|
|
15180
|
+
level: String(r.level ?? "project"),
|
|
15181
|
+
project: o.project,
|
|
15182
|
+
domain: String(r.domain ?? "rules"),
|
|
15183
|
+
itemId,
|
|
15184
|
+
event: "item.cited",
|
|
15185
|
+
ref: t.ref,
|
|
15186
|
+
...o.agent ? { agent: o.agent } : {},
|
|
15187
|
+
...o.session ? { session: o.session } : {}
|
|
15188
|
+
});
|
|
15189
|
+
}
|
|
15190
|
+
});
|
|
15191
|
+
appendAudit(events, o.sink);
|
|
15192
|
+
return events.map((e) => e.itemId);
|
|
14963
15193
|
}
|
|
14964
15194
|
function readGitMessages(repo, since, run) {
|
|
14965
|
-
|
|
15195
|
+
return parseLog(run(["-C", repo, "log", "--all", `--since=${since.toISOString()}`, LOG_FORMAT]));
|
|
15196
|
+
}
|
|
15197
|
+
function readBranchOnlyMessages(repo, run, max = 200) {
|
|
15198
|
+
const branch = run(["-C", repo, "rev-parse", "--abbrev-ref", "HEAD"]).trim();
|
|
15199
|
+
if (!branch)
|
|
15200
|
+
return [];
|
|
15201
|
+
const own = branch === "HEAD" ? [] : [`--exclude=${branch}`];
|
|
15202
|
+
return parseLog(run(["-C", repo, "log", `--max-count=${max}`, "HEAD", "--not", ...own, "--branches", ...own.length ? [`--exclude=*/${branch}`] : [], "--remotes", LOG_FORMAT]));
|
|
15203
|
+
}
|
|
15204
|
+
function parseLog(out) {
|
|
14966
15205
|
return out.split("").filter((c) => c.trim()).map((c) => {
|
|
14967
15206
|
const [sha, at, ...rest] = c.split("");
|
|
14968
15207
|
return { sha: sha.trim(), at: new Date(at), text: rest.join("") };
|
|
14969
15208
|
});
|
|
14970
15209
|
}
|
|
14971
|
-
var DAY_MS4, CITE_LOOKBACK_DAYS, escapeRe2, mentionsId;
|
|
15210
|
+
var DAY_MS4, CITE_LOOKBACK_DAYS, escapeRe2, mentionsId, LOG_FORMAT;
|
|
14972
15211
|
var init_cite = __esm({
|
|
14973
15212
|
"packages/core/dist/knowledge/cite.js"() {
|
|
14974
15213
|
init_audit();
|
|
@@ -14977,6 +15216,7 @@ var init_cite = __esm({
|
|
|
14977
15216
|
CITE_LOOKBACK_DAYS = 7;
|
|
14978
15217
|
escapeRe2 = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
14979
15218
|
mentionsId = (text, id) => new RegExp(`(?<![\\w.-])${escapeRe2(id)}(?![\\w-])`).test(text);
|
|
15219
|
+
LOG_FORMAT = "--format=%x1e%H%x1f%cI%x1f%B";
|
|
14980
15220
|
}
|
|
14981
15221
|
});
|
|
14982
15222
|
|
|
@@ -14994,6 +15234,7 @@ var init_knowledge2 = __esm({
|
|
|
14994
15234
|
init_migrate();
|
|
14995
15235
|
init_verify();
|
|
14996
15236
|
init_ingest();
|
|
15237
|
+
init_errata();
|
|
14997
15238
|
init_anchor();
|
|
14998
15239
|
init_extract();
|
|
14999
15240
|
init_match();
|
|
@@ -15204,7 +15445,6 @@ __export(dist_exports, {
|
|
|
15204
15445
|
extractToolPayload: () => extractToolPayload,
|
|
15205
15446
|
extractUserIntentFromTranscript: () => extractUserIntentFromTranscript,
|
|
15206
15447
|
fallsBackToPane: () => fallsBackToPane,
|
|
15207
|
-
fileForRef: () => fileForRef,
|
|
15208
15448
|
findCrewPane: () => findCrewPane,
|
|
15209
15449
|
findLegacyKbs: () => findLegacyKbs,
|
|
15210
15450
|
findLegacyOverlays: () => findLegacyOverlays,
|
|
@@ -15244,6 +15484,7 @@ __export(dist_exports, {
|
|
|
15244
15484
|
isDaemonSocketLive: () => isDaemonSocketLive,
|
|
15245
15485
|
isGateCacheEnabled: () => isGateCacheEnabled,
|
|
15246
15486
|
isGateSession: () => isGateSession,
|
|
15487
|
+
isGatedRef: () => isGatedRef,
|
|
15247
15488
|
isNotifyActive: () => isNotifyActive,
|
|
15248
15489
|
isOperatorInitiatedCommand: () => isOperatorInitiatedCommand,
|
|
15249
15490
|
isPendingProposalDup: () => isPendingProposalDup,
|
|
@@ -15261,6 +15502,7 @@ __export(dist_exports, {
|
|
|
15261
15502
|
launchOneWorkspace: () => launchOneWorkspace,
|
|
15262
15503
|
legacyKbDir: () => legacyKbDir,
|
|
15263
15504
|
listSessions: () => listSessions,
|
|
15505
|
+
loadErrata: () => loadErrata,
|
|
15264
15506
|
loadKbRules: () => loadKbRules,
|
|
15265
15507
|
loadPending: () => loadPending,
|
|
15266
15508
|
loadProposals: () => loadProposals,
|
|
@@ -15295,6 +15537,7 @@ __export(dist_exports, {
|
|
|
15295
15537
|
normalizedViews: () => normalizedViews,
|
|
15296
15538
|
notePaneScreen: () => notePaneScreen,
|
|
15297
15539
|
notifyToggle: () => notifyToggle,
|
|
15540
|
+
orphanedErrata: () => orphanedErrata,
|
|
15298
15541
|
parseBearer: () => parseBearer,
|
|
15299
15542
|
parseClassifierVerdict: () => parseClassifierVerdict,
|
|
15300
15543
|
parseCommand: () => parseCommand,
|
|
@@ -15319,6 +15562,7 @@ __export(dist_exports, {
|
|
|
15319
15562
|
pruneTopics: () => pruneTopics,
|
|
15320
15563
|
purgeExpiredWorkItems: () => purgeExpiredWorkItems,
|
|
15321
15564
|
readAuditRecords: () => readAuditRecords,
|
|
15565
|
+
readBranchOnlyMessages: () => readBranchOnlyMessages,
|
|
15322
15566
|
readCaptainAddress: () => readCaptainAddress,
|
|
15323
15567
|
readCursor: () => readCursor,
|
|
15324
15568
|
readEscalations: () => readEscalations,
|
|
@@ -15342,9 +15586,13 @@ __export(dist_exports, {
|
|
|
15342
15586
|
recoverStall: () => recoverStall,
|
|
15343
15587
|
reduce: () => reduce,
|
|
15344
15588
|
reduceLifecycle: () => reduceLifecycle,
|
|
15589
|
+
refCandidates: () => refCandidates,
|
|
15590
|
+
refCanon: () => refCanon,
|
|
15345
15591
|
refFor: () => refFor,
|
|
15592
|
+
refPath: () => refPath,
|
|
15346
15593
|
releaseDaemonLock: () => releaseDaemonLock,
|
|
15347
15594
|
removeRunningMarker: () => removeRunningMarker,
|
|
15595
|
+
removeSource: () => removeSource,
|
|
15348
15596
|
renderEnvAssignments: () => renderEnvAssignments,
|
|
15349
15597
|
renderPlist: () => renderPlist,
|
|
15350
15598
|
renderReport: () => renderReport,
|
|
@@ -15374,6 +15622,7 @@ __export(dist_exports, {
|
|
|
15374
15622
|
resolveSetupGroup: () => resolveSetupGroup,
|
|
15375
15623
|
resolveSetupToken: () => resolveSetupToken,
|
|
15376
15624
|
resolveSetupUserId: () => resolveSetupUserId,
|
|
15625
|
+
resolveSourceRef: () => resolveSourceRef,
|
|
15377
15626
|
restartDaemonIfRunning: () => restartDaemonIfRunning,
|
|
15378
15627
|
rotateIfNeeded: () => rotateIfNeeded,
|
|
15379
15628
|
ruleAuditScope: () => ruleAuditScope,
|
|
@@ -15407,6 +15656,7 @@ __export(dist_exports, {
|
|
|
15407
15656
|
saveSessions: () => saveSessions,
|
|
15408
15657
|
saveState: () => saveState,
|
|
15409
15658
|
scanAndLogCitations: () => scanAndLogCitations,
|
|
15659
|
+
scanCitations: () => scanCitations,
|
|
15410
15660
|
scheduleFile: () => scheduleFile,
|
|
15411
15661
|
scoreKb: () => scoreKb,
|
|
15412
15662
|
scoresFile: () => scoresFile,
|
|
@@ -15427,6 +15677,7 @@ __export(dist_exports, {
|
|
|
15427
15677
|
sideNextAutoName: () => sideNextAutoName,
|
|
15428
15678
|
sideTitleFor: () => sideTitleFor,
|
|
15429
15679
|
snapshotSources: () => snapshotSources,
|
|
15680
|
+
sourceCovers: () => sourceCovers,
|
|
15430
15681
|
spansOverlap: () => spansOverlap,
|
|
15431
15682
|
splitSections: () => splitSections,
|
|
15432
15683
|
splitStatement: () => splitStatement,
|
|
@@ -15561,7 +15812,7 @@ import { readdirSync as readdirSync4, readFileSync as readFileSync12 } from "fs"
|
|
|
15561
15812
|
import { join as join18 } from "path";
|
|
15562
15813
|
|
|
15563
15814
|
// packages/agents/dist/claude/registry.js
|
|
15564
|
-
import
|
|
15815
|
+
import fs31 from "fs";
|
|
15565
15816
|
import { join as join17 } from "path";
|
|
15566
15817
|
import { homedir as homedir7 } from "os";
|
|
15567
15818
|
var CLAUDE_SESSIONS_DIR = join17(homedir7(), ".claude", "sessions");
|
|
@@ -15606,11 +15857,11 @@ function toLifecycleSnapshot(entry, taskId, alive, now) {
|
|
|
15606
15857
|
function readClaudeStatusBySocketPath(socketPath) {
|
|
15607
15858
|
let files;
|
|
15608
15859
|
try {
|
|
15609
|
-
files =
|
|
15860
|
+
files = fs31.readdirSync(CLAUDE_SESSIONS_DIR);
|
|
15610
15861
|
} catch {
|
|
15611
15862
|
return void 0;
|
|
15612
15863
|
}
|
|
15613
|
-
const entries = parseRegistryDir(files, (name) =>
|
|
15864
|
+
const entries = parseRegistryDir(files, (name) => fs31.readFileSync(join17(CLAUDE_SESSIONS_DIR, name), "utf8"));
|
|
15614
15865
|
const entry = entries.find((e) => e.messagingSocketPath === socketPath);
|
|
15615
15866
|
if (!entry)
|
|
15616
15867
|
return void 0;
|
|
@@ -15633,38 +15884,38 @@ import { homedir as homedir8 } from "os";
|
|
|
15633
15884
|
var SQUADRANT_STATE_DIR = join19(homedir8(), ".config", "squadrant", "state");
|
|
15634
15885
|
|
|
15635
15886
|
// packages/agents/dist/drivers/launch-cmd.js
|
|
15636
|
-
import
|
|
15637
|
-
import
|
|
15887
|
+
import fs32 from "fs";
|
|
15888
|
+
import path32 from "path";
|
|
15638
15889
|
|
|
15639
15890
|
// packages/agents/dist/projection/cursor.js
|
|
15640
15891
|
import { mkdir, readFile, writeFile } from "fs/promises";
|
|
15641
|
-
import
|
|
15642
|
-
import
|
|
15892
|
+
import path33 from "path";
|
|
15893
|
+
import os9 from "os";
|
|
15643
15894
|
|
|
15644
15895
|
// packages/agents/dist/projection/codex.js
|
|
15645
15896
|
import { mkdir as mkdir2, readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
|
|
15646
|
-
import
|
|
15647
|
-
import
|
|
15897
|
+
import path34 from "path";
|
|
15898
|
+
import os10 from "os";
|
|
15648
15899
|
|
|
15649
15900
|
// packages/agents/dist/projection/gemini.js
|
|
15650
15901
|
import { mkdir as mkdir3, readFile as readFile3, writeFile as writeFile3 } from "fs/promises";
|
|
15651
|
-
import
|
|
15652
|
-
import
|
|
15902
|
+
import path35 from "path";
|
|
15903
|
+
import os11 from "os";
|
|
15653
15904
|
|
|
15654
15905
|
// packages/agents/dist/projection/opencode.js
|
|
15655
15906
|
import { mkdir as mkdir4, readFile as readFile4, writeFile as writeFile4 } from "fs/promises";
|
|
15656
|
-
import
|
|
15657
|
-
import
|
|
15907
|
+
import path36 from "path";
|
|
15908
|
+
import os12 from "os";
|
|
15658
15909
|
|
|
15659
15910
|
// packages/agents/dist/projection/opencode-skills.js
|
|
15660
|
-
import
|
|
15661
|
-
import
|
|
15662
|
-
import
|
|
15911
|
+
import fs33 from "fs";
|
|
15912
|
+
import os13 from "os";
|
|
15913
|
+
import path37 from "path";
|
|
15663
15914
|
var OPENCODE_SKILL_MARKER = ".squadrant-managed";
|
|
15664
15915
|
var MARKER_BODY = "squadrant\n";
|
|
15665
15916
|
function defaultOpencodeSkillsRoot(env = process.env) {
|
|
15666
|
-
const configHome = env.XDG_CONFIG_HOME ||
|
|
15667
|
-
return
|
|
15917
|
+
const configHome = env.XDG_CONFIG_HOME || path37.join(os13.homedir(), ".config");
|
|
15918
|
+
return path37.join(configHome, "opencode", "skills");
|
|
15668
15919
|
}
|
|
15669
15920
|
var SAFE_NAME = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
|
|
15670
15921
|
function parseSkillName(raw) {
|
|
@@ -15679,62 +15930,62 @@ function parseSkillName(raw) {
|
|
|
15679
15930
|
}
|
|
15680
15931
|
function listSourceSkills(sourceSkillsDir) {
|
|
15681
15932
|
const out = /* @__PURE__ */ new Map();
|
|
15682
|
-
if (!
|
|
15933
|
+
if (!fs33.existsSync(sourceSkillsDir))
|
|
15683
15934
|
return out;
|
|
15684
|
-
for (const entry of
|
|
15935
|
+
for (const entry of fs33.readdirSync(sourceSkillsDir, { withFileTypes: true })) {
|
|
15685
15936
|
if (!entry.isDirectory())
|
|
15686
15937
|
continue;
|
|
15687
|
-
const skillPath =
|
|
15688
|
-
if (!
|
|
15938
|
+
const skillPath = path37.join(sourceSkillsDir, entry.name, "SKILL.md");
|
|
15939
|
+
if (!fs33.existsSync(skillPath))
|
|
15689
15940
|
continue;
|
|
15690
|
-
const name = parseSkillName(
|
|
15941
|
+
const name = parseSkillName(fs33.readFileSync(skillPath, "utf-8"));
|
|
15691
15942
|
if (name && SAFE_NAME.test(name))
|
|
15692
15943
|
out.set(name, skillPath);
|
|
15693
15944
|
}
|
|
15694
15945
|
return out;
|
|
15695
15946
|
}
|
|
15696
15947
|
function hasMarker(dir) {
|
|
15697
|
-
return
|
|
15948
|
+
return fs33.existsSync(path37.join(dir, OPENCODE_SKILL_MARKER));
|
|
15698
15949
|
}
|
|
15699
15950
|
function syncOpencodeSkills(opts) {
|
|
15700
15951
|
const result = { written: [], unchanged: [], removed: [], skipped: [] };
|
|
15701
15952
|
const wanted = listSourceSkills(opts.sourceSkillsDir);
|
|
15702
|
-
if (wanted.size === 0 && !
|
|
15953
|
+
if (wanted.size === 0 && !fs33.existsSync(opts.sourceSkillsDir))
|
|
15703
15954
|
return result;
|
|
15704
15955
|
if (!opts.dryRun)
|
|
15705
|
-
|
|
15956
|
+
fs33.mkdirSync(opts.skillsRoot, { recursive: true });
|
|
15706
15957
|
for (const [name, srcPath] of wanted) {
|
|
15707
|
-
const targetDir =
|
|
15708
|
-
const targetSkill =
|
|
15958
|
+
const targetDir = path37.join(opts.skillsRoot, name);
|
|
15959
|
+
const targetSkill = path37.join(targetDir, "SKILL.md");
|
|
15709
15960
|
const managed = hasMarker(targetDir);
|
|
15710
|
-
if (
|
|
15961
|
+
if (fs33.existsSync(targetSkill) && !managed) {
|
|
15711
15962
|
result.skipped.push({ name, reason: "foreign-collision" });
|
|
15712
15963
|
continue;
|
|
15713
15964
|
}
|
|
15714
|
-
const current =
|
|
15715
|
-
if (current && current.equals(
|
|
15965
|
+
const current = fs33.existsSync(targetSkill) ? fs33.readFileSync(targetSkill) : null;
|
|
15966
|
+
if (current && current.equals(fs33.readFileSync(srcPath))) {
|
|
15716
15967
|
if (!managed && !opts.dryRun) {
|
|
15717
|
-
|
|
15968
|
+
fs33.writeFileSync(path37.join(targetDir, OPENCODE_SKILL_MARKER), MARKER_BODY);
|
|
15718
15969
|
}
|
|
15719
15970
|
result.unchanged.push(name);
|
|
15720
15971
|
continue;
|
|
15721
15972
|
}
|
|
15722
15973
|
if (!opts.dryRun) {
|
|
15723
|
-
|
|
15724
|
-
|
|
15725
|
-
|
|
15974
|
+
fs33.mkdirSync(targetDir, { recursive: true });
|
|
15975
|
+
fs33.copyFileSync(srcPath, targetSkill);
|
|
15976
|
+
fs33.writeFileSync(path37.join(targetDir, OPENCODE_SKILL_MARKER), MARKER_BODY);
|
|
15726
15977
|
}
|
|
15727
15978
|
result.written.push(name);
|
|
15728
15979
|
}
|
|
15729
|
-
if (
|
|
15730
|
-
for (const entry of
|
|
15980
|
+
if (fs33.existsSync(opts.skillsRoot)) {
|
|
15981
|
+
for (const entry of fs33.readdirSync(opts.skillsRoot, { withFileTypes: true })) {
|
|
15731
15982
|
if (!entry.isDirectory() || wanted.has(entry.name))
|
|
15732
15983
|
continue;
|
|
15733
|
-
const dir =
|
|
15984
|
+
const dir = path37.join(opts.skillsRoot, entry.name);
|
|
15734
15985
|
if (!hasMarker(dir))
|
|
15735
15986
|
continue;
|
|
15736
15987
|
if (!opts.dryRun)
|
|
15737
|
-
|
|
15988
|
+
fs33.rmSync(dir, { recursive: true, force: true });
|
|
15738
15989
|
result.removed.push(entry.name);
|
|
15739
15990
|
}
|
|
15740
15991
|
}
|
|
@@ -15742,7 +15993,7 @@ function syncOpencodeSkills(opts) {
|
|
|
15742
15993
|
}
|
|
15743
15994
|
function syncShippedOpencodeSkills(opts) {
|
|
15744
15995
|
return syncOpencodeSkills({
|
|
15745
|
-
sourceSkillsDir:
|
|
15996
|
+
sourceSkillsDir: path37.join(opts.pkgRoot, "plugin", "skills"),
|
|
15746
15997
|
skillsRoot: opts.skillsRoot ?? defaultOpencodeSkillsRoot(),
|
|
15747
15998
|
dryRun: opts.dryRun
|
|
15748
15999
|
});
|
|
@@ -15750,8 +16001,8 @@ function syncShippedOpencodeSkills(opts) {
|
|
|
15750
16001
|
|
|
15751
16002
|
// packages/agents/dist/projection/claude.js
|
|
15752
16003
|
import { mkdir as mkdir5, readFile as readFile5, writeFile as writeFile5 } from "fs/promises";
|
|
15753
|
-
import
|
|
15754
|
-
import
|
|
16004
|
+
import path38 from "path";
|
|
16005
|
+
import os14 from "os";
|
|
15755
16006
|
|
|
15756
16007
|
// packages/agents/dist/codex/app-server-client.js
|
|
15757
16008
|
import { EventEmitter } from "events";
|
|
@@ -17095,9 +17346,9 @@ var ClaudeReceiptListener = class {
|
|
|
17095
17346
|
};
|
|
17096
17347
|
|
|
17097
17348
|
// packages/agents/dist/claude/api-key-approval.js
|
|
17098
|
-
import
|
|
17099
|
-
import
|
|
17100
|
-
import
|
|
17349
|
+
import fs34 from "fs";
|
|
17350
|
+
import os15 from "os";
|
|
17351
|
+
import path39 from "path";
|
|
17101
17352
|
|
|
17102
17353
|
// packages/agents/dist/opencode/http-channel.js
|
|
17103
17354
|
init_dist2();
|
|
@@ -17189,10 +17440,10 @@ var OpencodeHttpChannel = class {
|
|
|
17189
17440
|
return cached;
|
|
17190
17441
|
const directory = this.directoryFor?.(taskId);
|
|
17191
17442
|
const createdAfterMs = this.createdAfterFor?.(taskId);
|
|
17192
|
-
for (const
|
|
17443
|
+
for (const path43 of ["/session?", "/api/session?"]) {
|
|
17193
17444
|
let res;
|
|
17194
17445
|
try {
|
|
17195
|
-
res = await this.request(`http://127.0.0.1:${port}${
|
|
17446
|
+
res = await this.request(`http://127.0.0.1:${port}${path43}`, { method: "GET" });
|
|
17196
17447
|
} catch {
|
|
17197
17448
|
return void 0;
|
|
17198
17449
|
}
|
|
@@ -17266,9 +17517,9 @@ function createOpencodeFactAdapter(deps) {
|
|
|
17266
17517
|
}
|
|
17267
17518
|
|
|
17268
17519
|
// packages/agents/dist/rules-hooks/install.js
|
|
17269
|
-
import
|
|
17270
|
-
import
|
|
17271
|
-
import
|
|
17520
|
+
import fs35 from "fs";
|
|
17521
|
+
import os16 from "os";
|
|
17522
|
+
import path40 from "path";
|
|
17272
17523
|
|
|
17273
17524
|
// packages/workspaces/dist/runtimes/cmux.js
|
|
17274
17525
|
init_dist();
|
|
@@ -17276,7 +17527,7 @@ init_dist();
|
|
|
17276
17527
|
init_dist();
|
|
17277
17528
|
init_dist2();
|
|
17278
17529
|
init_dist2();
|
|
17279
|
-
import { execFile as execFile3, execFileSync as
|
|
17530
|
+
import { execFile as execFile3, execFileSync as execFileSync9 } from "child_process";
|
|
17280
17531
|
var CMUX_TIMEOUT = 15e3;
|
|
17281
17532
|
var CmuxTimeoutError = class extends Error {
|
|
17282
17533
|
constructor(cmd) {
|
|
@@ -17950,7 +18201,7 @@ var RuntimeRegistry = class {
|
|
|
17950
18201
|
|
|
17951
18202
|
// packages/workspaces/dist/notifiers/cmux.js
|
|
17952
18203
|
init_dist();
|
|
17953
|
-
import { execFile as execFileCb, execFileSync as
|
|
18204
|
+
import { execFile as execFileCb, execFileSync as execFileSync10 } from "child_process";
|
|
17954
18205
|
import { promisify as promisify3 } from "util";
|
|
17955
18206
|
var execFile4 = promisify3(execFileCb);
|
|
17956
18207
|
function createCmuxNotifier(_scope) {
|
|
@@ -17958,7 +18209,7 @@ function createCmuxNotifier(_scope) {
|
|
|
17958
18209
|
name: "cmux",
|
|
17959
18210
|
async probe() {
|
|
17960
18211
|
try {
|
|
17961
|
-
|
|
18212
|
+
execFileSync10(resolveCmuxBin(), ["capabilities"], { encoding: "utf-8", stdio: "pipe", timeout: CMUX_TIMEOUT });
|
|
17962
18213
|
return { installed: true, reachable: true };
|
|
17963
18214
|
} catch (err) {
|
|
17964
18215
|
const code = err.code;
|
|
@@ -18006,9 +18257,9 @@ var NotifierRegistry = class {
|
|
|
18006
18257
|
};
|
|
18007
18258
|
|
|
18008
18259
|
// packages/workspaces/dist/workspaces/obsidian.js
|
|
18009
|
-
import
|
|
18260
|
+
import fs36 from "fs/promises";
|
|
18010
18261
|
import { existsSync as existsSync11 } from "fs";
|
|
18011
|
-
import
|
|
18262
|
+
import path41 from "path";
|
|
18012
18263
|
|
|
18013
18264
|
// packages/workspaces/dist/workspaces/registry.js
|
|
18014
18265
|
init_dist();
|
|
@@ -18168,9 +18419,9 @@ import { homedir as homedir11 } from "os";
|
|
|
18168
18419
|
// packages/workspaces/dist/cmux-daemon/store-fingerprint.js
|
|
18169
18420
|
init_dist();
|
|
18170
18421
|
init_dist2();
|
|
18171
|
-
import { execFileSync as
|
|
18422
|
+
import { execFileSync as execFileSync11 } from "child_process";
|
|
18172
18423
|
function defaultExecPs(pid) {
|
|
18173
|
-
return
|
|
18424
|
+
return execFileSync11("ps", ["-o", "command=", "-p", String(pid)], {
|
|
18174
18425
|
encoding: "utf-8",
|
|
18175
18426
|
stdio: ["ignore", "pipe", "ignore"]
|
|
18176
18427
|
});
|
|
@@ -18558,9 +18809,9 @@ function defaultListFiles(dir) {
|
|
|
18558
18809
|
return [];
|
|
18559
18810
|
}
|
|
18560
18811
|
}
|
|
18561
|
-
function defaultReadFile(
|
|
18812
|
+
function defaultReadFile(path43) {
|
|
18562
18813
|
try {
|
|
18563
|
-
return readFileSync17(
|
|
18814
|
+
return readFileSync17(path43, "utf-8");
|
|
18564
18815
|
} catch {
|
|
18565
18816
|
return void 0;
|
|
18566
18817
|
}
|
|
@@ -18940,16 +19191,16 @@ function extractDetail(sub, payload) {
|
|
|
18940
19191
|
}
|
|
18941
19192
|
return void 0;
|
|
18942
19193
|
}
|
|
18943
|
-
function defaultReadFile2(
|
|
19194
|
+
function defaultReadFile2(path43) {
|
|
18944
19195
|
try {
|
|
18945
|
-
return readFileSync18(
|
|
19196
|
+
return readFileSync18(path43, "utf-8");
|
|
18946
19197
|
} catch {
|
|
18947
19198
|
return void 0;
|
|
18948
19199
|
}
|
|
18949
19200
|
}
|
|
18950
|
-
function defaultWriteFile(
|
|
18951
|
-
mkdirSync8(
|
|
18952
|
-
writeFileSync11(
|
|
19201
|
+
function defaultWriteFile(path43, content) {
|
|
19202
|
+
mkdirSync8(path43.replace(/\/[^/]+$/, ""), { recursive: true });
|
|
19203
|
+
writeFileSync11(path43, content, "utf-8");
|
|
18953
19204
|
}
|
|
18954
19205
|
|
|
18955
19206
|
// packages/workspaces/dist/crew-pane.js
|
|
@@ -19034,9 +19285,9 @@ init_dist();
|
|
|
19034
19285
|
|
|
19035
19286
|
// packages/cli/src/lib/daemon-restart-broadcast.ts
|
|
19036
19287
|
init_dist();
|
|
19037
|
-
import
|
|
19288
|
+
import path42 from "path";
|
|
19038
19289
|
function statePath2(stateRoot) {
|
|
19039
|
-
return
|
|
19290
|
+
return path42.join(stateRoot, "daemon-restart-state.json");
|
|
19040
19291
|
}
|
|
19041
19292
|
function computeRestartSignature(version, buildMtimeMs) {
|
|
19042
19293
|
return `${version}::${buildMtimeMs}`;
|
|
@@ -19085,7 +19336,7 @@ async function maybeBroadcastDaemonRestart(opts) {
|
|
|
19085
19336
|
|
|
19086
19337
|
// packages/cli/src/lib/captain-channel-factory.ts
|
|
19087
19338
|
import { createServer as createServer4, connect as netConnect } from "net";
|
|
19088
|
-
import
|
|
19339
|
+
import fs37 from "fs";
|
|
19089
19340
|
import { join as join26 } from "path";
|
|
19090
19341
|
import { randomUUID as randomUUID5 } from "crypto";
|
|
19091
19342
|
import chalk2 from "chalk";
|
|
@@ -19094,15 +19345,15 @@ var shared;
|
|
|
19094
19345
|
var registryEntryPath = () => join26(CLAUDE_SESSIONS_DIR, `${process.pid}.json`);
|
|
19095
19346
|
function unregisterSenderIdentity() {
|
|
19096
19347
|
try {
|
|
19097
|
-
|
|
19348
|
+
fs37.unlinkSync(registryEntryPath());
|
|
19098
19349
|
} catch {
|
|
19099
19350
|
}
|
|
19100
19351
|
}
|
|
19101
19352
|
function registerSenderIdentity(socketPath) {
|
|
19102
19353
|
try {
|
|
19103
19354
|
unregisterSenderIdentity();
|
|
19104
|
-
|
|
19105
|
-
|
|
19355
|
+
fs37.mkdirSync(CLAUDE_SESSIONS_DIR, { recursive: true });
|
|
19356
|
+
fs37.writeFileSync(
|
|
19106
19357
|
registryEntryPath(),
|
|
19107
19358
|
JSON.stringify({
|
|
19108
19359
|
pid: process.pid,
|
|
@@ -19128,7 +19379,7 @@ async function sharedReceiptListener() {
|
|
|
19128
19379
|
// must never be the reason we refuse to start.
|
|
19129
19380
|
unlinkStale: (p) => {
|
|
19130
19381
|
try {
|
|
19131
|
-
|
|
19382
|
+
fs37.unlinkSync(p);
|
|
19132
19383
|
} catch {
|
|
19133
19384
|
}
|
|
19134
19385
|
},
|
|
@@ -19153,7 +19404,7 @@ async function buildCaptainChannel() {
|
|
|
19153
19404
|
// in /tmp/x registers cwd "/private/tmp/x" on macOS, so cwd matching silently
|
|
19154
19405
|
// missed and every captain ping reported accepted-unconfirmed.
|
|
19155
19406
|
statusFor: (taskId) => readClaudeStatusBySocketPath(captainSocketPath(taskId)),
|
|
19156
|
-
wire: (p, e) => writeLine(p, e, { connect: (
|
|
19407
|
+
wire: (p, e) => writeLine(p, e, { connect: (path43) => netConnect(path43) }),
|
|
19157
19408
|
receipts,
|
|
19158
19409
|
newMsgId: () => randomUUID5(),
|
|
19159
19410
|
sleep: (ms) => new Promise((r) => setTimeout(r, ms)),
|