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/index.js
CHANGED
|
@@ -466,7 +466,8 @@ function validateRuleFrontmatter(fm) {
|
|
|
466
466
|
if (fm[k] !== void 0 && !isStrArr(fm[k]))
|
|
467
467
|
p.push(`${k} must be a string array`);
|
|
468
468
|
}
|
|
469
|
-
|
|
469
|
+
const mayBeSourceless = fm.status === "stale" || fm.status === "retired";
|
|
470
|
+
if (!Array.isArray(fm.sources) || fm.sources.length === 0 && !mayBeSourceless) {
|
|
470
471
|
p.push("sources must be a non-empty array");
|
|
471
472
|
} else {
|
|
472
473
|
fm.sources.forEach((s, i) => {
|
|
@@ -500,6 +501,26 @@ function validateSourceEntry(e) {
|
|
|
500
501
|
p.push("domain must be a string");
|
|
501
502
|
if (e.sensitivity !== void 0 && e.sensitivity !== "local-only")
|
|
502
503
|
p.push("sensitivity must be 'local-only' when set");
|
|
504
|
+
if (e.review !== void 0 && e.review !== "required")
|
|
505
|
+
p.push("review must be 'required' when set");
|
|
506
|
+
return p;
|
|
507
|
+
}
|
|
508
|
+
function validateErratum(e) {
|
|
509
|
+
if (!isObj(e))
|
|
510
|
+
return ["erratum must be an object"];
|
|
511
|
+
const p = [];
|
|
512
|
+
if (typeof e.id !== "string" || !RULE_ID_RE.test(e.id))
|
|
513
|
+
p.push(`id must match ${RULE_ID_RE}`);
|
|
514
|
+
for (const k of ["ref", "quote", "reason"]) {
|
|
515
|
+
if (typeof e[k] !== "string" || e[k] === "")
|
|
516
|
+
p.push(`${k} must be a non-empty string`);
|
|
517
|
+
}
|
|
518
|
+
if (e.evidence !== void 0 && !isStrArr(e.evidence))
|
|
519
|
+
p.push("evidence must be a string array");
|
|
520
|
+
for (const k of ["checked", "by", "at", "decision"]) {
|
|
521
|
+
if (e[k] !== void 0 && typeof e[k] !== "string")
|
|
522
|
+
p.push(`${k} must be a string`);
|
|
523
|
+
}
|
|
503
524
|
return p;
|
|
504
525
|
}
|
|
505
526
|
function kbConfigs(cfg) {
|
|
@@ -624,22 +645,22 @@ function defaultCmuxConfigPath() {
|
|
|
624
645
|
return join(homedir(), ".config", "cmux", "cmux.json");
|
|
625
646
|
}
|
|
626
647
|
function ensureSocketAutomation(opts = {}) {
|
|
627
|
-
const
|
|
628
|
-
if (!existsSync(
|
|
629
|
-
mkdirSync(dirname(
|
|
630
|
-
writeFileSync(
|
|
631
|
-
return { path:
|
|
648
|
+
const path60 = opts.path ?? defaultCmuxConfigPath();
|
|
649
|
+
if (!existsSync(path60)) {
|
|
650
|
+
mkdirSync(dirname(path60), { recursive: true });
|
|
651
|
+
writeFileSync(path60, MINIMAL_TEMPLATE);
|
|
652
|
+
return { path: path60, changed: true, alreadySet: false };
|
|
632
653
|
}
|
|
633
|
-
const text = readFileSync(
|
|
654
|
+
const text = readFileSync(path60, "utf-8");
|
|
634
655
|
const current = parse(text)?.automation?.socketControlMode;
|
|
635
656
|
if (current === AUTOMATION_MODE) {
|
|
636
|
-
return { path:
|
|
657
|
+
return { path: path60, changed: false, alreadySet: true };
|
|
637
658
|
}
|
|
638
659
|
const edits = modify(text, [...SOCKET_CONTROL_MODE_PATH], AUTOMATION_MODE, {
|
|
639
660
|
formattingOptions: { insertSpaces: true, tabSize: 2 }
|
|
640
661
|
});
|
|
641
|
-
writeFileSync(
|
|
642
|
-
return { path:
|
|
662
|
+
writeFileSync(path60, applyEdits(text, edits));
|
|
663
|
+
return { path: path60, changed: true, alreadySet: false };
|
|
643
664
|
}
|
|
644
665
|
var SOCKET_CONTROL_MODE_PATH, AUTOMATION_MODE, MINIMAL_TEMPLATE;
|
|
645
666
|
var init_cmux_config = __esm({
|
|
@@ -792,9 +813,9 @@ import { join as join4 } from "path";
|
|
|
792
813
|
function defaultStatePath() {
|
|
793
814
|
return join4(homedir3(), ".config", "squadrant", "state", "cmux-autoconfig.json");
|
|
794
815
|
}
|
|
795
|
-
function readState(
|
|
816
|
+
function readState(path60) {
|
|
796
817
|
try {
|
|
797
|
-
return JSON.parse(readConfigFileSync(
|
|
818
|
+
return JSON.parse(readConfigFileSync(path60));
|
|
798
819
|
} catch {
|
|
799
820
|
return {};
|
|
800
821
|
}
|
|
@@ -955,18 +976,18 @@ function detectDrift(user, def) {
|
|
|
955
976
|
}
|
|
956
977
|
}
|
|
957
978
|
}
|
|
958
|
-
const checkBackend = (
|
|
979
|
+
const checkBackend = (path60, backend, agentName) => {
|
|
959
980
|
if (backend === void 0)
|
|
960
981
|
return;
|
|
961
982
|
if (!isBackendMode(backend)) {
|
|
962
|
-
items.push({ path:
|
|
983
|
+
items.push({ path: path60, kind: "invalid", severity: "warn", current: backend, note: "unknown backend; expected native|direct|proxy" });
|
|
963
984
|
return;
|
|
964
985
|
}
|
|
965
986
|
if (backend !== "native") {
|
|
966
987
|
if (agentName !== "claude") {
|
|
967
|
-
items.push({ path:
|
|
988
|
+
items.push({ path: path60, kind: "invalid", severity: "warn", current: backend, note: `backend '${backend}' is claude-only (agent '${agentName ?? "?"}')` });
|
|
968
989
|
} else if (!router) {
|
|
969
|
-
items.push({ path:
|
|
990
|
+
items.push({ path: path60, kind: "invalid", severity: "warn", current: backend, note: `backend '${backend}' requires defaults.router` });
|
|
970
991
|
}
|
|
971
992
|
}
|
|
972
993
|
};
|
|
@@ -1859,6 +1880,7 @@ __export(dist_exports, {
|
|
|
1859
1880
|
saveConfig: () => saveConfig,
|
|
1860
1881
|
saveProjectOverride: () => saveProjectOverride,
|
|
1861
1882
|
subscribedKbs: () => subscribedKbs,
|
|
1883
|
+
validateErratum: () => validateErratum,
|
|
1862
1884
|
validateRuleFrontmatter: () => validateRuleFrontmatter,
|
|
1863
1885
|
validateSourceEntry: () => validateSourceEntry,
|
|
1864
1886
|
withStamp: () => withStamp,
|
|
@@ -3510,10 +3532,10 @@ function detectForeignInstall(parsed, thisEntry, registeredEntryExists) {
|
|
|
3510
3532
|
isUpgrade: isVersionUpgrade(parsed.daemonEntry, thisEntry)
|
|
3511
3533
|
};
|
|
3512
3534
|
}
|
|
3513
|
-
function sanitizePathForPlist(
|
|
3535
|
+
function sanitizePathForPlist(path60) {
|
|
3514
3536
|
const seen = /* @__PURE__ */ new Set();
|
|
3515
3537
|
const stable = [];
|
|
3516
|
-
for (const p of
|
|
3538
|
+
for (const p of path60.split(":")) {
|
|
3517
3539
|
if (!p)
|
|
3518
3540
|
continue;
|
|
3519
3541
|
if (p.includes("/.claude/plugins/"))
|
|
@@ -6053,11 +6075,11 @@ var init_captain_record = __esm({
|
|
|
6053
6075
|
// packages/core/dist/opencode-session.js
|
|
6054
6076
|
import { execFileSync as execFileSync4 } from "child_process";
|
|
6055
6077
|
async function listSessions(port, fetchImpl = fetch, timeoutMs = 5e3) {
|
|
6056
|
-
for (const
|
|
6078
|
+
for (const path60 of ["/session", "/api/session"]) {
|
|
6057
6079
|
const ac = new AbortController();
|
|
6058
6080
|
const t = setTimeout(() => ac.abort(), timeoutMs);
|
|
6059
6081
|
try {
|
|
6060
|
-
const res = await fetchImpl(`http://127.0.0.1:${port}${
|
|
6082
|
+
const res = await fetchImpl(`http://127.0.0.1:${port}${path60}`, { signal: ac.signal });
|
|
6061
6083
|
if (!res.ok)
|
|
6062
6084
|
continue;
|
|
6063
6085
|
const rows = await res.json();
|
|
@@ -6750,10 +6772,10 @@ function distBuiltAt() {
|
|
|
6750
6772
|
return 0;
|
|
6751
6773
|
}
|
|
6752
6774
|
}
|
|
6753
|
-
function gatherLogStats(
|
|
6775
|
+
function gatherLogStats(path60, now, windowMs) {
|
|
6754
6776
|
let sizeBytes = 0;
|
|
6755
6777
|
try {
|
|
6756
|
-
sizeBytes = statSync3(
|
|
6778
|
+
sizeBytes = statSync3(path60).size;
|
|
6757
6779
|
} catch {
|
|
6758
6780
|
return { errorCount: 0, sizeBytes: 0, windowMs };
|
|
6759
6781
|
}
|
|
@@ -6764,7 +6786,7 @@ function gatherLogStats(path59, now, windowMs) {
|
|
|
6764
6786
|
const len = sizeBytes - start;
|
|
6765
6787
|
let text = "";
|
|
6766
6788
|
try {
|
|
6767
|
-
const fd = openSync2(
|
|
6789
|
+
const fd = openSync2(path60, "r");
|
|
6768
6790
|
try {
|
|
6769
6791
|
const buf = Buffer.alloc(len);
|
|
6770
6792
|
readSync(fd, buf, 0, len, start);
|
|
@@ -9010,8 +9032,8 @@ var init_stream = __esm({
|
|
|
9010
9032
|
// packages/core/dist/router/shim.js
|
|
9011
9033
|
import { createServer as createServer3 } from "http";
|
|
9012
9034
|
import { Readable } from "stream";
|
|
9013
|
-
function joinUrl(base,
|
|
9014
|
-
return base.replace(/\/+$/, "") +
|
|
9035
|
+
function joinUrl(base, path60) {
|
|
9036
|
+
return base.replace(/\/+$/, "") + path60;
|
|
9015
9037
|
}
|
|
9016
9038
|
async function readBody(req) {
|
|
9017
9039
|
const chunks = [];
|
|
@@ -9187,8 +9209,8 @@ function createRouterShim(opts) {
|
|
|
9187
9209
|
writeJson(res, 200, { input_tokens: Math.max(1, Math.ceil(text.length / 4)) });
|
|
9188
9210
|
}
|
|
9189
9211
|
function handler(req, res) {
|
|
9190
|
-
const
|
|
9191
|
-
if (req.method === "POST" &&
|
|
9212
|
+
const path60 = pathnameOf(req.url);
|
|
9213
|
+
if (req.method === "POST" && path60 === "/v1/messages") {
|
|
9192
9214
|
void handleMessages(req, res).catch((err) => {
|
|
9193
9215
|
log(`router internal error: ${err instanceof Error ? err.message : String(err)}`);
|
|
9194
9216
|
if (!res.headersSent) {
|
|
@@ -9200,18 +9222,18 @@ function createRouterShim(opts) {
|
|
|
9200
9222
|
});
|
|
9201
9223
|
return;
|
|
9202
9224
|
}
|
|
9203
|
-
if (req.method === "POST" &&
|
|
9225
|
+
if (req.method === "POST" && path60 === "/v1/messages/count_tokens") {
|
|
9204
9226
|
void handleCountTokens(req, res).catch(() => {
|
|
9205
9227
|
if (!res.headersSent)
|
|
9206
9228
|
writeJson(res, 502, anthropicError(502, "api_error", "router internal error").body);
|
|
9207
9229
|
});
|
|
9208
9230
|
return;
|
|
9209
9231
|
}
|
|
9210
|
-
if (req.method === "GET" &&
|
|
9232
|
+
if (req.method === "GET" && path60 === "/v1/models") {
|
|
9211
9233
|
writeJson(res, 200, modelsList([...advertisedModels]));
|
|
9212
9234
|
return;
|
|
9213
9235
|
}
|
|
9214
|
-
if (req.method === "GET" &&
|
|
9236
|
+
if (req.method === "GET" && path60 === "/healthz") {
|
|
9215
9237
|
writeJson(res, 200, { ready: server?.listening === true, upstreamReachable, lastError });
|
|
9216
9238
|
return;
|
|
9217
9239
|
}
|
|
@@ -9480,11 +9502,11 @@ async function probeCaptainChannel(project, opts = {}) {
|
|
|
9480
9502
|
}
|
|
9481
9503
|
}
|
|
9482
9504
|
async function httpReachable(port, fetchImpl, timeoutMs) {
|
|
9483
|
-
for (const
|
|
9505
|
+
for (const path60 of ["/session", "/api/session"]) {
|
|
9484
9506
|
const ac = new AbortController();
|
|
9485
9507
|
const t = setTimeout(() => ac.abort(), timeoutMs);
|
|
9486
9508
|
try {
|
|
9487
|
-
const res = await fetchImpl(`http://127.0.0.1:${port}${
|
|
9509
|
+
const res = await fetchImpl(`http://127.0.0.1:${port}${path60}`, { signal: ac.signal });
|
|
9488
9510
|
if (res.ok)
|
|
9489
9511
|
return true;
|
|
9490
9512
|
} catch {
|
|
@@ -10406,6 +10428,35 @@ function expandSource(kbRoot, entry) {
|
|
|
10406
10428
|
const re = globToRegExp(abs.split(path16.sep).join("/"));
|
|
10407
10429
|
return walkFiles(root).filter((f) => re.test(f.split(path16.sep).join("/"))).sort();
|
|
10408
10430
|
}
|
|
10431
|
+
function refCandidates(kbRoot, sources, ref) {
|
|
10432
|
+
const asIs = path16.resolve(kbRoot, expandHome(ref));
|
|
10433
|
+
if (path16.isAbsolute(expandHome(ref)))
|
|
10434
|
+
return [asIs];
|
|
10435
|
+
const bases = /* @__PURE__ */ new Set([kbRoot]);
|
|
10436
|
+
for (const s of sources) {
|
|
10437
|
+
let d = path16.resolve(kbRoot, expandHome(s.path.split(/[*?[{]/)[0]));
|
|
10438
|
+
for (let i = 0; i < 6 && d !== path16.dirname(d); i++) {
|
|
10439
|
+
d = path16.dirname(d);
|
|
10440
|
+
bases.add(d);
|
|
10441
|
+
}
|
|
10442
|
+
}
|
|
10443
|
+
return [.../* @__PURE__ */ new Set([asIs, ...[...bases].map((b) => path16.join(b, ref))])];
|
|
10444
|
+
}
|
|
10445
|
+
function refPath(kbRoot, sources, ref) {
|
|
10446
|
+
const cands = refCandidates(kbRoot, sources, ref);
|
|
10447
|
+
return cands.find(isFile) ?? cands.find((f) => sources.some((e) => entryCovers(kbRoot, e, f))) ?? cands[0];
|
|
10448
|
+
}
|
|
10449
|
+
function refCanon(kbRoot, sources) {
|
|
10450
|
+
const memo = /* @__PURE__ */ new Map();
|
|
10451
|
+
return (ref) => {
|
|
10452
|
+
let c = memo.get(ref);
|
|
10453
|
+
if (c === void 0) {
|
|
10454
|
+
c = refFor(kbRoot, refPath(kbRoot, sources, ref));
|
|
10455
|
+
memo.set(ref, c);
|
|
10456
|
+
}
|
|
10457
|
+
return c;
|
|
10458
|
+
};
|
|
10459
|
+
}
|
|
10409
10460
|
function detectChange(kbRoot, file) {
|
|
10410
10461
|
const ref = refFor(kbRoot, file);
|
|
10411
10462
|
const st = fs15.statSync(file);
|
|
@@ -10502,7 +10553,7 @@ async function planIngest(kbRoot, opts) {
|
|
|
10502
10553
|
}
|
|
10503
10554
|
return plan;
|
|
10504
10555
|
}
|
|
10505
|
-
var execFileAsync, CONVERTED_DIR, DEFAULT_MAX_SECTIONS_PER_PASS, CHARS_PER_TOKEN, PASS_THROUGH, SECTION_TARGET_CHARS, markitdownConverter, expandHome,
|
|
10556
|
+
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;
|
|
10506
10557
|
var init_ingest = __esm({
|
|
10507
10558
|
"packages/core/dist/knowledge/ingest.js"() {
|
|
10508
10559
|
execFileAsync = promisify2(execFile2);
|
|
@@ -10516,10 +10567,17 @@ var init_ingest = __esm({
|
|
|
10516
10567
|
return stdout;
|
|
10517
10568
|
};
|
|
10518
10569
|
expandHome = (p) => p === "~" || p.startsWith("~/") ? path16.join(os7.homedir(), p.slice(1)) : p;
|
|
10519
|
-
fileForRef = (kbRoot, ref) => path16.resolve(kbRoot, expandHome(ref));
|
|
10520
10570
|
cacheKey = (ref) => `${ref.replace(/[^A-Za-z0-9._-]+/g, "_")}.${crypto3.createHash("sha1").update(ref).digest("hex").slice(0, 6)}`;
|
|
10521
10571
|
convertedFile = (kbRoot, ref) => path16.join(kbRoot, CONVERTED_DIR, `${cacheKey(ref)}.md`);
|
|
10522
10572
|
stampFile = (kbRoot, ref) => path16.join(kbRoot, CONVERTED_DIR, `${cacheKey(ref)}.sha`);
|
|
10573
|
+
isFile = (f) => fs15.existsSync(f) && fs15.statSync(f).isFile();
|
|
10574
|
+
resolveSourceRef = (kbRoot, sources, ref) => refCandidates(kbRoot, sources, ref).find(isFile);
|
|
10575
|
+
entryCovers = (kbRoot, entry, file) => {
|
|
10576
|
+
const abs = path16.resolve(kbRoot, expandHome(entry.path));
|
|
10577
|
+
return /[*?]/.test(entry.path) ? globToRegExp(abs.split(path16.sep).join("/")).test(file.split(path16.sep).join("/")) : abs === file;
|
|
10578
|
+
};
|
|
10579
|
+
sourceCovers = (kbRoot, sources, entry, ref) => entryCovers(kbRoot, entry, refPath(kbRoot, sources, ref));
|
|
10580
|
+
isGatedRef = (kbRoot, sources, ref) => sources.some((e) => e.review === "required" && sourceCovers(kbRoot, sources, e, ref));
|
|
10523
10581
|
sha256 = (file) => crypto3.createHash("sha256").update(fs15.readFileSync(file)).digest("hex");
|
|
10524
10582
|
}
|
|
10525
10583
|
});
|
|
@@ -10602,7 +10660,6 @@ var init_verify = __esm({
|
|
|
10602
10660
|
|
|
10603
10661
|
// packages/core/dist/knowledge/store.js
|
|
10604
10662
|
import fs16 from "fs";
|
|
10605
|
-
import os8 from "os";
|
|
10606
10663
|
import path17 from "path";
|
|
10607
10664
|
import matter2 from "gray-matter";
|
|
10608
10665
|
function duplicateIdProblem(id, ignored, used) {
|
|
@@ -10663,18 +10720,6 @@ function loadRulesDir(dir, layer, opts = {}) {
|
|
|
10663
10720
|
}
|
|
10664
10721
|
return { rules, errors };
|
|
10665
10722
|
}
|
|
10666
|
-
function resolveSourceRef(ref, kbRoot, sources) {
|
|
10667
|
-
const bases = /* @__PURE__ */ new Set([kbRoot]);
|
|
10668
|
-
for (const s of sources) {
|
|
10669
|
-
let d = path17.resolve(kbRoot, expandHome2(s.path.split(/[*?[{]/)[0]));
|
|
10670
|
-
for (let i = 0; i < 6 && d !== path17.dirname(d); i++) {
|
|
10671
|
-
d = path17.dirname(d);
|
|
10672
|
-
bases.add(d);
|
|
10673
|
-
}
|
|
10674
|
-
}
|
|
10675
|
-
const cands = [path17.resolve(kbRoot, expandHome2(ref)), ...[...bases].map((b) => path17.join(b, ref))];
|
|
10676
|
-
return cands.find((c) => fs16.existsSync(c) && fs16.statSync(c).isFile());
|
|
10677
|
-
}
|
|
10678
10723
|
function validateKb(opts) {
|
|
10679
10724
|
const { rules, errors } = loadRulesDir(opts.rulesDir, "kb", { includeProposed: true });
|
|
10680
10725
|
const checks = [];
|
|
@@ -10694,17 +10739,18 @@ function validateKb(opts) {
|
|
|
10694
10739
|
else
|
|
10695
10740
|
checks.push({ level: "ok", message: "no duplicate ids" });
|
|
10696
10741
|
const cache = /* @__PURE__ */ new Map();
|
|
10742
|
+
const canon = refCanon(opts.kbRoot, opts.sources);
|
|
10697
10743
|
let verified = 0, unresolved = 0, notIngested = 0;
|
|
10698
10744
|
for (const r of rules) {
|
|
10699
10745
|
r.sources.forEach((src, i) => {
|
|
10700
|
-
const file = resolveSourceRef(
|
|
10746
|
+
const file = resolveSourceRef(opts.kbRoot, opts.sources, src.ref);
|
|
10701
10747
|
if (!file) {
|
|
10702
10748
|
unresolved++;
|
|
10703
10749
|
return;
|
|
10704
10750
|
}
|
|
10705
10751
|
const key = `${src.ref}\0${file}`;
|
|
10706
10752
|
if (!cache.has(key)) {
|
|
10707
|
-
const conv = readState2(opts.kbRoot, src.ref) ? convertedFile(opts.kbRoot, src.ref) : null;
|
|
10753
|
+
const conv = readState2(opts.kbRoot, canon(src.ref)) ? convertedFile(opts.kbRoot, canon(src.ref)) : null;
|
|
10708
10754
|
const cached = !!conv && fs16.existsSync(conv);
|
|
10709
10755
|
cache.set(key, {
|
|
10710
10756
|
hay: normalizedViews(fs16.readFileSync(cached ? conv : file, "utf8")),
|
|
@@ -10712,9 +10758,14 @@ function validateKb(opts) {
|
|
|
10712
10758
|
});
|
|
10713
10759
|
}
|
|
10714
10760
|
const { hay, convertible } = cache.get(key);
|
|
10715
|
-
|
|
10761
|
+
const span = findQuote(hay, src.quote);
|
|
10762
|
+
if (span) {
|
|
10716
10763
|
verified++;
|
|
10717
|
-
|
|
10764
|
+
const active = r.status === "active" && !path17.relative(opts.rulesDir, r.file).split(path17.sep).includes(PROPOSED_DIR);
|
|
10765
|
+
const err = active ? (opts.errata ?? []).find((e) => canon(e.ref) === canon(src.ref) && ((o) => !!o && spansOverlap(o, span))(findQuote(hay, e.quote))) : void 0;
|
|
10766
|
+
if (err)
|
|
10767
|
+
checks.push({ level: "warn", message: `${r.id}: grounded in erratum ${err.id} (${err.reason}); re-check or retire it (${r.file})` });
|
|
10768
|
+
} else if (convertible)
|
|
10718
10769
|
notIngested++;
|
|
10719
10770
|
else
|
|
10720
10771
|
checks.push({ level: "fail", message: `quote not found in ${file}: ${r.id} sources[${i}] (${r.file})` });
|
|
@@ -10734,7 +10785,7 @@ function validateKb(opts) {
|
|
|
10734
10785
|
}
|
|
10735
10786
|
return { checks, ok: !checks.some((c) => c.level === "fail") };
|
|
10736
10787
|
}
|
|
10737
|
-
var NO_JS_FRONTMATTER
|
|
10788
|
+
var NO_JS_FRONTMATTER;
|
|
10738
10789
|
var init_store2 = __esm({
|
|
10739
10790
|
"packages/core/dist/knowledge/store.js"() {
|
|
10740
10791
|
init_dist();
|
|
@@ -10746,7 +10797,6 @@ var init_store2 = __esm({
|
|
|
10746
10797
|
throw new Error("only YAML front matter is allowed");
|
|
10747
10798
|
} } }
|
|
10748
10799
|
};
|
|
10749
|
-
expandHome2 = (p) => p === "~" || p.startsWith("~/") ? path17.join(os8.homedir(), p.slice(1)) : p;
|
|
10750
10800
|
}
|
|
10751
10801
|
});
|
|
10752
10802
|
|
|
@@ -13919,6 +13969,7 @@ var init_js_yaml = __esm({
|
|
|
13919
13969
|
// packages/core/dist/knowledge/sources.js
|
|
13920
13970
|
import fs19 from "fs";
|
|
13921
13971
|
import path19 from "path";
|
|
13972
|
+
import matter3 from "gray-matter";
|
|
13922
13973
|
function loadSources(kbRoot) {
|
|
13923
13974
|
const file = path19.join(kbRoot, "sources.yaml");
|
|
13924
13975
|
if (!fs19.existsSync(file))
|
|
@@ -13944,20 +13995,77 @@ function loadSources(kbRoot) {
|
|
|
13944
13995
|
});
|
|
13945
13996
|
return { sources, errors };
|
|
13946
13997
|
}
|
|
13998
|
+
function dropEntryBlock(text, entryPath) {
|
|
13999
|
+
const lines = text.split("\n");
|
|
14000
|
+
const q = entryPath.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
14001
|
+
const head = new RegExp(`^-\\s+path:\\s*(['"]?)${q}\\1\\s*(#.*)?$`);
|
|
14002
|
+
const i = lines.findIndex((l) => head.test(l));
|
|
14003
|
+
if (i < 0)
|
|
14004
|
+
return null;
|
|
14005
|
+
let j = i + 1;
|
|
14006
|
+
while (j < lines.length && /^\s+\S/.test(lines[j]))
|
|
14007
|
+
j++;
|
|
14008
|
+
return [...lines.slice(0, i), ...lines.slice(j)].join("\n");
|
|
14009
|
+
}
|
|
14010
|
+
function removeSource(kbRoot, rulesDir, entryPath, opts = {}) {
|
|
14011
|
+
const file = path19.join(kbRoot, "sources.yaml");
|
|
14012
|
+
const { sources } = loadSources(kbRoot);
|
|
14013
|
+
const entry = sources.find((s) => s.path === entryPath);
|
|
14014
|
+
if (!entry)
|
|
14015
|
+
throw new Error(`no sources.yaml entry with path '${entryPath}' (give it exactly as listed by \`knowledge sources\`)`);
|
|
14016
|
+
const edited = dropEntryBlock(fs19.readFileSync(file, "utf8"), entryPath);
|
|
14017
|
+
if (edited === null)
|
|
14018
|
+
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`);
|
|
14019
|
+
const res = { dryRun: !!opts.dryRun, entryRemoved: true, stripped: [], stale: [] };
|
|
14020
|
+
const writes = [];
|
|
14021
|
+
for (const rule2 of loadRulesDir(rulesDir, "kb").rules) {
|
|
14022
|
+
const kept = rule2.sources.filter((s) => !sourceCovers(kbRoot, sources, entry, s.ref));
|
|
14023
|
+
if (kept.length === rule2.sources.length)
|
|
14024
|
+
continue;
|
|
14025
|
+
res.stripped.push(rule2.id);
|
|
14026
|
+
const parsed = matter3(fs19.readFileSync(rule2.file, "utf8"), { engines: { javascript: () => {
|
|
14027
|
+
throw new Error("only YAML front matter is allowed");
|
|
14028
|
+
} } });
|
|
14029
|
+
const fm = { ...parsed.data, sources: kept };
|
|
14030
|
+
if (!kept.length) {
|
|
14031
|
+
res.stale.push(rule2.id);
|
|
14032
|
+
if (fm.status === "active")
|
|
14033
|
+
fm.status = "stale";
|
|
14034
|
+
}
|
|
14035
|
+
writes.push({ file: rule2.file, text: matter3.stringify(parsed.content, JSON.parse(JSON.stringify(fm))) });
|
|
14036
|
+
}
|
|
14037
|
+
res.stripped.sort();
|
|
14038
|
+
res.stale.sort();
|
|
14039
|
+
if (opts.dryRun)
|
|
14040
|
+
return res;
|
|
14041
|
+
for (const w of writes)
|
|
14042
|
+
fs19.writeFileSync(w.file, w.text);
|
|
14043
|
+
fs19.writeFileSync(file, edited);
|
|
14044
|
+
const name = opts.kbName ?? path19.basename(kbRoot);
|
|
14045
|
+
writeIndex(kbRoot, compileIndex(name, loadRulesDir(rulesDir, `kb:${name}`).rules));
|
|
14046
|
+
return res;
|
|
14047
|
+
}
|
|
13947
14048
|
var SOURCES_TEMPLATE;
|
|
13948
14049
|
var init_sources = __esm({
|
|
13949
14050
|
"packages/core/dist/knowledge/sources.js"() {
|
|
13950
14051
|
init_js_yaml();
|
|
13951
14052
|
init_dist();
|
|
14053
|
+
init_index_file();
|
|
14054
|
+
init_ingest();
|
|
14055
|
+
init_store2();
|
|
13952
14056
|
SOURCES_TEMPLATE = `# Trusted sources for this knowledge base (spec \xA73). Only these can produce rules.
|
|
13953
14057
|
# priority: company > project > agent (decides conflicts).
|
|
13954
14058
|
# sensitivity: local-only \u2192 never sent to a hosted model (D12).
|
|
14059
|
+
# review: required \u2192 new rules from this source wait in rules/_proposed/ for the operator; they never go live on their own.
|
|
13955
14060
|
#
|
|
13956
14061
|
# - path: raw/finance/**
|
|
13957
14062
|
# priority: company
|
|
13958
14063
|
# - path: ~/work/flooros/docs/handbook/**
|
|
13959
14064
|
# priority: project
|
|
13960
14065
|
# domain: coding
|
|
14066
|
+
# - path: raw/**
|
|
14067
|
+
# priority: agent
|
|
14068
|
+
# review: required
|
|
13961
14069
|
[]
|
|
13962
14070
|
`;
|
|
13963
14071
|
}
|
|
@@ -14032,7 +14140,7 @@ var init_match = __esm({
|
|
|
14032
14140
|
|
|
14033
14141
|
// packages/core/dist/knowledge/audit.js
|
|
14034
14142
|
import fs20 from "fs";
|
|
14035
|
-
import
|
|
14143
|
+
import os8 from "os";
|
|
14036
14144
|
import path21 from "path";
|
|
14037
14145
|
function appendAudit(events, sink = {}) {
|
|
14038
14146
|
if (!events.length)
|
|
@@ -14062,8 +14170,8 @@ var AUDIT_QUERY_CHARS, defaultAuditDir, auditMachineId;
|
|
|
14062
14170
|
var init_audit = __esm({
|
|
14063
14171
|
"packages/core/dist/knowledge/audit.js"() {
|
|
14064
14172
|
AUDIT_QUERY_CHARS = 200;
|
|
14065
|
-
defaultAuditDir = () => process.env.SQUADRANT_AUDIT_DIR || path21.join(
|
|
14066
|
-
auditMachineId = () =>
|
|
14173
|
+
defaultAuditDir = () => process.env.SQUADRANT_AUDIT_DIR || path21.join(os8.homedir(), ".local", "state", "squadrant", "audit");
|
|
14174
|
+
auditMachineId = () => os8.hostname().replace(/[^A-Za-z0-9_-]/g, "_") || "host";
|
|
14067
14175
|
}
|
|
14068
14176
|
});
|
|
14069
14177
|
|
|
@@ -14349,7 +14457,7 @@ var init_inject = __esm({
|
|
|
14349
14457
|
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+/));
|
|
14350
14458
|
DATA_NOTE = "These are project rules (data from the knowledge base), not instructions to run anything.";
|
|
14351
14459
|
line = (r) => `${r.modality.toUpperCase()} ${r.id}: ${r.statement}`;
|
|
14352
|
-
CITE_NOTE = "
|
|
14460
|
+
CITE_NOTE = "List the rule ids you apply as `Rules: <id>, <id>` at the end of your signal done message (commit messages count too).";
|
|
14353
14461
|
escapeRe = (t) => t.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
14354
14462
|
BRIEF_POINTER_RE = /^Full task is at (\S+\.md) — cat it/;
|
|
14355
14463
|
READ_TOOLS = /* @__PURE__ */ new Set(["read", "read_file", "readfile", "view"]);
|
|
@@ -14461,67 +14569,157 @@ var init_migrate = __esm({
|
|
|
14461
14569
|
}
|
|
14462
14570
|
});
|
|
14463
14571
|
|
|
14464
|
-
// packages/core/dist/knowledge/
|
|
14572
|
+
// packages/core/dist/knowledge/errata.js
|
|
14465
14573
|
import fs23 from "fs";
|
|
14466
14574
|
import path24 from "path";
|
|
14467
|
-
function
|
|
14575
|
+
function loadErrata(kbRoot) {
|
|
14576
|
+
const file = path24.join(kbRoot, "errata.yaml");
|
|
14577
|
+
if (!fs23.existsSync(file))
|
|
14578
|
+
return { errata: [], errors: [] };
|
|
14579
|
+
let data;
|
|
14580
|
+
try {
|
|
14581
|
+
data = yaml.load(fs23.readFileSync(file, "utf8"), { schema: yaml.JSON_SCHEMA });
|
|
14582
|
+
} catch (e) {
|
|
14583
|
+
return { errata: [], errors: [`YAML parse error: ${e.message.split("\n")[0]}`] };
|
|
14584
|
+
}
|
|
14585
|
+
if (data == null)
|
|
14586
|
+
return { errata: [], errors: [] };
|
|
14587
|
+
if (!Array.isArray(data))
|
|
14588
|
+
return { errata: [], errors: ["errata.yaml must be a YAML list of entries"] };
|
|
14589
|
+
const errata = [];
|
|
14590
|
+
const errors = [];
|
|
14591
|
+
data.forEach((entry, i) => {
|
|
14592
|
+
const problems = validateErratum(entry);
|
|
14593
|
+
if (problems.length)
|
|
14594
|
+
errors.push(...problems.map((p) => `entry ${i}: ${p}`));
|
|
14595
|
+
else
|
|
14596
|
+
errata.push(entry);
|
|
14597
|
+
});
|
|
14598
|
+
return { errata, errors };
|
|
14599
|
+
}
|
|
14600
|
+
function orphanedErrata(kbRoot, sources, errata, refs) {
|
|
14601
|
+
const canon = refCanon(kbRoot, sources);
|
|
14602
|
+
const only = refs ? new Set([...refs].map(canon)) : void 0;
|
|
14603
|
+
const hays = /* @__PURE__ */ new Map();
|
|
14604
|
+
const out = [];
|
|
14605
|
+
for (const e of errata) {
|
|
14606
|
+
const ref = canon(e.ref);
|
|
14607
|
+
if (only && !only.has(ref))
|
|
14608
|
+
continue;
|
|
14609
|
+
if (!hays.has(ref)) {
|
|
14610
|
+
const conv = readState2(kbRoot, ref) ? convertedFile(kbRoot, ref) : null;
|
|
14611
|
+
hays.set(ref, conv && fs23.existsSync(conv) ? normalizedViews(fs23.readFileSync(conv, "utf8")) : null);
|
|
14612
|
+
}
|
|
14613
|
+
const hay = hays.get(ref);
|
|
14614
|
+
if (hay && !findQuote(hay, e.quote))
|
|
14615
|
+
out.push({ id: e.id, ref: e.ref });
|
|
14616
|
+
}
|
|
14617
|
+
return out;
|
|
14618
|
+
}
|
|
14619
|
+
var init_errata = __esm({
|
|
14620
|
+
"packages/core/dist/knowledge/errata.js"() {
|
|
14621
|
+
init_js_yaml();
|
|
14622
|
+
init_dist();
|
|
14623
|
+
init_ingest();
|
|
14624
|
+
init_verify();
|
|
14625
|
+
}
|
|
14626
|
+
});
|
|
14627
|
+
|
|
14628
|
+
// packages/core/dist/knowledge/anchor.js
|
|
14629
|
+
import fs24 from "fs";
|
|
14630
|
+
import { execFileSync as execFileSync7 } from "child_process";
|
|
14631
|
+
import path25 from "path";
|
|
14632
|
+
function gitFiles(root) {
|
|
14633
|
+
try {
|
|
14634
|
+
const out = execFileSync7("git", ["ls-files", "-co", "--exclude-standard", "-z"], { cwd: root, encoding: "utf8", stdio: ["ignore", "pipe", "ignore"], maxBuffer: 64 * 1024 * 1024 });
|
|
14635
|
+
return out.split("\0").filter(Boolean).sort();
|
|
14636
|
+
} catch {
|
|
14637
|
+
return null;
|
|
14638
|
+
}
|
|
14639
|
+
}
|
|
14640
|
+
function* repoFiles(root, maxFiles) {
|
|
14468
14641
|
let count = 0;
|
|
14642
|
+
const listed = gitFiles(root);
|
|
14643
|
+
if (listed) {
|
|
14644
|
+
for (const rel of listed) {
|
|
14645
|
+
if (!CODE_EXT.has(path25.extname(rel)) || rel.split("/").slice(0, -1).some((d) => SKIP_DIRS.has(d)))
|
|
14646
|
+
continue;
|
|
14647
|
+
if (++count > maxFiles) {
|
|
14648
|
+
console.warn(`anchor: ${root} has more than ${maxFiles} code files; anchors cover only the first ${maxFiles}`);
|
|
14649
|
+
return;
|
|
14650
|
+
}
|
|
14651
|
+
yield path25.join(root, rel);
|
|
14652
|
+
}
|
|
14653
|
+
return;
|
|
14654
|
+
}
|
|
14469
14655
|
const stack = [root];
|
|
14470
14656
|
while (stack.length) {
|
|
14471
14657
|
const dir = stack.pop();
|
|
14472
14658
|
let ents;
|
|
14473
14659
|
try {
|
|
14474
|
-
ents =
|
|
14660
|
+
ents = fs24.readdirSync(dir, { withFileTypes: true }).sort((a, b) => a.name < b.name ? 1 : -1);
|
|
14475
14661
|
} catch {
|
|
14476
14662
|
continue;
|
|
14477
14663
|
}
|
|
14478
14664
|
for (const ent of ents) {
|
|
14479
14665
|
if (ent.isDirectory()) {
|
|
14480
14666
|
if (!SKIP_DIRS.has(ent.name))
|
|
14481
|
-
stack.push(
|
|
14482
|
-
} else if (ent.isFile() && CODE_EXT.has(
|
|
14483
|
-
if (++count >
|
|
14667
|
+
stack.push(path25.join(dir, ent.name));
|
|
14668
|
+
} else if (ent.isFile() && CODE_EXT.has(path25.extname(ent.name))) {
|
|
14669
|
+
if (++count > maxFiles) {
|
|
14670
|
+
console.warn(`anchor: ${root} has more than ${maxFiles} code files; anchors cover only the first ${maxFiles}`);
|
|
14484
14671
|
return;
|
|
14485
|
-
|
|
14672
|
+
}
|
|
14673
|
+
yield path25.join(dir, ent.name);
|
|
14486
14674
|
}
|
|
14487
14675
|
}
|
|
14488
14676
|
}
|
|
14489
14677
|
}
|
|
14490
|
-
function
|
|
14491
|
-
const
|
|
14492
|
-
|
|
14493
|
-
return null;
|
|
14494
|
-
const hits = [];
|
|
14495
|
-
for (const file of repoFiles(repoRoot)) {
|
|
14496
|
-
let text;
|
|
14678
|
+
function scanRepo(root, maxFiles) {
|
|
14679
|
+
const out = [];
|
|
14680
|
+
for (const file of repoFiles(root, maxFiles)) {
|
|
14497
14681
|
try {
|
|
14498
|
-
if (
|
|
14682
|
+
if (fs24.statSync(file).size > MAX_FILE_BYTES)
|
|
14499
14683
|
continue;
|
|
14500
|
-
text =
|
|
14684
|
+
const text = fs24.readFileSync(file, "utf8");
|
|
14685
|
+
const rel = path25.relative(root, file).split(path25.sep).join("/");
|
|
14686
|
+
out.push({ rel, text, hay: `${path25.relative(root, file)}
|
|
14687
|
+
${text}`.toLowerCase() });
|
|
14501
14688
|
} catch {
|
|
14502
14689
|
continue;
|
|
14503
14690
|
}
|
|
14504
|
-
|
|
14505
|
-
|
|
14691
|
+
}
|
|
14692
|
+
return out;
|
|
14693
|
+
}
|
|
14694
|
+
function computeAnchor(repoRoot, triggers, cache, maxFiles = MAX_FILES) {
|
|
14695
|
+
const terms2 = anchorTerms(triggers);
|
|
14696
|
+
if (!terms2.length || !fs24.existsSync(repoRoot))
|
|
14697
|
+
return null;
|
|
14698
|
+
let files = cache?.get(repoRoot);
|
|
14699
|
+
if (!files) {
|
|
14700
|
+
files = scanRepo(repoRoot, maxFiles);
|
|
14701
|
+
cache?.set(repoRoot, files);
|
|
14702
|
+
}
|
|
14703
|
+
const hits = [];
|
|
14704
|
+
for (const { rel, text, hay } of files) {
|
|
14506
14705
|
const score = terms2.filter((t) => hay.includes(t)).length;
|
|
14507
14706
|
if (!score)
|
|
14508
14707
|
continue;
|
|
14509
|
-
|
|
14510
|
-
hits.push({ rel: path24.relative(repoRoot, file).split(path24.sep).join("/"), score, symbols: symbols2 });
|
|
14708
|
+
hits.push({ rel, score, text });
|
|
14511
14709
|
}
|
|
14512
14710
|
if (!hits.length)
|
|
14513
14711
|
return null;
|
|
14514
14712
|
hits.sort((a, b) => b.score - a.score || (a.rel < b.rel ? -1 : 1));
|
|
14515
14713
|
const top = hits.slice(0, MAX_PATHS);
|
|
14516
|
-
const symbols = [...new Set(top.flatMap((h) => h.
|
|
14714
|
+
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);
|
|
14517
14715
|
return { paths: top.map((h) => h.rel).sort(), ...symbols.length ? { symbols } : {} };
|
|
14518
14716
|
}
|
|
14519
14717
|
var SKIP_DIRS, CODE_EXT, MAX_FILES, MAX_FILE_BYTES, MAX_PATHS, MAX_SYMBOLS, SYMBOL_RE, anchorTerms;
|
|
14520
14718
|
var init_anchor = __esm({
|
|
14521
14719
|
"packages/core/dist/knowledge/anchor.js"() {
|
|
14522
|
-
SKIP_DIRS = /* @__PURE__ */ new Set([".git", "node_modules", "dist", "build", "coverage", ".next", ".worktrees", ".planning", ".converted"]);
|
|
14720
|
+
SKIP_DIRS = /* @__PURE__ */ new Set([".git", "node_modules", "dist", "build", "coverage", ".next", ".worktrees", ".planning", ".converted", ".venv", "venv", "__pycache__"]);
|
|
14523
14721
|
CODE_EXT = /* @__PURE__ */ new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".py", ".go", ".rs", ".java", ".kt", ".swift", ".rb", ".php", ".cs", ".sol", ".sql", ".md"]);
|
|
14524
|
-
MAX_FILES =
|
|
14722
|
+
MAX_FILES = 2e4;
|
|
14525
14723
|
MAX_FILE_BYTES = 256 * 1024;
|
|
14526
14724
|
MAX_PATHS = 5;
|
|
14527
14725
|
MAX_SYMBOLS = 10;
|
|
@@ -14531,11 +14729,11 @@ var init_anchor = __esm({
|
|
|
14531
14729
|
});
|
|
14532
14730
|
|
|
14533
14731
|
// packages/core/dist/knowledge/extract.js
|
|
14534
|
-
import
|
|
14535
|
-
import
|
|
14536
|
-
import
|
|
14732
|
+
import fs25 from "fs";
|
|
14733
|
+
import path26 from "path";
|
|
14734
|
+
import matter4 from "gray-matter";
|
|
14537
14735
|
function serialize(fm, body) {
|
|
14538
|
-
return
|
|
14736
|
+
return matter4.stringify(body.trim() + "\n", clean(fm));
|
|
14539
14737
|
}
|
|
14540
14738
|
function validateCandidate(c) {
|
|
14541
14739
|
const p = [];
|
|
@@ -14565,8 +14763,8 @@ function validateCandidate(c) {
|
|
|
14565
14763
|
}
|
|
14566
14764
|
return p;
|
|
14567
14765
|
}
|
|
14568
|
-
function upsertSource(fm, src) {
|
|
14569
|
-
const i = fm.sources.findIndex((s) => s.ref === src.ref);
|
|
14766
|
+
function upsertSource(fm, src, canon) {
|
|
14767
|
+
const i = fm.sources.findIndex((s) => canon(s.ref) === canon(src.ref));
|
|
14570
14768
|
if (i < 0) {
|
|
14571
14769
|
fm.sources.push(src);
|
|
14572
14770
|
return true;
|
|
@@ -14578,9 +14776,9 @@ function upsertSource(fm, src) {
|
|
|
14578
14776
|
}
|
|
14579
14777
|
function applyCandidates(input, opts) {
|
|
14580
14778
|
const { kb, kbRoot, rulesDir } = opts;
|
|
14581
|
-
const res = { created: [], merged: [], proposed: [], superseded: [], stale: [], rejected: [], doclingFlags: [], idOverrides: [] };
|
|
14779
|
+
const res = { created: [], merged: [], proposed: [], superseded: [], stale: [], rejected: [], doclingFlags: [], idOverrides: [], orphanedErrata: [] };
|
|
14582
14780
|
const events = [];
|
|
14583
|
-
const ev2 = (event, itemId,
|
|
14781
|
+
const ev2 = (event, itemId, extra = {}) => events.push({ kb, level: "group", project: "", domain: "rules", itemId, event, ...extra });
|
|
14584
14782
|
const loaded = loadRulesDir(rulesDir, `kb:${kb}`);
|
|
14585
14783
|
const work = /* @__PURE__ */ new Map();
|
|
14586
14784
|
for (const r of loaded.rules) {
|
|
@@ -14590,7 +14788,8 @@ function applyCandidates(input, opts) {
|
|
|
14590
14788
|
const norm = /* @__PURE__ */ new Map();
|
|
14591
14789
|
const totals = /* @__PURE__ */ new Map();
|
|
14592
14790
|
const touched = /* @__PURE__ */ new Set();
|
|
14593
|
-
const
|
|
14791
|
+
const canon = refCanon(kbRoot, opts.sources ?? []);
|
|
14792
|
+
const complete = new Set((input.complete ?? []).map(canon));
|
|
14594
14793
|
for (const cand of input.candidates) {
|
|
14595
14794
|
const problems = validateCandidate(cand);
|
|
14596
14795
|
if (problems.length) {
|
|
@@ -14599,13 +14798,13 @@ function applyCandidates(input, opts) {
|
|
|
14599
14798
|
}
|
|
14600
14799
|
const st = readState2(kbRoot, cand.source);
|
|
14601
14800
|
const convFile = st ? convertedFile(kbRoot, cand.source) : null;
|
|
14602
|
-
if (!st || !
|
|
14801
|
+
if (!st || !fs25.existsSync(convFile)) {
|
|
14603
14802
|
res.rejected.push({ id: cand.id, source: cand.source, reason: "unknown source (not ingested)" });
|
|
14604
14803
|
continue;
|
|
14605
14804
|
}
|
|
14606
14805
|
let hay = norm.get(cand.source);
|
|
14607
14806
|
if (!hay) {
|
|
14608
|
-
hay = normalizedViews(
|
|
14807
|
+
hay = normalizedViews(fs25.readFileSync(convFile, "utf8"));
|
|
14609
14808
|
norm.set(cand.source, hay);
|
|
14610
14809
|
}
|
|
14611
14810
|
const tot = totals.get(cand.source) ?? { total: 0, dropped: 0 };
|
|
@@ -14615,13 +14814,20 @@ function applyCandidates(input, opts) {
|
|
|
14615
14814
|
if (!offset) {
|
|
14616
14815
|
tot.dropped++;
|
|
14617
14816
|
res.rejected.push({ id: cand.id, source: cand.source, reason: "ungrounded" });
|
|
14618
|
-
ev2("item.rejected", cand.id,
|
|
14817
|
+
ev2("item.rejected", cand.id, { reason: "ungrounded" });
|
|
14818
|
+
continue;
|
|
14819
|
+
}
|
|
14820
|
+
const hit = (opts.errata ?? []).find((e) => canon(e.ref) === canon(cand.source) && ((o) => !!o && spansOverlap(o, offset))(findQuote(hay, e.quote)));
|
|
14821
|
+
if (hit) {
|
|
14822
|
+
tot.total--;
|
|
14823
|
+
res.rejected.push({ id: cand.id, source: cand.source, reason: `errata:${hit.id}` });
|
|
14824
|
+
ev2("item.rejected", cand.id, { reason: `errata:${hit.id}` });
|
|
14619
14825
|
continue;
|
|
14620
14826
|
}
|
|
14621
14827
|
let id = cand.id;
|
|
14622
14828
|
for (const [wid, w] of work) {
|
|
14623
14829
|
const span = (s) => s.sha === st.sha ? s.offset : findQuote(hay, s.quote) ?? s.offset;
|
|
14624
|
-
if (w.fm.sources.some((s) => s.ref === cand.source && s.offset && ((o) => !!o && spansOverlap(o, offset))(span(s)))) {
|
|
14830
|
+
if (w.fm.sources.some((s) => canon(s.ref) === canon(cand.source) && s.offset && ((o) => !!o && spansOverlap(o, offset))(span(s)))) {
|
|
14625
14831
|
id = wid;
|
|
14626
14832
|
break;
|
|
14627
14833
|
}
|
|
@@ -14636,7 +14842,7 @@ function applyCandidates(input, opts) {
|
|
|
14636
14842
|
|
|
14637
14843
|
${cand.rationale.trim()}` : "");
|
|
14638
14844
|
if (target && contradicted.length === 0 && sameMeaning(target, cand)) {
|
|
14639
|
-
let changed = upsertSource(target.fm, src);
|
|
14845
|
+
let changed = upsertSource(target.fm, src, canon);
|
|
14640
14846
|
if (target.fm.status === "stale") {
|
|
14641
14847
|
target.fm.status = "active";
|
|
14642
14848
|
changed = true;
|
|
@@ -14647,7 +14853,7 @@ ${cand.rationale.trim()}` : "");
|
|
|
14647
14853
|
}
|
|
14648
14854
|
continue;
|
|
14649
14855
|
}
|
|
14650
|
-
if (!target && contradicted.length === 0) {
|
|
14856
|
+
if (!target && contradicted.length === 0 && !isGatedRef(kbRoot, opts.sources ?? [], cand.source)) {
|
|
14651
14857
|
const fm2 = {
|
|
14652
14858
|
id,
|
|
14653
14859
|
domain: cand.domain,
|
|
@@ -14660,9 +14866,9 @@ ${cand.rationale.trim()}` : "");
|
|
|
14660
14866
|
supersedes: [],
|
|
14661
14867
|
conflictsWith: []
|
|
14662
14868
|
};
|
|
14663
|
-
work.set(id, { fm: fm2, body: bodyOf(), file:
|
|
14869
|
+
work.set(id, { fm: fm2, body: bodyOf(), file: path26.join(rulesDir, cand.domain, `${id}.md`), dirty: true, isNew: true });
|
|
14664
14870
|
res.created.push(id);
|
|
14665
|
-
ev2("item.applied", id
|
|
14871
|
+
ev2("item.applied", id);
|
|
14666
14872
|
continue;
|
|
14667
14873
|
}
|
|
14668
14874
|
const fm = {
|
|
@@ -14677,42 +14883,43 @@ ${cand.rationale.trim()}` : "");
|
|
|
14677
14883
|
supersedes: [],
|
|
14678
14884
|
conflictsWith: contradicted
|
|
14679
14885
|
};
|
|
14680
|
-
const dir =
|
|
14681
|
-
const file =
|
|
14886
|
+
const dir = path26.join(rulesDir, PROPOSED_DIR);
|
|
14887
|
+
const file = path26.join(dir, `${id}@${st.sha.slice(0, SHA_LEN)}.md`);
|
|
14682
14888
|
const text = serialize(fm, bodyOf());
|
|
14683
|
-
if (
|
|
14889
|
+
if (fs25.existsSync(file) && fs25.readFileSync(file, "utf8") === text)
|
|
14684
14890
|
continue;
|
|
14685
|
-
|
|
14686
|
-
for (const other of
|
|
14687
|
-
if (!other.startsWith(`${id}@`) || !other.endsWith(".md") ||
|
|
14891
|
+
fs25.mkdirSync(dir, { recursive: true });
|
|
14892
|
+
for (const other of fs25.readdirSync(dir)) {
|
|
14893
|
+
if (!other.startsWith(`${id}@`) || !other.endsWith(".md") || path26.join(dir, other) === file)
|
|
14688
14894
|
continue;
|
|
14689
|
-
const old =
|
|
14690
|
-
if (!old.data.sources?.some((s) => s.ref === cand.source))
|
|
14895
|
+
const old = matter4(fs25.readFileSync(path26.join(dir, other), "utf8"));
|
|
14896
|
+
if (!old.data.sources?.some((s) => canon(s.ref) === canon(cand.source)))
|
|
14691
14897
|
continue;
|
|
14692
|
-
|
|
14693
|
-
|
|
14898
|
+
fs25.writeFileSync(path26.join(dir, other.replace(/\.md$/, ".superseded")), matter4.stringify(old.content, { ...old.data, supersededBy: path26.basename(file) }));
|
|
14899
|
+
fs25.rmSync(path26.join(dir, other));
|
|
14694
14900
|
res.superseded.push(other.replace(/\.md$/, ""));
|
|
14695
|
-
ev2("item.superseded", id
|
|
14901
|
+
ev2("item.superseded", id);
|
|
14696
14902
|
}
|
|
14697
|
-
|
|
14903
|
+
fs25.writeFileSync(file, text);
|
|
14698
14904
|
res.proposed.push(`${id}@${st.sha.slice(0, SHA_LEN)}`);
|
|
14699
|
-
ev2("item.proposed", id
|
|
14905
|
+
ev2("item.proposed", id);
|
|
14700
14906
|
}
|
|
14701
14907
|
for (const [id, w] of work) {
|
|
14702
14908
|
if (touched.has(id) || w.fm.status !== "active" || w.isNew)
|
|
14703
14909
|
continue;
|
|
14704
|
-
if (w.fm.sources.length && w.fm.sources.every((s) => complete.has(s.ref))) {
|
|
14910
|
+
if (w.fm.sources.length && w.fm.sources.every((s) => complete.has(canon(s.ref)))) {
|
|
14705
14911
|
w.fm.status = "stale";
|
|
14706
14912
|
w.dirty = true;
|
|
14707
14913
|
res.stale.push(id);
|
|
14708
14914
|
}
|
|
14709
14915
|
}
|
|
14916
|
+
const anchorCache = /* @__PURE__ */ new Map();
|
|
14710
14917
|
for (const w of work.values()) {
|
|
14711
14918
|
if (!w.dirty || !opts.projects?.length)
|
|
14712
14919
|
continue;
|
|
14713
14920
|
const anchors = { ...w.fm.anchors ?? {} };
|
|
14714
14921
|
for (const p of opts.projects) {
|
|
14715
|
-
const a = computeAnchor(p.root, w.fm.triggers);
|
|
14922
|
+
const a = computeAnchor(p.root, w.fm.triggers, anchorCache);
|
|
14716
14923
|
if (a)
|
|
14717
14924
|
anchors[p.name] = a;
|
|
14718
14925
|
}
|
|
@@ -14722,11 +14929,12 @@ ${cand.rationale.trim()}` : "");
|
|
|
14722
14929
|
for (const w of work.values()) {
|
|
14723
14930
|
if (!w.dirty)
|
|
14724
14931
|
continue;
|
|
14725
|
-
|
|
14932
|
+
fs25.mkdirSync(path26.dirname(w.file), { recursive: true });
|
|
14726
14933
|
const text = serialize(w.fm, w.body);
|
|
14727
|
-
if (!
|
|
14728
|
-
|
|
14934
|
+
if (!fs25.existsSync(w.file) || fs25.readFileSync(w.file, "utf8") !== text)
|
|
14935
|
+
fs25.writeFileSync(w.file, text);
|
|
14729
14936
|
}
|
|
14937
|
+
res.orphanedErrata = orphanedErrata(kbRoot, opts.sources ?? [], opts.errata ?? [], totals.keys());
|
|
14730
14938
|
for (const [ref, t] of totals)
|
|
14731
14939
|
if (needsDocling(t.dropped, t.total))
|
|
14732
14940
|
res.doclingFlags.push({ ref, ...t });
|
|
@@ -14743,6 +14951,7 @@ var init_extract = __esm({
|
|
|
14743
14951
|
init_anchor();
|
|
14744
14952
|
init_index_file();
|
|
14745
14953
|
init_ingest();
|
|
14954
|
+
init_errata();
|
|
14746
14955
|
init_paths();
|
|
14747
14956
|
init_store2();
|
|
14748
14957
|
init_verify();
|
|
@@ -14759,20 +14968,20 @@ var init_extract = __esm({
|
|
|
14759
14968
|
});
|
|
14760
14969
|
|
|
14761
14970
|
// packages/core/dist/knowledge/schedule.js
|
|
14762
|
-
import
|
|
14763
|
-
import
|
|
14971
|
+
import fs26 from "fs";
|
|
14972
|
+
import path27 from "path";
|
|
14764
14973
|
function readSchedule(stateRoot) {
|
|
14765
14974
|
try {
|
|
14766
|
-
return JSON.parse(
|
|
14975
|
+
return JSON.parse(fs26.readFileSync(scheduleFile(stateRoot), "utf8"));
|
|
14767
14976
|
} catch {
|
|
14768
14977
|
return {};
|
|
14769
14978
|
}
|
|
14770
14979
|
}
|
|
14771
14980
|
function writeSchedule(stateRoot, s) {
|
|
14772
|
-
|
|
14981
|
+
fs26.mkdirSync(stateRoot, { recursive: true });
|
|
14773
14982
|
const tmp = `${scheduleFile(stateRoot)}.${process.pid}.tmp`;
|
|
14774
|
-
|
|
14775
|
-
|
|
14983
|
+
fs26.writeFileSync(tmp, JSON.stringify(s, null, 2) + "\n");
|
|
14984
|
+
fs26.renameSync(tmp, scheduleFile(stateRoot));
|
|
14776
14985
|
}
|
|
14777
14986
|
function snapshotSources(kbRoot, sources) {
|
|
14778
14987
|
const out = {};
|
|
@@ -14852,7 +15061,7 @@ async function tickKnowledgeSchedule(d) {
|
|
|
14852
15061
|
continue;
|
|
14853
15062
|
try {
|
|
14854
15063
|
const root = kbDir(d.cfg, kb);
|
|
14855
|
-
if (!
|
|
15064
|
+
if (!fs26.existsSync(root))
|
|
14856
15065
|
continue;
|
|
14857
15066
|
const { sources } = loadSources(root);
|
|
14858
15067
|
if (!sources.length)
|
|
@@ -14917,27 +15126,27 @@ var init_schedule = __esm({
|
|
|
14917
15126
|
init_sources();
|
|
14918
15127
|
RUNNING_STALE_MS = 6 * 60 * 60 * 1e3;
|
|
14919
15128
|
DAY_MS = 24 * 60 * 60 * 1e3;
|
|
14920
|
-
scheduleFile = (stateRoot) =>
|
|
15129
|
+
scheduleFile = (stateRoot) => path27.join(stateRoot, "knowledge-schedule.json");
|
|
14921
15130
|
reconcileConfig = (cfg, kb) => ({ ...DEFAULT_RECONCILE, ...kbConfigs(cfg)[kb]?.reconcile });
|
|
14922
15131
|
}
|
|
14923
15132
|
});
|
|
14924
15133
|
|
|
14925
15134
|
// packages/core/dist/knowledge/review.js
|
|
14926
15135
|
import crypto4 from "crypto";
|
|
14927
|
-
import { execFileSync as
|
|
14928
|
-
import
|
|
14929
|
-
import
|
|
14930
|
-
import
|
|
15136
|
+
import { execFileSync as execFileSync8 } from "child_process";
|
|
15137
|
+
import fs27 from "fs";
|
|
15138
|
+
import path28 from "path";
|
|
15139
|
+
import matter5 from "gray-matter";
|
|
14931
15140
|
function readEscalations(kbRoot) {
|
|
14932
15141
|
try {
|
|
14933
|
-
return JSON.parse(
|
|
15142
|
+
return JSON.parse(fs27.readFileSync(escalationsFile(kbRoot), "utf8")).items;
|
|
14934
15143
|
} catch {
|
|
14935
15144
|
return [];
|
|
14936
15145
|
}
|
|
14937
15146
|
}
|
|
14938
15147
|
function writeEscalations(kbRoot, items) {
|
|
14939
|
-
|
|
14940
|
-
|
|
15148
|
+
fs27.mkdirSync(kbRoot, { recursive: true });
|
|
15149
|
+
fs27.writeFileSync(escalationsFile(kbRoot), JSON.stringify({ items }, null, 2) + "\n");
|
|
14941
15150
|
}
|
|
14942
15151
|
function addEscalation(kbRoot, e) {
|
|
14943
15152
|
const items = readEscalations(kbRoot);
|
|
@@ -14947,18 +15156,14 @@ function addEscalation(kbRoot, e) {
|
|
|
14947
15156
|
return true;
|
|
14948
15157
|
}
|
|
14949
15158
|
function appendVerdict(kbRoot, v2, now) {
|
|
14950
|
-
|
|
14951
|
-
|
|
15159
|
+
fs27.mkdirSync(kbRoot, { recursive: true });
|
|
15160
|
+
fs27.appendFileSync(verdictsFile(kbRoot), JSON.stringify({ ts: now.toISOString(), ...v2 }) + "\n");
|
|
14952
15161
|
}
|
|
14953
15162
|
function priorityOfRef(c, ref) {
|
|
14954
15163
|
if (ref.startsWith("agent:"))
|
|
14955
15164
|
return "agent";
|
|
14956
15165
|
const root = kbDir(c.cfg, c.kb);
|
|
14957
|
-
|
|
14958
|
-
for (const f of expandSource(root, e))
|
|
14959
|
-
if (refFor(root, f) === ref)
|
|
14960
|
-
return e.priority;
|
|
14961
|
-
return "project";
|
|
15166
|
+
return c.sources.find((e) => sourceCovers(root, c.sources, e, ref))?.priority ?? "project";
|
|
14962
15167
|
}
|
|
14963
15168
|
function priorityOfRule(c, r) {
|
|
14964
15169
|
return r.sources.map((s) => priorityOfRef(c, s.ref)).sort((a, b) => PRIORITY_RANK[b] - PRIORITY_RANK[a])[0] ?? "project";
|
|
@@ -14969,20 +15174,20 @@ function loadProposals(c) {
|
|
|
14969
15174
|
const byId = new Map(live.map((r) => [r.id, r]));
|
|
14970
15175
|
const proposals = [];
|
|
14971
15176
|
const pdirs = /* @__PURE__ */ new Set();
|
|
14972
|
-
for (const f of
|
|
14973
|
-
if (
|
|
15177
|
+
for (const f of fs27.existsSync(dir) ? walkDirs(dir) : [])
|
|
15178
|
+
if (path28.basename(f) === PROPOSED_DIR)
|
|
14974
15179
|
pdirs.add(f);
|
|
14975
15180
|
for (const pd of pdirs) {
|
|
14976
15181
|
for (const rule2 of loadRulesDir(pd, `kb:${c.kb}`, { includeProposed: true }).rules) {
|
|
14977
|
-
proposals.push({ key:
|
|
15182
|
+
proposals.push({ key: path28.basename(rule2.file).replace(/\.md$/, ""), rule: rule2, live: byId.get(rule2.id) });
|
|
14978
15183
|
}
|
|
14979
15184
|
}
|
|
14980
15185
|
return { proposals, live };
|
|
14981
15186
|
}
|
|
14982
15187
|
function walkDirs(dir, out = []) {
|
|
14983
|
-
for (const e of
|
|
15188
|
+
for (const e of fs27.readdirSync(dir, { withFileTypes: true }))
|
|
14984
15189
|
if (e.isDirectory()) {
|
|
14985
|
-
const f =
|
|
15190
|
+
const f = path28.join(dir, e.name);
|
|
14986
15191
|
out.push(f);
|
|
14987
15192
|
walkDirs(f, out);
|
|
14988
15193
|
}
|
|
@@ -14995,7 +15200,7 @@ function reindex(c) {
|
|
|
14995
15200
|
function anchorsFor(c, fm) {
|
|
14996
15201
|
const anchors = { ...fm.anchors ?? {} };
|
|
14997
15202
|
for (const p of c.projects ?? []) {
|
|
14998
|
-
const a = computeAnchor(p.root, fm.triggers);
|
|
15203
|
+
const a = computeAnchor(p.root, fm.triggers, c.anchorCache);
|
|
14999
15204
|
if (a)
|
|
15000
15205
|
anchors[p.name] = a;
|
|
15001
15206
|
}
|
|
@@ -15011,9 +15216,9 @@ function promoteProposal(c, p, by, justification, events) {
|
|
|
15011
15216
|
continue;
|
|
15012
15217
|
const o = readFm(other.file);
|
|
15013
15218
|
o.fm.status = "retired";
|
|
15014
|
-
|
|
15219
|
+
fs27.writeFileSync(other.file, fileText(o.fm, o.body));
|
|
15015
15220
|
retired.push(id);
|
|
15016
|
-
events.push(ev(c, "item.superseded", id
|
|
15221
|
+
events.push(ev(c, "item.superseded", id));
|
|
15017
15222
|
}
|
|
15018
15223
|
const next = { ...fm, status: "active", approvedBy: by, justification, supersedes: [.../* @__PURE__ */ new Set([...fm.supersedes ?? [], ...retired])], conflictsWith: [] };
|
|
15019
15224
|
if (p.live?.decision)
|
|
@@ -15021,29 +15226,30 @@ function promoteProposal(c, p, by, justification, events) {
|
|
|
15021
15226
|
const anchors = anchorsFor(c, { ...next, anchors: p.live?.anchors ?? fm.anchors });
|
|
15022
15227
|
if (anchors)
|
|
15023
15228
|
next.anchors = anchors;
|
|
15024
|
-
const target = p.live?.file ??
|
|
15025
|
-
|
|
15026
|
-
|
|
15027
|
-
|
|
15028
|
-
events.push(ev(c, "item.approved", next.id
|
|
15229
|
+
const target = p.live?.file ?? path28.join(dir, next.domain, `${next.id}.md`);
|
|
15230
|
+
fs27.mkdirSync(path28.dirname(target), { recursive: true });
|
|
15231
|
+
fs27.writeFileSync(target, fileText(next, body));
|
|
15232
|
+
fs27.rmSync(p.rule.file);
|
|
15233
|
+
events.push(ev(c, "item.approved", next.id), ev(c, "item.applied", next.id));
|
|
15029
15234
|
if (p.live)
|
|
15030
|
-
events.push(ev(c, "item.superseded", next.id
|
|
15235
|
+
events.push(ev(c, "item.superseded", next.id));
|
|
15031
15236
|
}
|
|
15032
15237
|
function dropProposal(c, p, events) {
|
|
15033
|
-
|
|
15034
|
-
events.push(ev(c, "item.rejected", p.rule.id,
|
|
15238
|
+
fs27.rmSync(p.rule.file);
|
|
15239
|
+
events.push(ev(c, "item.rejected", p.rule.id, { reason: "reviewer" }));
|
|
15035
15240
|
}
|
|
15036
15241
|
function mergeInto(c, p, targetId, live, events) {
|
|
15037
15242
|
const t = live.find((r) => r.id === targetId);
|
|
15038
15243
|
if (!t)
|
|
15039
15244
|
return false;
|
|
15040
15245
|
const tf = readFm(t.file);
|
|
15246
|
+
const canon = refCanon(kbDir(c.cfg, c.kb), c.sources);
|
|
15041
15247
|
for (const s of p.rule.sources)
|
|
15042
|
-
if (!tf.fm.sources.some((x) => x.ref === s.ref))
|
|
15248
|
+
if (!tf.fm.sources.some((x) => canon(x.ref) === canon(s.ref)))
|
|
15043
15249
|
tf.fm.sources.push(s);
|
|
15044
|
-
|
|
15045
|
-
|
|
15046
|
-
events.push(ev(c, "item.superseded", p.rule.id
|
|
15250
|
+
fs27.writeFileSync(t.file, fileText(tf.fm, tf.body));
|
|
15251
|
+
fs27.rmSync(p.rule.file);
|
|
15252
|
+
events.push(ev(c, "item.superseded", p.rule.id), ev(c, "item.applied", targetId));
|
|
15047
15253
|
return true;
|
|
15048
15254
|
}
|
|
15049
15255
|
function evaluateCodeConflict(c, rule2, cc) {
|
|
@@ -15052,7 +15258,7 @@ function evaluateCodeConflict(c, rule2, cc) {
|
|
|
15052
15258
|
const root = proj?.root;
|
|
15053
15259
|
const code = root ? g.lastCommit(root, cc.files) : null;
|
|
15054
15260
|
const kbRoot = kbDir(c.cfg, c.kb);
|
|
15055
|
-
const docDates = rule2.sources.map((s) => g.docDate(
|
|
15261
|
+
const docDates = rule2.sources.map((s) => g.docDate(refPath(kbRoot, c.sources, s.ref))).filter((d2) => !!d2).sort();
|
|
15056
15262
|
const docDate = docDates[docDates.length - 1];
|
|
15057
15263
|
const docRev = docRevOf(rule2);
|
|
15058
15264
|
const evidence = { docRev, codeRev: code?.rev ?? "unknown", files: cc.files, project: cc.project };
|
|
@@ -15074,6 +15280,7 @@ function evaluateCodeConflict(c, rule2, cc) {
|
|
|
15074
15280
|
};
|
|
15075
15281
|
}
|
|
15076
15282
|
function applyDecisions(file, c) {
|
|
15283
|
+
c = { ...c, anchorCache: /* @__PURE__ */ new Map() };
|
|
15077
15284
|
const now = nowOf(c);
|
|
15078
15285
|
const kbRoot = kbDir(c.cfg, c.kb);
|
|
15079
15286
|
const threshold = reconcileConfig(c.cfg, c.kb).autoApproveConfidence;
|
|
@@ -15117,14 +15324,15 @@ function applyDecisions(file, c) {
|
|
|
15117
15324
|
f.fm.status = "active";
|
|
15118
15325
|
if (d.loc && f.fm.sources[0])
|
|
15119
15326
|
f.fm.sources[0].loc = d.loc;
|
|
15120
|
-
|
|
15121
|
-
|
|
15327
|
+
const noSource = !rule2.sources.length;
|
|
15328
|
+
if (conf >= threshold && !d.flag && !reasons.length && !noSource) {
|
|
15329
|
+
fs27.writeFileSync(rule2.file, fileText(f.fm, f.body));
|
|
15122
15330
|
res.applied.push(d.item);
|
|
15123
|
-
events.push(ev(c, "item.applied", rule2.id
|
|
15331
|
+
events.push(ev(c, "item.applied", rule2.id));
|
|
15124
15332
|
verdict(d, "applied", { confidence: conf });
|
|
15125
15333
|
continue;
|
|
15126
15334
|
}
|
|
15127
|
-
reasons.push(conf < threshold ? "low-confidence" : "reviewer-flagged");
|
|
15335
|
+
reasons.push(noSource ? "no-source" : conf < threshold ? "low-confidence" : "reviewer-flagged");
|
|
15128
15336
|
} else if (d.decision === "approve") {
|
|
15129
15337
|
if (strong(rule2.modality))
|
|
15130
15338
|
reasons.push("retiring must/must-not");
|
|
@@ -15135,9 +15343,9 @@ function applyDecisions(file, c) {
|
|
|
15135
15343
|
if (!reasons.length) {
|
|
15136
15344
|
const f = readFm(rule2.file);
|
|
15137
15345
|
f.fm.status = "retired";
|
|
15138
|
-
|
|
15346
|
+
fs27.writeFileSync(rule2.file, fileText(f.fm, f.body));
|
|
15139
15347
|
res.applied.push(d.item);
|
|
15140
|
-
events.push(ev(c, "item.archived", rule2.id
|
|
15348
|
+
events.push(ev(c, "item.archived", rule2.id));
|
|
15141
15349
|
verdict(d, "applied", { confidence: conf });
|
|
15142
15350
|
continue;
|
|
15143
15351
|
}
|
|
@@ -15152,6 +15360,8 @@ function applyDecisions(file, c) {
|
|
|
15152
15360
|
reasons.push("reviewer-flagged");
|
|
15153
15361
|
if (conf < threshold)
|
|
15154
15362
|
reasons.push("low-confidence");
|
|
15363
|
+
if (p.rule.sources.some((s) => isGatedRef(kbRoot, c.sources, s.ref)))
|
|
15364
|
+
reasons.push("review-required");
|
|
15155
15365
|
if (d.decision === "approve") {
|
|
15156
15366
|
const myPri = priorityOfRule(c, p.rule);
|
|
15157
15367
|
const conflicted = (p.rule.conflictsWith ?? []).map((id) => live.find((r) => r.id === id)).filter((r) => !!r);
|
|
@@ -15213,7 +15423,7 @@ function applyPair(pd, c, res, threshold, events, kbRoot, now) {
|
|
|
15213
15423
|
for (const [x, y] of [[a, b], [b, a]]) {
|
|
15214
15424
|
const f = readFm(x.file);
|
|
15215
15425
|
f.fm.conflictsWith = [.../* @__PURE__ */ new Set([...f.fm.conflictsWith ?? [], y.id])];
|
|
15216
|
-
|
|
15426
|
+
fs27.writeFileSync(x.file, fileText(f.fm, f.body));
|
|
15217
15427
|
}
|
|
15218
15428
|
return;
|
|
15219
15429
|
}
|
|
@@ -15224,15 +15434,16 @@ function applyPair(pd, c, res, threshold, events, kbRoot, now) {
|
|
|
15224
15434
|
return;
|
|
15225
15435
|
}
|
|
15226
15436
|
const kf = readFm(keep.file);
|
|
15437
|
+
const canon = refCanon(kbRoot, c.sources);
|
|
15227
15438
|
for (const s of drop.sources)
|
|
15228
|
-
if (!kf.fm.sources.some((x) => x.ref === s.ref))
|
|
15439
|
+
if (!kf.fm.sources.some((x) => canon(x.ref) === canon(s.ref)))
|
|
15229
15440
|
kf.fm.sources.push(s);
|
|
15230
15441
|
kf.fm.supersedes = [.../* @__PURE__ */ new Set([...kf.fm.supersedes ?? [], drop.id])];
|
|
15231
|
-
|
|
15442
|
+
fs27.writeFileSync(keep.file, fileText(kf.fm, kf.body));
|
|
15232
15443
|
const df = readFm(drop.file);
|
|
15233
15444
|
df.fm.status = "retired";
|
|
15234
|
-
|
|
15235
|
-
events.push(ev(c, "item.superseded", drop.id
|
|
15445
|
+
fs27.writeFileSync(drop.file, fileText(df.fm, df.body));
|
|
15446
|
+
events.push(ev(c, "item.superseded", drop.id), ev(c, "item.applied", keep.id));
|
|
15236
15447
|
res.applied.push(key);
|
|
15237
15448
|
}
|
|
15238
15449
|
function resolveEscalation(c, key, r, by, reason) {
|
|
@@ -15262,9 +15473,9 @@ function resolveEscalation(c, key, r, by, reason) {
|
|
|
15262
15473
|
f.fm.decision = decision;
|
|
15263
15474
|
if (r.verdict === "supersede-with-code") {
|
|
15264
15475
|
f.fm.status = "retired";
|
|
15265
|
-
events.push(ev(c, "item.superseded", rule2.id
|
|
15476
|
+
events.push(ev(c, "item.superseded", rule2.id));
|
|
15266
15477
|
}
|
|
15267
|
-
|
|
15478
|
+
fs27.writeFileSync(rule2.file, fileText(f.fm, f.body));
|
|
15268
15479
|
return done(`${rule2.id}: ${r.verdict}`);
|
|
15269
15480
|
}
|
|
15270
15481
|
if (esc2.kind === "proposal") {
|
|
@@ -15281,23 +15492,26 @@ function resolveEscalation(c, key, r, by, reason) {
|
|
|
15281
15492
|
}
|
|
15282
15493
|
if (esc2.kind === "stale-retire") {
|
|
15283
15494
|
const rule2 = live.find((x) => x.id === esc2.ruleId);
|
|
15495
|
+
if (rule2 && r.kind !== "approve" && !rule2.sources.length) {
|
|
15496
|
+
throw new Error(`Rule ${rule2.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.`);
|
|
15497
|
+
}
|
|
15284
15498
|
if (rule2) {
|
|
15285
15499
|
const f = readFm(rule2.file);
|
|
15286
15500
|
f.fm.status = r.kind === "approve" ? "retired" : "active";
|
|
15287
|
-
|
|
15288
|
-
events.push(ev(c, r.kind === "approve" ? "item.archived" : "item.applied", rule2.id
|
|
15501
|
+
fs27.writeFileSync(rule2.file, fileText(f.fm, f.body));
|
|
15502
|
+
events.push(ev(c, r.kind === "approve" ? "item.archived" : "item.applied", rule2.id));
|
|
15289
15503
|
}
|
|
15290
15504
|
return done(`${esc2.ruleId}: ${r.kind === "approve" ? "retired" : "kept"}`);
|
|
15291
15505
|
}
|
|
15292
15506
|
if (esc2.kind === "override-base-changed") {
|
|
15293
|
-
const ov = esc2.item &&
|
|
15507
|
+
const ov = esc2.item && fs27.existsSync(esc2.item) ? esc2.item : void 0;
|
|
15294
15508
|
if (ov) {
|
|
15295
15509
|
if (r.kind === "reject")
|
|
15296
|
-
|
|
15510
|
+
fs27.rmSync(ov);
|
|
15297
15511
|
else {
|
|
15298
15512
|
const f = readFm(ov);
|
|
15299
15513
|
f.fm.overridesBase = esc2.evidence?.docRev;
|
|
15300
|
-
|
|
15514
|
+
fs27.writeFileSync(ov, fileText(f.fm, f.body));
|
|
15301
15515
|
}
|
|
15302
15516
|
}
|
|
15303
15517
|
return done(`${esc2.ruleId}: override ${r.kind === "reject" ? "dropped" : "kept"}`);
|
|
@@ -15321,11 +15535,11 @@ ${o.evidence}`).digest("hex");
|
|
|
15321
15535
|
supersedes: [],
|
|
15322
15536
|
conflictsWith: []
|
|
15323
15537
|
};
|
|
15324
|
-
const dir =
|
|
15325
|
-
|
|
15326
|
-
const file =
|
|
15327
|
-
|
|
15328
|
-
appendAudit([ev(c, "item.proposed", id
|
|
15538
|
+
const dir = path28.join(kbRulesDir(c.cfg, c.kb), PROPOSED_DIR);
|
|
15539
|
+
fs27.mkdirSync(dir, { recursive: true });
|
|
15540
|
+
const file = path28.join(dir, `${id}@${sha.slice(0, SHA_LEN2)}.md`);
|
|
15541
|
+
fs27.writeFileSync(file, fileText(fm, o.statement));
|
|
15542
|
+
appendAudit([ev(c, "item.proposed", id)], c.audit);
|
|
15329
15543
|
return file;
|
|
15330
15544
|
}
|
|
15331
15545
|
function buildReviewPacket(c) {
|
|
@@ -15365,10 +15579,10 @@ var init_review = __esm({
|
|
|
15365
15579
|
PRIORITY_RANK = { company: 3, project: 2, agent: 1 };
|
|
15366
15580
|
SHA_LEN2 = 12;
|
|
15367
15581
|
strong = (m) => m === "must" || m === "must-not";
|
|
15368
|
-
escalationsFile = (kbRoot) =>
|
|
15369
|
-
verdictsFile = (kbRoot) =>
|
|
15582
|
+
escalationsFile = (kbRoot) => path28.join(kbRoot, "escalations.json");
|
|
15583
|
+
verdictsFile = (kbRoot) => path28.join(kbRoot, "verdicts.jsonl");
|
|
15370
15584
|
needsYouCount = (kbRoot) => readEscalations(kbRoot).filter((e) => e.needsYou).length;
|
|
15371
|
-
git = (root, args) =>
|
|
15585
|
+
git = (root, args) => execFileSync8("git", ["-C", root, ...args], { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] }).trim();
|
|
15372
15586
|
realGit = {
|
|
15373
15587
|
lastCommit(root, files) {
|
|
15374
15588
|
try {
|
|
@@ -15387,34 +15601,34 @@ var init_review = __esm({
|
|
|
15387
15601
|
},
|
|
15388
15602
|
docDate(file) {
|
|
15389
15603
|
try {
|
|
15390
|
-
const d = git(
|
|
15604
|
+
const d = git(path28.dirname(file), ["log", "-1", "--format=%cI", "--", path28.basename(file)]);
|
|
15391
15605
|
if (d)
|
|
15392
15606
|
return d;
|
|
15393
15607
|
} catch {
|
|
15394
15608
|
}
|
|
15395
15609
|
try {
|
|
15396
|
-
return
|
|
15610
|
+
return fs27.statSync(file).mtime.toISOString();
|
|
15397
15611
|
} catch {
|
|
15398
15612
|
return null;
|
|
15399
15613
|
}
|
|
15400
15614
|
}
|
|
15401
15615
|
};
|
|
15402
15616
|
nowOf = (c) => c.now?.() ?? /* @__PURE__ */ new Date();
|
|
15403
|
-
fileText = (fm, body) =>
|
|
15617
|
+
fileText = (fm, body) => matter5.stringify(body.trim() + "\n", JSON.parse(JSON.stringify(fm)));
|
|
15404
15618
|
readFm = (file) => {
|
|
15405
|
-
const m =
|
|
15619
|
+
const m = matter5(fs27.readFileSync(file, "utf8"));
|
|
15406
15620
|
return { fm: m.data, body: m.content };
|
|
15407
15621
|
};
|
|
15408
|
-
ev = (c, event, itemId,
|
|
15622
|
+
ev = (c, event, itemId, extra = {}) => ({ kb: c.kb, level: "group", project: "", domain: "rules", itemId, event, ...extra });
|
|
15409
15623
|
docRevOf = (r) => r.sources.map((s) => `${s.ref}@${s.sha.slice(0, SHA_LEN2)}`).join(",");
|
|
15410
15624
|
}
|
|
15411
15625
|
});
|
|
15412
15626
|
|
|
15413
15627
|
// packages/core/dist/knowledge/fullpass.js
|
|
15414
15628
|
import crypto5 from "crypto";
|
|
15415
|
-
import
|
|
15416
|
-
import
|
|
15417
|
-
import
|
|
15629
|
+
import fs28 from "fs";
|
|
15630
|
+
import path29 from "path";
|
|
15631
|
+
import matter6 from "gray-matter";
|
|
15418
15632
|
function dedupPairs(rules) {
|
|
15419
15633
|
const active = rules.filter((r) => r.status === "active").sort((x, y) => x.id.localeCompare(y.id));
|
|
15420
15634
|
const out = [];
|
|
@@ -15430,12 +15644,12 @@ function dedupPairs(rules) {
|
|
|
15430
15644
|
return out.slice(0, MAX_DEDUP_PAIRS);
|
|
15431
15645
|
}
|
|
15432
15646
|
function readAuditRecords(kb, since, dir = defaultAuditDir()) {
|
|
15433
|
-
if (!
|
|
15647
|
+
if (!fs28.existsSync(dir))
|
|
15434
15648
|
return [];
|
|
15435
15649
|
const sinceMonth = since.toISOString().slice(0, 7);
|
|
15436
15650
|
const out = [];
|
|
15437
|
-
for (const f of
|
|
15438
|
-
for (const line2 of
|
|
15651
|
+
for (const f of fs28.readdirSync(dir).filter((n) => n.endsWith(".jsonl") && n.slice(0, 7) >= sinceMonth).sort()) {
|
|
15652
|
+
for (const line2 of fs28.readFileSync(path29.join(dir, f), "utf8").split("\n")) {
|
|
15439
15653
|
if (!line2.trim())
|
|
15440
15654
|
continue;
|
|
15441
15655
|
try {
|
|
@@ -15498,8 +15712,8 @@ function checkOverrides(cfg, kb) {
|
|
|
15498
15712
|
continue;
|
|
15499
15713
|
const h = baseHash(b);
|
|
15500
15714
|
if (!o.overridesBase) {
|
|
15501
|
-
const m =
|
|
15502
|
-
|
|
15715
|
+
const m = matter6(fs28.readFileSync(o.file, "utf8"));
|
|
15716
|
+
fs28.writeFileSync(o.file, matter6.stringify(m.content, { ...m.data, overridesBase: h }));
|
|
15503
15717
|
continue;
|
|
15504
15718
|
}
|
|
15505
15719
|
out.push({ project, ruleId: o.id, file: o.file, baseHash: h, changed: o.overridesBase !== h });
|
|
@@ -15542,8 +15756,8 @@ var init_fullpass = __esm({
|
|
|
15542
15756
|
});
|
|
15543
15757
|
|
|
15544
15758
|
// packages/core/dist/knowledge/scores.js
|
|
15545
|
-
import
|
|
15546
|
-
import
|
|
15759
|
+
import fs29 from "fs";
|
|
15760
|
+
import path30 from "path";
|
|
15547
15761
|
function tally(records, into = emptyTally()) {
|
|
15548
15762
|
for (const e of records) {
|
|
15549
15763
|
const domain = typeof e.domain === "string" && e.domain ? e.domain : "rules";
|
|
@@ -15552,7 +15766,7 @@ function tally(records, into = emptyTally()) {
|
|
|
15552
15766
|
d.writes++;
|
|
15553
15767
|
if (READ_EVENTS.has(e.event ?? ""))
|
|
15554
15768
|
d.reads++;
|
|
15555
|
-
if (!e.itemId)
|
|
15769
|
+
if (!e.itemId || WRITE_EVENTS.has(e.event ?? ""))
|
|
15556
15770
|
continue;
|
|
15557
15771
|
const c = into.items[`${domain}|${e.itemId}`] ??= { ...zero(), domain, itemId: e.itemId };
|
|
15558
15772
|
switch (e.event) {
|
|
@@ -15589,7 +15803,7 @@ function tally(records, into = emptyTally()) {
|
|
|
15589
15803
|
}
|
|
15590
15804
|
function parseLines(file) {
|
|
15591
15805
|
const out = [];
|
|
15592
|
-
for (const line2 of
|
|
15806
|
+
for (const line2 of fs29.readFileSync(file, "utf8").split("\n")) {
|
|
15593
15807
|
if (!line2.trim())
|
|
15594
15808
|
continue;
|
|
15595
15809
|
try {
|
|
@@ -15601,37 +15815,37 @@ function parseLines(file) {
|
|
|
15601
15815
|
}
|
|
15602
15816
|
function compactAudit(o) {
|
|
15603
15817
|
const dir = o.dir ?? defaultAuditDir();
|
|
15604
|
-
if (!
|
|
15818
|
+
if (!fs29.existsSync(dir))
|
|
15605
15819
|
return [];
|
|
15606
15820
|
const cutoffMonth = new Date(o.now.getTime() - SCORE_WINDOW_DAYS * DAY_MS3).toISOString().slice(0, 7);
|
|
15607
15821
|
const done = [];
|
|
15608
|
-
for (const f of
|
|
15822
|
+
for (const f of fs29.readdirSync(dir).sort()) {
|
|
15609
15823
|
const m = MONTH_FILE_RE.exec(f);
|
|
15610
15824
|
if (!m || m[1] >= cutoffMonth)
|
|
15611
15825
|
continue;
|
|
15612
15826
|
const [, month, machine] = m;
|
|
15613
15827
|
const byKb = /* @__PURE__ */ new Map();
|
|
15614
|
-
for (const r of parseLines(
|
|
15828
|
+
for (const r of parseLines(path30.join(dir, f)))
|
|
15615
15829
|
byKb.set(r.kb ?? "", [...byKb.get(r.kb ?? "") ?? [], r]);
|
|
15616
|
-
const statsPath =
|
|
15617
|
-
const prior =
|
|
15830
|
+
const statsPath = path30.join(dir, statsFileName(month, machine));
|
|
15831
|
+
const prior = fs29.existsSync(statsPath) ? JSON.parse(fs29.readFileSync(statsPath, "utf8")) : null;
|
|
15618
15832
|
const kbs = prior?.kbs ?? {};
|
|
15619
15833
|
for (const [kb, recs] of byKb)
|
|
15620
15834
|
kbs[kb] = tally(recs, kbs[kb]);
|
|
15621
|
-
|
|
15622
|
-
|
|
15623
|
-
|
|
15835
|
+
fs29.writeFileSync(`${statsPath}.tmp`, JSON.stringify({ month, machine, kbs }));
|
|
15836
|
+
fs29.renameSync(`${statsPath}.tmp`, statsPath);
|
|
15837
|
+
fs29.unlinkSync(path30.join(dir, f));
|
|
15624
15838
|
done.push(month);
|
|
15625
15839
|
}
|
|
15626
15840
|
return done;
|
|
15627
15841
|
}
|
|
15628
15842
|
function readCompacted(kb, dir) {
|
|
15629
15843
|
const t = emptyTally();
|
|
15630
|
-
if (!
|
|
15844
|
+
if (!fs29.existsSync(dir))
|
|
15631
15845
|
return t;
|
|
15632
|
-
for (const f of
|
|
15846
|
+
for (const f of fs29.readdirSync(dir).filter((n) => n.endsWith(".stats.json"))) {
|
|
15633
15847
|
try {
|
|
15634
|
-
const k = JSON.parse(
|
|
15848
|
+
const k = JSON.parse(fs29.readFileSync(path30.join(dir, f), "utf8")).kbs[kb];
|
|
15635
15849
|
if (k)
|
|
15636
15850
|
mergeTally(t, k);
|
|
15637
15851
|
} catch {
|
|
@@ -15681,7 +15895,7 @@ function computeScores(i) {
|
|
|
15681
15895
|
noise: w.noise,
|
|
15682
15896
|
wrong: w.wrong,
|
|
15683
15897
|
fireRate: w.surfaced,
|
|
15684
|
-
pullRate: w.shown,
|
|
15898
|
+
pullRate: w.shown + w.searched,
|
|
15685
15899
|
useRate: ratio(w.cited, w.surfaced),
|
|
15686
15900
|
noiseRate: ratio(w.noise, w.surfaced),
|
|
15687
15901
|
violationRate: ratio(w.violated, w.surfaced),
|
|
@@ -15723,21 +15937,21 @@ function computeScores(i) {
|
|
|
15723
15937
|
function scoreKb(o) {
|
|
15724
15938
|
const dir = o.auditDir ?? defaultAuditDir();
|
|
15725
15939
|
const records = [];
|
|
15726
|
-
if (
|
|
15727
|
-
for (const f of
|
|
15728
|
-
records.push(...parseLines(
|
|
15940
|
+
if (fs29.existsSync(dir)) {
|
|
15941
|
+
for (const f of fs29.readdirSync(dir).filter((n) => MONTH_FILE_RE.test(n)).sort()) {
|
|
15942
|
+
records.push(...parseLines(path30.join(dir, f)).filter((r) => r.kb === o.kb));
|
|
15729
15943
|
}
|
|
15730
15944
|
}
|
|
15731
15945
|
let verdicts = [];
|
|
15732
15946
|
try {
|
|
15733
|
-
verdicts =
|
|
15947
|
+
verdicts = fs29.readFileSync(path30.join(o.kbRoot, "verdicts.jsonl"), "utf8").split("\n").filter(Boolean).map((l) => JSON.parse(l));
|
|
15734
15948
|
} catch {
|
|
15735
15949
|
}
|
|
15736
15950
|
return computeScores({ kb: o.kb, records, now: o.now, known: o.known, compacted: readCompacted(o.kb, dir), verdicts });
|
|
15737
15951
|
}
|
|
15738
15952
|
function writeScores(kbRoot, s) {
|
|
15739
|
-
|
|
15740
|
-
|
|
15953
|
+
fs29.mkdirSync(kbRoot, { recursive: true });
|
|
15954
|
+
fs29.writeFileSync(scoresFile(kbRoot), JSON.stringify(s, null, 2) + "\n");
|
|
15741
15955
|
}
|
|
15742
15956
|
function renderScoresSection(s) {
|
|
15743
15957
|
const pct = (x) => x === null ? "n/a" : `${Math.round(x * 100)}%`;
|
|
@@ -15750,7 +15964,7 @@ function renderScoresSection(s) {
|
|
|
15750
15964
|
...used.length ? [
|
|
15751
15965
|
"| Item | Surfaced | Pulled | Cited | Use | Noise | Violated |",
|
|
15752
15966
|
"|---|---|---|---|---|---|---|",
|
|
15753
|
-
...used.map((x) => `| ${x.itemId} | ${x.surfaced} | ${x.
|
|
15967
|
+
...used.map((x) => `| ${x.itemId} | ${x.surfaced} | ${x.pullRate} | ${x.cited} | ${pct(x.useRate)} | ${pct(x.noiseRate)} | ${pct(x.violationRate)} |`)
|
|
15754
15968
|
] : ["No items surfaced."],
|
|
15755
15969
|
"",
|
|
15756
15970
|
`- Never fired (${never.length}): ${never.slice(0, 20).join(", ") || "none"}${never.length > 20 ? ", \u2026" : ""}`,
|
|
@@ -15778,13 +15992,13 @@ var init_scores = __esm({
|
|
|
15778
15992
|
MONTH_FILE_RE = /^(\d{4}-\d{2})\.(.+)\.jsonl$/;
|
|
15779
15993
|
statsFileName = (month, machine) => `${month}.${machine}.stats.json`;
|
|
15780
15994
|
ratio = (n, d) => d ? Math.round(n / d * 1e3) / 1e3 : null;
|
|
15781
|
-
scoresFile = (kbRoot) =>
|
|
15995
|
+
scoresFile = (kbRoot) => path30.join(kbRoot, "scores.json");
|
|
15782
15996
|
}
|
|
15783
15997
|
});
|
|
15784
15998
|
|
|
15785
15999
|
// packages/core/dist/knowledge/report.js
|
|
15786
|
-
import
|
|
15787
|
-
import
|
|
16000
|
+
import fs30 from "fs";
|
|
16001
|
+
import path31 from "path";
|
|
15788
16002
|
function renderReport(cfg, kb, o) {
|
|
15789
16003
|
const { rules } = loadKbRules(cfg, kb, { includeProposed: true });
|
|
15790
16004
|
const count = (s) => rules.filter((r) => r.status === s).length;
|
|
@@ -15806,6 +16020,11 @@ function renderReport(cfg, kb, o) {
|
|
|
15806
16020
|
const info = esc2.filter((e) => !e.needsYou);
|
|
15807
16021
|
if (info.length)
|
|
15808
16022
|
L.push("", `## For information (${info.length})`, "", ...info.map((e) => `- **${e.key}**: ${e.explanation}`));
|
|
16023
|
+
const { errata, errors: errataErrors } = loadErrata(kbDir(cfg, kb));
|
|
16024
|
+
const orphans = orphanedErrata(kbDir(cfg, kb), loadSources(kbDir(cfg, kb)).sources, errata);
|
|
16025
|
+
if (orphans.length || errataErrors.length) {
|
|
16026
|
+
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}`));
|
|
16027
|
+
}
|
|
15809
16028
|
if (o.full) {
|
|
15810
16029
|
const { usage: usage2, caps } = o.full;
|
|
15811
16030
|
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"}`);
|
|
@@ -15815,14 +16034,16 @@ function renderReport(cfg, kb, o) {
|
|
|
15815
16034
|
return L.join("\n") + "\n";
|
|
15816
16035
|
}
|
|
15817
16036
|
function writeReport(cfg, kb, o) {
|
|
15818
|
-
const file =
|
|
15819
|
-
|
|
16037
|
+
const file = path31.join(kbDir(cfg, kb), "REPORT.md");
|
|
16038
|
+
fs30.writeFileSync(file, renderReport(cfg, kb, o));
|
|
15820
16039
|
return file;
|
|
15821
16040
|
}
|
|
15822
16041
|
var init_report = __esm({
|
|
15823
16042
|
"packages/core/dist/knowledge/report.js"() {
|
|
16043
|
+
init_errata();
|
|
15824
16044
|
init_layers();
|
|
15825
16045
|
init_paths();
|
|
16046
|
+
init_sources();
|
|
15826
16047
|
init_review();
|
|
15827
16048
|
init_scores();
|
|
15828
16049
|
}
|
|
@@ -15864,44 +16085,63 @@ var init_reconcile = __esm({
|
|
|
15864
16085
|
|
|
15865
16086
|
// packages/core/dist/knowledge/cite.js
|
|
15866
16087
|
function scanAndLogCitations(i) {
|
|
15867
|
-
|
|
15868
|
-
|
|
15869
|
-
|
|
15870
|
-
|
|
15871
|
-
|
|
15872
|
-
|
|
15873
|
-
|
|
15874
|
-
|
|
15875
|
-
|
|
15876
|
-
|
|
15877
|
-
|
|
15878
|
-
|
|
15879
|
-
|
|
15880
|
-
|
|
15881
|
-
delivered
|
|
15882
|
-
|
|
15883
|
-
|
|
15884
|
-
|
|
15885
|
-
|
|
15886
|
-
|
|
15887
|
-
|
|
15888
|
-
|
|
15889
|
-
|
|
15890
|
-
|
|
15891
|
-
|
|
15892
|
-
|
|
15893
|
-
|
|
15894
|
-
|
|
15895
|
-
|
|
16088
|
+
return scanCitations([i], i);
|
|
16089
|
+
}
|
|
16090
|
+
function scanCitations(texts, o) {
|
|
16091
|
+
if (!texts.length)
|
|
16092
|
+
return [];
|
|
16093
|
+
const now = o.sink?.now?.() ?? /* @__PURE__ */ new Date();
|
|
16094
|
+
const lookbackMs = (o.lookbackDays ?? CITE_LOOKBACK_DAYS) * DAY_MS4;
|
|
16095
|
+
const ats = texts.map((t) => (t.at ?? now).getTime());
|
|
16096
|
+
const records = readAuditRecords(void 0, new Date(Math.min(...ats) - lookbackMs), o.sink?.dir ?? defaultAuditDir()).filter((r) => r.itemId && r.project === o.project);
|
|
16097
|
+
const already = new Set(records.filter((r) => r.event === "item.cited").map((r) => `${r.ref}|${r.itemId}`));
|
|
16098
|
+
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));
|
|
16099
|
+
const events = [];
|
|
16100
|
+
texts.forEach((t, n) => {
|
|
16101
|
+
const at = ats[n];
|
|
16102
|
+
const delivered = /* @__PURE__ */ new Map();
|
|
16103
|
+
for (const r of deliveries) {
|
|
16104
|
+
const ts = Date.parse(r.ts);
|
|
16105
|
+
if (ts <= at && ts >= at - lookbackMs)
|
|
16106
|
+
delivered.set(r.itemId, r);
|
|
16107
|
+
}
|
|
16108
|
+
for (const [itemId, r] of delivered) {
|
|
16109
|
+
if (already.has(`${t.ref}|${itemId}`) || !mentionsId(t.text, itemId))
|
|
16110
|
+
continue;
|
|
16111
|
+
already.add(`${t.ref}|${itemId}`);
|
|
16112
|
+
events.push({
|
|
16113
|
+
kb: String(r.kb ?? ""),
|
|
16114
|
+
level: String(r.level ?? "project"),
|
|
16115
|
+
project: o.project,
|
|
16116
|
+
domain: String(r.domain ?? "rules"),
|
|
16117
|
+
itemId,
|
|
16118
|
+
event: "item.cited",
|
|
16119
|
+
ref: t.ref,
|
|
16120
|
+
...o.agent ? { agent: o.agent } : {},
|
|
16121
|
+
...o.session ? { session: o.session } : {}
|
|
16122
|
+
});
|
|
16123
|
+
}
|
|
16124
|
+
});
|
|
16125
|
+
appendAudit(events, o.sink);
|
|
16126
|
+
return events.map((e) => e.itemId);
|
|
15896
16127
|
}
|
|
15897
16128
|
function readGitMessages(repo, since, run) {
|
|
15898
|
-
|
|
16129
|
+
return parseLog(run(["-C", repo, "log", "--all", `--since=${since.toISOString()}`, LOG_FORMAT]));
|
|
16130
|
+
}
|
|
16131
|
+
function readBranchOnlyMessages(repo, run, max = 200) {
|
|
16132
|
+
const branch = run(["-C", repo, "rev-parse", "--abbrev-ref", "HEAD"]).trim();
|
|
16133
|
+
if (!branch)
|
|
16134
|
+
return [];
|
|
16135
|
+
const own = branch === "HEAD" ? [] : [`--exclude=${branch}`];
|
|
16136
|
+
return parseLog(run(["-C", repo, "log", `--max-count=${max}`, "HEAD", "--not", ...own, "--branches", ...own.length ? [`--exclude=*/${branch}`] : [], "--remotes", LOG_FORMAT]));
|
|
16137
|
+
}
|
|
16138
|
+
function parseLog(out) {
|
|
15899
16139
|
return out.split("").filter((c) => c.trim()).map((c) => {
|
|
15900
16140
|
const [sha, at, ...rest] = c.split("");
|
|
15901
16141
|
return { sha: sha.trim(), at: new Date(at), text: rest.join("") };
|
|
15902
16142
|
});
|
|
15903
16143
|
}
|
|
15904
|
-
var DAY_MS4, CITE_LOOKBACK_DAYS, escapeRe2, mentionsId;
|
|
16144
|
+
var DAY_MS4, CITE_LOOKBACK_DAYS, escapeRe2, mentionsId, LOG_FORMAT;
|
|
15905
16145
|
var init_cite = __esm({
|
|
15906
16146
|
"packages/core/dist/knowledge/cite.js"() {
|
|
15907
16147
|
init_audit();
|
|
@@ -15910,6 +16150,7 @@ var init_cite = __esm({
|
|
|
15910
16150
|
CITE_LOOKBACK_DAYS = 7;
|
|
15911
16151
|
escapeRe2 = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
15912
16152
|
mentionsId = (text, id) => new RegExp(`(?<![\\w.-])${escapeRe2(id)}(?![\\w-])`).test(text);
|
|
16153
|
+
LOG_FORMAT = "--format=%x1e%H%x1f%cI%x1f%B";
|
|
15913
16154
|
}
|
|
15914
16155
|
});
|
|
15915
16156
|
|
|
@@ -15927,6 +16168,7 @@ var init_knowledge2 = __esm({
|
|
|
15927
16168
|
init_migrate();
|
|
15928
16169
|
init_verify();
|
|
15929
16170
|
init_ingest();
|
|
16171
|
+
init_errata();
|
|
15930
16172
|
init_anchor();
|
|
15931
16173
|
init_extract();
|
|
15932
16174
|
init_match();
|
|
@@ -16137,7 +16379,6 @@ __export(dist_exports2, {
|
|
|
16137
16379
|
extractToolPayload: () => extractToolPayload,
|
|
16138
16380
|
extractUserIntentFromTranscript: () => extractUserIntentFromTranscript,
|
|
16139
16381
|
fallsBackToPane: () => fallsBackToPane,
|
|
16140
|
-
fileForRef: () => fileForRef,
|
|
16141
16382
|
findCrewPane: () => findCrewPane,
|
|
16142
16383
|
findLegacyKbs: () => findLegacyKbs,
|
|
16143
16384
|
findLegacyOverlays: () => findLegacyOverlays,
|
|
@@ -16177,6 +16418,7 @@ __export(dist_exports2, {
|
|
|
16177
16418
|
isDaemonSocketLive: () => isDaemonSocketLive,
|
|
16178
16419
|
isGateCacheEnabled: () => isGateCacheEnabled,
|
|
16179
16420
|
isGateSession: () => isGateSession,
|
|
16421
|
+
isGatedRef: () => isGatedRef,
|
|
16180
16422
|
isNotifyActive: () => isNotifyActive,
|
|
16181
16423
|
isOperatorInitiatedCommand: () => isOperatorInitiatedCommand,
|
|
16182
16424
|
isPendingProposalDup: () => isPendingProposalDup,
|
|
@@ -16194,6 +16436,7 @@ __export(dist_exports2, {
|
|
|
16194
16436
|
launchOneWorkspace: () => launchOneWorkspace,
|
|
16195
16437
|
legacyKbDir: () => legacyKbDir,
|
|
16196
16438
|
listSessions: () => listSessions,
|
|
16439
|
+
loadErrata: () => loadErrata,
|
|
16197
16440
|
loadKbRules: () => loadKbRules,
|
|
16198
16441
|
loadPending: () => loadPending,
|
|
16199
16442
|
loadProposals: () => loadProposals,
|
|
@@ -16228,6 +16471,7 @@ __export(dist_exports2, {
|
|
|
16228
16471
|
normalizedViews: () => normalizedViews,
|
|
16229
16472
|
notePaneScreen: () => notePaneScreen,
|
|
16230
16473
|
notifyToggle: () => notifyToggle,
|
|
16474
|
+
orphanedErrata: () => orphanedErrata,
|
|
16231
16475
|
parseBearer: () => parseBearer,
|
|
16232
16476
|
parseClassifierVerdict: () => parseClassifierVerdict,
|
|
16233
16477
|
parseCommand: () => parseCommand,
|
|
@@ -16252,6 +16496,7 @@ __export(dist_exports2, {
|
|
|
16252
16496
|
pruneTopics: () => pruneTopics,
|
|
16253
16497
|
purgeExpiredWorkItems: () => purgeExpiredWorkItems,
|
|
16254
16498
|
readAuditRecords: () => readAuditRecords,
|
|
16499
|
+
readBranchOnlyMessages: () => readBranchOnlyMessages,
|
|
16255
16500
|
readCaptainAddress: () => readCaptainAddress,
|
|
16256
16501
|
readCursor: () => readCursor,
|
|
16257
16502
|
readEscalations: () => readEscalations,
|
|
@@ -16275,9 +16520,13 @@ __export(dist_exports2, {
|
|
|
16275
16520
|
recoverStall: () => recoverStall,
|
|
16276
16521
|
reduce: () => reduce,
|
|
16277
16522
|
reduceLifecycle: () => reduceLifecycle,
|
|
16523
|
+
refCandidates: () => refCandidates,
|
|
16524
|
+
refCanon: () => refCanon,
|
|
16278
16525
|
refFor: () => refFor,
|
|
16526
|
+
refPath: () => refPath,
|
|
16279
16527
|
releaseDaemonLock: () => releaseDaemonLock,
|
|
16280
16528
|
removeRunningMarker: () => removeRunningMarker,
|
|
16529
|
+
removeSource: () => removeSource,
|
|
16281
16530
|
renderEnvAssignments: () => renderEnvAssignments,
|
|
16282
16531
|
renderPlist: () => renderPlist,
|
|
16283
16532
|
renderReport: () => renderReport,
|
|
@@ -16307,6 +16556,7 @@ __export(dist_exports2, {
|
|
|
16307
16556
|
resolveSetupGroup: () => resolveSetupGroup,
|
|
16308
16557
|
resolveSetupToken: () => resolveSetupToken,
|
|
16309
16558
|
resolveSetupUserId: () => resolveSetupUserId,
|
|
16559
|
+
resolveSourceRef: () => resolveSourceRef,
|
|
16310
16560
|
restartDaemonIfRunning: () => restartDaemonIfRunning,
|
|
16311
16561
|
rotateIfNeeded: () => rotateIfNeeded,
|
|
16312
16562
|
ruleAuditScope: () => ruleAuditScope,
|
|
@@ -16340,6 +16590,7 @@ __export(dist_exports2, {
|
|
|
16340
16590
|
saveSessions: () => saveSessions,
|
|
16341
16591
|
saveState: () => saveState,
|
|
16342
16592
|
scanAndLogCitations: () => scanAndLogCitations,
|
|
16593
|
+
scanCitations: () => scanCitations,
|
|
16343
16594
|
scheduleFile: () => scheduleFile,
|
|
16344
16595
|
scoreKb: () => scoreKb,
|
|
16345
16596
|
scoresFile: () => scoresFile,
|
|
@@ -16360,6 +16611,7 @@ __export(dist_exports2, {
|
|
|
16360
16611
|
sideNextAutoName: () => sideNextAutoName,
|
|
16361
16612
|
sideTitleFor: () => sideTitleFor,
|
|
16362
16613
|
snapshotSources: () => snapshotSources,
|
|
16614
|
+
sourceCovers: () => sourceCovers,
|
|
16363
16615
|
spansOverlap: () => spansOverlap,
|
|
16364
16616
|
splitSections: () => splitSections,
|
|
16365
16617
|
splitStatement: () => splitStatement,
|
|
@@ -16455,7 +16707,7 @@ var init_dist2 = __esm({
|
|
|
16455
16707
|
});
|
|
16456
16708
|
|
|
16457
16709
|
// packages/agents/dist/claude/registry.js
|
|
16458
|
-
import
|
|
16710
|
+
import fs31 from "fs";
|
|
16459
16711
|
import { join as join17 } from "path";
|
|
16460
16712
|
import { homedir as homedir7 } from "os";
|
|
16461
16713
|
function parseRegistryDir(files, readFile7) {
|
|
@@ -16500,11 +16752,11 @@ function readClaudeStatus(task) {
|
|
|
16500
16752
|
return void 0;
|
|
16501
16753
|
let files;
|
|
16502
16754
|
try {
|
|
16503
|
-
files =
|
|
16755
|
+
files = fs31.readdirSync(CLAUDE_SESSIONS_DIR);
|
|
16504
16756
|
} catch {
|
|
16505
16757
|
return void 0;
|
|
16506
16758
|
}
|
|
16507
|
-
const entries = parseRegistryDir(files, (name) =>
|
|
16759
|
+
const entries = parseRegistryDir(files, (name) => fs31.readFileSync(join17(CLAUDE_SESSIONS_DIR, name), "utf8"));
|
|
16508
16760
|
let entry;
|
|
16509
16761
|
if (task.messagingSocketPath) {
|
|
16510
16762
|
entry = entries.find((e) => e.messagingSocketPath === task.messagingSocketPath);
|
|
@@ -16519,11 +16771,11 @@ function readClaudeStatus(task) {
|
|
|
16519
16771
|
function readClaudeStatusByCwd(cwd) {
|
|
16520
16772
|
let files;
|
|
16521
16773
|
try {
|
|
16522
|
-
files =
|
|
16774
|
+
files = fs31.readdirSync(CLAUDE_SESSIONS_DIR);
|
|
16523
16775
|
} catch {
|
|
16524
16776
|
return void 0;
|
|
16525
16777
|
}
|
|
16526
|
-
const entries = parseRegistryDir(files, (name) =>
|
|
16778
|
+
const entries = parseRegistryDir(files, (name) => fs31.readFileSync(join17(CLAUDE_SESSIONS_DIR, name), "utf8"));
|
|
16527
16779
|
const entry = entries.find((e) => e.cwd === cwd);
|
|
16528
16780
|
if (!entry)
|
|
16529
16781
|
return void 0;
|
|
@@ -16532,11 +16784,11 @@ function readClaudeStatusByCwd(cwd) {
|
|
|
16532
16784
|
function readClaudeStatusBySocketPath(socketPath2) {
|
|
16533
16785
|
let files;
|
|
16534
16786
|
try {
|
|
16535
|
-
files =
|
|
16787
|
+
files = fs31.readdirSync(CLAUDE_SESSIONS_DIR);
|
|
16536
16788
|
} catch {
|
|
16537
16789
|
return void 0;
|
|
16538
16790
|
}
|
|
16539
|
-
const entries = parseRegistryDir(files, (name) =>
|
|
16791
|
+
const entries = parseRegistryDir(files, (name) => fs31.readFileSync(join17(CLAUDE_SESSIONS_DIR, name), "utf8"));
|
|
16540
16792
|
const entry = entries.find((e) => e.messagingSocketPath === socketPath2);
|
|
16541
16793
|
if (!entry)
|
|
16542
16794
|
return void 0;
|
|
@@ -16959,8 +17211,8 @@ var init_registry2 = __esm({
|
|
|
16959
17211
|
});
|
|
16960
17212
|
|
|
16961
17213
|
// packages/agents/dist/drivers/launch-cmd.js
|
|
16962
|
-
import
|
|
16963
|
-
import
|
|
17214
|
+
import fs32 from "fs";
|
|
17215
|
+
import path32 from "path";
|
|
16964
17216
|
function buildAgentCmd(agentName, registry, role, fresh, permissionMode, model, templatesDir, messagingSocketPath, sessionName, thinking, captainBoot, settingsPath) {
|
|
16965
17217
|
const driver = registry.getDriver(agentName);
|
|
16966
17218
|
if (driver.name === "claude") {
|
|
@@ -16987,14 +17239,14 @@ function buildAgentCmd(agentName, registry, role, fresh, permissionMode, model,
|
|
|
16987
17239
|
cmd += ` --settings ${settingsPath}`;
|
|
16988
17240
|
}
|
|
16989
17241
|
if (templatesDir) {
|
|
16990
|
-
const roleFile2 =
|
|
16991
|
-
const legacyRoleFile =
|
|
16992
|
-
const actualRoleFile =
|
|
17242
|
+
const roleFile2 = path32.join(templatesDir, `${role}.claude.md`);
|
|
17243
|
+
const legacyRoleFile = path32.join(templatesDir, `${role}.CLAUDE.md`);
|
|
17244
|
+
const actualRoleFile = fs32.existsSync(roleFile2) ? roleFile2 : fs32.existsSync(legacyRoleFile) ? legacyRoleFile : null;
|
|
16993
17245
|
if (actualRoleFile) {
|
|
16994
17246
|
cmd += ` --append-system-prompt-file ${actualRoleFile}`;
|
|
16995
17247
|
}
|
|
16996
|
-
const pluginDir =
|
|
16997
|
-
if (
|
|
17248
|
+
const pluginDir = path32.join(templatesDir, "..", "plugin");
|
|
17249
|
+
if (fs32.existsSync(pluginDir)) {
|
|
16998
17250
|
cmd += ` --plugin-dir ${pluginDir}`;
|
|
16999
17251
|
}
|
|
17000
17252
|
}
|
|
@@ -17003,14 +17255,14 @@ function buildAgentCmd(agentName, registry, role, fresh, permissionMode, model,
|
|
|
17003
17255
|
}
|
|
17004
17256
|
return cmd;
|
|
17005
17257
|
}
|
|
17006
|
-
const roleFile = templatesDir ?
|
|
17258
|
+
const roleFile = templatesDir ? path32.join(templatesDir, `${role}.${driver.templateSuffix}.md`) : void 0;
|
|
17007
17259
|
return driver.buildCommand({
|
|
17008
17260
|
prompt: `You are a squadrant ${role}. Read your instructions from ${roleFile ?? role} and begin.`,
|
|
17009
17261
|
workdir: process.cwd(),
|
|
17010
17262
|
role,
|
|
17011
17263
|
model,
|
|
17012
17264
|
autoApprove: true,
|
|
17013
|
-
promptFile: roleFile &&
|
|
17265
|
+
promptFile: roleFile && fs32.existsSync(roleFile) ? roleFile : void 0,
|
|
17014
17266
|
...captainBoot && role === "captain" ? {
|
|
17015
17267
|
interactive: true,
|
|
17016
17268
|
...captainBoot.port ? { port: captainBoot.port } : {},
|
|
@@ -17040,8 +17292,8 @@ var init_drivers = __esm({
|
|
|
17040
17292
|
|
|
17041
17293
|
// packages/agents/dist/projection/cursor.js
|
|
17042
17294
|
import { mkdir, readFile, writeFile } from "fs/promises";
|
|
17043
|
-
import
|
|
17044
|
-
import
|
|
17295
|
+
import path33 from "path";
|
|
17296
|
+
import os9 from "os";
|
|
17045
17297
|
function renderMdc(source) {
|
|
17046
17298
|
const skillSections = source.skills.map((s) => `## Skill: ${s.name}
|
|
17047
17299
|
|
|
@@ -17089,7 +17341,7 @@ function createCursorEmitter() {
|
|
|
17089
17341
|
if (scope === "user") {
|
|
17090
17342
|
return [
|
|
17091
17343
|
{
|
|
17092
|
-
path:
|
|
17344
|
+
path: path33.join(os9.homedir(), ".cursor/rules/squadrant-global.mdc"),
|
|
17093
17345
|
shared: false,
|
|
17094
17346
|
format: "mdc"
|
|
17095
17347
|
}
|
|
@@ -17099,7 +17351,7 @@ function createCursorEmitter() {
|
|
|
17099
17351
|
return [];
|
|
17100
17352
|
return [
|
|
17101
17353
|
{
|
|
17102
|
-
path:
|
|
17354
|
+
path: path33.join(projectRoot, ".cursor/rules/squadrant.mdc"),
|
|
17103
17355
|
shared: false,
|
|
17104
17356
|
format: "mdc"
|
|
17105
17357
|
}
|
|
@@ -17116,7 +17368,7 @@ function createCursorEmitter() {
|
|
|
17116
17368
|
diff: buildDiff(existing, generated)
|
|
17117
17369
|
};
|
|
17118
17370
|
}
|
|
17119
|
-
await mkdir(
|
|
17371
|
+
await mkdir(path33.dirname(dest.path), { recursive: true });
|
|
17120
17372
|
await writeFile(dest.path, generated, "utf-8");
|
|
17121
17373
|
return {
|
|
17122
17374
|
written: true,
|
|
@@ -17167,8 +17419,8 @@ var init_marker = __esm({
|
|
|
17167
17419
|
|
|
17168
17420
|
// packages/agents/dist/projection/codex.js
|
|
17169
17421
|
import { mkdir as mkdir2, readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
|
|
17170
|
-
import
|
|
17171
|
-
import
|
|
17422
|
+
import path34 from "path";
|
|
17423
|
+
import os10 from "os";
|
|
17172
17424
|
function renderMarkdown(source) {
|
|
17173
17425
|
const skillSections = source.skills.map((s) => `## Skill: ${s.name}
|
|
17174
17426
|
|
|
@@ -17192,7 +17444,7 @@ function createCodexEmitter() {
|
|
|
17192
17444
|
destinations(scope, projectRoot) {
|
|
17193
17445
|
if (scope === "user") {
|
|
17194
17446
|
return [{
|
|
17195
|
-
path:
|
|
17447
|
+
path: path34.join(os10.homedir(), ".codex/AGENTS.md"),
|
|
17196
17448
|
shared: true,
|
|
17197
17449
|
format: "markdown"
|
|
17198
17450
|
}];
|
|
@@ -17200,7 +17452,7 @@ function createCodexEmitter() {
|
|
|
17200
17452
|
if (!projectRoot)
|
|
17201
17453
|
return [];
|
|
17202
17454
|
return [{
|
|
17203
|
-
path:
|
|
17455
|
+
path: path34.join(projectRoot, "AGENTS.md"),
|
|
17204
17456
|
shared: true,
|
|
17205
17457
|
format: "markdown"
|
|
17206
17458
|
}];
|
|
@@ -17221,7 +17473,7 @@ ${existing ?? ""}
|
|
|
17221
17473
|
${generated}`
|
|
17222
17474
|
};
|
|
17223
17475
|
}
|
|
17224
|
-
await mkdir2(
|
|
17476
|
+
await mkdir2(path34.dirname(dest.path), { recursive: true });
|
|
17225
17477
|
await writeFile2(dest.path, generated, "utf-8");
|
|
17226
17478
|
return {
|
|
17227
17479
|
written: true,
|
|
@@ -17239,8 +17491,8 @@ var init_codex2 = __esm({
|
|
|
17239
17491
|
|
|
17240
17492
|
// packages/agents/dist/projection/gemini.js
|
|
17241
17493
|
import { mkdir as mkdir3, readFile as readFile3, writeFile as writeFile3 } from "fs/promises";
|
|
17242
|
-
import
|
|
17243
|
-
import
|
|
17494
|
+
import path35 from "path";
|
|
17495
|
+
import os11 from "os";
|
|
17244
17496
|
function renderMarkdown2(source) {
|
|
17245
17497
|
const skillSections = source.skills.map((s) => `## Skill: ${s.name}
|
|
17246
17498
|
|
|
@@ -17264,7 +17516,7 @@ function createGeminiEmitter() {
|
|
|
17264
17516
|
destinations(scope, projectRoot) {
|
|
17265
17517
|
if (scope === "user") {
|
|
17266
17518
|
return [{
|
|
17267
|
-
path:
|
|
17519
|
+
path: path35.join(os11.homedir(), ".gemini/GEMINI.md"),
|
|
17268
17520
|
shared: true,
|
|
17269
17521
|
format: "markdown"
|
|
17270
17522
|
}];
|
|
@@ -17272,7 +17524,7 @@ function createGeminiEmitter() {
|
|
|
17272
17524
|
if (!projectRoot)
|
|
17273
17525
|
return [];
|
|
17274
17526
|
return [{
|
|
17275
|
-
path:
|
|
17527
|
+
path: path35.join(projectRoot, "GEMINI.md"),
|
|
17276
17528
|
shared: true,
|
|
17277
17529
|
format: "markdown"
|
|
17278
17530
|
}];
|
|
@@ -17293,7 +17545,7 @@ ${existing ?? ""}
|
|
|
17293
17545
|
${generated}`
|
|
17294
17546
|
};
|
|
17295
17547
|
}
|
|
17296
|
-
await mkdir3(
|
|
17548
|
+
await mkdir3(path35.dirname(dest.path), { recursive: true });
|
|
17297
17549
|
await writeFile3(dest.path, generated, "utf-8");
|
|
17298
17550
|
return {
|
|
17299
17551
|
written: true,
|
|
@@ -17311,8 +17563,8 @@ var init_gemini2 = __esm({
|
|
|
17311
17563
|
|
|
17312
17564
|
// packages/agents/dist/projection/opencode.js
|
|
17313
17565
|
import { mkdir as mkdir4, readFile as readFile4, writeFile as writeFile4 } from "fs/promises";
|
|
17314
|
-
import
|
|
17315
|
-
import
|
|
17566
|
+
import path36 from "path";
|
|
17567
|
+
import os12 from "os";
|
|
17316
17568
|
function renderMarkdown3(source) {
|
|
17317
17569
|
const skillSections = source.skills.map((s) => `## Skill: ${s.name}
|
|
17318
17570
|
|
|
@@ -17336,7 +17588,7 @@ function createOpencodeEmitter() {
|
|
|
17336
17588
|
destinations(scope, projectRoot) {
|
|
17337
17589
|
if (scope === "user") {
|
|
17338
17590
|
return [{
|
|
17339
|
-
path:
|
|
17591
|
+
path: path36.join(os12.homedir(), ".config", "opencode", "AGENTS.md"),
|
|
17340
17592
|
shared: true,
|
|
17341
17593
|
format: "markdown"
|
|
17342
17594
|
}];
|
|
@@ -17344,7 +17596,7 @@ function createOpencodeEmitter() {
|
|
|
17344
17596
|
if (!projectRoot)
|
|
17345
17597
|
return [];
|
|
17346
17598
|
return [{
|
|
17347
|
-
path:
|
|
17599
|
+
path: path36.join(projectRoot, "AGENTS.md"),
|
|
17348
17600
|
shared: true,
|
|
17349
17601
|
format: "markdown"
|
|
17350
17602
|
}];
|
|
@@ -17365,7 +17617,7 @@ ${existing ?? ""}
|
|
|
17365
17617
|
${generated}`
|
|
17366
17618
|
};
|
|
17367
17619
|
}
|
|
17368
|
-
await mkdir4(
|
|
17620
|
+
await mkdir4(path36.dirname(dest.path), { recursive: true });
|
|
17369
17621
|
await writeFile4(dest.path, generated, "utf-8");
|
|
17370
17622
|
return {
|
|
17371
17623
|
written: true,
|
|
@@ -17382,12 +17634,12 @@ var init_opencode2 = __esm({
|
|
|
17382
17634
|
});
|
|
17383
17635
|
|
|
17384
17636
|
// packages/agents/dist/projection/opencode-skills.js
|
|
17385
|
-
import
|
|
17386
|
-
import
|
|
17387
|
-
import
|
|
17637
|
+
import fs33 from "fs";
|
|
17638
|
+
import os13 from "os";
|
|
17639
|
+
import path37 from "path";
|
|
17388
17640
|
function defaultOpencodeSkillsRoot(env = process.env) {
|
|
17389
|
-
const configHome = env.XDG_CONFIG_HOME ||
|
|
17390
|
-
return
|
|
17641
|
+
const configHome = env.XDG_CONFIG_HOME || path37.join(os13.homedir(), ".config");
|
|
17642
|
+
return path37.join(configHome, "opencode", "skills");
|
|
17391
17643
|
}
|
|
17392
17644
|
function parseSkillName(raw) {
|
|
17393
17645
|
const fm = raw.match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
|
@@ -17401,62 +17653,62 @@ function parseSkillName(raw) {
|
|
|
17401
17653
|
}
|
|
17402
17654
|
function listSourceSkills(sourceSkillsDir) {
|
|
17403
17655
|
const out = /* @__PURE__ */ new Map();
|
|
17404
|
-
if (!
|
|
17656
|
+
if (!fs33.existsSync(sourceSkillsDir))
|
|
17405
17657
|
return out;
|
|
17406
|
-
for (const entry of
|
|
17658
|
+
for (const entry of fs33.readdirSync(sourceSkillsDir, { withFileTypes: true })) {
|
|
17407
17659
|
if (!entry.isDirectory())
|
|
17408
17660
|
continue;
|
|
17409
|
-
const skillPath =
|
|
17410
|
-
if (!
|
|
17661
|
+
const skillPath = path37.join(sourceSkillsDir, entry.name, "SKILL.md");
|
|
17662
|
+
if (!fs33.existsSync(skillPath))
|
|
17411
17663
|
continue;
|
|
17412
|
-
const name = parseSkillName(
|
|
17664
|
+
const name = parseSkillName(fs33.readFileSync(skillPath, "utf-8"));
|
|
17413
17665
|
if (name && SAFE_NAME.test(name))
|
|
17414
17666
|
out.set(name, skillPath);
|
|
17415
17667
|
}
|
|
17416
17668
|
return out;
|
|
17417
17669
|
}
|
|
17418
17670
|
function hasMarker(dir) {
|
|
17419
|
-
return
|
|
17671
|
+
return fs33.existsSync(path37.join(dir, OPENCODE_SKILL_MARKER));
|
|
17420
17672
|
}
|
|
17421
17673
|
function syncOpencodeSkills(opts) {
|
|
17422
17674
|
const result = { written: [], unchanged: [], removed: [], skipped: [] };
|
|
17423
17675
|
const wanted = listSourceSkills(opts.sourceSkillsDir);
|
|
17424
|
-
if (wanted.size === 0 && !
|
|
17676
|
+
if (wanted.size === 0 && !fs33.existsSync(opts.sourceSkillsDir))
|
|
17425
17677
|
return result;
|
|
17426
17678
|
if (!opts.dryRun)
|
|
17427
|
-
|
|
17679
|
+
fs33.mkdirSync(opts.skillsRoot, { recursive: true });
|
|
17428
17680
|
for (const [name, srcPath] of wanted) {
|
|
17429
|
-
const targetDir =
|
|
17430
|
-
const targetSkill =
|
|
17681
|
+
const targetDir = path37.join(opts.skillsRoot, name);
|
|
17682
|
+
const targetSkill = path37.join(targetDir, "SKILL.md");
|
|
17431
17683
|
const managed = hasMarker(targetDir);
|
|
17432
|
-
if (
|
|
17684
|
+
if (fs33.existsSync(targetSkill) && !managed) {
|
|
17433
17685
|
result.skipped.push({ name, reason: "foreign-collision" });
|
|
17434
17686
|
continue;
|
|
17435
17687
|
}
|
|
17436
|
-
const current =
|
|
17437
|
-
if (current && current.equals(
|
|
17688
|
+
const current = fs33.existsSync(targetSkill) ? fs33.readFileSync(targetSkill) : null;
|
|
17689
|
+
if (current && current.equals(fs33.readFileSync(srcPath))) {
|
|
17438
17690
|
if (!managed && !opts.dryRun) {
|
|
17439
|
-
|
|
17691
|
+
fs33.writeFileSync(path37.join(targetDir, OPENCODE_SKILL_MARKER), MARKER_BODY);
|
|
17440
17692
|
}
|
|
17441
17693
|
result.unchanged.push(name);
|
|
17442
17694
|
continue;
|
|
17443
17695
|
}
|
|
17444
17696
|
if (!opts.dryRun) {
|
|
17445
|
-
|
|
17446
|
-
|
|
17447
|
-
|
|
17697
|
+
fs33.mkdirSync(targetDir, { recursive: true });
|
|
17698
|
+
fs33.copyFileSync(srcPath, targetSkill);
|
|
17699
|
+
fs33.writeFileSync(path37.join(targetDir, OPENCODE_SKILL_MARKER), MARKER_BODY);
|
|
17448
17700
|
}
|
|
17449
17701
|
result.written.push(name);
|
|
17450
17702
|
}
|
|
17451
|
-
if (
|
|
17452
|
-
for (const entry of
|
|
17703
|
+
if (fs33.existsSync(opts.skillsRoot)) {
|
|
17704
|
+
for (const entry of fs33.readdirSync(opts.skillsRoot, { withFileTypes: true })) {
|
|
17453
17705
|
if (!entry.isDirectory() || wanted.has(entry.name))
|
|
17454
17706
|
continue;
|
|
17455
|
-
const dir =
|
|
17707
|
+
const dir = path37.join(opts.skillsRoot, entry.name);
|
|
17456
17708
|
if (!hasMarker(dir))
|
|
17457
17709
|
continue;
|
|
17458
17710
|
if (!opts.dryRun)
|
|
17459
|
-
|
|
17711
|
+
fs33.rmSync(dir, { recursive: true, force: true });
|
|
17460
17712
|
result.removed.push(entry.name);
|
|
17461
17713
|
}
|
|
17462
17714
|
}
|
|
@@ -17464,7 +17716,7 @@ function syncOpencodeSkills(opts) {
|
|
|
17464
17716
|
}
|
|
17465
17717
|
function syncShippedOpencodeSkills(opts) {
|
|
17466
17718
|
return syncOpencodeSkills({
|
|
17467
|
-
sourceSkillsDir:
|
|
17719
|
+
sourceSkillsDir: path37.join(opts.pkgRoot, "plugin", "skills"),
|
|
17468
17720
|
skillsRoot: opts.skillsRoot ?? defaultOpencodeSkillsRoot(),
|
|
17469
17721
|
dryRun: opts.dryRun
|
|
17470
17722
|
});
|
|
@@ -17480,8 +17732,8 @@ var init_opencode_skills = __esm({
|
|
|
17480
17732
|
|
|
17481
17733
|
// packages/agents/dist/projection/claude.js
|
|
17482
17734
|
import { mkdir as mkdir5, readFile as readFile5, writeFile as writeFile5 } from "fs/promises";
|
|
17483
|
-
import
|
|
17484
|
-
import
|
|
17735
|
+
import path38 from "path";
|
|
17736
|
+
import os14 from "os";
|
|
17485
17737
|
function renderMarkdown4(source) {
|
|
17486
17738
|
const skillSections = source.skills.map((s) => `## Skill: ${s.name}
|
|
17487
17739
|
|
|
@@ -17505,7 +17757,7 @@ function createClaudeEmitter() {
|
|
|
17505
17757
|
destinations(scope, projectRoot) {
|
|
17506
17758
|
if (scope === "user") {
|
|
17507
17759
|
return [{
|
|
17508
|
-
path:
|
|
17760
|
+
path: path38.join(os14.homedir(), ".claude/CLAUDE.md"),
|
|
17509
17761
|
shared: true,
|
|
17510
17762
|
format: "markdown"
|
|
17511
17763
|
}];
|
|
@@ -17513,7 +17765,7 @@ function createClaudeEmitter() {
|
|
|
17513
17765
|
if (!projectRoot)
|
|
17514
17766
|
return [];
|
|
17515
17767
|
return [{
|
|
17516
|
-
path:
|
|
17768
|
+
path: path38.join(projectRoot, "CLAUDE.md"),
|
|
17517
17769
|
shared: true,
|
|
17518
17770
|
format: "markdown"
|
|
17519
17771
|
}];
|
|
@@ -17534,7 +17786,7 @@ ${existing ?? ""}
|
|
|
17534
17786
|
${generated}`
|
|
17535
17787
|
};
|
|
17536
17788
|
}
|
|
17537
|
-
await mkdir5(
|
|
17789
|
+
await mkdir5(path38.dirname(dest.path), { recursive: true });
|
|
17538
17790
|
await writeFile5(dest.path, generated, "utf-8");
|
|
17539
17791
|
return {
|
|
17540
17792
|
written: true,
|
|
@@ -18569,8 +18821,8 @@ function resolveLastAssistantText(payload) {
|
|
|
18569
18821
|
const derived = deriveTranscriptPath(p?.session_id, cwd);
|
|
18570
18822
|
if (derived)
|
|
18571
18823
|
candidates.push(derived);
|
|
18572
|
-
for (const
|
|
18573
|
-
const text = readLastAssistantText(
|
|
18824
|
+
for (const path60 of candidates) {
|
|
18825
|
+
const text = readLastAssistantText(path60);
|
|
18574
18826
|
if (text != null)
|
|
18575
18827
|
return text;
|
|
18576
18828
|
}
|
|
@@ -19459,22 +19711,22 @@ var init_receipt_listener = __esm({
|
|
|
19459
19711
|
});
|
|
19460
19712
|
|
|
19461
19713
|
// packages/agents/dist/claude/api-key-approval.js
|
|
19462
|
-
import
|
|
19463
|
-
import
|
|
19464
|
-
import
|
|
19714
|
+
import fs34 from "fs";
|
|
19715
|
+
import os15 from "os";
|
|
19716
|
+
import path39 from "path";
|
|
19465
19717
|
function ensureClaudeApiKeyApproved(apiKey, opts = {}) {
|
|
19466
19718
|
const suffix = apiKey.slice(-20);
|
|
19467
19719
|
if (!suffix)
|
|
19468
19720
|
return { changed: false, reason: "empty api key" };
|
|
19469
|
-
const file = opts.claudeJsonPath ??
|
|
19721
|
+
const file = opts.claudeJsonPath ?? path39.join(os15.homedir(), ".claude.json");
|
|
19470
19722
|
const log = opts.log ?? (() => {
|
|
19471
19723
|
});
|
|
19472
|
-
if (!
|
|
19724
|
+
if (!fs34.existsSync(file)) {
|
|
19473
19725
|
return { changed: false, reason: "no ~/.claude.json yet \u2014 skipping routed-key pre-approval" };
|
|
19474
19726
|
}
|
|
19475
19727
|
let doc;
|
|
19476
19728
|
try {
|
|
19477
|
-
doc = JSON.parse(
|
|
19729
|
+
doc = JSON.parse(fs34.readFileSync(file, "utf8"));
|
|
19478
19730
|
} catch {
|
|
19479
19731
|
return {
|
|
19480
19732
|
changed: false,
|
|
@@ -19496,11 +19748,11 @@ function ensureClaudeApiKeyApproved(apiKey, opts = {}) {
|
|
|
19496
19748
|
};
|
|
19497
19749
|
const tmp = `${file}.squadrant-tmp`;
|
|
19498
19750
|
try {
|
|
19499
|
-
|
|
19500
|
-
|
|
19751
|
+
fs34.writeFileSync(tmp, JSON.stringify(doc, null, 2) + "\n", { mode: fs34.statSync(file).mode & 511 });
|
|
19752
|
+
fs34.renameSync(tmp, file);
|
|
19501
19753
|
} catch (e) {
|
|
19502
19754
|
try {
|
|
19503
|
-
|
|
19755
|
+
fs34.unlinkSync(tmp);
|
|
19504
19756
|
} catch {
|
|
19505
19757
|
}
|
|
19506
19758
|
return {
|
|
@@ -19609,10 +19861,10 @@ var init_http_channel = __esm({
|
|
|
19609
19861
|
return cached;
|
|
19610
19862
|
const directory = this.directoryFor?.(taskId);
|
|
19611
19863
|
const createdAfterMs = this.createdAfterFor?.(taskId);
|
|
19612
|
-
for (const
|
|
19864
|
+
for (const path60 of ["/session?", "/api/session?"]) {
|
|
19613
19865
|
let res;
|
|
19614
19866
|
try {
|
|
19615
|
-
res = await this.request(`http://127.0.0.1:${port}${
|
|
19867
|
+
res = await this.request(`http://127.0.0.1:${port}${path60}`, { method: "GET" });
|
|
19616
19868
|
} catch {
|
|
19617
19869
|
return void 0;
|
|
19618
19870
|
}
|
|
@@ -19692,12 +19944,12 @@ var init_fact_adapter = __esm({
|
|
|
19692
19944
|
});
|
|
19693
19945
|
|
|
19694
19946
|
// packages/agents/dist/rules-hooks/install.js
|
|
19695
|
-
import
|
|
19696
|
-
import
|
|
19697
|
-
import
|
|
19947
|
+
import fs35 from "fs";
|
|
19948
|
+
import os16 from "os";
|
|
19949
|
+
import path40 from "path";
|
|
19698
19950
|
function readJson(file) {
|
|
19699
19951
|
try {
|
|
19700
|
-
const v2 = JSON.parse(
|
|
19952
|
+
const v2 = JSON.parse(fs35.readFileSync(file, "utf8"));
|
|
19701
19953
|
return typeof v2 === "object" && v2 !== null && !Array.isArray(v2) ? v2 : {};
|
|
19702
19954
|
} catch (err) {
|
|
19703
19955
|
if (err.code === "ENOENT")
|
|
@@ -19719,24 +19971,24 @@ function mergeHooks(root, agent, specs, cli, timeout) {
|
|
|
19719
19971
|
function writeIfChanged(file, next, dryRun) {
|
|
19720
19972
|
let prev = null;
|
|
19721
19973
|
try {
|
|
19722
|
-
prev =
|
|
19974
|
+
prev = fs35.readFileSync(file, "utf8");
|
|
19723
19975
|
} catch {
|
|
19724
19976
|
}
|
|
19725
19977
|
const changed = prev !== next;
|
|
19726
19978
|
if (changed && !dryRun) {
|
|
19727
|
-
|
|
19728
|
-
|
|
19979
|
+
fs35.mkdirSync(path40.dirname(file), { recursive: true });
|
|
19980
|
+
fs35.writeFileSync(file, next);
|
|
19729
19981
|
}
|
|
19730
19982
|
return { path: file, changed };
|
|
19731
19983
|
}
|
|
19732
19984
|
function installCodexRulesHooks(opts = {}) {
|
|
19733
19985
|
const env = opts.env ?? process.env;
|
|
19734
|
-
const file = opts.target ??
|
|
19986
|
+
const file = opts.target ?? path40.join(env.CODEX_HOME ?? path40.join(os16.homedir(), ".codex"), "hooks.json");
|
|
19735
19987
|
const merged = mergeHooks(readJson(file), "codex", CODEX_HOOKS, opts.cli ?? "squadrant", 5);
|
|
19736
19988
|
return writeIfChanged(file, JSON.stringify(merged, null, 2) + "\n", opts.dryRun);
|
|
19737
19989
|
}
|
|
19738
19990
|
function installGeminiRulesHooks(opts = {}) {
|
|
19739
|
-
const file = opts.target ??
|
|
19991
|
+
const file = opts.target ?? path40.join(os16.homedir(), ".gemini", "settings.json");
|
|
19740
19992
|
const merged = mergeHooks(readJson(file), "gemini", GEMINI_HOOKS, opts.cli ?? "squadrant", 5e3);
|
|
19741
19993
|
return writeIfChanged(file, JSON.stringify(merged, null, 2) + "\n", opts.dryRun);
|
|
19742
19994
|
}
|
|
@@ -19777,9 +20029,9 @@ export const SquadrantRules = async ({ directory }) => {
|
|
|
19777
20029
|
}
|
|
19778
20030
|
function installOpencodeRulesHooks(opts = {}) {
|
|
19779
20031
|
const env = opts.env ?? process.env;
|
|
19780
|
-
const file = opts.target ??
|
|
20032
|
+
const file = opts.target ?? path40.join(env.XDG_CONFIG_HOME || path40.join(os16.homedir(), ".config"), "opencode", "plugin", "squadrant-rules.js");
|
|
19781
20033
|
try {
|
|
19782
|
-
if (!
|
|
20034
|
+
if (!fs35.readFileSync(file, "utf8").startsWith(OPENCODE_PLUGIN_MARKER))
|
|
19783
20035
|
return { path: file, changed: false, skipped: "foreign-file" };
|
|
19784
20036
|
} catch {
|
|
19785
20037
|
}
|
|
@@ -19908,12 +20160,12 @@ var init_dist3 = __esm({
|
|
|
19908
20160
|
});
|
|
19909
20161
|
|
|
19910
20162
|
// packages/workspaces/dist/runtimes/cmux.js
|
|
19911
|
-
import { execFile as execFile3, execFileSync as
|
|
20163
|
+
import { execFile as execFile3, execFileSync as execFileSync9 } from "child_process";
|
|
19912
20164
|
function isInsideCmux() {
|
|
19913
20165
|
return !!process.env.CMUX_WORKSPACE_ID;
|
|
19914
20166
|
}
|
|
19915
20167
|
function cmuxLocal(args) {
|
|
19916
|
-
return
|
|
20168
|
+
return execFileSync9(resolveCmuxBin(), args, {
|
|
19917
20169
|
encoding: "utf-8",
|
|
19918
20170
|
stdio: ["ignore", "pipe", "pipe"],
|
|
19919
20171
|
timeout: CMUX_TIMEOUT
|
|
@@ -20679,14 +20931,14 @@ var init_runtimes = __esm({
|
|
|
20679
20931
|
});
|
|
20680
20932
|
|
|
20681
20933
|
// packages/workspaces/dist/notifiers/cmux.js
|
|
20682
|
-
import { execFile as execFileCb, execFileSync as
|
|
20934
|
+
import { execFile as execFileCb, execFileSync as execFileSync10 } from "child_process";
|
|
20683
20935
|
import { promisify as promisify3 } from "util";
|
|
20684
20936
|
function createCmuxNotifier(_scope) {
|
|
20685
20937
|
return {
|
|
20686
20938
|
name: "cmux",
|
|
20687
20939
|
async probe() {
|
|
20688
20940
|
try {
|
|
20689
|
-
|
|
20941
|
+
execFileSync10(resolveCmuxBin(), ["capabilities"], { encoding: "utf-8", stdio: "pipe", timeout: CMUX_TIMEOUT });
|
|
20690
20942
|
return { installed: true, reachable: true };
|
|
20691
20943
|
} catch (err) {
|
|
20692
20944
|
const code = err.code;
|
|
@@ -20755,13 +21007,13 @@ var init_notifiers = __esm({
|
|
|
20755
21007
|
});
|
|
20756
21008
|
|
|
20757
21009
|
// packages/workspaces/dist/workspaces/obsidian.js
|
|
20758
|
-
import
|
|
21010
|
+
import fs36 from "fs/promises";
|
|
20759
21011
|
import { existsSync as existsSync11 } from "fs";
|
|
20760
|
-
import
|
|
21012
|
+
import path41 from "path";
|
|
20761
21013
|
function resolveInRoot(root, relative) {
|
|
20762
|
-
const joined =
|
|
20763
|
-
const normalized2 =
|
|
20764
|
-
if (joined !==
|
|
21014
|
+
const joined = path41.resolve(root, relative);
|
|
21015
|
+
const normalized2 = path41.resolve(root) + path41.sep;
|
|
21016
|
+
if (joined !== path41.resolve(root) && !joined.startsWith(normalized2)) {
|
|
20765
21017
|
throw new Error(`Path '${relative}' escapes workspace root`);
|
|
20766
21018
|
}
|
|
20767
21019
|
return joined;
|
|
@@ -20780,16 +21032,16 @@ function createObsidianDriver(scope) {
|
|
|
20780
21032
|
};
|
|
20781
21033
|
},
|
|
20782
21034
|
async read(rel) {
|
|
20783
|
-
return
|
|
21035
|
+
return fs36.readFile(resolveInRoot(root, rel), "utf-8");
|
|
20784
21036
|
},
|
|
20785
21037
|
async write(rel, content) {
|
|
20786
21038
|
const abs = resolveInRoot(root, rel);
|
|
20787
|
-
await
|
|
20788
|
-
await
|
|
21039
|
+
await fs36.mkdir(path41.dirname(abs), { recursive: true });
|
|
21040
|
+
await fs36.writeFile(abs, content);
|
|
20789
21041
|
},
|
|
20790
21042
|
async exists(rel) {
|
|
20791
21043
|
try {
|
|
20792
|
-
await
|
|
21044
|
+
await fs36.access(resolveInRoot(root, rel));
|
|
20793
21045
|
return true;
|
|
20794
21046
|
} catch {
|
|
20795
21047
|
return false;
|
|
@@ -20797,13 +21049,13 @@ function createObsidianDriver(scope) {
|
|
|
20797
21049
|
},
|
|
20798
21050
|
async list(rel) {
|
|
20799
21051
|
try {
|
|
20800
|
-
return await
|
|
21052
|
+
return await fs36.readdir(resolveInRoot(root, rel));
|
|
20801
21053
|
} catch {
|
|
20802
21054
|
return [];
|
|
20803
21055
|
}
|
|
20804
21056
|
},
|
|
20805
21057
|
async mkdir(rel) {
|
|
20806
|
-
await
|
|
21058
|
+
await fs36.mkdir(resolveInRoot(root, rel), { recursive: true });
|
|
20807
21059
|
}
|
|
20808
21060
|
};
|
|
20809
21061
|
}
|
|
@@ -21012,9 +21264,9 @@ var init_events_bridge = __esm({
|
|
|
21012
21264
|
});
|
|
21013
21265
|
|
|
21014
21266
|
// packages/workspaces/dist/cmux-daemon/store-fingerprint.js
|
|
21015
|
-
import { execFileSync as
|
|
21267
|
+
import { execFileSync as execFileSync11 } from "child_process";
|
|
21016
21268
|
function defaultExecPs(pid) {
|
|
21017
|
-
return
|
|
21269
|
+
return execFileSync11("ps", ["-o", "command=", "-p", String(pid)], {
|
|
21018
21270
|
encoding: "utf-8",
|
|
21019
21271
|
stdio: ["ignore", "pipe", "ignore"]
|
|
21020
21272
|
});
|
|
@@ -21217,9 +21469,9 @@ function defaultListFiles(dir) {
|
|
|
21217
21469
|
return [];
|
|
21218
21470
|
}
|
|
21219
21471
|
}
|
|
21220
|
-
function defaultReadFile(
|
|
21472
|
+
function defaultReadFile(path60) {
|
|
21221
21473
|
try {
|
|
21222
|
-
return readFileSync17(
|
|
21474
|
+
return readFileSync17(path60, "utf-8");
|
|
21223
21475
|
} catch {
|
|
21224
21476
|
return void 0;
|
|
21225
21477
|
}
|
|
@@ -21712,16 +21964,16 @@ function extractDetail(sub, payload) {
|
|
|
21712
21964
|
}
|
|
21713
21965
|
return void 0;
|
|
21714
21966
|
}
|
|
21715
|
-
function defaultReadFile2(
|
|
21967
|
+
function defaultReadFile2(path60) {
|
|
21716
21968
|
try {
|
|
21717
|
-
return readFileSync18(
|
|
21969
|
+
return readFileSync18(path60, "utf-8");
|
|
21718
21970
|
} catch {
|
|
21719
21971
|
return void 0;
|
|
21720
21972
|
}
|
|
21721
21973
|
}
|
|
21722
|
-
function defaultWriteFile(
|
|
21723
|
-
mkdirSync8(
|
|
21724
|
-
writeFileSync11(
|
|
21974
|
+
function defaultWriteFile(path60, content) {
|
|
21975
|
+
mkdirSync8(path60.replace(/\/[^/]+$/, ""), { recursive: true });
|
|
21976
|
+
writeFileSync11(path60, content, "utf-8");
|
|
21725
21977
|
}
|
|
21726
21978
|
var CLAUDE_HOOK_EVENTS, DEFAULT_CLI_CMD, FOREIGN_AUTO_GATE_MARKER, SUBAGENT_MODEL_KEY, SMALL_FAST_MODEL_KEY, NativeHookSource;
|
|
21727
21979
|
var init_native_hook_source = __esm({
|
|
@@ -22293,9 +22545,9 @@ init_dist();
|
|
|
22293
22545
|
init_dist4();
|
|
22294
22546
|
import { Command } from "commander";
|
|
22295
22547
|
import { execSync as execSync7 } from "child_process";
|
|
22296
|
-
import
|
|
22548
|
+
import fs37 from "fs";
|
|
22297
22549
|
import { stat } from "fs/promises";
|
|
22298
|
-
import
|
|
22550
|
+
import path42 from "path";
|
|
22299
22551
|
import chalk3 from "chalk";
|
|
22300
22552
|
|
|
22301
22553
|
// packages/cli/src/commands/health-view.ts
|
|
@@ -22397,7 +22649,7 @@ function settingsHaveAgentTeams() {
|
|
|
22397
22649
|
try {
|
|
22398
22650
|
const home = process.env.HOME || "";
|
|
22399
22651
|
const settings = JSON.parse(
|
|
22400
|
-
|
|
22652
|
+
fs37.readFileSync(`${home}/.claude/settings.json`, "utf-8")
|
|
22401
22653
|
);
|
|
22402
22654
|
return settings?.env?.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS === "1";
|
|
22403
22655
|
} catch {
|
|
@@ -22408,7 +22660,7 @@ function pluginInstalled(pluginKey) {
|
|
|
22408
22660
|
try {
|
|
22409
22661
|
const home = process.env.HOME || "";
|
|
22410
22662
|
const plugins = JSON.parse(
|
|
22411
|
-
|
|
22663
|
+
fs37.readFileSync(
|
|
22412
22664
|
`${home}/.claude/plugins/installed_plugins.json`,
|
|
22413
22665
|
"utf-8"
|
|
22414
22666
|
)
|
|
@@ -22432,9 +22684,9 @@ function tryGetVersion(cmd) {
|
|
|
22432
22684
|
}
|
|
22433
22685
|
function candidateGlobalInstalls(roots) {
|
|
22434
22686
|
const out = [];
|
|
22435
|
-
if (roots.npm) out.push({ manager: "npm", packageJsonPath:
|
|
22436
|
-
if (roots.pnpm) out.push({ manager: "pnpm", packageJsonPath:
|
|
22437
|
-
if (roots.yarn) out.push({ manager: "yarn", packageJsonPath:
|
|
22687
|
+
if (roots.npm) out.push({ manager: "npm", packageJsonPath: path42.join(roots.npm, "squadrant", "package.json") });
|
|
22688
|
+
if (roots.pnpm) out.push({ manager: "pnpm", packageJsonPath: path42.join(roots.pnpm, "squadrant", "package.json") });
|
|
22689
|
+
if (roots.yarn) out.push({ manager: "yarn", packageJsonPath: path42.join(roots.yarn, "node_modules", "squadrant", "package.json") });
|
|
22438
22690
|
return out;
|
|
22439
22691
|
}
|
|
22440
22692
|
function findInstalledSquadrants(candidates, readVersion) {
|
|
@@ -22454,7 +22706,7 @@ ${lines.join("\n")}
|
|
|
22454
22706
|
}
|
|
22455
22707
|
function readPackageVersion(packageJsonPath) {
|
|
22456
22708
|
try {
|
|
22457
|
-
const pkg2 = JSON.parse(
|
|
22709
|
+
const pkg2 = JSON.parse(fs37.readFileSync(packageJsonPath, "utf-8"));
|
|
22458
22710
|
return typeof pkg2.version === "string" ? pkg2.version : null;
|
|
22459
22711
|
} catch {
|
|
22460
22712
|
return null;
|
|
@@ -22537,7 +22789,7 @@ var doctorCommand = new Command("doctor").description("Check system health and p
|
|
|
22537
22789
|
));
|
|
22538
22790
|
checkOptional(
|
|
22539
22791
|
"Obsidian installed",
|
|
22540
|
-
commandExists("obsidian") ||
|
|
22792
|
+
commandExists("obsidian") || fs37.existsSync("/Applications/Obsidian.app"),
|
|
22541
22793
|
"viewer for the hub vault; the vault is plain Markdown",
|
|
22542
22794
|
"Install from: https://obsidian.md"
|
|
22543
22795
|
);
|
|
@@ -22634,7 +22886,7 @@ var doctorCommand = new Command("doctor").description("Check system health and p
|
|
|
22634
22886
|
const emitter = projectionRegistry.get(name);
|
|
22635
22887
|
const [userDest] = emitter.destinations("user");
|
|
22636
22888
|
if (!userDest) continue;
|
|
22637
|
-
const dir =
|
|
22889
|
+
const dir = path42.dirname(userDest.path);
|
|
22638
22890
|
let status;
|
|
22639
22891
|
try {
|
|
22640
22892
|
await stat(dir);
|
|
@@ -22655,7 +22907,7 @@ var doctorCommand = new Command("doctor").description("Check system health and p
|
|
|
22655
22907
|
results.push(
|
|
22656
22908
|
check(
|
|
22657
22909
|
"Squadrant config exists",
|
|
22658
|
-
|
|
22910
|
+
fs37.existsSync(
|
|
22659
22911
|
process.env.SQUADRANT_CONFIG || `${process.env.HOME}/.config/squadrant/config.json`
|
|
22660
22912
|
),
|
|
22661
22913
|
"Run: squadrant init"
|
|
@@ -22739,9 +22991,9 @@ init_dist();
|
|
|
22739
22991
|
init_dist4();
|
|
22740
22992
|
init_dist();
|
|
22741
22993
|
import { Command as Command2 } from "commander";
|
|
22742
|
-
import
|
|
22743
|
-
import
|
|
22744
|
-
import
|
|
22994
|
+
import fs38 from "fs";
|
|
22995
|
+
import path43 from "path";
|
|
22996
|
+
import os17 from "os";
|
|
22745
22997
|
import readline from "readline";
|
|
22746
22998
|
import chalk4 from "chalk";
|
|
22747
22999
|
|
|
@@ -22991,22 +23243,22 @@ function detectClaudeAuth(probe = {}) {
|
|
|
22991
23243
|
// packages/cli/src/commands/init.ts
|
|
22992
23244
|
init_dist3();
|
|
22993
23245
|
function findPackageRoot() {
|
|
22994
|
-
let dir =
|
|
23246
|
+
let dir = path43.dirname(new URL(import.meta.url).pathname);
|
|
22995
23247
|
while (dir !== "/") {
|
|
22996
|
-
if (
|
|
22997
|
-
dir =
|
|
23248
|
+
if (fs38.existsSync(path43.join(dir, "package.json"))) return dir;
|
|
23249
|
+
dir = path43.dirname(dir);
|
|
22998
23250
|
}
|
|
22999
23251
|
return process.cwd();
|
|
23000
23252
|
}
|
|
23001
23253
|
function copyDirRecursive(src, dest) {
|
|
23002
|
-
|
|
23003
|
-
for (const entry of
|
|
23004
|
-
const srcPath =
|
|
23005
|
-
const destPath =
|
|
23254
|
+
fs38.mkdirSync(dest, { recursive: true });
|
|
23255
|
+
for (const entry of fs38.readdirSync(src, { withFileTypes: true })) {
|
|
23256
|
+
const srcPath = path43.join(src, entry.name);
|
|
23257
|
+
const destPath = path43.join(dest, entry.name);
|
|
23006
23258
|
if (entry.isDirectory()) {
|
|
23007
23259
|
copyDirRecursive(srcPath, destPath);
|
|
23008
23260
|
} else {
|
|
23009
|
-
|
|
23261
|
+
fs38.copyFileSync(srcPath, destPath);
|
|
23010
23262
|
}
|
|
23011
23263
|
}
|
|
23012
23264
|
}
|
|
@@ -23048,7 +23300,7 @@ function warnIfNoAnthropic(preset, auth) {
|
|
|
23048
23300
|
var initCommand = new Command2("init").description("Guided first-time setup: provider, hub vault, agents, plugins, projects (re-run-safe)").option("--hub <path>", "Hub vault path", "~/squadrant-hub").option("--preset <id>", "provider preset: a|b|c (non-interactive; d accepted as a deprecated alias for c)").action(async (opts) => {
|
|
23049
23301
|
const hubPath = resolveHome(opts.hub);
|
|
23050
23302
|
const pkgRoot = findPackageRoot();
|
|
23051
|
-
const configDir =
|
|
23303
|
+
const configDir = path43.join(os17.homedir(), ".config", "squadrant");
|
|
23052
23304
|
const isTTY = process.stdin.isTTY === true;
|
|
23053
23305
|
console.log(chalk4.bold("\nSquadrant Init\n"));
|
|
23054
23306
|
let explicitPreset;
|
|
@@ -23086,8 +23338,8 @@ var initCommand = new Command2("init").description("Guided first-time setup: pro
|
|
|
23086
23338
|
}
|
|
23087
23339
|
const wsRegistry = new WorkspaceRegistry({ obsidian: createObsidianDriver });
|
|
23088
23340
|
try {
|
|
23089
|
-
if (
|
|
23090
|
-
const existing = JSON.parse(
|
|
23341
|
+
if (fs38.existsSync(DEFAULT_CONFIG_PATH)) {
|
|
23342
|
+
const existing = JSON.parse(fs38.readFileSync(DEFAULT_CONFIG_PATH, "utf-8"));
|
|
23091
23343
|
wsRegistry.get(existing.workspace ?? "obsidian");
|
|
23092
23344
|
}
|
|
23093
23345
|
} catch (err) {
|
|
@@ -23095,7 +23347,7 @@ var initCommand = new Command2("init").description("Guided first-time setup: pro
|
|
|
23095
23347
|
return;
|
|
23096
23348
|
}
|
|
23097
23349
|
stepHeader(1, 5, "Hub vault");
|
|
23098
|
-
const configExists =
|
|
23350
|
+
const configExists = fs38.existsSync(DEFAULT_CONFIG_PATH);
|
|
23099
23351
|
let config;
|
|
23100
23352
|
if (configExists) {
|
|
23101
23353
|
console.log(chalk4.yellow(" \u26A0 Config already exists, skipping creation"));
|
|
@@ -23133,37 +23385,37 @@ var initCommand = new Command2("init").description("Guided first-time setup: pro
|
|
|
23133
23385
|
saveConfig(config);
|
|
23134
23386
|
console.log(chalk4.green(` \u2714 Config updated at ${DEFAULT_CONFIG_PATH}`));
|
|
23135
23387
|
}
|
|
23136
|
-
const hubTemplate =
|
|
23137
|
-
if (
|
|
23388
|
+
const hubTemplate = path43.join(pkgRoot, "obsidian", "hub");
|
|
23389
|
+
if (fs38.existsSync(hubPath)) {
|
|
23138
23390
|
console.log(chalk4.yellow(` \u26A0 Hub vault already exists at ${hubPath}`));
|
|
23139
|
-
} else if (
|
|
23391
|
+
} else if (fs38.existsSync(hubTemplate)) {
|
|
23140
23392
|
copyDirRecursive(hubTemplate, hubPath);
|
|
23141
23393
|
console.log(chalk4.green(` \u2714 Hub vault scaffolded at ${hubPath}`));
|
|
23142
23394
|
} else {
|
|
23143
|
-
|
|
23395
|
+
fs38.mkdirSync(hubPath, { recursive: true });
|
|
23144
23396
|
console.log(chalk4.yellow(` \u26A0 Hub template not found; created empty directory at ${hubPath}`));
|
|
23145
23397
|
}
|
|
23146
|
-
const hubDashboardSrc =
|
|
23147
|
-
const hubDashboardDest =
|
|
23148
|
-
if (
|
|
23149
|
-
|
|
23398
|
+
const hubDashboardSrc = path43.join(pkgRoot, "obsidian", "hub", "dashboard.md");
|
|
23399
|
+
const hubDashboardDest = path43.join(hubPath, "dashboard.md");
|
|
23400
|
+
if (fs38.existsSync(hubDashboardSrc)) {
|
|
23401
|
+
fs38.copyFileSync(hubDashboardSrc, hubDashboardDest);
|
|
23150
23402
|
console.log(chalk4.green(` \u2714 Dashboard refreshed`));
|
|
23151
23403
|
}
|
|
23152
|
-
|
|
23404
|
+
fs38.mkdirSync(path43.join(hubPath, "projects"), { recursive: true });
|
|
23153
23405
|
ensureRuntimeSynced({ sourceRoot: pkgRoot, runtimeRoot: configDir });
|
|
23154
23406
|
console.log(chalk4.green(` \u2714 Runtime assets synced to ${configDir}`));
|
|
23155
23407
|
stepHeader(2, 5, "Agent + projection setup");
|
|
23156
|
-
const settingsPath =
|
|
23408
|
+
const settingsPath = path43.join(os17.homedir(), ".claude", "settings.json");
|
|
23157
23409
|
try {
|
|
23158
23410
|
let settings = {};
|
|
23159
|
-
if (
|
|
23160
|
-
settings = JSON.parse(
|
|
23411
|
+
if (fs38.existsSync(settingsPath)) {
|
|
23412
|
+
settings = JSON.parse(fs38.readFileSync(settingsPath, "utf-8"));
|
|
23161
23413
|
}
|
|
23162
23414
|
const env = settings.env || {};
|
|
23163
23415
|
if (env.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS !== "1") {
|
|
23164
23416
|
settings.env = { ...env, CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS: "1" };
|
|
23165
|
-
|
|
23166
|
-
|
|
23417
|
+
fs38.mkdirSync(path43.dirname(settingsPath), { recursive: true });
|
|
23418
|
+
fs38.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
|
|
23167
23419
|
console.log(chalk4.green(" \u2714 Agent Teams enabled in ~/.claude/settings.json"));
|
|
23168
23420
|
} else {
|
|
23169
23421
|
console.log(chalk4.green(" \u2714 Agent Teams already enabled"));
|
|
@@ -23216,7 +23468,7 @@ var initCommand = new Command2("init").description("Guided first-time setup: pro
|
|
|
23216
23468
|
chalk4.cyan(" Absolute path to your first project (Enter to skip): ")
|
|
23217
23469
|
);
|
|
23218
23470
|
if (projectPath) {
|
|
23219
|
-
const projectName =
|
|
23471
|
+
const projectName = path43.basename(projectPath);
|
|
23220
23472
|
console.log(chalk4.bold(`
|
|
23221
23473
|
Run this to register it:`));
|
|
23222
23474
|
console.log(chalk4.cyan(` squadrant projects add ${projectName} ${projectPath}
|
|
@@ -23244,8 +23496,8 @@ var initCommand = new Command2("init").description("Guided first-time setup: pro
|
|
|
23244
23496
|
init_dist();
|
|
23245
23497
|
init_dist2();
|
|
23246
23498
|
import { Command as Command3 } from "commander";
|
|
23247
|
-
import
|
|
23248
|
-
import
|
|
23499
|
+
import fs39 from "fs";
|
|
23500
|
+
import path44 from "path";
|
|
23249
23501
|
import chalk5 from "chalk";
|
|
23250
23502
|
function restartAfterProjectsAdd(opts) {
|
|
23251
23503
|
const doRestart = opts.doRestart ?? restartDaemonIfRunning;
|
|
@@ -23257,22 +23509,22 @@ function restartAfterProjectsAdd(opts) {
|
|
|
23257
23509
|
}
|
|
23258
23510
|
}
|
|
23259
23511
|
function findPackageRoot2() {
|
|
23260
|
-
let dir =
|
|
23512
|
+
let dir = path44.dirname(new URL(import.meta.url).pathname);
|
|
23261
23513
|
while (dir !== "/") {
|
|
23262
|
-
if (
|
|
23263
|
-
dir =
|
|
23514
|
+
if (fs39.existsSync(path44.join(dir, "package.json"))) return dir;
|
|
23515
|
+
dir = path44.dirname(dir);
|
|
23264
23516
|
}
|
|
23265
23517
|
return process.cwd();
|
|
23266
23518
|
}
|
|
23267
23519
|
function copyDirRecursive2(src, dest) {
|
|
23268
|
-
|
|
23269
|
-
for (const entry of
|
|
23270
|
-
const srcPath =
|
|
23271
|
-
const destPath =
|
|
23520
|
+
fs39.mkdirSync(dest, { recursive: true });
|
|
23521
|
+
for (const entry of fs39.readdirSync(src, { withFileTypes: true })) {
|
|
23522
|
+
const srcPath = path44.join(src, entry.name);
|
|
23523
|
+
const destPath = path44.join(dest, entry.name);
|
|
23272
23524
|
if (entry.isDirectory()) {
|
|
23273
23525
|
copyDirRecursive2(srcPath, destPath);
|
|
23274
23526
|
} else {
|
|
23275
|
-
|
|
23527
|
+
fs39.copyFileSync(srcPath, destPath);
|
|
23276
23528
|
}
|
|
23277
23529
|
}
|
|
23278
23530
|
}
|
|
@@ -23308,7 +23560,7 @@ var addCmd = new Command3("add").description("Register a project").argument("<na
|
|
|
23308
23560
|
process.exit(1);
|
|
23309
23561
|
}
|
|
23310
23562
|
const resolvedPath = resolveHome(projectPath);
|
|
23311
|
-
if (!
|
|
23563
|
+
if (!fs39.existsSync(path44.join(resolvedPath, ".git"))) {
|
|
23312
23564
|
console.log(chalk5.yellow(`
|
|
23313
23565
|
\u26A0 No .git found at ${resolvedPath}. Make sure this is the project root, not a parent directory.
|
|
23314
23566
|
`));
|
|
@@ -23361,7 +23613,7 @@ var addCmd = new Command3("add").description("Register a project").argument("<na
|
|
|
23361
23613
|
\u26A0 Group '${group}' already has '${primary[0]}' as primary. Overriding.`));
|
|
23362
23614
|
}
|
|
23363
23615
|
}
|
|
23364
|
-
const spokeVault = opts.spoke ? resolveHome(opts.spoke) :
|
|
23616
|
+
const spokeVault = opts.spoke ? resolveHome(opts.spoke) : path44.join(config.hubVault, "spokes", name);
|
|
23365
23617
|
const project = {
|
|
23366
23618
|
path: resolvedPath,
|
|
23367
23619
|
captainName,
|
|
@@ -23376,20 +23628,20 @@ var addCmd = new Command3("add").description("Register a project").argument("<na
|
|
|
23376
23628
|
\u2714 Project '${name}' registered`));
|
|
23377
23629
|
restartAfterProjectsAdd({ noRestart: opts.restart === false });
|
|
23378
23630
|
const pkgRoot = findPackageRoot2();
|
|
23379
|
-
const spokeTemplate =
|
|
23380
|
-
if (
|
|
23631
|
+
const spokeTemplate = path44.join(pkgRoot, "obsidian", "spoke");
|
|
23632
|
+
if (fs39.existsSync(spokeVault)) {
|
|
23381
23633
|
console.log(chalk5.yellow(` \u26A0 Spoke vault already exists at ${spokeVault}, skipping scaffold`));
|
|
23382
|
-
} else if (
|
|
23634
|
+
} else if (fs39.existsSync(spokeTemplate)) {
|
|
23383
23635
|
copyDirRecursive2(spokeTemplate, spokeVault);
|
|
23384
|
-
const statusPath =
|
|
23385
|
-
if (
|
|
23386
|
-
const content =
|
|
23636
|
+
const statusPath = path44.join(spokeVault, "status.md");
|
|
23637
|
+
if (fs39.existsSync(statusPath)) {
|
|
23638
|
+
const content = fs39.readFileSync(statusPath, "utf-8");
|
|
23387
23639
|
const updated = content.replace(/^project: unnamed/m, `project: ${name}`);
|
|
23388
|
-
|
|
23640
|
+
fs39.writeFileSync(statusPath, updated);
|
|
23389
23641
|
}
|
|
23390
23642
|
console.log(chalk5.green(` \u2714 Spoke vault scaffolded at ${spokeVault}`));
|
|
23391
23643
|
} else {
|
|
23392
|
-
|
|
23644
|
+
fs39.mkdirSync(spokeVault, { recursive: true });
|
|
23393
23645
|
console.log(chalk5.yellow(` \u26A0 Spoke template not found; created empty dir at ${spokeVault}`));
|
|
23394
23646
|
}
|
|
23395
23647
|
console.log("");
|
|
@@ -23458,10 +23710,10 @@ init_dist3();
|
|
|
23458
23710
|
init_dist();
|
|
23459
23711
|
import { Command as Command5 } from "commander";
|
|
23460
23712
|
import { execSync as execSync9 } from "child_process";
|
|
23461
|
-
import
|
|
23462
|
-
import
|
|
23713
|
+
import path45 from "path";
|
|
23714
|
+
import os18 from "os";
|
|
23463
23715
|
import chalk7 from "chalk";
|
|
23464
|
-
var TEMPLATES_DIR2 =
|
|
23716
|
+
var TEMPLATES_DIR2 = path45.join(os18.homedir(), ".config", "squadrant", "templates");
|
|
23465
23717
|
var TASK_PROMPTS = {
|
|
23466
23718
|
briefing: "Run your daily briefing using the squadrant:command-ops skill. Read all spoke handoffs, yesterday's logs, current status; produce a concise cross-project briefing; save to {hubVault}/daily-logs/YYYY-MM-DD.md; then exit.",
|
|
23467
23719
|
"learnings-review": "Run a learnings review using the squadrant:command-ops skill. Scan {spokeVault}/learnings across all projects, identify cross-project patterns, propose captured-skill or fix actions, and exit when done.",
|
|
@@ -23494,7 +23746,7 @@ async function runCommandSpawn(input) {
|
|
|
23494
23746
|
if (!agent) {
|
|
23495
23747
|
throw new Error(`Unknown agent '${agentName}'. Known: claude, codex, gemini, opencode.`);
|
|
23496
23748
|
}
|
|
23497
|
-
const promptFile =
|
|
23749
|
+
const promptFile = path45.join(TEMPLATES_DIR2, `command.${agent.templateSuffix}.md`);
|
|
23498
23750
|
const cliCommand = agent.buildCommand({
|
|
23499
23751
|
prompt,
|
|
23500
23752
|
workdir: process.cwd(),
|
|
@@ -23535,7 +23787,7 @@ init_dist3();
|
|
|
23535
23787
|
import { Command as Command9 } from "commander";
|
|
23536
23788
|
import { createConnection as createConnection4 } from "net";
|
|
23537
23789
|
import { randomUUID as randomUUID5 } from "crypto";
|
|
23538
|
-
import { execFileSync as
|
|
23790
|
+
import { execFileSync as execFileSync12, spawnSync } from "child_process";
|
|
23539
23791
|
import { homedir as homedir15 } from "os";
|
|
23540
23792
|
import { join as join27 } from "path";
|
|
23541
23793
|
import { mkdirSync as mkdirSync10, writeFileSync as writeFileSync13 } from "fs";
|
|
@@ -24017,6 +24269,31 @@ function defaultWriteResult(id, payload) {
|
|
|
24017
24269
|
writeFileSync13(file, payload);
|
|
24018
24270
|
return file;
|
|
24019
24271
|
}
|
|
24272
|
+
var CITE_GIT_TIMEOUT_MS = 2e3;
|
|
24273
|
+
var citeGit = (args) => {
|
|
24274
|
+
const r = spawnSync("git", args, { encoding: "utf8", timeout: CITE_GIT_TIMEOUT_MS, stdio: ["ignore", "pipe", "ignore"] });
|
|
24275
|
+
if (r.error) throw r.error;
|
|
24276
|
+
return r.status === 0 ? r.stdout : "";
|
|
24277
|
+
};
|
|
24278
|
+
function logSignalCitations(state, o) {
|
|
24279
|
+
const env = o.env ?? process.env;
|
|
24280
|
+
const project = o.project ?? env.SQUADRANT_CREW_PROJECT;
|
|
24281
|
+
if (state !== "done" && state !== "review" || !project) return [];
|
|
24282
|
+
const texts = o.message ? [{ text: o.message, ref: `crew-${state}:${o.taskId ?? env.SQUADRANT_CREW_TASK_ID}` }] : [];
|
|
24283
|
+
try {
|
|
24284
|
+
texts.push(...readBranchOnlyMessages(o.cwd ?? process.cwd(), o.git ?? citeGit).map((c) => ({ text: c.text, ref: `git:${c.sha}`, at: c.at })));
|
|
24285
|
+
} catch (e) {
|
|
24286
|
+
process.stderr.write(`squadrant: rule citation scan of commits skipped: ${e.message}
|
|
24287
|
+
`);
|
|
24288
|
+
}
|
|
24289
|
+
try {
|
|
24290
|
+
return scanCitations(texts, { project, sink: o.audit });
|
|
24291
|
+
} catch (e) {
|
|
24292
|
+
process.stderr.write(`squadrant: rule citation scan skipped: ${e.message}
|
|
24293
|
+
`);
|
|
24294
|
+
return [];
|
|
24295
|
+
}
|
|
24296
|
+
}
|
|
24020
24297
|
async function runCrewSignal(signal, o, deps) {
|
|
24021
24298
|
const taskId = o.taskId ?? process.env.SQUADRANT_CREW_TASK_ID;
|
|
24022
24299
|
const project = o.project ?? process.env.SQUADRANT_CREW_PROJECT;
|
|
@@ -24039,10 +24316,10 @@ function resolveApproveTarget(tasks, crew) {
|
|
|
24039
24316
|
return matches.reduce((a, b) => (b.createdAt ?? 0) > (a.createdAt ?? 0) ? b : a);
|
|
24040
24317
|
}
|
|
24041
24318
|
function defaultPushBranch(cwd, branch) {
|
|
24042
|
-
|
|
24319
|
+
execFileSync12("git", ["-C", cwd, "push", "-u", "origin", branch], { encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"] });
|
|
24043
24320
|
}
|
|
24044
24321
|
function defaultCreatePr(cwd, o) {
|
|
24045
|
-
return
|
|
24322
|
+
return execFileSync12(
|
|
24046
24323
|
"gh",
|
|
24047
24324
|
["pr", "create", "--base", o.base, "--head", o.branch, "--title", o.title, "--body", o.body],
|
|
24048
24325
|
{ cwd, encoding: "utf-8" }
|
|
@@ -24050,7 +24327,7 @@ function defaultCreatePr(cwd, o) {
|
|
|
24050
24327
|
}
|
|
24051
24328
|
function defaultGetCommitSubject(cwd) {
|
|
24052
24329
|
try {
|
|
24053
|
-
return
|
|
24330
|
+
return execFileSync12("git", ["-C", cwd, "log", "-1", "--format=%s"], {
|
|
24054
24331
|
encoding: "utf-8",
|
|
24055
24332
|
stdio: ["ignore", "pipe", "pipe"]
|
|
24056
24333
|
}).trim();
|
|
@@ -24205,13 +24482,7 @@ function addControlPlaneCrewCommands(crew) {
|
|
|
24205
24482
|
...opts.project !== void 0 ? { project: opts.project } : {},
|
|
24206
24483
|
writeResult: defaultWriteResult
|
|
24207
24484
|
}, { call: squadrantdCall });
|
|
24208
|
-
|
|
24209
|
-
if ((state === "done" || state === "review") && opts.message && citeProject) {
|
|
24210
|
-
try {
|
|
24211
|
-
scanAndLogCitations({ text: opts.message, ref: `crew-${state}:${opts.taskId ?? process.env.SQUADRANT_CREW_TASK_ID}`, project: citeProject });
|
|
24212
|
-
} catch {
|
|
24213
|
-
}
|
|
24214
|
-
}
|
|
24485
|
+
logSignalCitations(state, opts);
|
|
24215
24486
|
process.exit(0);
|
|
24216
24487
|
} catch (e) {
|
|
24217
24488
|
process.stderr.write(`${e.message}
|
|
@@ -24300,7 +24571,7 @@ import { connect as netConnect2 } from "net";
|
|
|
24300
24571
|
init_dist3();
|
|
24301
24572
|
init_dist2();
|
|
24302
24573
|
import { createServer as createServer4, connect as netConnect } from "net";
|
|
24303
|
-
import
|
|
24574
|
+
import fs40 from "fs";
|
|
24304
24575
|
import { join as join28 } from "path";
|
|
24305
24576
|
import { randomUUID as randomUUID6 } from "crypto";
|
|
24306
24577
|
import chalk10 from "chalk";
|
|
@@ -24308,15 +24579,15 @@ var shared;
|
|
|
24308
24579
|
var registryEntryPath = () => join28(CLAUDE_SESSIONS_DIR, `${process.pid}.json`);
|
|
24309
24580
|
function unregisterSenderIdentity() {
|
|
24310
24581
|
try {
|
|
24311
|
-
|
|
24582
|
+
fs40.unlinkSync(registryEntryPath());
|
|
24312
24583
|
} catch {
|
|
24313
24584
|
}
|
|
24314
24585
|
}
|
|
24315
24586
|
function registerSenderIdentity(socketPath2) {
|
|
24316
24587
|
try {
|
|
24317
24588
|
unregisterSenderIdentity();
|
|
24318
|
-
|
|
24319
|
-
|
|
24589
|
+
fs40.mkdirSync(CLAUDE_SESSIONS_DIR, { recursive: true });
|
|
24590
|
+
fs40.writeFileSync(
|
|
24320
24591
|
registryEntryPath(),
|
|
24321
24592
|
JSON.stringify({
|
|
24322
24593
|
pid: process.pid,
|
|
@@ -24342,7 +24613,7 @@ async function sharedReceiptListener() {
|
|
|
24342
24613
|
// must never be the reason we refuse to start.
|
|
24343
24614
|
unlinkStale: (p) => {
|
|
24344
24615
|
try {
|
|
24345
|
-
|
|
24616
|
+
fs40.unlinkSync(p);
|
|
24346
24617
|
} catch {
|
|
24347
24618
|
}
|
|
24348
24619
|
},
|
|
@@ -24367,7 +24638,7 @@ async function buildCaptainChannel() {
|
|
|
24367
24638
|
// in /tmp/x registers cwd "/private/tmp/x" on macOS, so cwd matching silently
|
|
24368
24639
|
// missed and every captain ping reported accepted-unconfirmed.
|
|
24369
24640
|
statusFor: (taskId) => readClaudeStatusBySocketPath(captainSocketPath(taskId)),
|
|
24370
|
-
wire: (p, e) => writeLine(p, e, { connect: (
|
|
24641
|
+
wire: (p, e) => writeLine(p, e, { connect: (path60) => netConnect(path60) }),
|
|
24371
24642
|
receipts,
|
|
24372
24643
|
newMsgId: () => randomUUID6(),
|
|
24373
24644
|
sleep: (ms) => new Promise((r) => setTimeout(r, ms)),
|
|
@@ -24396,7 +24667,7 @@ async function sendClaudeFirstTurnViaPeer(runtime, o, getTaskRecord) {
|
|
|
24396
24667
|
socketPathFor: () => o.messagingSocketPath,
|
|
24397
24668
|
sessionIdFor: () => readClaudeStatusBySocketPath(o.messagingSocketPath)?.sessionId,
|
|
24398
24669
|
statusFor: () => readClaudeStatusBySocketPath(o.messagingSocketPath),
|
|
24399
|
-
wire: (p, e) => writeLine(p, e, { connect: (
|
|
24670
|
+
wire: (p, e) => writeLine(p, e, { connect: (path60) => netConnect2(path60) }),
|
|
24400
24671
|
receipts,
|
|
24401
24672
|
newMsgId: () => randomUUID7(),
|
|
24402
24673
|
sleep: (ms) => new Promise((r) => setTimeout(r, ms)),
|
|
@@ -24540,7 +24811,7 @@ async function runCrewSend2(project, name, message, opts) {
|
|
|
24540
24811
|
socketPathFor: (taskId) => tasks.find((t) => t.id === taskId)?.messagingSocketPath,
|
|
24541
24812
|
sessionIdFor: (taskId) => tasks.find((t) => t.id === taskId)?.sessionId,
|
|
24542
24813
|
statusFor: (taskId) => readClaudeStatus(tasks.find((t) => t.id === taskId)),
|
|
24543
|
-
wire: (p, e) => writeLine(p, e, { connect: (
|
|
24814
|
+
wire: (p, e) => writeLine(p, e, { connect: (path60) => netConnect3(path60) }),
|
|
24544
24815
|
receipts,
|
|
24545
24816
|
newMsgId: () => randomUUID8(),
|
|
24546
24817
|
sleep: (ms) => new Promise((r) => setTimeout(r, ms)),
|
|
@@ -24738,7 +25009,7 @@ init_dist();
|
|
|
24738
25009
|
init_dist4();
|
|
24739
25010
|
import { Command as Command11 } from "commander";
|
|
24740
25011
|
import chalk12 from "chalk";
|
|
24741
|
-
import { execFileSync as
|
|
25012
|
+
import { execFileSync as execFileSync13 } from "child_process";
|
|
24742
25013
|
import readline2 from "readline";
|
|
24743
25014
|
function resolveDiffTarget(tasks, crew, projectPath) {
|
|
24744
25015
|
const matches = tasks.filter((t) => t.name === crew);
|
|
@@ -24809,14 +25080,14 @@ function promptLine2(question) {
|
|
|
24809
25080
|
}
|
|
24810
25081
|
function getPrDiff(projectPath, pr) {
|
|
24811
25082
|
try {
|
|
24812
|
-
return
|
|
25083
|
+
return execFileSync13("gh", ["pr", "diff", pr], { cwd: projectPath, encoding: "utf-8" });
|
|
24813
25084
|
} catch (e) {
|
|
24814
25085
|
throw new Error(`Could not fetch PR #${pr} diff (gh pr diff failed): ${e.message}`);
|
|
24815
25086
|
}
|
|
24816
25087
|
}
|
|
24817
25088
|
function getRefsDiff(projectPath, base, head) {
|
|
24818
25089
|
try {
|
|
24819
|
-
return
|
|
25090
|
+
return execFileSync13("git", ["-C", projectPath, "diff", `${base}...${head}`], { encoding: "utf-8" });
|
|
24820
25091
|
} catch (e) {
|
|
24821
25092
|
throw new Error(`Could not diff ${base}...${head}: ${e.message}`);
|
|
24822
25093
|
}
|
|
@@ -24837,7 +25108,7 @@ async function openCrewDiff(project, proj, crew, opts, runtime, workspaceId) {
|
|
|
24837
25108
|
let opened = 0;
|
|
24838
25109
|
for (const source of sources) {
|
|
24839
25110
|
const statArgs = source === "staged" ? ["diff", "--stat", "--cached"] : ["diff", "--stat"];
|
|
24840
|
-
const stat2 =
|
|
25111
|
+
const stat2 = execFileSync13("git", ["-C", target.cwd, ...statArgs], { encoding: "utf-8" }).trim();
|
|
24841
25112
|
if (!stat2) continue;
|
|
24842
25113
|
await runtime.showDiff({
|
|
24843
25114
|
workspaceId,
|
|
@@ -24858,7 +25129,7 @@ async function openCrewDiff(project, proj, crew, opts, runtime, workspaceId) {
|
|
|
24858
25129
|
}
|
|
24859
25130
|
return;
|
|
24860
25131
|
}
|
|
24861
|
-
const diffStat =
|
|
25132
|
+
const diffStat = execFileSync13(
|
|
24862
25133
|
"git",
|
|
24863
25134
|
["-C", target.cwd, "diff", "--stat", `${base}...HEAD`],
|
|
24864
25135
|
{ encoding: "utf-8" }
|
|
@@ -24907,7 +25178,7 @@ async function runDiff(project, crewArg, opts) {
|
|
|
24907
25178
|
const base = resolveWorktreeBase(proj.path);
|
|
24908
25179
|
const stats = buildCrewDiffStats(tasks, proj.path, base, (cwd, b) => {
|
|
24909
25180
|
try {
|
|
24910
|
-
return
|
|
25181
|
+
return execFileSync13("git", ["-C", cwd, "diff", "--stat", `${b}...HEAD`], { encoding: "utf-8" });
|
|
24911
25182
|
} catch {
|
|
24912
25183
|
return "";
|
|
24913
25184
|
}
|
|
@@ -24934,11 +25205,11 @@ init_dist4();
|
|
|
24934
25205
|
init_dist();
|
|
24935
25206
|
init_dist2();
|
|
24936
25207
|
import { Command as Command12 } from "commander";
|
|
24937
|
-
import
|
|
24938
|
-
import
|
|
24939
|
-
import
|
|
25208
|
+
import fs41 from "fs";
|
|
25209
|
+
import path46 from "path";
|
|
25210
|
+
import os19 from "os";
|
|
24940
25211
|
import chalk13 from "chalk";
|
|
24941
|
-
var TEMPLATES_DIR3 =
|
|
25212
|
+
var TEMPLATES_DIR3 = path46.join(os19.homedir(), ".config", "squadrant", "templates");
|
|
24942
25213
|
async function runSideSpawn2(input) {
|
|
24943
25214
|
const config = loadConfig();
|
|
24944
25215
|
const proj = config.projects[input.project];
|
|
@@ -24963,7 +25234,7 @@ async function runSideSpawn2(input) {
|
|
|
24963
25234
|
}
|
|
24964
25235
|
const sideModel = sideRole?.model;
|
|
24965
25236
|
const sideThinking = sideRole?.thinking;
|
|
24966
|
-
const promptFile =
|
|
25237
|
+
const promptFile = path46.join(
|
|
24967
25238
|
TEMPLATES_DIR3,
|
|
24968
25239
|
`side.${input.role}.${agent.templateSuffix}.md`
|
|
24969
25240
|
);
|
|
@@ -24971,7 +25242,7 @@ async function runSideSpawn2(input) {
|
|
|
24971
25242
|
prompt: input.topic,
|
|
24972
25243
|
workdir: spawnCwd,
|
|
24973
25244
|
role: "side",
|
|
24974
|
-
promptFile:
|
|
25245
|
+
promptFile: fs41.existsSync(promptFile) ? promptFile : void 0,
|
|
24975
25246
|
interactive: true,
|
|
24976
25247
|
permissionMode: config.defaults.permissions?.crew ?? "auto",
|
|
24977
25248
|
...sideModel ? { model: sideModel } : {},
|
|
@@ -25234,8 +25505,8 @@ function renderDashboard(rows, opts) {
|
|
|
25234
25505
|
|
|
25235
25506
|
// packages/web/dist/sync-hub.js
|
|
25236
25507
|
init_dist();
|
|
25237
|
-
import
|
|
25238
|
-
import
|
|
25508
|
+
import fs42 from "fs";
|
|
25509
|
+
import path47 from "path";
|
|
25239
25510
|
function buildMirrorMarkdown(s) {
|
|
25240
25511
|
const fenced = "```";
|
|
25241
25512
|
return [
|
|
@@ -25261,15 +25532,15 @@ function buildMirrorMarkdown(s) {
|
|
|
25261
25532
|
function syncHub(deps) {
|
|
25262
25533
|
if (!deps.config.hubVault)
|
|
25263
25534
|
return [];
|
|
25264
|
-
const writeFile6 = deps.writeFile ?? ((p, c) =>
|
|
25265
|
-
const mkdir6 = deps.mkdir ?? ((p) =>
|
|
25266
|
-
const projectsDir =
|
|
25535
|
+
const writeFile6 = deps.writeFile ?? ((p, c) => fs42.writeFileSync(p, c));
|
|
25536
|
+
const mkdir6 = deps.mkdir ?? ((p) => fs42.mkdirSync(p, { recursive: true }));
|
|
25537
|
+
const projectsDir = path47.join(resolveHome(deps.config.hubVault), "projects");
|
|
25267
25538
|
mkdir6(projectsDir);
|
|
25268
25539
|
const out = [];
|
|
25269
25540
|
for (const s of deps.statuses) {
|
|
25270
25541
|
if (s.state === "unknown")
|
|
25271
25542
|
continue;
|
|
25272
|
-
const hubPath =
|
|
25543
|
+
const hubPath = path47.join(projectsDir, `${s.project}.md`);
|
|
25273
25544
|
try {
|
|
25274
25545
|
writeFile6(hubPath, buildMirrorMarkdown(s));
|
|
25275
25546
|
out.push({ project: s.project, hubPath });
|
|
@@ -26275,18 +26546,18 @@ function renderHtml(snap, opts = {}) {
|
|
|
26275
26546
|
import { closeSync as closeSync3, openSync as openSync3, readSync as readSync2, statSync as statSync4 } from "fs";
|
|
26276
26547
|
var LOG_TAIL_BYTES = 256 * 1024;
|
|
26277
26548
|
var LOG_RING_SIZE = 1e3;
|
|
26278
|
-
function defaultSize(
|
|
26549
|
+
function defaultSize(path60) {
|
|
26279
26550
|
try {
|
|
26280
|
-
return statSync4(
|
|
26551
|
+
return statSync4(path60).size;
|
|
26281
26552
|
} catch {
|
|
26282
26553
|
return 0;
|
|
26283
26554
|
}
|
|
26284
26555
|
}
|
|
26285
|
-
function defaultRead(
|
|
26556
|
+
function defaultRead(path60, start, len) {
|
|
26286
26557
|
if (len <= 0)
|
|
26287
26558
|
return "";
|
|
26288
26559
|
try {
|
|
26289
|
-
const fd = openSync3(
|
|
26560
|
+
const fd = openSync3(path60, "r");
|
|
26290
26561
|
try {
|
|
26291
26562
|
const buf = Buffer.alloc(len);
|
|
26292
26563
|
const n = readSync2(fd, buf, 0, len, start);
|
|
@@ -26306,8 +26577,8 @@ var LogTailer = class {
|
|
|
26306
26577
|
ring = [];
|
|
26307
26578
|
size;
|
|
26308
26579
|
read;
|
|
26309
|
-
constructor(
|
|
26310
|
-
this.path =
|
|
26580
|
+
constructor(path60, ringSize = LOG_RING_SIZE, deps = {}) {
|
|
26581
|
+
this.path = path60;
|
|
26311
26582
|
this.ringSize = ringSize;
|
|
26312
26583
|
this.size = deps.size ?? defaultSize;
|
|
26313
26584
|
this.read = deps.read ?? defaultRead;
|
|
@@ -26582,10 +26853,10 @@ init_dist3();
|
|
|
26582
26853
|
init_dist4();
|
|
26583
26854
|
init_dist2();
|
|
26584
26855
|
import { Command as Command14 } from "commander";
|
|
26585
|
-
import { execSync as execSync11, execFileSync as
|
|
26586
|
-
import
|
|
26587
|
-
import
|
|
26588
|
-
import
|
|
26856
|
+
import { execSync as execSync11, execFileSync as execFileSync14 } from "child_process";
|
|
26857
|
+
import fs43 from "fs";
|
|
26858
|
+
import path48 from "path";
|
|
26859
|
+
import os20 from "os";
|
|
26589
26860
|
import chalk16 from "chalk";
|
|
26590
26861
|
|
|
26591
26862
|
// packages/cli/src/commands/launch-interactive.ts
|
|
@@ -26677,8 +26948,8 @@ function resolveLaunchBackend(o) {
|
|
|
26677
26948
|
// packages/cli/src/commands/launch.ts
|
|
26678
26949
|
init_dist2();
|
|
26679
26950
|
var CMUX_APP = "/Applications/cmux.app";
|
|
26680
|
-
var TEMPLATES_DIR4 =
|
|
26681
|
-
var SESSIONS_PATH2 =
|
|
26951
|
+
var TEMPLATES_DIR4 = path48.join(os20.homedir(), ".config", "squadrant", "templates");
|
|
26952
|
+
var SESSIONS_PATH2 = path48.join(os20.homedir(), ".config", "squadrant", "sessions.json");
|
|
26682
26953
|
function shouldWireCaptainChannel(agentName, config) {
|
|
26683
26954
|
return agentName === "claude" && resolveCaptainChannelMode(config.defaults) !== "off";
|
|
26684
26955
|
}
|
|
@@ -26700,7 +26971,7 @@ function pickResumeSessionId(record, agentName, fresh = false) {
|
|
|
26700
26971
|
}
|
|
26701
26972
|
function isOpencodeCaptainDir(dir) {
|
|
26702
26973
|
try {
|
|
26703
|
-
|
|
26974
|
+
execFileSync14("git", ["-C", dir, "rev-parse", "--verify", "HEAD"], { stdio: "ignore" });
|
|
26704
26975
|
return true;
|
|
26705
26976
|
} catch {
|
|
26706
26977
|
return false;
|
|
@@ -26775,7 +27046,7 @@ var launchCommand = new Command14("launch").description(
|
|
|
26775
27046
|
initialPrompt = "Run your startup checklist: use the squadrant:command-ops skill, complete your daily briefing, then report ready.";
|
|
26776
27047
|
}
|
|
26777
27048
|
const runtime = projectName ? runtimes.forProject(projectName, config) : runtimes.global(config);
|
|
26778
|
-
const stateRoot =
|
|
27049
|
+
const stateRoot = path48.join(os20.homedir(), ".config", "squadrant", "state");
|
|
26779
27050
|
const isOpencodeCaptain = role === "captain" && agentName === "opencode" && !!projectName;
|
|
26780
27051
|
if (isOpencodeCaptain && !isOpencodeCaptainDir(cwd)) {
|
|
26781
27052
|
console.error(chalk16.red(`
|
|
@@ -26928,12 +27199,12 @@ var launchCommand = new Command14("launch").description(
|
|
|
26928
27199
|
}
|
|
26929
27200
|
if (opts.all) {
|
|
26930
27201
|
const hubPath = resolveHome(config.hubVault);
|
|
26931
|
-
|
|
27202
|
+
fs43.mkdirSync(hubPath, { recursive: true });
|
|
26932
27203
|
console.log(chalk16.bold("\nLaunching all captain workspaces\n"));
|
|
26933
27204
|
for (const [name, proj] of Object.entries(config.projects)) {
|
|
26934
27205
|
const projPath = resolveHome(proj.path);
|
|
26935
27206
|
const spokePath = resolveHome(proj.spokeVault);
|
|
26936
|
-
if (!
|
|
27207
|
+
if (!fs43.existsSync(spokePath)) {
|
|
26937
27208
|
const spokeDriver = new WorkspaceRegistry({ obsidian: createObsidianDriver }).forProject(name, config);
|
|
26938
27209
|
await ensureSpokeLayout(spokeDriver);
|
|
26939
27210
|
console.log(chalk16.cyan(` \u2714 Created spoke vault at ${spokePath}`));
|
|
@@ -26971,7 +27242,7 @@ Launching ${selected.length} captain workspace(s) in parallel
|
|
|
26971
27242
|
const proj = config.projects[name];
|
|
26972
27243
|
const projPath = resolveHome(proj.path);
|
|
26973
27244
|
const spokePath = resolveHome(proj.spokeVault);
|
|
26974
|
-
if (!
|
|
27245
|
+
if (!fs43.existsSync(spokePath)) {
|
|
26975
27246
|
const spokeDriver = new WorkspaceRegistry({ obsidian: createObsidianDriver }).forProject(name, config);
|
|
26976
27247
|
await ensureSpokeLayout(spokeDriver);
|
|
26977
27248
|
console.log(chalk16.cyan(` \u2714 Created spoke vault at ${spokePath}`));
|
|
@@ -26995,7 +27266,7 @@ Launching ${selected.length} captain workspace(s) in parallel
|
|
|
26995
27266
|
const proj = config.projects[project];
|
|
26996
27267
|
const projPath = resolveHome(proj.path);
|
|
26997
27268
|
const spokePath = resolveHome(proj.spokeVault);
|
|
26998
|
-
if (!
|
|
27269
|
+
if (!fs43.existsSync(spokePath)) {
|
|
26999
27270
|
const spokeDriver = new WorkspaceRegistry({ obsidian: createObsidianDriver }).forProject(project, config);
|
|
27000
27271
|
await ensureSpokeLayout(spokeDriver);
|
|
27001
27272
|
console.log(chalk16.cyan(` \u2714 Created spoke vault at ${spokePath}`));
|
|
@@ -27131,24 +27402,24 @@ Shutting down captain workspace for '${project}'...
|
|
|
27131
27402
|
// packages/cli/src/commands/feedback.ts
|
|
27132
27403
|
init_dist();
|
|
27133
27404
|
import { Command as Command16 } from "commander";
|
|
27134
|
-
import
|
|
27135
|
-
import
|
|
27136
|
-
import
|
|
27405
|
+
import fs44 from "fs";
|
|
27406
|
+
import os21 from "os";
|
|
27407
|
+
import path49 from "path";
|
|
27137
27408
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
27138
27409
|
import { execSync as execSync12 } from "child_process";
|
|
27139
27410
|
import chalk18 from "chalk";
|
|
27140
27411
|
var REPO_URL = "https://github.com/tu11aa/squadrant";
|
|
27141
27412
|
function readPkgVersion() {
|
|
27142
27413
|
try {
|
|
27143
|
-
const pkgPath =
|
|
27144
|
-
return JSON.parse(
|
|
27414
|
+
const pkgPath = path49.join(path49.dirname(fileURLToPath3(import.meta.url)), "..", "package.json");
|
|
27415
|
+
return JSON.parse(fs44.readFileSync(pkgPath, "utf-8")).version ?? "unknown";
|
|
27145
27416
|
} catch {
|
|
27146
27417
|
return "unknown";
|
|
27147
27418
|
}
|
|
27148
27419
|
}
|
|
27149
27420
|
function readMetrics(metricsPath) {
|
|
27150
27421
|
try {
|
|
27151
|
-
return JSON.parse(
|
|
27422
|
+
return JSON.parse(fs44.readFileSync(metricsPath, "utf-8"));
|
|
27152
27423
|
} catch {
|
|
27153
27424
|
return {};
|
|
27154
27425
|
}
|
|
@@ -27186,7 +27457,7 @@ function buildIssueUrl(metrics, squadrantVersion) {
|
|
|
27186
27457
|
}
|
|
27187
27458
|
var feedbackCommand = new Command16("feedback").description("Open a pre-filled GitHub issue for feedback or bug reports").action(() => {
|
|
27188
27459
|
const config = loadConfig();
|
|
27189
|
-
const metricsPath = config.metrics?.path ||
|
|
27460
|
+
const metricsPath = config.metrics?.path || path49.join(os21.homedir(), ".config", "squadrant", "metrics.json");
|
|
27190
27461
|
const metrics = readMetrics(metricsPath);
|
|
27191
27462
|
const version = readStamp(config) ?? readPkgVersion();
|
|
27192
27463
|
const issueUrl = buildIssueUrl(metrics, version);
|
|
@@ -27486,9 +27757,9 @@ workspaceCommand.command("read").description("Print the contents of a scope-rela
|
|
|
27486
27757
|
const config = loadConfig();
|
|
27487
27758
|
const registry = buildRegistry2();
|
|
27488
27759
|
try {
|
|
27489
|
-
const { projectTarget, path:
|
|
27760
|
+
const { projectTarget, path: path60 } = resolveTargetAndPath(arg1, arg2, !!opts.hub);
|
|
27490
27761
|
const driver = resolveDriver(registry, config, projectTarget, !!opts.hub);
|
|
27491
|
-
const content = await driver.read(
|
|
27762
|
+
const content = await driver.read(path60);
|
|
27492
27763
|
process.stdout.write(content);
|
|
27493
27764
|
} catch (err) {
|
|
27494
27765
|
console.error(chalk21.red(err.message));
|
|
@@ -27500,26 +27771,26 @@ workspaceCommand.command("write").description("Write content to a scope-relative
|
|
|
27500
27771
|
const registry = buildRegistry2();
|
|
27501
27772
|
try {
|
|
27502
27773
|
let projectTarget;
|
|
27503
|
-
let
|
|
27774
|
+
let path60;
|
|
27504
27775
|
let rawContent;
|
|
27505
27776
|
if (opts.hub) {
|
|
27506
27777
|
if (arg3 !== void 0) {
|
|
27507
27778
|
throw new Error("With --hub, pass only the path and content");
|
|
27508
27779
|
}
|
|
27509
27780
|
projectTarget = void 0;
|
|
27510
|
-
|
|
27781
|
+
path60 = arg1;
|
|
27511
27782
|
rawContent = arg2;
|
|
27512
27783
|
} else {
|
|
27513
27784
|
if (arg3 === void 0) {
|
|
27514
27785
|
throw new Error("Missing content \u2014 usage: <project> <path> <content>");
|
|
27515
27786
|
}
|
|
27516
27787
|
projectTarget = arg1;
|
|
27517
|
-
|
|
27788
|
+
path60 = arg2;
|
|
27518
27789
|
rawContent = arg3;
|
|
27519
27790
|
}
|
|
27520
27791
|
const driver = resolveDriver(registry, config, projectTarget, !!opts.hub);
|
|
27521
27792
|
const payload = rawContent === "-" ? await readStdin() : rawContent;
|
|
27522
|
-
await driver.write(
|
|
27793
|
+
await driver.write(path60, payload);
|
|
27523
27794
|
} catch (err) {
|
|
27524
27795
|
console.error(chalk21.red(err.message));
|
|
27525
27796
|
process.exit(1);
|
|
@@ -27529,9 +27800,9 @@ workspaceCommand.command("list").description("List entries in a scope-relative d
|
|
|
27529
27800
|
const config = loadConfig();
|
|
27530
27801
|
const registry = buildRegistry2();
|
|
27531
27802
|
try {
|
|
27532
|
-
const { projectTarget, path:
|
|
27803
|
+
const { projectTarget, path: path60 } = resolveTargetAndPath(arg1, arg2, !!opts.hub);
|
|
27533
27804
|
const driver = resolveDriver(registry, config, projectTarget, !!opts.hub);
|
|
27534
|
-
const entries = await driver.list(
|
|
27805
|
+
const entries = await driver.list(path60);
|
|
27535
27806
|
for (const entry of entries) console.log(entry);
|
|
27536
27807
|
} catch (err) {
|
|
27537
27808
|
console.error(chalk21.red(err.message));
|
|
@@ -27542,9 +27813,9 @@ workspaceCommand.command("exists").description("Exit 0 if path exists, 1 if not"
|
|
|
27542
27813
|
const config = loadConfig();
|
|
27543
27814
|
const registry = buildRegistry2();
|
|
27544
27815
|
try {
|
|
27545
|
-
const { projectTarget, path:
|
|
27816
|
+
const { projectTarget, path: path60 } = resolveTargetAndPath(arg1, arg2, !!opts.hub);
|
|
27546
27817
|
const driver = resolveDriver(registry, config, projectTarget, !!opts.hub);
|
|
27547
|
-
const ok2 = await driver.exists(
|
|
27818
|
+
const ok2 = await driver.exists(path60);
|
|
27548
27819
|
process.exit(ok2 ? 0 : 1);
|
|
27549
27820
|
} catch (err) {
|
|
27550
27821
|
console.error(chalk21.red(err.message));
|
|
@@ -27555,9 +27826,9 @@ workspaceCommand.command("mkdir").description("Recursively create a scope-relati
|
|
|
27555
27826
|
const config = loadConfig();
|
|
27556
27827
|
const registry = buildRegistry2();
|
|
27557
27828
|
try {
|
|
27558
|
-
const { projectTarget, path:
|
|
27829
|
+
const { projectTarget, path: path60 } = resolveTargetAndPath(arg1, arg2, !!opts.hub);
|
|
27559
27830
|
const driver = resolveDriver(registry, config, projectTarget, !!opts.hub);
|
|
27560
|
-
await driver.mkdir(
|
|
27831
|
+
await driver.mkdir(path60);
|
|
27561
27832
|
} catch (err) {
|
|
27562
27833
|
console.error(chalk21.red(err.message));
|
|
27563
27834
|
process.exit(1);
|
|
@@ -27597,8 +27868,8 @@ init_dist4();
|
|
|
27597
27868
|
init_dist();
|
|
27598
27869
|
import { Command as Command21 } from "commander";
|
|
27599
27870
|
import chalk23 from "chalk";
|
|
27600
|
-
import
|
|
27601
|
-
import
|
|
27871
|
+
import fs45 from "fs";
|
|
27872
|
+
import path50 from "path";
|
|
27602
27873
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
27603
27874
|
function parseScope(v2) {
|
|
27604
27875
|
if (v2 !== "user" && v2 !== "project") {
|
|
@@ -27607,10 +27878,10 @@ function parseScope(v2) {
|
|
|
27607
27878
|
return v2;
|
|
27608
27879
|
}
|
|
27609
27880
|
function findPackageRoot3() {
|
|
27610
|
-
let dir =
|
|
27881
|
+
let dir = path50.dirname(fileURLToPath4(import.meta.url));
|
|
27611
27882
|
while (dir !== "/" && dir !== "") {
|
|
27612
|
-
if (
|
|
27613
|
-
dir =
|
|
27883
|
+
if (fs45.existsSync(path50.join(dir, "package.json"))) return dir;
|
|
27884
|
+
dir = path50.dirname(dir);
|
|
27614
27885
|
}
|
|
27615
27886
|
return process.cwd();
|
|
27616
27887
|
}
|
|
@@ -27825,12 +28096,12 @@ init_dist();
|
|
|
27825
28096
|
init_dist();
|
|
27826
28097
|
init_dist2();
|
|
27827
28098
|
import { Command as Command23 } from "commander";
|
|
27828
|
-
import
|
|
28099
|
+
import fs46 from "fs";
|
|
27829
28100
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
27830
28101
|
import { dirname as dirname8, join as join31 } from "path";
|
|
27831
28102
|
import chalk24 from "chalk";
|
|
27832
28103
|
function runConfigCheck(opts) {
|
|
27833
|
-
const raw = JSON.parse(
|
|
28104
|
+
const raw = JSON.parse(fs46.readFileSync(opts.configPath, "utf-8"));
|
|
27834
28105
|
const def = getDefaultConfig();
|
|
27835
28106
|
const items = detectDrift(raw, def);
|
|
27836
28107
|
let working = raw;
|
|
@@ -27918,7 +28189,7 @@ function printItems(items) {
|
|
|
27918
28189
|
var configCommand = new Command23("config").description("Inspect and reconcile squadrant config");
|
|
27919
28190
|
configCommand.command("check").description("Detect config drift vs the current default schema").option("--fix", "Apply the safe tier (add missing, remove deprecated)", false).option("--accept", "Stamp the current version without changing config (dismiss advisories)", false).option("--json", "Output drift items as JSON", false).action((opts) => {
|
|
27920
28191
|
const pkgVersion = readPkgVersion2();
|
|
27921
|
-
if (!
|
|
28192
|
+
if (!fs46.existsSync(DEFAULT_CONFIG_PATH)) {
|
|
27922
28193
|
console.log(chalk24.yellow("No config found \u2014 run `squadrant init` first."));
|
|
27923
28194
|
return;
|
|
27924
28195
|
}
|
|
@@ -27964,12 +28235,12 @@ configCommand.command("set").description("Write a config value by dotted key (e.
|
|
|
27964
28235
|
});
|
|
27965
28236
|
function readPkgVersion2() {
|
|
27966
28237
|
const pkgPath = join31(dirname8(fileURLToPath5(import.meta.url)), "..", "package.json");
|
|
27967
|
-
return JSON.parse(
|
|
28238
|
+
return JSON.parse(fs46.readFileSync(pkgPath, "utf-8")).version;
|
|
27968
28239
|
}
|
|
27969
28240
|
|
|
27970
28241
|
// packages/cli/src/commands/heal.ts
|
|
27971
28242
|
init_dist();
|
|
27972
|
-
import { execFileSync as
|
|
28243
|
+
import { execFileSync as execFileSync15 } from "child_process";
|
|
27973
28244
|
import { join as join32 } from "path";
|
|
27974
28245
|
import { homedir as homedir17 } from "os";
|
|
27975
28246
|
import { Command as Command24 } from "commander";
|
|
@@ -28178,7 +28449,7 @@ async function runHealCaptain(projects, deps) {
|
|
|
28178
28449
|
}
|
|
28179
28450
|
function kickstartDaemonForHealCaptain() {
|
|
28180
28451
|
const uid = process.getuid?.() ?? 0;
|
|
28181
|
-
|
|
28452
|
+
execFileSync15("launchctl", ["kickstart", "-k", `gui/${uid}/${LABEL}`], { stdio: "ignore" });
|
|
28182
28453
|
}
|
|
28183
28454
|
var healCommand = new Command24("heal").description("Targeted, idempotent remediation for squadrant components (daemon, health)").addHelpText("after", "\nDeferred: 'squadrant heal crew <id>' (re-attach) \u2014 see issue #100.").addCommand(
|
|
28184
28455
|
new Command24("status").description("Dry-run: print unhealthy components and the exact heal command for each").option("-p, --project <project>", "scope to one project").option("--json", "output machine-readable JSON (exit 0=healthy, 1=error, 2=unhealthy)").action(async (opts) => {
|
|
@@ -28409,8 +28680,8 @@ var cmuxCommand = new Command28("cmux").description("cmux integration helpers").
|
|
|
28409
28680
|
// packages/cli/src/commands/effort.ts
|
|
28410
28681
|
init_dist();
|
|
28411
28682
|
init_dist2();
|
|
28412
|
-
import
|
|
28413
|
-
import
|
|
28683
|
+
import fs47 from "fs";
|
|
28684
|
+
import path51 from "path";
|
|
28414
28685
|
import { Command as Command29 } from "commander";
|
|
28415
28686
|
import chalk30 from "chalk";
|
|
28416
28687
|
var VALID_EFFORTS = ["max", "balance", "low"];
|
|
@@ -28453,9 +28724,9 @@ function effortScopeLabel(projectName) {
|
|
|
28453
28724
|
}
|
|
28454
28725
|
function canonical(p) {
|
|
28455
28726
|
try {
|
|
28456
|
-
return
|
|
28727
|
+
return fs47.realpathSync(p);
|
|
28457
28728
|
} catch {
|
|
28458
|
-
return
|
|
28729
|
+
return path51.resolve(p);
|
|
28459
28730
|
}
|
|
28460
28731
|
}
|
|
28461
28732
|
async function notifyCaptainsOfEffort(effort, config, driver, cwd = process.cwd(), append, scopeProject, projectConfigRoot) {
|
|
@@ -28505,7 +28776,7 @@ var effortCommand = new Command29("effort").description("Get or set the crew tok
|
|
|
28505
28776
|
const config = loadConfig();
|
|
28506
28777
|
const registry = new RuntimeRegistry2({ cmux: createCmuxDriver2() });
|
|
28507
28778
|
const driver = registry.global(config);
|
|
28508
|
-
const stateRoot =
|
|
28779
|
+
const stateRoot = path51.join(path51.dirname(DEFAULT_CONFIG_PATH), "state");
|
|
28509
28780
|
const append = (project, text) => appendCaptainMessage({ stateRoot, project, text, source: "daemon" });
|
|
28510
28781
|
await notifyCaptainsOfEffort(effort, config, driver, process.cwd(), append, options.project);
|
|
28511
28782
|
} catch {
|
|
@@ -28515,13 +28786,13 @@ var effortCommand = new Command29("effort").description("Get or set the crew tok
|
|
|
28515
28786
|
|
|
28516
28787
|
// packages/cli/src/commands/tokens.ts
|
|
28517
28788
|
init_dist();
|
|
28518
|
-
import
|
|
28519
|
-
import
|
|
28520
|
-
import
|
|
28789
|
+
import fs48 from "fs";
|
|
28790
|
+
import path52 from "path";
|
|
28791
|
+
import os22 from "os";
|
|
28521
28792
|
import readline3 from "readline";
|
|
28522
28793
|
import { Command as Command30 } from "commander";
|
|
28523
28794
|
import chalk31 from "chalk";
|
|
28524
|
-
var CLAUDE_PROJECTS_DIR =
|
|
28795
|
+
var CLAUDE_PROJECTS_DIR = path52.join(os22.homedir(), ".claude", "projects");
|
|
28525
28796
|
function parseTranscriptLine(rawLine) {
|
|
28526
28797
|
const line2 = rawLine.trim();
|
|
28527
28798
|
if (!line2) return { timestamp: null, usage: null };
|
|
@@ -28571,7 +28842,7 @@ function foldTranscriptLine(agg, rawLine, state) {
|
|
|
28571
28842
|
async function aggregateTranscriptFile(filePath) {
|
|
28572
28843
|
const agg = emptySessionAggregate();
|
|
28573
28844
|
const state = { lastCacheRead: null };
|
|
28574
|
-
const rl = readline3.createInterface({ input:
|
|
28845
|
+
const rl = readline3.createInterface({ input: fs48.createReadStream(filePath), crlfDelay: Infinity });
|
|
28575
28846
|
for await (const line2 of rl) {
|
|
28576
28847
|
foldTranscriptLine(agg, line2, state);
|
|
28577
28848
|
}
|
|
@@ -28639,22 +28910,22 @@ function buildRoleReport(role, sessions) {
|
|
|
28639
28910
|
}
|
|
28640
28911
|
async function readdirSafe(dir) {
|
|
28641
28912
|
try {
|
|
28642
|
-
return await
|
|
28913
|
+
return await fs48.promises.readdir(dir);
|
|
28643
28914
|
} catch {
|
|
28644
28915
|
return [];
|
|
28645
28916
|
}
|
|
28646
28917
|
}
|
|
28647
28918
|
async function listJsonlFiles(dir) {
|
|
28648
28919
|
const entries = await readdirSafe(dir);
|
|
28649
|
-
return entries.filter((e) => e.endsWith(".jsonl")).map((e) =>
|
|
28920
|
+
return entries.filter((e) => e.endsWith(".jsonl")).map((e) => path52.join(dir, e));
|
|
28650
28921
|
}
|
|
28651
28922
|
async function findTranscriptDirs(claudeProjectsDir, captainSlug) {
|
|
28652
28923
|
const entries = await readdirSafe(claudeProjectsDir);
|
|
28653
28924
|
const captainDirs = [];
|
|
28654
28925
|
const crewDirs = [];
|
|
28655
28926
|
for (const entry of entries) {
|
|
28656
|
-
if (entry === captainSlug) captainDirs.push(
|
|
28657
|
-
else if (isCrewDirName(entry, captainSlug)) crewDirs.push(
|
|
28927
|
+
if (entry === captainSlug) captainDirs.push(path52.join(claudeProjectsDir, entry));
|
|
28928
|
+
else if (isCrewDirName(entry, captainSlug)) crewDirs.push(path52.join(claudeProjectsDir, entry));
|
|
28658
28929
|
}
|
|
28659
28930
|
return { captainDirs, crewDirs };
|
|
28660
28931
|
}
|
|
@@ -29141,8 +29412,8 @@ import { join as join36 } from "path";
|
|
|
29141
29412
|
import { homedir as homedir20 } from "os";
|
|
29142
29413
|
|
|
29143
29414
|
// packages/cli/src/lib/captain-session-registry.ts
|
|
29144
|
-
import
|
|
29145
|
-
import
|
|
29415
|
+
import fs49 from "fs";
|
|
29416
|
+
import path53 from "path";
|
|
29146
29417
|
|
|
29147
29418
|
// packages/cli/src/lib/handoff-facts.ts
|
|
29148
29419
|
var STALE_FETCH_WARNING_MS = 24 * 60 * 60 * 1e3;
|
|
@@ -29193,15 +29464,15 @@ function assembleHandoffFacts(live, claudeMem, gapSessions, checkpoint, now, ext
|
|
|
29193
29464
|
// packages/cli/src/lib/captain-session-registry.ts
|
|
29194
29465
|
var CAPTAIN_SESSION_REGISTRY_FILE = "captain-sessions.jsonl";
|
|
29195
29466
|
function appendCaptainSession(spokeVault, record) {
|
|
29196
|
-
|
|
29197
|
-
const file =
|
|
29198
|
-
|
|
29467
|
+
fs49.mkdirSync(spokeVault, { recursive: true });
|
|
29468
|
+
const file = path53.join(spokeVault, CAPTAIN_SESSION_REGISTRY_FILE);
|
|
29469
|
+
fs49.appendFileSync(file, JSON.stringify(record) + "\n");
|
|
29199
29470
|
}
|
|
29200
29471
|
function readCaptainSessionRegistry(spokeVault) {
|
|
29201
|
-
const file =
|
|
29202
|
-
if (!
|
|
29472
|
+
const file = path53.join(spokeVault, CAPTAIN_SESSION_REGISTRY_FILE);
|
|
29473
|
+
if (!fs49.existsSync(file)) return [];
|
|
29203
29474
|
const records = [];
|
|
29204
|
-
for (const line2 of
|
|
29475
|
+
for (const line2 of fs49.readFileSync(file, "utf-8").split("\n")) {
|
|
29205
29476
|
if (!line2.trim()) continue;
|
|
29206
29477
|
try {
|
|
29207
29478
|
records.push(JSON.parse(line2));
|
|
@@ -29651,13 +29922,13 @@ function hooksCommand() {
|
|
|
29651
29922
|
// packages/cli/src/commands/work.ts
|
|
29652
29923
|
init_dist();
|
|
29653
29924
|
init_dist2();
|
|
29654
|
-
import
|
|
29925
|
+
import path54 from "path";
|
|
29655
29926
|
import { Command as Command34 } from "commander";
|
|
29656
29927
|
import chalk34 from "chalk";
|
|
29657
29928
|
function detectCurrentProject(config, cwd = process.cwd()) {
|
|
29658
29929
|
for (const [name, proj] of Object.entries(config.projects)) {
|
|
29659
29930
|
const projPath = resolveHome(proj.path);
|
|
29660
|
-
if (cwd === projPath || cwd.startsWith(projPath +
|
|
29931
|
+
if (cwd === projPath || cwd.startsWith(projPath + path54.sep)) return name;
|
|
29661
29932
|
}
|
|
29662
29933
|
return void 0;
|
|
29663
29934
|
}
|
|
@@ -29789,14 +30060,14 @@ var workCommand = new Command34("work").description("Track your own in-flight wo
|
|
|
29789
30060
|
// packages/cli/src/commands/handoff.ts
|
|
29790
30061
|
init_dist();
|
|
29791
30062
|
import { Command as Command35 } from "commander";
|
|
29792
|
-
import
|
|
29793
|
-
import
|
|
30063
|
+
import path57 from "path";
|
|
30064
|
+
import os23 from "os";
|
|
29794
30065
|
|
|
29795
30066
|
// packages/cli/src/lib/handoff-live-repo.ts
|
|
29796
30067
|
init_dist();
|
|
29797
|
-
import { execFileSync as
|
|
29798
|
-
import
|
|
29799
|
-
import
|
|
30068
|
+
import { execFileSync as execFileSync16 } from "child_process";
|
|
30069
|
+
import fs50 from "fs";
|
|
30070
|
+
import path55 from "path";
|
|
29800
30071
|
|
|
29801
30072
|
// packages/cli/src/lib/handoff-branch-state.ts
|
|
29802
30073
|
function tryRun(runner, cmd, args, cwd) {
|
|
@@ -29873,7 +30144,7 @@ var OPEN_PR_LIMIT = 20;
|
|
|
29873
30144
|
var RELEASE_BRANCH = "main";
|
|
29874
30145
|
var defaultCommandRunner = {
|
|
29875
30146
|
run(cmd, args, cwd) {
|
|
29876
|
-
return
|
|
30147
|
+
return execFileSync16(cmd, args, { cwd, encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"] });
|
|
29877
30148
|
}
|
|
29878
30149
|
};
|
|
29879
30150
|
function tryRun2(runner, cmd, args, cwd) {
|
|
@@ -29935,7 +30206,7 @@ function localAheadOfBase(runner, projectPath, base) {
|
|
|
29935
30206
|
}
|
|
29936
30207
|
function readFetchAgeMs(projectPath, now) {
|
|
29937
30208
|
try {
|
|
29938
|
-
const stat2 =
|
|
30209
|
+
const stat2 = fs50.statSync(path55.join(projectPath, ".git", "FETCH_HEAD"));
|
|
29939
30210
|
return Math.max(0, now - stat2.mtime.getTime());
|
|
29940
30211
|
} catch {
|
|
29941
30212
|
return null;
|
|
@@ -30006,7 +30277,7 @@ function gatherLiveRepoState(projectPath, fallbackBaseBranch, tasks, runner = de
|
|
|
30006
30277
|
|
|
30007
30278
|
// packages/cli/src/lib/handoff-claude-mem.ts
|
|
30008
30279
|
import { createRequire } from "module";
|
|
30009
|
-
import
|
|
30280
|
+
import fs51 from "fs";
|
|
30010
30281
|
var { DatabaseSync } = createRequire(import.meta.url)("node:sqlite");
|
|
30011
30282
|
var CLAUDE_MEM_RECENCY_LIMIT = 20;
|
|
30012
30283
|
function decisionText(row) {
|
|
@@ -30020,7 +30291,7 @@ function decisionText(row) {
|
|
|
30020
30291
|
return row.narrative ?? "";
|
|
30021
30292
|
}
|
|
30022
30293
|
function queryClaudeMem(dbPath, project) {
|
|
30023
|
-
if (!
|
|
30294
|
+
if (!fs51.existsSync(dbPath)) return null;
|
|
30024
30295
|
let db;
|
|
30025
30296
|
try {
|
|
30026
30297
|
db = new DatabaseSync(dbPath, { readOnly: true });
|
|
@@ -30063,7 +30334,7 @@ function queryClaudeMem(dbPath, project) {
|
|
|
30063
30334
|
}
|
|
30064
30335
|
|
|
30065
30336
|
// packages/cli/src/lib/handoff-transcript.ts
|
|
30066
|
-
import
|
|
30337
|
+
import fs52 from "fs";
|
|
30067
30338
|
var TRANSCRIPT_BYTE_CAP = 2e5;
|
|
30068
30339
|
var DIGEST_BYTE_CAP = 8 * 1024;
|
|
30069
30340
|
var PROMPT_TRUNCATE_CHARS = 300;
|
|
@@ -30172,27 +30443,27 @@ function extractMessages(tailText) {
|
|
|
30172
30443
|
return { lastUserMessage, lastAssistantText, digest };
|
|
30173
30444
|
}
|
|
30174
30445
|
function extractTranscriptTail(transcriptPath, byteCap = TRANSCRIPT_BYTE_CAP) {
|
|
30175
|
-
if (!
|
|
30176
|
-
const content =
|
|
30446
|
+
if (!fs52.existsSync(transcriptPath)) return null;
|
|
30447
|
+
const content = fs52.readFileSync(transcriptPath, "utf-8");
|
|
30177
30448
|
const { lastUserMessage, lastAssistantText, digest } = extractMessages(tailOf(content, byteCap));
|
|
30178
|
-
const mtimeIso =
|
|
30449
|
+
const mtimeIso = fs52.statSync(transcriptPath).mtime.toISOString();
|
|
30179
30450
|
return { path: transcriptPath, mtimeIso, lastUserMessage, lastAssistantText, digest };
|
|
30180
30451
|
}
|
|
30181
30452
|
|
|
30182
30453
|
// packages/cli/src/lib/handoff-archive.ts
|
|
30183
|
-
import
|
|
30184
|
-
import
|
|
30454
|
+
import fs53 from "fs";
|
|
30455
|
+
import path56 from "path";
|
|
30185
30456
|
function readNewestArchivedHandoff(spokeVault, now) {
|
|
30186
|
-
const dir =
|
|
30187
|
-
if (!
|
|
30188
|
-
const candidates =
|
|
30189
|
-
const full =
|
|
30190
|
-
return { name: e.name, full, mtime:
|
|
30457
|
+
const dir = path56.join(spokeVault, "handoffs");
|
|
30458
|
+
if (!fs53.existsSync(dir)) return null;
|
|
30459
|
+
const candidates = fs53.readdirSync(dir, { withFileTypes: true }).filter((e) => e.isFile() && e.name.endsWith(".json")).map((e) => {
|
|
30460
|
+
const full = path56.join(dir, e.name);
|
|
30461
|
+
return { name: e.name, full, mtime: fs53.statSync(full).mtime };
|
|
30191
30462
|
}).sort((a, b) => b.mtime.getTime() - a.mtime.getTime());
|
|
30192
30463
|
for (const candidate of candidates) {
|
|
30193
30464
|
let content;
|
|
30194
30465
|
try {
|
|
30195
|
-
content = JSON.parse(
|
|
30466
|
+
content = JSON.parse(fs53.readFileSync(candidate.full, "utf-8"));
|
|
30196
30467
|
} catch {
|
|
30197
30468
|
continue;
|
|
30198
30469
|
}
|
|
@@ -30202,7 +30473,7 @@ function readNewestArchivedHandoff(spokeVault, now) {
|
|
|
30202
30473
|
}
|
|
30203
30474
|
|
|
30204
30475
|
// packages/cli/src/commands/handoff.ts
|
|
30205
|
-
var CLAUDE_MEM_DB_PATH =
|
|
30476
|
+
var CLAUDE_MEM_DB_PATH = path57.join(os23.homedir(), ".claude-mem", "claude-mem.db");
|
|
30206
30477
|
async function defaultFetchTasks(project) {
|
|
30207
30478
|
return await squadrantdCall({ kind: "list", project });
|
|
30208
30479
|
}
|
|
@@ -30270,9 +30541,9 @@ function filterSessions(rows, f) {
|
|
|
30270
30541
|
if (f.agent && r.agent !== f.agent) return false;
|
|
30271
30542
|
if (f.liveOnly && r.status === "stale") return false;
|
|
30272
30543
|
if (f.project) {
|
|
30273
|
-
const
|
|
30544
|
+
const path60 = f.projects?.[f.project];
|
|
30274
30545
|
const byRecord = r.project === f.project;
|
|
30275
|
-
const byCwd = !!
|
|
30546
|
+
const byCwd = !!path60 && !!r.cwd && (r.cwd === normalized(path60) || r.cwd.startsWith(normalized(path60) + "/"));
|
|
30276
30547
|
if (!byRecord && !byCwd) return false;
|
|
30277
30548
|
}
|
|
30278
30549
|
return true;
|
|
@@ -30362,8 +30633,8 @@ var sessionsCommand = new Command36("sessions").description("List live agent ses
|
|
|
30362
30633
|
init_dist();
|
|
30363
30634
|
init_dist2();
|
|
30364
30635
|
init_dist3();
|
|
30365
|
-
import
|
|
30366
|
-
import
|
|
30636
|
+
import os24 from "os";
|
|
30637
|
+
import path58 from "path";
|
|
30367
30638
|
import { Command as Command37 } from "commander";
|
|
30368
30639
|
import chalk36 from "chalk";
|
|
30369
30640
|
|
|
@@ -30481,7 +30752,7 @@ function buildWhoamiDeps(opts = {}) {
|
|
|
30481
30752
|
const projects = Object.fromEntries(
|
|
30482
30753
|
Object.entries(config.projects).map(([n, p]) => [n, resolveHome(p.path)])
|
|
30483
30754
|
);
|
|
30484
|
-
const root = stateRoot ??
|
|
30755
|
+
const root = stateRoot ?? path58.join(os24.homedir(), ".config", "squadrant", "state");
|
|
30485
30756
|
const store = createStore(root);
|
|
30486
30757
|
const merged = {
|
|
30487
30758
|
env: process.env,
|
|
@@ -30533,11 +30804,11 @@ var whoamiCommand = new Command37("whoami").description("Show the agent session
|
|
|
30533
30804
|
// packages/cli/src/commands/knowledge.ts
|
|
30534
30805
|
init_dist();
|
|
30535
30806
|
init_dist2();
|
|
30536
|
-
import
|
|
30537
|
-
import
|
|
30538
|
-
import
|
|
30807
|
+
import fs54 from "fs";
|
|
30808
|
+
import os25 from "os";
|
|
30809
|
+
import path59 from "path";
|
|
30539
30810
|
import readline4 from "readline/promises";
|
|
30540
|
-
import { spawnSync } from "child_process";
|
|
30811
|
+
import { spawnSync as spawnSync2 } from "child_process";
|
|
30541
30812
|
import { Command as Command39 } from "commander";
|
|
30542
30813
|
import chalk38 from "chalk";
|
|
30543
30814
|
|
|
@@ -30602,7 +30873,8 @@ function runRulesSearch(query, opts, configPath = DEFAULT_CONFIG_PATH) {
|
|
|
30602
30873
|
const rules = loadFor(opts, configPath);
|
|
30603
30874
|
const hits = searchRules(rules, query, { statuses: opts.all ? [...RULE_STATUSES] : DEFAULT_SEARCH_STATUSES });
|
|
30604
30875
|
const project = resolveRulesProject(loadConfig(configPath), opts);
|
|
30605
|
-
|
|
30876
|
+
const shown = hits.slice(0, parseLimit(opts.limit));
|
|
30877
|
+
appendAudit(shown.length ? shown.map((h) => ({ ...ruleAuditScope(h.rule), project, domain: "rules", itemId: h.rule.id, event: "item.searched", query, score: h.score })) : [{ kb: "", level: "project", project, domain: "rules", itemId: "", event: "item.searched", query }], opts.audit);
|
|
30606
30878
|
return hits;
|
|
30607
30879
|
}
|
|
30608
30880
|
function runRulesList(opts, configPath = DEFAULT_CONFIG_PATH) {
|
|
@@ -30685,18 +30957,18 @@ function runKnowledgeInit(kb, configPath = DEFAULT_CONFIG_PATH) {
|
|
|
30685
30957
|
const cfg = loadConfig(configPath);
|
|
30686
30958
|
const dir = kbDir(cfg, kb);
|
|
30687
30959
|
const created = [];
|
|
30688
|
-
for (const d of [
|
|
30689
|
-
if (!
|
|
30690
|
-
|
|
30691
|
-
created.push(
|
|
30960
|
+
for (const d of [path59.join(dir, "raw"), kbRulesDir(cfg, kb), path59.join(kbRulesDir(cfg, kb), PROPOSED_DIR)]) {
|
|
30961
|
+
if (!fs54.existsSync(d)) {
|
|
30962
|
+
fs54.mkdirSync(d, { recursive: true });
|
|
30963
|
+
created.push(path59.relative(dir, d));
|
|
30692
30964
|
}
|
|
30693
30965
|
}
|
|
30694
|
-
const sourcesFile =
|
|
30695
|
-
if (!
|
|
30696
|
-
|
|
30966
|
+
const sourcesFile = path59.join(dir, "sources.yaml");
|
|
30967
|
+
if (!fs54.existsSync(sourcesFile)) {
|
|
30968
|
+
fs54.writeFileSync(sourcesFile, SOURCES_TEMPLATE);
|
|
30697
30969
|
created.push("sources.yaml");
|
|
30698
30970
|
}
|
|
30699
|
-
if (!
|
|
30971
|
+
if (!fs54.existsSync(path59.join(dir, "index.json"))) {
|
|
30700
30972
|
writeIndex(dir, compileIndex(kb, []));
|
|
30701
30973
|
created.push("index.json");
|
|
30702
30974
|
}
|
|
@@ -30713,7 +30985,7 @@ function runKnowledgeSubscribe(kb, project, configPath = DEFAULT_CONFIG_PATH) {
|
|
|
30713
30985
|
const cfg = loadConfig(configPath);
|
|
30714
30986
|
const pc = cfg.projects[project];
|
|
30715
30987
|
if (!pc) throw new Error(`Unknown project '${project}'`);
|
|
30716
|
-
if (!
|
|
30988
|
+
if (!fs54.existsSync(kbDir(cfg, kb))) {
|
|
30717
30989
|
throw new Error(`Knowledge base '${kb}' does not exist. Run: squadrant knowledge init ${kb}`);
|
|
30718
30990
|
}
|
|
30719
30991
|
const list = pc.knowledge ?? [];
|
|
@@ -30728,6 +31000,12 @@ function runKnowledgeSources(kb, configPath = DEFAULT_CONFIG_PATH) {
|
|
|
30728
31000
|
const cfg = loadConfig(configPath);
|
|
30729
31001
|
return loadSources(kbDir(cfg, kb));
|
|
30730
31002
|
}
|
|
31003
|
+
function runKnowledgeSourcesRemove(kb, entryPath, opts = {}, configPath = DEFAULT_CONFIG_PATH) {
|
|
31004
|
+
assertKbName(kb);
|
|
31005
|
+
const cfg = loadConfig(configPath);
|
|
31006
|
+
if (!fs54.existsSync(kbDir(cfg, kb))) throw new Error(`Knowledge base '${kb}' does not exist. Run: squadrant knowledge init ${kb}`);
|
|
31007
|
+
return removeSource(kbDir(cfg, kb), kbRulesDir(cfg, kb), entryPath, { ...opts, kbName: kb });
|
|
31008
|
+
}
|
|
30731
31009
|
var knowledgeCommand = new Command39("knowledge").description("Manage rules knowledge bases (#893)");
|
|
30732
31010
|
knowledgeCommand.command("init <kb>").description("Create a knowledge base (its own git repo) under ~/squadrant/kb/<kb>/").action((kb) => {
|
|
30733
31011
|
const { dir, created } = runKnowledgeInit(kb);
|
|
@@ -30739,11 +31017,20 @@ knowledgeCommand.command("subscribe <kb>").description("Subscribe a project to a
|
|
|
30739
31017
|
const list = runKnowledgeSubscribe(kb, opts.project);
|
|
30740
31018
|
console.log(`${opts.project} knowledge: ${list.join(", ")}`);
|
|
30741
31019
|
});
|
|
30742
|
-
knowledgeCommand.command("sources <kb>").description("List the trusted sources of a knowledge base").action((kb) => {
|
|
31020
|
+
knowledgeCommand.command("sources <kb>").description("List the trusted sources of a knowledge base; --remove drops one and strips its refs from rules").option("--remove <path>", "remove the sources.yaml entry with this exact path; rules left with no source become stale").option("--dry-run", "with --remove: print what would change, write nothing").action((kb, o) => {
|
|
31021
|
+
if (o.dryRun && !o.remove) throw new Error("--dry-run only applies to --remove");
|
|
31022
|
+
if (o.remove) {
|
|
31023
|
+
const r = runKnowledgeSourcesRemove(kb, o.remove, { dryRun: o.dryRun });
|
|
31024
|
+
const stripped = r.stripped.length - r.stale.length;
|
|
31025
|
+
console.log(`${r.dryRun ? "would remove" : "removed"} ${o.remove}: ${r.stripped.length} rules lose a ref, ${r.stale.length} left with no source (stale), ${stripped} keep another source`);
|
|
31026
|
+
for (const id of r.stale) console.log(chalk38.yellow(` stale: ${id}`));
|
|
31027
|
+
if (r.dryRun) console.log(chalk38.dim("dry run: nothing written"));
|
|
31028
|
+
return;
|
|
31029
|
+
}
|
|
30743
31030
|
const { sources, errors } = runKnowledgeSources(kb);
|
|
30744
31031
|
if (!sources.length && !errors.length) console.log("(no sources \u2014 edit sources.yaml)");
|
|
30745
31032
|
for (const s of sources) {
|
|
30746
|
-
console.log(` ${s.priority.padEnd(8)} ${s.path}${s.domain ? ` [${s.domain}]` : ""}${s.sensitivity ? chalk38.yellow(" local-only") : ""}`);
|
|
31033
|
+
console.log(` ${s.priority.padEnd(8)} ${s.path}${s.domain ? ` [${s.domain}]` : ""}${s.sensitivity ? chalk38.yellow(" local-only") : ""}${s.review ? chalk38.cyan(" review: required") : ""}`);
|
|
30747
31034
|
}
|
|
30748
31035
|
for (const e of errors) console.log(chalk38.red(` \u2718 ${e}`));
|
|
30749
31036
|
if (errors.length) process.exitCode = 1;
|
|
@@ -30751,9 +31038,9 @@ knowledgeCommand.command("sources <kb>").description("List the trusted sources o
|
|
|
30751
31038
|
function runKnowledgeReindex(kb, configPath = DEFAULT_CONFIG_PATH) {
|
|
30752
31039
|
assertKbName(kb);
|
|
30753
31040
|
const cfg = loadConfig(configPath);
|
|
30754
|
-
if (!
|
|
31041
|
+
if (!fs54.existsSync(kbDir(cfg, kb))) throw new Error(`Knowledge base '${kb}' does not exist. Run: squadrant knowledge init ${kb}`);
|
|
30755
31042
|
const { rules: all, errors: allErrors } = loadKbRules(cfg, kb, { includeProposed: true });
|
|
30756
|
-
const proposedRoot =
|
|
31043
|
+
const proposedRoot = path59.join(kbRulesDir(cfg, kb), PROPOSED_DIR) + path59.sep;
|
|
30757
31044
|
const live = all.filter((r) => !r.file.startsWith(proposedRoot));
|
|
30758
31045
|
const pendingDups = allErrors.filter((e) => isPendingProposalDup(e, kbRulesDir(cfg, kb)));
|
|
30759
31046
|
const errors = allErrors.filter((e) => !pendingDups.includes(e));
|
|
@@ -30763,11 +31050,15 @@ function runKnowledgeReindex(kb, configPath = DEFAULT_CONFIG_PATH) {
|
|
|
30763
31050
|
function runKnowledgeValidate(kb, configPath = DEFAULT_CONFIG_PATH) {
|
|
30764
31051
|
assertKbName(kb);
|
|
30765
31052
|
const cfg = loadConfig(configPath);
|
|
30766
|
-
if (!
|
|
31053
|
+
if (!fs54.existsSync(kbDir(cfg, kb))) throw new Error(`Knowledge base '${kb}' does not exist. Run: squadrant knowledge init ${kb}`);
|
|
30767
31054
|
const { sources, errors } = loadSources(kbDir(cfg, kb));
|
|
30768
|
-
const
|
|
30769
|
-
const
|
|
30770
|
-
|
|
31055
|
+
const { errata, errors: errataErrors } = loadErrata(kbDir(cfg, kb));
|
|
31056
|
+
const res = validateKb({ rulesDir: kbRulesDir(cfg, kb), kbRoot: kbDir(cfg, kb), sources, errata, domains: kbConfigs(cfg)[kb]?.domains });
|
|
31057
|
+
const srcChecks = [
|
|
31058
|
+
...errors.map((e) => ({ level: "fail", message: `sources.yaml: ${e}` })),
|
|
31059
|
+
...errataErrors.map((e) => ({ level: "fail", message: `errata.yaml: ${e}` }))
|
|
31060
|
+
];
|
|
31061
|
+
return { checks: [...srcChecks, ...res.checks], ok: res.ok && !srcChecks.length };
|
|
30771
31062
|
}
|
|
30772
31063
|
knowledgeCommand.command("reindex <kb>").description("Recompile index.json from the KB's rule files").action((kb) => {
|
|
30773
31064
|
const r = runKnowledgeReindex(kb);
|
|
@@ -30793,7 +31084,7 @@ knowledgeCommand.command("migrate").description("Move <hubVault>/knowledge/<kb>/
|
|
|
30793
31084
|
function requireKb(kb, configPath) {
|
|
30794
31085
|
assertKbName(kb);
|
|
30795
31086
|
const cfg = loadConfig(configPath);
|
|
30796
|
-
if (!
|
|
31087
|
+
if (!fs54.existsSync(kbDir(cfg, kb))) throw new Error(`Knowledge base '${kb}' does not exist. Run: squadrant knowledge init ${kb}`);
|
|
30797
31088
|
return cfg;
|
|
30798
31089
|
}
|
|
30799
31090
|
async function runKnowledgeIngest(kb, opts = {}, configPath = DEFAULT_CONFIG_PATH) {
|
|
@@ -30812,10 +31103,14 @@ async function runKnowledgeIngest(kb, opts = {}, configPath = DEFAULT_CONFIG_PAT
|
|
|
30812
31103
|
}
|
|
30813
31104
|
function runKnowledgeApply(kb, candidatesFile, configPath = DEFAULT_CONFIG_PATH) {
|
|
30814
31105
|
const cfg = requireKb(kb, configPath);
|
|
30815
|
-
const input = JSON.parse(
|
|
31106
|
+
const input = JSON.parse(fs54.readFileSync(candidatesFile, "utf8"));
|
|
30816
31107
|
if (!input || !Array.isArray(input.candidates)) throw new Error("candidates file must be { complete?: string[], candidates: [...] }");
|
|
30817
31108
|
const projects = Object.entries(cfg.projects).filter(([name, pc]) => pc.path && subscribedKbs(cfg, name).includes(kb)).map(([name, pc]) => ({ name, root: resolveHome(pc.path) }));
|
|
30818
|
-
|
|
31109
|
+
const { errata, errors } = loadErrata(kbDir(cfg, kb));
|
|
31110
|
+
if (errors.length) throw new Error(`errata.yaml: ${errors.join("; ")}`);
|
|
31111
|
+
const { sources, errors: sourceErrors } = loadSources(kbDir(cfg, kb));
|
|
31112
|
+
if (sourceErrors.length) throw new Error(`sources.yaml: ${sourceErrors.join("; ")}`);
|
|
31113
|
+
return applyCandidates(input, { kb, kbRoot: kbDir(cfg, kb), rulesDir: kbRulesDir(cfg, kb), projects, sources, errata });
|
|
30819
31114
|
}
|
|
30820
31115
|
knowledgeCommand.command("ingest <kb>").description("Detect changed sources, convert them (markitdown) into .converted/, and print the section plan for the knowledge-extract skill").option("--dry-run", "estimate tokens only; write nothing").option("--json", "print the full plan as JSON").option("--local-model", "a local model is available, so sensitivity: local-only sources are planned instead of skipped").option("--max-sections <n>", "override maxSectionsPerPass", (v2) => parseInt(v2, 10)).action(async (kb, opts) => {
|
|
30821
31116
|
const plan = await runKnowledgeIngest(kb, opts);
|
|
@@ -30834,16 +31129,19 @@ knowledgeCommand.command("apply <kb> <candidates>").description("Verify extracte
|
|
|
30834
31129
|
console.log(`created ${r.created.length}, merged ${r.merged.length}, proposed ${r.proposed.length}, superseded ${r.superseded.length}, stale ${r.stale.length}, rejected ${r.rejected.length}`);
|
|
30835
31130
|
for (const x of r.rejected) console.log(chalk38.red(` \u2718 ${x.id} (${x.source}): ${x.reason}`));
|
|
30836
31131
|
for (const x of r.idOverrides) console.log(chalk38.dim(` id ${x.from} \u2192 ${x.to} (matched by quote offset)`));
|
|
31132
|
+
for (const e of r.orphanedErrata) console.log(chalk38.yellow(` errata ${e.id} (${e.ref}): quote no longer found; the raw file changed, re-check it`));
|
|
30837
31133
|
for (const d of r.doclingFlags) console.log(chalk38.yellow(` ${d.ref}: ${d.dropped}/${d.total} candidates dropped; conversion likely poor, try docling`));
|
|
30838
31134
|
});
|
|
30839
|
-
var defaultStateRoot2 = () =>
|
|
31135
|
+
var defaultStateRoot2 = () => path59.join(path59.dirname(DEFAULT_CONFIG_PATH), "state");
|
|
30840
31136
|
function reviewContext(kb, configPath) {
|
|
30841
31137
|
const cfg = requireKb(kb, configPath);
|
|
30842
31138
|
const projects = Object.entries(cfg.projects).filter(([name, pc]) => pc.path && subscribedKbs(cfg, name).includes(kb)).map(([name, pc]) => ({ name, root: resolveHome(pc.path) }));
|
|
30843
|
-
|
|
31139
|
+
const { sources, errors } = loadSources(kbDir(cfg, kb));
|
|
31140
|
+
if (errors.length) throw new Error(`sources.yaml: ${errors.join("; ")}`);
|
|
31141
|
+
return { cfg, kb, sources, projects };
|
|
30844
31142
|
}
|
|
30845
31143
|
function runKnowledgeReviewApply(kb, file, configPath = DEFAULT_CONFIG_PATH) {
|
|
30846
|
-
return applyDecisions(JSON.parse(
|
|
31144
|
+
return applyDecisions(JSON.parse(fs54.readFileSync(file, "utf8")), reviewContext(kb, configPath));
|
|
30847
31145
|
}
|
|
30848
31146
|
function runKnowledgeResolve(kb, key, r, by, reason, configPath = DEFAULT_CONFIG_PATH) {
|
|
30849
31147
|
return resolveEscalation(reviewContext(kb, configPath), key, r, by, reason);
|
|
@@ -30863,7 +31161,7 @@ knowledgeCommand.command("review <kb>").description("Escalations for the operato
|
|
|
30863
31161
|
for (const x of r.skipped) console.log(chalk38.red(` \u2718 ${x.item}: ${x.reason}`));
|
|
30864
31162
|
return;
|
|
30865
31163
|
}
|
|
30866
|
-
const by =
|
|
31164
|
+
const by = os25.userInfo().username;
|
|
30867
31165
|
const resolution = () => o.keepDoc ? { kind: "verdict", verdict: "keep-doc" } : o.supersedeWithCode ? { kind: "verdict", verdict: "supersede-with-code" } : o.approve ? { kind: "approve" } : o.reject ? { kind: "reject" } : null;
|
|
30868
31166
|
if (o.resolve) {
|
|
30869
31167
|
const r = resolution();
|
|
@@ -30891,8 +31189,8 @@ ${e.explanation}`);
|
|
|
30891
31189
|
else if (ans === "r") r = { kind: "reject" };
|
|
30892
31190
|
else if (ans === "e" && e.kind === "proposal") {
|
|
30893
31191
|
const ctx = reviewContext(kb, DEFAULT_CONFIG_PATH);
|
|
30894
|
-
const file =
|
|
30895
|
-
|
|
31192
|
+
const file = path59.join(kbRulesDir(ctx.cfg, kb), PROPOSED_DIR, `${e.item}.md`);
|
|
31193
|
+
spawnSync2(process.env.EDITOR ?? "vi", [file], { stdio: "inherit" });
|
|
30896
31194
|
r = { kind: "approve" };
|
|
30897
31195
|
}
|
|
30898
31196
|
if (r) console.log(chalk38.green(runKnowledgeResolve(kb, e.key, r, by, reason)));
|
|
@@ -30963,7 +31261,7 @@ function renderStats(all) {
|
|
|
30963
31261
|
const pct = (x) => x === null ? "-" : `${Math.round(x * 100)}%`;
|
|
30964
31262
|
return all.flatMap((s) => [
|
|
30965
31263
|
`${s.kb} (last ${s.windowDays} days)`,
|
|
30966
|
-
...s.items.map((x) => ` ${x.itemId} surfaced ${x.surfaced} pulled ${x.
|
|
31264
|
+
...s.items.map((x) => ` ${x.itemId} surfaced ${x.surfaced} pulled ${x.pullRate} cited ${x.cited} use ${pct(x.useRate)} noise ${pct(x.noiseRate)} violated ${pct(x.violationRate)}${x.neverFired30d ? " NEVER FIRED" : ""}`),
|
|
30967
31265
|
...s.domains.map((d) => ` domain ${d.domain}: writes ${d.writesPerMonth}/mo reads ${d.readsPerMonth}/mo${d.deadDomain ? " DEAD DOMAIN" : ""}`),
|
|
30968
31266
|
` agents: ${Object.entries(s.perAgentCoverage).map(([k, v2]) => `${k} ${v2}`).join(", ") || "none"}`
|
|
30969
31267
|
]);
|
|
@@ -30974,10 +31272,10 @@ knowledgeCommand.command("stats").description("Scores computed from the audit lo
|
|
|
30974
31272
|
else for (const l of renderStats(all)) console.log(l);
|
|
30975
31273
|
});
|
|
30976
31274
|
function runKnowledgeCiteScan(o) {
|
|
30977
|
-
const run = o.git_run ?? ((args) =>
|
|
31275
|
+
const run = o.git_run ?? ((args) => spawnSync2("git", args, { encoding: "utf8" }).stdout ?? "");
|
|
30978
31276
|
if (o.git) {
|
|
30979
31277
|
const since = new Date((o.audit?.now?.() ?? /* @__PURE__ */ new Date()).getTime() - (o.sinceDays ?? 30) * 864e5);
|
|
30980
|
-
return readGitMessages(o.git, since, run).
|
|
31278
|
+
return scanCitations(readGitMessages(o.git, since, run).map((c) => ({ text: c.text, ref: `git:${c.sha}`, at: c.at })), { project: o.project, sink: o.audit });
|
|
30981
31279
|
}
|
|
30982
31280
|
if (!o.text) throw new Error("Pass --text <message> or --git <repo>");
|
|
30983
31281
|
return scanAndLogCitations({ text: o.text, ref: o.ref ?? "manual", project: o.project, sink: o.audit });
|