claudish 12.0.1 → 12.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +1649 -422
- package/package.json +5 -5
package/dist/index.js
CHANGED
|
@@ -901,7 +901,7 @@ var init_onepassword_config = __esm(() => {
|
|
|
901
901
|
});
|
|
902
902
|
|
|
903
903
|
// src/version.ts
|
|
904
|
-
var VERSION = "12.
|
|
904
|
+
var VERSION = "12.1.1";
|
|
905
905
|
|
|
906
906
|
// src/logger.ts
|
|
907
907
|
import { appendFile, existsSync as existsSync2, mkdirSync, readdirSync, unlinkSync, writeFileSync as writeFileSync2 } from "fs";
|
|
@@ -45606,7 +45606,8 @@ var init_contract = __esm(() => {
|
|
|
45606
45606
|
"cancel",
|
|
45607
45607
|
"capture",
|
|
45608
45608
|
"capture_since_seq",
|
|
45609
|
-
"capture_spans"
|
|
45609
|
+
"capture_spans",
|
|
45610
|
+
"resize"
|
|
45610
45611
|
];
|
|
45611
45612
|
SLOT_STATES = [
|
|
45612
45613
|
"STARTING",
|
|
@@ -63874,6 +63875,20 @@ function resolveClaudishSpawn(env = process.env) {
|
|
|
63874
63875
|
}
|
|
63875
63876
|
var CLAUDISH_BIN_ENV = "CLAUDISH_BIN";
|
|
63876
63877
|
|
|
63878
|
+
// src/pane/pane-size.ts
|
|
63879
|
+
function clamp(n, lo, hi) {
|
|
63880
|
+
return Math.min(hi, Math.max(lo, Math.trunc(n)));
|
|
63881
|
+
}
|
|
63882
|
+
function clampPaneSize(cols, rows) {
|
|
63883
|
+
const c = clamp(cols, MIN_PANE_COLS, MAX_PANE_COLS);
|
|
63884
|
+
const r = clamp(rows, MIN_PANE_ROWS, MAX_PANE_ROWS);
|
|
63885
|
+
return { cols: c, rows: Math.min(r, Math.floor(MAX_PANE_CELLS / c)) };
|
|
63886
|
+
}
|
|
63887
|
+
function samePaneSize(a, b) {
|
|
63888
|
+
return !!a && !!b && a.cols === b.cols && a.rows === b.rows;
|
|
63889
|
+
}
|
|
63890
|
+
var DEFAULT_PANE_COLS = 160, DEFAULT_PANE_ROWS = 50, MIN_PANE_COLS = 80, MAX_PANE_COLS = 9999, MIN_PANE_ROWS = 24, MAX_PANE_ROWS = 9999, MAX_PANE_CELLS = 4000000, RESIZE_QUIET_MS = 2000;
|
|
63891
|
+
|
|
63877
63892
|
// src/pane/process-identity.ts
|
|
63878
63893
|
import { execFile, execFileSync as execFileSync2 } from "child_process";
|
|
63879
63894
|
import { lstatSync } from "fs";
|
|
@@ -64217,12 +64232,6 @@ function mintPaneId(kind, label) {
|
|
|
64217
64232
|
throw new Error(`minted an invalid pane id: ${id}`);
|
|
64218
64233
|
return id;
|
|
64219
64234
|
}
|
|
64220
|
-
function sockPathFor(root, id) {
|
|
64221
|
-
const p = sockPathOf(root, id);
|
|
64222
|
-
if (Buffer.byteLength(p) >= 100)
|
|
64223
|
-
throw new PaneRootError(`pane socket path ${p} is ${Buffer.byteLength(p)} bytes; it must be < 100`);
|
|
64224
|
-
return p;
|
|
64225
|
-
}
|
|
64226
64235
|
function isStrippedFromChildEnv(key) {
|
|
64227
64236
|
return STRIPPED_CHILD_VARS.includes(key) || key.startsWith("MAGMUX_") || TERMINAL_IDENTITY_VARS.includes(key) || TERMINAL_IDENTITY_PREFIXES.some((p) => key.startsWith(p)) || HOST_IDENTITY_VARS.includes(key);
|
|
64228
64237
|
}
|
|
@@ -64233,8 +64242,8 @@ function buildPaneEnv(input) {
|
|
|
64233
64242
|
continue;
|
|
64234
64243
|
env[k] = v;
|
|
64235
64244
|
}
|
|
64236
|
-
env.COLUMNS =
|
|
64237
|
-
env.LINES =
|
|
64245
|
+
env.COLUMNS = String(input.cols ?? DEFAULT_PANE_COLS);
|
|
64246
|
+
env.LINES = String(input.rows ?? DEFAULT_PANE_ROWS);
|
|
64238
64247
|
if (input.parentEnv.CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC === undefined)
|
|
64239
64248
|
env.CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC = "1";
|
|
64240
64249
|
Object.assign(env, input.slotEnv);
|
|
@@ -64360,24 +64369,46 @@ function versionAtLeast(v, min) {
|
|
|
64360
64369
|
return true;
|
|
64361
64370
|
}
|
|
64362
64371
|
async function assertMagmuxAvailable(binary) {
|
|
64363
|
-
const
|
|
64372
|
+
const key = binary ?? "";
|
|
64373
|
+
const cached = magmuxCache.get(key);
|
|
64364
64374
|
if (cached)
|
|
64365
64375
|
return cached;
|
|
64376
|
+
const inFlight = magmuxProbes.get(key);
|
|
64377
|
+
if (inFlight)
|
|
64378
|
+
return inFlight;
|
|
64379
|
+
const probe = (async () => {
|
|
64380
|
+
try {
|
|
64381
|
+
const result = await probeMagmux(binary);
|
|
64382
|
+
magmuxCache.set(key, result);
|
|
64383
|
+
return result;
|
|
64384
|
+
} finally {
|
|
64385
|
+
magmuxProbes.delete(key);
|
|
64386
|
+
}
|
|
64387
|
+
})();
|
|
64388
|
+
magmuxProbes.set(key, probe);
|
|
64389
|
+
return probe;
|
|
64390
|
+
}
|
|
64391
|
+
async function probeMagmux(binary) {
|
|
64366
64392
|
const found = binary ?? findMagmuxBinaryOrNull();
|
|
64367
64393
|
if (!found)
|
|
64368
64394
|
throw new MagmuxUnavailableError("magmux_unavailable: magmux not found (bundled package or PATH); install it: brew install MadAppGang/tap/magmux");
|
|
64395
|
+
let version = await readMagmuxVersion(found);
|
|
64396
|
+
if (!version)
|
|
64397
|
+
version = await readMagmuxVersion(found);
|
|
64398
|
+
if (!version || !versionAtLeast(version, MIN_MAGMUX_VERSION))
|
|
64399
|
+
throw new MagmuxUnavailableError(`magmux_unavailable: ${found} is version ${version || "unknown"}; panes need >= ${MIN_MAGMUX_VERSION} (a socket at any path depth, and the Claude Code input gate bound to a named transcript); upgrade: brew upgrade MadAppGang/tap/magmux`);
|
|
64400
|
+
return { binary: found, version };
|
|
64401
|
+
}
|
|
64402
|
+
async function readMagmuxVersion(found) {
|
|
64369
64403
|
let out = "";
|
|
64370
64404
|
try {
|
|
64371
|
-
|
|
64405
|
+
const r = await execFileAsync(found, ["--version"], { encoding: "utf8", timeout: 5000 });
|
|
64406
|
+
out = `${r.stdout}
|
|
64407
|
+
${r.stderr}`;
|
|
64372
64408
|
} catch (e) {
|
|
64373
64409
|
throw new MagmuxUnavailableError(`magmux_unavailable: ${found} --version failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
64374
64410
|
}
|
|
64375
|
-
|
|
64376
|
-
if (!version || !versionAtLeast(version, MIN_MAGMUX_VERSION))
|
|
64377
|
-
throw new MagmuxUnavailableError(`magmux_unavailable: ${found} is version ${version || "unknown"}; panes need >= ${MIN_MAGMUX_VERSION}`);
|
|
64378
|
-
const result = { binary: found, version };
|
|
64379
|
-
magmuxCache.set(binary ?? "", result);
|
|
64380
|
-
return result;
|
|
64411
|
+
return out.match(/(\d+\.\d+\.\d+)/)?.[1] ?? "";
|
|
64381
64412
|
}
|
|
64382
64413
|
function resolveClaudishLaunch(parentEnv) {
|
|
64383
64414
|
const t = resolveClaudishSpawn(parentEnv);
|
|
@@ -64426,21 +64457,35 @@ function spawnPaneWatcher(args) {
|
|
|
64426
64457
|
proc.stdin?.unref?.();
|
|
64427
64458
|
return proc;
|
|
64428
64459
|
}
|
|
64429
|
-
function
|
|
64430
|
-
|
|
64460
|
+
function paneMagmuxArgv(input) {
|
|
64461
|
+
return [
|
|
64431
64462
|
"--headless",
|
|
64432
64463
|
"--no-status",
|
|
64464
|
+
"--controller",
|
|
64465
|
+
"claude-code",
|
|
64466
|
+
"--session-id",
|
|
64467
|
+
input.sessionUuid,
|
|
64468
|
+
"--transcript",
|
|
64469
|
+
resolve3(input.transcriptPath),
|
|
64433
64470
|
"--id",
|
|
64434
64471
|
input.paneId,
|
|
64435
64472
|
"--sock-dir",
|
|
64436
64473
|
input.sockRoot,
|
|
64437
64474
|
"-e",
|
|
64438
64475
|
paneCommand(input.ctlDir)
|
|
64439
|
-
]
|
|
64476
|
+
];
|
|
64477
|
+
}
|
|
64478
|
+
function spawnPaneMagmux(input) {
|
|
64479
|
+
const proc = spawn(input.binary, paneMagmuxArgv(input), {
|
|
64480
|
+
cwd: input.cwd,
|
|
64481
|
+
env: input.env,
|
|
64482
|
+
stdio: ["ignore", "ignore", "pipe"],
|
|
64483
|
+
detached: true
|
|
64484
|
+
});
|
|
64440
64485
|
proc.on("error", () => {});
|
|
64441
64486
|
return proc;
|
|
64442
64487
|
}
|
|
64443
|
-
var SOCK_ROOT, PaneRootError, OWNER_START36, TERMINAL_IDENTITY_VARS, TERMINAL_IDENTITY_PREFIXES, HOST_IDENTITY_VARS, LINUX_ENV_STRING_LIMIT = 131000, PaneEnvTooLargeError, OWN_ARGV, TRANSPORT_BREAKERS, IDENTITY_BREAKERS, PRINT_ONLY_FLAGS, MODE_FLAGS, SUBCOMMAND_WORDS, CLAUDE_CODE_VALUE_FLAGS, KNOWN_CLAUDISH_FLAGS, MIN_MAGMUX_VERSION = "0.
|
|
64488
|
+
var SOCK_ROOT, PaneRootError, OWNER_START36, TERMINAL_IDENTITY_VARS, TERMINAL_IDENTITY_PREFIXES, HOST_IDENTITY_VARS, LINUX_ENV_STRING_LIMIT = 131000, PaneEnvTooLargeError, OWN_ARGV, TRANSPORT_BREAKERS, IDENTITY_BREAKERS, PRINT_ONLY_FLAGS, MODE_FLAGS, SUBCOMMAND_WORDS, CLAUDE_CODE_VALUE_FLAGS, KNOWN_CLAUDISH_FLAGS, MIN_MAGMUX_VERSION = "0.18.0", MagmuxUnavailableError, magmuxCache, magmuxProbes, execFileAsync, ClaudishNotFoundError, SHELL_SHIM = `#!/bin/sh
|
|
64444
64489
|
[ "$1" = -l ] && shift
|
|
64445
64490
|
exec /bin/sh "$@"
|
|
64446
64491
|
`, FATAL_MAGMUX_STDERR;
|
|
@@ -64614,15 +64659,30 @@ var init_pane_launch = __esm(() => {
|
|
|
64614
64659
|
code = "magmux_unavailable";
|
|
64615
64660
|
};
|
|
64616
64661
|
magmuxCache = new Map;
|
|
64662
|
+
magmuxProbes = new Map;
|
|
64617
64663
|
execFileAsync = promisify5(execFile2);
|
|
64618
64664
|
ClaudishNotFoundError = class ClaudishNotFoundError extends Error {
|
|
64619
64665
|
code = "pane_lost";
|
|
64620
64666
|
};
|
|
64621
|
-
FATAL_MAGMUX_STDERR = /ignoring --id|
|
|
64667
|
+
FATAL_MAGMUX_STDERR = /ignoring --id|magmux: (?:--sock-dir|MAGMUX_SOCK_DIR) |magmux: socket/;
|
|
64622
64668
|
});
|
|
64623
64669
|
|
|
64624
64670
|
// src/pane/magmux-client.ts
|
|
64625
64671
|
import { Socket } from "net";
|
|
64672
|
+
function failureOf(m) {
|
|
64673
|
+
const out = {
|
|
64674
|
+
ok: false,
|
|
64675
|
+
code: String(m.code ?? "error"),
|
|
64676
|
+
error: String(m.error ?? "")
|
|
64677
|
+
};
|
|
64678
|
+
if (typeof m.reason === "string" && m.reason)
|
|
64679
|
+
out.reason = m.reason;
|
|
64680
|
+
if (typeof m.typed === "boolean")
|
|
64681
|
+
out.typed = m.typed;
|
|
64682
|
+
if (typeof m.maybeSubmitted === "boolean")
|
|
64683
|
+
out.maybeSubmitted = m.maybeSubmitted;
|
|
64684
|
+
return out;
|
|
64685
|
+
}
|
|
64626
64686
|
function dialOnce(sockPath) {
|
|
64627
64687
|
return new Promise((resolve, reject) => {
|
|
64628
64688
|
const s = new Socket;
|
|
@@ -64749,7 +64809,7 @@ class MagmuxClient {
|
|
|
64749
64809
|
return;
|
|
64750
64810
|
clearTimeout(p.timer);
|
|
64751
64811
|
this.pending.delete(m.id);
|
|
64752
|
-
p.resolve(m.ok === true ? { ok: true, result: m.result ?? {} } :
|
|
64812
|
+
p.resolve(m.ok === true ? { ok: true, result: m.result ?? {} } : failureOf(m));
|
|
64753
64813
|
return;
|
|
64754
64814
|
}
|
|
64755
64815
|
if (m.type === "shutdown")
|
|
@@ -65247,6 +65307,352 @@ var init_process_tree = __esm(() => {
|
|
|
65247
65307
|
KILL_PROCESS_GROUP = process.platform !== "win32";
|
|
65248
65308
|
});
|
|
65249
65309
|
|
|
65310
|
+
// src/pane/box-locate.ts
|
|
65311
|
+
function isRuleRow(line) {
|
|
65312
|
+
if (!line || line.length < MIN_RULE_CELLS)
|
|
65313
|
+
return false;
|
|
65314
|
+
return /^\u2500+(?: [^\u2500]+ \u2500+)?$/.test(line);
|
|
65315
|
+
}
|
|
65316
|
+
function nearestRule(lines, from, step) {
|
|
65317
|
+
for (let i = 1;i <= RULE_SEARCH_ROWS; i++) {
|
|
65318
|
+
const r = from + i * step;
|
|
65319
|
+
if (r < 0 || r >= lines.length)
|
|
65320
|
+
return -1;
|
|
65321
|
+
if (isRuleRow(lines[r]))
|
|
65322
|
+
return r;
|
|
65323
|
+
}
|
|
65324
|
+
return -1;
|
|
65325
|
+
}
|
|
65326
|
+
function inspectBox(s) {
|
|
65327
|
+
const lines = s.lines;
|
|
65328
|
+
const y = s.cursor.y;
|
|
65329
|
+
if (!Number.isInteger(y) || y < 0 || y >= s.rows || y >= lines.length) {
|
|
65330
|
+
return { kind: "unknown", why: "cursor_off_screen" };
|
|
65331
|
+
}
|
|
65332
|
+
if (SELECTED_OPTION.test(lines[y] ?? ""))
|
|
65333
|
+
return { kind: "dialog", why: "selected_option" };
|
|
65334
|
+
const top = nearestRule(lines, y, -1);
|
|
65335
|
+
if (top < 0)
|
|
65336
|
+
return { kind: "unknown", why: "no_rule_above" };
|
|
65337
|
+
const bottom = nearestRule(lines, y, 1);
|
|
65338
|
+
if (bottom < 0)
|
|
65339
|
+
return { kind: "unknown", why: "no_rule_below" };
|
|
65340
|
+
const first = lines[top + 1] ?? "";
|
|
65341
|
+
if (SELECTED_OPTION.test(first))
|
|
65342
|
+
return { kind: "dialog", why: "selected_option" };
|
|
65343
|
+
if (lines.slice(bottom + 1).some((l) => SELECT_FOOTER.test(l))) {
|
|
65344
|
+
return { kind: "dialog", why: "select_footer" };
|
|
65345
|
+
}
|
|
65346
|
+
if (!PROMPT_ROW.test(first))
|
|
65347
|
+
return { kind: "unknown", why: "no_prompt_row" };
|
|
65348
|
+
return { kind: "box", box: { top, bottom, caretRow: y } };
|
|
65349
|
+
}
|
|
65350
|
+
function locateBox(s) {
|
|
65351
|
+
const at = inspectBox(s);
|
|
65352
|
+
return at.kind === "box" ? at.box : null;
|
|
65353
|
+
}
|
|
65354
|
+
function visibleText(line, spans) {
|
|
65355
|
+
if (!spans?.length)
|
|
65356
|
+
return line;
|
|
65357
|
+
const chars = Array.from(line);
|
|
65358
|
+
for (const [col, len, , , attr] of spans) {
|
|
65359
|
+
if ((attr & ATTR_FAINT) === 0)
|
|
65360
|
+
continue;
|
|
65361
|
+
for (let c = col;c < col + len && c < chars.length; c++)
|
|
65362
|
+
chars[c] = " ";
|
|
65363
|
+
}
|
|
65364
|
+
return chars.join("");
|
|
65365
|
+
}
|
|
65366
|
+
function locatedBoxText(s, box) {
|
|
65367
|
+
const parts = [];
|
|
65368
|
+
for (let i = box.top + 1;i < box.bottom; i++) {
|
|
65369
|
+
const raw = visibleText(s.lines[i] ?? "", s.spans[i]);
|
|
65370
|
+
const body = i === box.top + 1 ? raw.replace(/^[\u276F!]\s?/, "") : raw.replace(/^ {2}/, "");
|
|
65371
|
+
parts.push(body.replace(/\s+$/, ""));
|
|
65372
|
+
}
|
|
65373
|
+
return parts.join(`
|
|
65374
|
+
`).trim();
|
|
65375
|
+
}
|
|
65376
|
+
var RULE_SEARCH_ROWS = 40, MIN_RULE_CELLS = 20, PROMPT_ROW, SELECTED_OPTION, SELECT_FOOTER, ATTR_FAINT = 2;
|
|
65377
|
+
var init_box_locate = __esm(() => {
|
|
65378
|
+
PROMPT_ROW = /^(\u276F(\u00A0|$)|!)/;
|
|
65379
|
+
SELECTED_OPTION = /^ *\u276F \d+\.\s+\S/;
|
|
65380
|
+
SELECT_FOOTER = /Enter to select \u00B7 \u2191\/\u2193 to navigate/;
|
|
65381
|
+
});
|
|
65382
|
+
|
|
65383
|
+
// src/pane/input-gate.ts
|
|
65384
|
+
function dialogKindOf(reason) {
|
|
65385
|
+
if (!reason?.startsWith(DIALOG_PREFIX))
|
|
65386
|
+
return null;
|
|
65387
|
+
const kind = reason.slice(DIALOG_PREFIX.length);
|
|
65388
|
+
return DIALOG_KINDS.has(kind) ? kind : null;
|
|
65389
|
+
}
|
|
65390
|
+
function str3(v) {
|
|
65391
|
+
return typeof v === "string" && v !== "" ? v : null;
|
|
65392
|
+
}
|
|
65393
|
+
function record4(v) {
|
|
65394
|
+
return v !== null && typeof v === "object" && !Array.isArray(v) ? v : null;
|
|
65395
|
+
}
|
|
65396
|
+
function paneZero(listResult) {
|
|
65397
|
+
const panes = record4(listResult)?.panes;
|
|
65398
|
+
if (!Array.isArray(panes))
|
|
65399
|
+
return null;
|
|
65400
|
+
for (const p of panes) {
|
|
65401
|
+
const row = record4(p);
|
|
65402
|
+
if (row?.pane === 0)
|
|
65403
|
+
return row;
|
|
65404
|
+
}
|
|
65405
|
+
return null;
|
|
65406
|
+
}
|
|
65407
|
+
function parseGateInput(listResult, now) {
|
|
65408
|
+
const input = record4(paneZero(listResult)?.input);
|
|
65409
|
+
if (!input || typeof input.ready !== "boolean")
|
|
65410
|
+
return null;
|
|
65411
|
+
const reason = input.ready ? null : str3(input.reason);
|
|
65412
|
+
return {
|
|
65413
|
+
ready: input.ready,
|
|
65414
|
+
reason,
|
|
65415
|
+
dialog: dialogKindOf(reason),
|
|
65416
|
+
detail: str3(input.detail),
|
|
65417
|
+
receivedAt: now
|
|
65418
|
+
};
|
|
65419
|
+
}
|
|
65420
|
+
function gateBasisOf(listResult) {
|
|
65421
|
+
const basis = paneZero(listResult)?.gateBasis;
|
|
65422
|
+
return basis === "direct" || basis === "declared" ? basis : null;
|
|
65423
|
+
}
|
|
65424
|
+
function parseGateBinding(listResult) {
|
|
65425
|
+
const row = paneZero(listResult);
|
|
65426
|
+
if (!row)
|
|
65427
|
+
return null;
|
|
65428
|
+
const boundRaw = str3(row.bound);
|
|
65429
|
+
const sessionId = str3(row.sessionId);
|
|
65430
|
+
const transcriptPath = str3(row.transcriptPath);
|
|
65431
|
+
let bound = "unbound";
|
|
65432
|
+
if (sessionId && transcriptPath) {
|
|
65433
|
+
if (boundRaw === "named" || boundRaw === "prompt" || boundRaw === "mtime")
|
|
65434
|
+
bound = boundRaw;
|
|
65435
|
+
}
|
|
65436
|
+
return { bound, boundRaw, sessionId, transcriptPath };
|
|
65437
|
+
}
|
|
65438
|
+
function assertNever(x) {
|
|
65439
|
+
throw new Error(`unreachable: ${JSON.stringify(x)}`);
|
|
65440
|
+
}
|
|
65441
|
+
function retypeOf(result) {
|
|
65442
|
+
if (result.retyped !== true)
|
|
65443
|
+
return { retyped: false, retypeCause: null };
|
|
65444
|
+
const cause = result.retypeCause;
|
|
65445
|
+
return {
|
|
65446
|
+
retyped: true,
|
|
65447
|
+
retypeCause: cause === "terminal_reset" || cause === "never_drawn" ? cause : "unknown"
|
|
65448
|
+
};
|
|
65449
|
+
}
|
|
65450
|
+
function okOutcome(result) {
|
|
65451
|
+
const { retyped, retypeCause } = retypeOf(result);
|
|
65452
|
+
const waitedMs = typeof result.waitedMs === "number" ? result.waitedMs : 0;
|
|
65453
|
+
const verified = str3(result.verified);
|
|
65454
|
+
const accept = result.accept;
|
|
65455
|
+
if (accept === "in_box")
|
|
65456
|
+
return { kind: "in_box", retyped, retypeCause, waitedMs, verified };
|
|
65457
|
+
if (accept === undefined) {
|
|
65458
|
+
return {
|
|
65459
|
+
kind: "unexpected",
|
|
65460
|
+
code: "ungated_reply",
|
|
65461
|
+
error: "ok with no accept: the pane is not gated"
|
|
65462
|
+
};
|
|
65463
|
+
}
|
|
65464
|
+
if (accept !== "confirmed" && accept !== "resent_enter" && accept !== "submitted_by_other") {
|
|
65465
|
+
return {
|
|
65466
|
+
kind: "unexpected",
|
|
65467
|
+
code: "unknown_accept",
|
|
65468
|
+
error: `accept ${JSON.stringify(accept)}`
|
|
65469
|
+
};
|
|
65470
|
+
}
|
|
65471
|
+
const evidence = result.evidence;
|
|
65472
|
+
if (evidence !== "history" && evidence !== "transcript") {
|
|
65473
|
+
return {
|
|
65474
|
+
kind: "unexpected",
|
|
65475
|
+
code: "unknown_evidence",
|
|
65476
|
+
error: `accept ${accept} with evidence ${JSON.stringify(evidence)}`
|
|
65477
|
+
};
|
|
65478
|
+
}
|
|
65479
|
+
const dismissed = Array.isArray(result.dismissed) ? result.dismissed.filter((d) => typeof d === "string") : [];
|
|
65480
|
+
return {
|
|
65481
|
+
kind: "accepted",
|
|
65482
|
+
accept,
|
|
65483
|
+
evidence,
|
|
65484
|
+
enterByMagmux: result.enter === true,
|
|
65485
|
+
retyped,
|
|
65486
|
+
retypeCause,
|
|
65487
|
+
dismissed,
|
|
65488
|
+
waitedMs,
|
|
65489
|
+
verified
|
|
65490
|
+
};
|
|
65491
|
+
}
|
|
65492
|
+
function notAcceptedOutcome(r) {
|
|
65493
|
+
const typed = r.typed === true;
|
|
65494
|
+
switch (r.reason) {
|
|
65495
|
+
case "text_mismatch":
|
|
65496
|
+
return {
|
|
65497
|
+
kind: "not_accepted",
|
|
65498
|
+
reason: "text_mismatch",
|
|
65499
|
+
maybeSubmitted: r.maybeSubmitted === true || r.error.includes(MAYBE_SUBMITTED_MARKER),
|
|
65500
|
+
typed,
|
|
65501
|
+
detail: r.error
|
|
65502
|
+
};
|
|
65503
|
+
case "empty_box":
|
|
65504
|
+
case "still_in_box":
|
|
65505
|
+
case "unconfirmed":
|
|
65506
|
+
return {
|
|
65507
|
+
kind: "not_accepted",
|
|
65508
|
+
reason: r.reason,
|
|
65509
|
+
maybeSubmitted: false,
|
|
65510
|
+
typed,
|
|
65511
|
+
detail: r.error
|
|
65512
|
+
};
|
|
65513
|
+
default:
|
|
65514
|
+
return {
|
|
65515
|
+
kind: "unexpected",
|
|
65516
|
+
code: `not_accepted:${r.reason ?? ""}`,
|
|
65517
|
+
error: r.error
|
|
65518
|
+
};
|
|
65519
|
+
}
|
|
65520
|
+
}
|
|
65521
|
+
function classifySendReply(r) {
|
|
65522
|
+
if (r.ok)
|
|
65523
|
+
return okOutcome(record4(r.result) ?? {});
|
|
65524
|
+
switch (r.code) {
|
|
65525
|
+
case "busy": {
|
|
65526
|
+
const reason = r.reason ?? "";
|
|
65527
|
+
return { kind: "busy", reason, dialog: dialogKindOf(reason), typed: r.typed === true };
|
|
65528
|
+
}
|
|
65529
|
+
case "not_accepted":
|
|
65530
|
+
return notAcceptedOutcome(r);
|
|
65531
|
+
case "bad_request":
|
|
65532
|
+
return { kind: "bad_request", error: r.error };
|
|
65533
|
+
case "client_timeout":
|
|
65534
|
+
case "client_lost":
|
|
65535
|
+
case "timeout":
|
|
65536
|
+
return { kind: "reply_lost", code: r.code };
|
|
65537
|
+
case "client_closed":
|
|
65538
|
+
case "no_client":
|
|
65539
|
+
return { kind: "unsent", code: r.code };
|
|
65540
|
+
case "pane_dead":
|
|
65541
|
+
case "no_such_pane":
|
|
65542
|
+
return { kind: "pane_gone", code: r.code, typed: r.typed === true };
|
|
65543
|
+
default:
|
|
65544
|
+
return { kind: "unexpected", code: r.code, error: r.error };
|
|
65545
|
+
}
|
|
65546
|
+
}
|
|
65547
|
+
function readyWaitMs(readyTimeoutMs) {
|
|
65548
|
+
if (readyTimeoutMs <= 0)
|
|
65549
|
+
return SEND_READY_WAIT_DEFAULT_MS;
|
|
65550
|
+
return Math.min(readyTimeoutMs, SEND_READY_WAIT_MAX_MS);
|
|
65551
|
+
}
|
|
65552
|
+
function typedWriteCount(text) {
|
|
65553
|
+
const rs = Array.from(text);
|
|
65554
|
+
let n = 0;
|
|
65555
|
+
let run = 0;
|
|
65556
|
+
for (let i = 0;i < rs.length; i++) {
|
|
65557
|
+
const r = rs[i];
|
|
65558
|
+
if (r === "\r" || r === `
|
|
65559
|
+
`) {
|
|
65560
|
+
if (r === "\r" && rs[i + 1] === `
|
|
65561
|
+
`)
|
|
65562
|
+
i++;
|
|
65563
|
+
if (run > 0) {
|
|
65564
|
+
n++;
|
|
65565
|
+
run = 0;
|
|
65566
|
+
}
|
|
65567
|
+
n++;
|
|
65568
|
+
} else {
|
|
65569
|
+
run++;
|
|
65570
|
+
if (run === SEND_TYPED_CHUNK_RUNES) {
|
|
65571
|
+
n++;
|
|
65572
|
+
run = 0;
|
|
65573
|
+
}
|
|
65574
|
+
}
|
|
65575
|
+
}
|
|
65576
|
+
return run > 0 ? n + 1 : n;
|
|
65577
|
+
}
|
|
65578
|
+
function sendBudgetMs(s) {
|
|
65579
|
+
let attempt = 0;
|
|
65580
|
+
if (s.typed ?? true)
|
|
65581
|
+
attempt += typedWriteCount(s.text) * (SEND_TYPED_CHUNK_GAP_MS + SEND_GATE_CHECK_COST_MS);
|
|
65582
|
+
attempt += s.keys * (SEND_KEY_GAP_MS + SEND_GATE_CHECK_COST_MS);
|
|
65583
|
+
attempt += SEND_SETTLE_MS + SEND_VERIFY_MIN_MS + SEND_VERIFY_STEP_MS;
|
|
65584
|
+
const accept = s.submit ? SEND_ACCEPT_WINDOWS * SEND_ACCEPT_WINDOW_MS : 0;
|
|
65585
|
+
return readyWaitMs(s.readyTimeoutMs) + 2 * attempt + accept + SEND_BUDGET_SLACK_MS;
|
|
65586
|
+
}
|
|
65587
|
+
var DIALOG_KINDS, BOOT_DIALOG_KINDS, DIALOG_PREFIX = "dialog:", MAYBE_SUBMITTED_MARKER = "check the conversation before sending", SEND_READY_WAIT_DEFAULT_MS = 1e4, SEND_READY_WAIT_MAX_MS = 60000, SEND_TYPED_CHUNK_RUNES = 32, SEND_TYPED_CHUNK_GAP_MS = 8, SEND_KEY_GAP_MS = 20, SEND_SETTLE_MS = 150, SEND_VERIFY_MIN_MS = 1200, SEND_VERIFY_STEP_MS = 40, SEND_GATE_CHECK_COST_MS = 2, SEND_ACCEPT_WINDOW_MS = 2000, SEND_ACCEPT_WINDOWS = 3, SEND_BUDGET_SLACK_MS = 2000;
|
|
65588
|
+
var init_input_gate = __esm(() => {
|
|
65589
|
+
DIALOG_KINDS = new Set([
|
|
65590
|
+
"permission",
|
|
65591
|
+
"question",
|
|
65592
|
+
"plan",
|
|
65593
|
+
"select",
|
|
65594
|
+
"trust",
|
|
65595
|
+
"bypass",
|
|
65596
|
+
"api_key",
|
|
65597
|
+
"onboarding"
|
|
65598
|
+
]);
|
|
65599
|
+
BOOT_DIALOG_KINDS = new Set([
|
|
65600
|
+
"trust",
|
|
65601
|
+
"bypass",
|
|
65602
|
+
"api_key",
|
|
65603
|
+
"onboarding"
|
|
65604
|
+
]);
|
|
65605
|
+
});
|
|
65606
|
+
|
|
65607
|
+
// src/pane/gate-binding.ts
|
|
65608
|
+
import { realpathSync as realpathSync2 } from "fs";
|
|
65609
|
+
import { basename as basename2, dirname as dirname14, join as join45, resolve as resolve4 } from "path";
|
|
65610
|
+
function normaliseTranscriptPath(p) {
|
|
65611
|
+
const abs = resolve4(p);
|
|
65612
|
+
const tail = [];
|
|
65613
|
+
let cur = abs;
|
|
65614
|
+
for (;; ) {
|
|
65615
|
+
try {
|
|
65616
|
+
return tail.length ? join45(realpathSync2(cur), ...tail.reverse()) : realpathSync2(cur);
|
|
65617
|
+
} catch {
|
|
65618
|
+
const parent = dirname14(cur);
|
|
65619
|
+
if (parent === cur)
|
|
65620
|
+
return abs;
|
|
65621
|
+
tail.push(basename2(cur));
|
|
65622
|
+
cur = parent;
|
|
65623
|
+
}
|
|
65624
|
+
}
|
|
65625
|
+
}
|
|
65626
|
+
function checkGateBinding(listResult, expected) {
|
|
65627
|
+
const v = expected.magmuxVersion || "?";
|
|
65628
|
+
const basis = gateBasisOf(listResult);
|
|
65629
|
+
if (basis !== "declared" || !parseGateInput(listResult, 0)) {
|
|
65630
|
+
return {
|
|
65631
|
+
ok: false,
|
|
65632
|
+
detail: `input_gate_unavailable: magmux ${v} did not gate pane 0 (gateBasis ${basis ?? "none"})`
|
|
65633
|
+
};
|
|
65634
|
+
}
|
|
65635
|
+
const b = parseGateBinding(listResult);
|
|
65636
|
+
const ours = normaliseTranscriptPath(expected.transcriptPath);
|
|
65637
|
+
const theirs = b?.transcriptPath ? normaliseTranscriptPath(b.transcriptPath) : null;
|
|
65638
|
+
const differs = [];
|
|
65639
|
+
if (b?.bound !== "named" && b?.boundRaw !== "named")
|
|
65640
|
+
differs.push(`bound ${b?.boundRaw ?? "none"}`);
|
|
65641
|
+
if (b?.sessionId !== expected.sessionUuid)
|
|
65642
|
+
differs.push(`sessionId ${b?.sessionId ?? "none"}, not ${expected.sessionUuid}`);
|
|
65643
|
+
if (theirs !== ours)
|
|
65644
|
+
differs.push(`transcriptPath ${theirs ?? "none"}, not ${ours}`);
|
|
65645
|
+
if (b?.bound === "named" && differs.length === 0)
|
|
65646
|
+
return { ok: true };
|
|
65647
|
+
return {
|
|
65648
|
+
ok: false,
|
|
65649
|
+
detail: `input_gate_unbound: magmux ${v} bound pane 0 to ${theirs ?? "none"} (${b?.boundRaw ?? "none"}), not ${ours}: ${differs.join("; ")}`
|
|
65650
|
+
};
|
|
65651
|
+
}
|
|
65652
|
+
var init_gate_binding = __esm(() => {
|
|
65653
|
+
init_input_gate();
|
|
65654
|
+
});
|
|
65655
|
+
|
|
65250
65656
|
// src/pane/screen-model.ts
|
|
65251
65657
|
function emptyScreen(cols, rows) {
|
|
65252
65658
|
return {
|
|
@@ -65264,7 +65670,7 @@ function emptyScreen(cols, rows) {
|
|
|
65264
65670
|
function isBoxRule(line, cols) {
|
|
65265
65671
|
if (!line || !/^\u2500+(?: [^\u2500]+ \u2500+)?$/.test(line))
|
|
65266
65672
|
return false;
|
|
65267
|
-
return line.length >= Math.max(20,
|
|
65673
|
+
return line.length >= Math.max(20, cols - 1);
|
|
65268
65674
|
}
|
|
65269
65675
|
function boxTopRow(lines, cols) {
|
|
65270
65676
|
for (let i = lines.length - 2;i >= 0; i--) {
|
|
@@ -65288,22 +65694,26 @@ function withSize(s, rows) {
|
|
|
65288
65694
|
spans.push([]);
|
|
65289
65695
|
return { lines, spans };
|
|
65290
65696
|
}
|
|
65291
|
-
function aboveBoxText(
|
|
65292
|
-
const
|
|
65293
|
-
return
|
|
65294
|
-
`);
|
|
65697
|
+
function aboveBoxText(s) {
|
|
65698
|
+
const box = locateBox(s);
|
|
65699
|
+
return box ? s.lines.slice(0, box.top).join(`
|
|
65700
|
+
`) : null;
|
|
65295
65701
|
}
|
|
65296
65702
|
function finish(prev, next, now) {
|
|
65297
65703
|
const visible = prev.seq === 0 || prev.cols !== next.cols || prev.rows !== next.rows || prev.alt !== next.alt || prev.cursor.x !== next.cursor.x || prev.cursor.y !== next.cursor.y || next.lines.some((l, i) => l !== prev.lines[i]) || next.spans.some((r, i) => !sameSpans(r, prev.spans[i]));
|
|
65298
65704
|
if (!visible)
|
|
65299
65705
|
return prev;
|
|
65300
|
-
const
|
|
65301
|
-
return {
|
|
65706
|
+
const out = {
|
|
65302
65707
|
...next,
|
|
65303
65708
|
seq: prev.seq + 1,
|
|
65304
65709
|
changedAt: now,
|
|
65305
|
-
aboveBoxChangedAt:
|
|
65710
|
+
aboveBoxChangedAt: prev.aboveBoxChangedAt
|
|
65306
65711
|
};
|
|
65712
|
+
const before = prev.seq === 0 ? null : aboveBoxText(prev);
|
|
65713
|
+
const after = aboveBoxText(out);
|
|
65714
|
+
if (before === null || after === null || before !== after)
|
|
65715
|
+
out.aboveBoxChangedAt = now;
|
|
65716
|
+
return out;
|
|
65307
65717
|
}
|
|
65308
65718
|
function applyFrame(s, frame, now = Date.now()) {
|
|
65309
65719
|
const rows = frame.rows;
|
|
@@ -65328,6 +65738,9 @@ function applyFrame(s, frame, now = Date.now()) {
|
|
|
65328
65738
|
alt: frame.alt ?? s.alt
|
|
65329
65739
|
}, now);
|
|
65330
65740
|
}
|
|
65741
|
+
var init_screen_model = __esm(() => {
|
|
65742
|
+
init_box_locate();
|
|
65743
|
+
});
|
|
65331
65744
|
|
|
65332
65745
|
// src/pane/screen-classifier.ts
|
|
65333
65746
|
function screenText(s) {
|
|
@@ -65337,18 +65750,44 @@ function screenText(s) {
|
|
|
65337
65750
|
return lines.join(`
|
|
65338
65751
|
`);
|
|
65339
65752
|
}
|
|
65340
|
-
function
|
|
65753
|
+
function flatText(lines) {
|
|
65754
|
+
return lines.join(" ").replace(/\s+/g, " ").trim();
|
|
65755
|
+
}
|
|
65756
|
+
function squash(s) {
|
|
65757
|
+
return s.replace(/\s+/g, "");
|
|
65758
|
+
}
|
|
65759
|
+
function echoHeadLength(cols) {
|
|
65760
|
+
return Math.max(1, Math.min(40, cols - 4));
|
|
65761
|
+
}
|
|
65762
|
+
function echoHead(line, cols) {
|
|
65763
|
+
return line.slice(0, echoHeadLength(cols));
|
|
65764
|
+
}
|
|
65765
|
+
function visibleText2(line, spans) {
|
|
65341
65766
|
if (!spans?.length)
|
|
65342
65767
|
return line;
|
|
65343
65768
|
const chars = Array.from(line);
|
|
65344
65769
|
for (const [col, len, , , attr] of spans) {
|
|
65345
|
-
if ((attr &
|
|
65770
|
+
if ((attr & ATTR_FAINT2) === 0)
|
|
65346
65771
|
continue;
|
|
65347
65772
|
for (let c = col;c < col + len && c < chars.length; c++)
|
|
65348
65773
|
chars[c] = " ";
|
|
65349
65774
|
}
|
|
65350
65775
|
return chars.join("");
|
|
65351
65776
|
}
|
|
65777
|
+
function echoAt(lines, i, head) {
|
|
65778
|
+
const first = lines[i] ?? "";
|
|
65779
|
+
if (!first.startsWith("\u276F "))
|
|
65780
|
+
return false;
|
|
65781
|
+
const want = squash(head);
|
|
65782
|
+
let got = squash(first.slice(2));
|
|
65783
|
+
for (let j = i + 1;got.length < want.length && j < lines.length; j++) {
|
|
65784
|
+
const row = lines[j] ?? "";
|
|
65785
|
+
if (!/^ {2}\S/.test(row))
|
|
65786
|
+
break;
|
|
65787
|
+
got += squash(row);
|
|
65788
|
+
}
|
|
65789
|
+
return got.startsWith(want);
|
|
65790
|
+
}
|
|
65352
65791
|
function inputBox(s) {
|
|
65353
65792
|
const top = boxTopRow(s.lines, s.cols);
|
|
65354
65793
|
if (top < 0)
|
|
@@ -65367,7 +65806,7 @@ function boxBottomRow(s, top) {
|
|
|
65367
65806
|
function boxText(s, top, bottom) {
|
|
65368
65807
|
const parts = [];
|
|
65369
65808
|
for (let i = top + 1;i < bottom; i++) {
|
|
65370
|
-
const raw =
|
|
65809
|
+
const raw = visibleText2(s.lines[i] ?? "", s.spans[i]);
|
|
65371
65810
|
const body = i === top + 1 ? raw.replace(/^\u276F\s?/, "") : raw.replace(/^ {2}/, "");
|
|
65372
65811
|
parts.push(body.replace(/\s+$/, ""));
|
|
65373
65812
|
}
|
|
@@ -65400,7 +65839,8 @@ function choiceDialog(s) {
|
|
|
65400
65839
|
const lines = s.lines;
|
|
65401
65840
|
const start = lastBulletRow(lines) + 1;
|
|
65402
65841
|
const below = lines.slice(start);
|
|
65403
|
-
const
|
|
65842
|
+
const flat = flatText(below);
|
|
65843
|
+
const kind = CHOICE_DIALOGS.find((d) => d.header.test(flat))?.kind;
|
|
65404
65844
|
if (!kind)
|
|
65405
65845
|
return null;
|
|
65406
65846
|
if (!below.some((l) => FIRST_OPTION.test(l)))
|
|
@@ -65408,14 +65848,19 @@ function choiceDialog(s) {
|
|
|
65408
65848
|
return { kind, text: below.filter((l) => l.trim()).join(`
|
|
65409
65849
|
`) };
|
|
65410
65850
|
}
|
|
65411
|
-
function
|
|
65412
|
-
return
|
|
65851
|
+
function dialogText(s) {
|
|
65852
|
+
return s.lines.slice(lastBulletRow(s.lines) + 1).filter((l) => l.trim()).join(`
|
|
65853
|
+
`);
|
|
65413
65854
|
}
|
|
65414
65855
|
function isWorking(s) {
|
|
65415
65856
|
const top = boxTopRow(s.lines, s.cols);
|
|
65416
65857
|
const region = top >= 0 ? s.lines.slice(0, top) : s.lines;
|
|
65417
65858
|
return region.some((l) => WORKING_ROW.test(l));
|
|
65418
65859
|
}
|
|
65860
|
+
function workingAboveBox(s) {
|
|
65861
|
+
const box = locateBox(s);
|
|
65862
|
+
return box ? s.lines.slice(0, box.top).some((l) => WORKING_ROW.test(l)) : null;
|
|
65863
|
+
}
|
|
65419
65864
|
function stopHookRunning(s) {
|
|
65420
65865
|
return s.lines.some((l) => /\(running Stop hook\b/.test(l));
|
|
65421
65866
|
}
|
|
@@ -65447,7 +65892,7 @@ function screenAnswer(s, echo) {
|
|
|
65447
65892
|
const lines = s.lines;
|
|
65448
65893
|
const top = boxTopRow(lines, s.cols);
|
|
65449
65894
|
const end = top >= 0 ? top : lines.length;
|
|
65450
|
-
const start = echoRow(lines, end,
|
|
65895
|
+
const start = echoRow(lines, end, echoHead(echo, s.cols)) + 1;
|
|
65451
65896
|
if (start <= 0)
|
|
65452
65897
|
return "";
|
|
65453
65898
|
const out = [];
|
|
@@ -65462,8 +65907,9 @@ function screenAnswer(s, echo) {
|
|
|
65462
65907
|
`).trim();
|
|
65463
65908
|
}
|
|
65464
65909
|
function echoRow(lines, end, head) {
|
|
65910
|
+
const above = lines.slice(0, end);
|
|
65465
65911
|
for (let i = end - 1;i >= 0; i--)
|
|
65466
|
-
if ((
|
|
65912
|
+
if (echoAt(above, i, head))
|
|
65467
65913
|
return i;
|
|
65468
65914
|
return -1;
|
|
65469
65915
|
}
|
|
@@ -65485,9 +65931,9 @@ function agentRejectedLine(text) {
|
|
|
65485
65931
|
const m = text.match(/--agent '([^']+)' not found\.(?: Available agents:[^\n]*)?/);
|
|
65486
65932
|
return m ? m[0] : null;
|
|
65487
65933
|
}
|
|
65488
|
-
function namedDialog(
|
|
65934
|
+
function namedDialog(flat) {
|
|
65489
65935
|
for (const d of NAMED_DIALOGS)
|
|
65490
|
-
if (
|
|
65936
|
+
if (flat.includes(d.marker))
|
|
65491
65937
|
return d.name;
|
|
65492
65938
|
return null;
|
|
65493
65939
|
}
|
|
@@ -65496,22 +65942,20 @@ function isUnnamedChoice(lines) {
|
|
|
65496
65942
|
const yesNo = lines.some((l) => /^\s*(\u276F\s*)?(\d+\.\s+)?(Yes|No)\b|\(esc\)/.test(l));
|
|
65497
65943
|
if (numbered && yesNo)
|
|
65498
65944
|
return true;
|
|
65499
|
-
return lines.some((l) => /Press Enter to continue/.test(l) ||
|
|
65500
|
-
}
|
|
65501
|
-
function
|
|
65502
|
-
const
|
|
65503
|
-
const box = inputBox(s);
|
|
65504
|
-
const named = namedDialog(text);
|
|
65505
|
-
if (box && !named)
|
|
65506
|
-
return box.text === "" ? { kind: "repl" } : { kind: "booting" };
|
|
65945
|
+
return lines.some((l) => /Press Enter to continue/.test(l) || SELECT_FOOTER2.test(l));
|
|
65946
|
+
}
|
|
65947
|
+
function nameBootScreen(s) {
|
|
65948
|
+
const named = namedDialog(flatText(s.lines));
|
|
65507
65949
|
if (named)
|
|
65508
|
-
return { kind: "dialog", name: named, text };
|
|
65950
|
+
return { kind: "dialog", name: named, text: screenText(s) };
|
|
65509
65951
|
if (isUnnamedChoice(s.lines))
|
|
65510
|
-
return { kind: "choice", text };
|
|
65952
|
+
return { kind: "choice", text: screenText(s) };
|
|
65511
65953
|
return { kind: "booting" };
|
|
65512
65954
|
}
|
|
65513
|
-
var NAMED_DIALOGS, CHOICE_DIALOGS, NUMBERED_OPTION, FIRST_OPTION,
|
|
65955
|
+
var NAMED_DIALOGS, CHOICE_DIALOGS, NUMBERED_OPTION, FIRST_OPTION, SELECT_FOOTER2, WORKING_ROW, BULLET, ERROR_ROW, ATTR_FAINT2 = 2, MENU_ROW, NON_ANSWER_ROW;
|
|
65514
65956
|
var init_screen_classifier = __esm(() => {
|
|
65957
|
+
init_box_locate();
|
|
65958
|
+
init_screen_model();
|
|
65515
65959
|
NAMED_DIALOGS = [
|
|
65516
65960
|
{ name: "onboarding", marker: "Choose the text style" },
|
|
65517
65961
|
{ name: "trust", marker: "Is this a project you created or one you trust" },
|
|
@@ -65522,15 +65966,15 @@ var init_screen_classifier = __esm(() => {
|
|
|
65522
65966
|
{ kind: "permission", header: /\bDo you want to proceed\?/ },
|
|
65523
65967
|
{
|
|
65524
65968
|
kind: "permission",
|
|
65525
|
-
header: /\bDo you want to (create|make this edit to|overwrite|delete)
|
|
65969
|
+
header: /\bDo you want to (create|make this edit to|overwrite|delete) .{1,300}?\?/
|
|
65526
65970
|
},
|
|
65527
65971
|
{ kind: "plan", header: /\bWould you like to proceed\?/ },
|
|
65528
65972
|
{ kind: "question", header: /Enter to select \u00B7 \u2191\/\u2193 to navigate/ }
|
|
65529
65973
|
];
|
|
65530
65974
|
NUMBERED_OPTION = /^\s*(\u276F\s*)?\d+\.\s+\S/;
|
|
65531
65975
|
FIRST_OPTION = /^\s*(\u276F\s*)?1\.\s+\S/;
|
|
65532
|
-
|
|
65533
|
-
WORKING_ROW = /^\s*[\u00B7\u2722\u2733\u2736\u273B\u273D*\u25CF\u2217]\s+[A-Z][\w'-]*\u2026(\s+\(
|
|
65976
|
+
SELECT_FOOTER2 = /Enter to (confirm|select)\b.*Esc to cancel/;
|
|
65977
|
+
WORKING_ROW = /^\s*[\u00B7\u2722\u2733\u2736\u273B\u273D*\u25CF\u2217]\s+[A-Z][\w'-]*\u2026(\s+\((?:.*\)|[^)]*))?\s*$/;
|
|
65534
65978
|
BULLET = /^\u23FA(\s|$)/;
|
|
65535
65979
|
ERROR_ROW = /^\u23FA\s.*(API Error\b|Please run \/login|Not logged in|You've hit your|session limit)|^\s*\u23BF\s+API Error\b/;
|
|
65536
65980
|
MENU_ROW = /^\s{2}\u276F \/\S|^\s{4}\/\S|^\s{4}[*+] \S/;
|
|
@@ -65539,7 +65983,7 @@ var init_screen_classifier = __esm(() => {
|
|
|
65539
65983
|
|
|
65540
65984
|
// src/pane/session-registry.ts
|
|
65541
65985
|
import { readFileSync as readFileSync29, readdirSync as readdirSync6 } from "fs";
|
|
65542
|
-
import { join as
|
|
65986
|
+
import { join as join46 } from "path";
|
|
65543
65987
|
function parseRegistryRecord(raw) {
|
|
65544
65988
|
let parsed;
|
|
65545
65989
|
try {
|
|
@@ -65584,7 +66028,7 @@ class SessionRegistry {
|
|
|
65584
66028
|
isAlive;
|
|
65585
66029
|
constructor(o) {
|
|
65586
66030
|
this.o = o;
|
|
65587
|
-
this.dir =
|
|
66031
|
+
this.dir = join46(o.configDir, "sessions");
|
|
65588
66032
|
this.now = o.now ?? Date.now;
|
|
65589
66033
|
this.isAlive = o.isAlive ?? pidAlive;
|
|
65590
66034
|
}
|
|
@@ -65620,7 +66064,7 @@ class SessionRegistry {
|
|
|
65620
66064
|
readPid(pid) {
|
|
65621
66065
|
let raw;
|
|
65622
66066
|
try {
|
|
65623
|
-
raw = readFileSync29(
|
|
66067
|
+
raw = readFileSync29(join46(this.dir, `${pid}.json`), "utf8");
|
|
65624
66068
|
} catch {
|
|
65625
66069
|
return null;
|
|
65626
66070
|
}
|
|
@@ -65665,14 +66109,28 @@ function activityOf(t) {
|
|
|
65665
66109
|
return "finishing";
|
|
65666
66110
|
return "thinking";
|
|
65667
66111
|
}
|
|
66112
|
+
function unconfirmedBy(f) {
|
|
66113
|
+
const g = f.gate;
|
|
66114
|
+
if (g === null)
|
|
66115
|
+
return "gate_unknown";
|
|
66116
|
+
if (!g.ready || g.dialog !== null)
|
|
66117
|
+
return (g.reason ?? "not_ready").slice(0, 48);
|
|
66118
|
+
if (f.working === true)
|
|
66119
|
+
return "working";
|
|
66120
|
+
return null;
|
|
66121
|
+
}
|
|
65668
66122
|
function corroborated(input) {
|
|
65669
66123
|
const quiet = input.corroborationMs ?? CORROBORATION_MS;
|
|
65670
66124
|
if (input.chatQuietMs < quiet)
|
|
65671
66125
|
return { ok: false };
|
|
65672
|
-
if (!input.
|
|
66126
|
+
if (!input.facts)
|
|
65673
66127
|
return { ok: true, anomaly: "screen_unverified" };
|
|
65674
|
-
const
|
|
65675
|
-
|
|
66128
|
+
const why = unconfirmedBy(input.facts);
|
|
66129
|
+
if (why === null)
|
|
66130
|
+
return { ok: true };
|
|
66131
|
+
if (input.chatQuietMs >= (input.corroborationGraceMs ?? CORROBORATION_GRACE_MS))
|
|
66132
|
+
return { ok: true, anomaly: `settle_gate_unconfirmed:${why}` };
|
|
66133
|
+
return { ok: false };
|
|
65676
66134
|
}
|
|
65677
66135
|
function settledAs(by, stopReason, c, extra = []) {
|
|
65678
66136
|
return {
|
|
@@ -65705,10 +66163,13 @@ function pathPrimary(t, input) {
|
|
|
65705
66163
|
function pathSecondary(t, input) {
|
|
65706
66164
|
if (!endingStop(t) || !stopHooksFinished(t, input.session))
|
|
65707
66165
|
return null;
|
|
65708
|
-
if (!input.
|
|
66166
|
+
if (!input.facts)
|
|
65709
66167
|
return null;
|
|
65710
66168
|
const window2 = input.secondaryQuietMs ?? SECONDARY_QUIET_MS;
|
|
65711
|
-
if (input.transcriptQuietMs < window2
|
|
66169
|
+
if (input.transcriptQuietMs < window2)
|
|
66170
|
+
return null;
|
|
66171
|
+
const above = input.facts.aboveBoxQuietMs;
|
|
66172
|
+
if (above !== null && above < window2)
|
|
65712
66173
|
return null;
|
|
65713
66174
|
const c = corroborated(input);
|
|
65714
66175
|
return c.ok ? settledAs("quiet", t.lastAssistant?.stopReason ?? null, c, ["settled_without_turn_duration"]) : null;
|
|
@@ -65739,9 +66200,10 @@ function decideSettle(input) {
|
|
|
65739
66200
|
return endingStop(t) ? settledAs("exit", t.lastAssistant.stopReason, {}) : notYet;
|
|
65740
66201
|
return pathSecondary(t, input) ?? notYet;
|
|
65741
66202
|
}
|
|
65742
|
-
var SECONDARY_QUIET_MS = 32000, CORROBORATION_MS = 500, CONTINUING;
|
|
66203
|
+
var SECONDARY_QUIET_MS = 32000, CORROBORATION_MS = 500, CONTINUING, CORROBORATION_GRACE_MS;
|
|
65743
66204
|
var init_settle_rule = __esm(() => {
|
|
65744
66205
|
CONTINUING = new Set(["tool_use", "pause_turn"]);
|
|
66206
|
+
CORROBORATION_GRACE_MS = SECONDARY_QUIET_MS;
|
|
65745
66207
|
});
|
|
65746
66208
|
|
|
65747
66209
|
// src/pane/slot-state.ts
|
|
@@ -65882,10 +66344,10 @@ import {
|
|
|
65882
66344
|
openSync as openSync8,
|
|
65883
66345
|
readSync as readSync3,
|
|
65884
66346
|
readdirSync as readdirSync7,
|
|
65885
|
-
realpathSync as
|
|
66347
|
+
realpathSync as realpathSync3,
|
|
65886
66348
|
statSync as statSync9
|
|
65887
66349
|
} from "fs";
|
|
65888
|
-
import { join as
|
|
66350
|
+
import { join as join47 } from "path";
|
|
65889
66351
|
function initialFollowerState(resolvePath = safeRealpath) {
|
|
65890
66352
|
return {
|
|
65891
66353
|
turns: [],
|
|
@@ -65900,7 +66362,7 @@ function initialFollowerState(resolvePath = safeRealpath) {
|
|
|
65900
66362
|
}
|
|
65901
66363
|
function safeRealpath(p) {
|
|
65902
66364
|
try {
|
|
65903
|
-
return
|
|
66365
|
+
return realpathSync3(p);
|
|
65904
66366
|
} catch {
|
|
65905
66367
|
return p;
|
|
65906
66368
|
}
|
|
@@ -66413,7 +66875,7 @@ class TranscriptFollower {
|
|
|
66413
66875
|
for (const f of this.subagentFiles()) {
|
|
66414
66876
|
let tail = this.subs.get(f);
|
|
66415
66877
|
if (!tail) {
|
|
66416
|
-
tail = new Tail(
|
|
66878
|
+
tail = new Tail(join47(this.subagentsDir, f));
|
|
66417
66879
|
this.subs.set(f, tail);
|
|
66418
66880
|
}
|
|
66419
66881
|
for (const { line } of tail.read()) {
|
|
@@ -66496,8 +66958,8 @@ var init_transcript_follower = __esm(() => {
|
|
|
66496
66958
|
});
|
|
66497
66959
|
|
|
66498
66960
|
// src/pane/pane-session.ts
|
|
66499
|
-
import { readFileSync as readFileSync30, realpathSync as
|
|
66500
|
-
import { join as
|
|
66961
|
+
import { readFileSync as readFileSync30, realpathSync as realpathSync4, rmSync as rmSync6, statSync as statSync10, writeFileSync as writeFileSync21 } from "fs";
|
|
66962
|
+
import { join as join48 } from "path";
|
|
66501
66963
|
function iso(ms) {
|
|
66502
66964
|
return new Date(ms).toISOString();
|
|
66503
66965
|
}
|
|
@@ -66534,7 +66996,7 @@ class PaneSessionImpl {
|
|
|
66534
66996
|
initialPending;
|
|
66535
66997
|
shape;
|
|
66536
66998
|
queue = [];
|
|
66537
|
-
screen
|
|
66999
|
+
screen;
|
|
66538
67000
|
final = false;
|
|
66539
67001
|
turnIndex = 0;
|
|
66540
67002
|
admission = null;
|
|
@@ -66570,8 +67032,25 @@ class PaneSessionImpl {
|
|
|
66570
67032
|
disagreeCounted = new Set;
|
|
66571
67033
|
exitScrollback = "";
|
|
66572
67034
|
exitLastLine = "";
|
|
66573
|
-
|
|
66574
|
-
|
|
67035
|
+
desiredSize;
|
|
67036
|
+
appliedSize;
|
|
67037
|
+
supportsResize = false;
|
|
67038
|
+
resizeWaiters = [];
|
|
67039
|
+
resizeDraining = false;
|
|
67040
|
+
lastSentSize = null;
|
|
67041
|
+
resizeQuietFrom = 0;
|
|
67042
|
+
resizeQuietUntil = 0;
|
|
67043
|
+
activityChangedAt = 0;
|
|
67044
|
+
gate = null;
|
|
67045
|
+
gateTrusted = false;
|
|
67046
|
+
gateInFlight = false;
|
|
67047
|
+
gateTimer = null;
|
|
67048
|
+
gateDeadSince = 0;
|
|
67049
|
+
lastSend = null;
|
|
67050
|
+
turnAcceptedAt = null;
|
|
67051
|
+
turnErrorLogSize = 0;
|
|
67052
|
+
witnessMissingCounted = false;
|
|
67053
|
+
abandonedIndex = null;
|
|
66575
67054
|
magmux = null;
|
|
66576
67055
|
watcher = null;
|
|
66577
67056
|
client = null;
|
|
@@ -66602,12 +67081,16 @@ class PaneSessionImpl {
|
|
|
66602
67081
|
this.turnDir = ids.turnDir;
|
|
66603
67082
|
this.identity = { paneId: ids.paneId, sessionUuid: o.sessionUuid, ctlDir: ids.ctlDir };
|
|
66604
67083
|
this.shape = o.shape;
|
|
67084
|
+
const size = launchSize(o);
|
|
67085
|
+
this.desiredSize = size;
|
|
67086
|
+
this.appliedSize = { ...size };
|
|
67087
|
+
this.screen = emptyScreen(size.cols, size.rows);
|
|
66605
67088
|
this.initialPending = !!o.initialPrompt;
|
|
66606
67089
|
if (o.initialPrompt)
|
|
66607
67090
|
this.queue.push(o.initialPrompt);
|
|
66608
67091
|
this.secondaryQuietMs = o.timings?.secondaryQuietMs ?? SECONDARY_QUIET_MS;
|
|
66609
67092
|
this.corroborationMs = o.timings?.corroborationMs ?? CORROBORATION_MS;
|
|
66610
|
-
this.follower = new TranscriptFollower(o.transcriptPath,
|
|
67093
|
+
this.follower = new TranscriptFollower(o.transcriptPath, join48(o.transcriptPath.replace(/\.jsonl$/, ""), "subagents"));
|
|
66611
67094
|
this.registry = new SessionRegistry({
|
|
66612
67095
|
configDir: claudeConfigDir(o.parentEnv ?? process.env),
|
|
66613
67096
|
sessionUuid: o.sessionUuid
|
|
@@ -66643,7 +67126,9 @@ class PaneSessionImpl {
|
|
|
66643
67126
|
sockRoot: this.root,
|
|
66644
67127
|
ctlDir: this.ctlDir,
|
|
66645
67128
|
cwd: input.cwd,
|
|
66646
|
-
env: input.env
|
|
67129
|
+
env: input.env,
|
|
67130
|
+
sessionUuid: this.o.sessionUuid,
|
|
67131
|
+
transcriptPath: this.o.transcriptPath
|
|
66647
67132
|
});
|
|
66648
67133
|
} catch (e) {
|
|
66649
67134
|
return this.spawnFailed(e);
|
|
@@ -66652,7 +67137,7 @@ class PaneSessionImpl {
|
|
|
66652
67137
|
return this.spawnFailed(new Error("magmux did not start"));
|
|
66653
67138
|
this.magmux = proc;
|
|
66654
67139
|
try {
|
|
66655
|
-
writeFileSync21(
|
|
67140
|
+
writeFileSync21(join48(this.ctlDir, "magmux.pid"), `${proc.pid}
|
|
66656
67141
|
`, { mode: 384 });
|
|
66657
67142
|
} catch {}
|
|
66658
67143
|
updateRecord(this.root, this.paneId, { magmuxPid: proc.pid });
|
|
@@ -66660,6 +67145,7 @@ class PaneSessionImpl {
|
|
|
66660
67145
|
proc.stderr?.on("data", (d) => this.onStderr(d));
|
|
66661
67146
|
proc.on("exit", (code, sig) => this.onMagmuxExit(code, sig));
|
|
66662
67147
|
this.ticker = setInterval(() => this.step(() => this.evaluate()), TICK_MS);
|
|
67148
|
+
this.gateTimer = setInterval(() => this.pollGate(), GATE_POLL_MS);
|
|
66663
67149
|
if (this.o.timeoutMs !== undefined)
|
|
66664
67150
|
this.timeoutTimer = setTimeout(() => this.step(() => this.fire("timeout")), Math.max(0, this.o.timeoutMs));
|
|
66665
67151
|
await this.connectFirst();
|
|
@@ -66689,7 +67175,6 @@ class PaneSessionImpl {
|
|
|
66689
67175
|
client.close();
|
|
66690
67176
|
return;
|
|
66691
67177
|
}
|
|
66692
|
-
this.client = client;
|
|
66693
67178
|
client.on("snapshot", (e) => this.onSnapshot(e));
|
|
66694
67179
|
client.on("frame", (f) => this.onFrame(f));
|
|
66695
67180
|
client.on("exit", (e) => void this.onPaneExit(e));
|
|
@@ -66701,8 +67186,15 @@ class PaneSessionImpl {
|
|
|
66701
67186
|
const caps = await client.request({
|
|
66702
67187
|
type: "capabilities"
|
|
66703
67188
|
});
|
|
67189
|
+
this.supportsResize = caps.ok && Array.isArray(caps.result.verbs) && caps.result.verbs.includes("resize");
|
|
67190
|
+
if (client.isClosed)
|
|
67191
|
+
return;
|
|
67192
|
+
this.client = client;
|
|
67193
|
+
this.gateTrusted = false;
|
|
67194
|
+
this.gate = null;
|
|
67195
|
+
const magmuxVersion = caps.ok ? String(caps.result.version ?? "") : "";
|
|
66704
67196
|
if (caps.ok) {
|
|
66705
|
-
const v =
|
|
67197
|
+
const v = magmuxVersion;
|
|
66706
67198
|
if (caps.result.protocol !== 1 || !versionAtLeast(v, MIN_MAGMUX_VERSION)) {
|
|
66707
67199
|
this.step(() => this.fire("pane_lost", {
|
|
66708
67200
|
detail: `magmux_unavailable: magmux ${v || "?"} protocol ${caps.result.protocol ?? "?"}; panes need >= ${MIN_MAGMUX_VERSION}, protocol 1`
|
|
@@ -66710,6 +67202,9 @@ class PaneSessionImpl {
|
|
|
66710
67202
|
return;
|
|
66711
67203
|
}
|
|
66712
67204
|
}
|
|
67205
|
+
this.lastSentSize = null;
|
|
67206
|
+
if (this.supportsResize && !samePaneSize(this.appliedSize, this.desiredSize))
|
|
67207
|
+
this.kickResize();
|
|
66713
67208
|
await client.request({ type: "watch", pane: 0, mode: "frames", fps: WATCH_FPS });
|
|
66714
67209
|
const list = await client.request({ type: "list" });
|
|
66715
67210
|
const p0 = list.ok ? list.result.panes?.find((p) => p.pane === 0) : undefined;
|
|
@@ -66719,7 +67214,76 @@ class PaneSessionImpl {
|
|
|
66719
67214
|
if (!reconnect)
|
|
66720
67215
|
await this.nextFrame(500);
|
|
66721
67216
|
this.onPaneExit({ exitCode: p0.exitCode ?? null, lastLine: "" });
|
|
67217
|
+
return;
|
|
67218
|
+
}
|
|
67219
|
+
if (!this.verifyGateBinding(client, list, magmuxVersion) || !list.ok)
|
|
67220
|
+
return;
|
|
67221
|
+
this.gateTrusted = true;
|
|
67222
|
+
this.onGateList(client, list.result);
|
|
67223
|
+
}
|
|
67224
|
+
verifyGateBinding(client, list, magmuxVersion) {
|
|
67225
|
+
if (client.isClosed || isTerminalPhase(this.phase))
|
|
67226
|
+
return false;
|
|
67227
|
+
if (!list.ok) {
|
|
67228
|
+
this.step(() => this.fire("pane_lost", {
|
|
67229
|
+
detail: `input_gate_unbound: magmux ${magmuxVersion || "?"} list failed (${list.code}: ${list.error}), so the binding of pane 0 is unknown`
|
|
67230
|
+
}));
|
|
67231
|
+
return false;
|
|
66722
67232
|
}
|
|
67233
|
+
if (!list.result.panes?.some((p) => p.pane === 0))
|
|
67234
|
+
return false;
|
|
67235
|
+
const check = checkGateBinding(list.result, {
|
|
67236
|
+
sessionUuid: this.o.sessionUuid,
|
|
67237
|
+
transcriptPath: this.o.transcriptPath,
|
|
67238
|
+
magmuxVersion
|
|
67239
|
+
});
|
|
67240
|
+
if (!check.ok) {
|
|
67241
|
+
this.step(() => this.fire("pane_lost", { detail: check.detail }));
|
|
67242
|
+
return false;
|
|
67243
|
+
}
|
|
67244
|
+
return true;
|
|
67245
|
+
}
|
|
67246
|
+
pollGate() {
|
|
67247
|
+
const c = this.client;
|
|
67248
|
+
if (!c || !this.gateTrusted || this.gateInFlight)
|
|
67249
|
+
return;
|
|
67250
|
+
if (this.reaping || isTerminalPhase(this.phase))
|
|
67251
|
+
return;
|
|
67252
|
+
this.gateInFlight = true;
|
|
67253
|
+
c.request({ type: "list" }, GATE_REPLY_MS).then((r) => {
|
|
67254
|
+
this.gateInFlight = false;
|
|
67255
|
+
if (r.ok)
|
|
67256
|
+
this.onGateList(c, r.result);
|
|
67257
|
+
});
|
|
67258
|
+
}
|
|
67259
|
+
onGateList(c, result) {
|
|
67260
|
+
if (c !== this.client || !this.gateTrusted || isTerminalPhase(this.phase))
|
|
67261
|
+
return;
|
|
67262
|
+
const now = Date.now();
|
|
67263
|
+
const p0 = result.panes?.find((p) => p.pane === 0);
|
|
67264
|
+
if (typeof p0?.pid === "number" && !this.panePidValue)
|
|
67265
|
+
this.setPanePid(p0.pid);
|
|
67266
|
+
if (p0?.dead === true && !this.paneExited) {
|
|
67267
|
+
if (this.gateDeadSince === 0)
|
|
67268
|
+
this.gateDeadSince = now;
|
|
67269
|
+
else if (now - this.gateDeadSince >= GATE_DEAD_BACKSTOP_MS) {
|
|
67270
|
+
this.anomaly("exit_event_missing");
|
|
67271
|
+
this.onPaneExit({ exitCode: p0.exitCode ?? null, lastLine: "" });
|
|
67272
|
+
return;
|
|
67273
|
+
}
|
|
67274
|
+
} else
|
|
67275
|
+
this.gateDeadSince = 0;
|
|
67276
|
+
const prev = this.gate;
|
|
67277
|
+
this.gate = parseGateInput(result, now);
|
|
67278
|
+
const g = this.gate;
|
|
67279
|
+
if (prev?.ready !== g?.ready || prev?.reason !== g?.reason)
|
|
67280
|
+
this.step(() => this.evaluate());
|
|
67281
|
+
}
|
|
67282
|
+
gateNow() {
|
|
67283
|
+
const g = this.gate;
|
|
67284
|
+
if (!g || !this.client || !this.gateTrusted)
|
|
67285
|
+
return null;
|
|
67286
|
+
return Date.now() - g.receivedAt <= GATE_STALE_MS ? g : null;
|
|
66723
67287
|
}
|
|
66724
67288
|
onStderr(d) {
|
|
66725
67289
|
if (this.stderrHead.length < 8192)
|
|
@@ -66742,7 +67306,10 @@ class PaneSessionImpl {
|
|
|
66742
67306
|
onFrame(f) {
|
|
66743
67307
|
if (f.pane !== undefined && f.pane !== 0)
|
|
66744
67308
|
return;
|
|
67309
|
+
const seq = this.screen.seq;
|
|
66745
67310
|
this.screen = applyFrame(this.screen, f);
|
|
67311
|
+
if (this.screen.seq !== seq && !this.inResizeQuiet(this.screen.changedAt))
|
|
67312
|
+
this.activityChangedAt = this.screen.changedAt;
|
|
66746
67313
|
this.framePending = true;
|
|
66747
67314
|
if (!this.claudeCodeVersion) {
|
|
66748
67315
|
const m = this.screen.lines.join(`
|
|
@@ -66753,8 +67320,11 @@ class PaneSessionImpl {
|
|
|
66753
67320
|
this.step(() => this.evaluate());
|
|
66754
67321
|
}
|
|
66755
67322
|
onDisconnected(client) {
|
|
66756
|
-
if (this.client === client)
|
|
67323
|
+
if (this.client === client) {
|
|
66757
67324
|
this.client = null;
|
|
67325
|
+
this.gate = null;
|
|
67326
|
+
this.gateTrusted = false;
|
|
67327
|
+
}
|
|
66758
67328
|
if (this.reaping || !alive(this.magmux))
|
|
66759
67329
|
return;
|
|
66760
67330
|
if (isTerminalPhase(this.phase))
|
|
@@ -66946,11 +67516,15 @@ class PaneSessionImpl {
|
|
|
66946
67516
|
if (!this.client)
|
|
66947
67517
|
return;
|
|
66948
67518
|
const idle = status === "idle";
|
|
66949
|
-
const dialog = hasChoiceDialog(this.screen);
|
|
66950
|
-
this.disagree("registry_idle_screen_booting", this.phase === "BOOTING" && idle && readBoot(this.screen).kind !== "repl", now);
|
|
66951
67519
|
this.disagree("registry_idle_screen_working", this.phase === "RUNNING" && idle && isWorking(this.screen), now);
|
|
66952
|
-
this.
|
|
66953
|
-
|
|
67520
|
+
const g = this.gateNow();
|
|
67521
|
+
if (!g)
|
|
67522
|
+
return;
|
|
67523
|
+
this.disagree("registry_idle_gate_starting", this.phase === "BOOTING" && idle && (g.reason === "starting" || g.reason === "no_input_box"), now, REGISTRY_GATE_BOOT_DISAGREE_MS);
|
|
67524
|
+
this.disagree("registry_waiting_gate_no_dialog", status === "waiting" && g.ready, now);
|
|
67525
|
+
this.disagree("gate_dialog_registry_not_waiting", g.dialog !== null && RUNTIME_DIALOG_KINDS.has(g.dialog) && (idle || status === "busy"), now);
|
|
67526
|
+
this.disagree("gate_ready_box_not_located", g.ready && locateBox(this.screen) === null, now);
|
|
67527
|
+
this.disagree("gate_dialog_screen_unrecognised", (g.dialog === "permission" || g.dialog === "plan" || g.dialog === "question") && choiceDialog(this.screen) === null, now);
|
|
66954
67528
|
}
|
|
66955
67529
|
disagree(key, holds, now, forMs = REGISTRY_DISAGREE_MS) {
|
|
66956
67530
|
if (!holds) {
|
|
@@ -66986,33 +67560,42 @@ class PaneSessionImpl {
|
|
|
66986
67560
|
}
|
|
66987
67561
|
evalBoot() {
|
|
66988
67562
|
const now = Date.now();
|
|
66989
|
-
const
|
|
66990
|
-
if (
|
|
66991
|
-
this.bootKind = r.kind;
|
|
66992
|
-
this.bootKindSince = now;
|
|
66993
|
-
}
|
|
66994
|
-
const staticFor = this.screen.seq === 0 ? 0 : now - this.screen.changedAt;
|
|
66995
|
-
const staticMs = this.t("bootStaticMs", BOOT_STATIC_MS);
|
|
66996
|
-
if (r.kind === "repl" && now - this.bootKindSince >= this.t("replStableMs", REPL_STABLE_MS)) {
|
|
67563
|
+
const g = this.gateNow();
|
|
67564
|
+
if (g?.ready) {
|
|
66997
67565
|
this.bootReady();
|
|
66998
67566
|
return;
|
|
66999
67567
|
}
|
|
67000
|
-
|
|
67001
|
-
|
|
67002
|
-
|
|
67003
|
-
|
|
67004
|
-
|
|
67005
|
-
this.fire("boot_blocked", { detail: r.text });
|
|
67568
|
+
const staticFor = this.screen.seq === 0 ? 0 : now - this.screen.changedAt;
|
|
67569
|
+
const settled = staticFor >= this.t("bootStaticMs", BOOT_STATIC_MS);
|
|
67570
|
+
const block = g && settled ? this.bootBlock(g) : null;
|
|
67571
|
+
if (block) {
|
|
67572
|
+
this.fire(block.ev, { detail: block.detail });
|
|
67006
67573
|
return;
|
|
67007
67574
|
}
|
|
67008
67575
|
if (now - this.startedAtMs >= (this.o.bootTimeoutMs ?? BOOT_TIMEOUT_MS)) {
|
|
67009
|
-
const blocked = this.screen.seq > 0 &&
|
|
67576
|
+
const blocked = this.screen.seq > 0 && settled && (g?.reason?.startsWith("dialog:") === true || nameBootScreen(this.screen).kind !== "booting");
|
|
67577
|
+
const gate = g ? `gate: ${g.reason ?? "ready"}${g.detail ? ` (${g.detail})` : ""}` : "gate: unknown";
|
|
67010
67578
|
this.fire("boot_deadline", {
|
|
67011
67579
|
reason: blocked ? "boot_blocked" : "boot_timeout",
|
|
67012
|
-
detail: screenTailOf(this.screen)
|
|
67580
|
+
detail: `${screenTailOf(this.screen)}
|
|
67581
|
+
${gate}`
|
|
67013
67582
|
});
|
|
67014
67583
|
}
|
|
67015
67584
|
}
|
|
67585
|
+
bootBlock(g) {
|
|
67586
|
+
if (g.dialog && BOOT_DIALOG_KINDS.has(g.dialog))
|
|
67587
|
+
return { ev: "boot_dialog", detail: dialogText(this.screen) };
|
|
67588
|
+
const named = nameBootScreen(this.screen);
|
|
67589
|
+
if (named.kind === "dialog")
|
|
67590
|
+
return { ev: "boot_dialog", detail: named.text };
|
|
67591
|
+
if (g.reason === "vim_mode")
|
|
67592
|
+
return { ev: "boot_blocked", detail: "vim editing mode is on (-- INSERT -- under the box)" };
|
|
67593
|
+
if (g.reason?.startsWith("dialog:"))
|
|
67594
|
+
return { ev: "boot_blocked", detail: screenText(this.screen) };
|
|
67595
|
+
if (named.kind === "choice" && g.reason !== null && GATE_KINDLESS_REASONS.has(g.reason))
|
|
67596
|
+
return { ev: "boot_blocked", detail: named.text };
|
|
67597
|
+
return null;
|
|
67598
|
+
}
|
|
67016
67599
|
bootReady() {
|
|
67017
67600
|
this.bootReadyAtMs = Date.now();
|
|
67018
67601
|
if (this.queue.length === 0) {
|
|
@@ -67038,7 +67621,7 @@ class PaneSessionImpl {
|
|
|
67038
67621
|
const head = this.queue.shift();
|
|
67039
67622
|
if (isControl(head)) {
|
|
67040
67623
|
this.exitRequested = true;
|
|
67041
|
-
this.
|
|
67624
|
+
this.submitControl(head.trim());
|
|
67042
67625
|
return;
|
|
67043
67626
|
}
|
|
67044
67627
|
this.fire("admit");
|
|
@@ -67062,6 +67645,9 @@ class PaneSessionImpl {
|
|
|
67062
67645
|
this.screenTurn = null;
|
|
67063
67646
|
this.rewakeOfSettled = false;
|
|
67064
67647
|
this.settledChatOffset = null;
|
|
67648
|
+
this.turnAcceptedAt = null;
|
|
67649
|
+
this.witnessMissingCounted = false;
|
|
67650
|
+
this.abandonedIndex = null;
|
|
67065
67651
|
if (plan.mode === "refused" || plan.mode === "control") {
|
|
67066
67652
|
this.anomaly(`delivery_refused:${plan.mode === "refused" ? plan.reason : "control"}`);
|
|
67067
67653
|
this.admission = null;
|
|
@@ -67077,79 +67663,385 @@ class PaneSessionImpl {
|
|
|
67077
67663
|
}
|
|
67078
67664
|
const delivery = (plan.mode === "file" || plan.mode === "command") && plan.file && plan.fileContent !== undefined ? { file: plan.file, text: plan.fileContent } : null;
|
|
67079
67665
|
this.follower.openTurn({ index, offset, witness: plan.witness, delivery });
|
|
67080
|
-
this.
|
|
67081
|
-
|
|
67082
|
-
|
|
67083
|
-
|
|
67084
|
-
initial,
|
|
67085
|
-
startedAt: Date.now(),
|
|
67086
|
-
deliveredAt: null,
|
|
67087
|
-
resent: false,
|
|
67088
|
-
panelEscaped: false,
|
|
67089
|
-
degraded: false
|
|
67090
|
-
};
|
|
67091
|
-
this.deliver(this.admission);
|
|
67666
|
+
const bound = initial ? this.o.admitTimeoutMs ?? ADMIT_TIMEOUT_MS : ADMIT_TIMEOUT_MS;
|
|
67667
|
+
const adm = newAdmission({ index, text, plan, initial, bound });
|
|
67668
|
+
this.admission = adm;
|
|
67669
|
+
this.runAdmission(adm);
|
|
67092
67670
|
}
|
|
67093
|
-
|
|
67094
|
-
|
|
67095
|
-
adm.deliveredAt = Date.now();
|
|
67671
|
+
admitting(adm) {
|
|
67672
|
+
return this.admission === adm && this.phase === "ADMITTING";
|
|
67096
67673
|
}
|
|
67097
|
-
async
|
|
67098
|
-
|
|
67674
|
+
async runAdmission(adm) {
|
|
67675
|
+
try {
|
|
67676
|
+
while (this.admitting(adm) && adm.submittedUnproven === null && !adm.stopped) {
|
|
67677
|
+
if (Date.now() >= adm.deadline)
|
|
67678
|
+
return;
|
|
67679
|
+
if (adm.panel) {
|
|
67680
|
+
await this.pause(adm, TICK_MS);
|
|
67681
|
+
continue;
|
|
67682
|
+
}
|
|
67683
|
+
if (!this.client || !this.gateTrusted) {
|
|
67684
|
+
await this.awaitTrustedClient(adm);
|
|
67685
|
+
continue;
|
|
67686
|
+
}
|
|
67687
|
+
if (await this.beforeSend(adm) !== "send")
|
|
67688
|
+
continue;
|
|
67689
|
+
if (!this.admitting(adm) || !await this.attemptOnce(adm))
|
|
67690
|
+
return;
|
|
67691
|
+
}
|
|
67692
|
+
} finally {
|
|
67693
|
+
adm.inFlight = false;
|
|
67694
|
+
}
|
|
67695
|
+
}
|
|
67696
|
+
awaitTrustedClient(adm) {
|
|
67697
|
+
return this.waitFor(() => !this.admitting(adm) || !!this.client && this.gateTrusted, Math.max(0, adm.deadline - Date.now()));
|
|
67698
|
+
}
|
|
67699
|
+
async attemptOnce(adm) {
|
|
67700
|
+
const c = this.client;
|
|
67701
|
+
if (!c)
|
|
67702
|
+
return true;
|
|
67703
|
+
const step = adm.step;
|
|
67704
|
+
const shape = sendShape(step, adm.line);
|
|
67705
|
+
const rt = readyTimeoutFor(step, adm.line, adm.deadline - Date.now());
|
|
67706
|
+
if (rt === null)
|
|
67099
67707
|
return false;
|
|
67100
|
-
|
|
67101
|
-
|
|
67102
|
-
|
|
67103
|
-
|
|
67104
|
-
|
|
67105
|
-
|
|
67106
|
-
|
|
67107
|
-
|
|
67108
|
-
|
|
67109
|
-
await this.typeLine(plan.line, true);
|
|
67708
|
+
const timeout = sendBudgetMs({ ...shape.budget, readyTimeoutMs: rt }) + SEND_CLIENT_SLACK_MS;
|
|
67709
|
+
const sentAt = Date.now();
|
|
67710
|
+
adm.inFlight = true;
|
|
67711
|
+
adm.attempts++;
|
|
67712
|
+
let reply;
|
|
67713
|
+
try {
|
|
67714
|
+
reply = await c.request({ ...shape.msg, readyTimeoutMs: rt }, timeout);
|
|
67715
|
+
} finally {
|
|
67716
|
+
adm.inFlight = false;
|
|
67110
67717
|
}
|
|
67718
|
+
const out = classifySendReply(reply);
|
|
67719
|
+
adm.last = out;
|
|
67720
|
+
this.noteLastSend(out, adm.attempts);
|
|
67721
|
+
if (!this.admitting(adm))
|
|
67722
|
+
return false;
|
|
67723
|
+
await this.onSendOutcome(adm, out, step, { client: c, until: sentAt + timeout });
|
|
67111
67724
|
return true;
|
|
67112
67725
|
}
|
|
67113
|
-
async
|
|
67114
|
-
|
|
67115
|
-
|
|
67116
|
-
|
|
67117
|
-
|
|
67118
|
-
|
|
67119
|
-
if (
|
|
67120
|
-
|
|
67121
|
-
|
|
67122
|
-
|
|
67123
|
-
if (await this.landedAfterLostReply(text, enter))
|
|
67124
|
-
return true;
|
|
67726
|
+
async onSendOutcome(adm, out, step, sent) {
|
|
67727
|
+
switch (out.kind) {
|
|
67728
|
+
case "accepted":
|
|
67729
|
+
this.onGateAccepted(adm, out);
|
|
67730
|
+
return;
|
|
67731
|
+
case "in_box":
|
|
67732
|
+
if (step !== "type") {
|
|
67733
|
+
this.anomaly("send_unexpected:in_box");
|
|
67734
|
+
this.stopAdmission(adm, "magmux answered in_box to a send that carried an Enter");
|
|
67735
|
+
return;
|
|
67125
67736
|
}
|
|
67737
|
+
if (out.retyped)
|
|
67738
|
+
this.anomaly(`gate_retyped:${out.retypeCause ?? "unknown"}`);
|
|
67739
|
+
await this.menuCheck(adm);
|
|
67740
|
+
adm.step = "enter";
|
|
67741
|
+
return;
|
|
67742
|
+
case "busy":
|
|
67743
|
+
await this.onBusy(adm, out, step);
|
|
67744
|
+
return;
|
|
67745
|
+
case "not_accepted":
|
|
67746
|
+
await this.onNotAccepted(adm, out, step);
|
|
67747
|
+
return;
|
|
67748
|
+
case "bad_request":
|
|
67749
|
+
this.anomaly("send_bad_request");
|
|
67750
|
+
this.stopAdmission(adm, `send_bad_request: ${out.error}`);
|
|
67751
|
+
return;
|
|
67752
|
+
case "reply_lost":
|
|
67753
|
+
this.anomaly("send_reply_lost");
|
|
67754
|
+
if (step === "type") {
|
|
67755
|
+
adm.lostType = sent;
|
|
67756
|
+
markClearFirst(adm);
|
|
67757
|
+
return;
|
|
67758
|
+
}
|
|
67759
|
+
adm.submittedUnproven = "reply_lost";
|
|
67760
|
+
return;
|
|
67761
|
+
case "unsent":
|
|
67762
|
+
await this.pause(adm, BUSY_RETRY_MS);
|
|
67763
|
+
return;
|
|
67764
|
+
case "pane_gone":
|
|
67765
|
+
adm.stopped = true;
|
|
67766
|
+
return;
|
|
67767
|
+
case "unexpected":
|
|
67768
|
+
this.anomaly(`send_unexpected:${out.code}`);
|
|
67769
|
+
this.stopAdmission(adm, `send_unexpected: ${out.code}${out.error ? `: ${out.error}` : ""}`);
|
|
67770
|
+
return;
|
|
67771
|
+
default:
|
|
67772
|
+
assertNever(out);
|
|
67773
|
+
}
|
|
67774
|
+
}
|
|
67775
|
+
onGateAccepted(adm, out) {
|
|
67776
|
+
if (out.accept === "resent_enter")
|
|
67777
|
+
this.anomaly("gate_resent_enter");
|
|
67778
|
+
if (out.accept === "submitted_by_other")
|
|
67779
|
+
this.anomaly("gate_submitted_by_other");
|
|
67780
|
+
if (out.retyped)
|
|
67781
|
+
this.anomaly(`gate_retyped:${out.retypeCause ?? "unknown"}`);
|
|
67782
|
+
if (out.dismissed.length > 0)
|
|
67783
|
+
this.anomaly("gate_dismissed_unexpected");
|
|
67784
|
+
if (out.evidence === "transcript") {
|
|
67785
|
+
this.anomaly("gate_transcript_evidence");
|
|
67786
|
+
if (!this.witnessNow()) {
|
|
67787
|
+
this.anomaly("gate_transcript_evidence_unwitnessed");
|
|
67788
|
+
adm.submittedUnproven = "unconfirmed";
|
|
67789
|
+
return;
|
|
67126
67790
|
}
|
|
67127
|
-
await Bun.sleep(500);
|
|
67128
67791
|
}
|
|
67129
|
-
this.
|
|
67792
|
+
this.acceptAdmission(adm);
|
|
67793
|
+
}
|
|
67794
|
+
async onBusy(adm, out, step) {
|
|
67795
|
+
const reason = out.reason || "unknown";
|
|
67796
|
+
if (this.stopOnGateBlock(adm, reason, out.dialog))
|
|
67797
|
+
return;
|
|
67798
|
+
if (out.dialog === "select" && step === "enter") {
|
|
67799
|
+
this.noteOnce(adm, "gate_dialog_at_admission:select");
|
|
67800
|
+
adm.panel = { showingSince: null, escaped: false, entered: false };
|
|
67801
|
+
return;
|
|
67802
|
+
}
|
|
67803
|
+
if (out.dialog) {
|
|
67804
|
+
this.noteOnce(adm, `gate_dialog_at_admission:${out.dialog}`);
|
|
67805
|
+
} else if (out.typed) {
|
|
67806
|
+
this.anomaly("gate_typed_withheld");
|
|
67807
|
+
markClearFirst(adm);
|
|
67808
|
+
} else if (reason === "box_not_empty") {
|
|
67809
|
+
this.anomaly("gate_box_not_empty");
|
|
67810
|
+
markClearFirst(adm);
|
|
67811
|
+
} else {
|
|
67812
|
+
this.noteOnce(adm, `gate_busy:${reason}`);
|
|
67813
|
+
}
|
|
67814
|
+
await this.pause(adm, BUSY_RETRY_MS);
|
|
67815
|
+
}
|
|
67816
|
+
stopOnGateBlock(adm, reason, dialog) {
|
|
67817
|
+
if (dialog && BOOT_DIALOG_KINDS.has(dialog)) {
|
|
67818
|
+
this.anomaly(`gate_boot_dialog:${dialog}`);
|
|
67819
|
+
this.stopAdmission(adm, dialogText(this.screen) || `busy ${reason}`, "first_run_dialog");
|
|
67820
|
+
return true;
|
|
67821
|
+
}
|
|
67822
|
+
if (reason === "vim_mode") {
|
|
67823
|
+
this.anomaly("gate_vim_mode");
|
|
67824
|
+
this.stopAdmission(adm, "busy vim_mode: vim editing mode is on (-- INSERT -- under the box)");
|
|
67825
|
+
return true;
|
|
67826
|
+
}
|
|
67130
67827
|
return false;
|
|
67131
67828
|
}
|
|
67132
|
-
async
|
|
67133
|
-
|
|
67134
|
-
|
|
67135
|
-
|
|
67136
|
-
|
|
67137
|
-
|
|
67138
|
-
|
|
67139
|
-
if (
|
|
67140
|
-
|
|
67141
|
-
|
|
67142
|
-
|
|
67829
|
+
async precheckGate(adm) {
|
|
67830
|
+
const g = this.gateNow();
|
|
67831
|
+
if (!g || g.ready)
|
|
67832
|
+
return "send";
|
|
67833
|
+
if (this.stopOnGateBlock(adm, g.reason ?? "unknown", g.dialog))
|
|
67834
|
+
return "stopped";
|
|
67835
|
+
const kind = g.dialog;
|
|
67836
|
+
if (kind !== "permission" && kind !== "question" && kind !== "plan")
|
|
67837
|
+
return "send";
|
|
67838
|
+
this.noteOnce(adm, `gate_dialog_at_admission:${kind}`);
|
|
67839
|
+
await this.waitFor(() => !this.admitting(adm) || this.gateNow()?.dialog !== kind, Math.max(0, adm.deadline - Date.now()));
|
|
67840
|
+
return "waited";
|
|
67841
|
+
}
|
|
67842
|
+
async beforeSend(adm) {
|
|
67843
|
+
if (adm.step === "enter")
|
|
67844
|
+
return "send";
|
|
67845
|
+
await this.clearLeftover(adm);
|
|
67846
|
+
if (!this.admitting(adm))
|
|
67847
|
+
return "stopped";
|
|
67848
|
+
return this.precheckGate(adm);
|
|
67849
|
+
}
|
|
67850
|
+
async onNotAccepted(adm, out, step) {
|
|
67851
|
+
switch (out.reason) {
|
|
67852
|
+
case "text_mismatch":
|
|
67853
|
+
if (out.maybeSubmitted) {
|
|
67854
|
+
this.anomaly("gate_maybe_submitted_by_other");
|
|
67855
|
+
adm.submittedUnproven = "maybe_submitted_by_other";
|
|
67856
|
+
return;
|
|
67857
|
+
}
|
|
67858
|
+
this.anomaly("gate_text_mismatch");
|
|
67859
|
+
markClearFirst(adm);
|
|
67860
|
+
if (adm.plan.mode === "command")
|
|
67861
|
+
adm.step = "type";
|
|
67862
|
+
await this.pause(adm, MISMATCH_SETTLE_MS);
|
|
67863
|
+
return;
|
|
67864
|
+
case "empty_box":
|
|
67865
|
+
if (step === "enter") {
|
|
67866
|
+
this.anomaly("gate_command_left_box");
|
|
67867
|
+
adm.submittedUnproven = "maybe_submitted_by_other";
|
|
67868
|
+
return;
|
|
67869
|
+
}
|
|
67870
|
+
this.anomaly("gate_empty_box");
|
|
67871
|
+
await this.pause(adm, BUSY_RETRY_MS);
|
|
67872
|
+
return;
|
|
67873
|
+
case "still_in_box":
|
|
67874
|
+
if (this.witnessNow()) {
|
|
67875
|
+
this.acceptAdmission(adm);
|
|
67876
|
+
return;
|
|
67877
|
+
}
|
|
67878
|
+
this.anomaly("gate_still_in_box");
|
|
67879
|
+
if (adm.stuckRetried) {
|
|
67880
|
+
adm.submittedUnproven = "still_in_box_twice";
|
|
67881
|
+
return;
|
|
67882
|
+
}
|
|
67883
|
+
adm.stuckRetried = true;
|
|
67884
|
+
await this.clearBox(adm);
|
|
67885
|
+
if (adm.plan.mode === "command")
|
|
67886
|
+
adm.step = "type";
|
|
67887
|
+
return;
|
|
67888
|
+
case "unconfirmed":
|
|
67889
|
+
this.anomaly("gate_unconfirmed");
|
|
67890
|
+
adm.submittedUnproven = "unconfirmed";
|
|
67891
|
+
if (step === "enter")
|
|
67892
|
+
adm.panel = { showingSince: null, escaped: false, entered: true };
|
|
67893
|
+
return;
|
|
67894
|
+
default:
|
|
67895
|
+
assertNever(out.reason);
|
|
67896
|
+
}
|
|
67897
|
+
}
|
|
67898
|
+
acceptAdmission(adm) {
|
|
67899
|
+
this.step(() => {
|
|
67900
|
+
if (this.admitting(adm))
|
|
67901
|
+
this.accept();
|
|
67902
|
+
});
|
|
67903
|
+
}
|
|
67904
|
+
stopAdmission(adm, detail, reason) {
|
|
67905
|
+
adm.stopped = true;
|
|
67906
|
+
this.step(() => {
|
|
67907
|
+
if (!this.admitting(adm))
|
|
67908
|
+
return;
|
|
67909
|
+
this.admission = null;
|
|
67910
|
+
if (adm.initial) {
|
|
67911
|
+
this.fire("admit_deadline", { reason, detail: `${detail}
|
|
67912
|
+
${screenTailOf(this.screen)}` });
|
|
67913
|
+
return;
|
|
67914
|
+
}
|
|
67915
|
+
this.anomaly("send_not_accepted");
|
|
67916
|
+
this.abandonedIndex = adm.index;
|
|
67917
|
+
this.fire("admit_abandoned");
|
|
67918
|
+
});
|
|
67919
|
+
}
|
|
67920
|
+
witnessNow() {
|
|
67921
|
+
return this.witnessed(this.pollFollower(true).current);
|
|
67922
|
+
}
|
|
67923
|
+
noteOnce(adm, key) {
|
|
67924
|
+
if (adm.noted.has(key))
|
|
67925
|
+
return;
|
|
67926
|
+
adm.noted.add(key);
|
|
67927
|
+
this.anomaly(key);
|
|
67928
|
+
}
|
|
67929
|
+
pause(adm, ms) {
|
|
67930
|
+
return this.waitFor(() => !this.admitting(adm), ms);
|
|
67931
|
+
}
|
|
67932
|
+
freshReady(after) {
|
|
67933
|
+
const g = this.gateNow();
|
|
67934
|
+
return !!g && g.receivedAt > after && g.ready;
|
|
67935
|
+
}
|
|
67936
|
+
async clearBox(adm) {
|
|
67937
|
+
const at = Date.now();
|
|
67938
|
+
await this.key("ctrl-u");
|
|
67939
|
+
await this.waitFor(() => !this.admitting(adm) || this.freshReady(at), CLEAR_WAIT_MS);
|
|
67940
|
+
}
|
|
67941
|
+
async clearLeftover(adm) {
|
|
67942
|
+
const lost = adm.lostType;
|
|
67943
|
+
if (lost) {
|
|
67944
|
+
adm.lostType = null;
|
|
67945
|
+
if (lost.client !== this.client || lost.client.isClosed)
|
|
67946
|
+
await this.pause(adm, Math.max(0, lost.until - Date.now()));
|
|
67947
|
+
if (!this.admitting(adm))
|
|
67948
|
+
return;
|
|
67949
|
+
}
|
|
67950
|
+
if (adm.clearFirst)
|
|
67951
|
+
await this.clearOwnLeftover(adm);
|
|
67952
|
+
else if (this.gateNow()?.reason === "box_not_empty")
|
|
67953
|
+
await this.clearBox(adm);
|
|
67954
|
+
}
|
|
67955
|
+
async clearOwnLeftover(adm) {
|
|
67956
|
+
const after = adm.clearAfter + GATE_POLL_MS;
|
|
67957
|
+
const newer = () => {
|
|
67958
|
+
const g = this.gateNow();
|
|
67959
|
+
return g && g.receivedAt > after ? g : null;
|
|
67960
|
+
};
|
|
67961
|
+
await this.waitFor(() => !this.admitting(adm) || newer() !== null, CLEAR_WAIT_MS + GATE_POLL_MS);
|
|
67962
|
+
if (!this.admitting(adm))
|
|
67963
|
+
return;
|
|
67964
|
+
const g = newer();
|
|
67965
|
+
if (g?.ready) {
|
|
67966
|
+
adm.clearFirst = false;
|
|
67967
|
+
return;
|
|
67968
|
+
}
|
|
67969
|
+
if (g && (g.dialog !== null || g.reason === "vim_mode"))
|
|
67970
|
+
return;
|
|
67971
|
+
adm.clearFirst = false;
|
|
67972
|
+
await this.clearBox(adm);
|
|
67973
|
+
}
|
|
67974
|
+
async menuCheck(adm) {
|
|
67975
|
+
const name = adm.line.match(/^\/\S+/)?.[0] ?? "";
|
|
67976
|
+
await this.waitFor(() => {
|
|
67977
|
+
if (!this.admitting(adm))
|
|
67978
|
+
return true;
|
|
67979
|
+
const box = locateBox(this.screen);
|
|
67980
|
+
return !!box && locatedBoxText(this.screen, box).startsWith(name);
|
|
67981
|
+
}, 2 * TICK_MS);
|
|
67982
|
+
if (!this.admitting(adm))
|
|
67983
|
+
return;
|
|
67984
|
+
const box = locateBox(this.screen);
|
|
67985
|
+
if (!box) {
|
|
67986
|
+
this.anomaly("menu_unverified");
|
|
67987
|
+
return;
|
|
67988
|
+
}
|
|
67989
|
+
const menu = menuAbove(this.screen.lines, box.top);
|
|
67990
|
+
if (menu.menuOpen && menu.menuItem !== name)
|
|
67991
|
+
await this.key("escape");
|
|
67992
|
+
}
|
|
67993
|
+
noteLastSend(out, attempts) {
|
|
67994
|
+
const s = { kind: out.kind, attempts };
|
|
67995
|
+
switch (out.kind) {
|
|
67996
|
+
case "accepted":
|
|
67997
|
+
s.accept = out.accept;
|
|
67998
|
+
s.evidence = out.evidence;
|
|
67999
|
+
if (out.retypeCause)
|
|
68000
|
+
s.retypeCause = out.retypeCause;
|
|
68001
|
+
break;
|
|
68002
|
+
case "in_box":
|
|
68003
|
+
s.accept = "in_box";
|
|
68004
|
+
if (out.retypeCause)
|
|
68005
|
+
s.retypeCause = out.retypeCause;
|
|
68006
|
+
break;
|
|
68007
|
+
case "busy":
|
|
68008
|
+
case "not_accepted":
|
|
68009
|
+
s.reason = out.reason;
|
|
68010
|
+
break;
|
|
68011
|
+
case "bad_request":
|
|
68012
|
+
s.reason = "bad_request";
|
|
68013
|
+
break;
|
|
68014
|
+
case "reply_lost":
|
|
68015
|
+
case "unsent":
|
|
68016
|
+
case "pane_gone":
|
|
68017
|
+
case "unexpected":
|
|
68018
|
+
s.reason = out.code;
|
|
68019
|
+
break;
|
|
68020
|
+
default:
|
|
68021
|
+
assertNever(out);
|
|
68022
|
+
}
|
|
68023
|
+
this.lastSend = s;
|
|
68024
|
+
return s;
|
|
68025
|
+
}
|
|
68026
|
+
async submitControl(line) {
|
|
68027
|
+
const c = this.client;
|
|
68028
|
+
if (!c) {
|
|
68029
|
+
this.anomaly("control_send:unsent");
|
|
68030
|
+
return;
|
|
67143
68031
|
}
|
|
67144
|
-
|
|
67145
|
-
|
|
67146
|
-
|
|
68032
|
+
const rt = SEND_READY_WAIT_DEFAULT_MS;
|
|
68033
|
+
const shape = sendShape("submit", line);
|
|
68034
|
+
const r = await c.request({ ...shape.msg, readyTimeoutMs: rt }, sendBudgetMs({ ...shape.budget, readyTimeoutMs: rt }) + SEND_CLIENT_SLACK_MS);
|
|
68035
|
+
const out = classifySendReply(r);
|
|
68036
|
+
const s = this.noteLastSend(out, 1);
|
|
68037
|
+
if (out.kind !== "accepted")
|
|
68038
|
+
this.anomaly(`control_send:${out.kind}${s.reason ? `:${s.reason}` : ""}`);
|
|
67147
68039
|
}
|
|
67148
68040
|
async key(k) {
|
|
67149
68041
|
const c = this.client;
|
|
67150
68042
|
if (!c)
|
|
67151
68043
|
return false;
|
|
67152
|
-
const r = await c.request({ type: "send", pane: 0, keys: [k], enter: false }, 1e4);
|
|
68044
|
+
const r = await c.request({ type: "send", pane: 0, keys: [k], enter: false, noGate: true }, 1e4);
|
|
67153
68045
|
return r.ok;
|
|
67154
68046
|
}
|
|
67155
68047
|
nextFrame(ms) {
|
|
@@ -67169,139 +68061,134 @@ class PaneSessionImpl {
|
|
|
67169
68061
|
const adm = this.admission;
|
|
67170
68062
|
if (!adm)
|
|
67171
68063
|
return;
|
|
67172
|
-
|
|
67173
|
-
if (cur && cur.index === adm.index && cur.acceptedAt !== null) {
|
|
68064
|
+
if (this.witnessed(view.current)) {
|
|
67174
68065
|
this.accept();
|
|
67175
68066
|
return;
|
|
67176
68067
|
}
|
|
67177
|
-
|
|
67178
|
-
|
|
67179
|
-
if (
|
|
67180
|
-
return;
|
|
67181
|
-
if (adm.deliveredAt && since >= this.t("resendAfterMs", RESEND_AFTER_MS))
|
|
67182
|
-
this.nudge(adm);
|
|
67183
|
-
if (adm.deliveredAt && (view.availability === "off" || since >= this.t("degradedEntryMs", DEGRADED_ENTRY_MS)))
|
|
67184
|
-
this.maybeDegradedAccept(adm, view);
|
|
67185
|
-
if (this.phase !== "ADMITTING")
|
|
68068
|
+
if (adm.panel)
|
|
68069
|
+
this.panelStep(adm);
|
|
68070
|
+
if (!this.admitting(adm))
|
|
67186
68071
|
return;
|
|
67187
|
-
if (now
|
|
68072
|
+
if (Date.now() >= adm.deadline && !adm.inFlight)
|
|
67188
68073
|
this.admitExpired(adm);
|
|
67189
68074
|
}
|
|
67190
|
-
|
|
67191
|
-
return
|
|
68075
|
+
panelShowing(g) {
|
|
68076
|
+
return !!g && (g.reason === "no_input_box" || g.dialog === "select") && /Esc to cancel/.test(flatText(this.screen.lines));
|
|
67192
68077
|
}
|
|
67193
|
-
|
|
67194
|
-
|
|
67195
|
-
|
|
67196
|
-
return false;
|
|
67197
|
-
adm.panelEscaped = true;
|
|
67198
|
-
this.anomaly("panel_dismissed");
|
|
67199
|
-
this.key("escape");
|
|
67200
|
-
return true;
|
|
67201
|
-
}
|
|
67202
|
-
const box = inputBox(this.screen);
|
|
67203
|
-
if (!box || box.text !== "" || this.panelOpen())
|
|
67204
|
-
return false;
|
|
67205
|
-
this.admission = null;
|
|
67206
|
-
this.anomaly("panel_command");
|
|
67207
|
-
if (adm.initial)
|
|
67208
|
-
this.fire("admit_deadline", {
|
|
67209
|
-
detail: `${adm.text.trim()} opened a panel and wrote no transcript record`
|
|
67210
|
-
});
|
|
67211
|
-
else
|
|
67212
|
-
this.fire("admit_abandoned");
|
|
67213
|
-
return true;
|
|
67214
|
-
}
|
|
67215
|
-
async awaitClearedBox(adm, head) {
|
|
67216
|
-
const end = Date.now() + this.t("nudgeClearDeadlineMs", NUDGE_CLEAR_DEADLINE_MS);
|
|
67217
|
-
for (;; ) {
|
|
67218
|
-
if (this.admission !== adm || this.phase !== "ADMITTING")
|
|
67219
|
-
return "gone";
|
|
67220
|
-
const box = inputBox(this.screen);
|
|
67221
|
-
if (box && box.text === "")
|
|
67222
|
-
return "empty";
|
|
67223
|
-
if (box && !box.text.startsWith(head))
|
|
67224
|
-
return "other";
|
|
67225
|
-
const left = end - Date.now();
|
|
67226
|
-
if (left <= 0)
|
|
67227
|
-
return box ? "line" : "other";
|
|
67228
|
-
await this.nextFrame(left);
|
|
67229
|
-
}
|
|
67230
|
-
}
|
|
67231
|
-
nudge(adm) {
|
|
67232
|
-
const box = inputBox(this.screen);
|
|
67233
|
-
const line = adm.plan.mode === "control" || adm.plan.mode === "refused" ? "" : adm.plan.line;
|
|
67234
|
-
const head = line.slice(0, 40);
|
|
67235
|
-
if (!adm.resent && box && line && box.text.startsWith(head)) {
|
|
67236
|
-
adm.resent = true;
|
|
67237
|
-
this.anomaly("resent_enter");
|
|
67238
|
-
(async () => {
|
|
67239
|
-
if (box.menuOpen)
|
|
67240
|
-
await this.key("escape");
|
|
67241
|
-
await this.key("ctrl-u");
|
|
67242
|
-
const after = await this.awaitClearedBox(adm, head);
|
|
67243
|
-
if (after === "gone")
|
|
67244
|
-
return;
|
|
67245
|
-
if (after === "empty") {
|
|
67246
|
-
this.anomaly("retyped_prompt");
|
|
67247
|
-
await this.typeAndSubmit(adm.plan);
|
|
67248
|
-
} else if (after === "line") {
|
|
67249
|
-
await this.key("enter");
|
|
67250
|
-
} else {
|
|
67251
|
-
this.anomaly("clear_failed");
|
|
67252
|
-
}
|
|
67253
|
-
})();
|
|
68078
|
+
panelStep(adm) {
|
|
68079
|
+
const p = adm.panel;
|
|
68080
|
+
if (!p)
|
|
67254
68081
|
return;
|
|
67255
|
-
|
|
67256
|
-
if (!
|
|
67257
|
-
|
|
67258
|
-
|
|
68082
|
+
const g = this.gateNow();
|
|
68083
|
+
if (!p.escaped) {
|
|
68084
|
+
if (!this.panelShowing(g)) {
|
|
68085
|
+
p.showingSince = null;
|
|
68086
|
+
return;
|
|
68087
|
+
}
|
|
68088
|
+
const now = Date.now();
|
|
68089
|
+
p.showingSince ??= now;
|
|
68090
|
+
if (now - p.showingSince < PANEL_SETTLE_MS)
|
|
68091
|
+
return;
|
|
68092
|
+
p.escaped = true;
|
|
68093
|
+
this.anomaly(g?.dialog === "select" ? "picker_dismissed" : "panel_dismissed");
|
|
67259
68094
|
this.key("escape");
|
|
67260
|
-
}
|
|
67261
|
-
}
|
|
67262
|
-
maybeDegradedAccept(adm, view) {
|
|
67263
|
-
if (view.availability === "ok")
|
|
67264
68095
|
return;
|
|
67265
|
-
|
|
67266
|
-
if (!
|
|
68096
|
+
}
|
|
68097
|
+
if (!g)
|
|
67267
68098
|
return;
|
|
67268
|
-
|
|
67269
|
-
|
|
67270
|
-
|
|
67271
|
-
|
|
68099
|
+
if (g.ready) {
|
|
68100
|
+
this.admission = null;
|
|
68101
|
+
this.anomaly("panel_command");
|
|
68102
|
+
if (adm.initial)
|
|
68103
|
+
this.fire("admit_deadline", {
|
|
68104
|
+
detail: `${adm.text.trim()} opened a panel and wrote no transcript record`
|
|
68105
|
+
});
|
|
68106
|
+
else
|
|
68107
|
+
this.fire("admit_abandoned");
|
|
67272
68108
|
return;
|
|
67273
|
-
|
|
67274
|
-
|
|
67275
|
-
|
|
67276
|
-
this.accept();
|
|
68109
|
+
}
|
|
68110
|
+
if (!p.entered && g.reason === "box_not_empty")
|
|
68111
|
+
adm.panel = null;
|
|
67277
68112
|
}
|
|
67278
68113
|
accept() {
|
|
67279
68114
|
this.admission = null;
|
|
67280
68115
|
this.initialDelivery = false;
|
|
67281
|
-
|
|
68116
|
+
const now = Date.now();
|
|
68117
|
+
this.lastChatSeenAt = now;
|
|
68118
|
+
this.turnAcceptedAt = now;
|
|
68119
|
+
this.turnErrorLogSize = this.errorLogSize();
|
|
67282
68120
|
this.fire("prompt_accepted");
|
|
67283
68121
|
}
|
|
67284
68122
|
admitExpired(adm) {
|
|
67285
68123
|
this.admission = null;
|
|
67286
68124
|
if (adm.initial) {
|
|
67287
|
-
this.fire("admit_deadline", {
|
|
68125
|
+
this.fire("admit_deadline", {
|
|
68126
|
+
detail: `${this.notAcceptedLine(adm)}
|
|
68127
|
+
${screenTailOf(this.screen)}`
|
|
68128
|
+
});
|
|
67288
68129
|
return;
|
|
67289
68130
|
}
|
|
67290
68131
|
this.anomaly("send_not_accepted");
|
|
68132
|
+
this.abandonedIndex = adm.index;
|
|
67291
68133
|
this.fire("admit_abandoned");
|
|
67292
68134
|
}
|
|
67293
|
-
|
|
68135
|
+
notAcceptedLine(adm) {
|
|
68136
|
+
const secs = Math.round((Date.now() - adm.startedAt) / 1000);
|
|
68137
|
+
switch (adm.submittedUnproven) {
|
|
68138
|
+
case "maybe_submitted_by_other":
|
|
68139
|
+
return "magmux could not tell whether the prompt was submitted (the box emptied without its Enter) and no transcript record of it appeared";
|
|
68140
|
+
case "unconfirmed":
|
|
68141
|
+
return `magmux not_accepted unconfirmed: Enter was pressed with no evidence it was submitted, and no transcript record appeared in ${secs} s`;
|
|
68142
|
+
case "reply_lost": {
|
|
68143
|
+
const code = adm.last?.kind === "reply_lost" ? adm.last.code : "client_lost";
|
|
68144
|
+
return `the magmux send reply was lost (${code}) and no transcript record of the prompt appeared in ${secs} s`;
|
|
68145
|
+
}
|
|
68146
|
+
case "still_in_box_twice":
|
|
68147
|
+
return "magmux not_accepted still_in_box: the prompt stayed in the input box after Enter, twice";
|
|
68148
|
+
case null:
|
|
68149
|
+
return `prompt not accepted in ${secs} s; ${describeLastReply(adm, this.gateNow())}`;
|
|
68150
|
+
default:
|
|
68151
|
+
return assertNever(adm.submittedUnproven);
|
|
68152
|
+
}
|
|
68153
|
+
}
|
|
68154
|
+
corroborationFacts() {
|
|
67294
68155
|
if (!this.client)
|
|
67295
68156
|
return null;
|
|
67296
|
-
const
|
|
68157
|
+
const g = this.gateNow();
|
|
67297
68158
|
return {
|
|
67298
|
-
|
|
67299
|
-
|
|
67300
|
-
|
|
67301
|
-
aboveBoxQuietMs: Date.now() - this.screen.aboveBoxChangedAt
|
|
68159
|
+
gate: g ? { ready: g.ready, dialog: g.dialog, reason: g.reason } : null,
|
|
68160
|
+
working: workingAboveBox(this.screen),
|
|
68161
|
+
aboveBoxQuietMs: this.aboveBoxQuietMs()
|
|
67302
68162
|
};
|
|
67303
68163
|
}
|
|
68164
|
+
aboveBoxQuietMs() {
|
|
68165
|
+
return locateBox(this.screen) ? Date.now() - this.screen.aboveBoxChangedAt : null;
|
|
68166
|
+
}
|
|
68167
|
+
checkUnwitnessed(view) {
|
|
68168
|
+
const at = this.turnAcceptedAt;
|
|
68169
|
+
if (at === null || this.rewakeOfSettled || this.witnessed(view.current))
|
|
68170
|
+
return;
|
|
68171
|
+
const since = Date.now() - at;
|
|
68172
|
+
const missing = view.availability === "absent" || view.availability === "empty";
|
|
68173
|
+
if (view.availability === "off" || missing && since >= this.t("degradedEntryMs", DEGRADED_ENTRY_MS)) {
|
|
68174
|
+
const d = this.currentDelivery;
|
|
68175
|
+
this.turnSource = "screen";
|
|
68176
|
+
this.anomaly("degraded_mode");
|
|
68177
|
+
this.screenTurn = {
|
|
68178
|
+
echo: d && d.mode !== "refused" ? d.line : "",
|
|
68179
|
+
acceptedAt: at,
|
|
68180
|
+
errorLogSize: this.turnErrorLogSize
|
|
68181
|
+
};
|
|
68182
|
+
return;
|
|
68183
|
+
}
|
|
68184
|
+
if (view.availability === "ok" && since >= ADMIT_TIMEOUT_MS && !this.witnessMissingCounted) {
|
|
68185
|
+
this.witnessMissingCounted = true;
|
|
68186
|
+
this.anomaly("witness_missing");
|
|
68187
|
+
}
|
|
68188
|
+
}
|
|
67304
68189
|
evalRunning(view) {
|
|
68190
|
+
if (this.turnSource === "transcript")
|
|
68191
|
+
this.checkUnwitnessed(view);
|
|
67305
68192
|
if (this.turnSource === "screen") {
|
|
67306
68193
|
this.evalScreenTurn(view);
|
|
67307
68194
|
return;
|
|
@@ -67321,22 +68208,24 @@ class PaneSessionImpl {
|
|
|
67321
68208
|
if (this.detectBlocked(t))
|
|
67322
68209
|
return;
|
|
67323
68210
|
const now = Date.now();
|
|
68211
|
+
const transcriptQuietMs = now - (view.lastAppendAt ?? this.startedAtMs);
|
|
67324
68212
|
const decision = decideSettle({
|
|
67325
68213
|
turn: t,
|
|
67326
68214
|
session: view.session,
|
|
67327
|
-
transcriptQuietMs
|
|
68215
|
+
transcriptQuietMs,
|
|
67328
68216
|
chatQuietMs: now - this.lastChatSeenAt,
|
|
67329
|
-
|
|
68217
|
+
facts: this.corroborationFacts(),
|
|
67330
68218
|
paneExited: false,
|
|
67331
68219
|
secondaryQuietMs: this.secondaryQuietMs,
|
|
67332
|
-
corroborationMs: this.corroborationMs
|
|
68220
|
+
corroborationMs: this.corroborationMs,
|
|
68221
|
+
corroborationGraceMs: this.t("gateGraceMs", GATE_GRACE_MS)
|
|
67333
68222
|
});
|
|
67334
68223
|
if (decision.settled) {
|
|
67335
68224
|
this.settle(t, decision, null);
|
|
67336
68225
|
return;
|
|
67337
68226
|
}
|
|
67338
68227
|
this.activity = decision.activity;
|
|
67339
|
-
this.checkTurnEndMissing();
|
|
68228
|
+
this.checkTurnEndMissing(t, transcriptQuietMs);
|
|
67340
68229
|
this.checkAgentCountMismatch(t);
|
|
67341
68230
|
}
|
|
67342
68231
|
checkEscape() {
|
|
@@ -67347,14 +68236,14 @@ class PaneSessionImpl {
|
|
|
67347
68236
|
this.anomaly("escape_not_effective");
|
|
67348
68237
|
this.escapeSentAt = null;
|
|
67349
68238
|
}
|
|
67350
|
-
checkTurnEndMissing() {
|
|
67351
|
-
if (this.activity !== "finishing") {
|
|
68239
|
+
checkTurnEndMissing(t, transcriptQuietMs) {
|
|
68240
|
+
if (this.activity !== "finishing" || t.turnDurationAfterLast || t.interruptAfterLast) {
|
|
67352
68241
|
this.turnEndMissing = false;
|
|
67353
68242
|
return;
|
|
67354
68243
|
}
|
|
67355
68244
|
if (!this.client)
|
|
67356
68245
|
return;
|
|
67357
|
-
const quiet =
|
|
68246
|
+
const quiet = this.aboveBoxQuietMs() ?? transcriptQuietMs;
|
|
67358
68247
|
const missing = quiet >= TURN_END_MISSING_FACTOR * this.secondaryQuietMs && !stopHookRunning(this.screen);
|
|
67359
68248
|
if (missing && !this.turnEndMissing)
|
|
67360
68249
|
this.anomaly("turn_end_record_missing");
|
|
@@ -67374,14 +68263,19 @@ class PaneSessionImpl {
|
|
|
67374
68263
|
let kind = null;
|
|
67375
68264
|
if (pending.name === "AskUserQuestion")
|
|
67376
68265
|
kind = "question";
|
|
67377
|
-
else
|
|
67378
|
-
|
|
68266
|
+
else {
|
|
68267
|
+
const dialog = this.gateNow()?.dialog ?? null;
|
|
68268
|
+
if (dialog === "permission" || dialog === "plan")
|
|
68269
|
+
kind = "permission";
|
|
68270
|
+
else if (dialog === "question")
|
|
68271
|
+
kind = "question";
|
|
68272
|
+
}
|
|
67379
68273
|
if (!kind)
|
|
67380
68274
|
return false;
|
|
67381
68275
|
this.blockedToolId = pending.id;
|
|
67382
68276
|
this.fire(kind === "question" ? "blocked_question" : "blocked_permission");
|
|
67383
68277
|
this.activity = pending.name;
|
|
67384
|
-
const text = blockText3(pending,
|
|
68278
|
+
const text = blockText3(pending, this.screen.seq > 0 ? dialogText(this.screen) || null : null);
|
|
67385
68279
|
let v;
|
|
67386
68280
|
try {
|
|
67387
68281
|
v = this.o.onBlocked({ kind, tool: pending.name, text });
|
|
@@ -67394,6 +68288,16 @@ class PaneSessionImpl {
|
|
|
67394
68288
|
}
|
|
67395
68289
|
evalIdle(view) {
|
|
67396
68290
|
const t = view.current;
|
|
68291
|
+
if (t && this.abandonedIndex !== null && t.index === this.abandonedIndex && t.acceptedAt !== null && !this.exitRequested) {
|
|
68292
|
+
this.abandonedIndex = null;
|
|
68293
|
+
this.anomaly("late_witness");
|
|
68294
|
+
this.turnAcceptedAt = Date.now();
|
|
68295
|
+
this.turnErrorLogSize = this.errorLogSize();
|
|
68296
|
+
this.lastChatSeenAt = Date.now();
|
|
68297
|
+
this.fire("rewake");
|
|
68298
|
+
this.activity = "thinking";
|
|
68299
|
+
return;
|
|
68300
|
+
}
|
|
67397
68301
|
if (!t || this.settledChatOffset === null || this.exitRequested)
|
|
67398
68302
|
return;
|
|
67399
68303
|
if (t.lastChatOffset !== null && t.lastChatOffset > this.settledChatOffset) {
|
|
@@ -67472,10 +68376,10 @@ class PaneSessionImpl {
|
|
|
67472
68376
|
return !!t && t.index === this.turnIndex && t.acceptedAt !== null;
|
|
67473
68377
|
}
|
|
67474
68378
|
screenSettleReady(view, answer, apiError) {
|
|
67475
|
-
const
|
|
67476
|
-
if (!
|
|
68379
|
+
const g = this.gateNow();
|
|
68380
|
+
if (!g || !g.ready || g.dialog !== null || workingAboveBox(this.screen) === true)
|
|
67477
68381
|
return false;
|
|
67478
|
-
const quiet = Date.now() - this.screen.
|
|
68382
|
+
const quiet = this.aboveBoxQuietMs() ?? Date.now() - this.screen.changedAt;
|
|
67479
68383
|
if (view.availability === "off" && quiet >= this.secondaryQuietMs)
|
|
67480
68384
|
return true;
|
|
67481
68385
|
return (!!answer || !!apiError) && quiet >= 2 * this.t("screenSettleQuietMs", SCREEN_SETTLE_QUIET_MS);
|
|
@@ -67554,7 +68458,7 @@ class PaneSessionImpl {
|
|
|
67554
68458
|
session: view.session,
|
|
67555
68459
|
transcriptQuietMs: Number.MAX_SAFE_INTEGER,
|
|
67556
68460
|
chatQuietMs: Number.MAX_SAFE_INTEGER,
|
|
67557
|
-
|
|
68461
|
+
facts: null,
|
|
67558
68462
|
paneExited: true,
|
|
67559
68463
|
secondaryQuietMs: this.secondaryQuietMs,
|
|
67560
68464
|
corroborationMs: 0
|
|
@@ -67604,7 +68508,7 @@ ${screenTailOf(this.screen)}`
|
|
|
67604
68508
|
snapshot() {
|
|
67605
68509
|
const view = this.follower.view();
|
|
67606
68510
|
const terminal = isTerminalPhase(this.phase);
|
|
67607
|
-
const lastAct = Math.max(this.
|
|
68511
|
+
const lastAct = Math.max(this.activityChangedAt, view.lastAppendAt ?? 0);
|
|
67608
68512
|
const cur = view.current;
|
|
67609
68513
|
const hasTranscript = view.availability === "ok" && view.usage.tokensIn + view.usage.tokensOut > 0;
|
|
67610
68514
|
return {
|
|
@@ -67689,6 +68593,115 @@ ${screenTailOf(this.screen)}`
|
|
|
67689
68593
|
return { ok: false, reason: "terminal" };
|
|
67690
68594
|
return { ok: true, queued: this.queue.length };
|
|
67691
68595
|
}
|
|
68596
|
+
async resize(cols, rows) {
|
|
68597
|
+
const size = clampPaneSize(cols, rows);
|
|
68598
|
+
if (isTerminalPhase(this.phase))
|
|
68599
|
+
return this.lastSizeOutcome();
|
|
68600
|
+
if (!this.supportsResize)
|
|
68601
|
+
throw new ContractErrorException("resize_unsupported", 'this magmux has no resize op (capabilities.verbs lacks "resize"); a newer magmux is needed');
|
|
68602
|
+
if (!this.client)
|
|
68603
|
+
return this.pendingOutcome(size);
|
|
68604
|
+
if (samePaneSize(this.appliedSize, size) && samePaneSize(this.desiredSize, size) && !this.resizeDraining)
|
|
68605
|
+
return { ...size, changed: false, seq: this.screen.seq };
|
|
68606
|
+
this.desiredSize = size;
|
|
68607
|
+
return new Promise((resolve, reject) => {
|
|
68608
|
+
this.resizeWaiters.push({ resolve, reject });
|
|
68609
|
+
this.kickResize();
|
|
68610
|
+
});
|
|
68611
|
+
}
|
|
68612
|
+
pendingOutcome(size) {
|
|
68613
|
+
this.desiredSize = { ...size };
|
|
68614
|
+
return { ...size, changed: true, seq: this.screen.seq, pending: true };
|
|
68615
|
+
}
|
|
68616
|
+
lastSizeOutcome() {
|
|
68617
|
+
return { cols: this.screen.cols, rows: this.screen.rows, changed: false, seq: this.screen.seq };
|
|
68618
|
+
}
|
|
68619
|
+
inResizeQuiet(at) {
|
|
68620
|
+
return this.resizeQuietFrom > 0 && at >= this.resizeQuietFrom && at < this.resizeQuietUntil;
|
|
68621
|
+
}
|
|
68622
|
+
extendResizeQuiet() {
|
|
68623
|
+
const now = Date.now();
|
|
68624
|
+
if (now >= this.resizeQuietUntil)
|
|
68625
|
+
this.resizeQuietFrom = now;
|
|
68626
|
+
this.resizeQuietUntil = Math.max(this.resizeQuietUntil, now + RESIZE_QUIET_MS);
|
|
68627
|
+
}
|
|
68628
|
+
resizeOwed() {
|
|
68629
|
+
return !!this.client && this.supportsResize && !isTerminalPhase(this.phase) && !samePaneSize(this.appliedSize, this.desiredSize) && !samePaneSize(this.lastSentSize, this.desiredSize);
|
|
68630
|
+
}
|
|
68631
|
+
kickResize() {
|
|
68632
|
+
if (this.resizeDraining)
|
|
68633
|
+
return;
|
|
68634
|
+
this.resizeDraining = true;
|
|
68635
|
+
this.drainResize().finally(() => {
|
|
68636
|
+
this.resizeDraining = false;
|
|
68637
|
+
if (this.resizeWaiters.length > 0 || this.resizeOwed())
|
|
68638
|
+
this.kickResize();
|
|
68639
|
+
});
|
|
68640
|
+
}
|
|
68641
|
+
async drainResize() {
|
|
68642
|
+
let first = true;
|
|
68643
|
+
while (first || this.resizeWaiters.length > 0 || this.resizeOwed()) {
|
|
68644
|
+
first = false;
|
|
68645
|
+
const batch = this.resizeWaiters.splice(0);
|
|
68646
|
+
const answer = (r) => {
|
|
68647
|
+
for (const w of batch)
|
|
68648
|
+
w.resolve(r);
|
|
68649
|
+
};
|
|
68650
|
+
const fail = (e) => {
|
|
68651
|
+
for (const w of batch)
|
|
68652
|
+
w.reject(e);
|
|
68653
|
+
};
|
|
68654
|
+
if (isTerminalPhase(this.phase)) {
|
|
68655
|
+
answer(this.lastSizeOutcome());
|
|
68656
|
+
continue;
|
|
68657
|
+
}
|
|
68658
|
+
const want = { ...this.desiredSize };
|
|
68659
|
+
const c = this.client;
|
|
68660
|
+
if (!c) {
|
|
68661
|
+
answer(this.pendingOutcome(want));
|
|
68662
|
+
continue;
|
|
68663
|
+
}
|
|
68664
|
+
if (!this.supportsResize) {
|
|
68665
|
+
fail(new ContractErrorException("resize_unsupported", "this magmux has no resize op"));
|
|
68666
|
+
continue;
|
|
68667
|
+
}
|
|
68668
|
+
this.lastSentSize = want;
|
|
68669
|
+
this.extendResizeQuiet();
|
|
68670
|
+
const r = await c.request({ type: "resize", pane: 0, cols: want.cols, rows: want.rows }, RESIZE_REPLY_MS);
|
|
68671
|
+
if (isTerminalPhase(this.phase)) {
|
|
68672
|
+
answer(this.lastSizeOutcome());
|
|
68673
|
+
continue;
|
|
68674
|
+
}
|
|
68675
|
+
if (!r.ok) {
|
|
68676
|
+
if (r.code === "client_lost" || r.code === "client_timeout") {
|
|
68677
|
+
this.appliedSize = null;
|
|
68678
|
+
this.extendResizeQuiet();
|
|
68679
|
+
}
|
|
68680
|
+
if (r.code === "client_lost" || r.code === "client_closed") {
|
|
68681
|
+
answer(this.pendingOutcome(this.desiredSize));
|
|
68682
|
+
continue;
|
|
68683
|
+
}
|
|
68684
|
+
fail(new ContractErrorException("delivery_unavailable", `magmux did not resize the pane: ${r.code}${r.error ? `: ${r.error}` : ""}`));
|
|
68685
|
+
continue;
|
|
68686
|
+
}
|
|
68687
|
+
const set = {
|
|
68688
|
+
cols: typeof r.result.cols === "number" ? r.result.cols : want.cols,
|
|
68689
|
+
rows: typeof r.result.rows === "number" ? r.result.rows : want.rows
|
|
68690
|
+
};
|
|
68691
|
+
this.appliedSize = set;
|
|
68692
|
+
if (r.result.changed !== true) {
|
|
68693
|
+
answer({ ...set, changed: false, seq: this.screen.seq });
|
|
68694
|
+
continue;
|
|
68695
|
+
}
|
|
68696
|
+
this.extendResizeQuiet();
|
|
68697
|
+
await this.waitFor(() => isTerminalPhase(this.phase) || this.screen.cols === set.cols && this.screen.rows === set.rows, RESIZE_SCREEN_MS);
|
|
68698
|
+
if (isTerminalPhase(this.phase)) {
|
|
68699
|
+
answer(this.lastSizeOutcome());
|
|
68700
|
+
continue;
|
|
68701
|
+
}
|
|
68702
|
+
answer({ ...set, changed: true, seq: this.screen.seq });
|
|
68703
|
+
}
|
|
68704
|
+
}
|
|
67692
68705
|
turnAnswer(index) {
|
|
67693
68706
|
const done = this.answers.get(index);
|
|
67694
68707
|
if (done !== undefined)
|
|
@@ -67704,6 +68717,7 @@ ${screenTailOf(this.screen)}`
|
|
|
67704
68717
|
diagnostics() {
|
|
67705
68718
|
const cur = this.follower.view().current;
|
|
67706
68719
|
const rec = this.registryRec;
|
|
68720
|
+
const g = this.gate;
|
|
67707
68721
|
return {
|
|
67708
68722
|
magmuxStderr: this.stderrHead,
|
|
67709
68723
|
registry: rec ? { status: rec.status, waitingFor: rec.waitingFor, version: rec.version } : null,
|
|
@@ -67713,7 +68727,9 @@ ${screenTailOf(this.screen)}`
|
|
|
67713
68727
|
linesReturned: cur.readCoverage.linesReturned,
|
|
67714
68728
|
complete: cur.readCoverage.complete,
|
|
67715
68729
|
reads: cur.readCoverage.reads
|
|
67716
|
-
} : null
|
|
68730
|
+
} : null,
|
|
68731
|
+
gate: g && this.client ? { ready: g.ready, reason: g.reason, detail: g.detail, ageMs: Date.now() - g.receivedAt } : null,
|
|
68732
|
+
lastSend: this.lastSend ? { ...this.lastSend } : null
|
|
67717
68733
|
};
|
|
67718
68734
|
}
|
|
67719
68735
|
cancel() {
|
|
@@ -67770,6 +68786,9 @@ ${screenTailOf(this.screen)}`
|
|
|
67770
68786
|
if (this.ticker)
|
|
67771
68787
|
clearInterval(this.ticker);
|
|
67772
68788
|
this.ticker = null;
|
|
68789
|
+
if (this.gateTimer)
|
|
68790
|
+
clearInterval(this.gateTimer);
|
|
68791
|
+
this.gateTimer = null;
|
|
67773
68792
|
await this.captureGroupBeforeReap();
|
|
67774
68793
|
const c = this.client;
|
|
67775
68794
|
if (c && !c.isClosed && !this.paneClosed) {
|
|
@@ -67881,6 +68900,94 @@ function signalQuietly(target, sig) {
|
|
|
67881
68900
|
process.kill(target, sig);
|
|
67882
68901
|
} catch {}
|
|
67883
68902
|
}
|
|
68903
|
+
function launchSize(o) {
|
|
68904
|
+
return o.initialSize ? clampPaneSize(o.initialSize.cols, o.initialSize.rows) : { cols: DEFAULT_PANE_COLS, rows: DEFAULT_PANE_ROWS };
|
|
68905
|
+
}
|
|
68906
|
+
function newAdmission(a) {
|
|
68907
|
+
const now = Date.now();
|
|
68908
|
+
return {
|
|
68909
|
+
index: a.index,
|
|
68910
|
+
text: a.text,
|
|
68911
|
+
plan: a.plan,
|
|
68912
|
+
line: a.plan.line,
|
|
68913
|
+
initial: a.initial,
|
|
68914
|
+
startedAt: now,
|
|
68915
|
+
deadline: now + a.bound,
|
|
68916
|
+
step: a.plan.mode === "command" ? "type" : "submit",
|
|
68917
|
+
inFlight: false,
|
|
68918
|
+
attempts: 0,
|
|
68919
|
+
submittedUnproven: null,
|
|
68920
|
+
stuckRetried: false,
|
|
68921
|
+
panel: null,
|
|
68922
|
+
stopped: false,
|
|
68923
|
+
clearFirst: false,
|
|
68924
|
+
clearAfter: 0,
|
|
68925
|
+
lostType: null,
|
|
68926
|
+
last: null,
|
|
68927
|
+
noted: new Set
|
|
68928
|
+
};
|
|
68929
|
+
}
|
|
68930
|
+
function markClearFirst(adm) {
|
|
68931
|
+
adm.clearFirst = true;
|
|
68932
|
+
adm.clearAfter = Date.now();
|
|
68933
|
+
}
|
|
68934
|
+
function sendShape(step, line) {
|
|
68935
|
+
switch (step) {
|
|
68936
|
+
case "submit":
|
|
68937
|
+
return {
|
|
68938
|
+
msg: { type: "send", pane: 0, text: line, typed: true, enter: true },
|
|
68939
|
+
budget: { text: line, keys: 1, submit: true }
|
|
68940
|
+
};
|
|
68941
|
+
case "type":
|
|
68942
|
+
return {
|
|
68943
|
+
msg: { type: "send", pane: 0, text: line, typed: true, enter: false },
|
|
68944
|
+
budget: { text: line, keys: 0, submit: false }
|
|
68945
|
+
};
|
|
68946
|
+
case "enter":
|
|
68947
|
+
return {
|
|
68948
|
+
msg: { type: "send", pane: 0, keys: ["enter"], enter: false },
|
|
68949
|
+
budget: { text: "", keys: 1, submit: true }
|
|
68950
|
+
};
|
|
68951
|
+
default:
|
|
68952
|
+
return assertNever(step);
|
|
68953
|
+
}
|
|
68954
|
+
}
|
|
68955
|
+
function fixedSendMs(step, line) {
|
|
68956
|
+
const rt = SEND_READY_WAIT_DEFAULT_MS;
|
|
68957
|
+
return sendBudgetMs({ ...sendShape(step, line).budget, readyTimeoutMs: rt }) - rt;
|
|
68958
|
+
}
|
|
68959
|
+
function readyTimeoutFor(step, line, leftMs) {
|
|
68960
|
+
const reserve = step === "type" ? fixedSendMs("enter", line) + SEND_CLIENT_SLACK_MS + MIN_READY_TIMEOUT_MS : 0;
|
|
68961
|
+
const rt = Math.min(SEND_READY_WAIT_DEFAULT_MS, leftMs - fixedSendMs(step, line) - SEND_CLIENT_SLACK_MS - reserve);
|
|
68962
|
+
return rt < MIN_READY_TIMEOUT_MS ? null : Math.floor(rt);
|
|
68963
|
+
}
|
|
68964
|
+
function describeLastReply(adm, gate) {
|
|
68965
|
+
const o = adm.last;
|
|
68966
|
+
if (!o) {
|
|
68967
|
+
const g = gate ? gate.ready ? "ready" : gate.reason ?? "not ready" : "unknown";
|
|
68968
|
+
return adm.attempts === 0 ? `no gated send fitted before the deadline (gate: ${g})` : `no magmux reply (gate: ${g})`;
|
|
68969
|
+
}
|
|
68970
|
+
switch (o.kind) {
|
|
68971
|
+
case "busy":
|
|
68972
|
+
return `last magmux reply: busy ${o.reason || "unknown"}${o.typed ? " (typed, Enter withheld)" : ""}${gate?.detail ? ` (${gate.detail})` : ""}`;
|
|
68973
|
+
case "not_accepted":
|
|
68974
|
+
return `last magmux reply: not_accepted ${o.reason}`;
|
|
68975
|
+
case "accepted":
|
|
68976
|
+
return `last magmux reply: ok ${o.accept} (${o.evidence})`;
|
|
68977
|
+
case "in_box":
|
|
68978
|
+
return "last magmux reply: in_box (the command was typed, its Enter never sent)";
|
|
68979
|
+
case "bad_request":
|
|
68980
|
+
return `last magmux reply: bad_request ${o.error}`;
|
|
68981
|
+
case "reply_lost":
|
|
68982
|
+
case "unsent":
|
|
68983
|
+
case "pane_gone":
|
|
68984
|
+
return `last magmux reply: ${o.code}`;
|
|
68985
|
+
case "unexpected":
|
|
68986
|
+
return `last magmux reply: ${o.code}`;
|
|
68987
|
+
default:
|
|
68988
|
+
return assertNever(o);
|
|
68989
|
+
}
|
|
68990
|
+
}
|
|
67884
68991
|
function isControl(text) {
|
|
67885
68992
|
const t = text.trim();
|
|
67886
68993
|
return t === "/exit" || t === "/quit";
|
|
@@ -67899,13 +69006,19 @@ function preparePane(o, root, parentEnv) {
|
|
|
67899
69006
|
let dirs = null;
|
|
67900
69007
|
try {
|
|
67901
69008
|
const paneId = mintPaneId(o.kind, o.label);
|
|
67902
|
-
const sockPath =
|
|
67903
|
-
const cwd =
|
|
69009
|
+
const sockPath = sockPathOf(root, paneId);
|
|
69010
|
+
const cwd = realpathSync4(o.cwd);
|
|
67904
69011
|
const launch = o.claudishSpawn ?? resolveClaudishLaunch(parentEnv);
|
|
67905
69012
|
dirs = createLaunchDirs(root);
|
|
67906
69013
|
const argv = buildClaudishPaneArgv(o.spawnModel, o.sessionUuid, dirs.turnDir, o.callerFlags);
|
|
67907
69014
|
writeLauncherFiles(dirs.ctlDir, launcherScript(cwd, launch, argv));
|
|
67908
|
-
const { magmuxEnv } = buildPaneEnv({
|
|
69015
|
+
const { magmuxEnv } = buildPaneEnv({
|
|
69016
|
+
parentEnv,
|
|
69017
|
+
slotEnv: o.slotEnv,
|
|
69018
|
+
cwd,
|
|
69019
|
+
ctlDir: dirs.ctlDir,
|
|
69020
|
+
...launchSize(o)
|
|
69021
|
+
});
|
|
67909
69022
|
return { paneId, sockPath, cwd, ...dirs, magmuxEnv };
|
|
67910
69023
|
} catch (e) {
|
|
67911
69024
|
for (const d of dirs ? [dirs.ctlDir, dirs.turnDir] : [])
|
|
@@ -67974,21 +69087,38 @@ async function startPaneSession(o) {
|
|
|
67974
69087
|
await session.start({ magmuxBinary: magmux.binary, env: p.magmuxEnv, cwd: p.cwd });
|
|
67975
69088
|
return session;
|
|
67976
69089
|
}
|
|
67977
|
-
var BOOT_TIMEOUT_MS = 90000, ADMIT_TIMEOUT_MS = 30000,
|
|
69090
|
+
var BOOT_TIMEOUT_MS = 90000, ADMIT_TIMEOUT_MS = 30000, DEGRADED_ENTRY_MS = 1e4, SCREEN_SETTLE_QUIET_MS = 3000, PANEL_SETTLE_MS = 500, SEND_CLIENT_SLACK_MS = 2000, MIN_READY_TIMEOUT_MS = 1000, BUSY_RETRY_MS = 250, MISMATCH_SETTLE_MS = 1000, CLEAR_WAIT_MS = 1000, BOOT_STATIC_MS = 5000, TICK_MS = 250, WATCH_FPS = 4, POLL_BACKSTOP_MS = 1000, TURN_END_MISSING_FACTOR = 3, RESIZE_REPLY_MS = 1e4, RESIZE_SCREEN_MS = 1000, GATE_POLL_MS = 250, GATE_REPLY_MS = 1000, GATE_STALE_MS = 1000, GATE_GRACE_MS, GATE_DEAD_BACKSTOP_MS = 1000, GATE_KINDLESS_REASONS, RUNTIME_DIALOG_KINDS, REGISTRY_READ_MS = 250, REGISTRY_DISAGREE_MS = 2000, REGISTRY_GATE_BOOT_DISAGREE_MS = 5000, REGISTRY_MISSING_MS = 5000, MAX_ANOMALY_KEYS = 64, KEPT_ANSWERS = 4, EVENT_REASON, VERDICT_EVENT, PaneStartError;
|
|
67978
69091
|
var init_pane_session = __esm(() => {
|
|
67979
69092
|
init_parent_session();
|
|
67980
69093
|
init_process_tree();
|
|
67981
69094
|
init_redact();
|
|
69095
|
+
init_box_locate();
|
|
69096
|
+
init_contract();
|
|
69097
|
+
init_gate_binding();
|
|
69098
|
+
init_input_gate();
|
|
67982
69099
|
init_magmux_client();
|
|
67983
69100
|
init_pane_launch();
|
|
67984
69101
|
init_pane_registry();
|
|
67985
69102
|
init_process_identity();
|
|
67986
69103
|
init_prompt_delivery();
|
|
67987
69104
|
init_screen_classifier();
|
|
69105
|
+
init_screen_model();
|
|
67988
69106
|
init_session_registry();
|
|
67989
69107
|
init_settle_rule();
|
|
67990
69108
|
init_slot_state();
|
|
67991
69109
|
init_transcript_follower();
|
|
69110
|
+
GATE_GRACE_MS = SECONDARY_QUIET_MS;
|
|
69111
|
+
GATE_KINDLESS_REASONS = new Set([
|
|
69112
|
+
"starting",
|
|
69113
|
+
"terminal_not_ready",
|
|
69114
|
+
"no_input_box"
|
|
69115
|
+
]);
|
|
69116
|
+
RUNTIME_DIALOG_KINDS = new Set([
|
|
69117
|
+
"permission",
|
|
69118
|
+
"question",
|
|
69119
|
+
"plan",
|
|
69120
|
+
"select"
|
|
69121
|
+
]);
|
|
67992
69122
|
EVENT_REASON = {
|
|
67993
69123
|
boot_dialog: "first_run_dialog",
|
|
67994
69124
|
boot_blocked: "boot_blocked",
|
|
@@ -68040,10 +69170,10 @@ __export(exports_session_discovery, {
|
|
|
68040
69170
|
transcriptPathFor: () => transcriptPathFor
|
|
68041
69171
|
});
|
|
68042
69172
|
import { execFile as execFile3, execFileSync as execFileSync3 } from "child_process";
|
|
68043
|
-
import { closeSync as closeSync9, openSync as openSync9, readSync as readSync4, readdirSync as readdirSync8, realpathSync as
|
|
68044
|
-
import { basename as
|
|
69173
|
+
import { closeSync as closeSync9, openSync as openSync9, readSync as readSync4, readdirSync as readdirSync8, realpathSync as realpathSync5, statSync as statSync11 } from "fs";
|
|
69174
|
+
import { basename as basename3, join as join49 } from "path";
|
|
68045
69175
|
function projectsDir(env = process.env) {
|
|
68046
|
-
return
|
|
69176
|
+
return join49(claudeConfigDir(env), "projects");
|
|
68047
69177
|
}
|
|
68048
69178
|
function slugForPath(absPath) {
|
|
68049
69179
|
return projectDirNameFor(absPath);
|
|
@@ -68051,9 +69181,9 @@ function slugForPath(absPath) {
|
|
|
68051
69181
|
function transcriptPathFor(cwd, sessionUuid, projectsRoot = projectsDir()) {
|
|
68052
69182
|
let real = cwd;
|
|
68053
69183
|
try {
|
|
68054
|
-
real =
|
|
69184
|
+
real = realpathSync5(cwd);
|
|
68055
69185
|
} catch {}
|
|
68056
|
-
return
|
|
69186
|
+
return join49(projectsRoot, slugForPath(real), `${sessionUuid}.jsonl`);
|
|
68057
69187
|
}
|
|
68058
69188
|
function isAgentSession(row) {
|
|
68059
69189
|
return row.entrypoint !== undefined && row.entrypoint !== "cli";
|
|
@@ -68100,7 +69230,7 @@ function projectDirs() {
|
|
|
68100
69230
|
}
|
|
68101
69231
|
}
|
|
68102
69232
|
function sessionsIn(dirName) {
|
|
68103
|
-
const dir =
|
|
69233
|
+
const dir = join49(projectsDir(), dirName);
|
|
68104
69234
|
let names;
|
|
68105
69235
|
try {
|
|
68106
69236
|
names = readdirSync8(dir).filter((n) => n.endsWith(".jsonl"));
|
|
@@ -68109,13 +69239,13 @@ function sessionsIn(dirName) {
|
|
|
68109
69239
|
}
|
|
68110
69240
|
const rows = [];
|
|
68111
69241
|
for (const n of names) {
|
|
68112
|
-
const file =
|
|
69242
|
+
const file = join49(dir, n);
|
|
68113
69243
|
try {
|
|
68114
69244
|
const st = statSync11(file);
|
|
68115
69245
|
if (st.size === 0)
|
|
68116
69246
|
continue;
|
|
68117
69247
|
const row = {
|
|
68118
|
-
id:
|
|
69248
|
+
id: basename3(n, ".jsonl"),
|
|
68119
69249
|
file,
|
|
68120
69250
|
mtimeMs: st.mtimeMs,
|
|
68121
69251
|
birthtimeMs: st.birthtimeMs,
|
|
@@ -68217,7 +69347,7 @@ function discoverWorktreeGroups(repo) {
|
|
|
68217
69347
|
if (hit) {
|
|
68218
69348
|
path = hit.path;
|
|
68219
69349
|
live = true;
|
|
68220
|
-
name = hit.path === repo.root ? "(root)" :
|
|
69350
|
+
name = hit.path === repo.root ? "(root)" : basename3(hit.path);
|
|
68221
69351
|
} else if (at !== -1 && dir.startsWith(rootSlug)) {
|
|
68222
69352
|
path = null;
|
|
68223
69353
|
live = false;
|
|
@@ -68487,7 +69617,7 @@ var init_session_discovery = __esm(() => {
|
|
|
68487
69617
|
// src/team-orchestrator.ts
|
|
68488
69618
|
import { randomBytes as randomBytes8, randomUUID as randomUUID5 } from "crypto";
|
|
68489
69619
|
import { existsSync as existsSync31, mkdirSync as mkdirSync21, readFileSync as readFileSync31, readdirSync as readdirSync9, statSync as statSync12, writeFileSync as writeFileSync22 } from "fs";
|
|
68490
|
-
import { basename as
|
|
69620
|
+
import { basename as basename4, join as join50, resolve as resolve5 } from "path";
|
|
68491
69621
|
function slotTerminal(e) {
|
|
68492
69622
|
if (!e.session)
|
|
68493
69623
|
return true;
|
|
@@ -68524,13 +69654,13 @@ function addressRun(path, runId) {
|
|
|
68524
69654
|
pruneRuns();
|
|
68525
69655
|
if (runId) {
|
|
68526
69656
|
const run = teamRuns.get(runId) ?? null;
|
|
68527
|
-
if (run && path !== undefined &&
|
|
69657
|
+
if (run && path !== undefined && resolve5(path) !== run.path)
|
|
68528
69658
|
return null;
|
|
68529
69659
|
return run;
|
|
68530
69660
|
}
|
|
68531
69661
|
if (path === undefined)
|
|
68532
69662
|
return null;
|
|
68533
|
-
const id = newestRunByPath.get(
|
|
69663
|
+
const id = newestRunByPath.get(resolve5(path));
|
|
68534
69664
|
return id ? teamRuns.get(id) ?? null : null;
|
|
68535
69665
|
}
|
|
68536
69666
|
function activeRunAt(path) {
|
|
@@ -68556,7 +69686,7 @@ function notableAnomalies(snap) {
|
|
|
68556
69686
|
return snap.anomalies.filter((a) => a.startsWith("background_shell_open") || a.startsWith("turn_end_record_missing") || a.startsWith("agent_count_mismatch") || a.startsWith("prompt_not_read"));
|
|
68557
69687
|
}
|
|
68558
69688
|
function upstreamLogPath(path, id) {
|
|
68559
|
-
return
|
|
69689
|
+
return join50(path, "errors", `${id}-upstream.jsonl`);
|
|
68560
69690
|
}
|
|
68561
69691
|
function neverSpawnedRow(e, m) {
|
|
68562
69692
|
return {
|
|
@@ -68649,9 +69779,9 @@ function teamRunRowFromDisk(path, status) {
|
|
|
68649
69779
|
const settled = slots.length > 0 && slots.every((s) => isTerminalState(s.state));
|
|
68650
69780
|
const completions = Object.values(status.models ?? {}).map((m) => m?.completedAt ? Date.parse(m.completedAt) : Number.NaN).filter(Number.isFinite);
|
|
68651
69781
|
return {
|
|
68652
|
-
run_id: status.runId ??
|
|
69782
|
+
run_id: status.runId ?? basename4(path),
|
|
68653
69783
|
path,
|
|
68654
|
-
kind: status.kind ?? (
|
|
69784
|
+
kind: status.kind ?? (basename4(path) === "judging" ? "judge" : "run"),
|
|
68655
69785
|
started_at: status.startedAt,
|
|
68656
69786
|
finished_at: settled ? new Date(completions.length ? Math.max(...completions) : statusMtimeMs(path) ?? Date.parse(status.startedAt)).toISOString() : null,
|
|
68657
69787
|
state: settled ? "SETTLED" : "ACTIVE",
|
|
@@ -68661,14 +69791,14 @@ function teamRunRowFromDisk(path, status) {
|
|
|
68661
69791
|
}
|
|
68662
69792
|
function statusMtimeMs(path) {
|
|
68663
69793
|
try {
|
|
68664
|
-
return statSync12(
|
|
69794
|
+
return statSync12(join50(path, "status.json")).mtimeMs;
|
|
68665
69795
|
} catch {
|
|
68666
69796
|
return null;
|
|
68667
69797
|
}
|
|
68668
69798
|
}
|
|
68669
69799
|
function readManifestOrNull(path) {
|
|
68670
69800
|
try {
|
|
68671
|
-
return JSON.parse(readFileSync31(
|
|
69801
|
+
return JSON.parse(readFileSync31(join50(path, "manifest.json"), "utf-8"));
|
|
68672
69802
|
} catch {
|
|
68673
69803
|
return null;
|
|
68674
69804
|
}
|
|
@@ -68702,10 +69832,10 @@ async function cancelTeamRun(path, slot, runId) {
|
|
|
68702
69832
|
function neverSpawnedCapture() {
|
|
68703
69833
|
return {
|
|
68704
69834
|
seq: 0,
|
|
68705
|
-
cols:
|
|
68706
|
-
rows:
|
|
69835
|
+
cols: DEFAULT_PANE_COLS,
|
|
69836
|
+
rows: DEFAULT_PANE_ROWS,
|
|
68707
69837
|
cursor: { x: 0, y: 0 },
|
|
68708
|
-
lines: Array.from({ length:
|
|
69838
|
+
lines: Array.from({ length: DEFAULT_PANE_ROWS }, () => ""),
|
|
68709
69839
|
final: true
|
|
68710
69840
|
};
|
|
68711
69841
|
}
|
|
@@ -68722,6 +69852,18 @@ function captureTeamSlot(path, slot, sinceSeq, spans, runId) {
|
|
|
68722
69852
|
}
|
|
68723
69853
|
return e.session.capture(sinceSeq, { spans: spans === true });
|
|
68724
69854
|
}
|
|
69855
|
+
async function resizeTeamSlot(path, slot, cols, rows, runId) {
|
|
69856
|
+
const run = addressRun(path, runId);
|
|
69857
|
+
if (!run)
|
|
69858
|
+
throw unknownRun(path, runId);
|
|
69859
|
+
const e = run.slots.get(slot);
|
|
69860
|
+
if (!e)
|
|
69861
|
+
throw new ContractErrorException("unknown_slot", `run ${run.runId} has no slot ${JSON.stringify(slot)}`);
|
|
69862
|
+
const where = { run_id: run.runId, path: run.path, slot };
|
|
69863
|
+
if (!e.session)
|
|
69864
|
+
return { ...where, cols: DEFAULT_PANE_COLS, rows: DEFAULT_PANE_ROWS, changed: false, seq: 0 };
|
|
69865
|
+
return { ...where, ...await e.session.resize(cols, rows) };
|
|
69866
|
+
}
|
|
68725
69867
|
function teamLiveMaps(path, runId) {
|
|
68726
69868
|
const run = addressRun(path, runId);
|
|
68727
69869
|
if (!run)
|
|
@@ -68860,7 +70002,7 @@ function persistErrorLog(errorLogPath, header, sections) {
|
|
|
68860
70002
|
} catch {}
|
|
68861
70003
|
}
|
|
68862
70004
|
function validateSessionPath(sessionPath) {
|
|
68863
|
-
const resolved =
|
|
70005
|
+
const resolved = resolve5(sessionPath);
|
|
68864
70006
|
const cwd = process.cwd();
|
|
68865
70007
|
if (!resolved.startsWith(`${cwd}/`) && resolved !== cwd) {
|
|
68866
70008
|
throw new Error(`Session path must be within current directory: ${sessionPath}`);
|
|
@@ -68868,7 +70010,7 @@ function validateSessionPath(sessionPath) {
|
|
|
68868
70010
|
return resolved;
|
|
68869
70011
|
}
|
|
68870
70012
|
function readTeamInputFile(inputPath) {
|
|
68871
|
-
const resolved =
|
|
70013
|
+
const resolved = resolve5(inputPath);
|
|
68872
70014
|
const cwd = process.cwd();
|
|
68873
70015
|
if (!resolved.startsWith(`${cwd}/`) && resolved !== cwd) {
|
|
68874
70016
|
throw new Error(`Input file must be within current directory: ${inputPath}`);
|
|
@@ -68886,14 +70028,14 @@ function setupSession(sessionPath, models, input) {
|
|
|
68886
70028
|
if (models.length === 0) {
|
|
68887
70029
|
throw new Error("At least one model is required");
|
|
68888
70030
|
}
|
|
68889
|
-
if (existsSync31(
|
|
70031
|
+
if (existsSync31(join50(sessionPath, "manifest.json"))) {
|
|
68890
70032
|
throw new Error(`Session already exists at ${sessionPath}. Use a new directory path or delete the existing session first.`);
|
|
68891
70033
|
}
|
|
68892
|
-
mkdirSync21(
|
|
68893
|
-
mkdirSync21(
|
|
70034
|
+
mkdirSync21(join50(sessionPath, "work"), { recursive: true });
|
|
70035
|
+
mkdirSync21(join50(sessionPath, "errors"), { recursive: true });
|
|
68894
70036
|
if (input !== undefined) {
|
|
68895
|
-
writeFileSync22(
|
|
68896
|
-
} else if (!existsSync31(
|
|
70037
|
+
writeFileSync22(join50(sessionPath, "input.md"), input, "utf-8");
|
|
70038
|
+
} else if (!existsSync31(join50(sessionPath, "input.md"))) {
|
|
68897
70039
|
throw new Error(`No input.md found at ${sessionPath} and no input provided`);
|
|
68898
70040
|
}
|
|
68899
70041
|
const ids = models.map((_, i) => String(i + 1).padStart(2, "0"));
|
|
@@ -68910,9 +70052,9 @@ function setupSession(sessionPath, models, input) {
|
|
|
68910
70052
|
model: models[i],
|
|
68911
70053
|
assignedAt: now
|
|
68912
70054
|
};
|
|
68913
|
-
mkdirSync21(
|
|
70055
|
+
mkdirSync21(join50(sessionPath, "work", anonId), { recursive: true });
|
|
68914
70056
|
}
|
|
68915
|
-
writeFileSync22(
|
|
70057
|
+
writeFileSync22(join50(sessionPath, "manifest.json"), JSON.stringify(manifest, null, 2), "utf-8");
|
|
68916
70058
|
const status = {
|
|
68917
70059
|
startedAt: now,
|
|
68918
70060
|
models: Object.fromEntries(Object.keys(manifest.models).map((id) => [
|
|
@@ -68927,7 +70069,7 @@ function setupSession(sessionPath, models, input) {
|
|
|
68927
70069
|
}
|
|
68928
70070
|
]))
|
|
68929
70071
|
};
|
|
68930
|
-
writeFileSync22(
|
|
70072
|
+
writeFileSync22(join50(sessionPath, "status.json"), JSON.stringify(status, null, 2), "utf-8");
|
|
68931
70073
|
return manifest;
|
|
68932
70074
|
}
|
|
68933
70075
|
function assertValidRequirePattern(pattern) {
|
|
@@ -68955,14 +70097,14 @@ async function preflightTeamRun(opts) {
|
|
|
68955
70097
|
throw new Error(`invalid_args: ${refusal}`);
|
|
68956
70098
|
}
|
|
68957
70099
|
await assertMagmuxAvailable();
|
|
68958
|
-
assertNoActiveRun(
|
|
70100
|
+
assertNoActiveRun(resolve5(opts.path));
|
|
68959
70101
|
const root = sockRootFor(opts.parentEnv ?? process.env);
|
|
68960
70102
|
const live = livePaneCount(root);
|
|
68961
70103
|
if (live + opts.slots > MAX_LIVE_PANES)
|
|
68962
70104
|
throw new Error(`pane_limit: ${live} live panes for this user, ${opts.slots} more would exceed ${MAX_LIVE_PANES}`);
|
|
68963
70105
|
}
|
|
68964
70106
|
function mintRunId(path, startMs) {
|
|
68965
|
-
return `${
|
|
70107
|
+
return `${basename4(path)}-${startMs.toString(36)}-${randomBytes8(3).toString("hex")}`;
|
|
68966
70108
|
}
|
|
68967
70109
|
function startModels(sessionPath, opts = {}) {
|
|
68968
70110
|
const flight = { aborted: false };
|
|
@@ -68986,10 +70128,10 @@ async function startModelsIn(flight, sessionPath, opts) {
|
|
|
68986
70128
|
const flagCheck = checkChildFlags(claudeFlags);
|
|
68987
70129
|
if (!flagCheck.ok)
|
|
68988
70130
|
throw new Error(`invalid_args: ${flagCheck.message}`);
|
|
68989
|
-
const path =
|
|
68990
|
-
const manifest = JSON.parse(readFileSync31(
|
|
68991
|
-
const statusPath =
|
|
68992
|
-
const inputContent = readFileSync31(
|
|
70131
|
+
const path = resolve5(sessionPath);
|
|
70132
|
+
const manifest = JSON.parse(readFileSync31(join50(path, "manifest.json"), "utf-8"));
|
|
70133
|
+
const statusPath = join50(path, "status.json");
|
|
70134
|
+
const inputContent = readFileSync31(join50(path, "input.md"), "utf-8");
|
|
68993
70135
|
const readAvailable = !flagsRemoveRead(claudeFlags);
|
|
68994
70136
|
const refusal = deliveryRefusal(inputContent, readAvailable);
|
|
68995
70137
|
if (refusal)
|
|
@@ -69027,13 +70169,13 @@ async function startModelsIn(flight, sessionPath, opts) {
|
|
|
69027
70169
|
mkdirSync21(statsDir(path), { recursive: true });
|
|
69028
70170
|
const entries = new Map;
|
|
69029
70171
|
let run = null;
|
|
69030
|
-
const errorLogPathOf = (id) =>
|
|
70172
|
+
const errorLogPathOf = (id) => join50(path, "errors", `${id}.log`);
|
|
69031
70173
|
const upstreamLogOf = (id) => upstreamLogPath(path, id);
|
|
69032
70174
|
const commandOf = (e) => ["claudish", "-i", "--model", e.spawnModel ?? e.model, "-y", "--quiet", ...claudeFlags].join(" ");
|
|
69033
70175
|
function writeResponse(e, text) {
|
|
69034
70176
|
e.answer = text;
|
|
69035
70177
|
try {
|
|
69036
|
-
writeFileSync22(
|
|
70178
|
+
writeFileSync22(join50(path, `response-${e.id}.md`), text, "utf-8");
|
|
69037
70179
|
} catch (err) {
|
|
69038
70180
|
persistErrorLog(errorLogPathOf(e.id), `response file not written: ${String(err)}`, []);
|
|
69039
70181
|
}
|
|
@@ -69350,7 +70492,7 @@ async function startModelsIn(flight, sessionPath, opts) {
|
|
|
69350
70492
|
done.catch(() => {});
|
|
69351
70493
|
return {
|
|
69352
70494
|
runId,
|
|
69353
|
-
teamSessionId:
|
|
70495
|
+
teamSessionId: basename4(path),
|
|
69354
70496
|
sessionPath: path,
|
|
69355
70497
|
slots: Object.fromEntries(Object.entries(manifest.models).map(([anonId, entry]) => [entry.model, anonId])),
|
|
69356
70498
|
done
|
|
@@ -69361,9 +70503,9 @@ async function runModels(sessionPath, opts = {}) {
|
|
|
69361
70503
|
return handle.done;
|
|
69362
70504
|
}
|
|
69363
70505
|
async function judgeResponses(sessionPath, opts = {}) {
|
|
69364
|
-
const active = activeRunAt(
|
|
70506
|
+
const active = activeRunAt(resolve5(sessionPath));
|
|
69365
70507
|
if (active)
|
|
69366
|
-
throw new Error(`invalid_args: the team run at ${
|
|
70508
|
+
throw new Error(`invalid_args: the team run at ${resolve5(sessionPath)} is still ACTIVE (run_id ${active.runId}); judge it once it has settled`);
|
|
69367
70509
|
const responseFiles = readdirSync9(sessionPath).filter((f) => f.startsWith("response-") && f.endsWith(".md")).sort();
|
|
69368
70510
|
if (responseFiles.length < 2) {
|
|
69369
70511
|
throw new Error(`Need at least 2 responses to judge, found ${responseFiles.length}`);
|
|
@@ -69371,13 +70513,13 @@ async function judgeResponses(sessionPath, opts = {}) {
|
|
|
69371
70513
|
const responses = {};
|
|
69372
70514
|
for (const file of responseFiles) {
|
|
69373
70515
|
const id = file.replace(/^response-/, "").replace(/\.md$/, "");
|
|
69374
|
-
responses[id] = readFileSync31(
|
|
70516
|
+
responses[id] = readFileSync31(join50(sessionPath, file), "utf-8");
|
|
69375
70517
|
}
|
|
69376
|
-
const input = readFileSync31(
|
|
70518
|
+
const input = readFileSync31(join50(sessionPath, "input.md"), "utf-8");
|
|
69377
70519
|
const judgePrompt = buildJudgePrompt(input, responses);
|
|
69378
|
-
writeFileSync22(
|
|
70520
|
+
writeFileSync22(join50(sessionPath, "judge-prompt.md"), judgePrompt, "utf-8");
|
|
69379
70521
|
const judgeModels = opts.judges ?? getDefaultJudgeModels(sessionPath);
|
|
69380
|
-
const judgePath =
|
|
70522
|
+
const judgePath = join50(sessionPath, "judging");
|
|
69381
70523
|
mkdirSync21(judgePath, { recursive: true });
|
|
69382
70524
|
setupSession(judgePath, judgeModels, judgePrompt);
|
|
69383
70525
|
await runModels(judgePath, {
|
|
@@ -69388,11 +70530,11 @@ async function judgeResponses(sessionPath, opts = {}) {
|
|
|
69388
70530
|
});
|
|
69389
70531
|
const votes = parseJudgeVotes(judgePath, Object.keys(responses));
|
|
69390
70532
|
const verdict = aggregateVerdict(votes, Object.keys(responses));
|
|
69391
|
-
writeFileSync22(
|
|
70533
|
+
writeFileSync22(join50(sessionPath, "verdict.md"), formatVerdict(verdict, sessionPath), "utf-8");
|
|
69392
70534
|
return verdict;
|
|
69393
70535
|
}
|
|
69394
70536
|
function getStatus(sessionPath) {
|
|
69395
|
-
return JSON.parse(readFileSync31(
|
|
70537
|
+
return JSON.parse(readFileSync31(join50(sessionPath, "status.json"), "utf-8"));
|
|
69396
70538
|
}
|
|
69397
70539
|
function readTeamStatus(sessionPath) {
|
|
69398
70540
|
try {
|
|
@@ -69428,7 +70570,7 @@ function fisherYatesShuffle(arr) {
|
|
|
69428
70570
|
return arr;
|
|
69429
70571
|
}
|
|
69430
70572
|
function getDefaultJudgeModels(sessionPath) {
|
|
69431
|
-
const manifest = JSON.parse(readFileSync31(
|
|
70573
|
+
const manifest = JSON.parse(readFileSync31(join50(sessionPath, "manifest.json"), "utf-8"));
|
|
69432
70574
|
return Object.values(manifest.models).map((e) => e.model);
|
|
69433
70575
|
}
|
|
69434
70576
|
function buildJudgePrompt(input, responses) {
|
|
@@ -69491,7 +70633,7 @@ function parseJudgeVotes(judgePath, responseIds) {
|
|
|
69491
70633
|
const judgeId = file.replace(/^response-/, "").replace(/\.md$/, "");
|
|
69492
70634
|
let content;
|
|
69493
70635
|
try {
|
|
69494
|
-
content = readFileSync31(
|
|
70636
|
+
content = readFileSync31(join50(judgePath, file), "utf-8");
|
|
69495
70637
|
} catch {
|
|
69496
70638
|
continue;
|
|
69497
70639
|
}
|
|
@@ -69543,7 +70685,7 @@ function aggregateVerdict(votes, responseIds) {
|
|
|
69543
70685
|
function formatVerdict(verdict, sessionPath) {
|
|
69544
70686
|
let manifest = null;
|
|
69545
70687
|
try {
|
|
69546
|
-
manifest = JSON.parse(readFileSync31(
|
|
70688
|
+
manifest = JSON.parse(readFileSync31(join50(sessionPath, "manifest.json"), "utf-8"));
|
|
69547
70689
|
} catch {}
|
|
69548
70690
|
let output = `# Team Verdict
|
|
69549
70691
|
|
|
@@ -69605,7 +70747,7 @@ import {
|
|
|
69605
70747
|
statSync as statSync13,
|
|
69606
70748
|
writeFileSync as writeFileSync23
|
|
69607
70749
|
} from "fs";
|
|
69608
|
-
import { join as
|
|
70750
|
+
import { join as join51, resolve as resolve6, sep } from "path";
|
|
69609
70751
|
function normaliseTimeoutSeconds(raw) {
|
|
69610
70752
|
const n = typeof raw === "string" && raw.trim() !== "" ? Number(raw) : raw;
|
|
69611
70753
|
if (typeof n !== "number" || !Number.isFinite(n))
|
|
@@ -69771,7 +70913,7 @@ function dropLeadingFragment(tail) {
|
|
|
69771
70913
|
return firstBreak === -1 ? tail.text : tail.text.slice(firstBreak + 1);
|
|
69772
70914
|
}
|
|
69773
70915
|
function diskAccounting(sessionDir) {
|
|
69774
|
-
const stats = readTokenStatsAt(
|
|
70916
|
+
const stats = readTokenStatsAt(join51(sessionDir, "tokens.json"));
|
|
69775
70917
|
return {
|
|
69776
70918
|
tokensIn: stats?.billed_input_tokens ?? null,
|
|
69777
70919
|
tokensOut: stats?.output_tokens ?? null,
|
|
@@ -69794,10 +70936,10 @@ function diskProseBytes(tail, fileBytes) {
|
|
|
69794
70936
|
function blankFinalCapture() {
|
|
69795
70937
|
return {
|
|
69796
70938
|
seq: 0,
|
|
69797
|
-
cols:
|
|
69798
|
-
rows:
|
|
70939
|
+
cols: DEFAULT_PANE_COLS,
|
|
70940
|
+
rows: DEFAULT_PANE_ROWS,
|
|
69799
70941
|
cursor: { x: 0, y: 0 },
|
|
69800
|
-
lines: Array.from({ length:
|
|
70942
|
+
lines: Array.from({ length: DEFAULT_PANE_ROWS }, () => ""),
|
|
69801
70943
|
final: true
|
|
69802
70944
|
};
|
|
69803
70945
|
}
|
|
@@ -69842,7 +70984,7 @@ class SessionManager {
|
|
|
69842
70984
|
let dir = "";
|
|
69843
70985
|
for (let attempt = 0;; attempt++) {
|
|
69844
70986
|
id = `team-${randomUUID6().replace(/-/g, "").slice(0, 8)}`;
|
|
69845
|
-
dir =
|
|
70987
|
+
dir = join51(this.sessionsDir, id);
|
|
69846
70988
|
try {
|
|
69847
70989
|
mkdirSync22(dir);
|
|
69848
70990
|
break;
|
|
@@ -69857,7 +70999,7 @@ class SessionManager {
|
|
|
69857
70999
|
sessionId: id,
|
|
69858
71000
|
parentClaudeSessionId: opts.parentClaudeSessionId,
|
|
69859
71001
|
startedAt,
|
|
69860
|
-
teamPath:
|
|
71002
|
+
teamPath: resolve6(opts.teamPath),
|
|
69861
71003
|
slots: opts.slots
|
|
69862
71004
|
});
|
|
69863
71005
|
this.teamRunStarts.set(id, startedAt);
|
|
@@ -69874,9 +71016,9 @@ class SessionManager {
|
|
|
69874
71016
|
if (dir === null)
|
|
69875
71017
|
throw new Error("not a record id");
|
|
69876
71018
|
const completedAt = new Date().toISOString();
|
|
69877
|
-
const startedAt = this.teamRunStarts.get(record) ?? metaString(readJsonObject(
|
|
71019
|
+
const startedAt = this.teamRunStarts.get(record) ?? metaString(readJsonObject(join51(dir, "spawn.json"), META_READ_LIMIT)?.startedAt) ?? completedAt;
|
|
69878
71020
|
const elapsedMs = Date.parse(completedAt) - Date.parse(startedAt);
|
|
69879
|
-
writeJsonAtomic(
|
|
71021
|
+
writeJsonAtomic(join51(dir, "meta.json"), {
|
|
69880
71022
|
kind: "team",
|
|
69881
71023
|
status: outcome.status,
|
|
69882
71024
|
startedAt,
|
|
@@ -69908,7 +71050,7 @@ class SessionManager {
|
|
|
69908
71050
|
startedAt,
|
|
69909
71051
|
...rest
|
|
69910
71052
|
};
|
|
69911
|
-
writeJsonAtomic(
|
|
71053
|
+
writeJsonAtomic(join51(dir, "spawn.json"), body);
|
|
69912
71054
|
}
|
|
69913
71055
|
async createSession(opts) {
|
|
69914
71056
|
if (this.activeSessions + this.starting >= this.maxSessions) {
|
|
@@ -69967,10 +71109,10 @@ class SessionManager {
|
|
|
69967
71109
|
const claudeSessionId = randomUUID6();
|
|
69968
71110
|
const timeout = normaliseTimeoutSeconds(opts.timeoutSeconds);
|
|
69969
71111
|
const startedAt = new Date().toISOString();
|
|
69970
|
-
const sessionDir = opts.sessionDir ??
|
|
71112
|
+
const sessionDir = opts.sessionDir ?? join51(this.sessionsDir, sessionId);
|
|
69971
71113
|
mkdirSync22(sessionDir, { recursive: true });
|
|
69972
71114
|
if (opts.prompt)
|
|
69973
|
-
writeFileSync23(
|
|
71115
|
+
writeFileSync23(join51(sessionDir, "prompt.md"), opts.prompt, "utf-8");
|
|
69974
71116
|
this.writeSpawnRecord(sessionDir, {
|
|
69975
71117
|
kind: "session",
|
|
69976
71118
|
sessionId,
|
|
@@ -69983,7 +71125,7 @@ class SessionManager {
|
|
|
69983
71125
|
const cwd = opts.cwd ?? process.cwd();
|
|
69984
71126
|
const parentEnv = opts.parentEnv ?? this.parentEnv;
|
|
69985
71127
|
const spawnModel = opts.spawnModel ?? null;
|
|
69986
|
-
const tokenFile = opts.tokenFile ??
|
|
71128
|
+
const tokenFile = opts.tokenFile ?? join51(sessionDir, "tokens.json");
|
|
69987
71129
|
return {
|
|
69988
71130
|
info: {
|
|
69989
71131
|
sessionId,
|
|
@@ -70019,28 +71161,30 @@ class SessionManager {
|
|
|
70019
71161
|
},
|
|
70020
71162
|
session: null,
|
|
70021
71163
|
scrollback: new ScrollbackBuffer(this.scrollbackCapacity),
|
|
70022
|
-
outputLogStream: createWriteStream(
|
|
71164
|
+
outputLogStream: createWriteStream(join51(sessionDir, "output.log")),
|
|
70023
71165
|
sessionDir,
|
|
70024
71166
|
cwd,
|
|
70025
71167
|
tokenFile,
|
|
70026
|
-
eventLogPath:
|
|
71168
|
+
eventLogPath: join51(sessionDir, "events.jsonl"),
|
|
70027
71169
|
eventLogBytes: 0,
|
|
70028
|
-
upstreamErrorLogPath:
|
|
71170
|
+
upstreamErrorLogPath: join51(sessionDir, "upstream-errors.jsonl"),
|
|
70029
71171
|
eventRing: [],
|
|
70030
71172
|
proseBytes: 0,
|
|
70031
71173
|
answeredTurns: new Map,
|
|
70032
|
-
waitLogPath:
|
|
71174
|
+
waitLogPath: join51(sessionDir, "waits.jsonl"),
|
|
70033
71175
|
waitLogBytes: 0,
|
|
70034
71176
|
waitSince: null,
|
|
70035
71177
|
ended: false,
|
|
70036
71178
|
evictHandle: null,
|
|
70037
71179
|
lastLoggedTool: null,
|
|
70038
71180
|
assistantIdsLogged: 0,
|
|
70039
|
-
anomaliesLogged: new Set
|
|
71181
|
+
anomaliesLogged: new Set,
|
|
71182
|
+
requestedSize: null
|
|
70040
71183
|
};
|
|
70041
71184
|
}
|
|
70042
71185
|
async startPane(entry, opts, p) {
|
|
70043
71186
|
const info = entry.info;
|
|
71187
|
+
const launch = entry.requestedSize;
|
|
70044
71188
|
const paneOpts = {
|
|
70045
71189
|
kind: "s",
|
|
70046
71190
|
label: info.sessionId,
|
|
@@ -70055,6 +71199,7 @@ class SessionManager {
|
|
|
70055
71199
|
},
|
|
70056
71200
|
shape: info.shape,
|
|
70057
71201
|
...opts.prompt ? { initialPrompt: opts.prompt } : {},
|
|
71202
|
+
...launch ? { initialSize: launch } : {},
|
|
70058
71203
|
readAvailable: p.readAvailable,
|
|
70059
71204
|
decide: (turn) => this.decide(entry, turn),
|
|
70060
71205
|
onBlocked: (b) => this.onBlocked(entry, b),
|
|
@@ -70070,6 +71215,12 @@ class SessionManager {
|
|
|
70070
71215
|
this.failNeverSpawned(entry, err);
|
|
70071
71216
|
throw err;
|
|
70072
71217
|
}
|
|
71218
|
+
const asked = entry.requestedSize;
|
|
71219
|
+
entry.requestedSize = null;
|
|
71220
|
+
if (asked && (asked.cols !== launch?.cols || asked.rows !== launch?.rows))
|
|
71221
|
+
entry.session.resize(asked.cols, asked.rows).catch(() => {
|
|
71222
|
+
return;
|
|
71223
|
+
});
|
|
70073
71224
|
if (!entry.ended)
|
|
70074
71225
|
this.applySnapshot(entry, entry.session.snapshot());
|
|
70075
71226
|
}
|
|
@@ -70163,7 +71314,7 @@ class SessionManager {
|
|
|
70163
71314
|
try {
|
|
70164
71315
|
const text = screenLines.join(`
|
|
70165
71316
|
`).replace(/\s+$/, "");
|
|
70166
|
-
writeFileSync23(
|
|
71317
|
+
writeFileSync23(join51(entry.sessionDir, "screen.txt"), `${redactSecrets2(text)}
|
|
70167
71318
|
`, "utf-8");
|
|
70168
71319
|
} catch {}
|
|
70169
71320
|
}
|
|
@@ -70177,7 +71328,7 @@ class SessionManager {
|
|
|
70177
71328
|
entry.waitSince = null;
|
|
70178
71329
|
}
|
|
70179
71330
|
try {
|
|
70180
|
-
writeJsonAtomic(
|
|
71331
|
+
writeJsonAtomic(join51(entry.sessionDir, "meta.json"), toMetaRecord(entry.info, entry.cwd));
|
|
70181
71332
|
} catch (err) {
|
|
70182
71333
|
process.stderr.write(`[claudish] session ${entry.info.sessionId}: could not write meta.json: ` + `${err instanceof Error ? err.message : String(err)}
|
|
70183
71334
|
`);
|
|
@@ -70321,6 +71472,8 @@ class SessionManager {
|
|
|
70321
71472
|
registry: null,
|
|
70322
71473
|
preambleBytes: 0,
|
|
70323
71474
|
readCoverage: null,
|
|
71475
|
+
gate: null,
|
|
71476
|
+
lastSend: null,
|
|
70324
71477
|
claudeCodeVersion: null,
|
|
70325
71478
|
anomalies: entry.info.detail ? [entry.info.detail] : []
|
|
70326
71479
|
};
|
|
@@ -70335,6 +71488,8 @@ class SessionManager {
|
|
|
70335
71488
|
registry: pane.registry,
|
|
70336
71489
|
preambleBytes: pane.preambleBytes,
|
|
70337
71490
|
readCoverage: pane.readCoverage,
|
|
71491
|
+
gate: pane.gate,
|
|
71492
|
+
lastSend: pane.lastSend,
|
|
70338
71493
|
claudeCodeVersion: snap.claudeCodeVersion,
|
|
70339
71494
|
anomalies: snap.anomalies
|
|
70340
71495
|
};
|
|
@@ -70348,6 +71503,26 @@ class SessionManager {
|
|
|
70348
71503
|
const r = entry.session.cancel();
|
|
70349
71504
|
return { session_id: sessionId, state: r.state, changed: r.changed };
|
|
70350
71505
|
}
|
|
71506
|
+
async resizeSession(sessionId, cols, rows) {
|
|
71507
|
+
const entry = this.liveEntry(sessionId);
|
|
71508
|
+
if (!entry)
|
|
71509
|
+
throw unknownSession(sessionId);
|
|
71510
|
+
if (!entry.session) {
|
|
71511
|
+
if (isTerminalState(entry.info.state))
|
|
71512
|
+
return {
|
|
71513
|
+
session_id: sessionId,
|
|
71514
|
+
cols: DEFAULT_PANE_COLS,
|
|
71515
|
+
rows: DEFAULT_PANE_ROWS,
|
|
71516
|
+
changed: false,
|
|
71517
|
+
seq: 0
|
|
71518
|
+
};
|
|
71519
|
+
const size = clampPaneSize(cols, rows);
|
|
71520
|
+
entry.requestedSize = size;
|
|
71521
|
+
return { session_id: sessionId, ...size, changed: true, seq: 0, pending: true };
|
|
71522
|
+
}
|
|
71523
|
+
const r = await entry.session.resize(cols, rows);
|
|
71524
|
+
return { session_id: sessionId, ...r };
|
|
71525
|
+
}
|
|
70351
71526
|
captureSession(sessionId, sinceSeq, spans) {
|
|
70352
71527
|
const entry = this.liveEntry(sessionId);
|
|
70353
71528
|
if (!entry)
|
|
@@ -70411,9 +71586,9 @@ class SessionManager {
|
|
|
70411
71586
|
diskSessionDir(sessionId) {
|
|
70412
71587
|
if (!SESSION_ID_RE.test(sessionId))
|
|
70413
71588
|
return null;
|
|
70414
|
-
const root =
|
|
70415
|
-
const dir =
|
|
70416
|
-
if (dir !==
|
|
71589
|
+
const root = resolve6(this.sessionsDir);
|
|
71590
|
+
const dir = resolve6(root, sessionId);
|
|
71591
|
+
if (dir !== join51(root, sessionId))
|
|
70417
71592
|
return null;
|
|
70418
71593
|
if (!dir.startsWith(root + sep))
|
|
70419
71594
|
return null;
|
|
@@ -70432,10 +71607,10 @@ class SessionManager {
|
|
|
70432
71607
|
} catch {
|
|
70433
71608
|
return null;
|
|
70434
71609
|
}
|
|
70435
|
-
const spawnRecord = readJsonObject(
|
|
71610
|
+
const spawnRecord = readJsonObject(join51(sessionDir, "spawn.json"), META_READ_LIMIT);
|
|
70436
71611
|
if (spawnRecord?.kind === "team")
|
|
70437
71612
|
return null;
|
|
70438
|
-
const meta = readJsonObject(
|
|
71613
|
+
const meta = readJsonObject(join51(sessionDir, "meta.json"), META_READ_LIMIT);
|
|
70439
71614
|
if (meta?.kind === "team")
|
|
70440
71615
|
return null;
|
|
70441
71616
|
const partial = meta === null;
|
|
@@ -70457,7 +71632,7 @@ class SessionManager {
|
|
|
70457
71632
|
return stored;
|
|
70458
71633
|
}
|
|
70459
71634
|
diskOutput(record, tailLines) {
|
|
70460
|
-
const tail = readTailText(
|
|
71635
|
+
const tail = readTailText(join51(record.sessionDir, "output.log"), OUTPUT_TAIL_BYTES);
|
|
70461
71636
|
const buffer = new ScrollbackBuffer(this.scrollbackCapacity);
|
|
70462
71637
|
if (tail?.text)
|
|
70463
71638
|
buffer.append(dropLeadingFragment(tail));
|
|
@@ -70477,12 +71652,12 @@ class SessionManager {
|
|
|
70477
71652
|
}
|
|
70478
71653
|
diskDiagnostics(record, limit) {
|
|
70479
71654
|
const { sessionDir, info } = record;
|
|
70480
|
-
const eventLogPath =
|
|
70481
|
-
const upstreamErrorLogPath =
|
|
70482
|
-
const outputLogPath =
|
|
71655
|
+
const eventLogPath = join51(sessionDir, "events.jsonl");
|
|
71656
|
+
const upstreamErrorLogPath = join51(sessionDir, "upstream-errors.jsonl");
|
|
71657
|
+
const outputLogPath = join51(sessionDir, "output.log");
|
|
70483
71658
|
const events = readTailLines2(eventLogPath, EVENT_TAIL_BYTES);
|
|
70484
71659
|
const outputTail = readTailText(outputLogPath, OUTPUT_TAIL_BYTES);
|
|
70485
|
-
const screen = readTailText(
|
|
71660
|
+
const screen = readTailText(join51(sessionDir, "screen.txt"), SCREEN_READ_BYTES);
|
|
70486
71661
|
return {
|
|
70487
71662
|
sessionId: info.sessionId,
|
|
70488
71663
|
state: info.state,
|
|
@@ -70515,6 +71690,8 @@ class SessionManager {
|
|
|
70515
71690
|
turnSource: info.turnSource,
|
|
70516
71691
|
preambleBytes: 0,
|
|
70517
71692
|
readCoverage: null,
|
|
71693
|
+
gate: null,
|
|
71694
|
+
lastSend: null,
|
|
70518
71695
|
claudeCodeVersion: null,
|
|
70519
71696
|
anomalies: record.partial ? [
|
|
70520
71697
|
`no readable meta.json in ${sessionDir} \u2014 this record was reconstructed from ` + "the remaining artifacts, so state, exit code and timings are unknown. The " + "session's process died before it could write a verdict."
|
|
@@ -70867,7 +72044,7 @@ var init_progress_heartbeat = __esm(() => {
|
|
|
70867
72044
|
import { spawn as spawn2 } from "child_process";
|
|
70868
72045
|
import { mkdirSync as mkdirSync23, mkdtempSync as mkdtempSync3, rmSync as rmSync7, writeFileSync as writeFileSync24 } from "fs";
|
|
70869
72046
|
import { tmpdir as tmpdir2 } from "os";
|
|
70870
|
-
import { join as
|
|
72047
|
+
import { join as join52 } from "path";
|
|
70871
72048
|
function claudeCodePrintArgv(model, systemPromptFile) {
|
|
70872
72049
|
const head = [PRINT_FLAGS[0], "--model", model, ...PRINT_FLAGS.slice(1)];
|
|
70873
72050
|
return systemPromptFile !== undefined ? [...head, "--system-prompt-file", systemPromptFile] : [...head, "--system-prompt", ""];
|
|
@@ -70985,13 +72162,13 @@ async function runPromptViaClaudeCode(model, prompt, systemPrompt, opts = {}) {
|
|
|
70985
72162
|
} catch (e) {
|
|
70986
72163
|
throw new Error(`cannot start claudish (${parentEnv.CLAUDISH_BIN?.trim() || "claudish"}): ${e instanceof Error ? e.message : String(e)}`);
|
|
70987
72164
|
}
|
|
70988
|
-
const root = mkdtempSync3(
|
|
72165
|
+
const root = mkdtempSync3(join52(tmpdir2(), "claudish-run-prompt-"));
|
|
70989
72166
|
try {
|
|
70990
|
-
const cwd =
|
|
72167
|
+
const cwd = join52(root, "cwd");
|
|
70991
72168
|
mkdirSync23(cwd, { mode: 448 });
|
|
70992
72169
|
let systemPromptFile;
|
|
70993
72170
|
if (typeof systemPrompt === "string" && systemPrompt.length > 0) {
|
|
70994
|
-
systemPromptFile =
|
|
72171
|
+
systemPromptFile = join52(root, "system-prompt.txt");
|
|
70995
72172
|
writeFileSync24(systemPromptFile, systemPrompt, { mode: 384 });
|
|
70996
72173
|
}
|
|
70997
72174
|
const argv = claudeCodePrintArgv(model, systemPromptFile);
|
|
@@ -71099,7 +72276,7 @@ var init_run_prompt_claude_code = __esm(() => {
|
|
|
71099
72276
|
// src/mcp-server.ts
|
|
71100
72277
|
import { existsSync as existsSync33, mkdirSync as mkdirSync24, readFileSync as readFileSync33, readdirSync as readdirSync10, writeFileSync as writeFileSync25 } from "fs";
|
|
71101
72278
|
import { homedir as homedir35 } from "os";
|
|
71102
|
-
import { dirname as
|
|
72279
|
+
import { dirname as dirname15, join as join53, resolve as resolve7 } from "path";
|
|
71103
72280
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
71104
72281
|
async function loadAllModels(forceRefresh = false) {
|
|
71105
72282
|
if (!forceRefresh && existsSync33(OPENROUTER_MODELS_CACHE_PATH)) {
|
|
@@ -71394,6 +72571,12 @@ function optionalInteger(raw, name) {
|
|
|
71394
72571
|
throw new ContractErrorException("invalid_args", `'${name}' must be an integer`);
|
|
71395
72572
|
return raw;
|
|
71396
72573
|
}
|
|
72574
|
+
function requiredInteger(raw, name, mode) {
|
|
72575
|
+
const n = optionalInteger(raw, name);
|
|
72576
|
+
if (n === undefined)
|
|
72577
|
+
throw new ContractErrorException("invalid_args", `'${name}' is required${mode ? ` for mode '${mode}'` : ""}`);
|
|
72578
|
+
return n;
|
|
72579
|
+
}
|
|
71397
72580
|
function teamStatusAnswer(path, runId) {
|
|
71398
72581
|
let row = null;
|
|
71399
72582
|
if (runId) {
|
|
@@ -71433,6 +72616,8 @@ async function teamContractVerb(mode, args) {
|
|
|
71433
72616
|
const slot = optionalString(args.slot, "slot");
|
|
71434
72617
|
const since = optionalInteger(args.since_seq, "since_seq");
|
|
71435
72618
|
const spans = optionalBoolean(args.spans, "spans");
|
|
72619
|
+
const cols = mode === "resize" ? requiredInteger(args.cols, "cols", mode) : undefined;
|
|
72620
|
+
const rows = mode === "resize" ? requiredInteger(args.rows, "rows", mode) : undefined;
|
|
71436
72621
|
switch (mode) {
|
|
71437
72622
|
case "status":
|
|
71438
72623
|
return contractAnswer(teamStatusAnswer(path, runId));
|
|
@@ -71443,6 +72628,11 @@ async function teamContractVerb(mode, args) {
|
|
|
71443
72628
|
throw new ContractErrorException("invalid_args", "'slot' is required for mode 'capture'");
|
|
71444
72629
|
return contractAnswer(captureTeamSlot(path, slot, since, spans, runId));
|
|
71445
72630
|
}
|
|
72631
|
+
case "resize": {
|
|
72632
|
+
if (slot === undefined)
|
|
72633
|
+
throw new ContractErrorException("invalid_args", "'slot' is required for mode 'resize'");
|
|
72634
|
+
return contractAnswer(await resizeTeamSlot(path, slot, cols, rows, runId));
|
|
72635
|
+
}
|
|
71446
72636
|
}
|
|
71447
72637
|
} catch (e) {
|
|
71448
72638
|
return contractErrorAnswer(e);
|
|
@@ -71816,18 +73006,18 @@ Use with: run_prompt(model="${suggested}", prompt="your prompt")`;
|
|
|
71816
73006
|
});
|
|
71817
73007
|
tools.push({
|
|
71818
73008
|
name: "team",
|
|
71819
|
-
description: "Run AI models on a task with anonymized outputs and optional blind judging. Every " + "slot is an interactive Claude Code session in its own headless magmux pane. " + "Modes: 'run' (START the models and return once each has taken its prompt \u2014 it does " + "NOT wait for answers), 'status' (per-slot state; read `run.slots`), 'list' (every " + "run this server holds), 'capture' (one slot's screen), '
|
|
73009
|
+
description: "Run AI models on a task with anonymized outputs and optional blind judging. Every " + "slot is an interactive Claude Code session in its own headless magmux pane. " + "Modes: 'run' (START the models and return once each has taken its prompt \u2014 it does " + "NOT wait for answers), 'status' (per-slot state; read `run.slots`), 'list' (every " + "run this server holds), 'capture' (one slot's screen), 'resize' (set one slot's " + "terminal size), 'cancel' (stop one slot or the whole run), 'judge'(blind-vote on existing outputs), 'run-and-judge' (the " + "blocking pipeline). Poll 'status' (read run.slots) or 'list'. " + "NO SLOT IS EVER KILLED ON A TIMER once its prompt is accepted. A team slot is a full " + "Claude Code session and may work for a long time; a slot inside a build or test " + "suite emits nothing for minutes and is working, not stuck. Judge the silence " + "against the task you set, and use 'cancel' if you decide a slot is wedged. A slot " + "that stops on a question it cannot answer is FAILED 'blocked' (team has no way to " + "answer it). JUDGING A WORKING SLOT: read live_output_bytes_by_slot, " + "idle_seconds_by_slot and activity_by_slot (or each row's idle_seconds and " + "activity). Do NOT use 'outputSize' \u2014 it is the size of the final answer, written " + "only when a slot finishes, so it is 0 for every working slot no matter how much " + "that slot has produced.",
|
|
71820
73010
|
inputSchema: {
|
|
71821
73011
|
type: "object",
|
|
71822
73012
|
properties: {
|
|
71823
73013
|
mode: {
|
|
71824
73014
|
type: "string",
|
|
71825
|
-
enum: ["run", "judge", "run-and-judge", "status", "cancel", "list", "capture"],
|
|
71826
|
-
description: "Operation mode. 'run' STARTS the models and returns once every slot has taken " + "its prompt (or failed to) \u2014 it does not wait for answers. Poll 'status' (read " + "`run.slots`) or 'list' for progress, then 'judge' once the slots have " + "finished. 'capture' returns one slot's screen. 'run-and-judge' is the blocking
|
|
73015
|
+
enum: ["run", "judge", "run-and-judge", "status", "cancel", "list", "capture", "resize"],
|
|
73016
|
+
description: "Operation mode. 'run' STARTS the models and returns once every slot has taken " + "its prompt (or failed to) \u2014 it does not wait for answers. Poll 'status' (read " + "`run.slots`) or 'list' for progress, then 'judge' once the slots have " + "finished. 'capture' returns one slot's screen; 'resize' sets its terminal size. " + "'run-and-judge' is the blocking pipeline and holds the call open for the whole run. 'cancel' stops one slot or " + "the whole run."
|
|
71827
73017
|
},
|
|
71828
73018
|
slot: {
|
|
71829
73019
|
type: "string",
|
|
71830
|
-
description: "For 'cancel' and '
|
|
73020
|
+
description: "For 'cancel', 'capture' and 'resize': the anonymised slot id (e.g. '02') from the " + "slot map 'run' returned. 'capture' and 'resize' require it; for 'cancel', omit it " + "to stop every slot in the run."
|
|
71831
73021
|
},
|
|
71832
73022
|
path: {
|
|
71833
73023
|
type: "string",
|
|
@@ -71835,7 +73025,7 @@ Use with: run_prompt(model="${suggested}", prompt="your prompt")`;
|
|
|
71835
73025
|
},
|
|
71836
73026
|
run_id: {
|
|
71837
73027
|
type: "string",
|
|
71838
|
-
description: "For 'status', 'cancel' and '
|
|
73028
|
+
description: "For 'status', 'cancel', 'capture' and 'resize': the run_id a 'run' answer " + "returned. It " + "addresses THAT run while this server retains it, even after a newer run reused " + "the path. Omit it to address the newest run at 'path'."
|
|
71839
73029
|
},
|
|
71840
73030
|
since_seq: {
|
|
71841
73031
|
type: "number",
|
|
@@ -71845,6 +73035,14 @@ Use with: run_prompt(model="${suggested}", prompt="your prompt")`;
|
|
|
71845
73035
|
type: "boolean",
|
|
71846
73036
|
description: "For 'capture': also return the colour/attribute spans of each line."
|
|
71847
73037
|
},
|
|
73038
|
+
cols: {
|
|
73039
|
+
type: "integer",
|
|
73040
|
+
description: "For 'resize' (required): the terminal width in columns, clamped to 80\u20139999. The " + "answer {run_id, path, slot, cols, rows, changed, seq} reports the size set."
|
|
73041
|
+
},
|
|
73042
|
+
rows: {
|
|
73043
|
+
type: "integer",
|
|
73044
|
+
description: "For 'resize' (required): the terminal height in rows, clamped to 24\u20139999 and to " + "at most 4 000 000 cells (cols \xD7 rows)."
|
|
73045
|
+
},
|
|
71848
73046
|
models: {
|
|
71849
73047
|
type: "array",
|
|
71850
73048
|
items: { type: "string" },
|
|
@@ -71886,7 +73084,7 @@ Use with: run_prompt(model="${suggested}", prompt="your prompt")`;
|
|
|
71886
73084
|
heartbeat: true,
|
|
71887
73085
|
handler: async (args, ctx) => {
|
|
71888
73086
|
const mode = args.mode;
|
|
71889
|
-
if (mode === "list" || mode === "status" || mode === "cancel" || mode === "capture") {
|
|
73087
|
+
if (mode === "list" || mode === "status" || mode === "cancel" || mode === "capture" || mode === "resize") {
|
|
71890
73088
|
return teamContractVerb(mode, args);
|
|
71891
73089
|
}
|
|
71892
73090
|
try {
|
|
@@ -71918,7 +73116,7 @@ Use with: run_prompt(model="${suggested}", prompt="your prompt")`;
|
|
|
71918
73116
|
const promptText = () => {
|
|
71919
73117
|
if (input !== undefined)
|
|
71920
73118
|
return input;
|
|
71921
|
-
const existing =
|
|
73119
|
+
const existing = join53(resolved, "input.md");
|
|
71922
73120
|
return existsSync33(existing) ? readFileSync33(existing, "utf-8") : undefined;
|
|
71923
73121
|
};
|
|
71924
73122
|
switch (mode) {
|
|
@@ -72077,16 +73275,16 @@ Use with: run_prompt(model="${suggested}", prompt="your prompt")`;
|
|
|
72077
73275
|
const sp = session_path;
|
|
72078
73276
|
for (const file of ["status.json", "manifest.json", "input.md"]) {
|
|
72079
73277
|
try {
|
|
72080
|
-
sessionData[file] = readFileSync33(
|
|
73278
|
+
sessionData[file] = readFileSync33(join53(sp, file), "utf-8");
|
|
72081
73279
|
} catch {}
|
|
72082
73280
|
}
|
|
72083
73281
|
try {
|
|
72084
|
-
const errorDir =
|
|
73282
|
+
const errorDir = join53(sp, "errors");
|
|
72085
73283
|
if (existsSync33(errorDir)) {
|
|
72086
73284
|
for (const f of readdirSync10(errorDir)) {
|
|
72087
73285
|
if (f.endsWith(".log")) {
|
|
72088
73286
|
try {
|
|
72089
|
-
sessionData[`errors/${f}`] = readFileSync33(
|
|
73287
|
+
sessionData[`errors/${f}`] = readFileSync33(join53(errorDir, f), "utf-8");
|
|
72090
73288
|
} catch {}
|
|
72091
73289
|
}
|
|
72092
73290
|
}
|
|
@@ -72096,7 +73294,7 @@ Use with: run_prompt(model="${suggested}", prompt="your prompt")`;
|
|
|
72096
73294
|
for (const f of readdirSync10(sp)) {
|
|
72097
73295
|
if (f.startsWith("response-") && f.endsWith(".md")) {
|
|
72098
73296
|
try {
|
|
72099
|
-
const content = readFileSync33(
|
|
73297
|
+
const content = readFileSync33(join53(sp, f), "utf-8");
|
|
72100
73298
|
sessionData[f] = content.slice(0, 200) + (content.length > 200 ? "... (truncated)" : "");
|
|
72101
73299
|
} catch {}
|
|
72102
73300
|
}
|
|
@@ -72105,7 +73303,7 @@ Use with: run_prompt(model="${suggested}", prompt="your prompt")`;
|
|
|
72105
73303
|
}
|
|
72106
73304
|
let version = "unknown";
|
|
72107
73305
|
try {
|
|
72108
|
-
const pkgPath =
|
|
73306
|
+
const pkgPath = join53(__dirname3, "../package.json");
|
|
72109
73307
|
if (existsSync33(pkgPath)) {
|
|
72110
73308
|
version = JSON.parse(readFileSync33(pkgPath, "utf-8")).version;
|
|
72111
73309
|
}
|
|
@@ -72185,7 +73383,7 @@ Report manually at https://github.com/anthropics/claudish/issues${autoSendHint}`
|
|
|
72185
73383
|
});
|
|
72186
73384
|
tools.push({
|
|
72187
73385
|
name: "create_session",
|
|
72188
|
-
description: "Create a new claudish proxy session for an external model: an interactive Claude Code running " + "it in its own headless magmux pane. Returns at once with state STARTING; nothing is " + "pushed while it runs: poll list_sessions (about once every 10 s) for its state, then " + "call get_output once it is COMPLETED. With a prompt it is one-shot (it ends when that turn " +
|
|
73386
|
+
description: "Create a new claudish proxy session for an external model: an interactive Claude Code running " + "it in its own headless magmux pane. Returns at once with state STARTING; nothing is " + "pushed while it runs: poll list_sessions (about once every 10 s) for its state, then " + "call get_output once it is COMPLETED. With a prompt it is one-shot (it ends when that turn " + `settles); without one it is interactive and waits for send_input. Needs magmux >= ${MIN_MAGMUX_VERSION} ` + "(darwin and linux).",
|
|
72189
73387
|
inputSchema: {
|
|
72190
73388
|
type: "object",
|
|
72191
73389
|
properties: {
|
|
@@ -72229,7 +73427,7 @@ Report manually at https://github.com/anthropics/claudish/issues${autoSendHint}`
|
|
|
72229
73427
|
const requestedModel = args.model;
|
|
72230
73428
|
const workDir = args.work_dir;
|
|
72231
73429
|
const plan = await prehydrateCredentialsForSpawn([requestedModel], {
|
|
72232
|
-
pin: workDir === undefined ||
|
|
73430
|
+
pin: workDir === undefined || resolve7(workDir) === process.cwd()
|
|
72233
73431
|
});
|
|
72234
73432
|
const parentClaudeSessionId = await parentSessionForCall({
|
|
72235
73433
|
hostPid: sessionManager.hostPid
|
|
@@ -72411,7 +73609,7 @@ Report manually at https://github.com/anthropics/claudish/issues${autoSendHint}`
|
|
|
72411
73609
|
});
|
|
72412
73610
|
tools.push({
|
|
72413
73611
|
name: "capture_session",
|
|
72414
|
-
description: "Read a session's current terminal screen
|
|
73612
|
+
description: "Read a session's current terminal screen: {seq, cols, rows, cursor, lines, final, " + "spans?}. A memory read, meant for polling about once per second. Pass the last `seq` as " + "since_seq to get {unchanged:true, seq, final} while nothing changed. `final:true` is the " + "last screen of a closed pane. Errors are a JSON ContractError.",
|
|
72415
73613
|
inputSchema: {
|
|
72416
73614
|
type: "object",
|
|
72417
73615
|
properties: {
|
|
@@ -72441,6 +73639,35 @@ Report manually at https://github.com/anthropics/claudish/issues${autoSendHint}`
|
|
|
72441
73639
|
}
|
|
72442
73640
|
}
|
|
72443
73641
|
});
|
|
73642
|
+
tools.push({
|
|
73643
|
+
name: "resize_session",
|
|
73644
|
+
description: "Set a session's terminal size: the child gets a real SIGWINCH and Claude Code reflows. " + "Allowed at any time, mid-turn included; the last call wins. The size is clamped to " + "cols 80\u20139999, rows 24\u20139999 and at most 4 000 000 cells (magmux's limits); the answer " + "{session_id, cols, rows, changed, seq, pending?} reports the size set. `seq` is the screen's seq after the resize: the next capture_session " + "shows the new cols/rows. `changed:false` = already that size. `pending:true` = the pane " + "is starting or its socket is reconnecting; the size is applied then. A finished session " + "answers its last size with changed:false. Errors are a JSON ContractError " + "(`resize_unsupported` when the installed magmux has no resize op).",
|
|
73645
|
+
inputSchema: {
|
|
73646
|
+
type: "object",
|
|
73647
|
+
properties: {
|
|
73648
|
+
session_id: { type: "string", description: "Session ID from create_session" },
|
|
73649
|
+
cols: { type: "integer", description: "Terminal width in columns (clamped to 80\u20139999)" },
|
|
73650
|
+
rows: {
|
|
73651
|
+
type: "integer",
|
|
73652
|
+
description: "Terminal height in rows (clamped to 24\u20139999 and 4 000 000 cells)"
|
|
73653
|
+
}
|
|
73654
|
+
},
|
|
73655
|
+
required: ["session_id", "cols", "rows"]
|
|
73656
|
+
},
|
|
73657
|
+
group: "session",
|
|
73658
|
+
handler: async (args) => {
|
|
73659
|
+
try {
|
|
73660
|
+
const sessionId = optionalString(args.session_id, "session_id");
|
|
73661
|
+
if (sessionId === undefined)
|
|
73662
|
+
throw new ContractErrorException("invalid_args", "'session_id' is required");
|
|
73663
|
+
const cols = requiredInteger(args.cols, "cols");
|
|
73664
|
+
const rows = requiredInteger(args.rows, "rows");
|
|
73665
|
+
return contractAnswer(await sessionManager.resizeSession(sessionId, cols, rows));
|
|
73666
|
+
} catch (e) {
|
|
73667
|
+
return contractErrorAnswer(e);
|
|
73668
|
+
}
|
|
73669
|
+
}
|
|
73670
|
+
});
|
|
72444
73671
|
return tools;
|
|
72445
73672
|
}
|
|
72446
73673
|
function resolveToolGroups(mode) {
|
|
@@ -72566,7 +73793,7 @@ Each session is an interactive Claude Code running the model in its own headless
|
|
|
72566
73793
|
3. send_input may be called at any time; it is queued until the session is idle.
|
|
72567
73794
|
4. COMPLETED: call get_output for the answer.
|
|
72568
73795
|
5. FAILED or TIMEOUT \u2014 or COMPLETED with an empty or surprising answer \u2014 call get_diagnostics. It returns the child's final screen, the upstream error bodies, the recent state records, the resolved model chain and the paths to the full records. It needs no re-run and no debug flag.
|
|
72569
|
-
6. capture_session reads a session's current screen; cancel_session stops it. Nothing stops a session for being idle: a child inside a long build is silent and working.
|
|
73796
|
+
6. capture_session reads a session's current screen; resize_session sets its terminal size (any time, mid-turn included); cancel_session stops it. Nothing stops a session for being idle: a child inside a long build is silent and working.
|
|
72570
73797
|
|
|
72571
73798
|
The session_id from create_session is the key for every session tool.`, proxyInstance = null, proxyStarting = null, SCORE_TIE_EPSILON = 0.000001, NEXT_STEP, sanitize2, TOOL_MODES;
|
|
72572
73799
|
var init_mcp_server = __esm(() => {
|
|
@@ -72599,9 +73826,9 @@ var init_mcp_server = __esm(() => {
|
|
|
72599
73826
|
import_dotenv2 = __toESM(require_main(), 1);
|
|
72600
73827
|
import_dotenv2.config({ quiet: true });
|
|
72601
73828
|
__filename3 = fileURLToPath3(import.meta.url);
|
|
72602
|
-
__dirname3 =
|
|
72603
|
-
CLAUDISH_CACHE_DIR =
|
|
72604
|
-
OPENROUTER_MODELS_CACHE_PATH =
|
|
73829
|
+
__dirname3 = dirname15(__filename3);
|
|
73830
|
+
CLAUDISH_CACHE_DIR = join53(homedir35(), ".claudish");
|
|
73831
|
+
OPENROUTER_MODELS_CACHE_PATH = join53(CLAUDISH_CACHE_DIR, "openrouter-models.json");
|
|
72605
73832
|
NEXT_STEP = {
|
|
72606
73833
|
cancelled: "you stopped this slot; nothing is wrong with it. Re-run it if you still want its vote",
|
|
72607
73834
|
timeout: "grid mode only \u2014 magmux ended the pane. The orchestrator has no deadline",
|
|
@@ -72612,7 +73839,7 @@ var init_mcp_server = __esm(() => {
|
|
|
72612
73839
|
prompt_not_accepted: "the REPL never took the prompt \u2014 read the evidence screen; retry",
|
|
72613
73840
|
prompt_not_read: "the child never read all of its task file \u2014 check that its agent or tool flags allow " + "Read and that the model can call tools; `what` says which lines were read",
|
|
72614
73841
|
child_exited: "read the evidence screen, then retry or drop the model",
|
|
72615
|
-
pane_lost:
|
|
73842
|
+
pane_lost: `magmux died \u2014 check \`magmux --version\` \u2265 ${MIN_MAGMUX_VERSION} and retry`,
|
|
72616
73843
|
blocked: "the child asked a question team cannot answer \u2014 make the prompt self-contained or use " + "create_session",
|
|
72617
73844
|
api_error: "retry once, or route via a different provider (or@<model>)",
|
|
72618
73845
|
refused: "the model refused \u2014 rephrase or drop the model",
|
|
@@ -72928,7 +74155,7 @@ var init_behavior_command = __esm(() => {
|
|
|
72928
74155
|
import { spawn as spawn3 } from "child_process";
|
|
72929
74156
|
import { existsSync as existsSync36, readFileSync as readFileSync36, writeFileSync as writeFileSync27 } from "fs";
|
|
72930
74157
|
import { connect as netConnect2 } from "net";
|
|
72931
|
-
import { join as
|
|
74158
|
+
import { join as join54 } from "path";
|
|
72932
74159
|
import { setTimeout as wait } from "timers/promises";
|
|
72933
74160
|
function paneRouteLine(explanation) {
|
|
72934
74161
|
const origin = describeRouteExplanation(explanation);
|
|
@@ -73078,9 +74305,9 @@ async function runWithGrid(sessionPath, models, input, opts) {
|
|
|
73078
74305
|
const keep = opts?.keep ?? false;
|
|
73079
74306
|
const manifest = setupSession(sessionPath, models, input);
|
|
73080
74307
|
const startedAt = new Date().toISOString();
|
|
73081
|
-
const gridfilePath =
|
|
73082
|
-
const prompt = readFileSync36(
|
|
73083
|
-
const rawPrompt = readFileSync36(
|
|
74308
|
+
const gridfilePath = join54(sessionPath, "gridfile.txt");
|
|
74309
|
+
const prompt = readFileSync36(join54(sessionPath, "input.md"), "utf-8").replace(/'/g, "'\\''").replace(/\n/g, " ");
|
|
74310
|
+
const rawPrompt = readFileSync36(join54(sessionPath, "input.md"), "utf-8");
|
|
73084
74311
|
const usedBannerColors = new Set;
|
|
73085
74312
|
const routeLines = mode === "interactive" ? new Map : await resolvePaneRouteLines(Object.values(manifest.models).map((entry) => entry.model));
|
|
73086
74313
|
const gridLines = Object.entries(manifest.models).map(([anonId]) => {
|
|
@@ -73112,7 +74339,7 @@ async function runWithGrid(sessionPath, models, input, opts) {
|
|
|
73112
74339
|
});
|
|
73113
74340
|
const [{ results }] = await Promise.all([subscription, procExit]);
|
|
73114
74341
|
const status = buildTeamStatus(manifest, startedAt, results?.panes ?? null);
|
|
73115
|
-
const statusPath =
|
|
74342
|
+
const statusPath = join54(sessionPath, "status.json");
|
|
73116
74343
|
writeFileSync27(statusPath, JSON.stringify(status, null, 2), "utf-8");
|
|
73117
74344
|
return status;
|
|
73118
74345
|
}
|
|
@@ -73133,7 +74360,7 @@ var init_team_grid = __esm(() => {
|
|
|
73133
74360
|
|
|
73134
74361
|
// src/team-cli.ts
|
|
73135
74362
|
import { readFileSync as readFileSync37 } from "fs";
|
|
73136
|
-
import { join as
|
|
74363
|
+
import { join as join55 } from "path";
|
|
73137
74364
|
async function runPaneTeam(sessionPath, models, input, opts) {
|
|
73138
74365
|
installPaneShutdownHooks({ exitAfter: true });
|
|
73139
74366
|
try {
|
|
@@ -73185,7 +74412,7 @@ Options (run / run-and-judge):
|
|
|
73185
74412
|
--timeout <secs> Grid modes only: magmux's own per-pane timeout (default: 300).
|
|
73186
74413
|
json mode has no deadline \u2014 nothing kills a working model.
|
|
73187
74414
|
json mode runs each model as an interactive pane in a headless
|
|
73188
|
-
magmux (>=
|
|
74415
|
+
magmux (>= ${MIN_MAGMUX_VERSION}; darwin and linux).
|
|
73189
74416
|
--grid Show all models in a magmux grid with live output + status bar
|
|
73190
74417
|
--mode <m> run only: json (default, panes), default (the grid, as --grid)
|
|
73191
74418
|
or interactive (as --interactive)
|
|
@@ -73278,7 +74505,7 @@ async function teamCommand(args) {
|
|
|
73278
74505
|
}
|
|
73279
74506
|
case "judge": {
|
|
73280
74507
|
await judgeResponses(sessionPath, { judges });
|
|
73281
|
-
console.log(readFileSync37(
|
|
74508
|
+
console.log(readFileSync37(join55(sessionPath, "verdict.md"), "utf-8"));
|
|
73282
74509
|
break;
|
|
73283
74510
|
}
|
|
73284
74511
|
case "run-and-judge": {
|
|
@@ -73294,7 +74521,7 @@ async function teamCommand(args) {
|
|
|
73294
74521
|
});
|
|
73295
74522
|
printStatus(status);
|
|
73296
74523
|
await judgeResponses(sessionPath, { judges });
|
|
73297
|
-
console.log(readFileSync37(
|
|
74524
|
+
console.log(readFileSync37(join55(sessionPath, "verdict.md"), "utf-8"));
|
|
73298
74525
|
break;
|
|
73299
74526
|
}
|
|
73300
74527
|
case "status": {
|
|
@@ -73883,7 +75110,7 @@ var init_keychain_command = __esm(() => {
|
|
|
73883
75110
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
73884
75111
|
import { existsSync as existsSync37, unlinkSync as unlinkSync9 } from "fs";
|
|
73885
75112
|
import { homedir as homedir36 } from "os";
|
|
73886
|
-
import { join as
|
|
75113
|
+
import { join as join56 } from "path";
|
|
73887
75114
|
async function defaultSuggestModel() {
|
|
73888
75115
|
try {
|
|
73889
75116
|
const tok = readSharedAntigravityToken();
|
|
@@ -74004,7 +75231,7 @@ No session detected yet. Starting the Antigravity CLI interactively \u2014
|
|
|
74004
75231
|
async logout(deps) {
|
|
74005
75232
|
deleteSharedAntigravityToken(deps);
|
|
74006
75233
|
try {
|
|
74007
|
-
const tokenFile =
|
|
75234
|
+
const tokenFile = join56(homedir36(), ".gemini", "antigravity-cli", "antigravity-oauth-token");
|
|
74008
75235
|
if (existsSync37(tokenFile))
|
|
74009
75236
|
unlinkSync9(tokenFile);
|
|
74010
75237
|
} catch {}
|
|
@@ -82490,7 +83717,7 @@ import {
|
|
|
82490
83717
|
writeFileSync as writeFileSync28
|
|
82491
83718
|
} from "fs";
|
|
82492
83719
|
import { homedir as homedir37, tmpdir as tmpdir3 } from "os";
|
|
82493
|
-
import { dirname as
|
|
83720
|
+
import { dirname as dirname16, join as join57 } from "path";
|
|
82494
83721
|
import { isatty } from "tty";
|
|
82495
83722
|
function releaseTerminalIsolation() {
|
|
82496
83723
|
if (!restoreTerminal)
|
|
@@ -82555,7 +83782,7 @@ function hasResolvableAnthropicAuth(deps = {}) {
|
|
|
82555
83782
|
if (isRealAnthropicEnvCredential(env, "ANTHROPIC_API_KEY") || isRealAnthropicEnvCredential(env, "ANTHROPIC_AUTH_TOKEN")) {
|
|
82556
83783
|
return true;
|
|
82557
83784
|
}
|
|
82558
|
-
if (fileExists(
|
|
83785
|
+
if (fileExists(join57(homedir37(), ".claude", ".credentials.json")))
|
|
82559
83786
|
return true;
|
|
82560
83787
|
return keychainProbe();
|
|
82561
83788
|
}
|
|
@@ -82570,7 +83797,7 @@ function isProxyAuthMode(config) {
|
|
|
82570
83797
|
}
|
|
82571
83798
|
function managedSettingsPath() {
|
|
82572
83799
|
if (isWindows2()) {
|
|
82573
|
-
return
|
|
83800
|
+
return join57(process.env.PROGRAMDATA || "C:\\ProgramData", "ClaudeCode", "managed-settings.json");
|
|
82574
83801
|
}
|
|
82575
83802
|
if (process.platform === "darwin") {
|
|
82576
83803
|
return "/Library/Application Support/ClaudeCode/managed-settings.json";
|
|
@@ -82591,9 +83818,9 @@ function isWindows2() {
|
|
|
82591
83818
|
}
|
|
82592
83819
|
function createStatusLineScript(tokenFilePath) {
|
|
82593
83820
|
const homeDir = process.env.HOME || process.env.USERPROFILE || tmpdir3();
|
|
82594
|
-
const claudishDir =
|
|
83821
|
+
const claudishDir = join57(homeDir, ".claudish");
|
|
82595
83822
|
const timestamp = Date.now();
|
|
82596
|
-
const scriptPath =
|
|
83823
|
+
const scriptPath = join57(claudishDir, `status-${timestamp}.js`);
|
|
82597
83824
|
const escapedTokenPath = tokenFilePath.replace(/\\/g, "\\\\");
|
|
82598
83825
|
const light = getThemeMode() === "light";
|
|
82599
83826
|
const cyanCode = light ? "38;2;14;116;144" : "96";
|
|
@@ -82731,7 +83958,7 @@ process.stdin.on('end', () => {
|
|
|
82731
83958
|
}
|
|
82732
83959
|
function initializeTokenFile(tokenFilePath) {
|
|
82733
83960
|
try {
|
|
82734
|
-
mkdirSync25(
|
|
83961
|
+
mkdirSync25(dirname16(tokenFilePath), { recursive: true });
|
|
82735
83962
|
writeFileSync28(tokenFilePath, JSON.stringify({
|
|
82736
83963
|
input_tokens: 0,
|
|
82737
83964
|
output_tokens: 0,
|
|
@@ -82763,7 +83990,7 @@ function cleanupStaleTokenFiles(dir, now = Date.now(), maxAgeMs = STALE_TOKEN_FI
|
|
|
82763
83990
|
if (!name.startsWith("tokens-") || !name.endsWith(".json"))
|
|
82764
83991
|
continue;
|
|
82765
83992
|
scanned++;
|
|
82766
|
-
const full =
|
|
83993
|
+
const full = join57(dir, name);
|
|
82767
83994
|
try {
|
|
82768
83995
|
if (statSync14(full).mtimeMs >= cutoff)
|
|
82769
83996
|
continue;
|
|
@@ -82792,9 +84019,9 @@ function parseSettingsArgSafe(value) {
|
|
|
82792
84019
|
}
|
|
82793
84020
|
function userSettingsFileCandidates(cwd) {
|
|
82794
84021
|
return [
|
|
82795
|
-
|
|
82796
|
-
|
|
82797
|
-
|
|
84022
|
+
join57(homedir37(), ".claude", "settings.json"),
|
|
84023
|
+
join57(cwd, ".claude", "settings.json"),
|
|
84024
|
+
join57(cwd, ".claude", "settings.local.json")
|
|
82798
84025
|
];
|
|
82799
84026
|
}
|
|
82800
84027
|
function discoverUserStatusLineCommand(claudeArgs = [], cwd = process.cwd()) {
|
|
@@ -82835,12 +84062,12 @@ function buildChainedStatusCommand(userCommand, claudishBody, claudishSegment) {
|
|
|
82835
84062
|
}
|
|
82836
84063
|
function createTempSettingsFile(_modelDisplay, port, proxyAuthMode, userStatusLineCommand) {
|
|
82837
84064
|
const homeDir = process.env.HOME || process.env.USERPROFILE || tmpdir3();
|
|
82838
|
-
const claudishDir =
|
|
84065
|
+
const claudishDir = join57(homeDir, ".claudish");
|
|
82839
84066
|
try {
|
|
82840
84067
|
mkdirSync25(claudishDir, { recursive: true });
|
|
82841
84068
|
} catch {}
|
|
82842
84069
|
const timestamp = Date.now();
|
|
82843
|
-
const tempPath =
|
|
84070
|
+
const tempPath = join57(claudishDir, `settings-${timestamp}.json`);
|
|
82844
84071
|
const assignedFile = assignedTokenFile(process.env) !== null;
|
|
82845
84072
|
const tokenFilePath = resolveTokenFilePath(port);
|
|
82846
84073
|
cleanupStaleTokenFiles(claudishDir);
|
|
@@ -83219,7 +84446,7 @@ async function runClaudeWithProxy(config, proxyUrl, onCleanup) {
|
|
|
83219
84446
|
console.error(`
|
|
83220
84447
|
Or set CLAUDE_PATH to your custom installation:`);
|
|
83221
84448
|
const home = homedir37();
|
|
83222
|
-
const localPath = isWindows2() ?
|
|
84449
|
+
const localPath = isWindows2() ? join57(home, ".claude", "local", "claude.exe") : join57(home, ".claude", "local", "claude");
|
|
83223
84450
|
console.error(` export CLAUDE_PATH=${localPath}`);
|
|
83224
84451
|
process.exit(1);
|
|
83225
84452
|
}
|
|
@@ -83332,15 +84559,15 @@ async function findClaudeBinary() {
|
|
|
83332
84559
|
}
|
|
83333
84560
|
}
|
|
83334
84561
|
const home = homedir37();
|
|
83335
|
-
const localPath = isWindows ?
|
|
84562
|
+
const localPath = isWindows ? join57(home, ".claude", "local", "claude.exe") : join57(home, ".claude", "local", "claude");
|
|
83336
84563
|
if (existsSync39(localPath)) {
|
|
83337
84564
|
return localPath;
|
|
83338
84565
|
}
|
|
83339
84566
|
if (isWindows) {
|
|
83340
84567
|
const windowsPaths = [
|
|
83341
|
-
|
|
83342
|
-
|
|
83343
|
-
|
|
84568
|
+
join57(home, "AppData", "Roaming", "npm", "claude.cmd"),
|
|
84569
|
+
join57(home, ".npm-global", "claude.cmd"),
|
|
84570
|
+
join57(home, "node_modules", ".bin", "claude.cmd")
|
|
83344
84571
|
];
|
|
83345
84572
|
for (const path of windowsPaths) {
|
|
83346
84573
|
if (existsSync39(path)) {
|
|
@@ -83351,11 +84578,11 @@ async function findClaudeBinary() {
|
|
|
83351
84578
|
const commonPaths = [
|
|
83352
84579
|
"/usr/local/bin/claude",
|
|
83353
84580
|
"/opt/homebrew/bin/claude",
|
|
83354
|
-
|
|
83355
|
-
|
|
83356
|
-
|
|
84581
|
+
join57(home, ".npm-global/bin/claude"),
|
|
84582
|
+
join57(home, ".local/bin/claude"),
|
|
84583
|
+
join57(home, "node_modules/.bin/claude"),
|
|
83357
84584
|
"/data/data/com.termux/files/usr/bin/claude",
|
|
83358
|
-
|
|
84585
|
+
join57(home, "../usr/bin/claude")
|
|
83359
84586
|
];
|
|
83360
84587
|
for (const path of commonPaths) {
|
|
83361
84588
|
if (existsSync39(path)) {
|
|
@@ -83440,16 +84667,16 @@ var init_claude_runner = __esm(() => {
|
|
|
83440
84667
|
// src/diag-output.ts
|
|
83441
84668
|
import { createWriteStream as createWriteStream2, mkdirSync as mkdirSync26, unlinkSync as unlinkSync11, writeFileSync as writeFileSync29 } from "fs";
|
|
83442
84669
|
import { homedir as homedir38 } from "os";
|
|
83443
|
-
import { join as
|
|
84670
|
+
import { join as join58 } from "path";
|
|
83444
84671
|
function getClaudishDir() {
|
|
83445
|
-
const dir =
|
|
84672
|
+
const dir = join58(homedir38(), ".claudish");
|
|
83446
84673
|
try {
|
|
83447
84674
|
mkdirSync26(dir, { recursive: true });
|
|
83448
84675
|
} catch {}
|
|
83449
84676
|
return dir;
|
|
83450
84677
|
}
|
|
83451
84678
|
function getDiagLogPath() {
|
|
83452
|
-
return
|
|
84679
|
+
return join58(getClaudishDir(), `diag-${process.pid}.log`);
|
|
83453
84680
|
}
|
|
83454
84681
|
|
|
83455
84682
|
class LogFileDiagOutput {
|
|
@@ -86064,7 +87291,7 @@ init_startup_trace();
|
|
|
86064
87291
|
init_picker_cancelled();
|
|
86065
87292
|
var import_dotenv3 = __toESM(require_main(), 1);
|
|
86066
87293
|
import { existsSync as existsSync40, readFileSync as readFileSync40 } from "fs";
|
|
86067
|
-
import { join as
|
|
87294
|
+
import { join as join59, resolve as resolve8 } from "path";
|
|
86068
87295
|
|
|
86069
87296
|
// src/tui/runtime/should-open-picker.ts
|
|
86070
87297
|
function noModelConfigured(gate) {
|
|
@@ -86176,7 +87403,7 @@ async function applyOpImport() {
|
|
|
86176
87403
|
async function applyConfigOverride() {
|
|
86177
87404
|
await Promise.resolve();
|
|
86178
87405
|
const plan = planConfigOverride(process.argv.slice(2), process.env, {
|
|
86179
|
-
resolve:
|
|
87406
|
+
resolve: resolve8,
|
|
86180
87407
|
exists: existsSync40
|
|
86181
87408
|
});
|
|
86182
87409
|
if (plan.kind === "none")
|
|
@@ -86380,7 +87607,7 @@ async function runCli() {
|
|
|
86380
87607
|
process.exit(1);
|
|
86381
87608
|
}
|
|
86382
87609
|
const mode = cliConfig.teamMode ?? "default";
|
|
86383
|
-
const sessionPath =
|
|
87610
|
+
const sessionPath = join59(process.cwd(), `.claudish-team-${Date.now()}`);
|
|
86384
87611
|
if (mode === "json") {
|
|
86385
87612
|
await Promise.resolve().then(() => init_pane());
|
|
86386
87613
|
await Promise.resolve().then(() => init_team_orchestrator());
|
|
@@ -86400,7 +87627,7 @@ async function runCli() {
|
|
|
86400
87627
|
const status = await runModels(sessionPath);
|
|
86401
87628
|
const result = { ...status, responses: {} };
|
|
86402
87629
|
for (const anonId of Object.keys(status.models)) {
|
|
86403
|
-
const responsePath =
|
|
87630
|
+
const responsePath = join59(sessionPath, `response-${anonId}.md`);
|
|
86404
87631
|
try {
|
|
86405
87632
|
const raw = readFileSync40(responsePath, "utf-8").trim();
|
|
86406
87633
|
try {
|