squadrant 0.27.1 → 0.28.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +755 -515
- package/dist/index.js.map +1 -1
- package/dist/squadrantd.js +451 -258
- 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,11 @@ 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 sourceCovers(kbRoot, entry, ref) {
|
|
10432
|
+
const abs = path16.resolve(kbRoot, expandHome(entry.path));
|
|
10433
|
+
const file = fileForRef(kbRoot, ref);
|
|
10434
|
+
return /[*?]/.test(entry.path) ? globToRegExp(abs.split(path16.sep).join("/")).test(file.split(path16.sep).join("/")) : abs === file;
|
|
10435
|
+
}
|
|
10409
10436
|
function detectChange(kbRoot, file) {
|
|
10410
10437
|
const ref = refFor(kbRoot, file);
|
|
10411
10438
|
const st = fs15.statSync(file);
|
|
@@ -10502,7 +10529,7 @@ async function planIngest(kbRoot, opts) {
|
|
|
10502
10529
|
}
|
|
10503
10530
|
return plan;
|
|
10504
10531
|
}
|
|
10505
|
-
var execFileAsync, CONVERTED_DIR, DEFAULT_MAX_SECTIONS_PER_PASS, CHARS_PER_TOKEN, PASS_THROUGH, SECTION_TARGET_CHARS, markitdownConverter, expandHome, fileForRef, cacheKey, convertedFile, stampFile, sha256;
|
|
10532
|
+
var execFileAsync, CONVERTED_DIR, DEFAULT_MAX_SECTIONS_PER_PASS, CHARS_PER_TOKEN, PASS_THROUGH, SECTION_TARGET_CHARS, markitdownConverter, expandHome, fileForRef, cacheKey, convertedFile, stampFile, isGatedRef, sha256;
|
|
10506
10533
|
var init_ingest = __esm({
|
|
10507
10534
|
"packages/core/dist/knowledge/ingest.js"() {
|
|
10508
10535
|
execFileAsync = promisify2(execFile2);
|
|
@@ -10520,6 +10547,7 @@ var init_ingest = __esm({
|
|
|
10520
10547
|
cacheKey = (ref) => `${ref.replace(/[^A-Za-z0-9._-]+/g, "_")}.${crypto3.createHash("sha1").update(ref).digest("hex").slice(0, 6)}`;
|
|
10521
10548
|
convertedFile = (kbRoot, ref) => path16.join(kbRoot, CONVERTED_DIR, `${cacheKey(ref)}.md`);
|
|
10522
10549
|
stampFile = (kbRoot, ref) => path16.join(kbRoot, CONVERTED_DIR, `${cacheKey(ref)}.sha`);
|
|
10550
|
+
isGatedRef = (kbRoot, sources, ref) => sources.some((e) => e.review === "required" && sourceCovers(kbRoot, e, ref));
|
|
10523
10551
|
sha256 = (file) => crypto3.createHash("sha256").update(fs15.readFileSync(file)).digest("hex");
|
|
10524
10552
|
}
|
|
10525
10553
|
});
|
|
@@ -10712,9 +10740,14 @@ function validateKb(opts) {
|
|
|
10712
10740
|
});
|
|
10713
10741
|
}
|
|
10714
10742
|
const { hay, convertible } = cache.get(key);
|
|
10715
|
-
|
|
10743
|
+
const span = findQuote(hay, src.quote);
|
|
10744
|
+
if (span) {
|
|
10716
10745
|
verified++;
|
|
10717
|
-
|
|
10746
|
+
const active = r.status === "active" && !path17.relative(opts.rulesDir, r.file).split(path17.sep).includes(PROPOSED_DIR);
|
|
10747
|
+
const err = active ? (opts.errata ?? []).find((e) => e.ref === src.ref && ((o) => !!o && spansOverlap(o, span))(findQuote(hay, e.quote))) : void 0;
|
|
10748
|
+
if (err)
|
|
10749
|
+
checks.push({ level: "warn", message: `${r.id}: grounded in erratum ${err.id} (${err.reason}); re-check or retire it (${r.file})` });
|
|
10750
|
+
} else if (convertible)
|
|
10718
10751
|
notIngested++;
|
|
10719
10752
|
else
|
|
10720
10753
|
checks.push({ level: "fail", message: `quote not found in ${file}: ${r.id} sources[${i}] (${r.file})` });
|
|
@@ -13919,6 +13952,7 @@ var init_js_yaml = __esm({
|
|
|
13919
13952
|
// packages/core/dist/knowledge/sources.js
|
|
13920
13953
|
import fs19 from "fs";
|
|
13921
13954
|
import path19 from "path";
|
|
13955
|
+
import matter3 from "gray-matter";
|
|
13922
13956
|
function loadSources(kbRoot) {
|
|
13923
13957
|
const file = path19.join(kbRoot, "sources.yaml");
|
|
13924
13958
|
if (!fs19.existsSync(file))
|
|
@@ -13944,20 +13978,77 @@ function loadSources(kbRoot) {
|
|
|
13944
13978
|
});
|
|
13945
13979
|
return { sources, errors };
|
|
13946
13980
|
}
|
|
13981
|
+
function dropEntryBlock(text, entryPath) {
|
|
13982
|
+
const lines = text.split("\n");
|
|
13983
|
+
const q = entryPath.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
13984
|
+
const head = new RegExp(`^-\\s+path:\\s*(['"]?)${q}\\1\\s*(#.*)?$`);
|
|
13985
|
+
const i = lines.findIndex((l) => head.test(l));
|
|
13986
|
+
if (i < 0)
|
|
13987
|
+
return null;
|
|
13988
|
+
let j = i + 1;
|
|
13989
|
+
while (j < lines.length && /^\s+\S/.test(lines[j]))
|
|
13990
|
+
j++;
|
|
13991
|
+
return [...lines.slice(0, i), ...lines.slice(j)].join("\n");
|
|
13992
|
+
}
|
|
13993
|
+
function removeSource(kbRoot, rulesDir, entryPath, opts = {}) {
|
|
13994
|
+
const file = path19.join(kbRoot, "sources.yaml");
|
|
13995
|
+
const { sources } = loadSources(kbRoot);
|
|
13996
|
+
const entry = sources.find((s) => s.path === entryPath);
|
|
13997
|
+
if (!entry)
|
|
13998
|
+
throw new Error(`no sources.yaml entry with path '${entryPath}' (give it exactly as listed by \`knowledge sources\`)`);
|
|
13999
|
+
const edited = dropEntryBlock(fs19.readFileSync(file, "utf8"), entryPath);
|
|
14000
|
+
if (edited === null)
|
|
14001
|
+
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`);
|
|
14002
|
+
const res = { dryRun: !!opts.dryRun, entryRemoved: true, stripped: [], stale: [] };
|
|
14003
|
+
const writes = [];
|
|
14004
|
+
for (const rule2 of loadRulesDir(rulesDir, "kb").rules) {
|
|
14005
|
+
const kept = rule2.sources.filter((s) => !sourceCovers(kbRoot, entry, s.ref));
|
|
14006
|
+
if (kept.length === rule2.sources.length)
|
|
14007
|
+
continue;
|
|
14008
|
+
res.stripped.push(rule2.id);
|
|
14009
|
+
const parsed = matter3(fs19.readFileSync(rule2.file, "utf8"), { engines: { javascript: () => {
|
|
14010
|
+
throw new Error("only YAML front matter is allowed");
|
|
14011
|
+
} } });
|
|
14012
|
+
const fm = { ...parsed.data, sources: kept };
|
|
14013
|
+
if (!kept.length) {
|
|
14014
|
+
res.stale.push(rule2.id);
|
|
14015
|
+
if (fm.status === "active")
|
|
14016
|
+
fm.status = "stale";
|
|
14017
|
+
}
|
|
14018
|
+
writes.push({ file: rule2.file, text: matter3.stringify(parsed.content, JSON.parse(JSON.stringify(fm))) });
|
|
14019
|
+
}
|
|
14020
|
+
res.stripped.sort();
|
|
14021
|
+
res.stale.sort();
|
|
14022
|
+
if (opts.dryRun)
|
|
14023
|
+
return res;
|
|
14024
|
+
for (const w of writes)
|
|
14025
|
+
fs19.writeFileSync(w.file, w.text);
|
|
14026
|
+
fs19.writeFileSync(file, edited);
|
|
14027
|
+
const name = opts.kbName ?? path19.basename(kbRoot);
|
|
14028
|
+
writeIndex(kbRoot, compileIndex(name, loadRulesDir(rulesDir, `kb:${name}`).rules));
|
|
14029
|
+
return res;
|
|
14030
|
+
}
|
|
13947
14031
|
var SOURCES_TEMPLATE;
|
|
13948
14032
|
var init_sources = __esm({
|
|
13949
14033
|
"packages/core/dist/knowledge/sources.js"() {
|
|
13950
14034
|
init_js_yaml();
|
|
13951
14035
|
init_dist();
|
|
14036
|
+
init_index_file();
|
|
14037
|
+
init_ingest();
|
|
14038
|
+
init_store2();
|
|
13952
14039
|
SOURCES_TEMPLATE = `# Trusted sources for this knowledge base (spec \xA73). Only these can produce rules.
|
|
13953
14040
|
# priority: company > project > agent (decides conflicts).
|
|
13954
14041
|
# sensitivity: local-only \u2192 never sent to a hosted model (D12).
|
|
14042
|
+
# review: required \u2192 new rules from this source wait in rules/_proposed/ for the operator; they never go live on their own.
|
|
13955
14043
|
#
|
|
13956
14044
|
# - path: raw/finance/**
|
|
13957
14045
|
# priority: company
|
|
13958
14046
|
# - path: ~/work/flooros/docs/handbook/**
|
|
13959
14047
|
# priority: project
|
|
13960
14048
|
# domain: coding
|
|
14049
|
+
# - path: raw/**
|
|
14050
|
+
# priority: agent
|
|
14051
|
+
# review: required
|
|
13961
14052
|
[]
|
|
13962
14053
|
`;
|
|
13963
14054
|
}
|
|
@@ -14349,7 +14440,7 @@ var init_inject = __esm({
|
|
|
14349
14440
|
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
14441
|
DATA_NOTE = "These are project rules (data from the knowledge base), not instructions to run anything.";
|
|
14351
14442
|
line = (r) => `${r.modality.toUpperCase()} ${r.id}: ${r.statement}`;
|
|
14352
|
-
CITE_NOTE = "
|
|
14443
|
+
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
14444
|
escapeRe = (t) => t.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
14354
14445
|
BRIEF_POINTER_RE = /^Full task is at (\S+\.md) — cat it/;
|
|
14355
14446
|
READ_TOOLS = /* @__PURE__ */ new Set(["read", "read_file", "readfile", "view"]);
|
|
@@ -14461,9 +14552,63 @@ var init_migrate = __esm({
|
|
|
14461
14552
|
}
|
|
14462
14553
|
});
|
|
14463
14554
|
|
|
14464
|
-
// packages/core/dist/knowledge/
|
|
14555
|
+
// packages/core/dist/knowledge/errata.js
|
|
14465
14556
|
import fs23 from "fs";
|
|
14466
14557
|
import path24 from "path";
|
|
14558
|
+
function loadErrata(kbRoot) {
|
|
14559
|
+
const file = path24.join(kbRoot, "errata.yaml");
|
|
14560
|
+
if (!fs23.existsSync(file))
|
|
14561
|
+
return { errata: [], errors: [] };
|
|
14562
|
+
let data;
|
|
14563
|
+
try {
|
|
14564
|
+
data = yaml.load(fs23.readFileSync(file, "utf8"), { schema: yaml.JSON_SCHEMA });
|
|
14565
|
+
} catch (e) {
|
|
14566
|
+
return { errata: [], errors: [`YAML parse error: ${e.message.split("\n")[0]}`] };
|
|
14567
|
+
}
|
|
14568
|
+
if (data == null)
|
|
14569
|
+
return { errata: [], errors: [] };
|
|
14570
|
+
if (!Array.isArray(data))
|
|
14571
|
+
return { errata: [], errors: ["errata.yaml must be a YAML list of entries"] };
|
|
14572
|
+
const errata = [];
|
|
14573
|
+
const errors = [];
|
|
14574
|
+
data.forEach((entry, i) => {
|
|
14575
|
+
const problems = validateErratum(entry);
|
|
14576
|
+
if (problems.length)
|
|
14577
|
+
errors.push(...problems.map((p) => `entry ${i}: ${p}`));
|
|
14578
|
+
else
|
|
14579
|
+
errata.push(entry);
|
|
14580
|
+
});
|
|
14581
|
+
return { errata, errors };
|
|
14582
|
+
}
|
|
14583
|
+
function orphanedErrata(kbRoot, errata, refs) {
|
|
14584
|
+
const only = refs ? new Set(refs) : void 0;
|
|
14585
|
+
const hays = /* @__PURE__ */ new Map();
|
|
14586
|
+
const out = [];
|
|
14587
|
+
for (const e of errata) {
|
|
14588
|
+
if (only && !only.has(e.ref))
|
|
14589
|
+
continue;
|
|
14590
|
+
if (!hays.has(e.ref)) {
|
|
14591
|
+
const conv = readState2(kbRoot, e.ref) ? convertedFile(kbRoot, e.ref) : null;
|
|
14592
|
+
hays.set(e.ref, conv && fs23.existsSync(conv) ? normalizedViews(fs23.readFileSync(conv, "utf8")) : null);
|
|
14593
|
+
}
|
|
14594
|
+
const hay = hays.get(e.ref);
|
|
14595
|
+
if (hay && !findQuote(hay, e.quote))
|
|
14596
|
+
out.push({ id: e.id, ref: e.ref });
|
|
14597
|
+
}
|
|
14598
|
+
return out;
|
|
14599
|
+
}
|
|
14600
|
+
var init_errata = __esm({
|
|
14601
|
+
"packages/core/dist/knowledge/errata.js"() {
|
|
14602
|
+
init_js_yaml();
|
|
14603
|
+
init_dist();
|
|
14604
|
+
init_ingest();
|
|
14605
|
+
init_verify();
|
|
14606
|
+
}
|
|
14607
|
+
});
|
|
14608
|
+
|
|
14609
|
+
// packages/core/dist/knowledge/anchor.js
|
|
14610
|
+
import fs24 from "fs";
|
|
14611
|
+
import path25 from "path";
|
|
14467
14612
|
function* repoFiles(root) {
|
|
14468
14613
|
let count = 0;
|
|
14469
14614
|
const stack = [root];
|
|
@@ -14471,43 +14616,43 @@ function* repoFiles(root) {
|
|
|
14471
14616
|
const dir = stack.pop();
|
|
14472
14617
|
let ents;
|
|
14473
14618
|
try {
|
|
14474
|
-
ents =
|
|
14619
|
+
ents = fs24.readdirSync(dir, { withFileTypes: true }).sort((a, b) => a.name < b.name ? 1 : -1);
|
|
14475
14620
|
} catch {
|
|
14476
14621
|
continue;
|
|
14477
14622
|
}
|
|
14478
14623
|
for (const ent of ents) {
|
|
14479
14624
|
if (ent.isDirectory()) {
|
|
14480
14625
|
if (!SKIP_DIRS.has(ent.name))
|
|
14481
|
-
stack.push(
|
|
14482
|
-
} else if (ent.isFile() && CODE_EXT.has(
|
|
14626
|
+
stack.push(path25.join(dir, ent.name));
|
|
14627
|
+
} else if (ent.isFile() && CODE_EXT.has(path25.extname(ent.name))) {
|
|
14483
14628
|
if (++count > MAX_FILES)
|
|
14484
14629
|
return;
|
|
14485
|
-
yield
|
|
14630
|
+
yield path25.join(dir, ent.name);
|
|
14486
14631
|
}
|
|
14487
14632
|
}
|
|
14488
14633
|
}
|
|
14489
14634
|
}
|
|
14490
14635
|
function computeAnchor(repoRoot, triggers) {
|
|
14491
14636
|
const terms2 = anchorTerms(triggers);
|
|
14492
|
-
if (!terms2.length || !
|
|
14637
|
+
if (!terms2.length || !fs24.existsSync(repoRoot))
|
|
14493
14638
|
return null;
|
|
14494
14639
|
const hits = [];
|
|
14495
14640
|
for (const file of repoFiles(repoRoot)) {
|
|
14496
14641
|
let text;
|
|
14497
14642
|
try {
|
|
14498
|
-
if (
|
|
14643
|
+
if (fs24.statSync(file).size > MAX_FILE_BYTES)
|
|
14499
14644
|
continue;
|
|
14500
|
-
text =
|
|
14645
|
+
text = fs24.readFileSync(file, "utf8");
|
|
14501
14646
|
} catch {
|
|
14502
14647
|
continue;
|
|
14503
14648
|
}
|
|
14504
|
-
const hay = `${
|
|
14649
|
+
const hay = `${path25.relative(repoRoot, file)}
|
|
14505
14650
|
${text}`.toLowerCase();
|
|
14506
14651
|
const score = terms2.filter((t) => hay.includes(t)).length;
|
|
14507
14652
|
if (!score)
|
|
14508
14653
|
continue;
|
|
14509
14654
|
const symbols2 = [...text.matchAll(SYMBOL_RE)].map((m) => m[1]).filter((s) => terms2.some((t) => s.toLowerCase().includes(t)));
|
|
14510
|
-
hits.push({ rel:
|
|
14655
|
+
hits.push({ rel: path25.relative(repoRoot, file).split(path25.sep).join("/"), score, symbols: symbols2 });
|
|
14511
14656
|
}
|
|
14512
14657
|
if (!hits.length)
|
|
14513
14658
|
return null;
|
|
@@ -14531,11 +14676,11 @@ var init_anchor = __esm({
|
|
|
14531
14676
|
});
|
|
14532
14677
|
|
|
14533
14678
|
// packages/core/dist/knowledge/extract.js
|
|
14534
|
-
import
|
|
14535
|
-
import
|
|
14536
|
-
import
|
|
14679
|
+
import fs25 from "fs";
|
|
14680
|
+
import path26 from "path";
|
|
14681
|
+
import matter4 from "gray-matter";
|
|
14537
14682
|
function serialize(fm, body) {
|
|
14538
|
-
return
|
|
14683
|
+
return matter4.stringify(body.trim() + "\n", clean(fm));
|
|
14539
14684
|
}
|
|
14540
14685
|
function validateCandidate(c) {
|
|
14541
14686
|
const p = [];
|
|
@@ -14578,9 +14723,9 @@ function upsertSource(fm, src) {
|
|
|
14578
14723
|
}
|
|
14579
14724
|
function applyCandidates(input, opts) {
|
|
14580
14725
|
const { kb, kbRoot, rulesDir } = opts;
|
|
14581
|
-
const res = { created: [], merged: [], proposed: [], superseded: [], stale: [], rejected: [], doclingFlags: [], idOverrides: [] };
|
|
14726
|
+
const res = { created: [], merged: [], proposed: [], superseded: [], stale: [], rejected: [], doclingFlags: [], idOverrides: [], orphanedErrata: [] };
|
|
14582
14727
|
const events = [];
|
|
14583
|
-
const ev2 = (event, itemId,
|
|
14728
|
+
const ev2 = (event, itemId, extra = {}) => events.push({ kb, level: "group", project: "", domain: "rules", itemId, event, ...extra });
|
|
14584
14729
|
const loaded = loadRulesDir(rulesDir, `kb:${kb}`);
|
|
14585
14730
|
const work = /* @__PURE__ */ new Map();
|
|
14586
14731
|
for (const r of loaded.rules) {
|
|
@@ -14599,13 +14744,13 @@ function applyCandidates(input, opts) {
|
|
|
14599
14744
|
}
|
|
14600
14745
|
const st = readState2(kbRoot, cand.source);
|
|
14601
14746
|
const convFile = st ? convertedFile(kbRoot, cand.source) : null;
|
|
14602
|
-
if (!st || !
|
|
14747
|
+
if (!st || !fs25.existsSync(convFile)) {
|
|
14603
14748
|
res.rejected.push({ id: cand.id, source: cand.source, reason: "unknown source (not ingested)" });
|
|
14604
14749
|
continue;
|
|
14605
14750
|
}
|
|
14606
14751
|
let hay = norm.get(cand.source);
|
|
14607
14752
|
if (!hay) {
|
|
14608
|
-
hay = normalizedViews(
|
|
14753
|
+
hay = normalizedViews(fs25.readFileSync(convFile, "utf8"));
|
|
14609
14754
|
norm.set(cand.source, hay);
|
|
14610
14755
|
}
|
|
14611
14756
|
const tot = totals.get(cand.source) ?? { total: 0, dropped: 0 };
|
|
@@ -14615,7 +14760,14 @@ function applyCandidates(input, opts) {
|
|
|
14615
14760
|
if (!offset) {
|
|
14616
14761
|
tot.dropped++;
|
|
14617
14762
|
res.rejected.push({ id: cand.id, source: cand.source, reason: "ungrounded" });
|
|
14618
|
-
ev2("item.rejected", cand.id,
|
|
14763
|
+
ev2("item.rejected", cand.id, { reason: "ungrounded" });
|
|
14764
|
+
continue;
|
|
14765
|
+
}
|
|
14766
|
+
const hit = (opts.errata ?? []).find((e) => e.ref === cand.source && ((o) => !!o && spansOverlap(o, offset))(findQuote(hay, e.quote)));
|
|
14767
|
+
if (hit) {
|
|
14768
|
+
tot.total--;
|
|
14769
|
+
res.rejected.push({ id: cand.id, source: cand.source, reason: `errata:${hit.id}` });
|
|
14770
|
+
ev2("item.rejected", cand.id, { reason: `errata:${hit.id}` });
|
|
14619
14771
|
continue;
|
|
14620
14772
|
}
|
|
14621
14773
|
let id = cand.id;
|
|
@@ -14647,7 +14799,7 @@ ${cand.rationale.trim()}` : "");
|
|
|
14647
14799
|
}
|
|
14648
14800
|
continue;
|
|
14649
14801
|
}
|
|
14650
|
-
if (!target && contradicted.length === 0) {
|
|
14802
|
+
if (!target && contradicted.length === 0 && !isGatedRef(kbRoot, opts.sources ?? [], cand.source)) {
|
|
14651
14803
|
const fm2 = {
|
|
14652
14804
|
id,
|
|
14653
14805
|
domain: cand.domain,
|
|
@@ -14660,9 +14812,9 @@ ${cand.rationale.trim()}` : "");
|
|
|
14660
14812
|
supersedes: [],
|
|
14661
14813
|
conflictsWith: []
|
|
14662
14814
|
};
|
|
14663
|
-
work.set(id, { fm: fm2, body: bodyOf(), file:
|
|
14815
|
+
work.set(id, { fm: fm2, body: bodyOf(), file: path26.join(rulesDir, cand.domain, `${id}.md`), dirty: true, isNew: true });
|
|
14664
14816
|
res.created.push(id);
|
|
14665
|
-
ev2("item.applied", id
|
|
14817
|
+
ev2("item.applied", id);
|
|
14666
14818
|
continue;
|
|
14667
14819
|
}
|
|
14668
14820
|
const fm = {
|
|
@@ -14677,26 +14829,26 @@ ${cand.rationale.trim()}` : "");
|
|
|
14677
14829
|
supersedes: [],
|
|
14678
14830
|
conflictsWith: contradicted
|
|
14679
14831
|
};
|
|
14680
|
-
const dir =
|
|
14681
|
-
const file =
|
|
14832
|
+
const dir = path26.join(rulesDir, PROPOSED_DIR);
|
|
14833
|
+
const file = path26.join(dir, `${id}@${st.sha.slice(0, SHA_LEN)}.md`);
|
|
14682
14834
|
const text = serialize(fm, bodyOf());
|
|
14683
|
-
if (
|
|
14835
|
+
if (fs25.existsSync(file) && fs25.readFileSync(file, "utf8") === text)
|
|
14684
14836
|
continue;
|
|
14685
|
-
|
|
14686
|
-
for (const other of
|
|
14687
|
-
if (!other.startsWith(`${id}@`) || !other.endsWith(".md") ||
|
|
14837
|
+
fs25.mkdirSync(dir, { recursive: true });
|
|
14838
|
+
for (const other of fs25.readdirSync(dir)) {
|
|
14839
|
+
if (!other.startsWith(`${id}@`) || !other.endsWith(".md") || path26.join(dir, other) === file)
|
|
14688
14840
|
continue;
|
|
14689
|
-
const old =
|
|
14841
|
+
const old = matter4(fs25.readFileSync(path26.join(dir, other), "utf8"));
|
|
14690
14842
|
if (!old.data.sources?.some((s) => s.ref === cand.source))
|
|
14691
14843
|
continue;
|
|
14692
|
-
|
|
14693
|
-
|
|
14844
|
+
fs25.writeFileSync(path26.join(dir, other.replace(/\.md$/, ".superseded")), matter4.stringify(old.content, { ...old.data, supersededBy: path26.basename(file) }));
|
|
14845
|
+
fs25.rmSync(path26.join(dir, other));
|
|
14694
14846
|
res.superseded.push(other.replace(/\.md$/, ""));
|
|
14695
|
-
ev2("item.superseded", id
|
|
14847
|
+
ev2("item.superseded", id);
|
|
14696
14848
|
}
|
|
14697
|
-
|
|
14849
|
+
fs25.writeFileSync(file, text);
|
|
14698
14850
|
res.proposed.push(`${id}@${st.sha.slice(0, SHA_LEN)}`);
|
|
14699
|
-
ev2("item.proposed", id
|
|
14851
|
+
ev2("item.proposed", id);
|
|
14700
14852
|
}
|
|
14701
14853
|
for (const [id, w] of work) {
|
|
14702
14854
|
if (touched.has(id) || w.fm.status !== "active" || w.isNew)
|
|
@@ -14722,11 +14874,12 @@ ${cand.rationale.trim()}` : "");
|
|
|
14722
14874
|
for (const w of work.values()) {
|
|
14723
14875
|
if (!w.dirty)
|
|
14724
14876
|
continue;
|
|
14725
|
-
|
|
14877
|
+
fs25.mkdirSync(path26.dirname(w.file), { recursive: true });
|
|
14726
14878
|
const text = serialize(w.fm, w.body);
|
|
14727
|
-
if (!
|
|
14728
|
-
|
|
14879
|
+
if (!fs25.existsSync(w.file) || fs25.readFileSync(w.file, "utf8") !== text)
|
|
14880
|
+
fs25.writeFileSync(w.file, text);
|
|
14729
14881
|
}
|
|
14882
|
+
res.orphanedErrata = orphanedErrata(kbRoot, opts.errata ?? [], totals.keys());
|
|
14730
14883
|
for (const [ref, t] of totals)
|
|
14731
14884
|
if (needsDocling(t.dropped, t.total))
|
|
14732
14885
|
res.doclingFlags.push({ ref, ...t });
|
|
@@ -14743,6 +14896,7 @@ var init_extract = __esm({
|
|
|
14743
14896
|
init_anchor();
|
|
14744
14897
|
init_index_file();
|
|
14745
14898
|
init_ingest();
|
|
14899
|
+
init_errata();
|
|
14746
14900
|
init_paths();
|
|
14747
14901
|
init_store2();
|
|
14748
14902
|
init_verify();
|
|
@@ -14759,20 +14913,20 @@ var init_extract = __esm({
|
|
|
14759
14913
|
});
|
|
14760
14914
|
|
|
14761
14915
|
// packages/core/dist/knowledge/schedule.js
|
|
14762
|
-
import
|
|
14763
|
-
import
|
|
14916
|
+
import fs26 from "fs";
|
|
14917
|
+
import path27 from "path";
|
|
14764
14918
|
function readSchedule(stateRoot) {
|
|
14765
14919
|
try {
|
|
14766
|
-
return JSON.parse(
|
|
14920
|
+
return JSON.parse(fs26.readFileSync(scheduleFile(stateRoot), "utf8"));
|
|
14767
14921
|
} catch {
|
|
14768
14922
|
return {};
|
|
14769
14923
|
}
|
|
14770
14924
|
}
|
|
14771
14925
|
function writeSchedule(stateRoot, s) {
|
|
14772
|
-
|
|
14926
|
+
fs26.mkdirSync(stateRoot, { recursive: true });
|
|
14773
14927
|
const tmp = `${scheduleFile(stateRoot)}.${process.pid}.tmp`;
|
|
14774
|
-
|
|
14775
|
-
|
|
14928
|
+
fs26.writeFileSync(tmp, JSON.stringify(s, null, 2) + "\n");
|
|
14929
|
+
fs26.renameSync(tmp, scheduleFile(stateRoot));
|
|
14776
14930
|
}
|
|
14777
14931
|
function snapshotSources(kbRoot, sources) {
|
|
14778
14932
|
const out = {};
|
|
@@ -14852,7 +15006,7 @@ async function tickKnowledgeSchedule(d) {
|
|
|
14852
15006
|
continue;
|
|
14853
15007
|
try {
|
|
14854
15008
|
const root = kbDir(d.cfg, kb);
|
|
14855
|
-
if (!
|
|
15009
|
+
if (!fs26.existsSync(root))
|
|
14856
15010
|
continue;
|
|
14857
15011
|
const { sources } = loadSources(root);
|
|
14858
15012
|
if (!sources.length)
|
|
@@ -14917,7 +15071,7 @@ var init_schedule = __esm({
|
|
|
14917
15071
|
init_sources();
|
|
14918
15072
|
RUNNING_STALE_MS = 6 * 60 * 60 * 1e3;
|
|
14919
15073
|
DAY_MS = 24 * 60 * 60 * 1e3;
|
|
14920
|
-
scheduleFile = (stateRoot) =>
|
|
15074
|
+
scheduleFile = (stateRoot) => path27.join(stateRoot, "knowledge-schedule.json");
|
|
14921
15075
|
reconcileConfig = (cfg, kb) => ({ ...DEFAULT_RECONCILE, ...kbConfigs(cfg)[kb]?.reconcile });
|
|
14922
15076
|
}
|
|
14923
15077
|
});
|
|
@@ -14925,19 +15079,19 @@ var init_schedule = __esm({
|
|
|
14925
15079
|
// packages/core/dist/knowledge/review.js
|
|
14926
15080
|
import crypto4 from "crypto";
|
|
14927
15081
|
import { execFileSync as execFileSync7 } from "child_process";
|
|
14928
|
-
import
|
|
14929
|
-
import
|
|
14930
|
-
import
|
|
15082
|
+
import fs27 from "fs";
|
|
15083
|
+
import path28 from "path";
|
|
15084
|
+
import matter5 from "gray-matter";
|
|
14931
15085
|
function readEscalations(kbRoot) {
|
|
14932
15086
|
try {
|
|
14933
|
-
return JSON.parse(
|
|
15087
|
+
return JSON.parse(fs27.readFileSync(escalationsFile(kbRoot), "utf8")).items;
|
|
14934
15088
|
} catch {
|
|
14935
15089
|
return [];
|
|
14936
15090
|
}
|
|
14937
15091
|
}
|
|
14938
15092
|
function writeEscalations(kbRoot, items) {
|
|
14939
|
-
|
|
14940
|
-
|
|
15093
|
+
fs27.mkdirSync(kbRoot, { recursive: true });
|
|
15094
|
+
fs27.writeFileSync(escalationsFile(kbRoot), JSON.stringify({ items }, null, 2) + "\n");
|
|
14941
15095
|
}
|
|
14942
15096
|
function addEscalation(kbRoot, e) {
|
|
14943
15097
|
const items = readEscalations(kbRoot);
|
|
@@ -14947,8 +15101,8 @@ function addEscalation(kbRoot, e) {
|
|
|
14947
15101
|
return true;
|
|
14948
15102
|
}
|
|
14949
15103
|
function appendVerdict(kbRoot, v2, now) {
|
|
14950
|
-
|
|
14951
|
-
|
|
15104
|
+
fs27.mkdirSync(kbRoot, { recursive: true });
|
|
15105
|
+
fs27.appendFileSync(verdictsFile(kbRoot), JSON.stringify({ ts: now.toISOString(), ...v2 }) + "\n");
|
|
14952
15106
|
}
|
|
14953
15107
|
function priorityOfRef(c, ref) {
|
|
14954
15108
|
if (ref.startsWith("agent:"))
|
|
@@ -14969,20 +15123,20 @@ function loadProposals(c) {
|
|
|
14969
15123
|
const byId = new Map(live.map((r) => [r.id, r]));
|
|
14970
15124
|
const proposals = [];
|
|
14971
15125
|
const pdirs = /* @__PURE__ */ new Set();
|
|
14972
|
-
for (const f of
|
|
14973
|
-
if (
|
|
15126
|
+
for (const f of fs27.existsSync(dir) ? walkDirs(dir) : [])
|
|
15127
|
+
if (path28.basename(f) === PROPOSED_DIR)
|
|
14974
15128
|
pdirs.add(f);
|
|
14975
15129
|
for (const pd of pdirs) {
|
|
14976
15130
|
for (const rule2 of loadRulesDir(pd, `kb:${c.kb}`, { includeProposed: true }).rules) {
|
|
14977
|
-
proposals.push({ key:
|
|
15131
|
+
proposals.push({ key: path28.basename(rule2.file).replace(/\.md$/, ""), rule: rule2, live: byId.get(rule2.id) });
|
|
14978
15132
|
}
|
|
14979
15133
|
}
|
|
14980
15134
|
return { proposals, live };
|
|
14981
15135
|
}
|
|
14982
15136
|
function walkDirs(dir, out = []) {
|
|
14983
|
-
for (const e of
|
|
15137
|
+
for (const e of fs27.readdirSync(dir, { withFileTypes: true }))
|
|
14984
15138
|
if (e.isDirectory()) {
|
|
14985
|
-
const f =
|
|
15139
|
+
const f = path28.join(dir, e.name);
|
|
14986
15140
|
out.push(f);
|
|
14987
15141
|
walkDirs(f, out);
|
|
14988
15142
|
}
|
|
@@ -15011,9 +15165,9 @@ function promoteProposal(c, p, by, justification, events) {
|
|
|
15011
15165
|
continue;
|
|
15012
15166
|
const o = readFm(other.file);
|
|
15013
15167
|
o.fm.status = "retired";
|
|
15014
|
-
|
|
15168
|
+
fs27.writeFileSync(other.file, fileText(o.fm, o.body));
|
|
15015
15169
|
retired.push(id);
|
|
15016
|
-
events.push(ev(c, "item.superseded", id
|
|
15170
|
+
events.push(ev(c, "item.superseded", id));
|
|
15017
15171
|
}
|
|
15018
15172
|
const next = { ...fm, status: "active", approvedBy: by, justification, supersedes: [.../* @__PURE__ */ new Set([...fm.supersedes ?? [], ...retired])], conflictsWith: [] };
|
|
15019
15173
|
if (p.live?.decision)
|
|
@@ -15021,17 +15175,17 @@ function promoteProposal(c, p, by, justification, events) {
|
|
|
15021
15175
|
const anchors = anchorsFor(c, { ...next, anchors: p.live?.anchors ?? fm.anchors });
|
|
15022
15176
|
if (anchors)
|
|
15023
15177
|
next.anchors = anchors;
|
|
15024
|
-
const target = p.live?.file ??
|
|
15025
|
-
|
|
15026
|
-
|
|
15027
|
-
|
|
15028
|
-
events.push(ev(c, "item.approved", next.id
|
|
15178
|
+
const target = p.live?.file ?? path28.join(dir, next.domain, `${next.id}.md`);
|
|
15179
|
+
fs27.mkdirSync(path28.dirname(target), { recursive: true });
|
|
15180
|
+
fs27.writeFileSync(target, fileText(next, body));
|
|
15181
|
+
fs27.rmSync(p.rule.file);
|
|
15182
|
+
events.push(ev(c, "item.approved", next.id), ev(c, "item.applied", next.id));
|
|
15029
15183
|
if (p.live)
|
|
15030
|
-
events.push(ev(c, "item.superseded", next.id
|
|
15184
|
+
events.push(ev(c, "item.superseded", next.id));
|
|
15031
15185
|
}
|
|
15032
15186
|
function dropProposal(c, p, events) {
|
|
15033
|
-
|
|
15034
|
-
events.push(ev(c, "item.rejected", p.rule.id,
|
|
15187
|
+
fs27.rmSync(p.rule.file);
|
|
15188
|
+
events.push(ev(c, "item.rejected", p.rule.id, { reason: "reviewer" }));
|
|
15035
15189
|
}
|
|
15036
15190
|
function mergeInto(c, p, targetId, live, events) {
|
|
15037
15191
|
const t = live.find((r) => r.id === targetId);
|
|
@@ -15041,9 +15195,9 @@ function mergeInto(c, p, targetId, live, events) {
|
|
|
15041
15195
|
for (const s of p.rule.sources)
|
|
15042
15196
|
if (!tf.fm.sources.some((x) => x.ref === s.ref))
|
|
15043
15197
|
tf.fm.sources.push(s);
|
|
15044
|
-
|
|
15045
|
-
|
|
15046
|
-
events.push(ev(c, "item.superseded", p.rule.id
|
|
15198
|
+
fs27.writeFileSync(t.file, fileText(tf.fm, tf.body));
|
|
15199
|
+
fs27.rmSync(p.rule.file);
|
|
15200
|
+
events.push(ev(c, "item.superseded", p.rule.id), ev(c, "item.applied", targetId));
|
|
15047
15201
|
return true;
|
|
15048
15202
|
}
|
|
15049
15203
|
function evaluateCodeConflict(c, rule2, cc) {
|
|
@@ -15117,14 +15271,15 @@ function applyDecisions(file, c) {
|
|
|
15117
15271
|
f.fm.status = "active";
|
|
15118
15272
|
if (d.loc && f.fm.sources[0])
|
|
15119
15273
|
f.fm.sources[0].loc = d.loc;
|
|
15120
|
-
|
|
15121
|
-
|
|
15274
|
+
const noSource = !rule2.sources.length;
|
|
15275
|
+
if (conf >= threshold && !d.flag && !reasons.length && !noSource) {
|
|
15276
|
+
fs27.writeFileSync(rule2.file, fileText(f.fm, f.body));
|
|
15122
15277
|
res.applied.push(d.item);
|
|
15123
|
-
events.push(ev(c, "item.applied", rule2.id
|
|
15278
|
+
events.push(ev(c, "item.applied", rule2.id));
|
|
15124
15279
|
verdict(d, "applied", { confidence: conf });
|
|
15125
15280
|
continue;
|
|
15126
15281
|
}
|
|
15127
|
-
reasons.push(conf < threshold ? "low-confidence" : "reviewer-flagged");
|
|
15282
|
+
reasons.push(noSource ? "no-source" : conf < threshold ? "low-confidence" : "reviewer-flagged");
|
|
15128
15283
|
} else if (d.decision === "approve") {
|
|
15129
15284
|
if (strong(rule2.modality))
|
|
15130
15285
|
reasons.push("retiring must/must-not");
|
|
@@ -15135,9 +15290,9 @@ function applyDecisions(file, c) {
|
|
|
15135
15290
|
if (!reasons.length) {
|
|
15136
15291
|
const f = readFm(rule2.file);
|
|
15137
15292
|
f.fm.status = "retired";
|
|
15138
|
-
|
|
15293
|
+
fs27.writeFileSync(rule2.file, fileText(f.fm, f.body));
|
|
15139
15294
|
res.applied.push(d.item);
|
|
15140
|
-
events.push(ev(c, "item.archived", rule2.id
|
|
15295
|
+
events.push(ev(c, "item.archived", rule2.id));
|
|
15141
15296
|
verdict(d, "applied", { confidence: conf });
|
|
15142
15297
|
continue;
|
|
15143
15298
|
}
|
|
@@ -15152,6 +15307,8 @@ function applyDecisions(file, c) {
|
|
|
15152
15307
|
reasons.push("reviewer-flagged");
|
|
15153
15308
|
if (conf < threshold)
|
|
15154
15309
|
reasons.push("low-confidence");
|
|
15310
|
+
if (p.rule.sources.some((s) => isGatedRef(kbRoot, c.sources, s.ref)))
|
|
15311
|
+
reasons.push("review-required");
|
|
15155
15312
|
if (d.decision === "approve") {
|
|
15156
15313
|
const myPri = priorityOfRule(c, p.rule);
|
|
15157
15314
|
const conflicted = (p.rule.conflictsWith ?? []).map((id) => live.find((r) => r.id === id)).filter((r) => !!r);
|
|
@@ -15213,7 +15370,7 @@ function applyPair(pd, c, res, threshold, events, kbRoot, now) {
|
|
|
15213
15370
|
for (const [x, y] of [[a, b], [b, a]]) {
|
|
15214
15371
|
const f = readFm(x.file);
|
|
15215
15372
|
f.fm.conflictsWith = [.../* @__PURE__ */ new Set([...f.fm.conflictsWith ?? [], y.id])];
|
|
15216
|
-
|
|
15373
|
+
fs27.writeFileSync(x.file, fileText(f.fm, f.body));
|
|
15217
15374
|
}
|
|
15218
15375
|
return;
|
|
15219
15376
|
}
|
|
@@ -15228,11 +15385,11 @@ function applyPair(pd, c, res, threshold, events, kbRoot, now) {
|
|
|
15228
15385
|
if (!kf.fm.sources.some((x) => x.ref === s.ref))
|
|
15229
15386
|
kf.fm.sources.push(s);
|
|
15230
15387
|
kf.fm.supersedes = [.../* @__PURE__ */ new Set([...kf.fm.supersedes ?? [], drop.id])];
|
|
15231
|
-
|
|
15388
|
+
fs27.writeFileSync(keep.file, fileText(kf.fm, kf.body));
|
|
15232
15389
|
const df = readFm(drop.file);
|
|
15233
15390
|
df.fm.status = "retired";
|
|
15234
|
-
|
|
15235
|
-
events.push(ev(c, "item.superseded", drop.id
|
|
15391
|
+
fs27.writeFileSync(drop.file, fileText(df.fm, df.body));
|
|
15392
|
+
events.push(ev(c, "item.superseded", drop.id), ev(c, "item.applied", keep.id));
|
|
15236
15393
|
res.applied.push(key);
|
|
15237
15394
|
}
|
|
15238
15395
|
function resolveEscalation(c, key, r, by, reason) {
|
|
@@ -15262,9 +15419,9 @@ function resolveEscalation(c, key, r, by, reason) {
|
|
|
15262
15419
|
f.fm.decision = decision;
|
|
15263
15420
|
if (r.verdict === "supersede-with-code") {
|
|
15264
15421
|
f.fm.status = "retired";
|
|
15265
|
-
events.push(ev(c, "item.superseded", rule2.id
|
|
15422
|
+
events.push(ev(c, "item.superseded", rule2.id));
|
|
15266
15423
|
}
|
|
15267
|
-
|
|
15424
|
+
fs27.writeFileSync(rule2.file, fileText(f.fm, f.body));
|
|
15268
15425
|
return done(`${rule2.id}: ${r.verdict}`);
|
|
15269
15426
|
}
|
|
15270
15427
|
if (esc2.kind === "proposal") {
|
|
@@ -15281,23 +15438,26 @@ function resolveEscalation(c, key, r, by, reason) {
|
|
|
15281
15438
|
}
|
|
15282
15439
|
if (esc2.kind === "stale-retire") {
|
|
15283
15440
|
const rule2 = live.find((x) => x.id === esc2.ruleId);
|
|
15441
|
+
if (rule2 && r.kind !== "approve" && !rule2.sources.length) {
|
|
15442
|
+
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.`);
|
|
15443
|
+
}
|
|
15284
15444
|
if (rule2) {
|
|
15285
15445
|
const f = readFm(rule2.file);
|
|
15286
15446
|
f.fm.status = r.kind === "approve" ? "retired" : "active";
|
|
15287
|
-
|
|
15288
|
-
events.push(ev(c, r.kind === "approve" ? "item.archived" : "item.applied", rule2.id
|
|
15447
|
+
fs27.writeFileSync(rule2.file, fileText(f.fm, f.body));
|
|
15448
|
+
events.push(ev(c, r.kind === "approve" ? "item.archived" : "item.applied", rule2.id));
|
|
15289
15449
|
}
|
|
15290
15450
|
return done(`${esc2.ruleId}: ${r.kind === "approve" ? "retired" : "kept"}`);
|
|
15291
15451
|
}
|
|
15292
15452
|
if (esc2.kind === "override-base-changed") {
|
|
15293
|
-
const ov = esc2.item &&
|
|
15453
|
+
const ov = esc2.item && fs27.existsSync(esc2.item) ? esc2.item : void 0;
|
|
15294
15454
|
if (ov) {
|
|
15295
15455
|
if (r.kind === "reject")
|
|
15296
|
-
|
|
15456
|
+
fs27.rmSync(ov);
|
|
15297
15457
|
else {
|
|
15298
15458
|
const f = readFm(ov);
|
|
15299
15459
|
f.fm.overridesBase = esc2.evidence?.docRev;
|
|
15300
|
-
|
|
15460
|
+
fs27.writeFileSync(ov, fileText(f.fm, f.body));
|
|
15301
15461
|
}
|
|
15302
15462
|
}
|
|
15303
15463
|
return done(`${esc2.ruleId}: override ${r.kind === "reject" ? "dropped" : "kept"}`);
|
|
@@ -15321,11 +15481,11 @@ ${o.evidence}`).digest("hex");
|
|
|
15321
15481
|
supersedes: [],
|
|
15322
15482
|
conflictsWith: []
|
|
15323
15483
|
};
|
|
15324
|
-
const dir =
|
|
15325
|
-
|
|
15326
|
-
const file =
|
|
15327
|
-
|
|
15328
|
-
appendAudit([ev(c, "item.proposed", id
|
|
15484
|
+
const dir = path28.join(kbRulesDir(c.cfg, c.kb), PROPOSED_DIR);
|
|
15485
|
+
fs27.mkdirSync(dir, { recursive: true });
|
|
15486
|
+
const file = path28.join(dir, `${id}@${sha.slice(0, SHA_LEN2)}.md`);
|
|
15487
|
+
fs27.writeFileSync(file, fileText(fm, o.statement));
|
|
15488
|
+
appendAudit([ev(c, "item.proposed", id)], c.audit);
|
|
15329
15489
|
return file;
|
|
15330
15490
|
}
|
|
15331
15491
|
function buildReviewPacket(c) {
|
|
@@ -15365,8 +15525,8 @@ var init_review = __esm({
|
|
|
15365
15525
|
PRIORITY_RANK = { company: 3, project: 2, agent: 1 };
|
|
15366
15526
|
SHA_LEN2 = 12;
|
|
15367
15527
|
strong = (m) => m === "must" || m === "must-not";
|
|
15368
|
-
escalationsFile = (kbRoot) =>
|
|
15369
|
-
verdictsFile = (kbRoot) =>
|
|
15528
|
+
escalationsFile = (kbRoot) => path28.join(kbRoot, "escalations.json");
|
|
15529
|
+
verdictsFile = (kbRoot) => path28.join(kbRoot, "verdicts.jsonl");
|
|
15370
15530
|
needsYouCount = (kbRoot) => readEscalations(kbRoot).filter((e) => e.needsYou).length;
|
|
15371
15531
|
git = (root, args) => execFileSync7("git", ["-C", root, ...args], { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] }).trim();
|
|
15372
15532
|
realGit = {
|
|
@@ -15387,34 +15547,34 @@ var init_review = __esm({
|
|
|
15387
15547
|
},
|
|
15388
15548
|
docDate(file) {
|
|
15389
15549
|
try {
|
|
15390
|
-
const d = git(
|
|
15550
|
+
const d = git(path28.dirname(file), ["log", "-1", "--format=%cI", "--", path28.basename(file)]);
|
|
15391
15551
|
if (d)
|
|
15392
15552
|
return d;
|
|
15393
15553
|
} catch {
|
|
15394
15554
|
}
|
|
15395
15555
|
try {
|
|
15396
|
-
return
|
|
15556
|
+
return fs27.statSync(file).mtime.toISOString();
|
|
15397
15557
|
} catch {
|
|
15398
15558
|
return null;
|
|
15399
15559
|
}
|
|
15400
15560
|
}
|
|
15401
15561
|
};
|
|
15402
15562
|
nowOf = (c) => c.now?.() ?? /* @__PURE__ */ new Date();
|
|
15403
|
-
fileText = (fm, body) =>
|
|
15563
|
+
fileText = (fm, body) => matter5.stringify(body.trim() + "\n", JSON.parse(JSON.stringify(fm)));
|
|
15404
15564
|
readFm = (file) => {
|
|
15405
|
-
const m =
|
|
15565
|
+
const m = matter5(fs27.readFileSync(file, "utf8"));
|
|
15406
15566
|
return { fm: m.data, body: m.content };
|
|
15407
15567
|
};
|
|
15408
|
-
ev = (c, event, itemId,
|
|
15568
|
+
ev = (c, event, itemId, extra = {}) => ({ kb: c.kb, level: "group", project: "", domain: "rules", itemId, event, ...extra });
|
|
15409
15569
|
docRevOf = (r) => r.sources.map((s) => `${s.ref}@${s.sha.slice(0, SHA_LEN2)}`).join(",");
|
|
15410
15570
|
}
|
|
15411
15571
|
});
|
|
15412
15572
|
|
|
15413
15573
|
// packages/core/dist/knowledge/fullpass.js
|
|
15414
15574
|
import crypto5 from "crypto";
|
|
15415
|
-
import
|
|
15416
|
-
import
|
|
15417
|
-
import
|
|
15575
|
+
import fs28 from "fs";
|
|
15576
|
+
import path29 from "path";
|
|
15577
|
+
import matter6 from "gray-matter";
|
|
15418
15578
|
function dedupPairs(rules) {
|
|
15419
15579
|
const active = rules.filter((r) => r.status === "active").sort((x, y) => x.id.localeCompare(y.id));
|
|
15420
15580
|
const out = [];
|
|
@@ -15430,12 +15590,12 @@ function dedupPairs(rules) {
|
|
|
15430
15590
|
return out.slice(0, MAX_DEDUP_PAIRS);
|
|
15431
15591
|
}
|
|
15432
15592
|
function readAuditRecords(kb, since, dir = defaultAuditDir()) {
|
|
15433
|
-
if (!
|
|
15593
|
+
if (!fs28.existsSync(dir))
|
|
15434
15594
|
return [];
|
|
15435
15595
|
const sinceMonth = since.toISOString().slice(0, 7);
|
|
15436
15596
|
const out = [];
|
|
15437
|
-
for (const f of
|
|
15438
|
-
for (const line2 of
|
|
15597
|
+
for (const f of fs28.readdirSync(dir).filter((n) => n.endsWith(".jsonl") && n.slice(0, 7) >= sinceMonth).sort()) {
|
|
15598
|
+
for (const line2 of fs28.readFileSync(path29.join(dir, f), "utf8").split("\n")) {
|
|
15439
15599
|
if (!line2.trim())
|
|
15440
15600
|
continue;
|
|
15441
15601
|
try {
|
|
@@ -15498,8 +15658,8 @@ function checkOverrides(cfg, kb) {
|
|
|
15498
15658
|
continue;
|
|
15499
15659
|
const h = baseHash(b);
|
|
15500
15660
|
if (!o.overridesBase) {
|
|
15501
|
-
const m =
|
|
15502
|
-
|
|
15661
|
+
const m = matter6(fs28.readFileSync(o.file, "utf8"));
|
|
15662
|
+
fs28.writeFileSync(o.file, matter6.stringify(m.content, { ...m.data, overridesBase: h }));
|
|
15503
15663
|
continue;
|
|
15504
15664
|
}
|
|
15505
15665
|
out.push({ project, ruleId: o.id, file: o.file, baseHash: h, changed: o.overridesBase !== h });
|
|
@@ -15542,8 +15702,8 @@ var init_fullpass = __esm({
|
|
|
15542
15702
|
});
|
|
15543
15703
|
|
|
15544
15704
|
// packages/core/dist/knowledge/scores.js
|
|
15545
|
-
import
|
|
15546
|
-
import
|
|
15705
|
+
import fs29 from "fs";
|
|
15706
|
+
import path30 from "path";
|
|
15547
15707
|
function tally(records, into = emptyTally()) {
|
|
15548
15708
|
for (const e of records) {
|
|
15549
15709
|
const domain = typeof e.domain === "string" && e.domain ? e.domain : "rules";
|
|
@@ -15552,7 +15712,7 @@ function tally(records, into = emptyTally()) {
|
|
|
15552
15712
|
d.writes++;
|
|
15553
15713
|
if (READ_EVENTS.has(e.event ?? ""))
|
|
15554
15714
|
d.reads++;
|
|
15555
|
-
if (!e.itemId)
|
|
15715
|
+
if (!e.itemId || WRITE_EVENTS.has(e.event ?? ""))
|
|
15556
15716
|
continue;
|
|
15557
15717
|
const c = into.items[`${domain}|${e.itemId}`] ??= { ...zero(), domain, itemId: e.itemId };
|
|
15558
15718
|
switch (e.event) {
|
|
@@ -15589,7 +15749,7 @@ function tally(records, into = emptyTally()) {
|
|
|
15589
15749
|
}
|
|
15590
15750
|
function parseLines(file) {
|
|
15591
15751
|
const out = [];
|
|
15592
|
-
for (const line2 of
|
|
15752
|
+
for (const line2 of fs29.readFileSync(file, "utf8").split("\n")) {
|
|
15593
15753
|
if (!line2.trim())
|
|
15594
15754
|
continue;
|
|
15595
15755
|
try {
|
|
@@ -15601,37 +15761,37 @@ function parseLines(file) {
|
|
|
15601
15761
|
}
|
|
15602
15762
|
function compactAudit(o) {
|
|
15603
15763
|
const dir = o.dir ?? defaultAuditDir();
|
|
15604
|
-
if (!
|
|
15764
|
+
if (!fs29.existsSync(dir))
|
|
15605
15765
|
return [];
|
|
15606
15766
|
const cutoffMonth = new Date(o.now.getTime() - SCORE_WINDOW_DAYS * DAY_MS3).toISOString().slice(0, 7);
|
|
15607
15767
|
const done = [];
|
|
15608
|
-
for (const f of
|
|
15768
|
+
for (const f of fs29.readdirSync(dir).sort()) {
|
|
15609
15769
|
const m = MONTH_FILE_RE.exec(f);
|
|
15610
15770
|
if (!m || m[1] >= cutoffMonth)
|
|
15611
15771
|
continue;
|
|
15612
15772
|
const [, month, machine] = m;
|
|
15613
15773
|
const byKb = /* @__PURE__ */ new Map();
|
|
15614
|
-
for (const r of parseLines(
|
|
15774
|
+
for (const r of parseLines(path30.join(dir, f)))
|
|
15615
15775
|
byKb.set(r.kb ?? "", [...byKb.get(r.kb ?? "") ?? [], r]);
|
|
15616
|
-
const statsPath =
|
|
15617
|
-
const prior =
|
|
15776
|
+
const statsPath = path30.join(dir, statsFileName(month, machine));
|
|
15777
|
+
const prior = fs29.existsSync(statsPath) ? JSON.parse(fs29.readFileSync(statsPath, "utf8")) : null;
|
|
15618
15778
|
const kbs = prior?.kbs ?? {};
|
|
15619
15779
|
for (const [kb, recs] of byKb)
|
|
15620
15780
|
kbs[kb] = tally(recs, kbs[kb]);
|
|
15621
|
-
|
|
15622
|
-
|
|
15623
|
-
|
|
15781
|
+
fs29.writeFileSync(`${statsPath}.tmp`, JSON.stringify({ month, machine, kbs }));
|
|
15782
|
+
fs29.renameSync(`${statsPath}.tmp`, statsPath);
|
|
15783
|
+
fs29.unlinkSync(path30.join(dir, f));
|
|
15624
15784
|
done.push(month);
|
|
15625
15785
|
}
|
|
15626
15786
|
return done;
|
|
15627
15787
|
}
|
|
15628
15788
|
function readCompacted(kb, dir) {
|
|
15629
15789
|
const t = emptyTally();
|
|
15630
|
-
if (!
|
|
15790
|
+
if (!fs29.existsSync(dir))
|
|
15631
15791
|
return t;
|
|
15632
|
-
for (const f of
|
|
15792
|
+
for (const f of fs29.readdirSync(dir).filter((n) => n.endsWith(".stats.json"))) {
|
|
15633
15793
|
try {
|
|
15634
|
-
const k = JSON.parse(
|
|
15794
|
+
const k = JSON.parse(fs29.readFileSync(path30.join(dir, f), "utf8")).kbs[kb];
|
|
15635
15795
|
if (k)
|
|
15636
15796
|
mergeTally(t, k);
|
|
15637
15797
|
} catch {
|
|
@@ -15681,7 +15841,7 @@ function computeScores(i) {
|
|
|
15681
15841
|
noise: w.noise,
|
|
15682
15842
|
wrong: w.wrong,
|
|
15683
15843
|
fireRate: w.surfaced,
|
|
15684
|
-
pullRate: w.shown,
|
|
15844
|
+
pullRate: w.shown + w.searched,
|
|
15685
15845
|
useRate: ratio(w.cited, w.surfaced),
|
|
15686
15846
|
noiseRate: ratio(w.noise, w.surfaced),
|
|
15687
15847
|
violationRate: ratio(w.violated, w.surfaced),
|
|
@@ -15723,21 +15883,21 @@ function computeScores(i) {
|
|
|
15723
15883
|
function scoreKb(o) {
|
|
15724
15884
|
const dir = o.auditDir ?? defaultAuditDir();
|
|
15725
15885
|
const records = [];
|
|
15726
|
-
if (
|
|
15727
|
-
for (const f of
|
|
15728
|
-
records.push(...parseLines(
|
|
15886
|
+
if (fs29.existsSync(dir)) {
|
|
15887
|
+
for (const f of fs29.readdirSync(dir).filter((n) => MONTH_FILE_RE.test(n)).sort()) {
|
|
15888
|
+
records.push(...parseLines(path30.join(dir, f)).filter((r) => r.kb === o.kb));
|
|
15729
15889
|
}
|
|
15730
15890
|
}
|
|
15731
15891
|
let verdicts = [];
|
|
15732
15892
|
try {
|
|
15733
|
-
verdicts =
|
|
15893
|
+
verdicts = fs29.readFileSync(path30.join(o.kbRoot, "verdicts.jsonl"), "utf8").split("\n").filter(Boolean).map((l) => JSON.parse(l));
|
|
15734
15894
|
} catch {
|
|
15735
15895
|
}
|
|
15736
15896
|
return computeScores({ kb: o.kb, records, now: o.now, known: o.known, compacted: readCompacted(o.kb, dir), verdicts });
|
|
15737
15897
|
}
|
|
15738
15898
|
function writeScores(kbRoot, s) {
|
|
15739
|
-
|
|
15740
|
-
|
|
15899
|
+
fs29.mkdirSync(kbRoot, { recursive: true });
|
|
15900
|
+
fs29.writeFileSync(scoresFile(kbRoot), JSON.stringify(s, null, 2) + "\n");
|
|
15741
15901
|
}
|
|
15742
15902
|
function renderScoresSection(s) {
|
|
15743
15903
|
const pct = (x) => x === null ? "n/a" : `${Math.round(x * 100)}%`;
|
|
@@ -15750,7 +15910,7 @@ function renderScoresSection(s) {
|
|
|
15750
15910
|
...used.length ? [
|
|
15751
15911
|
"| Item | Surfaced | Pulled | Cited | Use | Noise | Violated |",
|
|
15752
15912
|
"|---|---|---|---|---|---|---|",
|
|
15753
|
-
...used.map((x) => `| ${x.itemId} | ${x.surfaced} | ${x.
|
|
15913
|
+
...used.map((x) => `| ${x.itemId} | ${x.surfaced} | ${x.pullRate} | ${x.cited} | ${pct(x.useRate)} | ${pct(x.noiseRate)} | ${pct(x.violationRate)} |`)
|
|
15754
15914
|
] : ["No items surfaced."],
|
|
15755
15915
|
"",
|
|
15756
15916
|
`- Never fired (${never.length}): ${never.slice(0, 20).join(", ") || "none"}${never.length > 20 ? ", \u2026" : ""}`,
|
|
@@ -15778,13 +15938,13 @@ var init_scores = __esm({
|
|
|
15778
15938
|
MONTH_FILE_RE = /^(\d{4}-\d{2})\.(.+)\.jsonl$/;
|
|
15779
15939
|
statsFileName = (month, machine) => `${month}.${machine}.stats.json`;
|
|
15780
15940
|
ratio = (n, d) => d ? Math.round(n / d * 1e3) / 1e3 : null;
|
|
15781
|
-
scoresFile = (kbRoot) =>
|
|
15941
|
+
scoresFile = (kbRoot) => path30.join(kbRoot, "scores.json");
|
|
15782
15942
|
}
|
|
15783
15943
|
});
|
|
15784
15944
|
|
|
15785
15945
|
// packages/core/dist/knowledge/report.js
|
|
15786
|
-
import
|
|
15787
|
-
import
|
|
15946
|
+
import fs30 from "fs";
|
|
15947
|
+
import path31 from "path";
|
|
15788
15948
|
function renderReport(cfg, kb, o) {
|
|
15789
15949
|
const { rules } = loadKbRules(cfg, kb, { includeProposed: true });
|
|
15790
15950
|
const count = (s) => rules.filter((r) => r.status === s).length;
|
|
@@ -15806,6 +15966,11 @@ function renderReport(cfg, kb, o) {
|
|
|
15806
15966
|
const info = esc2.filter((e) => !e.needsYou);
|
|
15807
15967
|
if (info.length)
|
|
15808
15968
|
L.push("", `## For information (${info.length})`, "", ...info.map((e) => `- **${e.key}**: ${e.explanation}`));
|
|
15969
|
+
const { errata, errors: errataErrors } = loadErrata(kbDir(cfg, kb));
|
|
15970
|
+
const orphans = orphanedErrata(kbDir(cfg, kb), errata);
|
|
15971
|
+
if (orphans.length || errataErrors.length) {
|
|
15972
|
+
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}`));
|
|
15973
|
+
}
|
|
15809
15974
|
if (o.full) {
|
|
15810
15975
|
const { usage: usage2, caps } = o.full;
|
|
15811
15976
|
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,12 +15980,13 @@ function renderReport(cfg, kb, o) {
|
|
|
15815
15980
|
return L.join("\n") + "\n";
|
|
15816
15981
|
}
|
|
15817
15982
|
function writeReport(cfg, kb, o) {
|
|
15818
|
-
const file =
|
|
15819
|
-
|
|
15983
|
+
const file = path31.join(kbDir(cfg, kb), "REPORT.md");
|
|
15984
|
+
fs30.writeFileSync(file, renderReport(cfg, kb, o));
|
|
15820
15985
|
return file;
|
|
15821
15986
|
}
|
|
15822
15987
|
var init_report = __esm({
|
|
15823
15988
|
"packages/core/dist/knowledge/report.js"() {
|
|
15989
|
+
init_errata();
|
|
15824
15990
|
init_layers();
|
|
15825
15991
|
init_paths();
|
|
15826
15992
|
init_review();
|
|
@@ -15864,44 +16030,63 @@ var init_reconcile = __esm({
|
|
|
15864
16030
|
|
|
15865
16031
|
// packages/core/dist/knowledge/cite.js
|
|
15866
16032
|
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
|
-
|
|
16033
|
+
return scanCitations([i], i);
|
|
16034
|
+
}
|
|
16035
|
+
function scanCitations(texts, o) {
|
|
16036
|
+
if (!texts.length)
|
|
16037
|
+
return [];
|
|
16038
|
+
const now = o.sink?.now?.() ?? /* @__PURE__ */ new Date();
|
|
16039
|
+
const lookbackMs = (o.lookbackDays ?? CITE_LOOKBACK_DAYS) * DAY_MS4;
|
|
16040
|
+
const ats = texts.map((t) => (t.at ?? now).getTime());
|
|
16041
|
+
const records = readAuditRecords(void 0, new Date(Math.min(...ats) - lookbackMs), o.sink?.dir ?? defaultAuditDir()).filter((r) => r.itemId && r.project === o.project);
|
|
16042
|
+
const already = new Set(records.filter((r) => r.event === "item.cited").map((r) => `${r.ref}|${r.itemId}`));
|
|
16043
|
+
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));
|
|
16044
|
+
const events = [];
|
|
16045
|
+
texts.forEach((t, n) => {
|
|
16046
|
+
const at = ats[n];
|
|
16047
|
+
const delivered = /* @__PURE__ */ new Map();
|
|
16048
|
+
for (const r of deliveries) {
|
|
16049
|
+
const ts = Date.parse(r.ts);
|
|
16050
|
+
if (ts <= at && ts >= at - lookbackMs)
|
|
16051
|
+
delivered.set(r.itemId, r);
|
|
16052
|
+
}
|
|
16053
|
+
for (const [itemId, r] of delivered) {
|
|
16054
|
+
if (already.has(`${t.ref}|${itemId}`) || !mentionsId(t.text, itemId))
|
|
16055
|
+
continue;
|
|
16056
|
+
already.add(`${t.ref}|${itemId}`);
|
|
16057
|
+
events.push({
|
|
16058
|
+
kb: String(r.kb ?? ""),
|
|
16059
|
+
level: String(r.level ?? "project"),
|
|
16060
|
+
project: o.project,
|
|
16061
|
+
domain: String(r.domain ?? "rules"),
|
|
16062
|
+
itemId,
|
|
16063
|
+
event: "item.cited",
|
|
16064
|
+
ref: t.ref,
|
|
16065
|
+
...o.agent ? { agent: o.agent } : {},
|
|
16066
|
+
...o.session ? { session: o.session } : {}
|
|
16067
|
+
});
|
|
16068
|
+
}
|
|
16069
|
+
});
|
|
16070
|
+
appendAudit(events, o.sink);
|
|
16071
|
+
return events.map((e) => e.itemId);
|
|
15896
16072
|
}
|
|
15897
16073
|
function readGitMessages(repo, since, run) {
|
|
15898
|
-
|
|
16074
|
+
return parseLog(run(["-C", repo, "log", "--all", `--since=${since.toISOString()}`, LOG_FORMAT]));
|
|
16075
|
+
}
|
|
16076
|
+
function readBranchOnlyMessages(repo, run, max = 200) {
|
|
16077
|
+
const branch = run(["-C", repo, "rev-parse", "--abbrev-ref", "HEAD"]).trim();
|
|
16078
|
+
if (!branch)
|
|
16079
|
+
return [];
|
|
16080
|
+
const own = branch === "HEAD" ? [] : [`--exclude=${branch}`];
|
|
16081
|
+
return parseLog(run(["-C", repo, "log", `--max-count=${max}`, "HEAD", "--not", ...own, "--branches", ...own.length ? [`--exclude=*/${branch}`] : [], "--remotes", LOG_FORMAT]));
|
|
16082
|
+
}
|
|
16083
|
+
function parseLog(out) {
|
|
15899
16084
|
return out.split("").filter((c) => c.trim()).map((c) => {
|
|
15900
16085
|
const [sha, at, ...rest] = c.split("");
|
|
15901
16086
|
return { sha: sha.trim(), at: new Date(at), text: rest.join("") };
|
|
15902
16087
|
});
|
|
15903
16088
|
}
|
|
15904
|
-
var DAY_MS4, CITE_LOOKBACK_DAYS, escapeRe2, mentionsId;
|
|
16089
|
+
var DAY_MS4, CITE_LOOKBACK_DAYS, escapeRe2, mentionsId, LOG_FORMAT;
|
|
15905
16090
|
var init_cite = __esm({
|
|
15906
16091
|
"packages/core/dist/knowledge/cite.js"() {
|
|
15907
16092
|
init_audit();
|
|
@@ -15910,6 +16095,7 @@ var init_cite = __esm({
|
|
|
15910
16095
|
CITE_LOOKBACK_DAYS = 7;
|
|
15911
16096
|
escapeRe2 = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
15912
16097
|
mentionsId = (text, id) => new RegExp(`(?<![\\w.-])${escapeRe2(id)}(?![\\w-])`).test(text);
|
|
16098
|
+
LOG_FORMAT = "--format=%x1e%H%x1f%cI%x1f%B";
|
|
15913
16099
|
}
|
|
15914
16100
|
});
|
|
15915
16101
|
|
|
@@ -15927,6 +16113,7 @@ var init_knowledge2 = __esm({
|
|
|
15927
16113
|
init_migrate();
|
|
15928
16114
|
init_verify();
|
|
15929
16115
|
init_ingest();
|
|
16116
|
+
init_errata();
|
|
15930
16117
|
init_anchor();
|
|
15931
16118
|
init_extract();
|
|
15932
16119
|
init_match();
|
|
@@ -16177,6 +16364,7 @@ __export(dist_exports2, {
|
|
|
16177
16364
|
isDaemonSocketLive: () => isDaemonSocketLive,
|
|
16178
16365
|
isGateCacheEnabled: () => isGateCacheEnabled,
|
|
16179
16366
|
isGateSession: () => isGateSession,
|
|
16367
|
+
isGatedRef: () => isGatedRef,
|
|
16180
16368
|
isNotifyActive: () => isNotifyActive,
|
|
16181
16369
|
isOperatorInitiatedCommand: () => isOperatorInitiatedCommand,
|
|
16182
16370
|
isPendingProposalDup: () => isPendingProposalDup,
|
|
@@ -16194,6 +16382,7 @@ __export(dist_exports2, {
|
|
|
16194
16382
|
launchOneWorkspace: () => launchOneWorkspace,
|
|
16195
16383
|
legacyKbDir: () => legacyKbDir,
|
|
16196
16384
|
listSessions: () => listSessions,
|
|
16385
|
+
loadErrata: () => loadErrata,
|
|
16197
16386
|
loadKbRules: () => loadKbRules,
|
|
16198
16387
|
loadPending: () => loadPending,
|
|
16199
16388
|
loadProposals: () => loadProposals,
|
|
@@ -16228,6 +16417,7 @@ __export(dist_exports2, {
|
|
|
16228
16417
|
normalizedViews: () => normalizedViews,
|
|
16229
16418
|
notePaneScreen: () => notePaneScreen,
|
|
16230
16419
|
notifyToggle: () => notifyToggle,
|
|
16420
|
+
orphanedErrata: () => orphanedErrata,
|
|
16231
16421
|
parseBearer: () => parseBearer,
|
|
16232
16422
|
parseClassifierVerdict: () => parseClassifierVerdict,
|
|
16233
16423
|
parseCommand: () => parseCommand,
|
|
@@ -16252,6 +16442,7 @@ __export(dist_exports2, {
|
|
|
16252
16442
|
pruneTopics: () => pruneTopics,
|
|
16253
16443
|
purgeExpiredWorkItems: () => purgeExpiredWorkItems,
|
|
16254
16444
|
readAuditRecords: () => readAuditRecords,
|
|
16445
|
+
readBranchOnlyMessages: () => readBranchOnlyMessages,
|
|
16255
16446
|
readCaptainAddress: () => readCaptainAddress,
|
|
16256
16447
|
readCursor: () => readCursor,
|
|
16257
16448
|
readEscalations: () => readEscalations,
|
|
@@ -16278,6 +16469,7 @@ __export(dist_exports2, {
|
|
|
16278
16469
|
refFor: () => refFor,
|
|
16279
16470
|
releaseDaemonLock: () => releaseDaemonLock,
|
|
16280
16471
|
removeRunningMarker: () => removeRunningMarker,
|
|
16472
|
+
removeSource: () => removeSource,
|
|
16281
16473
|
renderEnvAssignments: () => renderEnvAssignments,
|
|
16282
16474
|
renderPlist: () => renderPlist,
|
|
16283
16475
|
renderReport: () => renderReport,
|
|
@@ -16340,6 +16532,7 @@ __export(dist_exports2, {
|
|
|
16340
16532
|
saveSessions: () => saveSessions,
|
|
16341
16533
|
saveState: () => saveState,
|
|
16342
16534
|
scanAndLogCitations: () => scanAndLogCitations,
|
|
16535
|
+
scanCitations: () => scanCitations,
|
|
16343
16536
|
scheduleFile: () => scheduleFile,
|
|
16344
16537
|
scoreKb: () => scoreKb,
|
|
16345
16538
|
scoresFile: () => scoresFile,
|
|
@@ -16360,6 +16553,7 @@ __export(dist_exports2, {
|
|
|
16360
16553
|
sideNextAutoName: () => sideNextAutoName,
|
|
16361
16554
|
sideTitleFor: () => sideTitleFor,
|
|
16362
16555
|
snapshotSources: () => snapshotSources,
|
|
16556
|
+
sourceCovers: () => sourceCovers,
|
|
16363
16557
|
spansOverlap: () => spansOverlap,
|
|
16364
16558
|
splitSections: () => splitSections,
|
|
16365
16559
|
splitStatement: () => splitStatement,
|
|
@@ -16455,7 +16649,7 @@ var init_dist2 = __esm({
|
|
|
16455
16649
|
});
|
|
16456
16650
|
|
|
16457
16651
|
// packages/agents/dist/claude/registry.js
|
|
16458
|
-
import
|
|
16652
|
+
import fs31 from "fs";
|
|
16459
16653
|
import { join as join17 } from "path";
|
|
16460
16654
|
import { homedir as homedir7 } from "os";
|
|
16461
16655
|
function parseRegistryDir(files, readFile7) {
|
|
@@ -16500,11 +16694,11 @@ function readClaudeStatus(task) {
|
|
|
16500
16694
|
return void 0;
|
|
16501
16695
|
let files;
|
|
16502
16696
|
try {
|
|
16503
|
-
files =
|
|
16697
|
+
files = fs31.readdirSync(CLAUDE_SESSIONS_DIR);
|
|
16504
16698
|
} catch {
|
|
16505
16699
|
return void 0;
|
|
16506
16700
|
}
|
|
16507
|
-
const entries = parseRegistryDir(files, (name) =>
|
|
16701
|
+
const entries = parseRegistryDir(files, (name) => fs31.readFileSync(join17(CLAUDE_SESSIONS_DIR, name), "utf8"));
|
|
16508
16702
|
let entry;
|
|
16509
16703
|
if (task.messagingSocketPath) {
|
|
16510
16704
|
entry = entries.find((e) => e.messagingSocketPath === task.messagingSocketPath);
|
|
@@ -16519,11 +16713,11 @@ function readClaudeStatus(task) {
|
|
|
16519
16713
|
function readClaudeStatusByCwd(cwd) {
|
|
16520
16714
|
let files;
|
|
16521
16715
|
try {
|
|
16522
|
-
files =
|
|
16716
|
+
files = fs31.readdirSync(CLAUDE_SESSIONS_DIR);
|
|
16523
16717
|
} catch {
|
|
16524
16718
|
return void 0;
|
|
16525
16719
|
}
|
|
16526
|
-
const entries = parseRegistryDir(files, (name) =>
|
|
16720
|
+
const entries = parseRegistryDir(files, (name) => fs31.readFileSync(join17(CLAUDE_SESSIONS_DIR, name), "utf8"));
|
|
16527
16721
|
const entry = entries.find((e) => e.cwd === cwd);
|
|
16528
16722
|
if (!entry)
|
|
16529
16723
|
return void 0;
|
|
@@ -16532,11 +16726,11 @@ function readClaudeStatusByCwd(cwd) {
|
|
|
16532
16726
|
function readClaudeStatusBySocketPath(socketPath2) {
|
|
16533
16727
|
let files;
|
|
16534
16728
|
try {
|
|
16535
|
-
files =
|
|
16729
|
+
files = fs31.readdirSync(CLAUDE_SESSIONS_DIR);
|
|
16536
16730
|
} catch {
|
|
16537
16731
|
return void 0;
|
|
16538
16732
|
}
|
|
16539
|
-
const entries = parseRegistryDir(files, (name) =>
|
|
16733
|
+
const entries = parseRegistryDir(files, (name) => fs31.readFileSync(join17(CLAUDE_SESSIONS_DIR, name), "utf8"));
|
|
16540
16734
|
const entry = entries.find((e) => e.messagingSocketPath === socketPath2);
|
|
16541
16735
|
if (!entry)
|
|
16542
16736
|
return void 0;
|
|
@@ -16959,8 +17153,8 @@ var init_registry2 = __esm({
|
|
|
16959
17153
|
});
|
|
16960
17154
|
|
|
16961
17155
|
// packages/agents/dist/drivers/launch-cmd.js
|
|
16962
|
-
import
|
|
16963
|
-
import
|
|
17156
|
+
import fs32 from "fs";
|
|
17157
|
+
import path32 from "path";
|
|
16964
17158
|
function buildAgentCmd(agentName, registry, role, fresh, permissionMode, model, templatesDir, messagingSocketPath, sessionName, thinking, captainBoot, settingsPath) {
|
|
16965
17159
|
const driver = registry.getDriver(agentName);
|
|
16966
17160
|
if (driver.name === "claude") {
|
|
@@ -16987,14 +17181,14 @@ function buildAgentCmd(agentName, registry, role, fresh, permissionMode, model,
|
|
|
16987
17181
|
cmd += ` --settings ${settingsPath}`;
|
|
16988
17182
|
}
|
|
16989
17183
|
if (templatesDir) {
|
|
16990
|
-
const roleFile2 =
|
|
16991
|
-
const legacyRoleFile =
|
|
16992
|
-
const actualRoleFile =
|
|
17184
|
+
const roleFile2 = path32.join(templatesDir, `${role}.claude.md`);
|
|
17185
|
+
const legacyRoleFile = path32.join(templatesDir, `${role}.CLAUDE.md`);
|
|
17186
|
+
const actualRoleFile = fs32.existsSync(roleFile2) ? roleFile2 : fs32.existsSync(legacyRoleFile) ? legacyRoleFile : null;
|
|
16993
17187
|
if (actualRoleFile) {
|
|
16994
17188
|
cmd += ` --append-system-prompt-file ${actualRoleFile}`;
|
|
16995
17189
|
}
|
|
16996
|
-
const pluginDir =
|
|
16997
|
-
if (
|
|
17190
|
+
const pluginDir = path32.join(templatesDir, "..", "plugin");
|
|
17191
|
+
if (fs32.existsSync(pluginDir)) {
|
|
16998
17192
|
cmd += ` --plugin-dir ${pluginDir}`;
|
|
16999
17193
|
}
|
|
17000
17194
|
}
|
|
@@ -17003,14 +17197,14 @@ function buildAgentCmd(agentName, registry, role, fresh, permissionMode, model,
|
|
|
17003
17197
|
}
|
|
17004
17198
|
return cmd;
|
|
17005
17199
|
}
|
|
17006
|
-
const roleFile = templatesDir ?
|
|
17200
|
+
const roleFile = templatesDir ? path32.join(templatesDir, `${role}.${driver.templateSuffix}.md`) : void 0;
|
|
17007
17201
|
return driver.buildCommand({
|
|
17008
17202
|
prompt: `You are a squadrant ${role}. Read your instructions from ${roleFile ?? role} and begin.`,
|
|
17009
17203
|
workdir: process.cwd(),
|
|
17010
17204
|
role,
|
|
17011
17205
|
model,
|
|
17012
17206
|
autoApprove: true,
|
|
17013
|
-
promptFile: roleFile &&
|
|
17207
|
+
promptFile: roleFile && fs32.existsSync(roleFile) ? roleFile : void 0,
|
|
17014
17208
|
...captainBoot && role === "captain" ? {
|
|
17015
17209
|
interactive: true,
|
|
17016
17210
|
...captainBoot.port ? { port: captainBoot.port } : {},
|
|
@@ -17040,7 +17234,7 @@ var init_drivers = __esm({
|
|
|
17040
17234
|
|
|
17041
17235
|
// packages/agents/dist/projection/cursor.js
|
|
17042
17236
|
import { mkdir, readFile, writeFile } from "fs/promises";
|
|
17043
|
-
import
|
|
17237
|
+
import path33 from "path";
|
|
17044
17238
|
import os10 from "os";
|
|
17045
17239
|
function renderMdc(source) {
|
|
17046
17240
|
const skillSections = source.skills.map((s) => `## Skill: ${s.name}
|
|
@@ -17089,7 +17283,7 @@ function createCursorEmitter() {
|
|
|
17089
17283
|
if (scope === "user") {
|
|
17090
17284
|
return [
|
|
17091
17285
|
{
|
|
17092
|
-
path:
|
|
17286
|
+
path: path33.join(os10.homedir(), ".cursor/rules/squadrant-global.mdc"),
|
|
17093
17287
|
shared: false,
|
|
17094
17288
|
format: "mdc"
|
|
17095
17289
|
}
|
|
@@ -17099,7 +17293,7 @@ function createCursorEmitter() {
|
|
|
17099
17293
|
return [];
|
|
17100
17294
|
return [
|
|
17101
17295
|
{
|
|
17102
|
-
path:
|
|
17296
|
+
path: path33.join(projectRoot, ".cursor/rules/squadrant.mdc"),
|
|
17103
17297
|
shared: false,
|
|
17104
17298
|
format: "mdc"
|
|
17105
17299
|
}
|
|
@@ -17116,7 +17310,7 @@ function createCursorEmitter() {
|
|
|
17116
17310
|
diff: buildDiff(existing, generated)
|
|
17117
17311
|
};
|
|
17118
17312
|
}
|
|
17119
|
-
await mkdir(
|
|
17313
|
+
await mkdir(path33.dirname(dest.path), { recursive: true });
|
|
17120
17314
|
await writeFile(dest.path, generated, "utf-8");
|
|
17121
17315
|
return {
|
|
17122
17316
|
written: true,
|
|
@@ -17167,7 +17361,7 @@ var init_marker = __esm({
|
|
|
17167
17361
|
|
|
17168
17362
|
// packages/agents/dist/projection/codex.js
|
|
17169
17363
|
import { mkdir as mkdir2, readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
|
|
17170
|
-
import
|
|
17364
|
+
import path34 from "path";
|
|
17171
17365
|
import os11 from "os";
|
|
17172
17366
|
function renderMarkdown(source) {
|
|
17173
17367
|
const skillSections = source.skills.map((s) => `## Skill: ${s.name}
|
|
@@ -17192,7 +17386,7 @@ function createCodexEmitter() {
|
|
|
17192
17386
|
destinations(scope, projectRoot) {
|
|
17193
17387
|
if (scope === "user") {
|
|
17194
17388
|
return [{
|
|
17195
|
-
path:
|
|
17389
|
+
path: path34.join(os11.homedir(), ".codex/AGENTS.md"),
|
|
17196
17390
|
shared: true,
|
|
17197
17391
|
format: "markdown"
|
|
17198
17392
|
}];
|
|
@@ -17200,7 +17394,7 @@ function createCodexEmitter() {
|
|
|
17200
17394
|
if (!projectRoot)
|
|
17201
17395
|
return [];
|
|
17202
17396
|
return [{
|
|
17203
|
-
path:
|
|
17397
|
+
path: path34.join(projectRoot, "AGENTS.md"),
|
|
17204
17398
|
shared: true,
|
|
17205
17399
|
format: "markdown"
|
|
17206
17400
|
}];
|
|
@@ -17221,7 +17415,7 @@ ${existing ?? ""}
|
|
|
17221
17415
|
${generated}`
|
|
17222
17416
|
};
|
|
17223
17417
|
}
|
|
17224
|
-
await mkdir2(
|
|
17418
|
+
await mkdir2(path34.dirname(dest.path), { recursive: true });
|
|
17225
17419
|
await writeFile2(dest.path, generated, "utf-8");
|
|
17226
17420
|
return {
|
|
17227
17421
|
written: true,
|
|
@@ -17239,7 +17433,7 @@ var init_codex2 = __esm({
|
|
|
17239
17433
|
|
|
17240
17434
|
// packages/agents/dist/projection/gemini.js
|
|
17241
17435
|
import { mkdir as mkdir3, readFile as readFile3, writeFile as writeFile3 } from "fs/promises";
|
|
17242
|
-
import
|
|
17436
|
+
import path35 from "path";
|
|
17243
17437
|
import os12 from "os";
|
|
17244
17438
|
function renderMarkdown2(source) {
|
|
17245
17439
|
const skillSections = source.skills.map((s) => `## Skill: ${s.name}
|
|
@@ -17264,7 +17458,7 @@ function createGeminiEmitter() {
|
|
|
17264
17458
|
destinations(scope, projectRoot) {
|
|
17265
17459
|
if (scope === "user") {
|
|
17266
17460
|
return [{
|
|
17267
|
-
path:
|
|
17461
|
+
path: path35.join(os12.homedir(), ".gemini/GEMINI.md"),
|
|
17268
17462
|
shared: true,
|
|
17269
17463
|
format: "markdown"
|
|
17270
17464
|
}];
|
|
@@ -17272,7 +17466,7 @@ function createGeminiEmitter() {
|
|
|
17272
17466
|
if (!projectRoot)
|
|
17273
17467
|
return [];
|
|
17274
17468
|
return [{
|
|
17275
|
-
path:
|
|
17469
|
+
path: path35.join(projectRoot, "GEMINI.md"),
|
|
17276
17470
|
shared: true,
|
|
17277
17471
|
format: "markdown"
|
|
17278
17472
|
}];
|
|
@@ -17293,7 +17487,7 @@ ${existing ?? ""}
|
|
|
17293
17487
|
${generated}`
|
|
17294
17488
|
};
|
|
17295
17489
|
}
|
|
17296
|
-
await mkdir3(
|
|
17490
|
+
await mkdir3(path35.dirname(dest.path), { recursive: true });
|
|
17297
17491
|
await writeFile3(dest.path, generated, "utf-8");
|
|
17298
17492
|
return {
|
|
17299
17493
|
written: true,
|
|
@@ -17311,7 +17505,7 @@ var init_gemini2 = __esm({
|
|
|
17311
17505
|
|
|
17312
17506
|
// packages/agents/dist/projection/opencode.js
|
|
17313
17507
|
import { mkdir as mkdir4, readFile as readFile4, writeFile as writeFile4 } from "fs/promises";
|
|
17314
|
-
import
|
|
17508
|
+
import path36 from "path";
|
|
17315
17509
|
import os13 from "os";
|
|
17316
17510
|
function renderMarkdown3(source) {
|
|
17317
17511
|
const skillSections = source.skills.map((s) => `## Skill: ${s.name}
|
|
@@ -17336,7 +17530,7 @@ function createOpencodeEmitter() {
|
|
|
17336
17530
|
destinations(scope, projectRoot) {
|
|
17337
17531
|
if (scope === "user") {
|
|
17338
17532
|
return [{
|
|
17339
|
-
path:
|
|
17533
|
+
path: path36.join(os13.homedir(), ".config", "opencode", "AGENTS.md"),
|
|
17340
17534
|
shared: true,
|
|
17341
17535
|
format: "markdown"
|
|
17342
17536
|
}];
|
|
@@ -17344,7 +17538,7 @@ function createOpencodeEmitter() {
|
|
|
17344
17538
|
if (!projectRoot)
|
|
17345
17539
|
return [];
|
|
17346
17540
|
return [{
|
|
17347
|
-
path:
|
|
17541
|
+
path: path36.join(projectRoot, "AGENTS.md"),
|
|
17348
17542
|
shared: true,
|
|
17349
17543
|
format: "markdown"
|
|
17350
17544
|
}];
|
|
@@ -17365,7 +17559,7 @@ ${existing ?? ""}
|
|
|
17365
17559
|
${generated}`
|
|
17366
17560
|
};
|
|
17367
17561
|
}
|
|
17368
|
-
await mkdir4(
|
|
17562
|
+
await mkdir4(path36.dirname(dest.path), { recursive: true });
|
|
17369
17563
|
await writeFile4(dest.path, generated, "utf-8");
|
|
17370
17564
|
return {
|
|
17371
17565
|
written: true,
|
|
@@ -17382,12 +17576,12 @@ var init_opencode2 = __esm({
|
|
|
17382
17576
|
});
|
|
17383
17577
|
|
|
17384
17578
|
// packages/agents/dist/projection/opencode-skills.js
|
|
17385
|
-
import
|
|
17579
|
+
import fs33 from "fs";
|
|
17386
17580
|
import os14 from "os";
|
|
17387
|
-
import
|
|
17581
|
+
import path37 from "path";
|
|
17388
17582
|
function defaultOpencodeSkillsRoot(env = process.env) {
|
|
17389
|
-
const configHome = env.XDG_CONFIG_HOME ||
|
|
17390
|
-
return
|
|
17583
|
+
const configHome = env.XDG_CONFIG_HOME || path37.join(os14.homedir(), ".config");
|
|
17584
|
+
return path37.join(configHome, "opencode", "skills");
|
|
17391
17585
|
}
|
|
17392
17586
|
function parseSkillName(raw) {
|
|
17393
17587
|
const fm = raw.match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
|
@@ -17401,62 +17595,62 @@ function parseSkillName(raw) {
|
|
|
17401
17595
|
}
|
|
17402
17596
|
function listSourceSkills(sourceSkillsDir) {
|
|
17403
17597
|
const out = /* @__PURE__ */ new Map();
|
|
17404
|
-
if (!
|
|
17598
|
+
if (!fs33.existsSync(sourceSkillsDir))
|
|
17405
17599
|
return out;
|
|
17406
|
-
for (const entry of
|
|
17600
|
+
for (const entry of fs33.readdirSync(sourceSkillsDir, { withFileTypes: true })) {
|
|
17407
17601
|
if (!entry.isDirectory())
|
|
17408
17602
|
continue;
|
|
17409
|
-
const skillPath =
|
|
17410
|
-
if (!
|
|
17603
|
+
const skillPath = path37.join(sourceSkillsDir, entry.name, "SKILL.md");
|
|
17604
|
+
if (!fs33.existsSync(skillPath))
|
|
17411
17605
|
continue;
|
|
17412
|
-
const name = parseSkillName(
|
|
17606
|
+
const name = parseSkillName(fs33.readFileSync(skillPath, "utf-8"));
|
|
17413
17607
|
if (name && SAFE_NAME.test(name))
|
|
17414
17608
|
out.set(name, skillPath);
|
|
17415
17609
|
}
|
|
17416
17610
|
return out;
|
|
17417
17611
|
}
|
|
17418
17612
|
function hasMarker(dir) {
|
|
17419
|
-
return
|
|
17613
|
+
return fs33.existsSync(path37.join(dir, OPENCODE_SKILL_MARKER));
|
|
17420
17614
|
}
|
|
17421
17615
|
function syncOpencodeSkills(opts) {
|
|
17422
17616
|
const result = { written: [], unchanged: [], removed: [], skipped: [] };
|
|
17423
17617
|
const wanted = listSourceSkills(opts.sourceSkillsDir);
|
|
17424
|
-
if (wanted.size === 0 && !
|
|
17618
|
+
if (wanted.size === 0 && !fs33.existsSync(opts.sourceSkillsDir))
|
|
17425
17619
|
return result;
|
|
17426
17620
|
if (!opts.dryRun)
|
|
17427
|
-
|
|
17621
|
+
fs33.mkdirSync(opts.skillsRoot, { recursive: true });
|
|
17428
17622
|
for (const [name, srcPath] of wanted) {
|
|
17429
|
-
const targetDir =
|
|
17430
|
-
const targetSkill =
|
|
17623
|
+
const targetDir = path37.join(opts.skillsRoot, name);
|
|
17624
|
+
const targetSkill = path37.join(targetDir, "SKILL.md");
|
|
17431
17625
|
const managed = hasMarker(targetDir);
|
|
17432
|
-
if (
|
|
17626
|
+
if (fs33.existsSync(targetSkill) && !managed) {
|
|
17433
17627
|
result.skipped.push({ name, reason: "foreign-collision" });
|
|
17434
17628
|
continue;
|
|
17435
17629
|
}
|
|
17436
|
-
const current =
|
|
17437
|
-
if (current && current.equals(
|
|
17630
|
+
const current = fs33.existsSync(targetSkill) ? fs33.readFileSync(targetSkill) : null;
|
|
17631
|
+
if (current && current.equals(fs33.readFileSync(srcPath))) {
|
|
17438
17632
|
if (!managed && !opts.dryRun) {
|
|
17439
|
-
|
|
17633
|
+
fs33.writeFileSync(path37.join(targetDir, OPENCODE_SKILL_MARKER), MARKER_BODY);
|
|
17440
17634
|
}
|
|
17441
17635
|
result.unchanged.push(name);
|
|
17442
17636
|
continue;
|
|
17443
17637
|
}
|
|
17444
17638
|
if (!opts.dryRun) {
|
|
17445
|
-
|
|
17446
|
-
|
|
17447
|
-
|
|
17639
|
+
fs33.mkdirSync(targetDir, { recursive: true });
|
|
17640
|
+
fs33.copyFileSync(srcPath, targetSkill);
|
|
17641
|
+
fs33.writeFileSync(path37.join(targetDir, OPENCODE_SKILL_MARKER), MARKER_BODY);
|
|
17448
17642
|
}
|
|
17449
17643
|
result.written.push(name);
|
|
17450
17644
|
}
|
|
17451
|
-
if (
|
|
17452
|
-
for (const entry of
|
|
17645
|
+
if (fs33.existsSync(opts.skillsRoot)) {
|
|
17646
|
+
for (const entry of fs33.readdirSync(opts.skillsRoot, { withFileTypes: true })) {
|
|
17453
17647
|
if (!entry.isDirectory() || wanted.has(entry.name))
|
|
17454
17648
|
continue;
|
|
17455
|
-
const dir =
|
|
17649
|
+
const dir = path37.join(opts.skillsRoot, entry.name);
|
|
17456
17650
|
if (!hasMarker(dir))
|
|
17457
17651
|
continue;
|
|
17458
17652
|
if (!opts.dryRun)
|
|
17459
|
-
|
|
17653
|
+
fs33.rmSync(dir, { recursive: true, force: true });
|
|
17460
17654
|
result.removed.push(entry.name);
|
|
17461
17655
|
}
|
|
17462
17656
|
}
|
|
@@ -17464,7 +17658,7 @@ function syncOpencodeSkills(opts) {
|
|
|
17464
17658
|
}
|
|
17465
17659
|
function syncShippedOpencodeSkills(opts) {
|
|
17466
17660
|
return syncOpencodeSkills({
|
|
17467
|
-
sourceSkillsDir:
|
|
17661
|
+
sourceSkillsDir: path37.join(opts.pkgRoot, "plugin", "skills"),
|
|
17468
17662
|
skillsRoot: opts.skillsRoot ?? defaultOpencodeSkillsRoot(),
|
|
17469
17663
|
dryRun: opts.dryRun
|
|
17470
17664
|
});
|
|
@@ -17480,7 +17674,7 @@ var init_opencode_skills = __esm({
|
|
|
17480
17674
|
|
|
17481
17675
|
// packages/agents/dist/projection/claude.js
|
|
17482
17676
|
import { mkdir as mkdir5, readFile as readFile5, writeFile as writeFile5 } from "fs/promises";
|
|
17483
|
-
import
|
|
17677
|
+
import path38 from "path";
|
|
17484
17678
|
import os15 from "os";
|
|
17485
17679
|
function renderMarkdown4(source) {
|
|
17486
17680
|
const skillSections = source.skills.map((s) => `## Skill: ${s.name}
|
|
@@ -17505,7 +17699,7 @@ function createClaudeEmitter() {
|
|
|
17505
17699
|
destinations(scope, projectRoot) {
|
|
17506
17700
|
if (scope === "user") {
|
|
17507
17701
|
return [{
|
|
17508
|
-
path:
|
|
17702
|
+
path: path38.join(os15.homedir(), ".claude/CLAUDE.md"),
|
|
17509
17703
|
shared: true,
|
|
17510
17704
|
format: "markdown"
|
|
17511
17705
|
}];
|
|
@@ -17513,7 +17707,7 @@ function createClaudeEmitter() {
|
|
|
17513
17707
|
if (!projectRoot)
|
|
17514
17708
|
return [];
|
|
17515
17709
|
return [{
|
|
17516
|
-
path:
|
|
17710
|
+
path: path38.join(projectRoot, "CLAUDE.md"),
|
|
17517
17711
|
shared: true,
|
|
17518
17712
|
format: "markdown"
|
|
17519
17713
|
}];
|
|
@@ -17534,7 +17728,7 @@ ${existing ?? ""}
|
|
|
17534
17728
|
${generated}`
|
|
17535
17729
|
};
|
|
17536
17730
|
}
|
|
17537
|
-
await mkdir5(
|
|
17731
|
+
await mkdir5(path38.dirname(dest.path), { recursive: true });
|
|
17538
17732
|
await writeFile5(dest.path, generated, "utf-8");
|
|
17539
17733
|
return {
|
|
17540
17734
|
written: true,
|
|
@@ -18569,8 +18763,8 @@ function resolveLastAssistantText(payload) {
|
|
|
18569
18763
|
const derived = deriveTranscriptPath(p?.session_id, cwd);
|
|
18570
18764
|
if (derived)
|
|
18571
18765
|
candidates.push(derived);
|
|
18572
|
-
for (const
|
|
18573
|
-
const text = readLastAssistantText(
|
|
18766
|
+
for (const path60 of candidates) {
|
|
18767
|
+
const text = readLastAssistantText(path60);
|
|
18574
18768
|
if (text != null)
|
|
18575
18769
|
return text;
|
|
18576
18770
|
}
|
|
@@ -19459,22 +19653,22 @@ var init_receipt_listener = __esm({
|
|
|
19459
19653
|
});
|
|
19460
19654
|
|
|
19461
19655
|
// packages/agents/dist/claude/api-key-approval.js
|
|
19462
|
-
import
|
|
19656
|
+
import fs34 from "fs";
|
|
19463
19657
|
import os16 from "os";
|
|
19464
|
-
import
|
|
19658
|
+
import path39 from "path";
|
|
19465
19659
|
function ensureClaudeApiKeyApproved(apiKey, opts = {}) {
|
|
19466
19660
|
const suffix = apiKey.slice(-20);
|
|
19467
19661
|
if (!suffix)
|
|
19468
19662
|
return { changed: false, reason: "empty api key" };
|
|
19469
|
-
const file = opts.claudeJsonPath ??
|
|
19663
|
+
const file = opts.claudeJsonPath ?? path39.join(os16.homedir(), ".claude.json");
|
|
19470
19664
|
const log = opts.log ?? (() => {
|
|
19471
19665
|
});
|
|
19472
|
-
if (!
|
|
19666
|
+
if (!fs34.existsSync(file)) {
|
|
19473
19667
|
return { changed: false, reason: "no ~/.claude.json yet \u2014 skipping routed-key pre-approval" };
|
|
19474
19668
|
}
|
|
19475
19669
|
let doc;
|
|
19476
19670
|
try {
|
|
19477
|
-
doc = JSON.parse(
|
|
19671
|
+
doc = JSON.parse(fs34.readFileSync(file, "utf8"));
|
|
19478
19672
|
} catch {
|
|
19479
19673
|
return {
|
|
19480
19674
|
changed: false,
|
|
@@ -19496,11 +19690,11 @@ function ensureClaudeApiKeyApproved(apiKey, opts = {}) {
|
|
|
19496
19690
|
};
|
|
19497
19691
|
const tmp = `${file}.squadrant-tmp`;
|
|
19498
19692
|
try {
|
|
19499
|
-
|
|
19500
|
-
|
|
19693
|
+
fs34.writeFileSync(tmp, JSON.stringify(doc, null, 2) + "\n", { mode: fs34.statSync(file).mode & 511 });
|
|
19694
|
+
fs34.renameSync(tmp, file);
|
|
19501
19695
|
} catch (e) {
|
|
19502
19696
|
try {
|
|
19503
|
-
|
|
19697
|
+
fs34.unlinkSync(tmp);
|
|
19504
19698
|
} catch {
|
|
19505
19699
|
}
|
|
19506
19700
|
return {
|
|
@@ -19609,10 +19803,10 @@ var init_http_channel = __esm({
|
|
|
19609
19803
|
return cached;
|
|
19610
19804
|
const directory = this.directoryFor?.(taskId);
|
|
19611
19805
|
const createdAfterMs = this.createdAfterFor?.(taskId);
|
|
19612
|
-
for (const
|
|
19806
|
+
for (const path60 of ["/session?", "/api/session?"]) {
|
|
19613
19807
|
let res;
|
|
19614
19808
|
try {
|
|
19615
|
-
res = await this.request(`http://127.0.0.1:${port}${
|
|
19809
|
+
res = await this.request(`http://127.0.0.1:${port}${path60}`, { method: "GET" });
|
|
19616
19810
|
} catch {
|
|
19617
19811
|
return void 0;
|
|
19618
19812
|
}
|
|
@@ -19692,12 +19886,12 @@ var init_fact_adapter = __esm({
|
|
|
19692
19886
|
});
|
|
19693
19887
|
|
|
19694
19888
|
// packages/agents/dist/rules-hooks/install.js
|
|
19695
|
-
import
|
|
19889
|
+
import fs35 from "fs";
|
|
19696
19890
|
import os17 from "os";
|
|
19697
|
-
import
|
|
19891
|
+
import path40 from "path";
|
|
19698
19892
|
function readJson(file) {
|
|
19699
19893
|
try {
|
|
19700
|
-
const v2 = JSON.parse(
|
|
19894
|
+
const v2 = JSON.parse(fs35.readFileSync(file, "utf8"));
|
|
19701
19895
|
return typeof v2 === "object" && v2 !== null && !Array.isArray(v2) ? v2 : {};
|
|
19702
19896
|
} catch (err) {
|
|
19703
19897
|
if (err.code === "ENOENT")
|
|
@@ -19719,24 +19913,24 @@ function mergeHooks(root, agent, specs, cli, timeout) {
|
|
|
19719
19913
|
function writeIfChanged(file, next, dryRun) {
|
|
19720
19914
|
let prev = null;
|
|
19721
19915
|
try {
|
|
19722
|
-
prev =
|
|
19916
|
+
prev = fs35.readFileSync(file, "utf8");
|
|
19723
19917
|
} catch {
|
|
19724
19918
|
}
|
|
19725
19919
|
const changed = prev !== next;
|
|
19726
19920
|
if (changed && !dryRun) {
|
|
19727
|
-
|
|
19728
|
-
|
|
19921
|
+
fs35.mkdirSync(path40.dirname(file), { recursive: true });
|
|
19922
|
+
fs35.writeFileSync(file, next);
|
|
19729
19923
|
}
|
|
19730
19924
|
return { path: file, changed };
|
|
19731
19925
|
}
|
|
19732
19926
|
function installCodexRulesHooks(opts = {}) {
|
|
19733
19927
|
const env = opts.env ?? process.env;
|
|
19734
|
-
const file = opts.target ??
|
|
19928
|
+
const file = opts.target ?? path40.join(env.CODEX_HOME ?? path40.join(os17.homedir(), ".codex"), "hooks.json");
|
|
19735
19929
|
const merged = mergeHooks(readJson(file), "codex", CODEX_HOOKS, opts.cli ?? "squadrant", 5);
|
|
19736
19930
|
return writeIfChanged(file, JSON.stringify(merged, null, 2) + "\n", opts.dryRun);
|
|
19737
19931
|
}
|
|
19738
19932
|
function installGeminiRulesHooks(opts = {}) {
|
|
19739
|
-
const file = opts.target ??
|
|
19933
|
+
const file = opts.target ?? path40.join(os17.homedir(), ".gemini", "settings.json");
|
|
19740
19934
|
const merged = mergeHooks(readJson(file), "gemini", GEMINI_HOOKS, opts.cli ?? "squadrant", 5e3);
|
|
19741
19935
|
return writeIfChanged(file, JSON.stringify(merged, null, 2) + "\n", opts.dryRun);
|
|
19742
19936
|
}
|
|
@@ -19777,9 +19971,9 @@ export const SquadrantRules = async ({ directory }) => {
|
|
|
19777
19971
|
}
|
|
19778
19972
|
function installOpencodeRulesHooks(opts = {}) {
|
|
19779
19973
|
const env = opts.env ?? process.env;
|
|
19780
|
-
const file = opts.target ??
|
|
19974
|
+
const file = opts.target ?? path40.join(env.XDG_CONFIG_HOME || path40.join(os17.homedir(), ".config"), "opencode", "plugin", "squadrant-rules.js");
|
|
19781
19975
|
try {
|
|
19782
|
-
if (!
|
|
19976
|
+
if (!fs35.readFileSync(file, "utf8").startsWith(OPENCODE_PLUGIN_MARKER))
|
|
19783
19977
|
return { path: file, changed: false, skipped: "foreign-file" };
|
|
19784
19978
|
} catch {
|
|
19785
19979
|
}
|
|
@@ -20755,13 +20949,13 @@ var init_notifiers = __esm({
|
|
|
20755
20949
|
});
|
|
20756
20950
|
|
|
20757
20951
|
// packages/workspaces/dist/workspaces/obsidian.js
|
|
20758
|
-
import
|
|
20952
|
+
import fs36 from "fs/promises";
|
|
20759
20953
|
import { existsSync as existsSync11 } from "fs";
|
|
20760
|
-
import
|
|
20954
|
+
import path41 from "path";
|
|
20761
20955
|
function resolveInRoot(root, relative) {
|
|
20762
|
-
const joined =
|
|
20763
|
-
const normalized2 =
|
|
20764
|
-
if (joined !==
|
|
20956
|
+
const joined = path41.resolve(root, relative);
|
|
20957
|
+
const normalized2 = path41.resolve(root) + path41.sep;
|
|
20958
|
+
if (joined !== path41.resolve(root) && !joined.startsWith(normalized2)) {
|
|
20765
20959
|
throw new Error(`Path '${relative}' escapes workspace root`);
|
|
20766
20960
|
}
|
|
20767
20961
|
return joined;
|
|
@@ -20780,16 +20974,16 @@ function createObsidianDriver(scope) {
|
|
|
20780
20974
|
};
|
|
20781
20975
|
},
|
|
20782
20976
|
async read(rel) {
|
|
20783
|
-
return
|
|
20977
|
+
return fs36.readFile(resolveInRoot(root, rel), "utf-8");
|
|
20784
20978
|
},
|
|
20785
20979
|
async write(rel, content) {
|
|
20786
20980
|
const abs = resolveInRoot(root, rel);
|
|
20787
|
-
await
|
|
20788
|
-
await
|
|
20981
|
+
await fs36.mkdir(path41.dirname(abs), { recursive: true });
|
|
20982
|
+
await fs36.writeFile(abs, content);
|
|
20789
20983
|
},
|
|
20790
20984
|
async exists(rel) {
|
|
20791
20985
|
try {
|
|
20792
|
-
await
|
|
20986
|
+
await fs36.access(resolveInRoot(root, rel));
|
|
20793
20987
|
return true;
|
|
20794
20988
|
} catch {
|
|
20795
20989
|
return false;
|
|
@@ -20797,13 +20991,13 @@ function createObsidianDriver(scope) {
|
|
|
20797
20991
|
},
|
|
20798
20992
|
async list(rel) {
|
|
20799
20993
|
try {
|
|
20800
|
-
return await
|
|
20994
|
+
return await fs36.readdir(resolveInRoot(root, rel));
|
|
20801
20995
|
} catch {
|
|
20802
20996
|
return [];
|
|
20803
20997
|
}
|
|
20804
20998
|
},
|
|
20805
20999
|
async mkdir(rel) {
|
|
20806
|
-
await
|
|
21000
|
+
await fs36.mkdir(resolveInRoot(root, rel), { recursive: true });
|
|
20807
21001
|
}
|
|
20808
21002
|
};
|
|
20809
21003
|
}
|
|
@@ -21217,9 +21411,9 @@ function defaultListFiles(dir) {
|
|
|
21217
21411
|
return [];
|
|
21218
21412
|
}
|
|
21219
21413
|
}
|
|
21220
|
-
function defaultReadFile(
|
|
21414
|
+
function defaultReadFile(path60) {
|
|
21221
21415
|
try {
|
|
21222
|
-
return readFileSync17(
|
|
21416
|
+
return readFileSync17(path60, "utf-8");
|
|
21223
21417
|
} catch {
|
|
21224
21418
|
return void 0;
|
|
21225
21419
|
}
|
|
@@ -21712,16 +21906,16 @@ function extractDetail(sub, payload) {
|
|
|
21712
21906
|
}
|
|
21713
21907
|
return void 0;
|
|
21714
21908
|
}
|
|
21715
|
-
function defaultReadFile2(
|
|
21909
|
+
function defaultReadFile2(path60) {
|
|
21716
21910
|
try {
|
|
21717
|
-
return readFileSync18(
|
|
21911
|
+
return readFileSync18(path60, "utf-8");
|
|
21718
21912
|
} catch {
|
|
21719
21913
|
return void 0;
|
|
21720
21914
|
}
|
|
21721
21915
|
}
|
|
21722
|
-
function defaultWriteFile(
|
|
21723
|
-
mkdirSync8(
|
|
21724
|
-
writeFileSync11(
|
|
21916
|
+
function defaultWriteFile(path60, content) {
|
|
21917
|
+
mkdirSync8(path60.replace(/\/[^/]+$/, ""), { recursive: true });
|
|
21918
|
+
writeFileSync11(path60, content, "utf-8");
|
|
21725
21919
|
}
|
|
21726
21920
|
var CLAUDE_HOOK_EVENTS, DEFAULT_CLI_CMD, FOREIGN_AUTO_GATE_MARKER, SUBAGENT_MODEL_KEY, SMALL_FAST_MODEL_KEY, NativeHookSource;
|
|
21727
21921
|
var init_native_hook_source = __esm({
|
|
@@ -22293,9 +22487,9 @@ init_dist();
|
|
|
22293
22487
|
init_dist4();
|
|
22294
22488
|
import { Command } from "commander";
|
|
22295
22489
|
import { execSync as execSync7 } from "child_process";
|
|
22296
|
-
import
|
|
22490
|
+
import fs37 from "fs";
|
|
22297
22491
|
import { stat } from "fs/promises";
|
|
22298
|
-
import
|
|
22492
|
+
import path42 from "path";
|
|
22299
22493
|
import chalk3 from "chalk";
|
|
22300
22494
|
|
|
22301
22495
|
// packages/cli/src/commands/health-view.ts
|
|
@@ -22397,7 +22591,7 @@ function settingsHaveAgentTeams() {
|
|
|
22397
22591
|
try {
|
|
22398
22592
|
const home = process.env.HOME || "";
|
|
22399
22593
|
const settings = JSON.parse(
|
|
22400
|
-
|
|
22594
|
+
fs37.readFileSync(`${home}/.claude/settings.json`, "utf-8")
|
|
22401
22595
|
);
|
|
22402
22596
|
return settings?.env?.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS === "1";
|
|
22403
22597
|
} catch {
|
|
@@ -22408,7 +22602,7 @@ function pluginInstalled(pluginKey) {
|
|
|
22408
22602
|
try {
|
|
22409
22603
|
const home = process.env.HOME || "";
|
|
22410
22604
|
const plugins = JSON.parse(
|
|
22411
|
-
|
|
22605
|
+
fs37.readFileSync(
|
|
22412
22606
|
`${home}/.claude/plugins/installed_plugins.json`,
|
|
22413
22607
|
"utf-8"
|
|
22414
22608
|
)
|
|
@@ -22432,9 +22626,9 @@ function tryGetVersion(cmd) {
|
|
|
22432
22626
|
}
|
|
22433
22627
|
function candidateGlobalInstalls(roots) {
|
|
22434
22628
|
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:
|
|
22629
|
+
if (roots.npm) out.push({ manager: "npm", packageJsonPath: path42.join(roots.npm, "squadrant", "package.json") });
|
|
22630
|
+
if (roots.pnpm) out.push({ manager: "pnpm", packageJsonPath: path42.join(roots.pnpm, "squadrant", "package.json") });
|
|
22631
|
+
if (roots.yarn) out.push({ manager: "yarn", packageJsonPath: path42.join(roots.yarn, "node_modules", "squadrant", "package.json") });
|
|
22438
22632
|
return out;
|
|
22439
22633
|
}
|
|
22440
22634
|
function findInstalledSquadrants(candidates, readVersion) {
|
|
@@ -22454,7 +22648,7 @@ ${lines.join("\n")}
|
|
|
22454
22648
|
}
|
|
22455
22649
|
function readPackageVersion(packageJsonPath) {
|
|
22456
22650
|
try {
|
|
22457
|
-
const pkg2 = JSON.parse(
|
|
22651
|
+
const pkg2 = JSON.parse(fs37.readFileSync(packageJsonPath, "utf-8"));
|
|
22458
22652
|
return typeof pkg2.version === "string" ? pkg2.version : null;
|
|
22459
22653
|
} catch {
|
|
22460
22654
|
return null;
|
|
@@ -22537,7 +22731,7 @@ var doctorCommand = new Command("doctor").description("Check system health and p
|
|
|
22537
22731
|
));
|
|
22538
22732
|
checkOptional(
|
|
22539
22733
|
"Obsidian installed",
|
|
22540
|
-
commandExists("obsidian") ||
|
|
22734
|
+
commandExists("obsidian") || fs37.existsSync("/Applications/Obsidian.app"),
|
|
22541
22735
|
"viewer for the hub vault; the vault is plain Markdown",
|
|
22542
22736
|
"Install from: https://obsidian.md"
|
|
22543
22737
|
);
|
|
@@ -22634,7 +22828,7 @@ var doctorCommand = new Command("doctor").description("Check system health and p
|
|
|
22634
22828
|
const emitter = projectionRegistry.get(name);
|
|
22635
22829
|
const [userDest] = emitter.destinations("user");
|
|
22636
22830
|
if (!userDest) continue;
|
|
22637
|
-
const dir =
|
|
22831
|
+
const dir = path42.dirname(userDest.path);
|
|
22638
22832
|
let status;
|
|
22639
22833
|
try {
|
|
22640
22834
|
await stat(dir);
|
|
@@ -22655,7 +22849,7 @@ var doctorCommand = new Command("doctor").description("Check system health and p
|
|
|
22655
22849
|
results.push(
|
|
22656
22850
|
check(
|
|
22657
22851
|
"Squadrant config exists",
|
|
22658
|
-
|
|
22852
|
+
fs37.existsSync(
|
|
22659
22853
|
process.env.SQUADRANT_CONFIG || `${process.env.HOME}/.config/squadrant/config.json`
|
|
22660
22854
|
),
|
|
22661
22855
|
"Run: squadrant init"
|
|
@@ -22739,8 +22933,8 @@ init_dist();
|
|
|
22739
22933
|
init_dist4();
|
|
22740
22934
|
init_dist();
|
|
22741
22935
|
import { Command as Command2 } from "commander";
|
|
22742
|
-
import
|
|
22743
|
-
import
|
|
22936
|
+
import fs38 from "fs";
|
|
22937
|
+
import path43 from "path";
|
|
22744
22938
|
import os18 from "os";
|
|
22745
22939
|
import readline from "readline";
|
|
22746
22940
|
import chalk4 from "chalk";
|
|
@@ -22991,22 +23185,22 @@ function detectClaudeAuth(probe = {}) {
|
|
|
22991
23185
|
// packages/cli/src/commands/init.ts
|
|
22992
23186
|
init_dist3();
|
|
22993
23187
|
function findPackageRoot() {
|
|
22994
|
-
let dir =
|
|
23188
|
+
let dir = path43.dirname(new URL(import.meta.url).pathname);
|
|
22995
23189
|
while (dir !== "/") {
|
|
22996
|
-
if (
|
|
22997
|
-
dir =
|
|
23190
|
+
if (fs38.existsSync(path43.join(dir, "package.json"))) return dir;
|
|
23191
|
+
dir = path43.dirname(dir);
|
|
22998
23192
|
}
|
|
22999
23193
|
return process.cwd();
|
|
23000
23194
|
}
|
|
23001
23195
|
function copyDirRecursive(src, dest) {
|
|
23002
|
-
|
|
23003
|
-
for (const entry of
|
|
23004
|
-
const srcPath =
|
|
23005
|
-
const destPath =
|
|
23196
|
+
fs38.mkdirSync(dest, { recursive: true });
|
|
23197
|
+
for (const entry of fs38.readdirSync(src, { withFileTypes: true })) {
|
|
23198
|
+
const srcPath = path43.join(src, entry.name);
|
|
23199
|
+
const destPath = path43.join(dest, entry.name);
|
|
23006
23200
|
if (entry.isDirectory()) {
|
|
23007
23201
|
copyDirRecursive(srcPath, destPath);
|
|
23008
23202
|
} else {
|
|
23009
|
-
|
|
23203
|
+
fs38.copyFileSync(srcPath, destPath);
|
|
23010
23204
|
}
|
|
23011
23205
|
}
|
|
23012
23206
|
}
|
|
@@ -23048,7 +23242,7 @@ function warnIfNoAnthropic(preset, auth) {
|
|
|
23048
23242
|
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
23243
|
const hubPath = resolveHome(opts.hub);
|
|
23050
23244
|
const pkgRoot = findPackageRoot();
|
|
23051
|
-
const configDir =
|
|
23245
|
+
const configDir = path43.join(os18.homedir(), ".config", "squadrant");
|
|
23052
23246
|
const isTTY = process.stdin.isTTY === true;
|
|
23053
23247
|
console.log(chalk4.bold("\nSquadrant Init\n"));
|
|
23054
23248
|
let explicitPreset;
|
|
@@ -23086,8 +23280,8 @@ var initCommand = new Command2("init").description("Guided first-time setup: pro
|
|
|
23086
23280
|
}
|
|
23087
23281
|
const wsRegistry = new WorkspaceRegistry({ obsidian: createObsidianDriver });
|
|
23088
23282
|
try {
|
|
23089
|
-
if (
|
|
23090
|
-
const existing = JSON.parse(
|
|
23283
|
+
if (fs38.existsSync(DEFAULT_CONFIG_PATH)) {
|
|
23284
|
+
const existing = JSON.parse(fs38.readFileSync(DEFAULT_CONFIG_PATH, "utf-8"));
|
|
23091
23285
|
wsRegistry.get(existing.workspace ?? "obsidian");
|
|
23092
23286
|
}
|
|
23093
23287
|
} catch (err) {
|
|
@@ -23095,7 +23289,7 @@ var initCommand = new Command2("init").description("Guided first-time setup: pro
|
|
|
23095
23289
|
return;
|
|
23096
23290
|
}
|
|
23097
23291
|
stepHeader(1, 5, "Hub vault");
|
|
23098
|
-
const configExists =
|
|
23292
|
+
const configExists = fs38.existsSync(DEFAULT_CONFIG_PATH);
|
|
23099
23293
|
let config;
|
|
23100
23294
|
if (configExists) {
|
|
23101
23295
|
console.log(chalk4.yellow(" \u26A0 Config already exists, skipping creation"));
|
|
@@ -23133,37 +23327,37 @@ var initCommand = new Command2("init").description("Guided first-time setup: pro
|
|
|
23133
23327
|
saveConfig(config);
|
|
23134
23328
|
console.log(chalk4.green(` \u2714 Config updated at ${DEFAULT_CONFIG_PATH}`));
|
|
23135
23329
|
}
|
|
23136
|
-
const hubTemplate =
|
|
23137
|
-
if (
|
|
23330
|
+
const hubTemplate = path43.join(pkgRoot, "obsidian", "hub");
|
|
23331
|
+
if (fs38.existsSync(hubPath)) {
|
|
23138
23332
|
console.log(chalk4.yellow(` \u26A0 Hub vault already exists at ${hubPath}`));
|
|
23139
|
-
} else if (
|
|
23333
|
+
} else if (fs38.existsSync(hubTemplate)) {
|
|
23140
23334
|
copyDirRecursive(hubTemplate, hubPath);
|
|
23141
23335
|
console.log(chalk4.green(` \u2714 Hub vault scaffolded at ${hubPath}`));
|
|
23142
23336
|
} else {
|
|
23143
|
-
|
|
23337
|
+
fs38.mkdirSync(hubPath, { recursive: true });
|
|
23144
23338
|
console.log(chalk4.yellow(` \u26A0 Hub template not found; created empty directory at ${hubPath}`));
|
|
23145
23339
|
}
|
|
23146
|
-
const hubDashboardSrc =
|
|
23147
|
-
const hubDashboardDest =
|
|
23148
|
-
if (
|
|
23149
|
-
|
|
23340
|
+
const hubDashboardSrc = path43.join(pkgRoot, "obsidian", "hub", "dashboard.md");
|
|
23341
|
+
const hubDashboardDest = path43.join(hubPath, "dashboard.md");
|
|
23342
|
+
if (fs38.existsSync(hubDashboardSrc)) {
|
|
23343
|
+
fs38.copyFileSync(hubDashboardSrc, hubDashboardDest);
|
|
23150
23344
|
console.log(chalk4.green(` \u2714 Dashboard refreshed`));
|
|
23151
23345
|
}
|
|
23152
|
-
|
|
23346
|
+
fs38.mkdirSync(path43.join(hubPath, "projects"), { recursive: true });
|
|
23153
23347
|
ensureRuntimeSynced({ sourceRoot: pkgRoot, runtimeRoot: configDir });
|
|
23154
23348
|
console.log(chalk4.green(` \u2714 Runtime assets synced to ${configDir}`));
|
|
23155
23349
|
stepHeader(2, 5, "Agent + projection setup");
|
|
23156
|
-
const settingsPath =
|
|
23350
|
+
const settingsPath = path43.join(os18.homedir(), ".claude", "settings.json");
|
|
23157
23351
|
try {
|
|
23158
23352
|
let settings = {};
|
|
23159
|
-
if (
|
|
23160
|
-
settings = JSON.parse(
|
|
23353
|
+
if (fs38.existsSync(settingsPath)) {
|
|
23354
|
+
settings = JSON.parse(fs38.readFileSync(settingsPath, "utf-8"));
|
|
23161
23355
|
}
|
|
23162
23356
|
const env = settings.env || {};
|
|
23163
23357
|
if (env.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS !== "1") {
|
|
23164
23358
|
settings.env = { ...env, CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS: "1" };
|
|
23165
|
-
|
|
23166
|
-
|
|
23359
|
+
fs38.mkdirSync(path43.dirname(settingsPath), { recursive: true });
|
|
23360
|
+
fs38.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
|
|
23167
23361
|
console.log(chalk4.green(" \u2714 Agent Teams enabled in ~/.claude/settings.json"));
|
|
23168
23362
|
} else {
|
|
23169
23363
|
console.log(chalk4.green(" \u2714 Agent Teams already enabled"));
|
|
@@ -23216,7 +23410,7 @@ var initCommand = new Command2("init").description("Guided first-time setup: pro
|
|
|
23216
23410
|
chalk4.cyan(" Absolute path to your first project (Enter to skip): ")
|
|
23217
23411
|
);
|
|
23218
23412
|
if (projectPath) {
|
|
23219
|
-
const projectName =
|
|
23413
|
+
const projectName = path43.basename(projectPath);
|
|
23220
23414
|
console.log(chalk4.bold(`
|
|
23221
23415
|
Run this to register it:`));
|
|
23222
23416
|
console.log(chalk4.cyan(` squadrant projects add ${projectName} ${projectPath}
|
|
@@ -23244,8 +23438,8 @@ var initCommand = new Command2("init").description("Guided first-time setup: pro
|
|
|
23244
23438
|
init_dist();
|
|
23245
23439
|
init_dist2();
|
|
23246
23440
|
import { Command as Command3 } from "commander";
|
|
23247
|
-
import
|
|
23248
|
-
import
|
|
23441
|
+
import fs39 from "fs";
|
|
23442
|
+
import path44 from "path";
|
|
23249
23443
|
import chalk5 from "chalk";
|
|
23250
23444
|
function restartAfterProjectsAdd(opts) {
|
|
23251
23445
|
const doRestart = opts.doRestart ?? restartDaemonIfRunning;
|
|
@@ -23257,22 +23451,22 @@ function restartAfterProjectsAdd(opts) {
|
|
|
23257
23451
|
}
|
|
23258
23452
|
}
|
|
23259
23453
|
function findPackageRoot2() {
|
|
23260
|
-
let dir =
|
|
23454
|
+
let dir = path44.dirname(new URL(import.meta.url).pathname);
|
|
23261
23455
|
while (dir !== "/") {
|
|
23262
|
-
if (
|
|
23263
|
-
dir =
|
|
23456
|
+
if (fs39.existsSync(path44.join(dir, "package.json"))) return dir;
|
|
23457
|
+
dir = path44.dirname(dir);
|
|
23264
23458
|
}
|
|
23265
23459
|
return process.cwd();
|
|
23266
23460
|
}
|
|
23267
23461
|
function copyDirRecursive2(src, dest) {
|
|
23268
|
-
|
|
23269
|
-
for (const entry of
|
|
23270
|
-
const srcPath =
|
|
23271
|
-
const destPath =
|
|
23462
|
+
fs39.mkdirSync(dest, { recursive: true });
|
|
23463
|
+
for (const entry of fs39.readdirSync(src, { withFileTypes: true })) {
|
|
23464
|
+
const srcPath = path44.join(src, entry.name);
|
|
23465
|
+
const destPath = path44.join(dest, entry.name);
|
|
23272
23466
|
if (entry.isDirectory()) {
|
|
23273
23467
|
copyDirRecursive2(srcPath, destPath);
|
|
23274
23468
|
} else {
|
|
23275
|
-
|
|
23469
|
+
fs39.copyFileSync(srcPath, destPath);
|
|
23276
23470
|
}
|
|
23277
23471
|
}
|
|
23278
23472
|
}
|
|
@@ -23308,7 +23502,7 @@ var addCmd = new Command3("add").description("Register a project").argument("<na
|
|
|
23308
23502
|
process.exit(1);
|
|
23309
23503
|
}
|
|
23310
23504
|
const resolvedPath = resolveHome(projectPath);
|
|
23311
|
-
if (!
|
|
23505
|
+
if (!fs39.existsSync(path44.join(resolvedPath, ".git"))) {
|
|
23312
23506
|
console.log(chalk5.yellow(`
|
|
23313
23507
|
\u26A0 No .git found at ${resolvedPath}. Make sure this is the project root, not a parent directory.
|
|
23314
23508
|
`));
|
|
@@ -23361,7 +23555,7 @@ var addCmd = new Command3("add").description("Register a project").argument("<na
|
|
|
23361
23555
|
\u26A0 Group '${group}' already has '${primary[0]}' as primary. Overriding.`));
|
|
23362
23556
|
}
|
|
23363
23557
|
}
|
|
23364
|
-
const spokeVault = opts.spoke ? resolveHome(opts.spoke) :
|
|
23558
|
+
const spokeVault = opts.spoke ? resolveHome(opts.spoke) : path44.join(config.hubVault, "spokes", name);
|
|
23365
23559
|
const project = {
|
|
23366
23560
|
path: resolvedPath,
|
|
23367
23561
|
captainName,
|
|
@@ -23376,20 +23570,20 @@ var addCmd = new Command3("add").description("Register a project").argument("<na
|
|
|
23376
23570
|
\u2714 Project '${name}' registered`));
|
|
23377
23571
|
restartAfterProjectsAdd({ noRestart: opts.restart === false });
|
|
23378
23572
|
const pkgRoot = findPackageRoot2();
|
|
23379
|
-
const spokeTemplate =
|
|
23380
|
-
if (
|
|
23573
|
+
const spokeTemplate = path44.join(pkgRoot, "obsidian", "spoke");
|
|
23574
|
+
if (fs39.existsSync(spokeVault)) {
|
|
23381
23575
|
console.log(chalk5.yellow(` \u26A0 Spoke vault already exists at ${spokeVault}, skipping scaffold`));
|
|
23382
|
-
} else if (
|
|
23576
|
+
} else if (fs39.existsSync(spokeTemplate)) {
|
|
23383
23577
|
copyDirRecursive2(spokeTemplate, spokeVault);
|
|
23384
|
-
const statusPath =
|
|
23385
|
-
if (
|
|
23386
|
-
const content =
|
|
23578
|
+
const statusPath = path44.join(spokeVault, "status.md");
|
|
23579
|
+
if (fs39.existsSync(statusPath)) {
|
|
23580
|
+
const content = fs39.readFileSync(statusPath, "utf-8");
|
|
23387
23581
|
const updated = content.replace(/^project: unnamed/m, `project: ${name}`);
|
|
23388
|
-
|
|
23582
|
+
fs39.writeFileSync(statusPath, updated);
|
|
23389
23583
|
}
|
|
23390
23584
|
console.log(chalk5.green(` \u2714 Spoke vault scaffolded at ${spokeVault}`));
|
|
23391
23585
|
} else {
|
|
23392
|
-
|
|
23586
|
+
fs39.mkdirSync(spokeVault, { recursive: true });
|
|
23393
23587
|
console.log(chalk5.yellow(` \u26A0 Spoke template not found; created empty dir at ${spokeVault}`));
|
|
23394
23588
|
}
|
|
23395
23589
|
console.log("");
|
|
@@ -23458,10 +23652,10 @@ init_dist3();
|
|
|
23458
23652
|
init_dist();
|
|
23459
23653
|
import { Command as Command5 } from "commander";
|
|
23460
23654
|
import { execSync as execSync9 } from "child_process";
|
|
23461
|
-
import
|
|
23655
|
+
import path45 from "path";
|
|
23462
23656
|
import os19 from "os";
|
|
23463
23657
|
import chalk7 from "chalk";
|
|
23464
|
-
var TEMPLATES_DIR2 =
|
|
23658
|
+
var TEMPLATES_DIR2 = path45.join(os19.homedir(), ".config", "squadrant", "templates");
|
|
23465
23659
|
var TASK_PROMPTS = {
|
|
23466
23660
|
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
23661
|
"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 +23688,7 @@ async function runCommandSpawn(input) {
|
|
|
23494
23688
|
if (!agent) {
|
|
23495
23689
|
throw new Error(`Unknown agent '${agentName}'. Known: claude, codex, gemini, opencode.`);
|
|
23496
23690
|
}
|
|
23497
|
-
const promptFile =
|
|
23691
|
+
const promptFile = path45.join(TEMPLATES_DIR2, `command.${agent.templateSuffix}.md`);
|
|
23498
23692
|
const cliCommand = agent.buildCommand({
|
|
23499
23693
|
prompt,
|
|
23500
23694
|
workdir: process.cwd(),
|
|
@@ -23535,7 +23729,7 @@ init_dist3();
|
|
|
23535
23729
|
import { Command as Command9 } from "commander";
|
|
23536
23730
|
import { createConnection as createConnection4 } from "net";
|
|
23537
23731
|
import { randomUUID as randomUUID5 } from "crypto";
|
|
23538
|
-
import { execFileSync as execFileSync11 } from "child_process";
|
|
23732
|
+
import { execFileSync as execFileSync11, spawnSync } from "child_process";
|
|
23539
23733
|
import { homedir as homedir15 } from "os";
|
|
23540
23734
|
import { join as join27 } from "path";
|
|
23541
23735
|
import { mkdirSync as mkdirSync10, writeFileSync as writeFileSync13 } from "fs";
|
|
@@ -24017,6 +24211,31 @@ function defaultWriteResult(id, payload) {
|
|
|
24017
24211
|
writeFileSync13(file, payload);
|
|
24018
24212
|
return file;
|
|
24019
24213
|
}
|
|
24214
|
+
var CITE_GIT_TIMEOUT_MS = 2e3;
|
|
24215
|
+
var citeGit = (args) => {
|
|
24216
|
+
const r = spawnSync("git", args, { encoding: "utf8", timeout: CITE_GIT_TIMEOUT_MS, stdio: ["ignore", "pipe", "ignore"] });
|
|
24217
|
+
if (r.error) throw r.error;
|
|
24218
|
+
return r.status === 0 ? r.stdout : "";
|
|
24219
|
+
};
|
|
24220
|
+
function logSignalCitations(state, o) {
|
|
24221
|
+
const env = o.env ?? process.env;
|
|
24222
|
+
const project = o.project ?? env.SQUADRANT_CREW_PROJECT;
|
|
24223
|
+
if (state !== "done" && state !== "review" || !project) return [];
|
|
24224
|
+
const texts = o.message ? [{ text: o.message, ref: `crew-${state}:${o.taskId ?? env.SQUADRANT_CREW_TASK_ID}` }] : [];
|
|
24225
|
+
try {
|
|
24226
|
+
texts.push(...readBranchOnlyMessages(o.cwd ?? process.cwd(), o.git ?? citeGit).map((c) => ({ text: c.text, ref: `git:${c.sha}`, at: c.at })));
|
|
24227
|
+
} catch (e) {
|
|
24228
|
+
process.stderr.write(`squadrant: rule citation scan of commits skipped: ${e.message}
|
|
24229
|
+
`);
|
|
24230
|
+
}
|
|
24231
|
+
try {
|
|
24232
|
+
return scanCitations(texts, { project, sink: o.audit });
|
|
24233
|
+
} catch (e) {
|
|
24234
|
+
process.stderr.write(`squadrant: rule citation scan skipped: ${e.message}
|
|
24235
|
+
`);
|
|
24236
|
+
return [];
|
|
24237
|
+
}
|
|
24238
|
+
}
|
|
24020
24239
|
async function runCrewSignal(signal, o, deps) {
|
|
24021
24240
|
const taskId = o.taskId ?? process.env.SQUADRANT_CREW_TASK_ID;
|
|
24022
24241
|
const project = o.project ?? process.env.SQUADRANT_CREW_PROJECT;
|
|
@@ -24205,13 +24424,7 @@ function addControlPlaneCrewCommands(crew) {
|
|
|
24205
24424
|
...opts.project !== void 0 ? { project: opts.project } : {},
|
|
24206
24425
|
writeResult: defaultWriteResult
|
|
24207
24426
|
}, { 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
|
-
}
|
|
24427
|
+
logSignalCitations(state, opts);
|
|
24215
24428
|
process.exit(0);
|
|
24216
24429
|
} catch (e) {
|
|
24217
24430
|
process.stderr.write(`${e.message}
|
|
@@ -24300,7 +24513,7 @@ import { connect as netConnect2 } from "net";
|
|
|
24300
24513
|
init_dist3();
|
|
24301
24514
|
init_dist2();
|
|
24302
24515
|
import { createServer as createServer4, connect as netConnect } from "net";
|
|
24303
|
-
import
|
|
24516
|
+
import fs40 from "fs";
|
|
24304
24517
|
import { join as join28 } from "path";
|
|
24305
24518
|
import { randomUUID as randomUUID6 } from "crypto";
|
|
24306
24519
|
import chalk10 from "chalk";
|
|
@@ -24308,15 +24521,15 @@ var shared;
|
|
|
24308
24521
|
var registryEntryPath = () => join28(CLAUDE_SESSIONS_DIR, `${process.pid}.json`);
|
|
24309
24522
|
function unregisterSenderIdentity() {
|
|
24310
24523
|
try {
|
|
24311
|
-
|
|
24524
|
+
fs40.unlinkSync(registryEntryPath());
|
|
24312
24525
|
} catch {
|
|
24313
24526
|
}
|
|
24314
24527
|
}
|
|
24315
24528
|
function registerSenderIdentity(socketPath2) {
|
|
24316
24529
|
try {
|
|
24317
24530
|
unregisterSenderIdentity();
|
|
24318
|
-
|
|
24319
|
-
|
|
24531
|
+
fs40.mkdirSync(CLAUDE_SESSIONS_DIR, { recursive: true });
|
|
24532
|
+
fs40.writeFileSync(
|
|
24320
24533
|
registryEntryPath(),
|
|
24321
24534
|
JSON.stringify({
|
|
24322
24535
|
pid: process.pid,
|
|
@@ -24342,7 +24555,7 @@ async function sharedReceiptListener() {
|
|
|
24342
24555
|
// must never be the reason we refuse to start.
|
|
24343
24556
|
unlinkStale: (p) => {
|
|
24344
24557
|
try {
|
|
24345
|
-
|
|
24558
|
+
fs40.unlinkSync(p);
|
|
24346
24559
|
} catch {
|
|
24347
24560
|
}
|
|
24348
24561
|
},
|
|
@@ -24367,7 +24580,7 @@ async function buildCaptainChannel() {
|
|
|
24367
24580
|
// in /tmp/x registers cwd "/private/tmp/x" on macOS, so cwd matching silently
|
|
24368
24581
|
// missed and every captain ping reported accepted-unconfirmed.
|
|
24369
24582
|
statusFor: (taskId) => readClaudeStatusBySocketPath(captainSocketPath(taskId)),
|
|
24370
|
-
wire: (p, e) => writeLine(p, e, { connect: (
|
|
24583
|
+
wire: (p, e) => writeLine(p, e, { connect: (path60) => netConnect(path60) }),
|
|
24371
24584
|
receipts,
|
|
24372
24585
|
newMsgId: () => randomUUID6(),
|
|
24373
24586
|
sleep: (ms) => new Promise((r) => setTimeout(r, ms)),
|
|
@@ -24396,7 +24609,7 @@ async function sendClaudeFirstTurnViaPeer(runtime, o, getTaskRecord) {
|
|
|
24396
24609
|
socketPathFor: () => o.messagingSocketPath,
|
|
24397
24610
|
sessionIdFor: () => readClaudeStatusBySocketPath(o.messagingSocketPath)?.sessionId,
|
|
24398
24611
|
statusFor: () => readClaudeStatusBySocketPath(o.messagingSocketPath),
|
|
24399
|
-
wire: (p, e) => writeLine(p, e, { connect: (
|
|
24612
|
+
wire: (p, e) => writeLine(p, e, { connect: (path60) => netConnect2(path60) }),
|
|
24400
24613
|
receipts,
|
|
24401
24614
|
newMsgId: () => randomUUID7(),
|
|
24402
24615
|
sleep: (ms) => new Promise((r) => setTimeout(r, ms)),
|
|
@@ -24540,7 +24753,7 @@ async function runCrewSend2(project, name, message, opts) {
|
|
|
24540
24753
|
socketPathFor: (taskId) => tasks.find((t) => t.id === taskId)?.messagingSocketPath,
|
|
24541
24754
|
sessionIdFor: (taskId) => tasks.find((t) => t.id === taskId)?.sessionId,
|
|
24542
24755
|
statusFor: (taskId) => readClaudeStatus(tasks.find((t) => t.id === taskId)),
|
|
24543
|
-
wire: (p, e) => writeLine(p, e, { connect: (
|
|
24756
|
+
wire: (p, e) => writeLine(p, e, { connect: (path60) => netConnect3(path60) }),
|
|
24544
24757
|
receipts,
|
|
24545
24758
|
newMsgId: () => randomUUID8(),
|
|
24546
24759
|
sleep: (ms) => new Promise((r) => setTimeout(r, ms)),
|
|
@@ -24934,11 +25147,11 @@ init_dist4();
|
|
|
24934
25147
|
init_dist();
|
|
24935
25148
|
init_dist2();
|
|
24936
25149
|
import { Command as Command12 } from "commander";
|
|
24937
|
-
import
|
|
24938
|
-
import
|
|
25150
|
+
import fs41 from "fs";
|
|
25151
|
+
import path46 from "path";
|
|
24939
25152
|
import os20 from "os";
|
|
24940
25153
|
import chalk13 from "chalk";
|
|
24941
|
-
var TEMPLATES_DIR3 =
|
|
25154
|
+
var TEMPLATES_DIR3 = path46.join(os20.homedir(), ".config", "squadrant", "templates");
|
|
24942
25155
|
async function runSideSpawn2(input) {
|
|
24943
25156
|
const config = loadConfig();
|
|
24944
25157
|
const proj = config.projects[input.project];
|
|
@@ -24963,7 +25176,7 @@ async function runSideSpawn2(input) {
|
|
|
24963
25176
|
}
|
|
24964
25177
|
const sideModel = sideRole?.model;
|
|
24965
25178
|
const sideThinking = sideRole?.thinking;
|
|
24966
|
-
const promptFile =
|
|
25179
|
+
const promptFile = path46.join(
|
|
24967
25180
|
TEMPLATES_DIR3,
|
|
24968
25181
|
`side.${input.role}.${agent.templateSuffix}.md`
|
|
24969
25182
|
);
|
|
@@ -24971,7 +25184,7 @@ async function runSideSpawn2(input) {
|
|
|
24971
25184
|
prompt: input.topic,
|
|
24972
25185
|
workdir: spawnCwd,
|
|
24973
25186
|
role: "side",
|
|
24974
|
-
promptFile:
|
|
25187
|
+
promptFile: fs41.existsSync(promptFile) ? promptFile : void 0,
|
|
24975
25188
|
interactive: true,
|
|
24976
25189
|
permissionMode: config.defaults.permissions?.crew ?? "auto",
|
|
24977
25190
|
...sideModel ? { model: sideModel } : {},
|
|
@@ -25234,8 +25447,8 @@ function renderDashboard(rows, opts) {
|
|
|
25234
25447
|
|
|
25235
25448
|
// packages/web/dist/sync-hub.js
|
|
25236
25449
|
init_dist();
|
|
25237
|
-
import
|
|
25238
|
-
import
|
|
25450
|
+
import fs42 from "fs";
|
|
25451
|
+
import path47 from "path";
|
|
25239
25452
|
function buildMirrorMarkdown(s) {
|
|
25240
25453
|
const fenced = "```";
|
|
25241
25454
|
return [
|
|
@@ -25261,15 +25474,15 @@ function buildMirrorMarkdown(s) {
|
|
|
25261
25474
|
function syncHub(deps) {
|
|
25262
25475
|
if (!deps.config.hubVault)
|
|
25263
25476
|
return [];
|
|
25264
|
-
const writeFile6 = deps.writeFile ?? ((p, c) =>
|
|
25265
|
-
const mkdir6 = deps.mkdir ?? ((p) =>
|
|
25266
|
-
const projectsDir =
|
|
25477
|
+
const writeFile6 = deps.writeFile ?? ((p, c) => fs42.writeFileSync(p, c));
|
|
25478
|
+
const mkdir6 = deps.mkdir ?? ((p) => fs42.mkdirSync(p, { recursive: true }));
|
|
25479
|
+
const projectsDir = path47.join(resolveHome(deps.config.hubVault), "projects");
|
|
25267
25480
|
mkdir6(projectsDir);
|
|
25268
25481
|
const out = [];
|
|
25269
25482
|
for (const s of deps.statuses) {
|
|
25270
25483
|
if (s.state === "unknown")
|
|
25271
25484
|
continue;
|
|
25272
|
-
const hubPath =
|
|
25485
|
+
const hubPath = path47.join(projectsDir, `${s.project}.md`);
|
|
25273
25486
|
try {
|
|
25274
25487
|
writeFile6(hubPath, buildMirrorMarkdown(s));
|
|
25275
25488
|
out.push({ project: s.project, hubPath });
|
|
@@ -26275,18 +26488,18 @@ function renderHtml(snap, opts = {}) {
|
|
|
26275
26488
|
import { closeSync as closeSync3, openSync as openSync3, readSync as readSync2, statSync as statSync4 } from "fs";
|
|
26276
26489
|
var LOG_TAIL_BYTES = 256 * 1024;
|
|
26277
26490
|
var LOG_RING_SIZE = 1e3;
|
|
26278
|
-
function defaultSize(
|
|
26491
|
+
function defaultSize(path60) {
|
|
26279
26492
|
try {
|
|
26280
|
-
return statSync4(
|
|
26493
|
+
return statSync4(path60).size;
|
|
26281
26494
|
} catch {
|
|
26282
26495
|
return 0;
|
|
26283
26496
|
}
|
|
26284
26497
|
}
|
|
26285
|
-
function defaultRead(
|
|
26498
|
+
function defaultRead(path60, start, len) {
|
|
26286
26499
|
if (len <= 0)
|
|
26287
26500
|
return "";
|
|
26288
26501
|
try {
|
|
26289
|
-
const fd = openSync3(
|
|
26502
|
+
const fd = openSync3(path60, "r");
|
|
26290
26503
|
try {
|
|
26291
26504
|
const buf = Buffer.alloc(len);
|
|
26292
26505
|
const n = readSync2(fd, buf, 0, len, start);
|
|
@@ -26306,8 +26519,8 @@ var LogTailer = class {
|
|
|
26306
26519
|
ring = [];
|
|
26307
26520
|
size;
|
|
26308
26521
|
read;
|
|
26309
|
-
constructor(
|
|
26310
|
-
this.path =
|
|
26522
|
+
constructor(path60, ringSize = LOG_RING_SIZE, deps = {}) {
|
|
26523
|
+
this.path = path60;
|
|
26311
26524
|
this.ringSize = ringSize;
|
|
26312
26525
|
this.size = deps.size ?? defaultSize;
|
|
26313
26526
|
this.read = deps.read ?? defaultRead;
|
|
@@ -26583,8 +26796,8 @@ init_dist4();
|
|
|
26583
26796
|
init_dist2();
|
|
26584
26797
|
import { Command as Command14 } from "commander";
|
|
26585
26798
|
import { execSync as execSync11, execFileSync as execFileSync13 } from "child_process";
|
|
26586
|
-
import
|
|
26587
|
-
import
|
|
26799
|
+
import fs43 from "fs";
|
|
26800
|
+
import path48 from "path";
|
|
26588
26801
|
import os21 from "os";
|
|
26589
26802
|
import chalk16 from "chalk";
|
|
26590
26803
|
|
|
@@ -26677,8 +26890,8 @@ function resolveLaunchBackend(o) {
|
|
|
26677
26890
|
// packages/cli/src/commands/launch.ts
|
|
26678
26891
|
init_dist2();
|
|
26679
26892
|
var CMUX_APP = "/Applications/cmux.app";
|
|
26680
|
-
var TEMPLATES_DIR4 =
|
|
26681
|
-
var SESSIONS_PATH2 =
|
|
26893
|
+
var TEMPLATES_DIR4 = path48.join(os21.homedir(), ".config", "squadrant", "templates");
|
|
26894
|
+
var SESSIONS_PATH2 = path48.join(os21.homedir(), ".config", "squadrant", "sessions.json");
|
|
26682
26895
|
function shouldWireCaptainChannel(agentName, config) {
|
|
26683
26896
|
return agentName === "claude" && resolveCaptainChannelMode(config.defaults) !== "off";
|
|
26684
26897
|
}
|
|
@@ -26775,7 +26988,7 @@ var launchCommand = new Command14("launch").description(
|
|
|
26775
26988
|
initialPrompt = "Run your startup checklist: use the squadrant:command-ops skill, complete your daily briefing, then report ready.";
|
|
26776
26989
|
}
|
|
26777
26990
|
const runtime = projectName ? runtimes.forProject(projectName, config) : runtimes.global(config);
|
|
26778
|
-
const stateRoot =
|
|
26991
|
+
const stateRoot = path48.join(os21.homedir(), ".config", "squadrant", "state");
|
|
26779
26992
|
const isOpencodeCaptain = role === "captain" && agentName === "opencode" && !!projectName;
|
|
26780
26993
|
if (isOpencodeCaptain && !isOpencodeCaptainDir(cwd)) {
|
|
26781
26994
|
console.error(chalk16.red(`
|
|
@@ -26928,12 +27141,12 @@ var launchCommand = new Command14("launch").description(
|
|
|
26928
27141
|
}
|
|
26929
27142
|
if (opts.all) {
|
|
26930
27143
|
const hubPath = resolveHome(config.hubVault);
|
|
26931
|
-
|
|
27144
|
+
fs43.mkdirSync(hubPath, { recursive: true });
|
|
26932
27145
|
console.log(chalk16.bold("\nLaunching all captain workspaces\n"));
|
|
26933
27146
|
for (const [name, proj] of Object.entries(config.projects)) {
|
|
26934
27147
|
const projPath = resolveHome(proj.path);
|
|
26935
27148
|
const spokePath = resolveHome(proj.spokeVault);
|
|
26936
|
-
if (!
|
|
27149
|
+
if (!fs43.existsSync(spokePath)) {
|
|
26937
27150
|
const spokeDriver = new WorkspaceRegistry({ obsidian: createObsidianDriver }).forProject(name, config);
|
|
26938
27151
|
await ensureSpokeLayout(spokeDriver);
|
|
26939
27152
|
console.log(chalk16.cyan(` \u2714 Created spoke vault at ${spokePath}`));
|
|
@@ -26971,7 +27184,7 @@ Launching ${selected.length} captain workspace(s) in parallel
|
|
|
26971
27184
|
const proj = config.projects[name];
|
|
26972
27185
|
const projPath = resolveHome(proj.path);
|
|
26973
27186
|
const spokePath = resolveHome(proj.spokeVault);
|
|
26974
|
-
if (!
|
|
27187
|
+
if (!fs43.existsSync(spokePath)) {
|
|
26975
27188
|
const spokeDriver = new WorkspaceRegistry({ obsidian: createObsidianDriver }).forProject(name, config);
|
|
26976
27189
|
await ensureSpokeLayout(spokeDriver);
|
|
26977
27190
|
console.log(chalk16.cyan(` \u2714 Created spoke vault at ${spokePath}`));
|
|
@@ -26995,7 +27208,7 @@ Launching ${selected.length} captain workspace(s) in parallel
|
|
|
26995
27208
|
const proj = config.projects[project];
|
|
26996
27209
|
const projPath = resolveHome(proj.path);
|
|
26997
27210
|
const spokePath = resolveHome(proj.spokeVault);
|
|
26998
|
-
if (!
|
|
27211
|
+
if (!fs43.existsSync(spokePath)) {
|
|
26999
27212
|
const spokeDriver = new WorkspaceRegistry({ obsidian: createObsidianDriver }).forProject(project, config);
|
|
27000
27213
|
await ensureSpokeLayout(spokeDriver);
|
|
27001
27214
|
console.log(chalk16.cyan(` \u2714 Created spoke vault at ${spokePath}`));
|
|
@@ -27131,24 +27344,24 @@ Shutting down captain workspace for '${project}'...
|
|
|
27131
27344
|
// packages/cli/src/commands/feedback.ts
|
|
27132
27345
|
init_dist();
|
|
27133
27346
|
import { Command as Command16 } from "commander";
|
|
27134
|
-
import
|
|
27347
|
+
import fs44 from "fs";
|
|
27135
27348
|
import os22 from "os";
|
|
27136
|
-
import
|
|
27349
|
+
import path49 from "path";
|
|
27137
27350
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
27138
27351
|
import { execSync as execSync12 } from "child_process";
|
|
27139
27352
|
import chalk18 from "chalk";
|
|
27140
27353
|
var REPO_URL = "https://github.com/tu11aa/squadrant";
|
|
27141
27354
|
function readPkgVersion() {
|
|
27142
27355
|
try {
|
|
27143
|
-
const pkgPath =
|
|
27144
|
-
return JSON.parse(
|
|
27356
|
+
const pkgPath = path49.join(path49.dirname(fileURLToPath3(import.meta.url)), "..", "package.json");
|
|
27357
|
+
return JSON.parse(fs44.readFileSync(pkgPath, "utf-8")).version ?? "unknown";
|
|
27145
27358
|
} catch {
|
|
27146
27359
|
return "unknown";
|
|
27147
27360
|
}
|
|
27148
27361
|
}
|
|
27149
27362
|
function readMetrics(metricsPath) {
|
|
27150
27363
|
try {
|
|
27151
|
-
return JSON.parse(
|
|
27364
|
+
return JSON.parse(fs44.readFileSync(metricsPath, "utf-8"));
|
|
27152
27365
|
} catch {
|
|
27153
27366
|
return {};
|
|
27154
27367
|
}
|
|
@@ -27186,7 +27399,7 @@ function buildIssueUrl(metrics, squadrantVersion) {
|
|
|
27186
27399
|
}
|
|
27187
27400
|
var feedbackCommand = new Command16("feedback").description("Open a pre-filled GitHub issue for feedback or bug reports").action(() => {
|
|
27188
27401
|
const config = loadConfig();
|
|
27189
|
-
const metricsPath = config.metrics?.path ||
|
|
27402
|
+
const metricsPath = config.metrics?.path || path49.join(os22.homedir(), ".config", "squadrant", "metrics.json");
|
|
27190
27403
|
const metrics = readMetrics(metricsPath);
|
|
27191
27404
|
const version = readStamp(config) ?? readPkgVersion();
|
|
27192
27405
|
const issueUrl = buildIssueUrl(metrics, version);
|
|
@@ -27486,9 +27699,9 @@ workspaceCommand.command("read").description("Print the contents of a scope-rela
|
|
|
27486
27699
|
const config = loadConfig();
|
|
27487
27700
|
const registry = buildRegistry2();
|
|
27488
27701
|
try {
|
|
27489
|
-
const { projectTarget, path:
|
|
27702
|
+
const { projectTarget, path: path60 } = resolveTargetAndPath(arg1, arg2, !!opts.hub);
|
|
27490
27703
|
const driver = resolveDriver(registry, config, projectTarget, !!opts.hub);
|
|
27491
|
-
const content = await driver.read(
|
|
27704
|
+
const content = await driver.read(path60);
|
|
27492
27705
|
process.stdout.write(content);
|
|
27493
27706
|
} catch (err) {
|
|
27494
27707
|
console.error(chalk21.red(err.message));
|
|
@@ -27500,26 +27713,26 @@ workspaceCommand.command("write").description("Write content to a scope-relative
|
|
|
27500
27713
|
const registry = buildRegistry2();
|
|
27501
27714
|
try {
|
|
27502
27715
|
let projectTarget;
|
|
27503
|
-
let
|
|
27716
|
+
let path60;
|
|
27504
27717
|
let rawContent;
|
|
27505
27718
|
if (opts.hub) {
|
|
27506
27719
|
if (arg3 !== void 0) {
|
|
27507
27720
|
throw new Error("With --hub, pass only the path and content");
|
|
27508
27721
|
}
|
|
27509
27722
|
projectTarget = void 0;
|
|
27510
|
-
|
|
27723
|
+
path60 = arg1;
|
|
27511
27724
|
rawContent = arg2;
|
|
27512
27725
|
} else {
|
|
27513
27726
|
if (arg3 === void 0) {
|
|
27514
27727
|
throw new Error("Missing content \u2014 usage: <project> <path> <content>");
|
|
27515
27728
|
}
|
|
27516
27729
|
projectTarget = arg1;
|
|
27517
|
-
|
|
27730
|
+
path60 = arg2;
|
|
27518
27731
|
rawContent = arg3;
|
|
27519
27732
|
}
|
|
27520
27733
|
const driver = resolveDriver(registry, config, projectTarget, !!opts.hub);
|
|
27521
27734
|
const payload = rawContent === "-" ? await readStdin() : rawContent;
|
|
27522
|
-
await driver.write(
|
|
27735
|
+
await driver.write(path60, payload);
|
|
27523
27736
|
} catch (err) {
|
|
27524
27737
|
console.error(chalk21.red(err.message));
|
|
27525
27738
|
process.exit(1);
|
|
@@ -27529,9 +27742,9 @@ workspaceCommand.command("list").description("List entries in a scope-relative d
|
|
|
27529
27742
|
const config = loadConfig();
|
|
27530
27743
|
const registry = buildRegistry2();
|
|
27531
27744
|
try {
|
|
27532
|
-
const { projectTarget, path:
|
|
27745
|
+
const { projectTarget, path: path60 } = resolveTargetAndPath(arg1, arg2, !!opts.hub);
|
|
27533
27746
|
const driver = resolveDriver(registry, config, projectTarget, !!opts.hub);
|
|
27534
|
-
const entries = await driver.list(
|
|
27747
|
+
const entries = await driver.list(path60);
|
|
27535
27748
|
for (const entry of entries) console.log(entry);
|
|
27536
27749
|
} catch (err) {
|
|
27537
27750
|
console.error(chalk21.red(err.message));
|
|
@@ -27542,9 +27755,9 @@ workspaceCommand.command("exists").description("Exit 0 if path exists, 1 if not"
|
|
|
27542
27755
|
const config = loadConfig();
|
|
27543
27756
|
const registry = buildRegistry2();
|
|
27544
27757
|
try {
|
|
27545
|
-
const { projectTarget, path:
|
|
27758
|
+
const { projectTarget, path: path60 } = resolveTargetAndPath(arg1, arg2, !!opts.hub);
|
|
27546
27759
|
const driver = resolveDriver(registry, config, projectTarget, !!opts.hub);
|
|
27547
|
-
const ok2 = await driver.exists(
|
|
27760
|
+
const ok2 = await driver.exists(path60);
|
|
27548
27761
|
process.exit(ok2 ? 0 : 1);
|
|
27549
27762
|
} catch (err) {
|
|
27550
27763
|
console.error(chalk21.red(err.message));
|
|
@@ -27555,9 +27768,9 @@ workspaceCommand.command("mkdir").description("Recursively create a scope-relati
|
|
|
27555
27768
|
const config = loadConfig();
|
|
27556
27769
|
const registry = buildRegistry2();
|
|
27557
27770
|
try {
|
|
27558
|
-
const { projectTarget, path:
|
|
27771
|
+
const { projectTarget, path: path60 } = resolveTargetAndPath(arg1, arg2, !!opts.hub);
|
|
27559
27772
|
const driver = resolveDriver(registry, config, projectTarget, !!opts.hub);
|
|
27560
|
-
await driver.mkdir(
|
|
27773
|
+
await driver.mkdir(path60);
|
|
27561
27774
|
} catch (err) {
|
|
27562
27775
|
console.error(chalk21.red(err.message));
|
|
27563
27776
|
process.exit(1);
|
|
@@ -27597,8 +27810,8 @@ init_dist4();
|
|
|
27597
27810
|
init_dist();
|
|
27598
27811
|
import { Command as Command21 } from "commander";
|
|
27599
27812
|
import chalk23 from "chalk";
|
|
27600
|
-
import
|
|
27601
|
-
import
|
|
27813
|
+
import fs45 from "fs";
|
|
27814
|
+
import path50 from "path";
|
|
27602
27815
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
27603
27816
|
function parseScope(v2) {
|
|
27604
27817
|
if (v2 !== "user" && v2 !== "project") {
|
|
@@ -27607,10 +27820,10 @@ function parseScope(v2) {
|
|
|
27607
27820
|
return v2;
|
|
27608
27821
|
}
|
|
27609
27822
|
function findPackageRoot3() {
|
|
27610
|
-
let dir =
|
|
27823
|
+
let dir = path50.dirname(fileURLToPath4(import.meta.url));
|
|
27611
27824
|
while (dir !== "/" && dir !== "") {
|
|
27612
|
-
if (
|
|
27613
|
-
dir =
|
|
27825
|
+
if (fs45.existsSync(path50.join(dir, "package.json"))) return dir;
|
|
27826
|
+
dir = path50.dirname(dir);
|
|
27614
27827
|
}
|
|
27615
27828
|
return process.cwd();
|
|
27616
27829
|
}
|
|
@@ -27825,12 +28038,12 @@ init_dist();
|
|
|
27825
28038
|
init_dist();
|
|
27826
28039
|
init_dist2();
|
|
27827
28040
|
import { Command as Command23 } from "commander";
|
|
27828
|
-
import
|
|
28041
|
+
import fs46 from "fs";
|
|
27829
28042
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
27830
28043
|
import { dirname as dirname8, join as join31 } from "path";
|
|
27831
28044
|
import chalk24 from "chalk";
|
|
27832
28045
|
function runConfigCheck(opts) {
|
|
27833
|
-
const raw = JSON.parse(
|
|
28046
|
+
const raw = JSON.parse(fs46.readFileSync(opts.configPath, "utf-8"));
|
|
27834
28047
|
const def = getDefaultConfig();
|
|
27835
28048
|
const items = detectDrift(raw, def);
|
|
27836
28049
|
let working = raw;
|
|
@@ -27918,7 +28131,7 @@ function printItems(items) {
|
|
|
27918
28131
|
var configCommand = new Command23("config").description("Inspect and reconcile squadrant config");
|
|
27919
28132
|
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
28133
|
const pkgVersion = readPkgVersion2();
|
|
27921
|
-
if (!
|
|
28134
|
+
if (!fs46.existsSync(DEFAULT_CONFIG_PATH)) {
|
|
27922
28135
|
console.log(chalk24.yellow("No config found \u2014 run `squadrant init` first."));
|
|
27923
28136
|
return;
|
|
27924
28137
|
}
|
|
@@ -27964,7 +28177,7 @@ configCommand.command("set").description("Write a config value by dotted key (e.
|
|
|
27964
28177
|
});
|
|
27965
28178
|
function readPkgVersion2() {
|
|
27966
28179
|
const pkgPath = join31(dirname8(fileURLToPath5(import.meta.url)), "..", "package.json");
|
|
27967
|
-
return JSON.parse(
|
|
28180
|
+
return JSON.parse(fs46.readFileSync(pkgPath, "utf-8")).version;
|
|
27968
28181
|
}
|
|
27969
28182
|
|
|
27970
28183
|
// packages/cli/src/commands/heal.ts
|
|
@@ -28409,8 +28622,8 @@ var cmuxCommand = new Command28("cmux").description("cmux integration helpers").
|
|
|
28409
28622
|
// packages/cli/src/commands/effort.ts
|
|
28410
28623
|
init_dist();
|
|
28411
28624
|
init_dist2();
|
|
28412
|
-
import
|
|
28413
|
-
import
|
|
28625
|
+
import fs47 from "fs";
|
|
28626
|
+
import path51 from "path";
|
|
28414
28627
|
import { Command as Command29 } from "commander";
|
|
28415
28628
|
import chalk30 from "chalk";
|
|
28416
28629
|
var VALID_EFFORTS = ["max", "balance", "low"];
|
|
@@ -28453,9 +28666,9 @@ function effortScopeLabel(projectName) {
|
|
|
28453
28666
|
}
|
|
28454
28667
|
function canonical(p) {
|
|
28455
28668
|
try {
|
|
28456
|
-
return
|
|
28669
|
+
return fs47.realpathSync(p);
|
|
28457
28670
|
} catch {
|
|
28458
|
-
return
|
|
28671
|
+
return path51.resolve(p);
|
|
28459
28672
|
}
|
|
28460
28673
|
}
|
|
28461
28674
|
async function notifyCaptainsOfEffort(effort, config, driver, cwd = process.cwd(), append, scopeProject, projectConfigRoot) {
|
|
@@ -28505,7 +28718,7 @@ var effortCommand = new Command29("effort").description("Get or set the crew tok
|
|
|
28505
28718
|
const config = loadConfig();
|
|
28506
28719
|
const registry = new RuntimeRegistry2({ cmux: createCmuxDriver2() });
|
|
28507
28720
|
const driver = registry.global(config);
|
|
28508
|
-
const stateRoot =
|
|
28721
|
+
const stateRoot = path51.join(path51.dirname(DEFAULT_CONFIG_PATH), "state");
|
|
28509
28722
|
const append = (project, text) => appendCaptainMessage({ stateRoot, project, text, source: "daemon" });
|
|
28510
28723
|
await notifyCaptainsOfEffort(effort, config, driver, process.cwd(), append, options.project);
|
|
28511
28724
|
} catch {
|
|
@@ -28515,13 +28728,13 @@ var effortCommand = new Command29("effort").description("Get or set the crew tok
|
|
|
28515
28728
|
|
|
28516
28729
|
// packages/cli/src/commands/tokens.ts
|
|
28517
28730
|
init_dist();
|
|
28518
|
-
import
|
|
28519
|
-
import
|
|
28731
|
+
import fs48 from "fs";
|
|
28732
|
+
import path52 from "path";
|
|
28520
28733
|
import os23 from "os";
|
|
28521
28734
|
import readline3 from "readline";
|
|
28522
28735
|
import { Command as Command30 } from "commander";
|
|
28523
28736
|
import chalk31 from "chalk";
|
|
28524
|
-
var CLAUDE_PROJECTS_DIR =
|
|
28737
|
+
var CLAUDE_PROJECTS_DIR = path52.join(os23.homedir(), ".claude", "projects");
|
|
28525
28738
|
function parseTranscriptLine(rawLine) {
|
|
28526
28739
|
const line2 = rawLine.trim();
|
|
28527
28740
|
if (!line2) return { timestamp: null, usage: null };
|
|
@@ -28571,7 +28784,7 @@ function foldTranscriptLine(agg, rawLine, state) {
|
|
|
28571
28784
|
async function aggregateTranscriptFile(filePath) {
|
|
28572
28785
|
const agg = emptySessionAggregate();
|
|
28573
28786
|
const state = { lastCacheRead: null };
|
|
28574
|
-
const rl = readline3.createInterface({ input:
|
|
28787
|
+
const rl = readline3.createInterface({ input: fs48.createReadStream(filePath), crlfDelay: Infinity });
|
|
28575
28788
|
for await (const line2 of rl) {
|
|
28576
28789
|
foldTranscriptLine(agg, line2, state);
|
|
28577
28790
|
}
|
|
@@ -28639,22 +28852,22 @@ function buildRoleReport(role, sessions) {
|
|
|
28639
28852
|
}
|
|
28640
28853
|
async function readdirSafe(dir) {
|
|
28641
28854
|
try {
|
|
28642
|
-
return await
|
|
28855
|
+
return await fs48.promises.readdir(dir);
|
|
28643
28856
|
} catch {
|
|
28644
28857
|
return [];
|
|
28645
28858
|
}
|
|
28646
28859
|
}
|
|
28647
28860
|
async function listJsonlFiles(dir) {
|
|
28648
28861
|
const entries = await readdirSafe(dir);
|
|
28649
|
-
return entries.filter((e) => e.endsWith(".jsonl")).map((e) =>
|
|
28862
|
+
return entries.filter((e) => e.endsWith(".jsonl")).map((e) => path52.join(dir, e));
|
|
28650
28863
|
}
|
|
28651
28864
|
async function findTranscriptDirs(claudeProjectsDir, captainSlug) {
|
|
28652
28865
|
const entries = await readdirSafe(claudeProjectsDir);
|
|
28653
28866
|
const captainDirs = [];
|
|
28654
28867
|
const crewDirs = [];
|
|
28655
28868
|
for (const entry of entries) {
|
|
28656
|
-
if (entry === captainSlug) captainDirs.push(
|
|
28657
|
-
else if (isCrewDirName(entry, captainSlug)) crewDirs.push(
|
|
28869
|
+
if (entry === captainSlug) captainDirs.push(path52.join(claudeProjectsDir, entry));
|
|
28870
|
+
else if (isCrewDirName(entry, captainSlug)) crewDirs.push(path52.join(claudeProjectsDir, entry));
|
|
28658
28871
|
}
|
|
28659
28872
|
return { captainDirs, crewDirs };
|
|
28660
28873
|
}
|
|
@@ -29141,8 +29354,8 @@ import { join as join36 } from "path";
|
|
|
29141
29354
|
import { homedir as homedir20 } from "os";
|
|
29142
29355
|
|
|
29143
29356
|
// packages/cli/src/lib/captain-session-registry.ts
|
|
29144
|
-
import
|
|
29145
|
-
import
|
|
29357
|
+
import fs49 from "fs";
|
|
29358
|
+
import path53 from "path";
|
|
29146
29359
|
|
|
29147
29360
|
// packages/cli/src/lib/handoff-facts.ts
|
|
29148
29361
|
var STALE_FETCH_WARNING_MS = 24 * 60 * 60 * 1e3;
|
|
@@ -29193,15 +29406,15 @@ function assembleHandoffFacts(live, claudeMem, gapSessions, checkpoint, now, ext
|
|
|
29193
29406
|
// packages/cli/src/lib/captain-session-registry.ts
|
|
29194
29407
|
var CAPTAIN_SESSION_REGISTRY_FILE = "captain-sessions.jsonl";
|
|
29195
29408
|
function appendCaptainSession(spokeVault, record) {
|
|
29196
|
-
|
|
29197
|
-
const file =
|
|
29198
|
-
|
|
29409
|
+
fs49.mkdirSync(spokeVault, { recursive: true });
|
|
29410
|
+
const file = path53.join(spokeVault, CAPTAIN_SESSION_REGISTRY_FILE);
|
|
29411
|
+
fs49.appendFileSync(file, JSON.stringify(record) + "\n");
|
|
29199
29412
|
}
|
|
29200
29413
|
function readCaptainSessionRegistry(spokeVault) {
|
|
29201
|
-
const file =
|
|
29202
|
-
if (!
|
|
29414
|
+
const file = path53.join(spokeVault, CAPTAIN_SESSION_REGISTRY_FILE);
|
|
29415
|
+
if (!fs49.existsSync(file)) return [];
|
|
29203
29416
|
const records = [];
|
|
29204
|
-
for (const line2 of
|
|
29417
|
+
for (const line2 of fs49.readFileSync(file, "utf-8").split("\n")) {
|
|
29205
29418
|
if (!line2.trim()) continue;
|
|
29206
29419
|
try {
|
|
29207
29420
|
records.push(JSON.parse(line2));
|
|
@@ -29651,13 +29864,13 @@ function hooksCommand() {
|
|
|
29651
29864
|
// packages/cli/src/commands/work.ts
|
|
29652
29865
|
init_dist();
|
|
29653
29866
|
init_dist2();
|
|
29654
|
-
import
|
|
29867
|
+
import path54 from "path";
|
|
29655
29868
|
import { Command as Command34 } from "commander";
|
|
29656
29869
|
import chalk34 from "chalk";
|
|
29657
29870
|
function detectCurrentProject(config, cwd = process.cwd()) {
|
|
29658
29871
|
for (const [name, proj] of Object.entries(config.projects)) {
|
|
29659
29872
|
const projPath = resolveHome(proj.path);
|
|
29660
|
-
if (cwd === projPath || cwd.startsWith(projPath +
|
|
29873
|
+
if (cwd === projPath || cwd.startsWith(projPath + path54.sep)) return name;
|
|
29661
29874
|
}
|
|
29662
29875
|
return void 0;
|
|
29663
29876
|
}
|
|
@@ -29789,14 +30002,14 @@ var workCommand = new Command34("work").description("Track your own in-flight wo
|
|
|
29789
30002
|
// packages/cli/src/commands/handoff.ts
|
|
29790
30003
|
init_dist();
|
|
29791
30004
|
import { Command as Command35 } from "commander";
|
|
29792
|
-
import
|
|
30005
|
+
import path57 from "path";
|
|
29793
30006
|
import os24 from "os";
|
|
29794
30007
|
|
|
29795
30008
|
// packages/cli/src/lib/handoff-live-repo.ts
|
|
29796
30009
|
init_dist();
|
|
29797
30010
|
import { execFileSync as execFileSync15 } from "child_process";
|
|
29798
|
-
import
|
|
29799
|
-
import
|
|
30011
|
+
import fs50 from "fs";
|
|
30012
|
+
import path55 from "path";
|
|
29800
30013
|
|
|
29801
30014
|
// packages/cli/src/lib/handoff-branch-state.ts
|
|
29802
30015
|
function tryRun(runner, cmd, args, cwd) {
|
|
@@ -29935,7 +30148,7 @@ function localAheadOfBase(runner, projectPath, base) {
|
|
|
29935
30148
|
}
|
|
29936
30149
|
function readFetchAgeMs(projectPath, now) {
|
|
29937
30150
|
try {
|
|
29938
|
-
const stat2 =
|
|
30151
|
+
const stat2 = fs50.statSync(path55.join(projectPath, ".git", "FETCH_HEAD"));
|
|
29939
30152
|
return Math.max(0, now - stat2.mtime.getTime());
|
|
29940
30153
|
} catch {
|
|
29941
30154
|
return null;
|
|
@@ -30006,7 +30219,7 @@ function gatherLiveRepoState(projectPath, fallbackBaseBranch, tasks, runner = de
|
|
|
30006
30219
|
|
|
30007
30220
|
// packages/cli/src/lib/handoff-claude-mem.ts
|
|
30008
30221
|
import { createRequire } from "module";
|
|
30009
|
-
import
|
|
30222
|
+
import fs51 from "fs";
|
|
30010
30223
|
var { DatabaseSync } = createRequire(import.meta.url)("node:sqlite");
|
|
30011
30224
|
var CLAUDE_MEM_RECENCY_LIMIT = 20;
|
|
30012
30225
|
function decisionText(row) {
|
|
@@ -30020,7 +30233,7 @@ function decisionText(row) {
|
|
|
30020
30233
|
return row.narrative ?? "";
|
|
30021
30234
|
}
|
|
30022
30235
|
function queryClaudeMem(dbPath, project) {
|
|
30023
|
-
if (!
|
|
30236
|
+
if (!fs51.existsSync(dbPath)) return null;
|
|
30024
30237
|
let db;
|
|
30025
30238
|
try {
|
|
30026
30239
|
db = new DatabaseSync(dbPath, { readOnly: true });
|
|
@@ -30063,7 +30276,7 @@ function queryClaudeMem(dbPath, project) {
|
|
|
30063
30276
|
}
|
|
30064
30277
|
|
|
30065
30278
|
// packages/cli/src/lib/handoff-transcript.ts
|
|
30066
|
-
import
|
|
30279
|
+
import fs52 from "fs";
|
|
30067
30280
|
var TRANSCRIPT_BYTE_CAP = 2e5;
|
|
30068
30281
|
var DIGEST_BYTE_CAP = 8 * 1024;
|
|
30069
30282
|
var PROMPT_TRUNCATE_CHARS = 300;
|
|
@@ -30172,27 +30385,27 @@ function extractMessages(tailText) {
|
|
|
30172
30385
|
return { lastUserMessage, lastAssistantText, digest };
|
|
30173
30386
|
}
|
|
30174
30387
|
function extractTranscriptTail(transcriptPath, byteCap = TRANSCRIPT_BYTE_CAP) {
|
|
30175
|
-
if (!
|
|
30176
|
-
const content =
|
|
30388
|
+
if (!fs52.existsSync(transcriptPath)) return null;
|
|
30389
|
+
const content = fs52.readFileSync(transcriptPath, "utf-8");
|
|
30177
30390
|
const { lastUserMessage, lastAssistantText, digest } = extractMessages(tailOf(content, byteCap));
|
|
30178
|
-
const mtimeIso =
|
|
30391
|
+
const mtimeIso = fs52.statSync(transcriptPath).mtime.toISOString();
|
|
30179
30392
|
return { path: transcriptPath, mtimeIso, lastUserMessage, lastAssistantText, digest };
|
|
30180
30393
|
}
|
|
30181
30394
|
|
|
30182
30395
|
// packages/cli/src/lib/handoff-archive.ts
|
|
30183
|
-
import
|
|
30184
|
-
import
|
|
30396
|
+
import fs53 from "fs";
|
|
30397
|
+
import path56 from "path";
|
|
30185
30398
|
function readNewestArchivedHandoff(spokeVault, now) {
|
|
30186
|
-
const dir =
|
|
30187
|
-
if (!
|
|
30188
|
-
const candidates =
|
|
30189
|
-
const full =
|
|
30190
|
-
return { name: e.name, full, mtime:
|
|
30399
|
+
const dir = path56.join(spokeVault, "handoffs");
|
|
30400
|
+
if (!fs53.existsSync(dir)) return null;
|
|
30401
|
+
const candidates = fs53.readdirSync(dir, { withFileTypes: true }).filter((e) => e.isFile() && e.name.endsWith(".json")).map((e) => {
|
|
30402
|
+
const full = path56.join(dir, e.name);
|
|
30403
|
+
return { name: e.name, full, mtime: fs53.statSync(full).mtime };
|
|
30191
30404
|
}).sort((a, b) => b.mtime.getTime() - a.mtime.getTime());
|
|
30192
30405
|
for (const candidate of candidates) {
|
|
30193
30406
|
let content;
|
|
30194
30407
|
try {
|
|
30195
|
-
content = JSON.parse(
|
|
30408
|
+
content = JSON.parse(fs53.readFileSync(candidate.full, "utf-8"));
|
|
30196
30409
|
} catch {
|
|
30197
30410
|
continue;
|
|
30198
30411
|
}
|
|
@@ -30202,7 +30415,7 @@ function readNewestArchivedHandoff(spokeVault, now) {
|
|
|
30202
30415
|
}
|
|
30203
30416
|
|
|
30204
30417
|
// packages/cli/src/commands/handoff.ts
|
|
30205
|
-
var CLAUDE_MEM_DB_PATH =
|
|
30418
|
+
var CLAUDE_MEM_DB_PATH = path57.join(os24.homedir(), ".claude-mem", "claude-mem.db");
|
|
30206
30419
|
async function defaultFetchTasks(project) {
|
|
30207
30420
|
return await squadrantdCall({ kind: "list", project });
|
|
30208
30421
|
}
|
|
@@ -30270,9 +30483,9 @@ function filterSessions(rows, f) {
|
|
|
30270
30483
|
if (f.agent && r.agent !== f.agent) return false;
|
|
30271
30484
|
if (f.liveOnly && r.status === "stale") return false;
|
|
30272
30485
|
if (f.project) {
|
|
30273
|
-
const
|
|
30486
|
+
const path60 = f.projects?.[f.project];
|
|
30274
30487
|
const byRecord = r.project === f.project;
|
|
30275
|
-
const byCwd = !!
|
|
30488
|
+
const byCwd = !!path60 && !!r.cwd && (r.cwd === normalized(path60) || r.cwd.startsWith(normalized(path60) + "/"));
|
|
30276
30489
|
if (!byRecord && !byCwd) return false;
|
|
30277
30490
|
}
|
|
30278
30491
|
return true;
|
|
@@ -30363,7 +30576,7 @@ init_dist();
|
|
|
30363
30576
|
init_dist2();
|
|
30364
30577
|
init_dist3();
|
|
30365
30578
|
import os25 from "os";
|
|
30366
|
-
import
|
|
30579
|
+
import path58 from "path";
|
|
30367
30580
|
import { Command as Command37 } from "commander";
|
|
30368
30581
|
import chalk36 from "chalk";
|
|
30369
30582
|
|
|
@@ -30481,7 +30694,7 @@ function buildWhoamiDeps(opts = {}) {
|
|
|
30481
30694
|
const projects = Object.fromEntries(
|
|
30482
30695
|
Object.entries(config.projects).map(([n, p]) => [n, resolveHome(p.path)])
|
|
30483
30696
|
);
|
|
30484
|
-
const root = stateRoot ??
|
|
30697
|
+
const root = stateRoot ?? path58.join(os25.homedir(), ".config", "squadrant", "state");
|
|
30485
30698
|
const store = createStore(root);
|
|
30486
30699
|
const merged = {
|
|
30487
30700
|
env: process.env,
|
|
@@ -30533,11 +30746,11 @@ var whoamiCommand = new Command37("whoami").description("Show the agent session
|
|
|
30533
30746
|
// packages/cli/src/commands/knowledge.ts
|
|
30534
30747
|
init_dist();
|
|
30535
30748
|
init_dist2();
|
|
30536
|
-
import
|
|
30749
|
+
import fs54 from "fs";
|
|
30537
30750
|
import os26 from "os";
|
|
30538
|
-
import
|
|
30751
|
+
import path59 from "path";
|
|
30539
30752
|
import readline4 from "readline/promises";
|
|
30540
|
-
import { spawnSync } from "child_process";
|
|
30753
|
+
import { spawnSync as spawnSync2 } from "child_process";
|
|
30541
30754
|
import { Command as Command39 } from "commander";
|
|
30542
30755
|
import chalk38 from "chalk";
|
|
30543
30756
|
|
|
@@ -30602,7 +30815,8 @@ function runRulesSearch(query, opts, configPath = DEFAULT_CONFIG_PATH) {
|
|
|
30602
30815
|
const rules = loadFor(opts, configPath);
|
|
30603
30816
|
const hits = searchRules(rules, query, { statuses: opts.all ? [...RULE_STATUSES] : DEFAULT_SEARCH_STATUSES });
|
|
30604
30817
|
const project = resolveRulesProject(loadConfig(configPath), opts);
|
|
30605
|
-
|
|
30818
|
+
const shown = hits.slice(0, parseLimit(opts.limit));
|
|
30819
|
+
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
30820
|
return hits;
|
|
30607
30821
|
}
|
|
30608
30822
|
function runRulesList(opts, configPath = DEFAULT_CONFIG_PATH) {
|
|
@@ -30685,18 +30899,18 @@ function runKnowledgeInit(kb, configPath = DEFAULT_CONFIG_PATH) {
|
|
|
30685
30899
|
const cfg = loadConfig(configPath);
|
|
30686
30900
|
const dir = kbDir(cfg, kb);
|
|
30687
30901
|
const created = [];
|
|
30688
|
-
for (const d of [
|
|
30689
|
-
if (!
|
|
30690
|
-
|
|
30691
|
-
created.push(
|
|
30902
|
+
for (const d of [path59.join(dir, "raw"), kbRulesDir(cfg, kb), path59.join(kbRulesDir(cfg, kb), PROPOSED_DIR)]) {
|
|
30903
|
+
if (!fs54.existsSync(d)) {
|
|
30904
|
+
fs54.mkdirSync(d, { recursive: true });
|
|
30905
|
+
created.push(path59.relative(dir, d));
|
|
30692
30906
|
}
|
|
30693
30907
|
}
|
|
30694
|
-
const sourcesFile =
|
|
30695
|
-
if (!
|
|
30696
|
-
|
|
30908
|
+
const sourcesFile = path59.join(dir, "sources.yaml");
|
|
30909
|
+
if (!fs54.existsSync(sourcesFile)) {
|
|
30910
|
+
fs54.writeFileSync(sourcesFile, SOURCES_TEMPLATE);
|
|
30697
30911
|
created.push("sources.yaml");
|
|
30698
30912
|
}
|
|
30699
|
-
if (!
|
|
30913
|
+
if (!fs54.existsSync(path59.join(dir, "index.json"))) {
|
|
30700
30914
|
writeIndex(dir, compileIndex(kb, []));
|
|
30701
30915
|
created.push("index.json");
|
|
30702
30916
|
}
|
|
@@ -30713,7 +30927,7 @@ function runKnowledgeSubscribe(kb, project, configPath = DEFAULT_CONFIG_PATH) {
|
|
|
30713
30927
|
const cfg = loadConfig(configPath);
|
|
30714
30928
|
const pc = cfg.projects[project];
|
|
30715
30929
|
if (!pc) throw new Error(`Unknown project '${project}'`);
|
|
30716
|
-
if (!
|
|
30930
|
+
if (!fs54.existsSync(kbDir(cfg, kb))) {
|
|
30717
30931
|
throw new Error(`Knowledge base '${kb}' does not exist. Run: squadrant knowledge init ${kb}`);
|
|
30718
30932
|
}
|
|
30719
30933
|
const list = pc.knowledge ?? [];
|
|
@@ -30728,6 +30942,12 @@ function runKnowledgeSources(kb, configPath = DEFAULT_CONFIG_PATH) {
|
|
|
30728
30942
|
const cfg = loadConfig(configPath);
|
|
30729
30943
|
return loadSources(kbDir(cfg, kb));
|
|
30730
30944
|
}
|
|
30945
|
+
function runKnowledgeSourcesRemove(kb, entryPath, opts = {}, configPath = DEFAULT_CONFIG_PATH) {
|
|
30946
|
+
assertKbName(kb);
|
|
30947
|
+
const cfg = loadConfig(configPath);
|
|
30948
|
+
if (!fs54.existsSync(kbDir(cfg, kb))) throw new Error(`Knowledge base '${kb}' does not exist. Run: squadrant knowledge init ${kb}`);
|
|
30949
|
+
return removeSource(kbDir(cfg, kb), kbRulesDir(cfg, kb), entryPath, { ...opts, kbName: kb });
|
|
30950
|
+
}
|
|
30731
30951
|
var knowledgeCommand = new Command39("knowledge").description("Manage rules knowledge bases (#893)");
|
|
30732
30952
|
knowledgeCommand.command("init <kb>").description("Create a knowledge base (its own git repo) under ~/squadrant/kb/<kb>/").action((kb) => {
|
|
30733
30953
|
const { dir, created } = runKnowledgeInit(kb);
|
|
@@ -30739,11 +30959,20 @@ knowledgeCommand.command("subscribe <kb>").description("Subscribe a project to a
|
|
|
30739
30959
|
const list = runKnowledgeSubscribe(kb, opts.project);
|
|
30740
30960
|
console.log(`${opts.project} knowledge: ${list.join(", ")}`);
|
|
30741
30961
|
});
|
|
30742
|
-
knowledgeCommand.command("sources <kb>").description("List the trusted sources of a knowledge base").action((kb) => {
|
|
30962
|
+
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) => {
|
|
30963
|
+
if (o.dryRun && !o.remove) throw new Error("--dry-run only applies to --remove");
|
|
30964
|
+
if (o.remove) {
|
|
30965
|
+
const r = runKnowledgeSourcesRemove(kb, o.remove, { dryRun: o.dryRun });
|
|
30966
|
+
const stripped = r.stripped.length - r.stale.length;
|
|
30967
|
+
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`);
|
|
30968
|
+
for (const id of r.stale) console.log(chalk38.yellow(` stale: ${id}`));
|
|
30969
|
+
if (r.dryRun) console.log(chalk38.dim("dry run: nothing written"));
|
|
30970
|
+
return;
|
|
30971
|
+
}
|
|
30743
30972
|
const { sources, errors } = runKnowledgeSources(kb);
|
|
30744
30973
|
if (!sources.length && !errors.length) console.log("(no sources \u2014 edit sources.yaml)");
|
|
30745
30974
|
for (const s of sources) {
|
|
30746
|
-
console.log(` ${s.priority.padEnd(8)} ${s.path}${s.domain ? ` [${s.domain}]` : ""}${s.sensitivity ? chalk38.yellow(" local-only") : ""}`);
|
|
30975
|
+
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
30976
|
}
|
|
30748
30977
|
for (const e of errors) console.log(chalk38.red(` \u2718 ${e}`));
|
|
30749
30978
|
if (errors.length) process.exitCode = 1;
|
|
@@ -30751,9 +30980,9 @@ knowledgeCommand.command("sources <kb>").description("List the trusted sources o
|
|
|
30751
30980
|
function runKnowledgeReindex(kb, configPath = DEFAULT_CONFIG_PATH) {
|
|
30752
30981
|
assertKbName(kb);
|
|
30753
30982
|
const cfg = loadConfig(configPath);
|
|
30754
|
-
if (!
|
|
30983
|
+
if (!fs54.existsSync(kbDir(cfg, kb))) throw new Error(`Knowledge base '${kb}' does not exist. Run: squadrant knowledge init ${kb}`);
|
|
30755
30984
|
const { rules: all, errors: allErrors } = loadKbRules(cfg, kb, { includeProposed: true });
|
|
30756
|
-
const proposedRoot =
|
|
30985
|
+
const proposedRoot = path59.join(kbRulesDir(cfg, kb), PROPOSED_DIR) + path59.sep;
|
|
30757
30986
|
const live = all.filter((r) => !r.file.startsWith(proposedRoot));
|
|
30758
30987
|
const pendingDups = allErrors.filter((e) => isPendingProposalDup(e, kbRulesDir(cfg, kb)));
|
|
30759
30988
|
const errors = allErrors.filter((e) => !pendingDups.includes(e));
|
|
@@ -30763,11 +30992,15 @@ function runKnowledgeReindex(kb, configPath = DEFAULT_CONFIG_PATH) {
|
|
|
30763
30992
|
function runKnowledgeValidate(kb, configPath = DEFAULT_CONFIG_PATH) {
|
|
30764
30993
|
assertKbName(kb);
|
|
30765
30994
|
const cfg = loadConfig(configPath);
|
|
30766
|
-
if (!
|
|
30995
|
+
if (!fs54.existsSync(kbDir(cfg, kb))) throw new Error(`Knowledge base '${kb}' does not exist. Run: squadrant knowledge init ${kb}`);
|
|
30767
30996
|
const { sources, errors } = loadSources(kbDir(cfg, kb));
|
|
30768
|
-
const
|
|
30769
|
-
const
|
|
30770
|
-
|
|
30997
|
+
const { errata, errors: errataErrors } = loadErrata(kbDir(cfg, kb));
|
|
30998
|
+
const res = validateKb({ rulesDir: kbRulesDir(cfg, kb), kbRoot: kbDir(cfg, kb), sources, errata, domains: kbConfigs(cfg)[kb]?.domains });
|
|
30999
|
+
const srcChecks = [
|
|
31000
|
+
...errors.map((e) => ({ level: "fail", message: `sources.yaml: ${e}` })),
|
|
31001
|
+
...errataErrors.map((e) => ({ level: "fail", message: `errata.yaml: ${e}` }))
|
|
31002
|
+
];
|
|
31003
|
+
return { checks: [...srcChecks, ...res.checks], ok: res.ok && !srcChecks.length };
|
|
30771
31004
|
}
|
|
30772
31005
|
knowledgeCommand.command("reindex <kb>").description("Recompile index.json from the KB's rule files").action((kb) => {
|
|
30773
31006
|
const r = runKnowledgeReindex(kb);
|
|
@@ -30793,7 +31026,7 @@ knowledgeCommand.command("migrate").description("Move <hubVault>/knowledge/<kb>/
|
|
|
30793
31026
|
function requireKb(kb, configPath) {
|
|
30794
31027
|
assertKbName(kb);
|
|
30795
31028
|
const cfg = loadConfig(configPath);
|
|
30796
|
-
if (!
|
|
31029
|
+
if (!fs54.existsSync(kbDir(cfg, kb))) throw new Error(`Knowledge base '${kb}' does not exist. Run: squadrant knowledge init ${kb}`);
|
|
30797
31030
|
return cfg;
|
|
30798
31031
|
}
|
|
30799
31032
|
async function runKnowledgeIngest(kb, opts = {}, configPath = DEFAULT_CONFIG_PATH) {
|
|
@@ -30812,10 +31045,14 @@ async function runKnowledgeIngest(kb, opts = {}, configPath = DEFAULT_CONFIG_PAT
|
|
|
30812
31045
|
}
|
|
30813
31046
|
function runKnowledgeApply(kb, candidatesFile, configPath = DEFAULT_CONFIG_PATH) {
|
|
30814
31047
|
const cfg = requireKb(kb, configPath);
|
|
30815
|
-
const input = JSON.parse(
|
|
31048
|
+
const input = JSON.parse(fs54.readFileSync(candidatesFile, "utf8"));
|
|
30816
31049
|
if (!input || !Array.isArray(input.candidates)) throw new Error("candidates file must be { complete?: string[], candidates: [...] }");
|
|
30817
31050
|
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
|
-
|
|
31051
|
+
const { errata, errors } = loadErrata(kbDir(cfg, kb));
|
|
31052
|
+
if (errors.length) throw new Error(`errata.yaml: ${errors.join("; ")}`);
|
|
31053
|
+
const { sources, errors: sourceErrors } = loadSources(kbDir(cfg, kb));
|
|
31054
|
+
if (sourceErrors.length) throw new Error(`sources.yaml: ${sourceErrors.join("; ")}`);
|
|
31055
|
+
return applyCandidates(input, { kb, kbRoot: kbDir(cfg, kb), rulesDir: kbRulesDir(cfg, kb), projects, sources, errata });
|
|
30819
31056
|
}
|
|
30820
31057
|
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
31058
|
const plan = await runKnowledgeIngest(kb, opts);
|
|
@@ -30834,16 +31071,19 @@ knowledgeCommand.command("apply <kb> <candidates>").description("Verify extracte
|
|
|
30834
31071
|
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
31072
|
for (const x of r.rejected) console.log(chalk38.red(` \u2718 ${x.id} (${x.source}): ${x.reason}`));
|
|
30836
31073
|
for (const x of r.idOverrides) console.log(chalk38.dim(` id ${x.from} \u2192 ${x.to} (matched by quote offset)`));
|
|
31074
|
+
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
31075
|
for (const d of r.doclingFlags) console.log(chalk38.yellow(` ${d.ref}: ${d.dropped}/${d.total} candidates dropped; conversion likely poor, try docling`));
|
|
30838
31076
|
});
|
|
30839
|
-
var defaultStateRoot2 = () =>
|
|
31077
|
+
var defaultStateRoot2 = () => path59.join(path59.dirname(DEFAULT_CONFIG_PATH), "state");
|
|
30840
31078
|
function reviewContext(kb, configPath) {
|
|
30841
31079
|
const cfg = requireKb(kb, configPath);
|
|
30842
31080
|
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
|
-
|
|
31081
|
+
const { sources, errors } = loadSources(kbDir(cfg, kb));
|
|
31082
|
+
if (errors.length) throw new Error(`sources.yaml: ${errors.join("; ")}`);
|
|
31083
|
+
return { cfg, kb, sources, projects };
|
|
30844
31084
|
}
|
|
30845
31085
|
function runKnowledgeReviewApply(kb, file, configPath = DEFAULT_CONFIG_PATH) {
|
|
30846
|
-
return applyDecisions(JSON.parse(
|
|
31086
|
+
return applyDecisions(JSON.parse(fs54.readFileSync(file, "utf8")), reviewContext(kb, configPath));
|
|
30847
31087
|
}
|
|
30848
31088
|
function runKnowledgeResolve(kb, key, r, by, reason, configPath = DEFAULT_CONFIG_PATH) {
|
|
30849
31089
|
return resolveEscalation(reviewContext(kb, configPath), key, r, by, reason);
|
|
@@ -30891,8 +31131,8 @@ ${e.explanation}`);
|
|
|
30891
31131
|
else if (ans === "r") r = { kind: "reject" };
|
|
30892
31132
|
else if (ans === "e" && e.kind === "proposal") {
|
|
30893
31133
|
const ctx = reviewContext(kb, DEFAULT_CONFIG_PATH);
|
|
30894
|
-
const file =
|
|
30895
|
-
|
|
31134
|
+
const file = path59.join(kbRulesDir(ctx.cfg, kb), PROPOSED_DIR, `${e.item}.md`);
|
|
31135
|
+
spawnSync2(process.env.EDITOR ?? "vi", [file], { stdio: "inherit" });
|
|
30896
31136
|
r = { kind: "approve" };
|
|
30897
31137
|
}
|
|
30898
31138
|
if (r) console.log(chalk38.green(runKnowledgeResolve(kb, e.key, r, by, reason)));
|
|
@@ -30963,7 +31203,7 @@ function renderStats(all) {
|
|
|
30963
31203
|
const pct = (x) => x === null ? "-" : `${Math.round(x * 100)}%`;
|
|
30964
31204
|
return all.flatMap((s) => [
|
|
30965
31205
|
`${s.kb} (last ${s.windowDays} days)`,
|
|
30966
|
-
...s.items.map((x) => ` ${x.itemId} surfaced ${x.surfaced} pulled ${x.
|
|
31206
|
+
...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
31207
|
...s.domains.map((d) => ` domain ${d.domain}: writes ${d.writesPerMonth}/mo reads ${d.readsPerMonth}/mo${d.deadDomain ? " DEAD DOMAIN" : ""}`),
|
|
30968
31208
|
` agents: ${Object.entries(s.perAgentCoverage).map(([k, v2]) => `${k} ${v2}`).join(", ") || "none"}`
|
|
30969
31209
|
]);
|
|
@@ -30974,10 +31214,10 @@ knowledgeCommand.command("stats").description("Scores computed from the audit lo
|
|
|
30974
31214
|
else for (const l of renderStats(all)) console.log(l);
|
|
30975
31215
|
});
|
|
30976
31216
|
function runKnowledgeCiteScan(o) {
|
|
30977
|
-
const run = o.git_run ?? ((args) =>
|
|
31217
|
+
const run = o.git_run ?? ((args) => spawnSync2("git", args, { encoding: "utf8" }).stdout ?? "");
|
|
30978
31218
|
if (o.git) {
|
|
30979
31219
|
const since = new Date((o.audit?.now?.() ?? /* @__PURE__ */ new Date()).getTime() - (o.sinceDays ?? 30) * 864e5);
|
|
30980
|
-
return readGitMessages(o.git, since, run).
|
|
31220
|
+
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
31221
|
}
|
|
30982
31222
|
if (!o.text) throw new Error("Pass --text <message> or --git <repo>");
|
|
30983
31223
|
return scanAndLogCitations({ text: o.text, ref: o.ref ?? "manual", project: o.project, sink: o.audit });
|