@mrciphersmith/keryx 0.2.121 → 0.2.122
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/cli.js +887 -194
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -42980,6 +42980,103 @@ async function startStdioTransport(server) {
|
|
|
42980
42980
|
await server.connect(transport);
|
|
42981
42981
|
}
|
|
42982
42982
|
|
|
42983
|
+
// src/tui/debug-log.ts
|
|
42984
|
+
import path192 from "path";
|
|
42985
|
+
function isDebugEnabled() {
|
|
42986
|
+
return activeRun !== undefined;
|
|
42987
|
+
}
|
|
42988
|
+
function currentDebugRun() {
|
|
42989
|
+
return activeRun;
|
|
42990
|
+
}
|
|
42991
|
+
function debugEvent(kind, data = {}) {
|
|
42992
|
+
const run = activeRun;
|
|
42993
|
+
if (run === undefined) {
|
|
42994
|
+
return;
|
|
42995
|
+
}
|
|
42996
|
+
seq += 1;
|
|
42997
|
+
try {
|
|
42998
|
+
appendOwnerOnlyLine(run.shellLog, safeStringify({ ts: new Date().toISOString(), seq, pid: process.pid, kind, ...data }));
|
|
42999
|
+
} catch {}
|
|
43000
|
+
}
|
|
43001
|
+
function callerStack() {
|
|
43002
|
+
const raw = new Error("stack").stack ?? "";
|
|
43003
|
+
return raw.split(`
|
|
43004
|
+
`).slice(1).filter((line) => !line.includes("debug-log.ts")).slice(0, 14).map((line) => line.trim()).join(" | ");
|
|
43005
|
+
}
|
|
43006
|
+
function startDebugRun(opts = {}) {
|
|
43007
|
+
const stamp = (opts.now ?? new Date).toISOString().replace(/[:.]/g, "-");
|
|
43008
|
+
const name = `${stamp}-${process.pid}`;
|
|
43009
|
+
const dir = ensureKeryxSubdir(["debug", name], opts.configDir);
|
|
43010
|
+
const run = {
|
|
43011
|
+
dir,
|
|
43012
|
+
shellLog: path192.join(dir, "shell.ndjson"),
|
|
43013
|
+
watcherLog: path192.join(dir, "watcher.ndjson")
|
|
43014
|
+
};
|
|
43015
|
+
try {
|
|
43016
|
+
writeOwnerOnlyFile(path192.join(path192.dirname(dir), "latest.txt"), `${dir}
|
|
43017
|
+
`);
|
|
43018
|
+
} catch {}
|
|
43019
|
+
activeRun = run;
|
|
43020
|
+
seq = 0;
|
|
43021
|
+
return run;
|
|
43022
|
+
}
|
|
43023
|
+
function summarizeInputChunk(chunk) {
|
|
43024
|
+
const buf = typeof chunk === "string" ? Buffer.from(chunk) : chunk;
|
|
43025
|
+
const text = buf.toString("utf8");
|
|
43026
|
+
let printable = 0;
|
|
43027
|
+
let control = 0;
|
|
43028
|
+
const sequences = [];
|
|
43029
|
+
for (let i = 0;i < text.length; i++) {
|
|
43030
|
+
const ch = text[i] ?? "";
|
|
43031
|
+
const code = ch.charCodeAt(0);
|
|
43032
|
+
if (ch === "\x1B") {
|
|
43033
|
+
let j = i + 1;
|
|
43034
|
+
while (j < text.length && j - i < 48) {
|
|
43035
|
+
const c = text.charCodeAt(j);
|
|
43036
|
+
if (j > i + 1 && c >= 64 && c <= 126 && text[j] !== "[" && text[j] !== "<" && text[j] !== ";") {
|
|
43037
|
+
break;
|
|
43038
|
+
}
|
|
43039
|
+
j++;
|
|
43040
|
+
}
|
|
43041
|
+
if (sequences.length < 12) {
|
|
43042
|
+
sequences.push(Buffer.from(text.slice(i, j + 1)).toString("hex"));
|
|
43043
|
+
}
|
|
43044
|
+
control++;
|
|
43045
|
+
i = j;
|
|
43046
|
+
} else if (code < 32 || code === 127) {
|
|
43047
|
+
control++;
|
|
43048
|
+
if (sequences.length < 12) {
|
|
43049
|
+
sequences.push(Buffer.from(ch).toString("hex"));
|
|
43050
|
+
}
|
|
43051
|
+
} else {
|
|
43052
|
+
printable++;
|
|
43053
|
+
}
|
|
43054
|
+
}
|
|
43055
|
+
return { bytes: buf.length, printable, control, sequences };
|
|
43056
|
+
}
|
|
43057
|
+
function safeStringify(value) {
|
|
43058
|
+
const seen = new WeakSet;
|
|
43059
|
+
return JSON.stringify(value, (_key, v) => {
|
|
43060
|
+
if (typeof v === "bigint") {
|
|
43061
|
+
return v.toString();
|
|
43062
|
+
}
|
|
43063
|
+
if (v instanceof Error) {
|
|
43064
|
+
return { name: v.name, message: v.message, stack: v.stack };
|
|
43065
|
+
}
|
|
43066
|
+
if (v !== null && typeof v === "object") {
|
|
43067
|
+
if (seen.has(v)) {
|
|
43068
|
+
return "[circular]";
|
|
43069
|
+
}
|
|
43070
|
+
seen.add(v);
|
|
43071
|
+
}
|
|
43072
|
+
return v;
|
|
43073
|
+
});
|
|
43074
|
+
}
|
|
43075
|
+
var activeRun, seq = 0;
|
|
43076
|
+
var init_debug_log = __esm(() => {
|
|
43077
|
+
init_config_dir();
|
|
43078
|
+
});
|
|
43079
|
+
|
|
42983
43080
|
// src/lib/oauth/device-code.ts
|
|
42984
43081
|
function requestInit(base, signal) {
|
|
42985
43082
|
return signal === undefined ? base : { ...base, signal };
|
|
@@ -43472,6 +43569,259 @@ var init_login = __esm(() => {
|
|
|
43472
43569
|
SESSION_REFRESHED_GRANTS = ["grok", "github-copilot"];
|
|
43473
43570
|
});
|
|
43474
43571
|
|
|
43572
|
+
// src/tui/debug-watcher.ts
|
|
43573
|
+
import { spawn as spawn6, spawnSync as spawnSync3 } from "child_process";
|
|
43574
|
+
import { closeSync as closeSync3, constants as constants2, openSync as openSync3, readdirSync as readdirSync3, readFileSync as readFileSync9, readlinkSync, statSync as statSync6 } from "fs";
|
|
43575
|
+
import path195 from "path";
|
|
43576
|
+
function parseEpollFdinfo(text) {
|
|
43577
|
+
const out = [];
|
|
43578
|
+
for (const line of text.split(`
|
|
43579
|
+
`)) {
|
|
43580
|
+
const match = /^tfd:\s*(\d+)\s+events:\s*([0-9a-fA-F]+)/.exec(line.trim());
|
|
43581
|
+
if (match?.[1] !== undefined && match[2] !== undefined) {
|
|
43582
|
+
out.push({ tfd: Number(match[1]), events: Number.parseInt(match[2], 16) });
|
|
43583
|
+
}
|
|
43584
|
+
}
|
|
43585
|
+
return out;
|
|
43586
|
+
}
|
|
43587
|
+
function ttyReaderArmed(ttyFds, epoll) {
|
|
43588
|
+
if (ttyFds.length === 0) {
|
|
43589
|
+
return;
|
|
43590
|
+
}
|
|
43591
|
+
return epoll.some((entry) => ttyFds.includes(entry.tfd) && (entry.events & EPOLLIN) !== 0);
|
|
43592
|
+
}
|
|
43593
|
+
function detectStall(history, window = 3) {
|
|
43594
|
+
if (history.length < window) {
|
|
43595
|
+
return;
|
|
43596
|
+
}
|
|
43597
|
+
const recent = history.slice(-window);
|
|
43598
|
+
if (recent.every((s) => s.alive && s.readerArmed === false)) {
|
|
43599
|
+
return "reader-not-polled";
|
|
43600
|
+
}
|
|
43601
|
+
if (recent.every((s) => s.alive && (s.pending ?? 0) > 0) && recent.every((s, i) => i === 0 || (s.pending ?? 0) >= (recent[i - 1]?.pending ?? 0))) {
|
|
43602
|
+
return "input-not-drained";
|
|
43603
|
+
}
|
|
43604
|
+
if (recent.every((s) => s.alive && (s.heartbeatAgeMs ?? 0) > 5000)) {
|
|
43605
|
+
return "event-loop-silent";
|
|
43606
|
+
}
|
|
43607
|
+
return;
|
|
43608
|
+
}
|
|
43609
|
+
function isAlive(pid) {
|
|
43610
|
+
try {
|
|
43611
|
+
process.kill(pid, 0);
|
|
43612
|
+
return true;
|
|
43613
|
+
} catch {
|
|
43614
|
+
return false;
|
|
43615
|
+
}
|
|
43616
|
+
}
|
|
43617
|
+
function readText(file) {
|
|
43618
|
+
try {
|
|
43619
|
+
return readFileSync9(file, "utf8");
|
|
43620
|
+
} catch {
|
|
43621
|
+
return;
|
|
43622
|
+
}
|
|
43623
|
+
}
|
|
43624
|
+
function listFds(pid) {
|
|
43625
|
+
const out = [];
|
|
43626
|
+
let entries;
|
|
43627
|
+
try {
|
|
43628
|
+
entries = readdirSync3(`/proc/${pid}/fd`);
|
|
43629
|
+
} catch {
|
|
43630
|
+
return out;
|
|
43631
|
+
}
|
|
43632
|
+
for (const name of entries) {
|
|
43633
|
+
const fd = Number(name);
|
|
43634
|
+
let link;
|
|
43635
|
+
try {
|
|
43636
|
+
link = readlinkSync(`/proc/${pid}/fd/${name}`);
|
|
43637
|
+
} catch {
|
|
43638
|
+
continue;
|
|
43639
|
+
}
|
|
43640
|
+
const flags = /flags:\s*(\S+)/.exec(readText(`/proc/${pid}/fdinfo/${name}`) ?? "")?.[1];
|
|
43641
|
+
out.push({ fd, link, flags });
|
|
43642
|
+
}
|
|
43643
|
+
return out;
|
|
43644
|
+
}
|
|
43645
|
+
function epollEntries(pid, fds) {
|
|
43646
|
+
return fds.filter((f) => f.link === "anon_inode:[eventpoll]").map((f) => ({ epfd: f.fd, entries: parseEpollFdinfo(readText(`/proc/${pid}/fdinfo/${f.fd}`) ?? "") }));
|
|
43647
|
+
}
|
|
43648
|
+
function threads(pid) {
|
|
43649
|
+
let tids;
|
|
43650
|
+
try {
|
|
43651
|
+
tids = readdirSync3(`/proc/${pid}/task`);
|
|
43652
|
+
} catch {
|
|
43653
|
+
return [];
|
|
43654
|
+
}
|
|
43655
|
+
return tids.map((tid) => {
|
|
43656
|
+
const base = `/proc/${pid}/task/${tid}`;
|
|
43657
|
+
const stat = readText(`${base}/stat`) ?? "";
|
|
43658
|
+
const state = /\)\s+(\S)/.exec(stat)?.[1] ?? "?";
|
|
43659
|
+
return { tid, comm: (readText(`${base}/comm`) ?? "").trim(), wchan: (readText(`${base}/wchan`) ?? "").trim(), state };
|
|
43660
|
+
});
|
|
43661
|
+
}
|
|
43662
|
+
async function makePendingReader() {
|
|
43663
|
+
if (process.platform !== "linux") {
|
|
43664
|
+
return () => {
|
|
43665
|
+
return;
|
|
43666
|
+
};
|
|
43667
|
+
}
|
|
43668
|
+
try {
|
|
43669
|
+
const ffi = await import("bun:ffi");
|
|
43670
|
+
const libc = ffi.dlopen("libc.so.6", {
|
|
43671
|
+
ioctl: { args: [ffi.FFIType.i32, ffi.FFIType.u64, ffi.FFIType.ptr], returns: ffi.FFIType.i32 }
|
|
43672
|
+
});
|
|
43673
|
+
return (fd) => {
|
|
43674
|
+
const out = new Int32Array(1);
|
|
43675
|
+
const rc = libc.symbols.ioctl(fd, FIONREAD, ffi.ptr(out));
|
|
43676
|
+
return rc === 0 ? out[0] ?? 0 : undefined;
|
|
43677
|
+
};
|
|
43678
|
+
} catch {
|
|
43679
|
+
return () => {
|
|
43680
|
+
return;
|
|
43681
|
+
};
|
|
43682
|
+
}
|
|
43683
|
+
}
|
|
43684
|
+
function spawnDebugWatcher(run) {
|
|
43685
|
+
const entry = process.argv[1];
|
|
43686
|
+
const args = [
|
|
43687
|
+
...entry !== undefined ? [entry] : [],
|
|
43688
|
+
"shell",
|
|
43689
|
+
"--debug-watcher",
|
|
43690
|
+
"--pid",
|
|
43691
|
+
String(process.pid),
|
|
43692
|
+
"--dir",
|
|
43693
|
+
run.dir
|
|
43694
|
+
];
|
|
43695
|
+
try {
|
|
43696
|
+
const child = spawn6(process.execPath, args, { detached: true, stdio: "ignore", env: process.env });
|
|
43697
|
+
child.unref();
|
|
43698
|
+
return child.pid;
|
|
43699
|
+
} catch {
|
|
43700
|
+
return;
|
|
43701
|
+
}
|
|
43702
|
+
}
|
|
43703
|
+
async function runDebugWatcher(argv) {
|
|
43704
|
+
const pidArg = argv[argv.indexOf("--pid") + 1];
|
|
43705
|
+
const dirArg = argv[argv.indexOf("--dir") + 1];
|
|
43706
|
+
const pid = Number(pidArg);
|
|
43707
|
+
if (!Number.isInteger(pid) || pid <= 0 || dirArg === undefined || !argv.includes("--dir")) {
|
|
43708
|
+
process.stderr.write(`usage: keryx shell --debug-watcher --pid <pid> --dir <debug run dir>
|
|
43709
|
+
`);
|
|
43710
|
+
process.exitCode = 2;
|
|
43711
|
+
return;
|
|
43712
|
+
}
|
|
43713
|
+
const logFile = path195.join(dirArg, "watcher.ndjson");
|
|
43714
|
+
const shellLog = path195.join(dirArg, "shell.ndjson");
|
|
43715
|
+
const log = (kind, data = {}) => {
|
|
43716
|
+
try {
|
|
43717
|
+
appendOwnerOnlyLine(logFile, JSON.stringify({ ts: new Date().toISOString(), watcher: process.pid, target: pid, kind, ...data }));
|
|
43718
|
+
} catch {}
|
|
43719
|
+
};
|
|
43720
|
+
const linux = process.platform === "linux" && isAlive(pid) && readText(`/proc/${pid}/stat`) !== undefined;
|
|
43721
|
+
const pendingOf = await makePendingReader();
|
|
43722
|
+
let ttyPath;
|
|
43723
|
+
let ttyFd;
|
|
43724
|
+
if (linux) {
|
|
43725
|
+
try {
|
|
43726
|
+
ttyPath = readlinkSync(`/proc/${pid}/fd/0`);
|
|
43727
|
+
if (isTtyLink(ttyPath)) {
|
|
43728
|
+
ttyFd = openSync3(ttyPath, constants2.O_RDONLY | constants2.O_NONBLOCK | constants2.O_NOCTTY);
|
|
43729
|
+
}
|
|
43730
|
+
} catch (error) {
|
|
43731
|
+
log("tty.open-failed", { error: String(error) });
|
|
43732
|
+
}
|
|
43733
|
+
}
|
|
43734
|
+
log("watcher.start", { linux, ttyPath, fionread: ttyFd !== undefined && pendingOf(ttyFd) !== undefined });
|
|
43735
|
+
const history = [];
|
|
43736
|
+
let lastLogged = "";
|
|
43737
|
+
let lastPeriodic = 0;
|
|
43738
|
+
let lastSignal = 0;
|
|
43739
|
+
const fullSnapshot = () => {
|
|
43740
|
+
const fds = listFds(pid);
|
|
43741
|
+
let stty;
|
|
43742
|
+
if (ttyPath !== undefined) {
|
|
43743
|
+
const res = spawnSync3("stty", ["-a", "-F", ttyPath], { encoding: "utf8", timeout: 2000 });
|
|
43744
|
+
stty = (res.stdout ?? "").trim() || (res.stderr ?? "").trim();
|
|
43745
|
+
}
|
|
43746
|
+
return {
|
|
43747
|
+
stat: (readText(`/proc/${pid}/stat`) ?? "").trim(),
|
|
43748
|
+
status: (readText(`/proc/${pid}/status`) ?? "").split(`
|
|
43749
|
+
`).filter((l) => /^(State|Threads|SigBlk|SigIgn|SigCgt|VmRSS):/.test(l)),
|
|
43750
|
+
fds,
|
|
43751
|
+
epoll: epollEntries(pid, fds),
|
|
43752
|
+
threads: threads(pid),
|
|
43753
|
+
stty
|
|
43754
|
+
};
|
|
43755
|
+
};
|
|
43756
|
+
const tick = () => {
|
|
43757
|
+
const alive = isAlive(pid);
|
|
43758
|
+
const sample = { alive };
|
|
43759
|
+
if (alive && linux) {
|
|
43760
|
+
const fds = listFds(pid);
|
|
43761
|
+
const ttyFds = fds.filter((f) => isTtyLink(f.link)).map((f) => f.fd);
|
|
43762
|
+
const entries = epollEntries(pid, fds).flatMap((e) => e.entries);
|
|
43763
|
+
sample.readerArmed = ttyReaderArmed(ttyFds, entries);
|
|
43764
|
+
}
|
|
43765
|
+
if (alive && ttyFd !== undefined) {
|
|
43766
|
+
sample.pending = pendingOf(ttyFd);
|
|
43767
|
+
}
|
|
43768
|
+
try {
|
|
43769
|
+
sample.heartbeatAgeMs = Date.now() - statSync6(shellLog).mtimeMs;
|
|
43770
|
+
} catch {
|
|
43771
|
+
sample.heartbeatAgeMs = undefined;
|
|
43772
|
+
}
|
|
43773
|
+
history.push(sample);
|
|
43774
|
+
if (history.length > 30)
|
|
43775
|
+
history.shift();
|
|
43776
|
+
if (!alive) {
|
|
43777
|
+
log("target.exit");
|
|
43778
|
+
return false;
|
|
43779
|
+
}
|
|
43780
|
+
const key = JSON.stringify({ a: sample.readerArmed, p: (sample.pending ?? 0) > 0 });
|
|
43781
|
+
const now = Date.now();
|
|
43782
|
+
if (key !== lastLogged || now - lastPeriodic > 1e4) {
|
|
43783
|
+
log("sample", { ...sample });
|
|
43784
|
+
lastLogged = key;
|
|
43785
|
+
lastPeriodic = now;
|
|
43786
|
+
}
|
|
43787
|
+
const stall = detectStall(history);
|
|
43788
|
+
if (stall !== undefined && now - lastSignal > 15000) {
|
|
43789
|
+
lastSignal = now;
|
|
43790
|
+
log("stall.detected", { reason: stall, recent: history.slice(-5), snapshot: linux ? fullSnapshot() : {} });
|
|
43791
|
+
if (stall !== "event-loop-silent" && process.platform !== "win32") {
|
|
43792
|
+
try {
|
|
43793
|
+
process.kill(pid, "SIGUSR2");
|
|
43794
|
+
log("recover.signal-sent", { signal: "SIGUSR2" });
|
|
43795
|
+
} catch (error) {
|
|
43796
|
+
log("recover.signal-failed", { error: String(error) });
|
|
43797
|
+
}
|
|
43798
|
+
setTimeout(() => {
|
|
43799
|
+
log("recover.after", { snapshot: linux ? fullSnapshot() : {}, pending: ttyFd !== undefined ? pendingOf(ttyFd) : undefined });
|
|
43800
|
+
}, 2000);
|
|
43801
|
+
}
|
|
43802
|
+
}
|
|
43803
|
+
return true;
|
|
43804
|
+
};
|
|
43805
|
+
await new Promise((resolve) => {
|
|
43806
|
+
const timer = setInterval(() => {
|
|
43807
|
+
if (!tick()) {
|
|
43808
|
+
clearInterval(timer);
|
|
43809
|
+
resolve();
|
|
43810
|
+
}
|
|
43811
|
+
}, 1000);
|
|
43812
|
+
});
|
|
43813
|
+
if (ttyFd !== undefined) {
|
|
43814
|
+
try {
|
|
43815
|
+
closeSync3(ttyFd);
|
|
43816
|
+
} catch {}
|
|
43817
|
+
}
|
|
43818
|
+
log("watcher.stop");
|
|
43819
|
+
}
|
|
43820
|
+
var EPOLLIN = 1, FIONREAD = 21531, isTtyLink = (link) => link.startsWith("/dev/pts/") || /^\/dev\/tty/.test(link);
|
|
43821
|
+
var init_debug_watcher = __esm(() => {
|
|
43822
|
+
init_config_dir();
|
|
43823
|
+
});
|
|
43824
|
+
|
|
43475
43825
|
// src/cli.ts
|
|
43476
43826
|
init_single_turn();
|
|
43477
43827
|
init_model_turn_port();
|
|
@@ -50274,7 +50624,7 @@ import path47 from "path";
|
|
|
50274
50624
|
// package.json
|
|
50275
50625
|
var package_default = {
|
|
50276
50626
|
name: "@mrciphersmith/keryx",
|
|
50277
|
-
version: "0.2.
|
|
50627
|
+
version: "0.2.122",
|
|
50278
50628
|
description: "Version-controlled project context for AI coding agents: code graph, architecture wiki, project memory, relevant tests, quality signals, and task flows.",
|
|
50279
50629
|
private: false,
|
|
50280
50630
|
publishConfig: {
|
|
@@ -90550,6 +90900,9 @@ function classifyBusyDispatch(params) {
|
|
|
90550
90900
|
return "not-a-command";
|
|
90551
90901
|
}
|
|
90552
90902
|
|
|
90903
|
+
// src/tui/tui-shell.ts
|
|
90904
|
+
init_debug_log();
|
|
90905
|
+
|
|
90553
90906
|
// src/tui/boot-animation.ts
|
|
90554
90907
|
var DEFAULT_BOOT_DURATION_MS = 350;
|
|
90555
90908
|
var WORDMARK = ["========================", " K E R Y X ", "========================"];
|
|
@@ -94050,10 +94403,10 @@ function describeElicitationPrompt(tool, inputJson) {
|
|
|
94050
94403
|
// src/lib/permission-mode-config.ts
|
|
94051
94404
|
init_permission_mode();
|
|
94052
94405
|
init_config_dir();
|
|
94053
|
-
import
|
|
94406
|
+
import path193 from "path";
|
|
94054
94407
|
var EMPTY3 = { schemaVersion: 1, projects: {} };
|
|
94055
94408
|
function permissionModeConfigPath(dir) {
|
|
94056
|
-
return
|
|
94409
|
+
return path193.join(keryxConfigDir(dir), "permission-mode.json");
|
|
94057
94410
|
}
|
|
94058
94411
|
function withRegistryLock2(dir, fn) {
|
|
94059
94412
|
return withFileLock2(`${permissionModeConfigPath(dir)}.lock`, fn, {
|
|
@@ -94297,6 +94650,7 @@ function createForegroundAgentIoFacade(owner, token, io) {
|
|
|
94297
94650
|
}
|
|
94298
94651
|
|
|
94299
94652
|
// src/tui/herdr-report.ts
|
|
94653
|
+
init_debug_log();
|
|
94300
94654
|
import net from "net";
|
|
94301
94655
|
var SOURCE = "herdr:keryx";
|
|
94302
94656
|
var AGENT = "keryx";
|
|
@@ -94336,6 +94690,7 @@ function createHerdrReporter(clock = () => Date.now(), connect = writeOnce) {
|
|
|
94336
94690
|
if (state === last)
|
|
94337
94691
|
return;
|
|
94338
94692
|
last = state;
|
|
94693
|
+
debugEvent("herdr.report", { state });
|
|
94339
94694
|
send("pane.report_agent", { state });
|
|
94340
94695
|
},
|
|
94341
94696
|
release() {
|
|
@@ -94371,6 +94726,14 @@ function writeOnce(socketPath, request) {
|
|
|
94371
94726
|
}
|
|
94372
94727
|
|
|
94373
94728
|
// src/tui/composer-choice.ts
|
|
94729
|
+
init_debug_log();
|
|
94730
|
+
var DEFAULT_ACCEPT_DELAY_MS = 400;
|
|
94731
|
+
function resolveAcceptDelay(request) {
|
|
94732
|
+
if (request.acceptDelayMs !== undefined) {
|
|
94733
|
+
return Math.max(0, request.acceptDelayMs);
|
|
94734
|
+
}
|
|
94735
|
+
return DEFAULT_ACCEPT_DELAY_MS;
|
|
94736
|
+
}
|
|
94374
94737
|
var MAX_SUBTITLE_CHARS = 8000;
|
|
94375
94738
|
var MAX_SUBTITLE_ROWS = 10;
|
|
94376
94739
|
var SUBTITLE_INLINE_MAX_CHARS = 76;
|
|
@@ -94408,12 +94771,17 @@ function lockDock(dock) {
|
|
|
94408
94771
|
async function showComposerChoice(otui, r, dock, request) {
|
|
94409
94772
|
const enqueue = request.enqueue !== false;
|
|
94410
94773
|
if (!enqueue && dockBusy(dock)) {
|
|
94774
|
+
debugEvent("choice.busy-cancel", { title: request.title });
|
|
94411
94775
|
request.onBusy?.();
|
|
94412
94776
|
return request.cancelId;
|
|
94413
94777
|
}
|
|
94778
|
+
const queuedAt = Date.now();
|
|
94779
|
+
debugEvent("choice.request", { title: request.title, waitingBehind: dockDepth.get(dock) ?? 0 });
|
|
94414
94780
|
const unlock = await lockDock(dock);
|
|
94781
|
+
debugEvent("choice.lock-acquired", { title: request.title, waitedMs: Date.now() - queuedAt });
|
|
94415
94782
|
try {
|
|
94416
94783
|
if (request.signal?.aborted === true) {
|
|
94784
|
+
debugEvent("choice.aborted-before-open", { title: request.title });
|
|
94417
94785
|
return request.cancelId;
|
|
94418
94786
|
}
|
|
94419
94787
|
return await presentComposerChoice(otui, r, dock, request);
|
|
@@ -94423,6 +94791,7 @@ async function showComposerChoice(otui, r, dock, request) {
|
|
|
94423
94791
|
}
|
|
94424
94792
|
function presentComposerChoice(otui, r, dock, request) {
|
|
94425
94793
|
if (dock.visible === true) {
|
|
94794
|
+
debugEvent("choice.dock-already-visible", { title: request.title });
|
|
94426
94795
|
request.onBusy?.();
|
|
94427
94796
|
return Promise.resolve(request.cancelId);
|
|
94428
94797
|
}
|
|
@@ -94434,6 +94803,9 @@ function presentComposerChoice(otui, r, dock, request) {
|
|
|
94434
94803
|
const recommendedIdx = options.findIndex((o) => o.recommended === true);
|
|
94435
94804
|
let selected = recommendedIdx >= 0 ? recommendedIdx : 0;
|
|
94436
94805
|
dock.visible = true;
|
|
94806
|
+
const openedAt = Date.now();
|
|
94807
|
+
const acceptDelayMs = resolveAcceptDelay(request);
|
|
94808
|
+
let lastTypedAt = 0;
|
|
94437
94809
|
request.onOpen?.();
|
|
94438
94810
|
const theme = getTheme();
|
|
94439
94811
|
const rawSubtitle = request.subtitle !== undefined && request.subtitle.length > 0 ? request.subtitle : undefined;
|
|
@@ -94501,13 +94873,14 @@ function presentComposerChoice(otui, r, dock, request) {
|
|
|
94501
94873
|
};
|
|
94502
94874
|
let settled = false;
|
|
94503
94875
|
const onAbort = () => {
|
|
94504
|
-
finish(request.cancelId);
|
|
94876
|
+
finish(request.cancelId, "abort");
|
|
94505
94877
|
};
|
|
94506
|
-
const finish = (id) => {
|
|
94878
|
+
const finish = (id, via = "key") => {
|
|
94507
94879
|
if (settled) {
|
|
94508
94880
|
return;
|
|
94509
94881
|
}
|
|
94510
94882
|
settled = true;
|
|
94883
|
+
debugEvent("choice.finish", { title: request.title, id, via, openMs: Date.now() - openedAt });
|
|
94511
94884
|
cleanup();
|
|
94512
94885
|
resolve(id);
|
|
94513
94886
|
};
|
|
@@ -94518,7 +94891,7 @@ function presentComposerChoice(otui, r, dock, request) {
|
|
|
94518
94891
|
width: "100%",
|
|
94519
94892
|
flexDirection: "column",
|
|
94520
94893
|
onMouseDown: () => {
|
|
94521
|
-
finish(o.id);
|
|
94894
|
+
finish(o.id, "click");
|
|
94522
94895
|
}
|
|
94523
94896
|
});
|
|
94524
94897
|
const label = new otui.TextRenderable(r, { id: `ch-opt-l-${i}-${Date.now()}`, content: o.displayLabel });
|
|
@@ -94576,8 +94949,11 @@ function presentComposerChoice(otui, r, dock, request) {
|
|
|
94576
94949
|
dock.visible = false;
|
|
94577
94950
|
}
|
|
94578
94951
|
const onKey = (key) => {
|
|
94952
|
+
if (!key.ctrl && typeof key.sequence === "string" && key.sequence.length === 1 && key.sequence >= " ") {
|
|
94953
|
+
lastTypedAt = Date.now();
|
|
94954
|
+
}
|
|
94579
94955
|
if (key.name === "escape") {
|
|
94580
|
-
finish(request.cancelId);
|
|
94956
|
+
finish(request.cancelId, "escape");
|
|
94581
94957
|
key.preventDefault();
|
|
94582
94958
|
key.stopPropagation();
|
|
94583
94959
|
return;
|
|
@@ -94614,6 +94990,17 @@ function presentComposerChoice(otui, r, dock, request) {
|
|
|
94614
94990
|
return;
|
|
94615
94991
|
}
|
|
94616
94992
|
if (key.name === "return" || key.name === "linefeed" || key.name === "kpenter") {
|
|
94993
|
+
const now = Date.now();
|
|
94994
|
+
if (now - openedAt < acceptDelayMs || now - lastTypedAt < acceptDelayMs) {
|
|
94995
|
+
debugEvent("choice.enter-ignored", {
|
|
94996
|
+
title: request.title,
|
|
94997
|
+
sinceOpenMs: now - openedAt,
|
|
94998
|
+
sinceTypingMs: lastTypedAt === 0 ? undefined : now - lastTypedAt
|
|
94999
|
+
});
|
|
95000
|
+
key.preventDefault();
|
|
95001
|
+
key.stopPropagation();
|
|
95002
|
+
return;
|
|
95003
|
+
}
|
|
94617
95004
|
const chosen = options[selected];
|
|
94618
95005
|
if (chosen !== undefined) {
|
|
94619
95006
|
finish(chosen.id);
|
|
@@ -94627,13 +95014,20 @@ function presentComposerChoice(otui, r, dock, request) {
|
|
|
94627
95014
|
request.signal.addEventListener("abort", onAbort, { once: true });
|
|
94628
95015
|
}
|
|
94629
95016
|
optionsScroll.focus();
|
|
95017
|
+
debugEvent("choice.open", {
|
|
95018
|
+
title: request.title,
|
|
95019
|
+
options: options.map((o) => o.id),
|
|
95020
|
+
selected: options[selected]?.id,
|
|
95021
|
+
scrollableSubtitle: hasScrollableSubtitle,
|
|
95022
|
+
acceptDelayMs
|
|
95023
|
+
});
|
|
94630
95024
|
});
|
|
94631
95025
|
}
|
|
94632
95026
|
|
|
94633
95027
|
// src/lib/version-check.ts
|
|
94634
95028
|
init_config_dir();
|
|
94635
95029
|
init_fs();
|
|
94636
|
-
import
|
|
95030
|
+
import path194 from "path";
|
|
94637
95031
|
var REGISTRY_URL = "https://registry.npmjs.org/@mrciphersmith%2Fkeryx/latest";
|
|
94638
95032
|
var FIXED_INSTALL_COMMAND = "npm install -g @mrciphersmith/keryx@latest";
|
|
94639
95033
|
var RESPONSE_BODY_LIMIT_BYTES = 64 * 1024;
|
|
@@ -94835,7 +95229,7 @@ async function checkVersion(options) {
|
|
|
94835
95229
|
const now = options.now ?? Date.now;
|
|
94836
95230
|
const timestamp = now();
|
|
94837
95231
|
const configDir = ensureKeryxConfigDir(options.cacheDir);
|
|
94838
|
-
const cacheFile =
|
|
95232
|
+
const cacheFile = path194.join(configDir, "version-check.json");
|
|
94839
95233
|
const cache = parseCache(cacheFile);
|
|
94840
95234
|
if (cache?.latestVersion !== undefined && cache.successAt !== undefined && timestamp - cache.successAt >= 0 && timestamp - cache.successAt < SUCCESS_CACHE_TTL_MS) {
|
|
94841
95235
|
return resultFor(options.currentVersion, current, cache.latestVersion, "cache");
|
|
@@ -94903,6 +95297,236 @@ async function checkVersion(options) {
|
|
|
94903
95297
|
return resultFor(options.currentVersion, current, latestVersion, "registry");
|
|
94904
95298
|
}
|
|
94905
95299
|
|
|
95300
|
+
// src/tui/shell-chrome.ts
|
|
95301
|
+
init_debug_log();
|
|
95302
|
+
|
|
95303
|
+
// src/tui/renderer-debug.ts
|
|
95304
|
+
init_debug_log();
|
|
95305
|
+
|
|
95306
|
+
// src/tui/stdin-guard.ts
|
|
95307
|
+
init_debug_log();
|
|
95308
|
+
var rendererListener;
|
|
95309
|
+
function stdinSnapshot(stdin) {
|
|
95310
|
+
const safe = (read) => {
|
|
95311
|
+
try {
|
|
95312
|
+
return read();
|
|
95313
|
+
} catch (error) {
|
|
95314
|
+
return `error: ${error instanceof Error ? error.message : String(error)}`;
|
|
95315
|
+
}
|
|
95316
|
+
};
|
|
95317
|
+
return {
|
|
95318
|
+
isTTY: safe(() => stdin.isTTY === true),
|
|
95319
|
+
isRaw: safe(() => stdin.isRaw),
|
|
95320
|
+
paused: safe(() => stdin.isPaused()),
|
|
95321
|
+
flowing: safe(() => stdin.readableFlowing),
|
|
95322
|
+
ended: safe(() => stdin.readableEnded),
|
|
95323
|
+
destroyed: safe(() => stdin.destroyed),
|
|
95324
|
+
buffered: safe(() => stdin.readableLength),
|
|
95325
|
+
dataListeners: safe(() => stdin.listenerCount("data")),
|
|
95326
|
+
readableListeners: safe(() => stdin.listenerCount("readable")),
|
|
95327
|
+
rendererAttached: safe(() => rendererListener === undefined ? undefined : stdin.listeners("data").includes(rendererListener))
|
|
95328
|
+
};
|
|
95329
|
+
}
|
|
95330
|
+
function stdinLooksStalled(snapshot) {
|
|
95331
|
+
return snapshot.paused === true || snapshot.flowing === false || snapshot.ended === true || snapshot.destroyed === true || snapshot.dataListeners === 0 || snapshot.rendererAttached === false || snapshot.isTTY === true && snapshot.isRaw === false;
|
|
95332
|
+
}
|
|
95333
|
+
function registerRendererInputListener(listener) {
|
|
95334
|
+
rendererListener = listener;
|
|
95335
|
+
}
|
|
95336
|
+
function recoverStdin(stdin, opts = {}) {
|
|
95337
|
+
const actions = [];
|
|
95338
|
+
const listener = opts.listener ?? rendererListener;
|
|
95339
|
+
const step = (name, run) => {
|
|
95340
|
+
try {
|
|
95341
|
+
run();
|
|
95342
|
+
actions.push(name);
|
|
95343
|
+
} catch (error) {
|
|
95344
|
+
actions.push(`${name} failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
95345
|
+
}
|
|
95346
|
+
};
|
|
95347
|
+
if (stdin.isTTY === true && typeof stdin.setRawMode === "function" && stdin.isRaw !== true) {
|
|
95348
|
+
step("setRawMode(true)", () => stdin.setRawMode?.(true));
|
|
95349
|
+
}
|
|
95350
|
+
if (listener !== undefined && !stdin.listeners("data").includes(listener)) {
|
|
95351
|
+
step("re-attach renderer data listener", () => stdin.on("data", listener));
|
|
95352
|
+
}
|
|
95353
|
+
if (opts.cycle === true) {
|
|
95354
|
+
step("pause()", () => stdin.pause());
|
|
95355
|
+
}
|
|
95356
|
+
step("resume()", () => stdin.resume());
|
|
95357
|
+
return actions;
|
|
95358
|
+
}
|
|
95359
|
+
function instrumentStdin(stdin) {
|
|
95360
|
+
const target = stdin;
|
|
95361
|
+
const restores = [];
|
|
95362
|
+
const wrap = (method, describe = () => ({})) => {
|
|
95363
|
+
const original = target[method];
|
|
95364
|
+
if (typeof original !== "function") {
|
|
95365
|
+
return;
|
|
95366
|
+
}
|
|
95367
|
+
const fn = original;
|
|
95368
|
+
target[method] = function(...args) {
|
|
95369
|
+
debugEvent(`stdin.${method}`, { ...describe(args), before: stdinSnapshot(stdin), stack: callerStack() });
|
|
95370
|
+
return fn.apply(this, args);
|
|
95371
|
+
};
|
|
95372
|
+
restores.push(() => {
|
|
95373
|
+
target[method] = original;
|
|
95374
|
+
});
|
|
95375
|
+
};
|
|
95376
|
+
const eventName = (args) => ({ event: String(args[0]) });
|
|
95377
|
+
wrap("pause");
|
|
95378
|
+
wrap("resume");
|
|
95379
|
+
wrap("setRawMode", (args) => ({ mode: args[0] }));
|
|
95380
|
+
wrap("removeListener", eventName);
|
|
95381
|
+
wrap("off", eventName);
|
|
95382
|
+
wrap("removeAllListeners", eventName);
|
|
95383
|
+
wrap("destroy");
|
|
95384
|
+
wrap("unref");
|
|
95385
|
+
wrap("unpipe");
|
|
95386
|
+
wrap("setEncoding", (args) => ({ encoding: args[0] }));
|
|
95387
|
+
const lifecycle = [];
|
|
95388
|
+
for (const event of ["end", "close", "error", "pause", "resume"]) {
|
|
95389
|
+
const handler = (...args) => {
|
|
95390
|
+
debugEvent(`stdin.event.${event}`, { args: args.map((a) => a instanceof Error ? a : String(a)), state: stdinSnapshot(stdin) });
|
|
95391
|
+
};
|
|
95392
|
+
lifecycle.push([event, handler]);
|
|
95393
|
+
}
|
|
95394
|
+
const onData = (chunk) => {
|
|
95395
|
+
debugEvent("stdin.data", summarizeInputChunk(chunk));
|
|
95396
|
+
};
|
|
95397
|
+
lifecycle.push(["data", onData]);
|
|
95398
|
+
for (const [event, handler] of lifecycle) {
|
|
95399
|
+
if (event === "error" && stdin.listenerCount("error") === 0) {
|
|
95400
|
+
continue;
|
|
95401
|
+
}
|
|
95402
|
+
stdin.on(event, handler);
|
|
95403
|
+
}
|
|
95404
|
+
debugEvent("stdin.instrumented", { state: stdinSnapshot(stdin) });
|
|
95405
|
+
return () => {
|
|
95406
|
+
for (const restore of restores)
|
|
95407
|
+
restore();
|
|
95408
|
+
for (const [event, handler] of lifecycle)
|
|
95409
|
+
stdin.off?.(event, handler);
|
|
95410
|
+
};
|
|
95411
|
+
}
|
|
95412
|
+
function startStdinHeartbeat(stdin, opts = {}) {
|
|
95413
|
+
const intervalMs = opts.intervalMs ?? 1000;
|
|
95414
|
+
const cooldownMs = opts.cooldownMs ?? 1e4;
|
|
95415
|
+
let lastRecovery = 0;
|
|
95416
|
+
const timer = setInterval(() => {
|
|
95417
|
+
const state = stdinSnapshot(stdin);
|
|
95418
|
+
const stalled = stdinLooksStalled(state);
|
|
95419
|
+
debugEvent("heartbeat", { stdin: state, stalled, ...opts.extra?.() ?? {} });
|
|
95420
|
+
if (stalled && (opts.shouldRecover?.() ?? true) && Date.now() - lastRecovery > cooldownMs) {
|
|
95421
|
+
lastRecovery = Date.now();
|
|
95422
|
+
const actions = recoverStdin(stdin, { cycle: true });
|
|
95423
|
+
debugEvent("stdin.stall.recovered-in-process", { before: state, actions, after: stdinSnapshot(stdin) });
|
|
95424
|
+
}
|
|
95425
|
+
}, intervalMs);
|
|
95426
|
+
timer.unref?.();
|
|
95427
|
+
return () => clearInterval(timer);
|
|
95428
|
+
}
|
|
95429
|
+
function installInputRecoverySignal(stdin, onRecovered, shouldRecover = () => true) {
|
|
95430
|
+
if (process.platform === "win32") {
|
|
95431
|
+
return () => {};
|
|
95432
|
+
}
|
|
95433
|
+
const handler = () => {
|
|
95434
|
+
if (!shouldRecover()) {
|
|
95435
|
+
debugEvent("signal.SIGUSR2.skipped", { reason: "renderer suspended or destroyed", stdin: stdinSnapshot(stdin) });
|
|
95436
|
+
return;
|
|
95437
|
+
}
|
|
95438
|
+
const before = stdinSnapshot(stdin);
|
|
95439
|
+
const actions = recoverStdin(stdin, { cycle: true });
|
|
95440
|
+
const after = stdinSnapshot(stdin);
|
|
95441
|
+
debugEvent("signal.SIGUSR2.recover", { before, actions, after, debug: isDebugEnabled() });
|
|
95442
|
+
try {
|
|
95443
|
+
onRecovered?.(actions);
|
|
95444
|
+
} catch {}
|
|
95445
|
+
};
|
|
95446
|
+
process.on("SIGUSR2", handler);
|
|
95447
|
+
return () => {
|
|
95448
|
+
process.off("SIGUSR2", handler);
|
|
95449
|
+
};
|
|
95450
|
+
}
|
|
95451
|
+
|
|
95452
|
+
// src/tui/renderer-debug.ts
|
|
95453
|
+
function attachRendererGuards(r, stdin = process.stdin) {
|
|
95454
|
+
const internals = r;
|
|
95455
|
+
registerRendererInputListener(internals.stdinListener);
|
|
95456
|
+
const shouldRecover = () => !r.isDestroyed && internals.controlState !== "explicit_suspended";
|
|
95457
|
+
const teardown = [];
|
|
95458
|
+
teardown.push(installInputRecoverySignal(stdin, () => {
|
|
95459
|
+
r.requestRender();
|
|
95460
|
+
}, shouldRecover));
|
|
95461
|
+
teardown.push(() => registerRendererInputListener(undefined));
|
|
95462
|
+
if (!isDebugEnabled()) {
|
|
95463
|
+
return () => {
|
|
95464
|
+
for (const fn of teardown.splice(0))
|
|
95465
|
+
fn();
|
|
95466
|
+
};
|
|
95467
|
+
}
|
|
95468
|
+
debugEvent("renderer.created", {
|
|
95469
|
+
controlState: internals.controlState,
|
|
95470
|
+
width: r.width,
|
|
95471
|
+
height: r.height,
|
|
95472
|
+
hasStdinListener: internals.stdinListener !== undefined
|
|
95473
|
+
});
|
|
95474
|
+
teardown.push(instrumentStdin(stdin));
|
|
95475
|
+
teardown.push(startStdinHeartbeat(stdin, {
|
|
95476
|
+
shouldRecover,
|
|
95477
|
+
extra: () => ({
|
|
95478
|
+
controlState: internals.controlState,
|
|
95479
|
+
focused: internals.currentFocusedRenderable?.id
|
|
95480
|
+
})
|
|
95481
|
+
}));
|
|
95482
|
+
const onKey = (key) => {
|
|
95483
|
+
const printable = key.sequence.length === 1 && key.sequence >= " " && !key.ctrl && !key.meta;
|
|
95484
|
+
queueMicrotask(() => {
|
|
95485
|
+
debugEvent("key", {
|
|
95486
|
+
name: printable ? "<printable>" : key.name,
|
|
95487
|
+
ctrl: key.ctrl,
|
|
95488
|
+
meta: key.meta,
|
|
95489
|
+
shift: key.shift,
|
|
95490
|
+
prevented: key.defaultPrevented,
|
|
95491
|
+
stopped: key.propagationStopped,
|
|
95492
|
+
focused: internals.currentFocusedRenderable?.id
|
|
95493
|
+
});
|
|
95494
|
+
});
|
|
95495
|
+
};
|
|
95496
|
+
internals._internalKeyInput?.onInternal("keypress", onKey);
|
|
95497
|
+
teardown.push(() => internals._internalKeyInput?.offInternal("keypress", onKey));
|
|
95498
|
+
const emitter = r;
|
|
95499
|
+
for (const event of ["resize", "focus", "blur", "capabilities"]) {
|
|
95500
|
+
const fn = (...args) => {
|
|
95501
|
+
debugEvent(`renderer.${event}`, event === "capabilities" ? {} : { args: args.map(String) });
|
|
95502
|
+
};
|
|
95503
|
+
emitter.on?.(event, fn);
|
|
95504
|
+
teardown.push(() => emitter.off?.(event, fn));
|
|
95505
|
+
}
|
|
95506
|
+
const target = r;
|
|
95507
|
+
for (const method of ["suspend", "resume", "pause", "stop", "destroy"]) {
|
|
95508
|
+
const original = target[method];
|
|
95509
|
+
if (typeof original !== "function")
|
|
95510
|
+
continue;
|
|
95511
|
+
const fn = original;
|
|
95512
|
+
target[method] = function(...args) {
|
|
95513
|
+
debugEvent(`renderer.${method}`, { controlState: internals.controlState, stack: callerStack() });
|
|
95514
|
+
return fn.apply(this, args);
|
|
95515
|
+
};
|
|
95516
|
+
teardown.push(() => {
|
|
95517
|
+
target[method] = original;
|
|
95518
|
+
});
|
|
95519
|
+
}
|
|
95520
|
+
return () => {
|
|
95521
|
+
debugEvent("renderer.teardown");
|
|
95522
|
+
for (const fn of teardown.splice(0)) {
|
|
95523
|
+
try {
|
|
95524
|
+
fn();
|
|
95525
|
+
} catch {}
|
|
95526
|
+
}
|
|
95527
|
+
};
|
|
95528
|
+
}
|
|
95529
|
+
|
|
94906
95530
|
// src/tui/shell-chrome.ts
|
|
94907
95531
|
function onKeypress3(r, handler) {
|
|
94908
95532
|
r._internalKeyInput.onInternal("keypress", handler);
|
|
@@ -95008,14 +95632,20 @@ function prefixFilter(commands, query) {
|
|
|
95008
95632
|
return commands.filter((c) => c.name.slice(1).toLowerCase().startsWith(needle));
|
|
95009
95633
|
}
|
|
95010
95634
|
async function createShellRenderer(otui, opts = {}) {
|
|
95011
|
-
|
|
95635
|
+
const guards = {};
|
|
95636
|
+
const renderer = await otui.createCliRenderer({
|
|
95012
95637
|
exitOnCtrlC: true,
|
|
95013
95638
|
screenMode: "alternate-screen",
|
|
95014
95639
|
clearOnShutdown: true,
|
|
95015
95640
|
useMouse: true,
|
|
95016
95641
|
backgroundColor: getTheme().bg,
|
|
95017
|
-
|
|
95642
|
+
onDestroy: () => {
|
|
95643
|
+
guards.detach?.();
|
|
95644
|
+
opts.onDestroy?.();
|
|
95645
|
+
}
|
|
95018
95646
|
});
|
|
95647
|
+
guards.detach = attachRendererGuards(renderer);
|
|
95648
|
+
return renderer;
|
|
95019
95649
|
}
|
|
95020
95650
|
async function createShellChrome(otui, renderer, opts) {
|
|
95021
95651
|
const r = renderer;
|
|
@@ -95178,10 +95808,12 @@ async function createShellChrome(otui, renderer, opts) {
|
|
|
95178
95808
|
};
|
|
95179
95809
|
const withOverlay = async (run) => {
|
|
95180
95810
|
overlayDepth += 1;
|
|
95811
|
+
debugEvent("overlay.enter", { depth: overlayDepth, dockVisible: dock.visible });
|
|
95181
95812
|
try {
|
|
95182
95813
|
return await run();
|
|
95183
95814
|
} finally {
|
|
95184
95815
|
overlayDepth -= 1;
|
|
95816
|
+
debugEvent("overlay.exit", { depth: overlayDepth, dockVisible: dock.visible });
|
|
95185
95817
|
}
|
|
95186
95818
|
};
|
|
95187
95819
|
const addOverlaySource = (isActive) => {
|
|
@@ -95430,9 +96062,11 @@ async function createShellChrome(otui, renderer, opts) {
|
|
|
95430
96062
|
});
|
|
95431
96063
|
textarea.onSubmit = () => {
|
|
95432
96064
|
if (overlayActive()) {
|
|
96065
|
+
debugEvent("composer.submit-blocked", { reason: "overlay active", dockVisible: dock.visible, overlayDepth });
|
|
95433
96066
|
return;
|
|
95434
96067
|
}
|
|
95435
96068
|
const line = input.value.trim();
|
|
96069
|
+
debugEvent("composer.submit", { chars: line.length, slash: line.startsWith("/") });
|
|
95436
96070
|
input.value = "";
|
|
95437
96071
|
hideMenu();
|
|
95438
96072
|
syncComposerHeight();
|
|
@@ -95550,6 +96184,15 @@ async function createShellChrome(otui, renderer, opts) {
|
|
|
95550
96184
|
appliedTheme = theme;
|
|
95551
96185
|
};
|
|
95552
96186
|
const unsubTheme = onThemeChange((theme) => applyTheme(theme));
|
|
96187
|
+
{
|
|
96188
|
+
const run = currentDebugRun();
|
|
96189
|
+
if (run !== undefined) {
|
|
96190
|
+
setTimeout(() => {
|
|
96191
|
+
if (alive)
|
|
96192
|
+
showToast(`debug log: ${run.dir}`);
|
|
96193
|
+
}, 0);
|
|
96194
|
+
}
|
|
96195
|
+
}
|
|
95553
96196
|
return {
|
|
95554
96197
|
renderer: r,
|
|
95555
96198
|
root: rootRow,
|
|
@@ -98114,6 +98757,7 @@ function attachBlockIo(io, addBlock, chrome = {}, thinkDisplay = () => "auto") {
|
|
|
98114
98757
|
});
|
|
98115
98758
|
};
|
|
98116
98759
|
io.onToolCall = (name, input) => {
|
|
98760
|
+
debugEvent("tool.call", { name, inputChars: input.length });
|
|
98117
98761
|
chrome.onToolCall?.(name, input);
|
|
98118
98762
|
const args = summarizeToolArgs(input);
|
|
98119
98763
|
addBlock({
|
|
@@ -98125,6 +98769,7 @@ function attachBlockIo(io, addBlock, chrome = {}, thinkDisplay = () => "auto") {
|
|
|
98125
98769
|
}, { hint: "ctrl+o", tone: "cyan" });
|
|
98126
98770
|
};
|
|
98127
98771
|
io.onToolResult = (name, result) => {
|
|
98772
|
+
debugEvent("tool.result", { name, isError: result.isError === true, outputChars: result.output.length });
|
|
98128
98773
|
chrome.onToolResult?.(name, result);
|
|
98129
98774
|
const { summary, lineCount, hidden } = collapseToolOutput(result.output);
|
|
98130
98775
|
const more = hidden > 0 ? ` \xB7 +${hidden} more` : "";
|
|
@@ -98292,6 +98937,9 @@ async function applyRuntimeSwitchToSlate(params) {
|
|
|
98292
98937
|
params.onHistoryChange?.("tool");
|
|
98293
98938
|
return true;
|
|
98294
98939
|
}
|
|
98940
|
+
function freshSlateSessionRef(sessionDir, cwd) {
|
|
98941
|
+
return { dir: sessionDir, cwd, opened: false };
|
|
98942
|
+
}
|
|
98295
98943
|
function fmtTokens(n) {
|
|
98296
98944
|
return n >= 1000 ? `${(n / 1000).toFixed(1)}K` : String(n);
|
|
98297
98945
|
}
|
|
@@ -99432,6 +100080,7 @@ async function launchTuiAgentShell(opts) {
|
|
|
99432
100080
|
let busyStartedAt = 0;
|
|
99433
100081
|
const setBusyPhase = (phase) => {
|
|
99434
100082
|
busyPhase = phase;
|
|
100083
|
+
debugEvent("busy.phase", { phase });
|
|
99435
100084
|
chrome.setBusyPhase(phase);
|
|
99436
100085
|
};
|
|
99437
100086
|
const startBusy = (phase = "waiting for model") => {
|
|
@@ -99654,6 +100303,7 @@ async function launchTuiAgentShell(opts) {
|
|
|
99654
100303
|
})();
|
|
99655
100304
|
};
|
|
99656
100305
|
const setMainAgent = (status, detail) => {
|
|
100306
|
+
debugEvent("main-agent", { status, detail });
|
|
99657
100307
|
fleet.upsert({
|
|
99658
100308
|
id: MAIN_AGENT_ID,
|
|
99659
100309
|
label: "main",
|
|
@@ -100099,6 +100749,9 @@ async function launchTuiAgentShell(opts) {
|
|
|
100099
100749
|
let nextArchiveIndex = 0;
|
|
100100
100750
|
let sessionPersistTimer;
|
|
100101
100751
|
let slateSession;
|
|
100752
|
+
const bindSlateToLiveSession = () => {
|
|
100753
|
+
slateSession = freshSlateSessionRef(liveSession.dir, sessionCwd);
|
|
100754
|
+
};
|
|
100102
100755
|
const onContextCompaction = (r) => {
|
|
100103
100756
|
const persisted = persistCompacted(liveSession, r.context, archive, {
|
|
100104
100757
|
provider: currentSel.provider,
|
|
@@ -100232,7 +100885,7 @@ async function launchTuiAgentShell(opts) {
|
|
|
100232
100885
|
model: currentSel.model
|
|
100233
100886
|
}));
|
|
100234
100887
|
}
|
|
100235
|
-
|
|
100888
|
+
bindSlateToLiveSession();
|
|
100236
100889
|
if (history.length === 0) {
|
|
100237
100890
|
removeSplash = mountEmptyTranscriptSplash(otui, r, transcript);
|
|
100238
100891
|
}
|
|
@@ -100333,6 +100986,8 @@ Staying in the current session.
|
|
|
100333
100986
|
return;
|
|
100334
100987
|
}
|
|
100335
100988
|
applyOpened(opened, true);
|
|
100989
|
+
bindSlateToLiveSession();
|
|
100990
|
+
refreshWorkspaceSidebar();
|
|
100336
100991
|
paintSessionHeader();
|
|
100337
100992
|
if (opened.archiveDegraded !== undefined) {
|
|
100338
100993
|
io.onSystem?.(`Archive unavailable \u2014 resumed from the active context (${opened.archiveDegraded})
|
|
@@ -101231,7 +101886,7 @@ Staying in the current session.
|
|
|
101231
101886
|
(async () => {
|
|
101232
101887
|
await closeSlateSession(slateSession, mintTimestampAttemptId);
|
|
101233
101888
|
startNewSession();
|
|
101234
|
-
|
|
101889
|
+
bindSlateToLiveSession();
|
|
101235
101890
|
refreshWorkspaceSidebar();
|
|
101236
101891
|
refreshReviewSidebar();
|
|
101237
101892
|
sessions.clear();
|
|
@@ -103663,6 +104318,7 @@ function parseShellCliFlags(args) {
|
|
|
103663
104318
|
let printPromptArg;
|
|
103664
104319
|
let eventsFile;
|
|
103665
104320
|
let eventsMaxField;
|
|
104321
|
+
let debug;
|
|
103666
104322
|
for (let i = 0;i < args.length; i++) {
|
|
103667
104323
|
const arg = args[i];
|
|
103668
104324
|
if (arg === "--provider") {
|
|
@@ -103713,6 +104369,8 @@ function parseShellCliFlags(args) {
|
|
|
103713
104369
|
i += 1;
|
|
103714
104370
|
} else if (arg === "--events-file") {
|
|
103715
104371
|
eventsFile = valueAfter(i++);
|
|
104372
|
+
} else if (arg === "--debug") {
|
|
104373
|
+
debug = true;
|
|
103716
104374
|
} else if (arg === "--events-max-field") {
|
|
103717
104375
|
const raw = valueAfter(i++);
|
|
103718
104376
|
const parsed = Number(raw);
|
|
@@ -103742,7 +104400,8 @@ function parseShellCliFlags(args) {
|
|
|
103742
104400
|
...denyTools !== undefined ? { denyTools } : {},
|
|
103743
104401
|
...printPromptArg !== undefined ? { printPrompt: printPromptArg } : {},
|
|
103744
104402
|
...eventsFile !== undefined ? { eventsFile } : {},
|
|
103745
|
-
...eventsMaxField !== undefined ? { eventsMaxField } : {}
|
|
104403
|
+
...eventsMaxField !== undefined ? { eventsMaxField } : {},
|
|
104404
|
+
...debug === true ? { debug: true } : {}
|
|
103746
104405
|
};
|
|
103747
104406
|
}
|
|
103748
104407
|
function chooseShellSurface(flags, isTty) {
|
|
@@ -103755,6 +104414,11 @@ function chooseShellSurface(flags, isTty) {
|
|
|
103755
104414
|
return flags.modeFlag === false ? "tui-chat" : "tui-agent";
|
|
103756
104415
|
}
|
|
103757
104416
|
async function shellCommand(args, runtime = {}) {
|
|
104417
|
+
if (args[0] === "--debug-watcher") {
|
|
104418
|
+
await Promise.resolve().then(() => init_debug_watcher());
|
|
104419
|
+
await runDebugWatcher(args.slice(1));
|
|
104420
|
+
return;
|
|
104421
|
+
}
|
|
103758
104422
|
const flags = parseShellCliFlags(args);
|
|
103759
104423
|
if (flags.help) {
|
|
103760
104424
|
console.log(`Usage: keryx shell [options]
|
|
@@ -103773,13 +104437,42 @@ async function shellCommand(args, runtime = {}) {
|
|
|
103773
104437
|
--print, -p <prompt> Run one agent turn on this prompt and exit
|
|
103774
104438
|
--events-file <path> Append an NDJSON transcript (turns, tools, usage)
|
|
103775
104439
|
--events-max-field <n> Per-field character cap in that transcript (default 4000)
|
|
104440
|
+
--debug Log the session (input, keys, dialogs, tools) and start a watcher
|
|
104441
|
+
that re-arms terminal input if it stops; see debug/latest.txt
|
|
103776
104442
|
|
|
103777
104443
|
Session continuation and resume are mutually exclusive. Permission flags
|
|
103778
104444
|
are ignored in chat mode. Without a TTY, resume without an ID uses the latest session.
|
|
103779
104445
|
|
|
104446
|
+
A shell that stops reacting to keys can be recovered from another terminal
|
|
104447
|
+
with: kill -USR2 <keryx pid>
|
|
104448
|
+
|
|
103780
104449
|
Example: keryx shell --provider ollama --model llama3.1:latest`);
|
|
103781
104450
|
return;
|
|
103782
104451
|
}
|
|
104452
|
+
if (flags.debug === true) {
|
|
104453
|
+
await Promise.resolve().then(() => init_debug_log());
|
|
104454
|
+
await Promise.resolve().then(() => init_debug_watcher());
|
|
104455
|
+
const run = startDebugRun(runtime.cacheDir !== undefined ? { configDir: runtime.cacheDir } : {});
|
|
104456
|
+
const watcherPid = spawnDebugWatcher(run);
|
|
104457
|
+
debugEvent("session.start", {
|
|
104458
|
+
version: package_default.version,
|
|
104459
|
+
argv: args,
|
|
104460
|
+
bun: typeof Bun !== "undefined" ? Bun.version : undefined,
|
|
104461
|
+
platform: process.platform,
|
|
104462
|
+
execPath: process.execPath,
|
|
104463
|
+
cwd: process.cwd(),
|
|
104464
|
+
stdinTTY: process.stdin.isTTY === true,
|
|
104465
|
+
stdoutTTY: process.stdout.isTTY === true,
|
|
104466
|
+
env: Object.fromEntries(["TERM", "TERM_PROGRAM", "COLORTERM", "TMUX", "HERDR_ENV", "HERDR_PANE_ID", "SSH_TTY", "LANG"].map((k) => [k, process.env[k]])),
|
|
104467
|
+
watcherPid,
|
|
104468
|
+
dir: run.dir
|
|
104469
|
+
});
|
|
104470
|
+
process.on("exit", (code) => {
|
|
104471
|
+
debugEvent("session.exit", { code });
|
|
104472
|
+
process.stderr.write(`keryx debug log: ${run.dir}
|
|
104473
|
+
`);
|
|
104474
|
+
});
|
|
104475
|
+
}
|
|
103783
104476
|
const versionCheck = (runtime.checkVersion ?? (() => checkVersion({
|
|
103784
104477
|
currentVersion: package_default.version,
|
|
103785
104478
|
...runtime.cacheDir !== undefined ? { cacheDir: runtime.cacheDir } : {}
|
|
@@ -104300,7 +104993,7 @@ Shell:
|
|
|
104300
104993
|
init_fs();
|
|
104301
104994
|
import { readFile as readFile99 } from "fs/promises";
|
|
104302
104995
|
import { stdin } from "process";
|
|
104303
|
-
import
|
|
104996
|
+
import path196 from "path";
|
|
104304
104997
|
var MODULES = [
|
|
104305
104998
|
{ name: "gdgraph", flag: "--no-gdgraph", desc: "code graph, symbols, affected context", defaultEnabled: true },
|
|
104306
104999
|
{ name: "gdctx", flag: "--no-gdctx", desc: "token-aware command/read output", defaultEnabled: true },
|
|
@@ -104346,8 +105039,8 @@ async function modulesCommand(args = []) {
|
|
|
104346
105039
|
return;
|
|
104347
105040
|
}
|
|
104348
105041
|
const wantsJson = args.includes("--json") && (sub === undefined || sub === "status" || sub === "list" || sub === "--json");
|
|
104349
|
-
const metaprojectRoot =
|
|
104350
|
-
const manifestPath =
|
|
105042
|
+
const metaprojectRoot = path196.join(process.cwd(), ".metaproject");
|
|
105043
|
+
const manifestPath = path196.join(metaprojectRoot, "metaproject.json");
|
|
104351
105044
|
if (!await pathExists(manifestPath)) {
|
|
104352
105045
|
if (wantsJson) {
|
|
104353
105046
|
console.log(JSON.stringify({ schemaVersion: 1, error: "not-initialized", modules: [] }, null, 2));
|
|
@@ -104469,18 +105162,18 @@ init_config_dir();
|
|
|
104469
105162
|
import { createHash as createHash44, randomBytes as randomBytes5, randomUUID as randomUUID30 } from "crypto";
|
|
104470
105163
|
import {
|
|
104471
105164
|
chmodSync as chmodSync4,
|
|
104472
|
-
closeSync as
|
|
105165
|
+
closeSync as closeSync4,
|
|
104473
105166
|
existsSync as existsSync34,
|
|
104474
105167
|
fsyncSync as fsyncSync2,
|
|
104475
|
-
openSync as
|
|
105168
|
+
openSync as openSync4,
|
|
104476
105169
|
renameSync as renameSync4,
|
|
104477
|
-
statSync as
|
|
105170
|
+
statSync as statSync7,
|
|
104478
105171
|
unlinkSync as unlinkSync3,
|
|
104479
105172
|
writeFileSync as writeFileSync9
|
|
104480
105173
|
} from "fs";
|
|
104481
|
-
import
|
|
105174
|
+
import path197 from "path";
|
|
104482
105175
|
function serveCredentialPath(dir) {
|
|
104483
|
-
return
|
|
105176
|
+
return path197.join(keryxConfigDir(dir), "serve-credentials.json");
|
|
104484
105177
|
}
|
|
104485
105178
|
function constantTimeEqual(a, b) {
|
|
104486
105179
|
const width = Math.max(a.length, b.length);
|
|
@@ -104509,7 +105202,7 @@ function isGroupOrOtherAccessible(file) {
|
|
|
104509
105202
|
if (process.platform === "win32") {
|
|
104510
105203
|
return false;
|
|
104511
105204
|
}
|
|
104512
|
-
const mode =
|
|
105205
|
+
const mode = statSync7(file, { throwIfNoEntry: false })?.mode;
|
|
104513
105206
|
return mode !== undefined && (mode & 63) !== 0;
|
|
104514
105207
|
}
|
|
104515
105208
|
function readServeCredential(dir) {
|
|
@@ -104553,13 +105246,13 @@ function writeStore(store, dir) {
|
|
|
104553
105246
|
const temp = `${file}.${randomUUID30()}.tmp`;
|
|
104554
105247
|
try {
|
|
104555
105248
|
ensureKeryxConfigDir(dir);
|
|
104556
|
-
const handle =
|
|
105249
|
+
const handle = openSync4(temp, "wx", 384);
|
|
104557
105250
|
try {
|
|
104558
105251
|
writeFileSync9(handle, `${JSON.stringify(store, null, 2)}
|
|
104559
105252
|
`, { encoding: "utf8" });
|
|
104560
105253
|
fsyncSync2(handle);
|
|
104561
105254
|
} finally {
|
|
104562
|
-
|
|
105255
|
+
closeSync4(handle);
|
|
104563
105256
|
}
|
|
104564
105257
|
renameSync4(temp, file);
|
|
104565
105258
|
tighten2(file, 384);
|
|
@@ -104713,23 +105406,23 @@ class AuthFailureThrottle {
|
|
|
104713
105406
|
// src/lib/serve-turn-store.ts
|
|
104714
105407
|
init_config_dir();
|
|
104715
105408
|
import { createHash as createHash45 } from "crypto";
|
|
104716
|
-
import { existsSync as existsSync35, readdirSync as
|
|
104717
|
-
import
|
|
105409
|
+
import { existsSync as existsSync35, readdirSync as readdirSync4, rmSync as rmSync2 } from "fs";
|
|
105410
|
+
import path198 from "path";
|
|
104718
105411
|
var MAX_TURN_EVENTS = 1e4;
|
|
104719
105412
|
function turnsRoot(dir) {
|
|
104720
|
-
return
|
|
105413
|
+
return path198.join(keryxConfigDir(dir), "turns");
|
|
104721
105414
|
}
|
|
104722
105415
|
function turnDir(turnId, dir) {
|
|
104723
|
-
return
|
|
105416
|
+
return path198.join(turnsRoot(dir), turnId);
|
|
104724
105417
|
}
|
|
104725
105418
|
function keyPath(project, idempotencyKey, dir) {
|
|
104726
105419
|
const projectBytes = Buffer.byteLength(project, "utf8");
|
|
104727
105420
|
const digest = createHash45("sha256").update(`${projectBytes}:${project}\x00${idempotencyKey}`, "utf8").digest("hex");
|
|
104728
|
-
return
|
|
105421
|
+
return path198.join(turnsRoot(dir), "keys", `${digest}.json`);
|
|
104729
105422
|
}
|
|
104730
105423
|
function legacyKeyPath(idempotencyKey, dir) {
|
|
104731
105424
|
const digest = createHash45("sha256").update(idempotencyKey, "utf8").digest("hex");
|
|
104732
|
-
return
|
|
105425
|
+
return path198.join(turnsRoot(dir), "keys", `${digest}.json`);
|
|
104733
105426
|
}
|
|
104734
105427
|
function adoptLegacyClaim(project, idempotencyKey, dir) {
|
|
104735
105428
|
const legacy = legacyKeyPath(idempotencyKey, dir);
|
|
@@ -104793,7 +105486,7 @@ function ensureTurnDir(turnId, dir) {
|
|
|
104793
105486
|
}
|
|
104794
105487
|
function createTurnRecord(record, dir) {
|
|
104795
105488
|
ensureTurnDir(record.turnId, dir);
|
|
104796
|
-
writeOwnerOnlyFile(
|
|
105489
|
+
writeOwnerOnlyFile(path198.join(turnDir(record.turnId, dir), "turn.json"), `${JSON.stringify(record, null, 2)}
|
|
104797
105490
|
`);
|
|
104798
105491
|
}
|
|
104799
105492
|
function appendTurnEvent(event, dir, opts) {
|
|
@@ -104802,12 +105495,12 @@ function appendTurnEvent(event, dir, opts) {
|
|
|
104802
105495
|
}
|
|
104803
105496
|
const line = JSON.stringify(event);
|
|
104804
105497
|
try {
|
|
104805
|
-
appendOwnerOnlyLine(
|
|
105498
|
+
appendOwnerOnlyLine(path198.join(turnDir(event.turnId, dir), "events.jsonl"), line);
|
|
104806
105499
|
} catch (error) {
|
|
104807
105500
|
if (error?.code !== "ENOENT") {
|
|
104808
105501
|
throw error;
|
|
104809
105502
|
}
|
|
104810
|
-
appendOwnerOnlyLine(
|
|
105503
|
+
appendOwnerOnlyLine(path198.join(ensureTurnDir(event.turnId, dir), "events.jsonl"), line);
|
|
104811
105504
|
}
|
|
104812
105505
|
return true;
|
|
104813
105506
|
}
|
|
@@ -104815,7 +105508,7 @@ function readTurnEvents(turnId, after = -1, dir) {
|
|
|
104815
105508
|
if (!isTurnId(turnId)) {
|
|
104816
105509
|
return { ok: false, reason: "not-a-turn-id" };
|
|
104817
105510
|
}
|
|
104818
|
-
const read = readTurnFile(
|
|
105511
|
+
const read = readTurnFile(path198.join(turnDir(turnId, dir), "events.jsonl"));
|
|
104819
105512
|
if (!read.ok) {
|
|
104820
105513
|
if (isDefiniteAbsence2(read.reason)) {
|
|
104821
105514
|
return { ok: true, value: [] };
|
|
@@ -104843,7 +105536,7 @@ function readTurnRecord(turnId, dir) {
|
|
|
104843
105536
|
if (!isTurnId(turnId)) {
|
|
104844
105537
|
return { ok: false, reason: "not-a-turn-id" };
|
|
104845
105538
|
}
|
|
104846
|
-
const read = readTurnFile(
|
|
105539
|
+
const read = readTurnFile(path198.join(turnDir(turnId, dir), "turn.json"));
|
|
104847
105540
|
if (!read.ok) {
|
|
104848
105541
|
return { ok: false, reason: read.reason };
|
|
104849
105542
|
}
|
|
@@ -104862,7 +105555,7 @@ function finishTurn(turnId, result, dir) {
|
|
|
104862
105555
|
if (!record.ok) {
|
|
104863
105556
|
return false;
|
|
104864
105557
|
}
|
|
104865
|
-
writeOwnerOnlyFile(
|
|
105558
|
+
writeOwnerOnlyFile(path198.join(turnDir(turnId, dir), "turn.json"), `${JSON.stringify({ ...record.value, result }, null, 2)}
|
|
104866
105559
|
`);
|
|
104867
105560
|
return true;
|
|
104868
105561
|
}
|
|
@@ -104908,7 +105601,7 @@ function releaseIdempotencyKey(project, idempotencyKey, turnId, dir) {
|
|
|
104908
105601
|
|
|
104909
105602
|
// src/lib/serve-turn.ts
|
|
104910
105603
|
import { randomUUID as randomUUID31 } from "crypto";
|
|
104911
|
-
import
|
|
105604
|
+
import path199 from "path";
|
|
104912
105605
|
init_service();
|
|
104913
105606
|
var REMOTE_ORIGIN = "remote:http";
|
|
104914
105607
|
var MAX_PROMPT_CHARS = 32000;
|
|
@@ -104977,9 +105670,9 @@ function isUuid(value) {
|
|
|
104977
105670
|
return typeof value === "string" && /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/.test(value);
|
|
104978
105671
|
}
|
|
104979
105672
|
function resolveProject(declared, dir) {
|
|
104980
|
-
const wanted =
|
|
105673
|
+
const wanted = path199.resolve(declared);
|
|
104981
105674
|
for (const entry of listProjects(dir, () => {})) {
|
|
104982
|
-
if (
|
|
105675
|
+
if (path199.resolve(entry.path) === wanted) {
|
|
104983
105676
|
return { ok: true, project: entry.path };
|
|
104984
105677
|
}
|
|
104985
105678
|
}
|
|
@@ -106012,10 +106705,10 @@ function printHelp19() {
|
|
|
106012
106705
|
}
|
|
106013
106706
|
|
|
106014
106707
|
// src/commands/update.ts
|
|
106015
|
-
import { spawn as
|
|
106708
|
+
import { spawn as spawn7 } from "child_process";
|
|
106016
106709
|
import { chmod as chmod4, mkdir as mkdir63, readFile as readFile100, readdir as readdir37, writeFile as writeFile54 } from "fs/promises";
|
|
106017
|
-
import { access as access4, constants as
|
|
106018
|
-
import
|
|
106710
|
+
import { access as access4, constants as constants3, existsSync as existsSync36 } from "fs";
|
|
106711
|
+
import path200 from "path";
|
|
106019
106712
|
import { fileURLToPath as fileURLToPath8 } from "url";
|
|
106020
106713
|
init_config2();
|
|
106021
106714
|
init_config();
|
|
@@ -106032,8 +106725,8 @@ async function updateCommand(args = []) {
|
|
|
106032
106725
|
return;
|
|
106033
106726
|
}
|
|
106034
106727
|
const projectRoot = process.cwd();
|
|
106035
|
-
const metaprojectRoot =
|
|
106036
|
-
banner("keryx update", `Refreshing the .metaproject workspace in ${
|
|
106728
|
+
const metaprojectRoot = path200.join(projectRoot, ".metaproject");
|
|
106729
|
+
banner("keryx update", `Refreshing the .metaproject workspace in ${path200.basename(projectRoot)}/`);
|
|
106037
106730
|
if (!await pathExists(metaprojectRoot)) {
|
|
106038
106731
|
console.log(` ${style.red(symbols.cross)} Metaproject is not initialized.`);
|
|
106039
106732
|
console.log(` ${style.cyan(symbols.arrow)} Run ${style.cyan("keryx init")} first.`);
|
|
@@ -106106,7 +106799,7 @@ async function updateCommand(args = []) {
|
|
|
106106
106799
|
nextSteps(steps);
|
|
106107
106800
|
}
|
|
106108
106801
|
async function previewServiceFiles(projectRoot, options) {
|
|
106109
|
-
const metaprojectRoot =
|
|
106802
|
+
const metaprojectRoot = path200.join(projectRoot, ".metaproject");
|
|
106110
106803
|
const manifestState = await readManifest5(metaprojectRoot);
|
|
106111
106804
|
const manifest = manifestState.manifest;
|
|
106112
106805
|
const enableTasks = moduleEnabled2(manifest, "tasks") || !options.noTasks;
|
|
@@ -106135,12 +106828,12 @@ async function previewServiceFiles(projectRoot, options) {
|
|
|
106135
106828
|
});
|
|
106136
106829
|
}
|
|
106137
106830
|
async function refreshServiceFiles(projectRoot, options) {
|
|
106138
|
-
const metaprojectRoot =
|
|
106831
|
+
const metaprojectRoot = path200.join(projectRoot, ".metaproject");
|
|
106139
106832
|
const manifestState = await readManifest5(metaprojectRoot);
|
|
106140
106833
|
const manifest = manifestState.manifest;
|
|
106141
106834
|
const recoveredManifest = !manifestState.exists || !manifestState.valid;
|
|
106142
106835
|
if (manifestState.migrated) {
|
|
106143
|
-
await writeFile54(
|
|
106836
|
+
await writeFile54(path200.join(metaprojectRoot, "metaproject.json"), `${JSON.stringify(manifest, null, 2)}
|
|
106144
106837
|
`, "utf8");
|
|
106145
106838
|
}
|
|
106146
106839
|
const enableGdgraph = moduleEnabled2(manifest, "gdgraph");
|
|
@@ -106177,9 +106870,9 @@ async function refreshServiceFiles(projectRoot, options) {
|
|
|
106177
106870
|
enableSecurity,
|
|
106178
106871
|
enableSac
|
|
106179
106872
|
});
|
|
106180
|
-
await writeTextIfChanged4(
|
|
106181
|
-
await writeTextIfChanged4(
|
|
106182
|
-
await writeTextIfChanged4(
|
|
106873
|
+
await writeTextIfChanged4(path200.join(metaprojectRoot, "core", "README.md"), renderMetaprojectCoreReadme());
|
|
106874
|
+
await writeTextIfChanged4(path200.join(metaprojectRoot, "hooks", "README.md"), renderHooksReadme());
|
|
106875
|
+
await writeTextIfChanged4(path200.join(metaprojectRoot, "skills", "project-rules", "README.md"), renderProjectRulesSkillReadme({ sources: ruleSources }));
|
|
106183
106876
|
await writeRoutingEntrypointPair(metaprojectRoot, {
|
|
106184
106877
|
enableGdgraph,
|
|
106185
106878
|
enableGdctx,
|
|
@@ -106202,7 +106895,7 @@ async function refreshServiceFiles(projectRoot, options) {
|
|
|
106202
106895
|
}
|
|
106203
106896
|
}
|
|
106204
106897
|
});
|
|
106205
|
-
await writeTextIfChanged4(
|
|
106898
|
+
await writeTextIfChanged4(path200.join(metaprojectRoot, "keryx-dashboard.html"), renderMetaprojectDashboardHtml({
|
|
106206
106899
|
enableGdgraph,
|
|
106207
106900
|
enableGdctx,
|
|
106208
106901
|
enableGdwiki,
|
|
@@ -106214,7 +106907,7 @@ async function refreshServiceFiles(projectRoot, options) {
|
|
|
106214
106907
|
enableSecurity,
|
|
106215
106908
|
data: dashboardData
|
|
106216
106909
|
}));
|
|
106217
|
-
await writeTextIfMissing4(
|
|
106910
|
+
await writeTextIfMissing4(path200.join(metaprojectRoot, "README.md"), renderMetaprojectReadme({
|
|
106218
106911
|
enableGdgraph,
|
|
106219
106912
|
enableGdctx,
|
|
106220
106913
|
enableGdwiki,
|
|
@@ -106227,31 +106920,31 @@ async function refreshServiceFiles(projectRoot, options) {
|
|
|
106227
106920
|
}));
|
|
106228
106921
|
if (enableGdgraph) {
|
|
106229
106922
|
await installGdgraphCoreScripts2(metaprojectRoot);
|
|
106230
|
-
await writeTextIfChanged4(
|
|
106231
|
-
await writeTextIfChanged4(
|
|
106232
|
-
await writeTextIfChanged4(
|
|
106923
|
+
await writeTextIfChanged4(path200.join(metaprojectRoot, "modules", "gdgraph.md"), renderGdgraphManifest());
|
|
106924
|
+
await writeTextIfChanged4(path200.join(metaprojectRoot, "core", "gdgraph", "README.md"), renderGdgraphCoreReadme());
|
|
106925
|
+
await writeTextIfChanged4(path200.join(metaprojectRoot, "skills", "gdgraph", "SKILL.md"), renderGdgraphSkillReadme());
|
|
106233
106926
|
await seedAssetsLock(metaprojectRoot);
|
|
106234
106927
|
if (manifest.modules?.gdgraph?.hooks?.gitPostCommit) {
|
|
106235
106928
|
await installManagedHook2(projectRoot, "post-commit", "gdgraph-post-commit", renderGdgraphPostCommitHook());
|
|
106236
106929
|
}
|
|
106237
106930
|
}
|
|
106238
106931
|
if (enableGdctx) {
|
|
106239
|
-
await writeTextIfMissing4(
|
|
106240
|
-
await writeTextIfChanged4(
|
|
106241
|
-
await writeTextIfChanged4(
|
|
106242
|
-
await writeTextIfChanged4(
|
|
106932
|
+
await writeTextIfMissing4(path200.join(metaprojectRoot, "gdctx.config.json"), renderGdctxConfig());
|
|
106933
|
+
await writeTextIfChanged4(path200.join(metaprojectRoot, "modules", "gdctx.md"), renderGdctxManifest());
|
|
106934
|
+
await writeTextIfChanged4(path200.join(metaprojectRoot, "core", "gdctx", "README.md"), renderGdctxCoreReadme());
|
|
106935
|
+
await writeTextIfChanged4(path200.join(metaprojectRoot, "skills", "gdctx", "SKILL.md"), renderGdctxSkillReadme());
|
|
106243
106936
|
}
|
|
106244
106937
|
if (enableGdwiki) {
|
|
106245
|
-
await writeTextIfMissing4(
|
|
106246
|
-
await writeTextIfChanged4(
|
|
106247
|
-
await writeTextIfChanged4(
|
|
106938
|
+
await writeTextIfMissing4(path200.join(metaprojectRoot, "wiki", "templates", "page.md"), renderWikiPageTemplate());
|
|
106939
|
+
await writeTextIfChanged4(path200.join(metaprojectRoot, "modules", "gdwiki.md"), renderGdwikiManifest());
|
|
106940
|
+
await writeTextIfChanged4(path200.join(metaprojectRoot, "skills", "gdwiki", "SKILL.md"), renderGdwikiSkillReadme());
|
|
106248
106941
|
if (manifest.modules?.gdgraph?.hooks?.gitPostCommit) {
|
|
106249
106942
|
await installManagedHook2(projectRoot, "post-commit", "gdwiki-post-commit", renderGdwikiPostCommitHook());
|
|
106250
106943
|
}
|
|
106251
106944
|
}
|
|
106252
106945
|
if (enableSac) {
|
|
106253
|
-
await writeTextIfMissing4(
|
|
106254
|
-
await writeTextIfChanged4(
|
|
106946
|
+
await writeTextIfMissing4(path200.join(metaprojectRoot, "modules", "sac.md"), renderSacManifest());
|
|
106947
|
+
await writeTextIfChanged4(path200.join(metaprojectRoot, "skills", "sac", "SKILL.md"), renderSacSkillReadme());
|
|
106255
106948
|
}
|
|
106256
106949
|
let gdskillsWarnings = [];
|
|
106257
106950
|
let gdskillsNotices = [];
|
|
@@ -106264,25 +106957,25 @@ async function refreshServiceFiles(projectRoot, options) {
|
|
|
106264
106957
|
}
|
|
106265
106958
|
}
|
|
106266
106959
|
if (enableHealth) {
|
|
106267
|
-
await writeTextIfMissing4(
|
|
106268
|
-
await writeTextIfChanged4(
|
|
106269
|
-
await writeTextIfChanged4(
|
|
106270
|
-
await writeTextIfChanged4(
|
|
106960
|
+
await writeTextIfMissing4(path200.join(metaprojectRoot, "health.config.json"), renderHealthConfig());
|
|
106961
|
+
await writeTextIfChanged4(path200.join(metaprojectRoot, "modules", "health.md"), renderHealthManifest());
|
|
106962
|
+
await writeTextIfChanged4(path200.join(metaprojectRoot, "core", "health", "README.md"), renderHealthCoreReadme());
|
|
106963
|
+
await writeTextIfChanged4(path200.join(metaprojectRoot, "skills", "health", "SKILL.md"), renderHealthSkillReadme());
|
|
106271
106964
|
if (manifest.modules?.health?.hooks?.gitPostCommit) {
|
|
106272
106965
|
await installManagedHook2(projectRoot, "post-commit", "health-post-commit", renderHealthPostCommitHook());
|
|
106273
106966
|
}
|
|
106274
106967
|
}
|
|
106275
106968
|
if (enableTesting) {
|
|
106276
|
-
await writeTextIfMissing4(
|
|
106969
|
+
await writeTextIfMissing4(path200.join(metaprojectRoot, "testing.config.json"), renderTestingConfig({
|
|
106277
106970
|
postCommitRefresh: Boolean(manifest.modules?.testing?.hooks?.gitPostCommit),
|
|
106278
106971
|
prePushGate: Boolean(manifest.modules?.testing?.hooks?.prePush)
|
|
106279
106972
|
}));
|
|
106280
|
-
await writeTextIfChanged4(
|
|
106281
|
-
await writeTextIfChanged4(
|
|
106282
|
-
await writeTextIfChanged4(
|
|
106973
|
+
await writeTextIfChanged4(path200.join(metaprojectRoot, "modules", "testing.md"), renderTestingManifest());
|
|
106974
|
+
await writeTextIfChanged4(path200.join(metaprojectRoot, "core", "testing", "README.md"), renderTestingCoreReadme());
|
|
106975
|
+
await writeTextIfChanged4(path200.join(metaprojectRoot, "skills", "testing", "SKILL.md"), renderTestingSkillReadme());
|
|
106283
106976
|
if (enableGdwiki) {
|
|
106284
|
-
await writeTextIfMissing4(
|
|
106285
|
-
await writeTextIfMissing4(
|
|
106977
|
+
await writeTextIfMissing4(path200.join(metaprojectRoot, "wiki", "testing", "README.md"), renderTestingWikiReadme());
|
|
106978
|
+
await writeTextIfMissing4(path200.join(metaprojectRoot, "wiki", "testing", "conventions.md"), renderTestingWikiConventions());
|
|
106286
106979
|
}
|
|
106287
106980
|
if (manifest.modules?.testing?.hooks?.gitPostCommit) {
|
|
106288
106981
|
await installManagedHook2(projectRoot, "post-commit", "testing-post-commit", renderTestingPostCommitHook());
|
|
@@ -106295,24 +106988,24 @@ async function refreshServiceFiles(projectRoot, options) {
|
|
|
106295
106988
|
await installManagedHook2(projectRoot, "post-commit", "metaproject-dashboard-post-commit", renderMetaprojectDashboardPostCommitHook());
|
|
106296
106989
|
}
|
|
106297
106990
|
if (enableMemory) {
|
|
106298
|
-
await writeTextIfMissing4(
|
|
106299
|
-
await writeTextIfMissing4(
|
|
106300
|
-
await writeTextIfChanged4(
|
|
106301
|
-
await writeTextIfChanged4(
|
|
106302
|
-
await writeTextIfChanged4(
|
|
106991
|
+
await writeTextIfMissing4(path200.join(metaprojectRoot, "memory.config.json"), renderMemoryConfig());
|
|
106992
|
+
await writeTextIfMissing4(path200.join(metaprojectRoot, "memory", "templates", "entry.md"), renderMemoryEntryTemplate());
|
|
106993
|
+
await writeTextIfChanged4(path200.join(metaprojectRoot, "modules", "memory.md"), renderMemoryManifest());
|
|
106994
|
+
await writeTextIfChanged4(path200.join(metaprojectRoot, "core", "memory", "README.md"), renderMemoryCoreReadme());
|
|
106995
|
+
await writeTextIfChanged4(path200.join(metaprojectRoot, "skills", "memory", "SKILL.md"), renderMemorySkillReadme());
|
|
106303
106996
|
}
|
|
106304
106997
|
if (enableTasks) {
|
|
106305
|
-
await writeTextIfChanged4(
|
|
106306
|
-
await writeTextIfChanged4(
|
|
106307
|
-
await writeTextIfChanged4(
|
|
106308
|
-
await writeTextIfChanged4(
|
|
106309
|
-
await writeTextIfChanged4(
|
|
106310
|
-
await writeTextIfChanged4(
|
|
106998
|
+
await writeTextIfChanged4(path200.join(metaprojectRoot, "flows", "README.md"), renderFlowsReadme());
|
|
106999
|
+
await writeTextIfChanged4(path200.join(metaprojectRoot, "modules", "tasks.md"), renderTasksManifest());
|
|
107000
|
+
await writeTextIfChanged4(path200.join(metaprojectRoot, "skills", "flow", "SKILL.md"), renderFlowSkillRouter());
|
|
107001
|
+
await writeTextIfChanged4(path200.join(metaprojectRoot, "skills", "flow", "init.md"), renderFlowInitSkill());
|
|
107002
|
+
await writeTextIfChanged4(path200.join(metaprojectRoot, "skills", "flow", "manage.md"), renderFlowManageSkill());
|
|
107003
|
+
await writeTextIfChanged4(path200.join(metaprojectRoot, "skills", "flow", "complete.md"), renderFlowCompleteSkill());
|
|
106311
107004
|
}
|
|
106312
107005
|
if (enableSecurity) {
|
|
106313
|
-
await writeTextIfMissing4(
|
|
106314
|
-
await writeTextIfChanged4(
|
|
106315
|
-
await writeTextIfChanged4(
|
|
107006
|
+
await writeTextIfMissing4(path200.join(metaprojectRoot, "security.config.json"), renderSecurityConfig());
|
|
107007
|
+
await writeTextIfChanged4(path200.join(metaprojectRoot, "modules", "security.md"), renderSecurityManifest());
|
|
107008
|
+
await writeTextIfChanged4(path200.join(metaprojectRoot, "core", "security", "README.md"), renderSecurityCoreReadme());
|
|
106316
107009
|
if (manifest.modules?.security?.hooks?.prePush) {
|
|
106317
107010
|
await installManagedHook2(projectRoot, "pre-push", "security-pre-push", renderSecurityPrePushHook());
|
|
106318
107011
|
}
|
|
@@ -106365,13 +107058,13 @@ async function refreshServiceFiles(projectRoot, options) {
|
|
|
106365
107058
|
};
|
|
106366
107059
|
}
|
|
106367
107060
|
async function buildDashboard(projectRoot = process.cwd()) {
|
|
106368
|
-
const metaprojectRoot =
|
|
107061
|
+
const metaprojectRoot = path200.join(projectRoot, ".metaproject");
|
|
106369
107062
|
if (!await pathExists(metaprojectRoot)) {
|
|
106370
107063
|
throw new Error("Metaproject is not initialized. Run: keryx init");
|
|
106371
107064
|
}
|
|
106372
107065
|
const manifest = (await readManifest5(metaprojectRoot)).manifest;
|
|
106373
107066
|
const data = await collectDashboardData(metaprojectRoot);
|
|
106374
|
-
const dashboardPath =
|
|
107067
|
+
const dashboardPath = path200.join(metaprojectRoot, "keryx-dashboard.html");
|
|
106375
107068
|
await writeTextIfChanged4(dashboardPath, renderMetaprojectDashboardHtml({
|
|
106376
107069
|
enableGdgraph: moduleEnabled2(manifest, "gdgraph"),
|
|
106377
107070
|
enableGdctx: moduleEnabled2(manifest, "gdctx"),
|
|
@@ -106391,7 +107084,7 @@ async function shouldInstallDashboardPostCommitHook(projectRoot, manifest) {
|
|
|
106391
107084
|
if (Object.values(modules).some((module) => Boolean(module.hooks?.gitPostCommit))) {
|
|
106392
107085
|
return true;
|
|
106393
107086
|
}
|
|
106394
|
-
const hookPath =
|
|
107087
|
+
const hookPath = path200.join(projectRoot, ".git", "hooks", "post-commit");
|
|
106395
107088
|
if (!await pathExists(hookPath)) {
|
|
106396
107089
|
return false;
|
|
106397
107090
|
}
|
|
@@ -106411,11 +107104,11 @@ async function collectDashboardData(metaprojectRoot) {
|
|
|
106411
107104
|
if (testing) {
|
|
106412
107105
|
data.testing = testing;
|
|
106413
107106
|
}
|
|
106414
|
-
const wiki = await collectMarkdownPages(
|
|
107107
|
+
const wiki = await collectMarkdownPages(path200.join(metaprojectRoot, "wiki"), "wiki");
|
|
106415
107108
|
if (wiki.length > 0) {
|
|
106416
107109
|
data.wiki = { pages: wiki };
|
|
106417
107110
|
}
|
|
106418
|
-
const memory = await collectMarkdownPages(
|
|
107111
|
+
const memory = await collectMarkdownPages(path200.join(metaprojectRoot, "memory"), "memory");
|
|
106419
107112
|
if (memory.length > 0) {
|
|
106420
107113
|
data.memory = { entries: memory };
|
|
106421
107114
|
}
|
|
@@ -106430,7 +107123,7 @@ async function collectDashboardData(metaprojectRoot) {
|
|
|
106430
107123
|
return data;
|
|
106431
107124
|
}
|
|
106432
107125
|
async function collectTasksDashboardData(metaprojectRoot) {
|
|
106433
|
-
const flowsRoot =
|
|
107126
|
+
const flowsRoot = path200.join(metaprojectRoot, "flows");
|
|
106434
107127
|
if (!await pathExists(flowsRoot)) {
|
|
106435
107128
|
return null;
|
|
106436
107129
|
}
|
|
@@ -106442,7 +107135,7 @@ async function collectTasksDashboardData(metaprojectRoot) {
|
|
|
106442
107135
|
}
|
|
106443
107136
|
const flows = [];
|
|
106444
107137
|
for (const dir of dirEntries) {
|
|
106445
|
-
const flowPath =
|
|
107138
|
+
const flowPath = path200.join(flowsRoot, dir, "flow.json");
|
|
106446
107139
|
if (!await pathExists(flowPath)) {
|
|
106447
107140
|
continue;
|
|
106448
107141
|
}
|
|
@@ -106450,7 +107143,7 @@ async function collectTasksDashboardData(metaprojectRoot) {
|
|
|
106450
107143
|
const flow = JSON.parse(await readFile100(flowPath, "utf8"));
|
|
106451
107144
|
const tasks = Array.isArray(flow.tasks) ? flow.tasks : [];
|
|
106452
107145
|
let acTotal = 0;
|
|
106453
|
-
const acPath =
|
|
107146
|
+
const acPath = path200.join(flowsRoot, dir, "acceptance-criteria.md");
|
|
106454
107147
|
if (await pathExists(acPath)) {
|
|
106455
107148
|
const acContent = await readFile100(acPath, "utf8");
|
|
106456
107149
|
acTotal = (acContent.match(/^- AC\d+:/gm) ?? []).length;
|
|
@@ -106504,7 +107197,7 @@ async function collectDashboardDocs(metaprojectRoot, wiki, memory) {
|
|
|
106504
107197
|
"data/testing/context.md"
|
|
106505
107198
|
];
|
|
106506
107199
|
for (const href of staticHrefs) {
|
|
106507
|
-
const filePath =
|
|
107200
|
+
const filePath = path200.join(metaprojectRoot, ...href.split("/"));
|
|
106508
107201
|
if (!await pathExists(filePath)) {
|
|
106509
107202
|
continue;
|
|
106510
107203
|
}
|
|
@@ -106521,7 +107214,7 @@ async function collectDashboardDocs(metaprojectRoot, wiki, memory) {
|
|
|
106521
107214
|
return docs;
|
|
106522
107215
|
}
|
|
106523
107216
|
async function collectHealthDashboardData(metaprojectRoot) {
|
|
106524
|
-
const reportPath =
|
|
107217
|
+
const reportPath = path200.join(metaprojectRoot, "data", "health", "artifacts", "latest.json");
|
|
106525
107218
|
if (!await pathExists(reportPath)) {
|
|
106526
107219
|
return;
|
|
106527
107220
|
}
|
|
@@ -106630,8 +107323,8 @@ function metricToScope(metric) {
|
|
|
106630
107323
|
};
|
|
106631
107324
|
}
|
|
106632
107325
|
async function collectGraphDashboardData(metaprojectRoot) {
|
|
106633
|
-
const nodesPath =
|
|
106634
|
-
const edgesPath =
|
|
107326
|
+
const nodesPath = path200.join(metaprojectRoot, "data", "gdgraph", "storage", "nodes.jsonl");
|
|
107327
|
+
const edgesPath = path200.join(metaprojectRoot, "data", "gdgraph", "storage", "edges.jsonl");
|
|
106635
107328
|
if (!await pathExists(nodesPath) || !await pathExists(edgesPath)) {
|
|
106636
107329
|
return;
|
|
106637
107330
|
}
|
|
@@ -106682,8 +107375,8 @@ async function collectGraphDashboardData(metaprojectRoot) {
|
|
|
106682
107375
|
};
|
|
106683
107376
|
}
|
|
106684
107377
|
async function collectTestingDashboardData(metaprojectRoot) {
|
|
106685
|
-
const reportPath =
|
|
106686
|
-
const contextPath =
|
|
107378
|
+
const reportPath = path200.join(metaprojectRoot, "data", "testing", "artifacts", "latest.json");
|
|
107379
|
+
const contextPath = path200.join(metaprojectRoot, "data", "testing", "context.md");
|
|
106687
107380
|
if (await pathExists(reportPath)) {
|
|
106688
107381
|
const report = JSON.parse(await readFile100(reportPath, "utf8"));
|
|
106689
107382
|
const totalTests = numberOrUndefined(report.total);
|
|
@@ -106712,7 +107405,7 @@ async function collectMarkdownPages(root, hrefPrefix) {
|
|
|
106712
107405
|
const files = await listMarkdownFiles(root);
|
|
106713
107406
|
const pages = [];
|
|
106714
107407
|
for (const filePath of files.slice(0, 40)) {
|
|
106715
|
-
const relativePath =
|
|
107408
|
+
const relativePath = path200.relative(root, filePath).split(path200.sep).join("/");
|
|
106716
107409
|
if (relativePath === "index.md" || relativePath.startsWith("templates/")) {
|
|
106717
107410
|
continue;
|
|
106718
107411
|
}
|
|
@@ -106733,7 +107426,7 @@ async function listMarkdownFiles(root) {
|
|
|
106733
107426
|
const entries = await readdir37(root, { withFileTypes: true });
|
|
106734
107427
|
const files = [];
|
|
106735
107428
|
for (const entry of entries) {
|
|
106736
|
-
const fullPath =
|
|
107429
|
+
const fullPath = path200.join(root, entry.name);
|
|
106737
107430
|
if (entry.isDirectory()) {
|
|
106738
107431
|
files.push(...await listMarkdownFiles(fullPath));
|
|
106739
107432
|
} else if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
@@ -106781,7 +107474,7 @@ async function writeRecoveredManifest(metaprojectRoot, modules) {
|
|
|
106781
107474
|
const manifest = {
|
|
106782
107475
|
schemaVersion: 1,
|
|
106783
107476
|
standardVersion: STANDARD_VERSION,
|
|
106784
|
-
name: `${
|
|
107477
|
+
name: `${path200.basename(path200.dirname(metaprojectRoot))}-metaproject`,
|
|
106785
107478
|
createdBy: "keryx",
|
|
106786
107479
|
profiles: computeProfiles(enabledModuleKeys),
|
|
106787
107480
|
paths: {
|
|
@@ -106871,11 +107564,11 @@ async function writeRecoveredManifest(metaprojectRoot, modules) {
|
|
|
106871
107564
|
metaproject: ".metaproject/index.md"
|
|
106872
107565
|
}
|
|
106873
107566
|
};
|
|
106874
|
-
await writeFile54(
|
|
107567
|
+
await writeFile54(path200.join(metaprojectRoot, "metaproject.json"), `${JSON.stringify(manifest, null, 2)}
|
|
106875
107568
|
`, "utf8");
|
|
106876
107569
|
}
|
|
106877
107570
|
async function enableTasksInManifest(metaprojectRoot) {
|
|
106878
|
-
const manifestPath =
|
|
107571
|
+
const manifestPath = path200.join(metaprojectRoot, "metaproject.json");
|
|
106879
107572
|
if (!await pathExists(manifestPath)) {
|
|
106880
107573
|
return;
|
|
106881
107574
|
}
|
|
@@ -106898,7 +107591,7 @@ async function enableTasksInManifest(metaprojectRoot) {
|
|
|
106898
107591
|
`, "utf8");
|
|
106899
107592
|
}
|
|
106900
107593
|
async function updateManifestAgentEntrypoints(metaprojectRoot, ruleSources) {
|
|
106901
|
-
const manifestPath =
|
|
107594
|
+
const manifestPath = path200.join(metaprojectRoot, "metaproject.json");
|
|
106902
107595
|
if (!await pathExists(manifestPath)) {
|
|
106903
107596
|
return;
|
|
106904
107597
|
}
|
|
@@ -106934,72 +107627,72 @@ async function updateRuntime(projectRoot) {
|
|
|
106934
107627
|
}
|
|
106935
107628
|
}
|
|
106936
107629
|
async function findRuntimeRoot(projectRoot) {
|
|
106937
|
-
const projectRuntime =
|
|
106938
|
-
if (await pathExists(
|
|
107630
|
+
const projectRuntime = path200.join(projectRoot, ".metaproject", "runtime", "keryx");
|
|
107631
|
+
if (await pathExists(path200.join(projectRuntime, ".git"))) {
|
|
106939
107632
|
return projectRuntime;
|
|
106940
107633
|
}
|
|
106941
107634
|
const home = process.env.HOME;
|
|
106942
107635
|
if (!home) {
|
|
106943
107636
|
return null;
|
|
106944
107637
|
}
|
|
106945
|
-
const globalRuntime =
|
|
106946
|
-
if (await pathExists(
|
|
107638
|
+
const globalRuntime = path200.join(home, ".keryx", "keryx");
|
|
107639
|
+
if (await pathExists(path200.join(globalRuntime, ".git"))) {
|
|
106947
107640
|
return globalRuntime;
|
|
106948
107641
|
}
|
|
106949
107642
|
return null;
|
|
106950
107643
|
}
|
|
106951
107644
|
async function createServiceDirs(metaprojectRoot, modules) {
|
|
106952
107645
|
const dirs = [
|
|
106953
|
-
|
|
106954
|
-
|
|
106955
|
-
|
|
106956
|
-
|
|
106957
|
-
|
|
107646
|
+
path200.join(metaprojectRoot, "core"),
|
|
107647
|
+
path200.join(metaprojectRoot, "hooks", "post-update.d"),
|
|
107648
|
+
path200.join(metaprojectRoot, "modules"),
|
|
107649
|
+
path200.join(metaprojectRoot, "rules"),
|
|
107650
|
+
path200.join(metaprojectRoot, "skills", "project-rules"),
|
|
106958
107651
|
...modules.enableGdgraph ? [
|
|
106959
|
-
|
|
106960
|
-
|
|
107652
|
+
path200.join(metaprojectRoot, "core", "gdgraph"),
|
|
107653
|
+
path200.join(metaprojectRoot, "skills", "gdgraph")
|
|
106961
107654
|
] : [],
|
|
106962
107655
|
...modules.enableGdctx ? [
|
|
106963
|
-
|
|
106964
|
-
|
|
107656
|
+
path200.join(metaprojectRoot, "core", "gdctx"),
|
|
107657
|
+
path200.join(metaprojectRoot, "skills", "gdctx")
|
|
106965
107658
|
] : [],
|
|
106966
107659
|
...modules.enableGdwiki ? [
|
|
106967
|
-
|
|
106968
|
-
|
|
107660
|
+
path200.join(metaprojectRoot, "skills", "gdwiki"),
|
|
107661
|
+
path200.join(metaprojectRoot, "wiki", "templates")
|
|
106969
107662
|
] : [],
|
|
106970
107663
|
...modules.enableHealth ? [
|
|
106971
|
-
|
|
106972
|
-
|
|
107664
|
+
path200.join(metaprojectRoot, "core", "health"),
|
|
107665
|
+
path200.join(metaprojectRoot, "skills", "health")
|
|
106973
107666
|
] : [],
|
|
106974
107667
|
...modules.enableTesting ? [
|
|
106975
|
-
|
|
106976
|
-
|
|
107668
|
+
path200.join(metaprojectRoot, "core", "testing"),
|
|
107669
|
+
path200.join(metaprojectRoot, "skills", "testing")
|
|
106977
107670
|
] : [],
|
|
106978
107671
|
...modules.enableMemory ? [
|
|
106979
|
-
|
|
106980
|
-
|
|
106981
|
-
|
|
107672
|
+
path200.join(metaprojectRoot, "core", "memory"),
|
|
107673
|
+
path200.join(metaprojectRoot, "skills", "memory"),
|
|
107674
|
+
path200.join(metaprojectRoot, "memory", "templates")
|
|
106982
107675
|
] : [],
|
|
106983
107676
|
...modules.enableTasks ? [
|
|
106984
|
-
|
|
106985
|
-
|
|
107677
|
+
path200.join(metaprojectRoot, "flows"),
|
|
107678
|
+
path200.join(metaprojectRoot, "skills", "flow")
|
|
106986
107679
|
] : [],
|
|
106987
107680
|
...modules.enableSecurity ? [
|
|
106988
|
-
|
|
107681
|
+
path200.join(metaprojectRoot, "core", "security")
|
|
106989
107682
|
] : [],
|
|
106990
107683
|
...modules.enableSac ? [
|
|
106991
|
-
|
|
107684
|
+
path200.join(metaprojectRoot, "skills", "sac")
|
|
106992
107685
|
] : []
|
|
106993
107686
|
];
|
|
106994
107687
|
await Promise.all(dirs.map((dir) => mkdir63(dir, { recursive: true })));
|
|
106995
107688
|
}
|
|
106996
107689
|
async function installGdgraphCoreScripts2(metaprojectRoot) {
|
|
106997
|
-
const gdgraphCoreRoot =
|
|
107690
|
+
const gdgraphCoreRoot = path200.join(metaprojectRoot, "core", "gdgraph");
|
|
106998
107691
|
await mkdir63(gdgraphCoreRoot, { recursive: true });
|
|
106999
107692
|
for (const file of GDGRAPH_CORE_SOURCES) {
|
|
107000
|
-
await copyFileIfChanged2(runtimeSourcePath2(`../gdgraph/${file}`),
|
|
107693
|
+
await copyFileIfChanged2(runtimeSourcePath2(`../gdgraph/${file}`), path200.join(gdgraphCoreRoot, file));
|
|
107001
107694
|
}
|
|
107002
|
-
await writeTextIfChanged4(
|
|
107695
|
+
await writeTextIfChanged4(path200.join(gdgraphCoreRoot, "cli.ts"), renderGdgraphCoreCli());
|
|
107003
107696
|
}
|
|
107004
107697
|
async function installManagedHook2(projectRoot, hookName, blockId, content) {
|
|
107005
107698
|
const hooksRoot = await resolveGitHooksRoot(projectRoot);
|
|
@@ -107007,7 +107700,7 @@ async function installManagedHook2(projectRoot, hookName, blockId, content) {
|
|
|
107007
107700
|
return;
|
|
107008
107701
|
}
|
|
107009
107702
|
await mkdir63(hooksRoot, { recursive: true });
|
|
107010
|
-
const hookPath =
|
|
107703
|
+
const hookPath = path200.join(hooksRoot, hookName);
|
|
107011
107704
|
const blockStart = `# keryx:${blockId}:begin`;
|
|
107012
107705
|
const blockEnd = `# keryx:${blockId}:end`;
|
|
107013
107706
|
const managedBlock = `${blockStart}
|
|
@@ -107028,7 +107721,7 @@ async function removeManagedHook2(projectRoot, hookName, blockId) {
|
|
|
107028
107721
|
if (!hooksRoot) {
|
|
107029
107722
|
return;
|
|
107030
107723
|
}
|
|
107031
|
-
const hookPath =
|
|
107724
|
+
const hookPath = path200.join(hooksRoot, hookName);
|
|
107032
107725
|
if (!await pathExists(hookPath)) {
|
|
107033
107726
|
return;
|
|
107034
107727
|
}
|
|
@@ -107050,7 +107743,7 @@ async function prePushHasSecurityBlock2(projectRoot) {
|
|
|
107050
107743
|
if (!hooksRoot) {
|
|
107051
107744
|
return false;
|
|
107052
107745
|
}
|
|
107053
|
-
const hookPath =
|
|
107746
|
+
const hookPath = path200.join(hooksRoot, "pre-push");
|
|
107054
107747
|
if (!await pathExists(hookPath)) {
|
|
107055
107748
|
return false;
|
|
107056
107749
|
}
|
|
@@ -107065,7 +107758,7 @@ async function agentSettingsHasSecuritySentinel2(projectRoot) {
|
|
|
107065
107758
|
return (await readFile100(file, "utf8")).includes(AGENT_HOOKS_SENTINEL);
|
|
107066
107759
|
}
|
|
107067
107760
|
async function readManifest5(metaprojectRoot) {
|
|
107068
|
-
const manifestPath =
|
|
107761
|
+
const manifestPath = path200.join(metaprojectRoot, "metaproject.json");
|
|
107069
107762
|
if (!await pathExists(manifestPath)) {
|
|
107070
107763
|
return {
|
|
107071
107764
|
exists: false,
|
|
@@ -107134,7 +107827,7 @@ async function inferManifestFromExistingMetaproject(metaprojectRoot) {
|
|
|
107134
107827
|
}
|
|
107135
107828
|
async function anyPathExists(root, candidates) {
|
|
107136
107829
|
for (const candidate of candidates) {
|
|
107137
|
-
if (await pathExists(
|
|
107830
|
+
if (await pathExists(path200.join(root, candidate))) {
|
|
107138
107831
|
return true;
|
|
107139
107832
|
}
|
|
107140
107833
|
}
|
|
@@ -107157,13 +107850,13 @@ function parseUpdateArgs(args) {
|
|
|
107157
107850
|
};
|
|
107158
107851
|
}
|
|
107159
107852
|
async function runPostUpdateHooks(projectRoot) {
|
|
107160
|
-
const hooksDir =
|
|
107853
|
+
const hooksDir = path200.join(projectRoot, ".metaproject", "hooks", "post-update.d");
|
|
107161
107854
|
if (!await pathExists(hooksDir)) {
|
|
107162
107855
|
return;
|
|
107163
107856
|
}
|
|
107164
107857
|
const entries = (await readdir37(hooksDir)).sort();
|
|
107165
107858
|
for (const entry of entries) {
|
|
107166
|
-
const hookPath =
|
|
107859
|
+
const hookPath = path200.join(hooksDir, entry);
|
|
107167
107860
|
try {
|
|
107168
107861
|
await accessExecutable(hookPath);
|
|
107169
107862
|
} catch {
|
|
@@ -107175,7 +107868,7 @@ async function runPostUpdateHooks(projectRoot) {
|
|
|
107175
107868
|
}
|
|
107176
107869
|
async function accessExecutable(filePath) {
|
|
107177
107870
|
await new Promise((resolve, reject) => {
|
|
107178
|
-
access4(filePath,
|
|
107871
|
+
access4(filePath, constants3.X_OK, (error) => {
|
|
107179
107872
|
if (error) {
|
|
107180
107873
|
reject(error);
|
|
107181
107874
|
return;
|
|
@@ -107186,7 +107879,7 @@ async function accessExecutable(filePath) {
|
|
|
107186
107879
|
}
|
|
107187
107880
|
async function run(command, args, cwd) {
|
|
107188
107881
|
await new Promise((resolve, reject) => {
|
|
107189
|
-
const child =
|
|
107882
|
+
const child = spawn7(command, args, {
|
|
107190
107883
|
cwd,
|
|
107191
107884
|
stdio: "inherit"
|
|
107192
107885
|
});
|
|
@@ -107204,14 +107897,14 @@ async function writeTextIfChanged4(filePath, content) {
|
|
|
107204
107897
|
if (await pathExists(filePath) && await readFile100(filePath, "utf8") === content) {
|
|
107205
107898
|
return;
|
|
107206
107899
|
}
|
|
107207
|
-
await mkdir63(
|
|
107900
|
+
await mkdir63(path200.dirname(filePath), { recursive: true });
|
|
107208
107901
|
await writeFile54(filePath, content, "utf8");
|
|
107209
107902
|
}
|
|
107210
107903
|
async function writeTextIfMissing4(filePath, content) {
|
|
107211
107904
|
if (await pathExists(filePath)) {
|
|
107212
107905
|
return;
|
|
107213
107906
|
}
|
|
107214
|
-
await mkdir63(
|
|
107907
|
+
await mkdir63(path200.dirname(filePath), { recursive: true });
|
|
107215
107908
|
await writeFile54(filePath, content, "utf8");
|
|
107216
107909
|
}
|
|
107217
107910
|
async function copyFileIfChanged2(from, to) {
|
|
@@ -107219,7 +107912,7 @@ async function copyFileIfChanged2(from, to) {
|
|
|
107219
107912
|
if (await pathExists(to) && await readFile100(to, "utf8") === next) {
|
|
107220
107913
|
return;
|
|
107221
107914
|
}
|
|
107222
|
-
await mkdir63(
|
|
107915
|
+
await mkdir63(path200.dirname(to), { recursive: true });
|
|
107223
107916
|
await writeFile54(to, next, "utf8");
|
|
107224
107917
|
}
|
|
107225
107918
|
function runtimeSourcePath2(relativePath) {
|
|
@@ -107228,7 +107921,7 @@ function runtimeSourcePath2(relativePath) {
|
|
|
107228
107921
|
return directPath;
|
|
107229
107922
|
}
|
|
107230
107923
|
if (relativePath.startsWith("../")) {
|
|
107231
|
-
const packagedSourcePath =
|
|
107924
|
+
const packagedSourcePath = path200.join(path200.dirname(fileURLToPath8(import.meta.url)), "..", "src", relativePath.slice(3));
|
|
107232
107925
|
if (existsSync36(packagedSourcePath)) {
|
|
107233
107926
|
return packagedSourcePath;
|
|
107234
107927
|
}
|
|
@@ -107262,8 +107955,8 @@ function printHelp20() {
|
|
|
107262
107955
|
}
|
|
107263
107956
|
|
|
107264
107957
|
// src/commands/dashboard.ts
|
|
107265
|
-
import { spawn as
|
|
107266
|
-
import
|
|
107958
|
+
import { spawn as spawn8 } from "child_process";
|
|
107959
|
+
import path201 from "path";
|
|
107267
107960
|
init_args();
|
|
107268
107961
|
async function dashboardCommand(args = []) {
|
|
107269
107962
|
const options = parseOptions(args);
|
|
@@ -107274,7 +107967,7 @@ async function dashboardCommand(args = []) {
|
|
|
107274
107967
|
}
|
|
107275
107968
|
if (subcommand === "build") {
|
|
107276
107969
|
const result = await buildDashboard();
|
|
107277
|
-
const rel =
|
|
107970
|
+
const rel = path201.relative(process.cwd(), result.path);
|
|
107278
107971
|
console.log(` ${style.green(symbols.ok)} Dashboard built ${style.cyan(symbols.arrow)} ${style.cyan(rel)}`);
|
|
107279
107972
|
note(`Open it: keryx dashboard open`);
|
|
107280
107973
|
return;
|
|
@@ -107282,7 +107975,7 @@ async function dashboardCommand(args = []) {
|
|
|
107282
107975
|
if (subcommand === "open") {
|
|
107283
107976
|
const result = await buildDashboard();
|
|
107284
107977
|
await openFile(result.path);
|
|
107285
|
-
const rel =
|
|
107978
|
+
const rel = path201.relative(process.cwd(), result.path);
|
|
107286
107979
|
console.log(` ${style.green(symbols.ok)} Opened ${style.cyan(rel)}`);
|
|
107287
107980
|
return;
|
|
107288
107981
|
}
|
|
@@ -107301,7 +107994,7 @@ async function openFile(filePath) {
|
|
|
107301
107994
|
const command = process.platform === "darwin" ? "open" : process.platform === "win32" ? "cmd" : "xdg-open";
|
|
107302
107995
|
const args = process.platform === "win32" ? ["/c", "start", "", filePath] : [filePath];
|
|
107303
107996
|
await new Promise((resolve, reject) => {
|
|
107304
|
-
const child =
|
|
107997
|
+
const child = spawn8(command, args, { stdio: "ignore", detached: true });
|
|
107305
107998
|
child.on("error", reject);
|
|
107306
107999
|
child.on("close", (code) => {
|
|
107307
108000
|
if (code === 0) {
|
|
@@ -107326,12 +108019,12 @@ function printHelp21() {
|
|
|
107326
108019
|
}
|
|
107327
108020
|
|
|
107328
108021
|
// src/commands/agents.ts
|
|
107329
|
-
import { readFileSync as
|
|
108022
|
+
import { readFileSync as readFileSync10 } from "fs";
|
|
107330
108023
|
|
|
107331
108024
|
// src/agents/bootstrap.ts
|
|
107332
108025
|
import { mkdir as mkdir64, readFile as readFile101, writeFile as writeFile55 } from "fs/promises";
|
|
107333
108026
|
import { homedir as homedir10 } from "os";
|
|
107334
|
-
import
|
|
108027
|
+
import path202 from "path";
|
|
107335
108028
|
init_fs();
|
|
107336
108029
|
var AGENT_BOOTSTRAP_START = "<!-- keryx:global-bootstrap -->";
|
|
107337
108030
|
var AGENT_BOOTSTRAP_END = "<!-- /keryx:global-bootstrap -->";
|
|
@@ -107341,35 +108034,35 @@ var AGENT_BOOTSTRAP_RUNTIMES = [
|
|
|
107341
108034
|
aliases: ["claude-code"],
|
|
107342
108035
|
label: "Claude Code",
|
|
107343
108036
|
fileName: "CLAUDE.md",
|
|
107344
|
-
filePath: (homeRoot) =>
|
|
108037
|
+
filePath: (homeRoot) => path202.join(homeRoot, ".claude", "CLAUDE.md")
|
|
107345
108038
|
},
|
|
107346
108039
|
{
|
|
107347
108040
|
id: "opencode",
|
|
107348
108041
|
aliases: ["open-code"],
|
|
107349
108042
|
label: "OpenCode",
|
|
107350
108043
|
fileName: "AGENTS.md",
|
|
107351
|
-
filePath: (homeRoot) =>
|
|
108044
|
+
filePath: (homeRoot) => path202.join(homeRoot, ".config", "opencode", "AGENTS.md")
|
|
107352
108045
|
},
|
|
107353
108046
|
{
|
|
107354
108047
|
id: "zcode",
|
|
107355
108048
|
aliases: ["zed", "zed-code"],
|
|
107356
108049
|
label: "ZCode",
|
|
107357
108050
|
fileName: "AGENTS.md",
|
|
107358
|
-
filePath: (homeRoot) =>
|
|
108051
|
+
filePath: (homeRoot) => path202.join(homeRoot, ".zcode", "AGENTS.md")
|
|
107359
108052
|
},
|
|
107360
108053
|
{
|
|
107361
108054
|
id: "codex",
|
|
107362
108055
|
aliases: [],
|
|
107363
108056
|
label: "Codex",
|
|
107364
108057
|
fileName: "AGENTS.md",
|
|
107365
|
-
filePath: (homeRoot) =>
|
|
108058
|
+
filePath: (homeRoot) => path202.join(homeRoot, ".codex", "AGENTS.md")
|
|
107366
108059
|
},
|
|
107367
108060
|
{
|
|
107368
108061
|
id: "antigravity",
|
|
107369
108062
|
aliases: ["antigravuty", "antigravity-code"],
|
|
107370
108063
|
label: "Antigravity",
|
|
107371
108064
|
fileName: "AGENTS.md",
|
|
107372
|
-
filePath: (homeRoot) =>
|
|
108065
|
+
filePath: (homeRoot) => path202.join(homeRoot, ".config", "antigravity", "AGENTS.md")
|
|
107373
108066
|
}
|
|
107374
108067
|
];
|
|
107375
108068
|
function agentBootstrapRuntimeIds() {
|
|
@@ -107417,7 +108110,7 @@ async function installAgentBootstrap(runtime, options = {}) {
|
|
|
107417
108110
|
const dryRun = options.dryRun === true;
|
|
107418
108111
|
const wrote = next !== current;
|
|
107419
108112
|
if (wrote && !dryRun) {
|
|
107420
|
-
await mkdir64(
|
|
108113
|
+
await mkdir64(path202.dirname(filePath), { recursive: true });
|
|
107421
108114
|
await writeFile55(filePath, next, "utf8");
|
|
107422
108115
|
}
|
|
107423
108116
|
const status = dryRun ? statusFromContent(runtime, filePath, exists, next) : await agentBootstrapStatus(runtime, homeRoot);
|
|
@@ -107827,7 +108520,7 @@ function monitorCommand(args) {
|
|
|
107827
108520
|
}
|
|
107828
108521
|
let events;
|
|
107829
108522
|
try {
|
|
107830
|
-
events = parseAgentEvents(
|
|
108523
|
+
events = parseAgentEvents(readFileSync10(source, "utf8"));
|
|
107831
108524
|
} catch (error) {
|
|
107832
108525
|
console.error(`Failed to read/parse agent-event source "${source}": ${error.message}`);
|
|
107833
108526
|
process.exitCode = 1;
|
|
@@ -107954,7 +108647,7 @@ function printBootstrapHelp() {
|
|
|
107954
108647
|
// src/commands/metrics.ts
|
|
107955
108648
|
init_args();
|
|
107956
108649
|
import { readFile as readFile102 } from "fs/promises";
|
|
107957
|
-
import
|
|
108650
|
+
import path204 from "path";
|
|
107958
108651
|
|
|
107959
108652
|
// src/metrics/benchmark.ts
|
|
107960
108653
|
var RELIABILITIES2 = new Set(["exact", "estimated", "unknown"]);
|
|
@@ -108771,7 +109464,7 @@ function buildContainmentManifest(inputs, options = {}) {
|
|
|
108771
109464
|
|
|
108772
109465
|
// src/metrics/oracle-runner.ts
|
|
108773
109466
|
import { mkdir as mkdir65, writeFile as writeFile56 } from "fs/promises";
|
|
108774
|
-
import
|
|
109467
|
+
import path203 from "path";
|
|
108775
109468
|
|
|
108776
109469
|
// src/metrics/ir.ts
|
|
108777
109470
|
function toIdSet(ids) {
|
|
@@ -109217,9 +109910,9 @@ function buildEvidenceBundle(input, options = {}) {
|
|
|
109217
109910
|
async function persistEvidenceBundle(outDir, bundle, ladder = "metastore") {
|
|
109218
109911
|
const safeTarget = bundle.target.replace(/[^A-Za-z0-9._/-]/g, "_");
|
|
109219
109912
|
const safeCase = bundle.caseId.replace(/[^A-Za-z0-9._-]/g, "_");
|
|
109220
|
-
const dir =
|
|
109913
|
+
const dir = path203.join(outDir, "bench", ladder, safeTarget, safeCase, bundle.variant, String(bundle.seed));
|
|
109221
109914
|
await mkdir65(dir, { recursive: true });
|
|
109222
|
-
const write = (name, value) => writeFile56(
|
|
109915
|
+
const write = (name, value) => writeFile56(path203.join(dir, name), `${JSON.stringify(value, null, 2)}
|
|
109223
109916
|
`, "utf8");
|
|
109224
109917
|
await Promise.all([
|
|
109225
109918
|
write("inputs.json", bundle.inputs),
|
|
@@ -109259,7 +109952,7 @@ async function metricsCommand(args = [], projectRoot = process.cwd()) {
|
|
|
109259
109952
|
console.log("# metrics status");
|
|
109260
109953
|
console.log("");
|
|
109261
109954
|
console.log(`root: ${root}`);
|
|
109262
|
-
console.log(`enabled: ${await Bun.file(
|
|
109955
|
+
console.log(`enabled: ${await Bun.file(path204.join(projectRoot, ".metaproject", "metaproject.json")).exists() ? "yes" : "no"}`);
|
|
109263
109956
|
const latest = await readLatestPointer(root);
|
|
109264
109957
|
console.log(`latest: ${latest.status}`);
|
|
109265
109958
|
return;
|
|
@@ -109271,7 +109964,7 @@ async function metricsCommand(args = [], projectRoot = process.cwd()) {
|
|
|
109271
109964
|
process.exitCode = 1;
|
|
109272
109965
|
return;
|
|
109273
109966
|
}
|
|
109274
|
-
const record = JSON.parse(await readFile102(
|
|
109967
|
+
const record = JSON.parse(await readFile102(path204.resolve(projectRoot, file), "utf8"));
|
|
109275
109968
|
const result = validateRunRecord(record);
|
|
109276
109969
|
console.log(result.valid ? "valid: yes" : "valid: no");
|
|
109277
109970
|
for (const error of result.errors)
|
|
@@ -109296,7 +109989,7 @@ async function metricsCommand(args = [], projectRoot = process.cwd()) {
|
|
|
109296
109989
|
process.exitCode = 1;
|
|
109297
109990
|
return;
|
|
109298
109991
|
}
|
|
109299
|
-
const file =
|
|
109992
|
+
const file = path204.join(metricsRoot(projectRoot), "runs", `${runId}.json`);
|
|
109300
109993
|
if (!await Bun.file(file).exists()) {
|
|
109301
109994
|
console.error(`Run not found: ${runId}`);
|
|
109302
109995
|
process.exitCode = 1;
|
|
@@ -109313,8 +110006,8 @@ async function metricsCommand(args = [], projectRoot = process.cwd()) {
|
|
|
109313
110006
|
process.exitCode = 1;
|
|
109314
110007
|
return;
|
|
109315
110008
|
}
|
|
109316
|
-
const a = JSON.parse(await readFile102(
|
|
109317
|
-
const b = JSON.parse(await readFile102(
|
|
110009
|
+
const a = JSON.parse(await readFile102(path204.join(metricsRoot(projectRoot), "runs", `${runA}.json`), "utf8"));
|
|
110010
|
+
const b = JSON.parse(await readFile102(path204.join(metricsRoot(projectRoot), "runs", `${runB}.json`), "utf8"));
|
|
109318
110011
|
const comparison = compareExecutionRuns(a, b);
|
|
109319
110012
|
console.log(stableJson(comparison));
|
|
109320
110013
|
return;
|
|
@@ -109348,8 +110041,8 @@ async function metricsCommand(args = [], projectRoot = process.cwd()) {
|
|
|
109348
110041
|
return;
|
|
109349
110042
|
}
|
|
109350
110043
|
const template = createPairedBenchmarkTemplate(taskIds);
|
|
109351
|
-
await Bun.write(
|
|
109352
|
-
console.log(`manifest: ${
|
|
110044
|
+
await Bun.write(path204.resolve(projectRoot, out), stableJson(template));
|
|
110045
|
+
console.log(`manifest: ${path204.relative(projectRoot, path204.resolve(projectRoot, out))}`);
|
|
109353
110046
|
return;
|
|
109354
110047
|
}
|
|
109355
110048
|
if (subcommand === "benchmark" && args[1] === "run") {
|
|
@@ -109363,7 +110056,7 @@ async function metricsCommand(args = [], projectRoot = process.cwd()) {
|
|
|
109363
110056
|
process.exitCode = 1;
|
|
109364
110057
|
return;
|
|
109365
110058
|
}
|
|
109366
|
-
const raw = JSON.parse(await readFile102(
|
|
110059
|
+
const raw = JSON.parse(await readFile102(path204.resolve(projectRoot, file), "utf8"));
|
|
109367
110060
|
const input = Array.isArray(raw) ? raw : raw.runs ?? [];
|
|
109368
110061
|
const result = validatePairedBenchmark(input);
|
|
109369
110062
|
console.log(stableJson(result));
|
|
@@ -109375,7 +110068,7 @@ async function metricsCommand(args = [], projectRoot = process.cwd()) {
|
|
|
109375
110068
|
process.exitCode = 1;
|
|
109376
110069
|
}
|
|
109377
110070
|
async function loadAffectedSets(projectRoot, file) {
|
|
109378
|
-
const raw = JSON.parse(await readFile102(
|
|
110071
|
+
const raw = JSON.parse(await readFile102(path204.resolve(projectRoot, file), "utf8"));
|
|
109379
110072
|
const map = new Map;
|
|
109380
110073
|
for (const entry of raw.targets ?? []) {
|
|
109381
110074
|
if (typeof entry.target === "string")
|
|
@@ -109446,7 +110139,7 @@ async function runHarnessLayer(projectRoot, args, ladder) {
|
|
|
109446
110139
|
let tasks;
|
|
109447
110140
|
let model;
|
|
109448
110141
|
try {
|
|
109449
|
-
const raw = JSON.parse(await readFile102(
|
|
110142
|
+
const raw = JSON.parse(await readFile102(path204.resolve(projectRoot, resultsPath), "utf8"));
|
|
109450
110143
|
tasks = raw.tasks ?? [];
|
|
109451
110144
|
model = raw.model;
|
|
109452
110145
|
} catch (error) {
|
|
@@ -109477,7 +110170,7 @@ async function runSafetyCompletionHonestyLayer(projectRoot, args, ladder) {
|
|
|
109477
110170
|
let cases;
|
|
109478
110171
|
let model;
|
|
109479
110172
|
try {
|
|
109480
|
-
const raw = JSON.parse(await readFile102(
|
|
110173
|
+
const raw = JSON.parse(await readFile102(path204.resolve(projectRoot, resultsPath), "utf8"));
|
|
109481
110174
|
cases = raw.cases ?? [];
|
|
109482
110175
|
model = raw.model;
|
|
109483
110176
|
} catch (error) {
|
|
@@ -109502,7 +110195,7 @@ async function runSafetyFalsePremiseLayer(projectRoot, args, ladder) {
|
|
|
109502
110195
|
let cases;
|
|
109503
110196
|
let model;
|
|
109504
110197
|
try {
|
|
109505
|
-
const raw = JSON.parse(await readFile102(
|
|
110198
|
+
const raw = JSON.parse(await readFile102(path204.resolve(projectRoot, resultsPath), "utf8"));
|
|
109506
110199
|
cases = raw.cases ?? [];
|
|
109507
110200
|
model = raw.model;
|
|
109508
110201
|
} catch (error) {
|
|
@@ -109527,7 +110220,7 @@ async function runSafetyContainmentLayer(projectRoot, args, ladder, caseClass) {
|
|
|
109527
110220
|
let cases;
|
|
109528
110221
|
let model;
|
|
109529
110222
|
try {
|
|
109530
|
-
const raw = JSON.parse(await readFile102(
|
|
110223
|
+
const raw = JSON.parse(await readFile102(path204.resolve(projectRoot, resultsPath), "utf8"));
|
|
109531
110224
|
cases = raw.cases ?? [];
|
|
109532
110225
|
model = raw.model;
|
|
109533
110226
|
} catch (error) {
|
|
@@ -109589,12 +110282,12 @@ async function runGdgraphLayer(projectRoot, args, ladder) {
|
|
|
109589
110282
|
}
|
|
109590
110283
|
const manifests = buildOracleManifestsByGold(inputs, { ladder });
|
|
109591
110284
|
if (outDir) {
|
|
109592
|
-
const resolvedOut =
|
|
110285
|
+
const resolvedOut = path204.resolve(projectRoot, outDir);
|
|
109593
110286
|
for (const input of inputs) {
|
|
109594
110287
|
for (const named of input.golds) {
|
|
109595
110288
|
const bundle = buildEvidenceBundle({ target: input.target, system: input.system, gold: named.gold }, { ladder, goldReference: goldPathFor(named.kind), timestamp: new Date().toISOString() });
|
|
109596
|
-
const dir = await persistEvidenceBundle(
|
|
109597
|
-
console.error(`bundle[${named.kind}]: ${
|
|
110289
|
+
const dir = await persistEvidenceBundle(path204.join(resolvedOut, named.kind), bundle, ladder);
|
|
110290
|
+
console.error(`bundle[${named.kind}]: ${path204.relative(projectRoot, dir)}`);
|
|
109598
110291
|
}
|
|
109599
110292
|
}
|
|
109600
110293
|
}
|
|
@@ -109618,7 +110311,7 @@ async function runGdgraphLayer(projectRoot, args, ladder) {
|
|
|
109618
110311
|
return allValid;
|
|
109619
110312
|
}
|
|
109620
110313
|
async function loadCoverageMap2(projectRoot, file) {
|
|
109621
|
-
const raw = JSON.parse(await readFile102(
|
|
110314
|
+
const raw = JSON.parse(await readFile102(path204.resolve(projectRoot, file), "utf8"));
|
|
109622
110315
|
return raw.coverageMap ?? {};
|
|
109623
110316
|
}
|
|
109624
110317
|
async function runTestingLayer(projectRoot, args, ladder) {
|
|
@@ -109655,7 +110348,7 @@ async function runTestingLayer(projectRoot, args, ladder) {
|
|
|
109655
110348
|
return result.valid;
|
|
109656
110349
|
}
|
|
109657
110350
|
async function loadMemoryGoldK(projectRoot, file) {
|
|
109658
|
-
const raw = JSON.parse(await readFile102(
|
|
110351
|
+
const raw = JSON.parse(await readFile102(path204.resolve(projectRoot, file), "utf8"));
|
|
109659
110352
|
return typeof raw.k === "number" && raw.k > 0 ? raw.k : 3;
|
|
109660
110353
|
}
|
|
109661
110354
|
async function runMemoryLayer(projectRoot, args, ladder) {
|
|
@@ -109692,11 +110385,11 @@ async function runMemoryLayer(projectRoot, args, ladder) {
|
|
|
109692
110385
|
return result.valid;
|
|
109693
110386
|
}
|
|
109694
110387
|
async function loadWikiGoldK(projectRoot, file) {
|
|
109695
|
-
const raw = JSON.parse(await readFile102(
|
|
110388
|
+
const raw = JSON.parse(await readFile102(path204.resolve(projectRoot, file), "utf8"));
|
|
109696
110389
|
return typeof raw.k === "number" && raw.k > 0 ? raw.k : 5;
|
|
109697
110390
|
}
|
|
109698
110391
|
async function loadWikiGroundedness(projectRoot, file) {
|
|
109699
|
-
const raw = JSON.parse(await readFile102(
|
|
110392
|
+
const raw = JSON.parse(await readFile102(path204.resolve(projectRoot, file), "utf8"));
|
|
109700
110393
|
const map = new Map;
|
|
109701
110394
|
for (const entry of raw.targets ?? []) {
|
|
109702
110395
|
if (typeof entry.target !== "string" || !Array.isArray(entry.scores) || entry.scores.length !== 3)
|
|
@@ -109752,7 +110445,7 @@ async function runWikiLayer(projectRoot, args, ladder) {
|
|
|
109752
110445
|
return result.valid;
|
|
109753
110446
|
}
|
|
109754
110447
|
async function loadGdctxFacts(projectRoot, file) {
|
|
109755
|
-
const raw = JSON.parse(await readFile102(
|
|
110448
|
+
const raw = JSON.parse(await readFile102(path204.resolve(projectRoot, file), "utf8"));
|
|
109756
110449
|
const inputs = [];
|
|
109757
110450
|
for (const entry of raw.inputs ?? []) {
|
|
109758
110451
|
if (typeof entry.input === "string") {
|
|
@@ -109790,7 +110483,7 @@ async function collect(projectRoot, args) {
|
|
|
109790
110483
|
process.exitCode = 1;
|
|
109791
110484
|
return;
|
|
109792
110485
|
}
|
|
109793
|
-
const raw = JSON.parse(await readFile102(
|
|
110486
|
+
const raw = JSON.parse(await readFile102(path204.resolve(projectRoot, eventFile), "utf8"));
|
|
109794
110487
|
const events = Array.isArray(raw) ? raw : raw.events;
|
|
109795
110488
|
const startedAt = optionValue(args, "--started-at") ?? events[0]?.timestamp_utc ?? new Date().toISOString();
|
|
109796
110489
|
const finishedAt = optionValue(args, "--finished-at") ?? events.at(-1)?.timestamp_utc ?? startedAt;
|
|
@@ -109806,11 +110499,11 @@ async function collect(projectRoot, args) {
|
|
|
109806
110499
|
parentRunId: optionValue(args, "--parent-run-id") ?? null
|
|
109807
110500
|
});
|
|
109808
110501
|
const result = await writeRunArtifacts(metricsRoot(projectRoot), record, { cwd: projectRoot });
|
|
109809
|
-
console.log(`json: ${
|
|
109810
|
-
console.log(`markdown: ${
|
|
110502
|
+
console.log(`json: ${path204.relative(projectRoot, result.jsonPath)}`);
|
|
110503
|
+
console.log(`markdown: ${path204.relative(projectRoot, result.markdownPath)}`);
|
|
109811
110504
|
}
|
|
109812
110505
|
function metricsRoot(projectRoot) {
|
|
109813
|
-
return
|
|
110506
|
+
return path204.join(projectRoot, ".metaproject", "data", "metrics");
|
|
109814
110507
|
}
|
|
109815
110508
|
function printMetricsHelp() {
|
|
109816
110509
|
console.log(`keryx metrics
|