@mrciphersmith/keryx 0.2.120 → 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.
Files changed (2) hide show
  1. package/dist/cli.js +1012 -220
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -29500,6 +29500,7 @@ async function runAgentTurnCore(io, deps, history, userLine, options = {}) {
29500
29500
  const spawnConcurrencyCandidates = calls.filter((call) => call.name === "spawn_subagent" && reservationByCallId.get(call.id)?.ok === true);
29501
29501
  const untrustedGateBlocksSpawns = untrustedContentSeen || batchContainsUntrustedWeb;
29502
29502
  const concurrentSpawnResults = spawnConcurrencyCandidates.length >= 2 && !untrustedGateBlocksSpawns && maxToolCalls === undefined ? await runConcurrentSpawnBatch(spawnConcurrencyCandidates, toolByName, io, deps, hasInvocationCapacity, reserveInvocation) : undefined;
29503
+ const answeredToolIds = new Set;
29503
29504
  let anchorsToAnnounce;
29504
29505
  let repeatedFailureHint;
29505
29506
  for (const call of calls) {
@@ -29507,6 +29508,26 @@ async function runAgentTurnCore(io, deps, history, userLine, options = {}) {
29507
29508
  system(`
29508
29509
  [stopped] Model turn interrupted by user.
29509
29510
  `);
29511
+ if (concurrentSpawnResults !== undefined) {
29512
+ for (const spawnCall of spawnConcurrencyCandidates) {
29513
+ if (answeredToolIds.has(spawnCall.id)) {
29514
+ continue;
29515
+ }
29516
+ const settled = concurrentSpawnResults.get(spawnCall.id);
29517
+ if (settled === undefined) {
29518
+ continue;
29519
+ }
29520
+ io.onToolResult?.(spawnCall.name, settled);
29521
+ history.push({
29522
+ role: "tool",
29523
+ content: redactSensitiveText(settled.output),
29524
+ provenance: "tool",
29525
+ toolCallId: spawnCall.id,
29526
+ ts: now()
29527
+ });
29528
+ io.onHistoryChange?.("tool");
29529
+ }
29530
+ }
29510
29531
  return {};
29511
29532
  }
29512
29533
  if (deps.unattended === true && call.name === "ask_user") {
@@ -29549,6 +29570,7 @@ ${modelOutput}` : modelOutput,
29549
29570
  ts: now()
29550
29571
  });
29551
29572
  io.onHistoryChange?.("tool");
29573
+ answeredToolIds.add(call.id);
29552
29574
  if (untrusted) {
29553
29575
  untrustedContentSeen = true;
29554
29576
  }
@@ -42958,6 +42980,103 @@ async function startStdioTransport(server) {
42958
42980
  await server.connect(transport);
42959
42981
  }
42960
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
+
42961
43080
  // src/lib/oauth/device-code.ts
42962
43081
  function requestInit(base, signal) {
42963
43082
  return signal === undefined ? base : { ...base, signal };
@@ -43450,6 +43569,259 @@ var init_login = __esm(() => {
43450
43569
  SESSION_REFRESHED_GRANTS = ["grok", "github-copilot"];
43451
43570
  });
43452
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
+
43453
43825
  // src/cli.ts
43454
43826
  init_single_turn();
43455
43827
  init_model_turn_port();
@@ -50252,7 +50624,7 @@ import path47 from "path";
50252
50624
  // package.json
50253
50625
  var package_default = {
50254
50626
  name: "@mrciphersmith/keryx",
50255
- version: "0.2.120",
50627
+ version: "0.2.122",
50256
50628
  description: "Version-controlled project context for AI coding agents: code graph, architecture wiki, project memory, relevant tests, quality signals, and task flows.",
50257
50629
  private: false,
50258
50630
  publishConfig: {
@@ -90528,6 +90900,9 @@ function classifyBusyDispatch(params) {
90528
90900
  return "not-a-command";
90529
90901
  }
90530
90902
 
90903
+ // src/tui/tui-shell.ts
90904
+ init_debug_log();
90905
+
90531
90906
  // src/tui/boot-animation.ts
90532
90907
  var DEFAULT_BOOT_DURATION_MS = 350;
90533
90908
  var WORDMARK = ["========================", " K E R Y X ", "========================"];
@@ -94028,10 +94403,10 @@ function describeElicitationPrompt(tool, inputJson) {
94028
94403
  // src/lib/permission-mode-config.ts
94029
94404
  init_permission_mode();
94030
94405
  init_config_dir();
94031
- import path192 from "path";
94406
+ import path193 from "path";
94032
94407
  var EMPTY3 = { schemaVersion: 1, projects: {} };
94033
94408
  function permissionModeConfigPath(dir) {
94034
- return path192.join(keryxConfigDir(dir), "permission-mode.json");
94409
+ return path193.join(keryxConfigDir(dir), "permission-mode.json");
94035
94410
  }
94036
94411
  function withRegistryLock2(dir, fn) {
94037
94412
  return withFileLock2(`${permissionModeConfigPath(dir)}.lock`, fn, {
@@ -94275,6 +94650,7 @@ function createForegroundAgentIoFacade(owner, token, io) {
94275
94650
  }
94276
94651
 
94277
94652
  // src/tui/herdr-report.ts
94653
+ init_debug_log();
94278
94654
  import net from "net";
94279
94655
  var SOURCE = "herdr:keryx";
94280
94656
  var AGENT = "keryx";
@@ -94314,6 +94690,7 @@ function createHerdrReporter(clock = () => Date.now(), connect = writeOnce) {
94314
94690
  if (state === last)
94315
94691
  return;
94316
94692
  last = state;
94693
+ debugEvent("herdr.report", { state });
94317
94694
  send("pane.report_agent", { state });
94318
94695
  },
94319
94696
  release() {
@@ -94349,6 +94726,14 @@ function writeOnce(socketPath, request) {
94349
94726
  }
94350
94727
 
94351
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
+ }
94352
94737
  var MAX_SUBTITLE_CHARS = 8000;
94353
94738
  var MAX_SUBTITLE_ROWS = 10;
94354
94739
  var SUBTITLE_INLINE_MAX_CHARS = 76;
@@ -94358,8 +94743,55 @@ function onKeypress2(r, handler) {
94358
94743
  r._internalKeyInput.onInternal("keypress", handler);
94359
94744
  return () => r._internalKeyInput.offInternal("keypress", handler);
94360
94745
  }
94361
- function showComposerChoice(otui, r, dock, request) {
94746
+ var dockChain = new WeakMap;
94747
+ var dockDepth = new WeakMap;
94748
+ function dockBusy(dock) {
94749
+ return (dockDepth.get(dock) ?? 0) > 0;
94750
+ }
94751
+ function lockDock(dock) {
94752
+ dockDepth.set(dock, (dockDepth.get(dock) ?? 0) + 1);
94753
+ const prev = dockChain.get(dock) ?? Promise.resolve();
94754
+ let release;
94755
+ const mine = new Promise((resolve) => {
94756
+ release = resolve;
94757
+ });
94758
+ dockChain.set(dock, prev.then(() => mine));
94759
+ return prev.then(() => {
94760
+ return () => {
94761
+ const n = (dockDepth.get(dock) ?? 1) - 1;
94762
+ if (n <= 0) {
94763
+ dockDepth.delete(dock);
94764
+ } else {
94765
+ dockDepth.set(dock, n);
94766
+ }
94767
+ release();
94768
+ };
94769
+ });
94770
+ }
94771
+ async function showComposerChoice(otui, r, dock, request) {
94772
+ const enqueue = request.enqueue !== false;
94773
+ if (!enqueue && dockBusy(dock)) {
94774
+ debugEvent("choice.busy-cancel", { title: request.title });
94775
+ request.onBusy?.();
94776
+ return request.cancelId;
94777
+ }
94778
+ const queuedAt = Date.now();
94779
+ debugEvent("choice.request", { title: request.title, waitingBehind: dockDepth.get(dock) ?? 0 });
94780
+ const unlock = await lockDock(dock);
94781
+ debugEvent("choice.lock-acquired", { title: request.title, waitedMs: Date.now() - queuedAt });
94782
+ try {
94783
+ if (request.signal?.aborted === true) {
94784
+ debugEvent("choice.aborted-before-open", { title: request.title });
94785
+ return request.cancelId;
94786
+ }
94787
+ return await presentComposerChoice(otui, r, dock, request);
94788
+ } finally {
94789
+ unlock();
94790
+ }
94791
+ }
94792
+ function presentComposerChoice(otui, r, dock, request) {
94362
94793
  if (dock.visible === true) {
94794
+ debugEvent("choice.dock-already-visible", { title: request.title });
94363
94795
  request.onBusy?.();
94364
94796
  return Promise.resolve(request.cancelId);
94365
94797
  }
@@ -94371,6 +94803,10 @@ function showComposerChoice(otui, r, dock, request) {
94371
94803
  const recommendedIdx = options.findIndex((o) => o.recommended === true);
94372
94804
  let selected = recommendedIdx >= 0 ? recommendedIdx : 0;
94373
94805
  dock.visible = true;
94806
+ const openedAt = Date.now();
94807
+ const acceptDelayMs = resolveAcceptDelay(request);
94808
+ let lastTypedAt = 0;
94809
+ request.onOpen?.();
94374
94810
  const theme = getTheme();
94375
94811
  const rawSubtitle = request.subtitle !== undefined && request.subtitle.length > 0 ? request.subtitle : undefined;
94376
94812
  const subtitleText = rawSubtitle !== undefined && rawSubtitle.length > MAX_SUBTITLE_CHARS ? `${rawSubtitle.slice(0, MAX_SUBTITLE_CHARS)}
@@ -94435,7 +94871,16 @@ function showComposerChoice(otui, r, dock, request) {
94435
94871
  }
94436
94872
  }
94437
94873
  };
94438
- const finish = (id) => {
94874
+ let settled = false;
94875
+ const onAbort = () => {
94876
+ finish(request.cancelId, "abort");
94877
+ };
94878
+ const finish = (id, via = "key") => {
94879
+ if (settled) {
94880
+ return;
94881
+ }
94882
+ settled = true;
94883
+ debugEvent("choice.finish", { title: request.title, id, via, openMs: Date.now() - openedAt });
94439
94884
  cleanup();
94440
94885
  resolve(id);
94441
94886
  };
@@ -94446,7 +94891,7 @@ function showComposerChoice(otui, r, dock, request) {
94446
94891
  width: "100%",
94447
94892
  flexDirection: "column",
94448
94893
  onMouseDown: () => {
94449
- finish(o.id);
94894
+ finish(o.id, "click");
94450
94895
  }
94451
94896
  });
94452
94897
  const label = new otui.TextRenderable(r, { id: `ch-opt-l-${i}-${Date.now()}`, content: o.displayLabel });
@@ -94487,6 +94932,7 @@ function showComposerChoice(otui, r, dock, request) {
94487
94932
  function cleanup() {
94488
94933
  closed = true;
94489
94934
  unsub();
94935
+ request.signal?.removeEventListener("abort", onAbort);
94490
94936
  try {
94491
94937
  dock.remove(title);
94492
94938
  if (subtitleScroll !== undefined) {
@@ -94503,8 +94949,11 @@ function showComposerChoice(otui, r, dock, request) {
94503
94949
  dock.visible = false;
94504
94950
  }
94505
94951
  const onKey = (key) => {
94952
+ if (!key.ctrl && typeof key.sequence === "string" && key.sequence.length === 1 && key.sequence >= " ") {
94953
+ lastTypedAt = Date.now();
94954
+ }
94506
94955
  if (key.name === "escape") {
94507
- finish(request.cancelId);
94956
+ finish(request.cancelId, "escape");
94508
94957
  key.preventDefault();
94509
94958
  key.stopPropagation();
94510
94959
  return;
@@ -94523,7 +94972,7 @@ function showComposerChoice(otui, r, dock, request) {
94523
94972
  }
94524
94973
  const focused = r.currentFocusedRenderable;
94525
94974
  const inScroll = subtitleScroll !== undefined && focused !== null && containsNode(subtitleScroll, focused);
94526
- if (inScroll) {
94975
+ if (inScroll && key.name !== "return" && key.name !== "linefeed" && key.name !== "kpenter") {
94527
94976
  return;
94528
94977
  }
94529
94978
  if (key.name === "up") {
@@ -94541,6 +94990,17 @@ function showComposerChoice(otui, r, dock, request) {
94541
94990
  return;
94542
94991
  }
94543
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
+ }
94544
95004
  const chosen = options[selected];
94545
95005
  if (chosen !== undefined) {
94546
95006
  finish(chosen.id);
@@ -94550,14 +95010,24 @@ function showComposerChoice(otui, r, dock, request) {
94550
95010
  }
94551
95011
  };
94552
95012
  const unsub = onKeypress2(r, onKey);
95013
+ if (request.signal !== undefined) {
95014
+ request.signal.addEventListener("abort", onAbort, { once: true });
95015
+ }
94553
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
+ });
94554
95024
  });
94555
95025
  }
94556
95026
 
94557
95027
  // src/lib/version-check.ts
94558
95028
  init_config_dir();
94559
95029
  init_fs();
94560
- import path193 from "path";
95030
+ import path194 from "path";
94561
95031
  var REGISTRY_URL = "https://registry.npmjs.org/@mrciphersmith%2Fkeryx/latest";
94562
95032
  var FIXED_INSTALL_COMMAND = "npm install -g @mrciphersmith/keryx@latest";
94563
95033
  var RESPONSE_BODY_LIMIT_BYTES = 64 * 1024;
@@ -94759,7 +95229,7 @@ async function checkVersion(options) {
94759
95229
  const now = options.now ?? Date.now;
94760
95230
  const timestamp = now();
94761
95231
  const configDir = ensureKeryxConfigDir(options.cacheDir);
94762
- const cacheFile = path193.join(configDir, "version-check.json");
95232
+ const cacheFile = path194.join(configDir, "version-check.json");
94763
95233
  const cache = parseCache(cacheFile);
94764
95234
  if (cache?.latestVersion !== undefined && cache.successAt !== undefined && timestamp - cache.successAt >= 0 && timestamp - cache.successAt < SUCCESS_CACHE_TTL_MS) {
94765
95235
  return resultFor(options.currentVersion, current, cache.latestVersion, "cache");
@@ -94827,6 +95297,236 @@ async function checkVersion(options) {
94827
95297
  return resultFor(options.currentVersion, current, latestVersion, "registry");
94828
95298
  }
94829
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
+
94830
95530
  // src/tui/shell-chrome.ts
94831
95531
  function onKeypress3(r, handler) {
94832
95532
  r._internalKeyInput.onInternal("keypress", handler);
@@ -94932,14 +95632,20 @@ function prefixFilter(commands, query) {
94932
95632
  return commands.filter((c) => c.name.slice(1).toLowerCase().startsWith(needle));
94933
95633
  }
94934
95634
  async function createShellRenderer(otui, opts = {}) {
94935
- return await otui.createCliRenderer({
95635
+ const guards = {};
95636
+ const renderer = await otui.createCliRenderer({
94936
95637
  exitOnCtrlC: true,
94937
95638
  screenMode: "alternate-screen",
94938
95639
  clearOnShutdown: true,
94939
95640
  useMouse: true,
94940
95641
  backgroundColor: getTheme().bg,
94941
- ...opts.onDestroy !== undefined ? { onDestroy: opts.onDestroy } : {}
95642
+ onDestroy: () => {
95643
+ guards.detach?.();
95644
+ opts.onDestroy?.();
95645
+ }
94942
95646
  });
95647
+ guards.detach = attachRendererGuards(renderer);
95648
+ return renderer;
94943
95649
  }
94944
95650
  async function createShellChrome(otui, renderer, opts) {
94945
95651
  const r = renderer;
@@ -95102,10 +95808,12 @@ async function createShellChrome(otui, renderer, opts) {
95102
95808
  };
95103
95809
  const withOverlay = async (run) => {
95104
95810
  overlayDepth += 1;
95811
+ debugEvent("overlay.enter", { depth: overlayDepth, dockVisible: dock.visible });
95105
95812
  try {
95106
95813
  return await run();
95107
95814
  } finally {
95108
95815
  overlayDepth -= 1;
95816
+ debugEvent("overlay.exit", { depth: overlayDepth, dockVisible: dock.visible });
95109
95817
  }
95110
95818
  };
95111
95819
  const addOverlaySource = (isActive) => {
@@ -95353,7 +96061,12 @@ async function createShellChrome(otui, renderer, opts) {
95353
96061
  }
95354
96062
  });
95355
96063
  textarea.onSubmit = () => {
96064
+ if (overlayActive()) {
96065
+ debugEvent("composer.submit-blocked", { reason: "overlay active", dockVisible: dock.visible, overlayDepth });
96066
+ return;
96067
+ }
95356
96068
  const line = input.value.trim();
96069
+ debugEvent("composer.submit", { chars: line.length, slash: line.startsWith("/") });
95357
96070
  input.value = "";
95358
96071
  hideMenu();
95359
96072
  syncComposerHeight();
@@ -95471,6 +96184,15 @@ async function createShellChrome(otui, renderer, opts) {
95471
96184
  appliedTheme = theme;
95472
96185
  };
95473
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
+ }
95474
96196
  return {
95475
96197
  renderer: r,
95476
96198
  root: rootRow,
@@ -98035,6 +98757,7 @@ function attachBlockIo(io, addBlock, chrome = {}, thinkDisplay = () => "auto") {
98035
98757
  });
98036
98758
  };
98037
98759
  io.onToolCall = (name, input) => {
98760
+ debugEvent("tool.call", { name, inputChars: input.length });
98038
98761
  chrome.onToolCall?.(name, input);
98039
98762
  const args = summarizeToolArgs(input);
98040
98763
  addBlock({
@@ -98046,6 +98769,7 @@ function attachBlockIo(io, addBlock, chrome = {}, thinkDisplay = () => "auto") {
98046
98769
  }, { hint: "ctrl+o", tone: "cyan" });
98047
98770
  };
98048
98771
  io.onToolResult = (name, result) => {
98772
+ debugEvent("tool.result", { name, isError: result.isError === true, outputChars: result.output.length });
98049
98773
  chrome.onToolResult?.(name, result);
98050
98774
  const { summary, lineCount, hidden } = collapseToolOutput(result.output);
98051
98775
  const more = hidden > 0 ? ` \xB7 +${hidden} more` : "";
@@ -98148,7 +98872,7 @@ function createApprovalContextLoader(cwd) {
98148
98872
  return buildApprovalContext(port, command);
98149
98873
  };
98150
98874
  }
98151
- async function pickShellApproval(otui, r, dock, command, loadContext, destructive = false, credentials = false) {
98875
+ async function pickShellApproval(otui, r, dock, command, loadContext, destructive = false, credentials = false, ui = {}) {
98152
98876
  let context;
98153
98877
  try {
98154
98878
  context = loadContext(command);
@@ -98188,7 +98912,9 @@ async function pickShellApproval(otui, r, dock, command, loadContext, destructiv
98188
98912
  subtitle: command,
98189
98913
  ...context !== undefined ? { context } : {},
98190
98914
  cancelId: "deny",
98191
- options
98915
+ options,
98916
+ ...ui.onOpen !== undefined ? { onOpen: ui.onOpen } : {},
98917
+ ...ui.signal !== undefined ? { signal: ui.signal } : {}
98192
98918
  });
98193
98919
  if (id === "once" || id === "always-exact" || id === "always-prefix" || id === "deny") {
98194
98920
  return id;
@@ -98211,6 +98937,9 @@ async function applyRuntimeSwitchToSlate(params) {
98211
98937
  params.onHistoryChange?.("tool");
98212
98938
  return true;
98213
98939
  }
98940
+ function freshSlateSessionRef(sessionDir, cwd) {
98941
+ return { dir: sessionDir, cwd, opened: false };
98942
+ }
98214
98943
  function fmtTokens(n) {
98215
98944
  return n >= 1000 ? `${(n / 1000).toFixed(1)}K` : String(n);
98216
98945
  }
@@ -99351,6 +100080,7 @@ async function launchTuiAgentShell(opts) {
99351
100080
  let busyStartedAt = 0;
99352
100081
  const setBusyPhase = (phase) => {
99353
100082
  busyPhase = phase;
100083
+ debugEvent("busy.phase", { phase });
99354
100084
  chrome.setBusyPhase(phase);
99355
100085
  };
99356
100086
  const startBusy = (phase = "waiting for model") => {
@@ -99533,10 +100263,12 @@ async function launchTuiAgentShell(opts) {
99533
100263
  chrome.hideMenu();
99534
100264
  setMainAgent("blocked", "approval");
99535
100265
  const preview = request.task.length > 80 ? `${request.task.slice(0, 77)}\u2026` : request.task;
99536
- const id = await showComposerChoice(otui, r, chrome.dock, {
100266
+ const id = await chrome.withOverlay(() => showComposerChoice(otui, r, chrome.dock, {
99537
100267
  title: `Run the external agent ${request.agentId}?`,
99538
100268
  subtitle: preview,
99539
100269
  cancelId: "deny",
100270
+ onOpen: () => chrome.blurComposer(),
100271
+ signal: foregroundOperation.signal,
99540
100272
  options: [
99541
100273
  {
99542
100274
  id: "allow",
@@ -99545,7 +100277,7 @@ async function launchTuiAgentShell(opts) {
99545
100277
  },
99546
100278
  { id: "deny", label: "Deny", description: "Do not start the external agent" }
99547
100279
  ]
99548
- });
100280
+ }));
99549
100281
  input.focus();
99550
100282
  setMainAgent("running", id === "allow" ? "external" : "denied");
99551
100283
  return id === "allow" ? { ok: true } : { ok: false, reason: `you declined the external spawn of ${request.agentId}` };
@@ -99571,6 +100303,7 @@ async function launchTuiAgentShell(opts) {
99571
100303
  })();
99572
100304
  };
99573
100305
  const setMainAgent = (status, detail) => {
100306
+ debugEvent("main-agent", { status, detail });
99574
100307
  fleet.upsert({
99575
100308
  id: MAIN_AGENT_ID,
99576
100309
  label: "main",
@@ -99716,10 +100449,12 @@ async function launchTuiAgentShell(opts) {
99716
100449
  }
99717
100450
  chrome.hideMenu();
99718
100451
  setMainAgent("blocked", "approval");
99719
- const id = await showComposerChoice(otui, r, chrome.dock, {
100452
+ const id = await chrome.withOverlay(() => showComposerChoice(otui, r, chrome.dock, {
99720
100453
  title: "Spawn general subagent?",
99721
100454
  subtitle: taskPreview,
99722
100455
  cancelId: "deny",
100456
+ onOpen: () => chrome.blurComposer(),
100457
+ signal: foregroundOperation.signal,
99723
100458
  options: [
99724
100459
  {
99725
100460
  id: "allow",
@@ -99729,7 +100464,7 @@ async function launchTuiAgentShell(opts) {
99729
100464
  },
99730
100465
  { id: "deny", label: "Deny", description: "Do not spawn" }
99731
100466
  ]
99732
- });
100467
+ }));
99733
100468
  input.focus();
99734
100469
  setMainAgent("running", id === "allow" ? "subagent" : "denied");
99735
100470
  transcript.add(new otui.TextRenderable(r, {
@@ -99758,15 +100493,17 @@ async function launchTuiAgentShell(opts) {
99758
100493
  }
99759
100494
  chrome.hideMenu();
99760
100495
  setMainAgent("blocked", "approval");
99761
- const id = await showComposerChoice(otui, r, chrome.dock, {
100496
+ const id = await chrome.withOverlay(() => showComposerChoice(otui, r, chrome.dock, {
99762
100497
  title: "Approve apply_patch?",
99763
100498
  subtitle: "Diff shown above \xB7 Esc denies",
99764
100499
  cancelId: "deny",
100500
+ onOpen: () => chrome.blurComposer(),
100501
+ signal: foregroundOperation.signal,
99765
100502
  options: [
99766
100503
  { id: "allow", label: "Approve", description: "Write the patch to disk", recommended: true },
99767
100504
  { id: "deny", label: "Deny", description: "Do not write anything" }
99768
100505
  ]
99769
- });
100506
+ }));
99770
100507
  input.focus();
99771
100508
  setMainAgent("running", id === "allow" ? "write" : "denied");
99772
100509
  transcript.add(new otui.TextRenderable(r, {
@@ -99792,15 +100529,17 @@ async function launchTuiAgentShell(opts) {
99792
100529
  }
99793
100530
  chrome.hideMenu();
99794
100531
  setMainAgent("blocked", "approval");
99795
- const id = await showComposerChoice(otui, r, chrome.dock, {
100532
+ const id = await chrome.withOverlay(() => showComposerChoice(otui, r, chrome.dock, {
99796
100533
  title: described.title,
99797
100534
  subtitle: summariseUseToolApproval(described),
99798
100535
  cancelId: "deny",
100536
+ onOpen: () => chrome.blurComposer(),
100537
+ signal: foregroundOperation.signal,
99799
100538
  options: [
99800
100539
  { id: APPROVAL_ALLOW_ID, label: "Approve", description: `run ${described.tool} on ${described.server}` },
99801
100540
  { id: "deny", label: "Deny", description: "the tool call is refused", recommended: true }
99802
100541
  ]
99803
- });
100542
+ }));
99804
100543
  input.focus();
99805
100544
  const allowed = isDockApproval(id);
99806
100545
  setMainAgent("running", allowed ? "write" : "denied");
@@ -99838,15 +100577,17 @@ async function launchTuiAgentShell(opts) {
99838
100577
  chrome.hideMenu();
99839
100578
  setMainAgent("blocked", "approval");
99840
100579
  const elicitationSubtitle = described.message.length > 80 ? `${described.message.slice(0, 77)}\u2026` : described.message;
99841
- const id = await showComposerChoice(otui, r, chrome.dock, {
100580
+ const id = await chrome.withOverlay(() => showComposerChoice(otui, r, chrome.dock, {
99842
100581
  title: "Approve codex elicitation?",
99843
100582
  subtitle: elicitationSubtitle,
99844
100583
  cancelId: "deny",
100584
+ onOpen: () => chrome.blurComposer(),
100585
+ signal: foregroundOperation.signal,
99845
100586
  options: [
99846
100587
  { id: "allow", label: "Approve", description: "codex proceeds with this action", recommended: true },
99847
100588
  { id: "deny", label: "Deny", description: "codex's action is refused" }
99848
100589
  ]
99849
- });
100590
+ }));
99850
100591
  input.focus();
99851
100592
  setMainAgent("running", id === "allow" ? "write" : "denied");
99852
100593
  transcript.add(new otui.TextRenderable(r, {
@@ -99901,7 +100642,10 @@ async function launchTuiAgentShell(opts) {
99901
100642
  setMainAgent("blocked", "approval");
99902
100643
  setBusyPhase("waiting for your approval (menu above input)");
99903
100644
  chrome.hideMenu();
99904
- const choice = await pickShellApproval(otui, r, chrome.dock, cmd, approvalContext, destructive, meta?.credentials === true);
100645
+ const choice = await chrome.withOverlay(() => pickShellApproval(otui, r, chrome.dock, cmd, approvalContext, destructive, meta?.credentials === true, {
100646
+ onOpen: () => chrome.blurComposer(),
100647
+ signal: foregroundOperation.signal
100648
+ }));
99905
100649
  input.focus();
99906
100650
  if (choice === "deny") {
99907
100651
  transcript.add(new otui.TextRenderable(r, {
@@ -99945,17 +100689,19 @@ async function launchTuiAgentShell(opts) {
99945
100689
  id: `ask${uid++}`,
99946
100690
  content: otui.t`${otui.yellow("? ")} ${otui.dim(qShort)}`
99947
100691
  }));
99948
- const chosen = await showComposerChoice(otui, r, chrome.dock, {
100692
+ const chosen = await chrome.withOverlay(() => showComposerChoice(otui, r, chrome.dock, {
99949
100693
  title: req.question.length > 72 ? `${req.question.slice(0, 69)}\u2026` : req.question,
99950
100694
  subtitle: "Pick an option \xB7 Esc cancels",
99951
100695
  cancelId: "__cancel__",
100696
+ onOpen: () => chrome.blurComposer(),
100697
+ signal: foregroundOperation.signal,
99952
100698
  options: req.options.map((o) => ({
99953
100699
  id: o.id,
99954
100700
  label: o.label,
99955
100701
  description: o.description.length > 0 ? o.description : " ",
99956
100702
  ...o.recommended === true ? { recommended: true } : {}
99957
100703
  }))
99958
- });
100704
+ }));
99959
100705
  input.focus();
99960
100706
  if (chosen !== "__cancel__") {
99961
100707
  const picked = req.options.find((o) => o.id === chosen);
@@ -100003,6 +100749,9 @@ async function launchTuiAgentShell(opts) {
100003
100749
  let nextArchiveIndex = 0;
100004
100750
  let sessionPersistTimer;
100005
100751
  let slateSession;
100752
+ const bindSlateToLiveSession = () => {
100753
+ slateSession = freshSlateSessionRef(liveSession.dir, sessionCwd);
100754
+ };
100006
100755
  const onContextCompaction = (r) => {
100007
100756
  const persisted = persistCompacted(liveSession, r.context, archive, {
100008
100757
  provider: currentSel.provider,
@@ -100136,7 +100885,7 @@ async function launchTuiAgentShell(opts) {
100136
100885
  model: currentSel.model
100137
100886
  }));
100138
100887
  }
100139
- slateSession = { dir: liveSession.dir, cwd: sessionCwd, opened: false };
100888
+ bindSlateToLiveSession();
100140
100889
  if (history.length === 0) {
100141
100890
  removeSplash = mountEmptyTranscriptSplash(otui, r, transcript);
100142
100891
  }
@@ -100237,6 +100986,8 @@ Staying in the current session.
100237
100986
  return;
100238
100987
  }
100239
100988
  applyOpened(opened, true);
100989
+ bindSlateToLiveSession();
100990
+ refreshWorkspaceSidebar();
100240
100991
  paintSessionHeader();
100241
100992
  if (opened.archiveDegraded !== undefined) {
100242
100993
  io.onSystem?.(`Archive unavailable \u2014 resumed from the active context (${opened.archiveDegraded})
@@ -100417,14 +101168,15 @@ Staying in the current session.
100417
101168
  title: "Switch to auto mode?",
100418
101169
  subtitle: "Skips confirmation for EVERY action, including destructive commands. Only credential-touching commands still ask.",
100419
101170
  cancelId: "cancel",
100420
- options: [
100421
- { id: "confirm", label: "Confirm", description: "I understand the risk" },
100422
- { id: "cancel", label: "Cancel", description: "Keep the current mode", recommended: true }
100423
- ],
101171
+ enqueue: false,
100424
101172
  onBusy: () => {
100425
101173
  blockedByOpenDialog = true;
100426
101174
  chrome.showToast("Answer the open approval first, then retry /mode.");
100427
- }
101175
+ },
101176
+ options: [
101177
+ { id: "confirm", label: "Confirm", description: "I understand the risk" },
101178
+ { id: "cancel", label: "Cancel", description: "Keep the current mode", recommended: true }
101179
+ ]
100428
101180
  }));
100429
101181
  input.focus();
100430
101182
  if (blockedByOpenDialog) {
@@ -100465,16 +101217,17 @@ Staying in the current session.
100465
101217
  title: `Permission mode (current: ${permissionMode})`,
100466
101218
  subtitle: stored !== undefined ? `Project default: ${stored}` : "No project default set.",
100467
101219
  cancelId: permissionMode,
101220
+ enqueue: false,
101221
+ onBusy: () => {
101222
+ blockedByOpenDialog = true;
101223
+ chrome.showToast("Answer the open approval first, then retry /mode.");
101224
+ },
100468
101225
  options: PERMISSION_MODES.map((m) => ({
100469
101226
  id: m,
100470
101227
  label: m,
100471
101228
  description: MODE_PICKER_DESCRIPTIONS[m],
100472
101229
  recommended: m === permissionMode
100473
- })),
100474
- onBusy: () => {
100475
- blockedByOpenDialog = true;
100476
- chrome.showToast("Answer the open approval first, then retry /mode.");
100477
- }
101230
+ }))
100478
101231
  }));
100479
101232
  input.focus();
100480
101233
  if (blockedByOpenDialog) {
@@ -101067,6 +101820,7 @@ Staying in the current session.
101067
101820
  { id: "side", label: "Side-1", description: "read-only answer, outside main history (as before)" }
101068
101821
  ],
101069
101822
  cancelId: "side",
101823
+ enqueue: false,
101070
101824
  onBusy: () => {
101071
101825
  blockedByOpenDialog = true;
101072
101826
  chrome.showToast("Answer the open approval first, then resend.");
@@ -101132,7 +101886,7 @@ Staying in the current session.
101132
101886
  (async () => {
101133
101887
  await closeSlateSession(slateSession, mintTimestampAttemptId);
101134
101888
  startNewSession();
101135
- slateSession = { dir: liveSession.dir, cwd: sessionCwd, opened: false };
101889
+ bindSlateToLiveSession();
101136
101890
  refreshWorkspaceSidebar();
101137
101891
  refreshReviewSidebar();
101138
101892
  sessions.clear();
@@ -103564,6 +104318,7 @@ function parseShellCliFlags(args) {
103564
104318
  let printPromptArg;
103565
104319
  let eventsFile;
103566
104320
  let eventsMaxField;
104321
+ let debug;
103567
104322
  for (let i = 0;i < args.length; i++) {
103568
104323
  const arg = args[i];
103569
104324
  if (arg === "--provider") {
@@ -103614,6 +104369,8 @@ function parseShellCliFlags(args) {
103614
104369
  i += 1;
103615
104370
  } else if (arg === "--events-file") {
103616
104371
  eventsFile = valueAfter(i++);
104372
+ } else if (arg === "--debug") {
104373
+ debug = true;
103617
104374
  } else if (arg === "--events-max-field") {
103618
104375
  const raw = valueAfter(i++);
103619
104376
  const parsed = Number(raw);
@@ -103643,7 +104400,8 @@ function parseShellCliFlags(args) {
103643
104400
  ...denyTools !== undefined ? { denyTools } : {},
103644
104401
  ...printPromptArg !== undefined ? { printPrompt: printPromptArg } : {},
103645
104402
  ...eventsFile !== undefined ? { eventsFile } : {},
103646
- ...eventsMaxField !== undefined ? { eventsMaxField } : {}
104403
+ ...eventsMaxField !== undefined ? { eventsMaxField } : {},
104404
+ ...debug === true ? { debug: true } : {}
103647
104405
  };
103648
104406
  }
103649
104407
  function chooseShellSurface(flags, isTty) {
@@ -103656,6 +104414,11 @@ function chooseShellSurface(flags, isTty) {
103656
104414
  return flags.modeFlag === false ? "tui-chat" : "tui-agent";
103657
104415
  }
103658
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
+ }
103659
104422
  const flags = parseShellCliFlags(args);
103660
104423
  if (flags.help) {
103661
104424
  console.log(`Usage: keryx shell [options]
@@ -103674,13 +104437,42 @@ async function shellCommand(args, runtime = {}) {
103674
104437
  --print, -p <prompt> Run one agent turn on this prompt and exit
103675
104438
  --events-file <path> Append an NDJSON transcript (turns, tools, usage)
103676
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
103677
104442
 
103678
104443
  Session continuation and resume are mutually exclusive. Permission flags
103679
104444
  are ignored in chat mode. Without a TTY, resume without an ID uses the latest session.
103680
104445
 
104446
+ A shell that stops reacting to keys can be recovered from another terminal
104447
+ with: kill -USR2 <keryx pid>
104448
+
103681
104449
  Example: keryx shell --provider ollama --model llama3.1:latest`);
103682
104450
  return;
103683
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
+ }
103684
104476
  const versionCheck = (runtime.checkVersion ?? (() => checkVersion({
103685
104477
  currentVersion: package_default.version,
103686
104478
  ...runtime.cacheDir !== undefined ? { cacheDir: runtime.cacheDir } : {}
@@ -104201,7 +104993,7 @@ Shell:
104201
104993
  init_fs();
104202
104994
  import { readFile as readFile99 } from "fs/promises";
104203
104995
  import { stdin } from "process";
104204
- import path194 from "path";
104996
+ import path196 from "path";
104205
104997
  var MODULES = [
104206
104998
  { name: "gdgraph", flag: "--no-gdgraph", desc: "code graph, symbols, affected context", defaultEnabled: true },
104207
104999
  { name: "gdctx", flag: "--no-gdctx", desc: "token-aware command/read output", defaultEnabled: true },
@@ -104247,8 +105039,8 @@ async function modulesCommand(args = []) {
104247
105039
  return;
104248
105040
  }
104249
105041
  const wantsJson = args.includes("--json") && (sub === undefined || sub === "status" || sub === "list" || sub === "--json");
104250
- const metaprojectRoot = path194.join(process.cwd(), ".metaproject");
104251
- const manifestPath = path194.join(metaprojectRoot, "metaproject.json");
105042
+ const metaprojectRoot = path196.join(process.cwd(), ".metaproject");
105043
+ const manifestPath = path196.join(metaprojectRoot, "metaproject.json");
104252
105044
  if (!await pathExists(manifestPath)) {
104253
105045
  if (wantsJson) {
104254
105046
  console.log(JSON.stringify({ schemaVersion: 1, error: "not-initialized", modules: [] }, null, 2));
@@ -104370,18 +105162,18 @@ init_config_dir();
104370
105162
  import { createHash as createHash44, randomBytes as randomBytes5, randomUUID as randomUUID30 } from "crypto";
104371
105163
  import {
104372
105164
  chmodSync as chmodSync4,
104373
- closeSync as closeSync3,
105165
+ closeSync as closeSync4,
104374
105166
  existsSync as existsSync34,
104375
105167
  fsyncSync as fsyncSync2,
104376
- openSync as openSync3,
105168
+ openSync as openSync4,
104377
105169
  renameSync as renameSync4,
104378
- statSync as statSync6,
105170
+ statSync as statSync7,
104379
105171
  unlinkSync as unlinkSync3,
104380
105172
  writeFileSync as writeFileSync9
104381
105173
  } from "fs";
104382
- import path195 from "path";
105174
+ import path197 from "path";
104383
105175
  function serveCredentialPath(dir) {
104384
- return path195.join(keryxConfigDir(dir), "serve-credentials.json");
105176
+ return path197.join(keryxConfigDir(dir), "serve-credentials.json");
104385
105177
  }
104386
105178
  function constantTimeEqual(a, b) {
104387
105179
  const width = Math.max(a.length, b.length);
@@ -104410,7 +105202,7 @@ function isGroupOrOtherAccessible(file) {
104410
105202
  if (process.platform === "win32") {
104411
105203
  return false;
104412
105204
  }
104413
- const mode = statSync6(file, { throwIfNoEntry: false })?.mode;
105205
+ const mode = statSync7(file, { throwIfNoEntry: false })?.mode;
104414
105206
  return mode !== undefined && (mode & 63) !== 0;
104415
105207
  }
104416
105208
  function readServeCredential(dir) {
@@ -104454,13 +105246,13 @@ function writeStore(store, dir) {
104454
105246
  const temp = `${file}.${randomUUID30()}.tmp`;
104455
105247
  try {
104456
105248
  ensureKeryxConfigDir(dir);
104457
- const handle = openSync3(temp, "wx", 384);
105249
+ const handle = openSync4(temp, "wx", 384);
104458
105250
  try {
104459
105251
  writeFileSync9(handle, `${JSON.stringify(store, null, 2)}
104460
105252
  `, { encoding: "utf8" });
104461
105253
  fsyncSync2(handle);
104462
105254
  } finally {
104463
- closeSync3(handle);
105255
+ closeSync4(handle);
104464
105256
  }
104465
105257
  renameSync4(temp, file);
104466
105258
  tighten2(file, 384);
@@ -104614,23 +105406,23 @@ class AuthFailureThrottle {
104614
105406
  // src/lib/serve-turn-store.ts
104615
105407
  init_config_dir();
104616
105408
  import { createHash as createHash45 } from "crypto";
104617
- import { existsSync as existsSync35, readdirSync as readdirSync3, rmSync as rmSync2 } from "fs";
104618
- import path196 from "path";
105409
+ import { existsSync as existsSync35, readdirSync as readdirSync4, rmSync as rmSync2 } from "fs";
105410
+ import path198 from "path";
104619
105411
  var MAX_TURN_EVENTS = 1e4;
104620
105412
  function turnsRoot(dir) {
104621
- return path196.join(keryxConfigDir(dir), "turns");
105413
+ return path198.join(keryxConfigDir(dir), "turns");
104622
105414
  }
104623
105415
  function turnDir(turnId, dir) {
104624
- return path196.join(turnsRoot(dir), turnId);
105416
+ return path198.join(turnsRoot(dir), turnId);
104625
105417
  }
104626
105418
  function keyPath(project, idempotencyKey, dir) {
104627
105419
  const projectBytes = Buffer.byteLength(project, "utf8");
104628
105420
  const digest = createHash45("sha256").update(`${projectBytes}:${project}\x00${idempotencyKey}`, "utf8").digest("hex");
104629
- return path196.join(turnsRoot(dir), "keys", `${digest}.json`);
105421
+ return path198.join(turnsRoot(dir), "keys", `${digest}.json`);
104630
105422
  }
104631
105423
  function legacyKeyPath(idempotencyKey, dir) {
104632
105424
  const digest = createHash45("sha256").update(idempotencyKey, "utf8").digest("hex");
104633
- return path196.join(turnsRoot(dir), "keys", `${digest}.json`);
105425
+ return path198.join(turnsRoot(dir), "keys", `${digest}.json`);
104634
105426
  }
104635
105427
  function adoptLegacyClaim(project, idempotencyKey, dir) {
104636
105428
  const legacy = legacyKeyPath(idempotencyKey, dir);
@@ -104694,7 +105486,7 @@ function ensureTurnDir(turnId, dir) {
104694
105486
  }
104695
105487
  function createTurnRecord(record, dir) {
104696
105488
  ensureTurnDir(record.turnId, dir);
104697
- writeOwnerOnlyFile(path196.join(turnDir(record.turnId, dir), "turn.json"), `${JSON.stringify(record, null, 2)}
105489
+ writeOwnerOnlyFile(path198.join(turnDir(record.turnId, dir), "turn.json"), `${JSON.stringify(record, null, 2)}
104698
105490
  `);
104699
105491
  }
104700
105492
  function appendTurnEvent(event, dir, opts) {
@@ -104703,12 +105495,12 @@ function appendTurnEvent(event, dir, opts) {
104703
105495
  }
104704
105496
  const line = JSON.stringify(event);
104705
105497
  try {
104706
- appendOwnerOnlyLine(path196.join(turnDir(event.turnId, dir), "events.jsonl"), line);
105498
+ appendOwnerOnlyLine(path198.join(turnDir(event.turnId, dir), "events.jsonl"), line);
104707
105499
  } catch (error) {
104708
105500
  if (error?.code !== "ENOENT") {
104709
105501
  throw error;
104710
105502
  }
104711
- appendOwnerOnlyLine(path196.join(ensureTurnDir(event.turnId, dir), "events.jsonl"), line);
105503
+ appendOwnerOnlyLine(path198.join(ensureTurnDir(event.turnId, dir), "events.jsonl"), line);
104712
105504
  }
104713
105505
  return true;
104714
105506
  }
@@ -104716,7 +105508,7 @@ function readTurnEvents(turnId, after = -1, dir) {
104716
105508
  if (!isTurnId(turnId)) {
104717
105509
  return { ok: false, reason: "not-a-turn-id" };
104718
105510
  }
104719
- const read = readTurnFile(path196.join(turnDir(turnId, dir), "events.jsonl"));
105511
+ const read = readTurnFile(path198.join(turnDir(turnId, dir), "events.jsonl"));
104720
105512
  if (!read.ok) {
104721
105513
  if (isDefiniteAbsence2(read.reason)) {
104722
105514
  return { ok: true, value: [] };
@@ -104744,7 +105536,7 @@ function readTurnRecord(turnId, dir) {
104744
105536
  if (!isTurnId(turnId)) {
104745
105537
  return { ok: false, reason: "not-a-turn-id" };
104746
105538
  }
104747
- const read = readTurnFile(path196.join(turnDir(turnId, dir), "turn.json"));
105539
+ const read = readTurnFile(path198.join(turnDir(turnId, dir), "turn.json"));
104748
105540
  if (!read.ok) {
104749
105541
  return { ok: false, reason: read.reason };
104750
105542
  }
@@ -104763,7 +105555,7 @@ function finishTurn(turnId, result, dir) {
104763
105555
  if (!record.ok) {
104764
105556
  return false;
104765
105557
  }
104766
- writeOwnerOnlyFile(path196.join(turnDir(turnId, dir), "turn.json"), `${JSON.stringify({ ...record.value, result }, null, 2)}
105558
+ writeOwnerOnlyFile(path198.join(turnDir(turnId, dir), "turn.json"), `${JSON.stringify({ ...record.value, result }, null, 2)}
104767
105559
  `);
104768
105560
  return true;
104769
105561
  }
@@ -104809,7 +105601,7 @@ function releaseIdempotencyKey(project, idempotencyKey, turnId, dir) {
104809
105601
 
104810
105602
  // src/lib/serve-turn.ts
104811
105603
  import { randomUUID as randomUUID31 } from "crypto";
104812
- import path197 from "path";
105604
+ import path199 from "path";
104813
105605
  init_service();
104814
105606
  var REMOTE_ORIGIN = "remote:http";
104815
105607
  var MAX_PROMPT_CHARS = 32000;
@@ -104878,9 +105670,9 @@ function isUuid(value) {
104878
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);
104879
105671
  }
104880
105672
  function resolveProject(declared, dir) {
104881
- const wanted = path197.resolve(declared);
105673
+ const wanted = path199.resolve(declared);
104882
105674
  for (const entry of listProjects(dir, () => {})) {
104883
- if (path197.resolve(entry.path) === wanted) {
105675
+ if (path199.resolve(entry.path) === wanted) {
104884
105676
  return { ok: true, project: entry.path };
104885
105677
  }
104886
105678
  }
@@ -105913,10 +106705,10 @@ function printHelp19() {
105913
106705
  }
105914
106706
 
105915
106707
  // src/commands/update.ts
105916
- import { spawn as spawn6 } from "child_process";
106708
+ import { spawn as spawn7 } from "child_process";
105917
106709
  import { chmod as chmod4, mkdir as mkdir63, readFile as readFile100, readdir as readdir37, writeFile as writeFile54 } from "fs/promises";
105918
- import { access as access4, constants as constants2, existsSync as existsSync36 } from "fs";
105919
- import path198 from "path";
106710
+ import { access as access4, constants as constants3, existsSync as existsSync36 } from "fs";
106711
+ import path200 from "path";
105920
106712
  import { fileURLToPath as fileURLToPath8 } from "url";
105921
106713
  init_config2();
105922
106714
  init_config();
@@ -105933,8 +106725,8 @@ async function updateCommand(args = []) {
105933
106725
  return;
105934
106726
  }
105935
106727
  const projectRoot = process.cwd();
105936
- const metaprojectRoot = path198.join(projectRoot, ".metaproject");
105937
- banner("keryx update", `Refreshing the .metaproject workspace in ${path198.basename(projectRoot)}/`);
106728
+ const metaprojectRoot = path200.join(projectRoot, ".metaproject");
106729
+ banner("keryx update", `Refreshing the .metaproject workspace in ${path200.basename(projectRoot)}/`);
105938
106730
  if (!await pathExists(metaprojectRoot)) {
105939
106731
  console.log(` ${style.red(symbols.cross)} Metaproject is not initialized.`);
105940
106732
  console.log(` ${style.cyan(symbols.arrow)} Run ${style.cyan("keryx init")} first.`);
@@ -106007,7 +106799,7 @@ async function updateCommand(args = []) {
106007
106799
  nextSteps(steps);
106008
106800
  }
106009
106801
  async function previewServiceFiles(projectRoot, options) {
106010
- const metaprojectRoot = path198.join(projectRoot, ".metaproject");
106802
+ const metaprojectRoot = path200.join(projectRoot, ".metaproject");
106011
106803
  const manifestState = await readManifest5(metaprojectRoot);
106012
106804
  const manifest = manifestState.manifest;
106013
106805
  const enableTasks = moduleEnabled2(manifest, "tasks") || !options.noTasks;
@@ -106036,12 +106828,12 @@ async function previewServiceFiles(projectRoot, options) {
106036
106828
  });
106037
106829
  }
106038
106830
  async function refreshServiceFiles(projectRoot, options) {
106039
- const metaprojectRoot = path198.join(projectRoot, ".metaproject");
106831
+ const metaprojectRoot = path200.join(projectRoot, ".metaproject");
106040
106832
  const manifestState = await readManifest5(metaprojectRoot);
106041
106833
  const manifest = manifestState.manifest;
106042
106834
  const recoveredManifest = !manifestState.exists || !manifestState.valid;
106043
106835
  if (manifestState.migrated) {
106044
- await writeFile54(path198.join(metaprojectRoot, "metaproject.json"), `${JSON.stringify(manifest, null, 2)}
106836
+ await writeFile54(path200.join(metaprojectRoot, "metaproject.json"), `${JSON.stringify(manifest, null, 2)}
106045
106837
  `, "utf8");
106046
106838
  }
106047
106839
  const enableGdgraph = moduleEnabled2(manifest, "gdgraph");
@@ -106078,9 +106870,9 @@ async function refreshServiceFiles(projectRoot, options) {
106078
106870
  enableSecurity,
106079
106871
  enableSac
106080
106872
  });
106081
- await writeTextIfChanged4(path198.join(metaprojectRoot, "core", "README.md"), renderMetaprojectCoreReadme());
106082
- await writeTextIfChanged4(path198.join(metaprojectRoot, "hooks", "README.md"), renderHooksReadme());
106083
- await writeTextIfChanged4(path198.join(metaprojectRoot, "skills", "project-rules", "README.md"), renderProjectRulesSkillReadme({ sources: ruleSources }));
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 }));
106084
106876
  await writeRoutingEntrypointPair(metaprojectRoot, {
106085
106877
  enableGdgraph,
106086
106878
  enableGdctx,
@@ -106103,7 +106895,7 @@ async function refreshServiceFiles(projectRoot, options) {
106103
106895
  }
106104
106896
  }
106105
106897
  });
106106
- await writeTextIfChanged4(path198.join(metaprojectRoot, "keryx-dashboard.html"), renderMetaprojectDashboardHtml({
106898
+ await writeTextIfChanged4(path200.join(metaprojectRoot, "keryx-dashboard.html"), renderMetaprojectDashboardHtml({
106107
106899
  enableGdgraph,
106108
106900
  enableGdctx,
106109
106901
  enableGdwiki,
@@ -106115,7 +106907,7 @@ async function refreshServiceFiles(projectRoot, options) {
106115
106907
  enableSecurity,
106116
106908
  data: dashboardData
106117
106909
  }));
106118
- await writeTextIfMissing4(path198.join(metaprojectRoot, "README.md"), renderMetaprojectReadme({
106910
+ await writeTextIfMissing4(path200.join(metaprojectRoot, "README.md"), renderMetaprojectReadme({
106119
106911
  enableGdgraph,
106120
106912
  enableGdctx,
106121
106913
  enableGdwiki,
@@ -106128,31 +106920,31 @@ async function refreshServiceFiles(projectRoot, options) {
106128
106920
  }));
106129
106921
  if (enableGdgraph) {
106130
106922
  await installGdgraphCoreScripts2(metaprojectRoot);
106131
- await writeTextIfChanged4(path198.join(metaprojectRoot, "modules", "gdgraph.md"), renderGdgraphManifest());
106132
- await writeTextIfChanged4(path198.join(metaprojectRoot, "core", "gdgraph", "README.md"), renderGdgraphCoreReadme());
106133
- await writeTextIfChanged4(path198.join(metaprojectRoot, "skills", "gdgraph", "SKILL.md"), renderGdgraphSkillReadme());
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());
106134
106926
  await seedAssetsLock(metaprojectRoot);
106135
106927
  if (manifest.modules?.gdgraph?.hooks?.gitPostCommit) {
106136
106928
  await installManagedHook2(projectRoot, "post-commit", "gdgraph-post-commit", renderGdgraphPostCommitHook());
106137
106929
  }
106138
106930
  }
106139
106931
  if (enableGdctx) {
106140
- await writeTextIfMissing4(path198.join(metaprojectRoot, "gdctx.config.json"), renderGdctxConfig());
106141
- await writeTextIfChanged4(path198.join(metaprojectRoot, "modules", "gdctx.md"), renderGdctxManifest());
106142
- await writeTextIfChanged4(path198.join(metaprojectRoot, "core", "gdctx", "README.md"), renderGdctxCoreReadme());
106143
- await writeTextIfChanged4(path198.join(metaprojectRoot, "skills", "gdctx", "SKILL.md"), renderGdctxSkillReadme());
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());
106144
106936
  }
106145
106937
  if (enableGdwiki) {
106146
- await writeTextIfMissing4(path198.join(metaprojectRoot, "wiki", "templates", "page.md"), renderWikiPageTemplate());
106147
- await writeTextIfChanged4(path198.join(metaprojectRoot, "modules", "gdwiki.md"), renderGdwikiManifest());
106148
- await writeTextIfChanged4(path198.join(metaprojectRoot, "skills", "gdwiki", "SKILL.md"), renderGdwikiSkillReadme());
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());
106149
106941
  if (manifest.modules?.gdgraph?.hooks?.gitPostCommit) {
106150
106942
  await installManagedHook2(projectRoot, "post-commit", "gdwiki-post-commit", renderGdwikiPostCommitHook());
106151
106943
  }
106152
106944
  }
106153
106945
  if (enableSac) {
106154
- await writeTextIfMissing4(path198.join(metaprojectRoot, "modules", "sac.md"), renderSacManifest());
106155
- await writeTextIfChanged4(path198.join(metaprojectRoot, "skills", "sac", "SKILL.md"), renderSacSkillReadme());
106946
+ await writeTextIfMissing4(path200.join(metaprojectRoot, "modules", "sac.md"), renderSacManifest());
106947
+ await writeTextIfChanged4(path200.join(metaprojectRoot, "skills", "sac", "SKILL.md"), renderSacSkillReadme());
106156
106948
  }
106157
106949
  let gdskillsWarnings = [];
106158
106950
  let gdskillsNotices = [];
@@ -106165,25 +106957,25 @@ async function refreshServiceFiles(projectRoot, options) {
106165
106957
  }
106166
106958
  }
106167
106959
  if (enableHealth) {
106168
- await writeTextIfMissing4(path198.join(metaprojectRoot, "health.config.json"), renderHealthConfig());
106169
- await writeTextIfChanged4(path198.join(metaprojectRoot, "modules", "health.md"), renderHealthManifest());
106170
- await writeTextIfChanged4(path198.join(metaprojectRoot, "core", "health", "README.md"), renderHealthCoreReadme());
106171
- await writeTextIfChanged4(path198.join(metaprojectRoot, "skills", "health", "SKILL.md"), renderHealthSkillReadme());
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());
106172
106964
  if (manifest.modules?.health?.hooks?.gitPostCommit) {
106173
106965
  await installManagedHook2(projectRoot, "post-commit", "health-post-commit", renderHealthPostCommitHook());
106174
106966
  }
106175
106967
  }
106176
106968
  if (enableTesting) {
106177
- await writeTextIfMissing4(path198.join(metaprojectRoot, "testing.config.json"), renderTestingConfig({
106969
+ await writeTextIfMissing4(path200.join(metaprojectRoot, "testing.config.json"), renderTestingConfig({
106178
106970
  postCommitRefresh: Boolean(manifest.modules?.testing?.hooks?.gitPostCommit),
106179
106971
  prePushGate: Boolean(manifest.modules?.testing?.hooks?.prePush)
106180
106972
  }));
106181
- await writeTextIfChanged4(path198.join(metaprojectRoot, "modules", "testing.md"), renderTestingManifest());
106182
- await writeTextIfChanged4(path198.join(metaprojectRoot, "core", "testing", "README.md"), renderTestingCoreReadme());
106183
- await writeTextIfChanged4(path198.join(metaprojectRoot, "skills", "testing", "SKILL.md"), renderTestingSkillReadme());
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());
106184
106976
  if (enableGdwiki) {
106185
- await writeTextIfMissing4(path198.join(metaprojectRoot, "wiki", "testing", "README.md"), renderTestingWikiReadme());
106186
- await writeTextIfMissing4(path198.join(metaprojectRoot, "wiki", "testing", "conventions.md"), renderTestingWikiConventions());
106977
+ await writeTextIfMissing4(path200.join(metaprojectRoot, "wiki", "testing", "README.md"), renderTestingWikiReadme());
106978
+ await writeTextIfMissing4(path200.join(metaprojectRoot, "wiki", "testing", "conventions.md"), renderTestingWikiConventions());
106187
106979
  }
106188
106980
  if (manifest.modules?.testing?.hooks?.gitPostCommit) {
106189
106981
  await installManagedHook2(projectRoot, "post-commit", "testing-post-commit", renderTestingPostCommitHook());
@@ -106196,24 +106988,24 @@ async function refreshServiceFiles(projectRoot, options) {
106196
106988
  await installManagedHook2(projectRoot, "post-commit", "metaproject-dashboard-post-commit", renderMetaprojectDashboardPostCommitHook());
106197
106989
  }
106198
106990
  if (enableMemory) {
106199
- await writeTextIfMissing4(path198.join(metaprojectRoot, "memory.config.json"), renderMemoryConfig());
106200
- await writeTextIfMissing4(path198.join(metaprojectRoot, "memory", "templates", "entry.md"), renderMemoryEntryTemplate());
106201
- await writeTextIfChanged4(path198.join(metaprojectRoot, "modules", "memory.md"), renderMemoryManifest());
106202
- await writeTextIfChanged4(path198.join(metaprojectRoot, "core", "memory", "README.md"), renderMemoryCoreReadme());
106203
- await writeTextIfChanged4(path198.join(metaprojectRoot, "skills", "memory", "SKILL.md"), renderMemorySkillReadme());
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());
106204
106996
  }
106205
106997
  if (enableTasks) {
106206
- await writeTextIfChanged4(path198.join(metaprojectRoot, "flows", "README.md"), renderFlowsReadme());
106207
- await writeTextIfChanged4(path198.join(metaprojectRoot, "modules", "tasks.md"), renderTasksManifest());
106208
- await writeTextIfChanged4(path198.join(metaprojectRoot, "skills", "flow", "SKILL.md"), renderFlowSkillRouter());
106209
- await writeTextIfChanged4(path198.join(metaprojectRoot, "skills", "flow", "init.md"), renderFlowInitSkill());
106210
- await writeTextIfChanged4(path198.join(metaprojectRoot, "skills", "flow", "manage.md"), renderFlowManageSkill());
106211
- await writeTextIfChanged4(path198.join(metaprojectRoot, "skills", "flow", "complete.md"), renderFlowCompleteSkill());
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());
106212
107004
  }
106213
107005
  if (enableSecurity) {
106214
- await writeTextIfMissing4(path198.join(metaprojectRoot, "security.config.json"), renderSecurityConfig());
106215
- await writeTextIfChanged4(path198.join(metaprojectRoot, "modules", "security.md"), renderSecurityManifest());
106216
- await writeTextIfChanged4(path198.join(metaprojectRoot, "core", "security", "README.md"), renderSecurityCoreReadme());
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());
106217
107009
  if (manifest.modules?.security?.hooks?.prePush) {
106218
107010
  await installManagedHook2(projectRoot, "pre-push", "security-pre-push", renderSecurityPrePushHook());
106219
107011
  }
@@ -106266,13 +107058,13 @@ async function refreshServiceFiles(projectRoot, options) {
106266
107058
  };
106267
107059
  }
106268
107060
  async function buildDashboard(projectRoot = process.cwd()) {
106269
- const metaprojectRoot = path198.join(projectRoot, ".metaproject");
107061
+ const metaprojectRoot = path200.join(projectRoot, ".metaproject");
106270
107062
  if (!await pathExists(metaprojectRoot)) {
106271
107063
  throw new Error("Metaproject is not initialized. Run: keryx init");
106272
107064
  }
106273
107065
  const manifest = (await readManifest5(metaprojectRoot)).manifest;
106274
107066
  const data = await collectDashboardData(metaprojectRoot);
106275
- const dashboardPath = path198.join(metaprojectRoot, "keryx-dashboard.html");
107067
+ const dashboardPath = path200.join(metaprojectRoot, "keryx-dashboard.html");
106276
107068
  await writeTextIfChanged4(dashboardPath, renderMetaprojectDashboardHtml({
106277
107069
  enableGdgraph: moduleEnabled2(manifest, "gdgraph"),
106278
107070
  enableGdctx: moduleEnabled2(manifest, "gdctx"),
@@ -106292,7 +107084,7 @@ async function shouldInstallDashboardPostCommitHook(projectRoot, manifest) {
106292
107084
  if (Object.values(modules).some((module) => Boolean(module.hooks?.gitPostCommit))) {
106293
107085
  return true;
106294
107086
  }
106295
- const hookPath = path198.join(projectRoot, ".git", "hooks", "post-commit");
107087
+ const hookPath = path200.join(projectRoot, ".git", "hooks", "post-commit");
106296
107088
  if (!await pathExists(hookPath)) {
106297
107089
  return false;
106298
107090
  }
@@ -106312,11 +107104,11 @@ async function collectDashboardData(metaprojectRoot) {
106312
107104
  if (testing) {
106313
107105
  data.testing = testing;
106314
107106
  }
106315
- const wiki = await collectMarkdownPages(path198.join(metaprojectRoot, "wiki"), "wiki");
107107
+ const wiki = await collectMarkdownPages(path200.join(metaprojectRoot, "wiki"), "wiki");
106316
107108
  if (wiki.length > 0) {
106317
107109
  data.wiki = { pages: wiki };
106318
107110
  }
106319
- const memory = await collectMarkdownPages(path198.join(metaprojectRoot, "memory"), "memory");
107111
+ const memory = await collectMarkdownPages(path200.join(metaprojectRoot, "memory"), "memory");
106320
107112
  if (memory.length > 0) {
106321
107113
  data.memory = { entries: memory };
106322
107114
  }
@@ -106331,7 +107123,7 @@ async function collectDashboardData(metaprojectRoot) {
106331
107123
  return data;
106332
107124
  }
106333
107125
  async function collectTasksDashboardData(metaprojectRoot) {
106334
- const flowsRoot = path198.join(metaprojectRoot, "flows");
107126
+ const flowsRoot = path200.join(metaprojectRoot, "flows");
106335
107127
  if (!await pathExists(flowsRoot)) {
106336
107128
  return null;
106337
107129
  }
@@ -106343,7 +107135,7 @@ async function collectTasksDashboardData(metaprojectRoot) {
106343
107135
  }
106344
107136
  const flows = [];
106345
107137
  for (const dir of dirEntries) {
106346
- const flowPath = path198.join(flowsRoot, dir, "flow.json");
107138
+ const flowPath = path200.join(flowsRoot, dir, "flow.json");
106347
107139
  if (!await pathExists(flowPath)) {
106348
107140
  continue;
106349
107141
  }
@@ -106351,7 +107143,7 @@ async function collectTasksDashboardData(metaprojectRoot) {
106351
107143
  const flow = JSON.parse(await readFile100(flowPath, "utf8"));
106352
107144
  const tasks = Array.isArray(flow.tasks) ? flow.tasks : [];
106353
107145
  let acTotal = 0;
106354
- const acPath = path198.join(flowsRoot, dir, "acceptance-criteria.md");
107146
+ const acPath = path200.join(flowsRoot, dir, "acceptance-criteria.md");
106355
107147
  if (await pathExists(acPath)) {
106356
107148
  const acContent = await readFile100(acPath, "utf8");
106357
107149
  acTotal = (acContent.match(/^- AC\d+:/gm) ?? []).length;
@@ -106405,7 +107197,7 @@ async function collectDashboardDocs(metaprojectRoot, wiki, memory) {
106405
107197
  "data/testing/context.md"
106406
107198
  ];
106407
107199
  for (const href of staticHrefs) {
106408
- const filePath = path198.join(metaprojectRoot, ...href.split("/"));
107200
+ const filePath = path200.join(metaprojectRoot, ...href.split("/"));
106409
107201
  if (!await pathExists(filePath)) {
106410
107202
  continue;
106411
107203
  }
@@ -106422,7 +107214,7 @@ async function collectDashboardDocs(metaprojectRoot, wiki, memory) {
106422
107214
  return docs;
106423
107215
  }
106424
107216
  async function collectHealthDashboardData(metaprojectRoot) {
106425
- const reportPath = path198.join(metaprojectRoot, "data", "health", "artifacts", "latest.json");
107217
+ const reportPath = path200.join(metaprojectRoot, "data", "health", "artifacts", "latest.json");
106426
107218
  if (!await pathExists(reportPath)) {
106427
107219
  return;
106428
107220
  }
@@ -106531,8 +107323,8 @@ function metricToScope(metric) {
106531
107323
  };
106532
107324
  }
106533
107325
  async function collectGraphDashboardData(metaprojectRoot) {
106534
- const nodesPath = path198.join(metaprojectRoot, "data", "gdgraph", "storage", "nodes.jsonl");
106535
- const edgesPath = path198.join(metaprojectRoot, "data", "gdgraph", "storage", "edges.jsonl");
107326
+ const nodesPath = path200.join(metaprojectRoot, "data", "gdgraph", "storage", "nodes.jsonl");
107327
+ const edgesPath = path200.join(metaprojectRoot, "data", "gdgraph", "storage", "edges.jsonl");
106536
107328
  if (!await pathExists(nodesPath) || !await pathExists(edgesPath)) {
106537
107329
  return;
106538
107330
  }
@@ -106583,8 +107375,8 @@ async function collectGraphDashboardData(metaprojectRoot) {
106583
107375
  };
106584
107376
  }
106585
107377
  async function collectTestingDashboardData(metaprojectRoot) {
106586
- const reportPath = path198.join(metaprojectRoot, "data", "testing", "artifacts", "latest.json");
106587
- const contextPath = path198.join(metaprojectRoot, "data", "testing", "context.md");
107378
+ const reportPath = path200.join(metaprojectRoot, "data", "testing", "artifacts", "latest.json");
107379
+ const contextPath = path200.join(metaprojectRoot, "data", "testing", "context.md");
106588
107380
  if (await pathExists(reportPath)) {
106589
107381
  const report = JSON.parse(await readFile100(reportPath, "utf8"));
106590
107382
  const totalTests = numberOrUndefined(report.total);
@@ -106613,7 +107405,7 @@ async function collectMarkdownPages(root, hrefPrefix) {
106613
107405
  const files = await listMarkdownFiles(root);
106614
107406
  const pages = [];
106615
107407
  for (const filePath of files.slice(0, 40)) {
106616
- const relativePath = path198.relative(root, filePath).split(path198.sep).join("/");
107408
+ const relativePath = path200.relative(root, filePath).split(path200.sep).join("/");
106617
107409
  if (relativePath === "index.md" || relativePath.startsWith("templates/")) {
106618
107410
  continue;
106619
107411
  }
@@ -106634,7 +107426,7 @@ async function listMarkdownFiles(root) {
106634
107426
  const entries = await readdir37(root, { withFileTypes: true });
106635
107427
  const files = [];
106636
107428
  for (const entry of entries) {
106637
- const fullPath = path198.join(root, entry.name);
107429
+ const fullPath = path200.join(root, entry.name);
106638
107430
  if (entry.isDirectory()) {
106639
107431
  files.push(...await listMarkdownFiles(fullPath));
106640
107432
  } else if (entry.isFile() && entry.name.endsWith(".md")) {
@@ -106682,7 +107474,7 @@ async function writeRecoveredManifest(metaprojectRoot, modules) {
106682
107474
  const manifest = {
106683
107475
  schemaVersion: 1,
106684
107476
  standardVersion: STANDARD_VERSION,
106685
- name: `${path198.basename(path198.dirname(metaprojectRoot))}-metaproject`,
107477
+ name: `${path200.basename(path200.dirname(metaprojectRoot))}-metaproject`,
106686
107478
  createdBy: "keryx",
106687
107479
  profiles: computeProfiles(enabledModuleKeys),
106688
107480
  paths: {
@@ -106772,11 +107564,11 @@ async function writeRecoveredManifest(metaprojectRoot, modules) {
106772
107564
  metaproject: ".metaproject/index.md"
106773
107565
  }
106774
107566
  };
106775
- await writeFile54(path198.join(metaprojectRoot, "metaproject.json"), `${JSON.stringify(manifest, null, 2)}
107567
+ await writeFile54(path200.join(metaprojectRoot, "metaproject.json"), `${JSON.stringify(manifest, null, 2)}
106776
107568
  `, "utf8");
106777
107569
  }
106778
107570
  async function enableTasksInManifest(metaprojectRoot) {
106779
- const manifestPath = path198.join(metaprojectRoot, "metaproject.json");
107571
+ const manifestPath = path200.join(metaprojectRoot, "metaproject.json");
106780
107572
  if (!await pathExists(manifestPath)) {
106781
107573
  return;
106782
107574
  }
@@ -106799,7 +107591,7 @@ async function enableTasksInManifest(metaprojectRoot) {
106799
107591
  `, "utf8");
106800
107592
  }
106801
107593
  async function updateManifestAgentEntrypoints(metaprojectRoot, ruleSources) {
106802
- const manifestPath = path198.join(metaprojectRoot, "metaproject.json");
107594
+ const manifestPath = path200.join(metaprojectRoot, "metaproject.json");
106803
107595
  if (!await pathExists(manifestPath)) {
106804
107596
  return;
106805
107597
  }
@@ -106835,72 +107627,72 @@ async function updateRuntime(projectRoot) {
106835
107627
  }
106836
107628
  }
106837
107629
  async function findRuntimeRoot(projectRoot) {
106838
- const projectRuntime = path198.join(projectRoot, ".metaproject", "runtime", "keryx");
106839
- if (await pathExists(path198.join(projectRuntime, ".git"))) {
107630
+ const projectRuntime = path200.join(projectRoot, ".metaproject", "runtime", "keryx");
107631
+ if (await pathExists(path200.join(projectRuntime, ".git"))) {
106840
107632
  return projectRuntime;
106841
107633
  }
106842
107634
  const home = process.env.HOME;
106843
107635
  if (!home) {
106844
107636
  return null;
106845
107637
  }
106846
- const globalRuntime = path198.join(home, ".keryx", "keryx");
106847
- if (await pathExists(path198.join(globalRuntime, ".git"))) {
107638
+ const globalRuntime = path200.join(home, ".keryx", "keryx");
107639
+ if (await pathExists(path200.join(globalRuntime, ".git"))) {
106848
107640
  return globalRuntime;
106849
107641
  }
106850
107642
  return null;
106851
107643
  }
106852
107644
  async function createServiceDirs(metaprojectRoot, modules) {
106853
107645
  const dirs = [
106854
- path198.join(metaprojectRoot, "core"),
106855
- path198.join(metaprojectRoot, "hooks", "post-update.d"),
106856
- path198.join(metaprojectRoot, "modules"),
106857
- path198.join(metaprojectRoot, "rules"),
106858
- path198.join(metaprojectRoot, "skills", "project-rules"),
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"),
106859
107651
  ...modules.enableGdgraph ? [
106860
- path198.join(metaprojectRoot, "core", "gdgraph"),
106861
- path198.join(metaprojectRoot, "skills", "gdgraph")
107652
+ path200.join(metaprojectRoot, "core", "gdgraph"),
107653
+ path200.join(metaprojectRoot, "skills", "gdgraph")
106862
107654
  ] : [],
106863
107655
  ...modules.enableGdctx ? [
106864
- path198.join(metaprojectRoot, "core", "gdctx"),
106865
- path198.join(metaprojectRoot, "skills", "gdctx")
107656
+ path200.join(metaprojectRoot, "core", "gdctx"),
107657
+ path200.join(metaprojectRoot, "skills", "gdctx")
106866
107658
  ] : [],
106867
107659
  ...modules.enableGdwiki ? [
106868
- path198.join(metaprojectRoot, "skills", "gdwiki"),
106869
- path198.join(metaprojectRoot, "wiki", "templates")
107660
+ path200.join(metaprojectRoot, "skills", "gdwiki"),
107661
+ path200.join(metaprojectRoot, "wiki", "templates")
106870
107662
  ] : [],
106871
107663
  ...modules.enableHealth ? [
106872
- path198.join(metaprojectRoot, "core", "health"),
106873
- path198.join(metaprojectRoot, "skills", "health")
107664
+ path200.join(metaprojectRoot, "core", "health"),
107665
+ path200.join(metaprojectRoot, "skills", "health")
106874
107666
  ] : [],
106875
107667
  ...modules.enableTesting ? [
106876
- path198.join(metaprojectRoot, "core", "testing"),
106877
- path198.join(metaprojectRoot, "skills", "testing")
107668
+ path200.join(metaprojectRoot, "core", "testing"),
107669
+ path200.join(metaprojectRoot, "skills", "testing")
106878
107670
  ] : [],
106879
107671
  ...modules.enableMemory ? [
106880
- path198.join(metaprojectRoot, "core", "memory"),
106881
- path198.join(metaprojectRoot, "skills", "memory"),
106882
- path198.join(metaprojectRoot, "memory", "templates")
107672
+ path200.join(metaprojectRoot, "core", "memory"),
107673
+ path200.join(metaprojectRoot, "skills", "memory"),
107674
+ path200.join(metaprojectRoot, "memory", "templates")
106883
107675
  ] : [],
106884
107676
  ...modules.enableTasks ? [
106885
- path198.join(metaprojectRoot, "flows"),
106886
- path198.join(metaprojectRoot, "skills", "flow")
107677
+ path200.join(metaprojectRoot, "flows"),
107678
+ path200.join(metaprojectRoot, "skills", "flow")
106887
107679
  ] : [],
106888
107680
  ...modules.enableSecurity ? [
106889
- path198.join(metaprojectRoot, "core", "security")
107681
+ path200.join(metaprojectRoot, "core", "security")
106890
107682
  ] : [],
106891
107683
  ...modules.enableSac ? [
106892
- path198.join(metaprojectRoot, "skills", "sac")
107684
+ path200.join(metaprojectRoot, "skills", "sac")
106893
107685
  ] : []
106894
107686
  ];
106895
107687
  await Promise.all(dirs.map((dir) => mkdir63(dir, { recursive: true })));
106896
107688
  }
106897
107689
  async function installGdgraphCoreScripts2(metaprojectRoot) {
106898
- const gdgraphCoreRoot = path198.join(metaprojectRoot, "core", "gdgraph");
107690
+ const gdgraphCoreRoot = path200.join(metaprojectRoot, "core", "gdgraph");
106899
107691
  await mkdir63(gdgraphCoreRoot, { recursive: true });
106900
107692
  for (const file of GDGRAPH_CORE_SOURCES) {
106901
- await copyFileIfChanged2(runtimeSourcePath2(`../gdgraph/${file}`), path198.join(gdgraphCoreRoot, file));
107693
+ await copyFileIfChanged2(runtimeSourcePath2(`../gdgraph/${file}`), path200.join(gdgraphCoreRoot, file));
106902
107694
  }
106903
- await writeTextIfChanged4(path198.join(gdgraphCoreRoot, "cli.ts"), renderGdgraphCoreCli());
107695
+ await writeTextIfChanged4(path200.join(gdgraphCoreRoot, "cli.ts"), renderGdgraphCoreCli());
106904
107696
  }
106905
107697
  async function installManagedHook2(projectRoot, hookName, blockId, content) {
106906
107698
  const hooksRoot = await resolveGitHooksRoot(projectRoot);
@@ -106908,7 +107700,7 @@ async function installManagedHook2(projectRoot, hookName, blockId, content) {
106908
107700
  return;
106909
107701
  }
106910
107702
  await mkdir63(hooksRoot, { recursive: true });
106911
- const hookPath = path198.join(hooksRoot, hookName);
107703
+ const hookPath = path200.join(hooksRoot, hookName);
106912
107704
  const blockStart = `# keryx:${blockId}:begin`;
106913
107705
  const blockEnd = `# keryx:${blockId}:end`;
106914
107706
  const managedBlock = `${blockStart}
@@ -106929,7 +107721,7 @@ async function removeManagedHook2(projectRoot, hookName, blockId) {
106929
107721
  if (!hooksRoot) {
106930
107722
  return;
106931
107723
  }
106932
- const hookPath = path198.join(hooksRoot, hookName);
107724
+ const hookPath = path200.join(hooksRoot, hookName);
106933
107725
  if (!await pathExists(hookPath)) {
106934
107726
  return;
106935
107727
  }
@@ -106951,7 +107743,7 @@ async function prePushHasSecurityBlock2(projectRoot) {
106951
107743
  if (!hooksRoot) {
106952
107744
  return false;
106953
107745
  }
106954
- const hookPath = path198.join(hooksRoot, "pre-push");
107746
+ const hookPath = path200.join(hooksRoot, "pre-push");
106955
107747
  if (!await pathExists(hookPath)) {
106956
107748
  return false;
106957
107749
  }
@@ -106966,7 +107758,7 @@ async function agentSettingsHasSecuritySentinel2(projectRoot) {
106966
107758
  return (await readFile100(file, "utf8")).includes(AGENT_HOOKS_SENTINEL);
106967
107759
  }
106968
107760
  async function readManifest5(metaprojectRoot) {
106969
- const manifestPath = path198.join(metaprojectRoot, "metaproject.json");
107761
+ const manifestPath = path200.join(metaprojectRoot, "metaproject.json");
106970
107762
  if (!await pathExists(manifestPath)) {
106971
107763
  return {
106972
107764
  exists: false,
@@ -107035,7 +107827,7 @@ async function inferManifestFromExistingMetaproject(metaprojectRoot) {
107035
107827
  }
107036
107828
  async function anyPathExists(root, candidates) {
107037
107829
  for (const candidate of candidates) {
107038
- if (await pathExists(path198.join(root, candidate))) {
107830
+ if (await pathExists(path200.join(root, candidate))) {
107039
107831
  return true;
107040
107832
  }
107041
107833
  }
@@ -107058,13 +107850,13 @@ function parseUpdateArgs(args) {
107058
107850
  };
107059
107851
  }
107060
107852
  async function runPostUpdateHooks(projectRoot) {
107061
- const hooksDir = path198.join(projectRoot, ".metaproject", "hooks", "post-update.d");
107853
+ const hooksDir = path200.join(projectRoot, ".metaproject", "hooks", "post-update.d");
107062
107854
  if (!await pathExists(hooksDir)) {
107063
107855
  return;
107064
107856
  }
107065
107857
  const entries = (await readdir37(hooksDir)).sort();
107066
107858
  for (const entry of entries) {
107067
- const hookPath = path198.join(hooksDir, entry);
107859
+ const hookPath = path200.join(hooksDir, entry);
107068
107860
  try {
107069
107861
  await accessExecutable(hookPath);
107070
107862
  } catch {
@@ -107076,7 +107868,7 @@ async function runPostUpdateHooks(projectRoot) {
107076
107868
  }
107077
107869
  async function accessExecutable(filePath) {
107078
107870
  await new Promise((resolve, reject) => {
107079
- access4(filePath, constants2.X_OK, (error) => {
107871
+ access4(filePath, constants3.X_OK, (error) => {
107080
107872
  if (error) {
107081
107873
  reject(error);
107082
107874
  return;
@@ -107087,7 +107879,7 @@ async function accessExecutable(filePath) {
107087
107879
  }
107088
107880
  async function run(command, args, cwd) {
107089
107881
  await new Promise((resolve, reject) => {
107090
- const child = spawn6(command, args, {
107882
+ const child = spawn7(command, args, {
107091
107883
  cwd,
107092
107884
  stdio: "inherit"
107093
107885
  });
@@ -107105,14 +107897,14 @@ async function writeTextIfChanged4(filePath, content) {
107105
107897
  if (await pathExists(filePath) && await readFile100(filePath, "utf8") === content) {
107106
107898
  return;
107107
107899
  }
107108
- await mkdir63(path198.dirname(filePath), { recursive: true });
107900
+ await mkdir63(path200.dirname(filePath), { recursive: true });
107109
107901
  await writeFile54(filePath, content, "utf8");
107110
107902
  }
107111
107903
  async function writeTextIfMissing4(filePath, content) {
107112
107904
  if (await pathExists(filePath)) {
107113
107905
  return;
107114
107906
  }
107115
- await mkdir63(path198.dirname(filePath), { recursive: true });
107907
+ await mkdir63(path200.dirname(filePath), { recursive: true });
107116
107908
  await writeFile54(filePath, content, "utf8");
107117
107909
  }
107118
107910
  async function copyFileIfChanged2(from, to) {
@@ -107120,7 +107912,7 @@ async function copyFileIfChanged2(from, to) {
107120
107912
  if (await pathExists(to) && await readFile100(to, "utf8") === next) {
107121
107913
  return;
107122
107914
  }
107123
- await mkdir63(path198.dirname(to), { recursive: true });
107915
+ await mkdir63(path200.dirname(to), { recursive: true });
107124
107916
  await writeFile54(to, next, "utf8");
107125
107917
  }
107126
107918
  function runtimeSourcePath2(relativePath) {
@@ -107129,7 +107921,7 @@ function runtimeSourcePath2(relativePath) {
107129
107921
  return directPath;
107130
107922
  }
107131
107923
  if (relativePath.startsWith("../")) {
107132
- const packagedSourcePath = path198.join(path198.dirname(fileURLToPath8(import.meta.url)), "..", "src", relativePath.slice(3));
107924
+ const packagedSourcePath = path200.join(path200.dirname(fileURLToPath8(import.meta.url)), "..", "src", relativePath.slice(3));
107133
107925
  if (existsSync36(packagedSourcePath)) {
107134
107926
  return packagedSourcePath;
107135
107927
  }
@@ -107163,8 +107955,8 @@ function printHelp20() {
107163
107955
  }
107164
107956
 
107165
107957
  // src/commands/dashboard.ts
107166
- import { spawn as spawn7 } from "child_process";
107167
- import path199 from "path";
107958
+ import { spawn as spawn8 } from "child_process";
107959
+ import path201 from "path";
107168
107960
  init_args();
107169
107961
  async function dashboardCommand(args = []) {
107170
107962
  const options = parseOptions(args);
@@ -107175,7 +107967,7 @@ async function dashboardCommand(args = []) {
107175
107967
  }
107176
107968
  if (subcommand === "build") {
107177
107969
  const result = await buildDashboard();
107178
- const rel = path199.relative(process.cwd(), result.path);
107970
+ const rel = path201.relative(process.cwd(), result.path);
107179
107971
  console.log(` ${style.green(symbols.ok)} Dashboard built ${style.cyan(symbols.arrow)} ${style.cyan(rel)}`);
107180
107972
  note(`Open it: keryx dashboard open`);
107181
107973
  return;
@@ -107183,7 +107975,7 @@ async function dashboardCommand(args = []) {
107183
107975
  if (subcommand === "open") {
107184
107976
  const result = await buildDashboard();
107185
107977
  await openFile(result.path);
107186
- const rel = path199.relative(process.cwd(), result.path);
107978
+ const rel = path201.relative(process.cwd(), result.path);
107187
107979
  console.log(` ${style.green(symbols.ok)} Opened ${style.cyan(rel)}`);
107188
107980
  return;
107189
107981
  }
@@ -107202,7 +107994,7 @@ async function openFile(filePath) {
107202
107994
  const command = process.platform === "darwin" ? "open" : process.platform === "win32" ? "cmd" : "xdg-open";
107203
107995
  const args = process.platform === "win32" ? ["/c", "start", "", filePath] : [filePath];
107204
107996
  await new Promise((resolve, reject) => {
107205
- const child = spawn7(command, args, { stdio: "ignore", detached: true });
107997
+ const child = spawn8(command, args, { stdio: "ignore", detached: true });
107206
107998
  child.on("error", reject);
107207
107999
  child.on("close", (code) => {
107208
108000
  if (code === 0) {
@@ -107227,12 +108019,12 @@ function printHelp21() {
107227
108019
  }
107228
108020
 
107229
108021
  // src/commands/agents.ts
107230
- import { readFileSync as readFileSync9 } from "fs";
108022
+ import { readFileSync as readFileSync10 } from "fs";
107231
108023
 
107232
108024
  // src/agents/bootstrap.ts
107233
108025
  import { mkdir as mkdir64, readFile as readFile101, writeFile as writeFile55 } from "fs/promises";
107234
108026
  import { homedir as homedir10 } from "os";
107235
- import path200 from "path";
108027
+ import path202 from "path";
107236
108028
  init_fs();
107237
108029
  var AGENT_BOOTSTRAP_START = "<!-- keryx:global-bootstrap -->";
107238
108030
  var AGENT_BOOTSTRAP_END = "<!-- /keryx:global-bootstrap -->";
@@ -107242,35 +108034,35 @@ var AGENT_BOOTSTRAP_RUNTIMES = [
107242
108034
  aliases: ["claude-code"],
107243
108035
  label: "Claude Code",
107244
108036
  fileName: "CLAUDE.md",
107245
- filePath: (homeRoot) => path200.join(homeRoot, ".claude", "CLAUDE.md")
108037
+ filePath: (homeRoot) => path202.join(homeRoot, ".claude", "CLAUDE.md")
107246
108038
  },
107247
108039
  {
107248
108040
  id: "opencode",
107249
108041
  aliases: ["open-code"],
107250
108042
  label: "OpenCode",
107251
108043
  fileName: "AGENTS.md",
107252
- filePath: (homeRoot) => path200.join(homeRoot, ".config", "opencode", "AGENTS.md")
108044
+ filePath: (homeRoot) => path202.join(homeRoot, ".config", "opencode", "AGENTS.md")
107253
108045
  },
107254
108046
  {
107255
108047
  id: "zcode",
107256
108048
  aliases: ["zed", "zed-code"],
107257
108049
  label: "ZCode",
107258
108050
  fileName: "AGENTS.md",
107259
- filePath: (homeRoot) => path200.join(homeRoot, ".zcode", "AGENTS.md")
108051
+ filePath: (homeRoot) => path202.join(homeRoot, ".zcode", "AGENTS.md")
107260
108052
  },
107261
108053
  {
107262
108054
  id: "codex",
107263
108055
  aliases: [],
107264
108056
  label: "Codex",
107265
108057
  fileName: "AGENTS.md",
107266
- filePath: (homeRoot) => path200.join(homeRoot, ".codex", "AGENTS.md")
108058
+ filePath: (homeRoot) => path202.join(homeRoot, ".codex", "AGENTS.md")
107267
108059
  },
107268
108060
  {
107269
108061
  id: "antigravity",
107270
108062
  aliases: ["antigravuty", "antigravity-code"],
107271
108063
  label: "Antigravity",
107272
108064
  fileName: "AGENTS.md",
107273
- filePath: (homeRoot) => path200.join(homeRoot, ".config", "antigravity", "AGENTS.md")
108065
+ filePath: (homeRoot) => path202.join(homeRoot, ".config", "antigravity", "AGENTS.md")
107274
108066
  }
107275
108067
  ];
107276
108068
  function agentBootstrapRuntimeIds() {
@@ -107318,7 +108110,7 @@ async function installAgentBootstrap(runtime, options = {}) {
107318
108110
  const dryRun = options.dryRun === true;
107319
108111
  const wrote = next !== current;
107320
108112
  if (wrote && !dryRun) {
107321
- await mkdir64(path200.dirname(filePath), { recursive: true });
108113
+ await mkdir64(path202.dirname(filePath), { recursive: true });
107322
108114
  await writeFile55(filePath, next, "utf8");
107323
108115
  }
107324
108116
  const status = dryRun ? statusFromContent(runtime, filePath, exists, next) : await agentBootstrapStatus(runtime, homeRoot);
@@ -107728,7 +108520,7 @@ function monitorCommand(args) {
107728
108520
  }
107729
108521
  let events;
107730
108522
  try {
107731
- events = parseAgentEvents(readFileSync9(source, "utf8"));
108523
+ events = parseAgentEvents(readFileSync10(source, "utf8"));
107732
108524
  } catch (error) {
107733
108525
  console.error(`Failed to read/parse agent-event source "${source}": ${error.message}`);
107734
108526
  process.exitCode = 1;
@@ -107855,7 +108647,7 @@ function printBootstrapHelp() {
107855
108647
  // src/commands/metrics.ts
107856
108648
  init_args();
107857
108649
  import { readFile as readFile102 } from "fs/promises";
107858
- import path202 from "path";
108650
+ import path204 from "path";
107859
108651
 
107860
108652
  // src/metrics/benchmark.ts
107861
108653
  var RELIABILITIES2 = new Set(["exact", "estimated", "unknown"]);
@@ -108672,7 +109464,7 @@ function buildContainmentManifest(inputs, options = {}) {
108672
109464
 
108673
109465
  // src/metrics/oracle-runner.ts
108674
109466
  import { mkdir as mkdir65, writeFile as writeFile56 } from "fs/promises";
108675
- import path201 from "path";
109467
+ import path203 from "path";
108676
109468
 
108677
109469
  // src/metrics/ir.ts
108678
109470
  function toIdSet(ids) {
@@ -109118,9 +109910,9 @@ function buildEvidenceBundle(input, options = {}) {
109118
109910
  async function persistEvidenceBundle(outDir, bundle, ladder = "metastore") {
109119
109911
  const safeTarget = bundle.target.replace(/[^A-Za-z0-9._/-]/g, "_");
109120
109912
  const safeCase = bundle.caseId.replace(/[^A-Za-z0-9._-]/g, "_");
109121
- const dir = path201.join(outDir, "bench", ladder, safeTarget, safeCase, bundle.variant, String(bundle.seed));
109913
+ const dir = path203.join(outDir, "bench", ladder, safeTarget, safeCase, bundle.variant, String(bundle.seed));
109122
109914
  await mkdir65(dir, { recursive: true });
109123
- const write = (name, value) => writeFile56(path201.join(dir, name), `${JSON.stringify(value, null, 2)}
109915
+ const write = (name, value) => writeFile56(path203.join(dir, name), `${JSON.stringify(value, null, 2)}
109124
109916
  `, "utf8");
109125
109917
  await Promise.all([
109126
109918
  write("inputs.json", bundle.inputs),
@@ -109160,7 +109952,7 @@ async function metricsCommand(args = [], projectRoot = process.cwd()) {
109160
109952
  console.log("# metrics status");
109161
109953
  console.log("");
109162
109954
  console.log(`root: ${root}`);
109163
- console.log(`enabled: ${await Bun.file(path202.join(projectRoot, ".metaproject", "metaproject.json")).exists() ? "yes" : "no"}`);
109955
+ console.log(`enabled: ${await Bun.file(path204.join(projectRoot, ".metaproject", "metaproject.json")).exists() ? "yes" : "no"}`);
109164
109956
  const latest = await readLatestPointer(root);
109165
109957
  console.log(`latest: ${latest.status}`);
109166
109958
  return;
@@ -109172,7 +109964,7 @@ async function metricsCommand(args = [], projectRoot = process.cwd()) {
109172
109964
  process.exitCode = 1;
109173
109965
  return;
109174
109966
  }
109175
- const record = JSON.parse(await readFile102(path202.resolve(projectRoot, file), "utf8"));
109967
+ const record = JSON.parse(await readFile102(path204.resolve(projectRoot, file), "utf8"));
109176
109968
  const result = validateRunRecord(record);
109177
109969
  console.log(result.valid ? "valid: yes" : "valid: no");
109178
109970
  for (const error of result.errors)
@@ -109197,7 +109989,7 @@ async function metricsCommand(args = [], projectRoot = process.cwd()) {
109197
109989
  process.exitCode = 1;
109198
109990
  return;
109199
109991
  }
109200
- const file = path202.join(metricsRoot(projectRoot), "runs", `${runId}.json`);
109992
+ const file = path204.join(metricsRoot(projectRoot), "runs", `${runId}.json`);
109201
109993
  if (!await Bun.file(file).exists()) {
109202
109994
  console.error(`Run not found: ${runId}`);
109203
109995
  process.exitCode = 1;
@@ -109214,8 +110006,8 @@ async function metricsCommand(args = [], projectRoot = process.cwd()) {
109214
110006
  process.exitCode = 1;
109215
110007
  return;
109216
110008
  }
109217
- const a = JSON.parse(await readFile102(path202.join(metricsRoot(projectRoot), "runs", `${runA}.json`), "utf8"));
109218
- const b = JSON.parse(await readFile102(path202.join(metricsRoot(projectRoot), "runs", `${runB}.json`), "utf8"));
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"));
109219
110011
  const comparison = compareExecutionRuns(a, b);
109220
110012
  console.log(stableJson(comparison));
109221
110013
  return;
@@ -109249,8 +110041,8 @@ async function metricsCommand(args = [], projectRoot = process.cwd()) {
109249
110041
  return;
109250
110042
  }
109251
110043
  const template = createPairedBenchmarkTemplate(taskIds);
109252
- await Bun.write(path202.resolve(projectRoot, out), stableJson(template));
109253
- console.log(`manifest: ${path202.relative(projectRoot, path202.resolve(projectRoot, out))}`);
110044
+ await Bun.write(path204.resolve(projectRoot, out), stableJson(template));
110045
+ console.log(`manifest: ${path204.relative(projectRoot, path204.resolve(projectRoot, out))}`);
109254
110046
  return;
109255
110047
  }
109256
110048
  if (subcommand === "benchmark" && args[1] === "run") {
@@ -109264,7 +110056,7 @@ async function metricsCommand(args = [], projectRoot = process.cwd()) {
109264
110056
  process.exitCode = 1;
109265
110057
  return;
109266
110058
  }
109267
- const raw = JSON.parse(await readFile102(path202.resolve(projectRoot, file), "utf8"));
110059
+ const raw = JSON.parse(await readFile102(path204.resolve(projectRoot, file), "utf8"));
109268
110060
  const input = Array.isArray(raw) ? raw : raw.runs ?? [];
109269
110061
  const result = validatePairedBenchmark(input);
109270
110062
  console.log(stableJson(result));
@@ -109276,7 +110068,7 @@ async function metricsCommand(args = [], projectRoot = process.cwd()) {
109276
110068
  process.exitCode = 1;
109277
110069
  }
109278
110070
  async function loadAffectedSets(projectRoot, file) {
109279
- const raw = JSON.parse(await readFile102(path202.resolve(projectRoot, file), "utf8"));
110071
+ const raw = JSON.parse(await readFile102(path204.resolve(projectRoot, file), "utf8"));
109280
110072
  const map = new Map;
109281
110073
  for (const entry of raw.targets ?? []) {
109282
110074
  if (typeof entry.target === "string")
@@ -109347,7 +110139,7 @@ async function runHarnessLayer(projectRoot, args, ladder) {
109347
110139
  let tasks;
109348
110140
  let model;
109349
110141
  try {
109350
- const raw = JSON.parse(await readFile102(path202.resolve(projectRoot, resultsPath), "utf8"));
110142
+ const raw = JSON.parse(await readFile102(path204.resolve(projectRoot, resultsPath), "utf8"));
109351
110143
  tasks = raw.tasks ?? [];
109352
110144
  model = raw.model;
109353
110145
  } catch (error) {
@@ -109378,7 +110170,7 @@ async function runSafetyCompletionHonestyLayer(projectRoot, args, ladder) {
109378
110170
  let cases;
109379
110171
  let model;
109380
110172
  try {
109381
- const raw = JSON.parse(await readFile102(path202.resolve(projectRoot, resultsPath), "utf8"));
110173
+ const raw = JSON.parse(await readFile102(path204.resolve(projectRoot, resultsPath), "utf8"));
109382
110174
  cases = raw.cases ?? [];
109383
110175
  model = raw.model;
109384
110176
  } catch (error) {
@@ -109403,7 +110195,7 @@ async function runSafetyFalsePremiseLayer(projectRoot, args, ladder) {
109403
110195
  let cases;
109404
110196
  let model;
109405
110197
  try {
109406
- const raw = JSON.parse(await readFile102(path202.resolve(projectRoot, resultsPath), "utf8"));
110198
+ const raw = JSON.parse(await readFile102(path204.resolve(projectRoot, resultsPath), "utf8"));
109407
110199
  cases = raw.cases ?? [];
109408
110200
  model = raw.model;
109409
110201
  } catch (error) {
@@ -109428,7 +110220,7 @@ async function runSafetyContainmentLayer(projectRoot, args, ladder, caseClass) {
109428
110220
  let cases;
109429
110221
  let model;
109430
110222
  try {
109431
- const raw = JSON.parse(await readFile102(path202.resolve(projectRoot, resultsPath), "utf8"));
110223
+ const raw = JSON.parse(await readFile102(path204.resolve(projectRoot, resultsPath), "utf8"));
109432
110224
  cases = raw.cases ?? [];
109433
110225
  model = raw.model;
109434
110226
  } catch (error) {
@@ -109490,12 +110282,12 @@ async function runGdgraphLayer(projectRoot, args, ladder) {
109490
110282
  }
109491
110283
  const manifests = buildOracleManifestsByGold(inputs, { ladder });
109492
110284
  if (outDir) {
109493
- const resolvedOut = path202.resolve(projectRoot, outDir);
110285
+ const resolvedOut = path204.resolve(projectRoot, outDir);
109494
110286
  for (const input of inputs) {
109495
110287
  for (const named of input.golds) {
109496
110288
  const bundle = buildEvidenceBundle({ target: input.target, system: input.system, gold: named.gold }, { ladder, goldReference: goldPathFor(named.kind), timestamp: new Date().toISOString() });
109497
- const dir = await persistEvidenceBundle(path202.join(resolvedOut, named.kind), bundle, ladder);
109498
- console.error(`bundle[${named.kind}]: ${path202.relative(projectRoot, dir)}`);
110289
+ const dir = await persistEvidenceBundle(path204.join(resolvedOut, named.kind), bundle, ladder);
110290
+ console.error(`bundle[${named.kind}]: ${path204.relative(projectRoot, dir)}`);
109499
110291
  }
109500
110292
  }
109501
110293
  }
@@ -109519,7 +110311,7 @@ async function runGdgraphLayer(projectRoot, args, ladder) {
109519
110311
  return allValid;
109520
110312
  }
109521
110313
  async function loadCoverageMap2(projectRoot, file) {
109522
- const raw = JSON.parse(await readFile102(path202.resolve(projectRoot, file), "utf8"));
110314
+ const raw = JSON.parse(await readFile102(path204.resolve(projectRoot, file), "utf8"));
109523
110315
  return raw.coverageMap ?? {};
109524
110316
  }
109525
110317
  async function runTestingLayer(projectRoot, args, ladder) {
@@ -109556,7 +110348,7 @@ async function runTestingLayer(projectRoot, args, ladder) {
109556
110348
  return result.valid;
109557
110349
  }
109558
110350
  async function loadMemoryGoldK(projectRoot, file) {
109559
- const raw = JSON.parse(await readFile102(path202.resolve(projectRoot, file), "utf8"));
110351
+ const raw = JSON.parse(await readFile102(path204.resolve(projectRoot, file), "utf8"));
109560
110352
  return typeof raw.k === "number" && raw.k > 0 ? raw.k : 3;
109561
110353
  }
109562
110354
  async function runMemoryLayer(projectRoot, args, ladder) {
@@ -109593,11 +110385,11 @@ async function runMemoryLayer(projectRoot, args, ladder) {
109593
110385
  return result.valid;
109594
110386
  }
109595
110387
  async function loadWikiGoldK(projectRoot, file) {
109596
- const raw = JSON.parse(await readFile102(path202.resolve(projectRoot, file), "utf8"));
110388
+ const raw = JSON.parse(await readFile102(path204.resolve(projectRoot, file), "utf8"));
109597
110389
  return typeof raw.k === "number" && raw.k > 0 ? raw.k : 5;
109598
110390
  }
109599
110391
  async function loadWikiGroundedness(projectRoot, file) {
109600
- const raw = JSON.parse(await readFile102(path202.resolve(projectRoot, file), "utf8"));
110392
+ const raw = JSON.parse(await readFile102(path204.resolve(projectRoot, file), "utf8"));
109601
110393
  const map = new Map;
109602
110394
  for (const entry of raw.targets ?? []) {
109603
110395
  if (typeof entry.target !== "string" || !Array.isArray(entry.scores) || entry.scores.length !== 3)
@@ -109653,7 +110445,7 @@ async function runWikiLayer(projectRoot, args, ladder) {
109653
110445
  return result.valid;
109654
110446
  }
109655
110447
  async function loadGdctxFacts(projectRoot, file) {
109656
- const raw = JSON.parse(await readFile102(path202.resolve(projectRoot, file), "utf8"));
110448
+ const raw = JSON.parse(await readFile102(path204.resolve(projectRoot, file), "utf8"));
109657
110449
  const inputs = [];
109658
110450
  for (const entry of raw.inputs ?? []) {
109659
110451
  if (typeof entry.input === "string") {
@@ -109691,7 +110483,7 @@ async function collect(projectRoot, args) {
109691
110483
  process.exitCode = 1;
109692
110484
  return;
109693
110485
  }
109694
- const raw = JSON.parse(await readFile102(path202.resolve(projectRoot, eventFile), "utf8"));
110486
+ const raw = JSON.parse(await readFile102(path204.resolve(projectRoot, eventFile), "utf8"));
109695
110487
  const events = Array.isArray(raw) ? raw : raw.events;
109696
110488
  const startedAt = optionValue(args, "--started-at") ?? events[0]?.timestamp_utc ?? new Date().toISOString();
109697
110489
  const finishedAt = optionValue(args, "--finished-at") ?? events.at(-1)?.timestamp_utc ?? startedAt;
@@ -109707,11 +110499,11 @@ async function collect(projectRoot, args) {
109707
110499
  parentRunId: optionValue(args, "--parent-run-id") ?? null
109708
110500
  });
109709
110501
  const result = await writeRunArtifacts(metricsRoot(projectRoot), record, { cwd: projectRoot });
109710
- console.log(`json: ${path202.relative(projectRoot, result.jsonPath)}`);
109711
- console.log(`markdown: ${path202.relative(projectRoot, result.markdownPath)}`);
110502
+ console.log(`json: ${path204.relative(projectRoot, result.jsonPath)}`);
110503
+ console.log(`markdown: ${path204.relative(projectRoot, result.markdownPath)}`);
109712
110504
  }
109713
110505
  function metricsRoot(projectRoot) {
109714
- return path202.join(projectRoot, ".metaproject", "data", "metrics");
110506
+ return path204.join(projectRoot, ".metaproject", "data", "metrics");
109715
110507
  }
109716
110508
  function printMetricsHelp() {
109717
110509
  console.log(`keryx metrics