claudish 12.0.1 → 12.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +1647 -414
- 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.0
|
|
904
|
+
var VERSION = "12.1.0";
|
|
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";
|
|
@@ -64233,8 +64248,8 @@ function buildPaneEnv(input) {
|
|
|
64233
64248
|
continue;
|
|
64234
64249
|
env[k] = v;
|
|
64235
64250
|
}
|
|
64236
|
-
env.COLUMNS =
|
|
64237
|
-
env.LINES =
|
|
64251
|
+
env.COLUMNS = String(input.cols ?? DEFAULT_PANE_COLS);
|
|
64252
|
+
env.LINES = String(input.rows ?? DEFAULT_PANE_ROWS);
|
|
64238
64253
|
if (input.parentEnv.CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC === undefined)
|
|
64239
64254
|
env.CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC = "1";
|
|
64240
64255
|
Object.assign(env, input.slotEnv);
|
|
@@ -64360,24 +64375,46 @@ function versionAtLeast(v, min) {
|
|
|
64360
64375
|
return true;
|
|
64361
64376
|
}
|
|
64362
64377
|
async function assertMagmuxAvailable(binary) {
|
|
64363
|
-
const
|
|
64378
|
+
const key = binary ?? "";
|
|
64379
|
+
const cached = magmuxCache.get(key);
|
|
64364
64380
|
if (cached)
|
|
64365
64381
|
return cached;
|
|
64382
|
+
const inFlight = magmuxProbes.get(key);
|
|
64383
|
+
if (inFlight)
|
|
64384
|
+
return inFlight;
|
|
64385
|
+
const probe = (async () => {
|
|
64386
|
+
try {
|
|
64387
|
+
const result = await probeMagmux(binary);
|
|
64388
|
+
magmuxCache.set(key, result);
|
|
64389
|
+
return result;
|
|
64390
|
+
} finally {
|
|
64391
|
+
magmuxProbes.delete(key);
|
|
64392
|
+
}
|
|
64393
|
+
})();
|
|
64394
|
+
magmuxProbes.set(key, probe);
|
|
64395
|
+
return probe;
|
|
64396
|
+
}
|
|
64397
|
+
async function probeMagmux(binary) {
|
|
64366
64398
|
const found = binary ?? findMagmuxBinaryOrNull();
|
|
64367
64399
|
if (!found)
|
|
64368
64400
|
throw new MagmuxUnavailableError("magmux_unavailable: magmux not found (bundled package or PATH); install it: brew install MadAppGang/tap/magmux");
|
|
64401
|
+
let version = await readMagmuxVersion(found);
|
|
64402
|
+
if (!version)
|
|
64403
|
+
version = await readMagmuxVersion(found);
|
|
64404
|
+
if (!version || !versionAtLeast(version, MIN_MAGMUX_VERSION))
|
|
64405
|
+
throw new MagmuxUnavailableError(`magmux_unavailable: ${found} is version ${version || "unknown"}; panes need >= ${MIN_MAGMUX_VERSION} (the Claude Code input gate bound to a named transcript); upgrade: brew upgrade MadAppGang/tap/magmux`);
|
|
64406
|
+
return { binary: found, version };
|
|
64407
|
+
}
|
|
64408
|
+
async function readMagmuxVersion(found) {
|
|
64369
64409
|
let out = "";
|
|
64370
64410
|
try {
|
|
64371
|
-
|
|
64411
|
+
const r = await execFileAsync(found, ["--version"], { encoding: "utf8", timeout: 5000 });
|
|
64412
|
+
out = `${r.stdout}
|
|
64413
|
+
${r.stderr}`;
|
|
64372
64414
|
} catch (e) {
|
|
64373
64415
|
throw new MagmuxUnavailableError(`magmux_unavailable: ${found} --version failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
64374
64416
|
}
|
|
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;
|
|
64417
|
+
return out.match(/(\d+\.\d+\.\d+)/)?.[1] ?? "";
|
|
64381
64418
|
}
|
|
64382
64419
|
function resolveClaudishLaunch(parentEnv) {
|
|
64383
64420
|
const t = resolveClaudishSpawn(parentEnv);
|
|
@@ -64426,21 +64463,35 @@ function spawnPaneWatcher(args) {
|
|
|
64426
64463
|
proc.stdin?.unref?.();
|
|
64427
64464
|
return proc;
|
|
64428
64465
|
}
|
|
64429
|
-
function
|
|
64430
|
-
|
|
64466
|
+
function paneMagmuxArgv(input) {
|
|
64467
|
+
return [
|
|
64431
64468
|
"--headless",
|
|
64432
64469
|
"--no-status",
|
|
64470
|
+
"--controller",
|
|
64471
|
+
"claude-code",
|
|
64472
|
+
"--session-id",
|
|
64473
|
+
input.sessionUuid,
|
|
64474
|
+
"--transcript",
|
|
64475
|
+
resolve3(input.transcriptPath),
|
|
64433
64476
|
"--id",
|
|
64434
64477
|
input.paneId,
|
|
64435
64478
|
"--sock-dir",
|
|
64436
64479
|
input.sockRoot,
|
|
64437
64480
|
"-e",
|
|
64438
64481
|
paneCommand(input.ctlDir)
|
|
64439
|
-
]
|
|
64482
|
+
];
|
|
64483
|
+
}
|
|
64484
|
+
function spawnPaneMagmux(input) {
|
|
64485
|
+
const proc = spawn(input.binary, paneMagmuxArgv(input), {
|
|
64486
|
+
cwd: input.cwd,
|
|
64487
|
+
env: input.env,
|
|
64488
|
+
stdio: ["ignore", "ignore", "pipe"],
|
|
64489
|
+
detached: true
|
|
64490
|
+
});
|
|
64440
64491
|
proc.on("error", () => {});
|
|
64441
64492
|
return proc;
|
|
64442
64493
|
}
|
|
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.
|
|
64494
|
+
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.17.0", MagmuxUnavailableError, magmuxCache, magmuxProbes, execFileAsync, ClaudishNotFoundError, SHELL_SHIM = `#!/bin/sh
|
|
64444
64495
|
[ "$1" = -l ] && shift
|
|
64445
64496
|
exec /bin/sh "$@"
|
|
64446
64497
|
`, FATAL_MAGMUX_STDERR;
|
|
@@ -64614,6 +64665,7 @@ var init_pane_launch = __esm(() => {
|
|
|
64614
64665
|
code = "magmux_unavailable";
|
|
64615
64666
|
};
|
|
64616
64667
|
magmuxCache = new Map;
|
|
64668
|
+
magmuxProbes = new Map;
|
|
64617
64669
|
execFileAsync = promisify5(execFile2);
|
|
64618
64670
|
ClaudishNotFoundError = class ClaudishNotFoundError extends Error {
|
|
64619
64671
|
code = "pane_lost";
|
|
@@ -64623,6 +64675,20 @@ var init_pane_launch = __esm(() => {
|
|
|
64623
64675
|
|
|
64624
64676
|
// src/pane/magmux-client.ts
|
|
64625
64677
|
import { Socket } from "net";
|
|
64678
|
+
function failureOf(m) {
|
|
64679
|
+
const out = {
|
|
64680
|
+
ok: false,
|
|
64681
|
+
code: String(m.code ?? "error"),
|
|
64682
|
+
error: String(m.error ?? "")
|
|
64683
|
+
};
|
|
64684
|
+
if (typeof m.reason === "string" && m.reason)
|
|
64685
|
+
out.reason = m.reason;
|
|
64686
|
+
if (typeof m.typed === "boolean")
|
|
64687
|
+
out.typed = m.typed;
|
|
64688
|
+
if (typeof m.maybeSubmitted === "boolean")
|
|
64689
|
+
out.maybeSubmitted = m.maybeSubmitted;
|
|
64690
|
+
return out;
|
|
64691
|
+
}
|
|
64626
64692
|
function dialOnce(sockPath) {
|
|
64627
64693
|
return new Promise((resolve, reject) => {
|
|
64628
64694
|
const s = new Socket;
|
|
@@ -64749,7 +64815,7 @@ class MagmuxClient {
|
|
|
64749
64815
|
return;
|
|
64750
64816
|
clearTimeout(p.timer);
|
|
64751
64817
|
this.pending.delete(m.id);
|
|
64752
|
-
p.resolve(m.ok === true ? { ok: true, result: m.result ?? {} } :
|
|
64818
|
+
p.resolve(m.ok === true ? { ok: true, result: m.result ?? {} } : failureOf(m));
|
|
64753
64819
|
return;
|
|
64754
64820
|
}
|
|
64755
64821
|
if (m.type === "shutdown")
|
|
@@ -65247,6 +65313,352 @@ var init_process_tree = __esm(() => {
|
|
|
65247
65313
|
KILL_PROCESS_GROUP = process.platform !== "win32";
|
|
65248
65314
|
});
|
|
65249
65315
|
|
|
65316
|
+
// src/pane/box-locate.ts
|
|
65317
|
+
function isRuleRow(line) {
|
|
65318
|
+
if (!line || line.length < MIN_RULE_CELLS)
|
|
65319
|
+
return false;
|
|
65320
|
+
return /^\u2500+(?: [^\u2500]+ \u2500+)?$/.test(line);
|
|
65321
|
+
}
|
|
65322
|
+
function nearestRule(lines, from, step) {
|
|
65323
|
+
for (let i = 1;i <= RULE_SEARCH_ROWS; i++) {
|
|
65324
|
+
const r = from + i * step;
|
|
65325
|
+
if (r < 0 || r >= lines.length)
|
|
65326
|
+
return -1;
|
|
65327
|
+
if (isRuleRow(lines[r]))
|
|
65328
|
+
return r;
|
|
65329
|
+
}
|
|
65330
|
+
return -1;
|
|
65331
|
+
}
|
|
65332
|
+
function inspectBox(s) {
|
|
65333
|
+
const lines = s.lines;
|
|
65334
|
+
const y = s.cursor.y;
|
|
65335
|
+
if (!Number.isInteger(y) || y < 0 || y >= s.rows || y >= lines.length) {
|
|
65336
|
+
return { kind: "unknown", why: "cursor_off_screen" };
|
|
65337
|
+
}
|
|
65338
|
+
if (SELECTED_OPTION.test(lines[y] ?? ""))
|
|
65339
|
+
return { kind: "dialog", why: "selected_option" };
|
|
65340
|
+
const top = nearestRule(lines, y, -1);
|
|
65341
|
+
if (top < 0)
|
|
65342
|
+
return { kind: "unknown", why: "no_rule_above" };
|
|
65343
|
+
const bottom = nearestRule(lines, y, 1);
|
|
65344
|
+
if (bottom < 0)
|
|
65345
|
+
return { kind: "unknown", why: "no_rule_below" };
|
|
65346
|
+
const first = lines[top + 1] ?? "";
|
|
65347
|
+
if (SELECTED_OPTION.test(first))
|
|
65348
|
+
return { kind: "dialog", why: "selected_option" };
|
|
65349
|
+
if (lines.slice(bottom + 1).some((l) => SELECT_FOOTER.test(l))) {
|
|
65350
|
+
return { kind: "dialog", why: "select_footer" };
|
|
65351
|
+
}
|
|
65352
|
+
if (!PROMPT_ROW.test(first))
|
|
65353
|
+
return { kind: "unknown", why: "no_prompt_row" };
|
|
65354
|
+
return { kind: "box", box: { top, bottom, caretRow: y } };
|
|
65355
|
+
}
|
|
65356
|
+
function locateBox(s) {
|
|
65357
|
+
const at = inspectBox(s);
|
|
65358
|
+
return at.kind === "box" ? at.box : null;
|
|
65359
|
+
}
|
|
65360
|
+
function visibleText(line, spans) {
|
|
65361
|
+
if (!spans?.length)
|
|
65362
|
+
return line;
|
|
65363
|
+
const chars = Array.from(line);
|
|
65364
|
+
for (const [col, len, , , attr] of spans) {
|
|
65365
|
+
if ((attr & ATTR_FAINT) === 0)
|
|
65366
|
+
continue;
|
|
65367
|
+
for (let c = col;c < col + len && c < chars.length; c++)
|
|
65368
|
+
chars[c] = " ";
|
|
65369
|
+
}
|
|
65370
|
+
return chars.join("");
|
|
65371
|
+
}
|
|
65372
|
+
function locatedBoxText(s, box) {
|
|
65373
|
+
const parts = [];
|
|
65374
|
+
for (let i = box.top + 1;i < box.bottom; i++) {
|
|
65375
|
+
const raw = visibleText(s.lines[i] ?? "", s.spans[i]);
|
|
65376
|
+
const body = i === box.top + 1 ? raw.replace(/^[\u276F!]\s?/, "") : raw.replace(/^ {2}/, "");
|
|
65377
|
+
parts.push(body.replace(/\s+$/, ""));
|
|
65378
|
+
}
|
|
65379
|
+
return parts.join(`
|
|
65380
|
+
`).trim();
|
|
65381
|
+
}
|
|
65382
|
+
var RULE_SEARCH_ROWS = 40, MIN_RULE_CELLS = 20, PROMPT_ROW, SELECTED_OPTION, SELECT_FOOTER, ATTR_FAINT = 2;
|
|
65383
|
+
var init_box_locate = __esm(() => {
|
|
65384
|
+
PROMPT_ROW = /^(\u276F(\u00A0|$)|!)/;
|
|
65385
|
+
SELECTED_OPTION = /^ *\u276F \d+\.\s+\S/;
|
|
65386
|
+
SELECT_FOOTER = /Enter to select \u00B7 \u2191\/\u2193 to navigate/;
|
|
65387
|
+
});
|
|
65388
|
+
|
|
65389
|
+
// src/pane/input-gate.ts
|
|
65390
|
+
function dialogKindOf(reason) {
|
|
65391
|
+
if (!reason?.startsWith(DIALOG_PREFIX))
|
|
65392
|
+
return null;
|
|
65393
|
+
const kind = reason.slice(DIALOG_PREFIX.length);
|
|
65394
|
+
return DIALOG_KINDS.has(kind) ? kind : null;
|
|
65395
|
+
}
|
|
65396
|
+
function str3(v) {
|
|
65397
|
+
return typeof v === "string" && v !== "" ? v : null;
|
|
65398
|
+
}
|
|
65399
|
+
function record4(v) {
|
|
65400
|
+
return v !== null && typeof v === "object" && !Array.isArray(v) ? v : null;
|
|
65401
|
+
}
|
|
65402
|
+
function paneZero(listResult) {
|
|
65403
|
+
const panes = record4(listResult)?.panes;
|
|
65404
|
+
if (!Array.isArray(panes))
|
|
65405
|
+
return null;
|
|
65406
|
+
for (const p of panes) {
|
|
65407
|
+
const row = record4(p);
|
|
65408
|
+
if (row?.pane === 0)
|
|
65409
|
+
return row;
|
|
65410
|
+
}
|
|
65411
|
+
return null;
|
|
65412
|
+
}
|
|
65413
|
+
function parseGateInput(listResult, now) {
|
|
65414
|
+
const input = record4(paneZero(listResult)?.input);
|
|
65415
|
+
if (!input || typeof input.ready !== "boolean")
|
|
65416
|
+
return null;
|
|
65417
|
+
const reason = input.ready ? null : str3(input.reason);
|
|
65418
|
+
return {
|
|
65419
|
+
ready: input.ready,
|
|
65420
|
+
reason,
|
|
65421
|
+
dialog: dialogKindOf(reason),
|
|
65422
|
+
detail: str3(input.detail),
|
|
65423
|
+
receivedAt: now
|
|
65424
|
+
};
|
|
65425
|
+
}
|
|
65426
|
+
function gateBasisOf(listResult) {
|
|
65427
|
+
const basis = paneZero(listResult)?.gateBasis;
|
|
65428
|
+
return basis === "direct" || basis === "declared" ? basis : null;
|
|
65429
|
+
}
|
|
65430
|
+
function parseGateBinding(listResult) {
|
|
65431
|
+
const row = paneZero(listResult);
|
|
65432
|
+
if (!row)
|
|
65433
|
+
return null;
|
|
65434
|
+
const boundRaw = str3(row.bound);
|
|
65435
|
+
const sessionId = str3(row.sessionId);
|
|
65436
|
+
const transcriptPath = str3(row.transcriptPath);
|
|
65437
|
+
let bound = "unbound";
|
|
65438
|
+
if (sessionId && transcriptPath) {
|
|
65439
|
+
if (boundRaw === "named" || boundRaw === "prompt" || boundRaw === "mtime")
|
|
65440
|
+
bound = boundRaw;
|
|
65441
|
+
}
|
|
65442
|
+
return { bound, boundRaw, sessionId, transcriptPath };
|
|
65443
|
+
}
|
|
65444
|
+
function assertNever(x) {
|
|
65445
|
+
throw new Error(`unreachable: ${JSON.stringify(x)}`);
|
|
65446
|
+
}
|
|
65447
|
+
function retypeOf(result) {
|
|
65448
|
+
if (result.retyped !== true)
|
|
65449
|
+
return { retyped: false, retypeCause: null };
|
|
65450
|
+
const cause = result.retypeCause;
|
|
65451
|
+
return {
|
|
65452
|
+
retyped: true,
|
|
65453
|
+
retypeCause: cause === "terminal_reset" || cause === "never_drawn" ? cause : "unknown"
|
|
65454
|
+
};
|
|
65455
|
+
}
|
|
65456
|
+
function okOutcome(result) {
|
|
65457
|
+
const { retyped, retypeCause } = retypeOf(result);
|
|
65458
|
+
const waitedMs = typeof result.waitedMs === "number" ? result.waitedMs : 0;
|
|
65459
|
+
const verified = str3(result.verified);
|
|
65460
|
+
const accept = result.accept;
|
|
65461
|
+
if (accept === "in_box")
|
|
65462
|
+
return { kind: "in_box", retyped, retypeCause, waitedMs, verified };
|
|
65463
|
+
if (accept === undefined) {
|
|
65464
|
+
return {
|
|
65465
|
+
kind: "unexpected",
|
|
65466
|
+
code: "ungated_reply",
|
|
65467
|
+
error: "ok with no accept: the pane is not gated"
|
|
65468
|
+
};
|
|
65469
|
+
}
|
|
65470
|
+
if (accept !== "confirmed" && accept !== "resent_enter" && accept !== "submitted_by_other") {
|
|
65471
|
+
return {
|
|
65472
|
+
kind: "unexpected",
|
|
65473
|
+
code: "unknown_accept",
|
|
65474
|
+
error: `accept ${JSON.stringify(accept)}`
|
|
65475
|
+
};
|
|
65476
|
+
}
|
|
65477
|
+
const evidence = result.evidence;
|
|
65478
|
+
if (evidence !== "history" && evidence !== "transcript") {
|
|
65479
|
+
return {
|
|
65480
|
+
kind: "unexpected",
|
|
65481
|
+
code: "unknown_evidence",
|
|
65482
|
+
error: `accept ${accept} with evidence ${JSON.stringify(evidence)}`
|
|
65483
|
+
};
|
|
65484
|
+
}
|
|
65485
|
+
const dismissed = Array.isArray(result.dismissed) ? result.dismissed.filter((d) => typeof d === "string") : [];
|
|
65486
|
+
return {
|
|
65487
|
+
kind: "accepted",
|
|
65488
|
+
accept,
|
|
65489
|
+
evidence,
|
|
65490
|
+
enterByMagmux: result.enter === true,
|
|
65491
|
+
retyped,
|
|
65492
|
+
retypeCause,
|
|
65493
|
+
dismissed,
|
|
65494
|
+
waitedMs,
|
|
65495
|
+
verified
|
|
65496
|
+
};
|
|
65497
|
+
}
|
|
65498
|
+
function notAcceptedOutcome(r) {
|
|
65499
|
+
const typed = r.typed === true;
|
|
65500
|
+
switch (r.reason) {
|
|
65501
|
+
case "text_mismatch":
|
|
65502
|
+
return {
|
|
65503
|
+
kind: "not_accepted",
|
|
65504
|
+
reason: "text_mismatch",
|
|
65505
|
+
maybeSubmitted: r.maybeSubmitted === true || r.error.includes(MAYBE_SUBMITTED_MARKER),
|
|
65506
|
+
typed,
|
|
65507
|
+
detail: r.error
|
|
65508
|
+
};
|
|
65509
|
+
case "empty_box":
|
|
65510
|
+
case "still_in_box":
|
|
65511
|
+
case "unconfirmed":
|
|
65512
|
+
return {
|
|
65513
|
+
kind: "not_accepted",
|
|
65514
|
+
reason: r.reason,
|
|
65515
|
+
maybeSubmitted: false,
|
|
65516
|
+
typed,
|
|
65517
|
+
detail: r.error
|
|
65518
|
+
};
|
|
65519
|
+
default:
|
|
65520
|
+
return {
|
|
65521
|
+
kind: "unexpected",
|
|
65522
|
+
code: `not_accepted:${r.reason ?? ""}`,
|
|
65523
|
+
error: r.error
|
|
65524
|
+
};
|
|
65525
|
+
}
|
|
65526
|
+
}
|
|
65527
|
+
function classifySendReply(r) {
|
|
65528
|
+
if (r.ok)
|
|
65529
|
+
return okOutcome(record4(r.result) ?? {});
|
|
65530
|
+
switch (r.code) {
|
|
65531
|
+
case "busy": {
|
|
65532
|
+
const reason = r.reason ?? "";
|
|
65533
|
+
return { kind: "busy", reason, dialog: dialogKindOf(reason), typed: r.typed === true };
|
|
65534
|
+
}
|
|
65535
|
+
case "not_accepted":
|
|
65536
|
+
return notAcceptedOutcome(r);
|
|
65537
|
+
case "bad_request":
|
|
65538
|
+
return { kind: "bad_request", error: r.error };
|
|
65539
|
+
case "client_timeout":
|
|
65540
|
+
case "client_lost":
|
|
65541
|
+
case "timeout":
|
|
65542
|
+
return { kind: "reply_lost", code: r.code };
|
|
65543
|
+
case "client_closed":
|
|
65544
|
+
case "no_client":
|
|
65545
|
+
return { kind: "unsent", code: r.code };
|
|
65546
|
+
case "pane_dead":
|
|
65547
|
+
case "no_such_pane":
|
|
65548
|
+
return { kind: "pane_gone", code: r.code, typed: r.typed === true };
|
|
65549
|
+
default:
|
|
65550
|
+
return { kind: "unexpected", code: r.code, error: r.error };
|
|
65551
|
+
}
|
|
65552
|
+
}
|
|
65553
|
+
function readyWaitMs(readyTimeoutMs) {
|
|
65554
|
+
if (readyTimeoutMs <= 0)
|
|
65555
|
+
return SEND_READY_WAIT_DEFAULT_MS;
|
|
65556
|
+
return Math.min(readyTimeoutMs, SEND_READY_WAIT_MAX_MS);
|
|
65557
|
+
}
|
|
65558
|
+
function typedWriteCount(text) {
|
|
65559
|
+
const rs = Array.from(text);
|
|
65560
|
+
let n = 0;
|
|
65561
|
+
let run = 0;
|
|
65562
|
+
for (let i = 0;i < rs.length; i++) {
|
|
65563
|
+
const r = rs[i];
|
|
65564
|
+
if (r === "\r" || r === `
|
|
65565
|
+
`) {
|
|
65566
|
+
if (r === "\r" && rs[i + 1] === `
|
|
65567
|
+
`)
|
|
65568
|
+
i++;
|
|
65569
|
+
if (run > 0) {
|
|
65570
|
+
n++;
|
|
65571
|
+
run = 0;
|
|
65572
|
+
}
|
|
65573
|
+
n++;
|
|
65574
|
+
} else {
|
|
65575
|
+
run++;
|
|
65576
|
+
if (run === SEND_TYPED_CHUNK_RUNES) {
|
|
65577
|
+
n++;
|
|
65578
|
+
run = 0;
|
|
65579
|
+
}
|
|
65580
|
+
}
|
|
65581
|
+
}
|
|
65582
|
+
return run > 0 ? n + 1 : n;
|
|
65583
|
+
}
|
|
65584
|
+
function sendBudgetMs(s) {
|
|
65585
|
+
let attempt = 0;
|
|
65586
|
+
if (s.typed ?? true)
|
|
65587
|
+
attempt += typedWriteCount(s.text) * (SEND_TYPED_CHUNK_GAP_MS + SEND_GATE_CHECK_COST_MS);
|
|
65588
|
+
attempt += s.keys * (SEND_KEY_GAP_MS + SEND_GATE_CHECK_COST_MS);
|
|
65589
|
+
attempt += SEND_SETTLE_MS + SEND_VERIFY_MIN_MS + SEND_VERIFY_STEP_MS;
|
|
65590
|
+
const accept = s.submit ? SEND_ACCEPT_WINDOWS * SEND_ACCEPT_WINDOW_MS : 0;
|
|
65591
|
+
return readyWaitMs(s.readyTimeoutMs) + 2 * attempt + accept + SEND_BUDGET_SLACK_MS;
|
|
65592
|
+
}
|
|
65593
|
+
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;
|
|
65594
|
+
var init_input_gate = __esm(() => {
|
|
65595
|
+
DIALOG_KINDS = new Set([
|
|
65596
|
+
"permission",
|
|
65597
|
+
"question",
|
|
65598
|
+
"plan",
|
|
65599
|
+
"select",
|
|
65600
|
+
"trust",
|
|
65601
|
+
"bypass",
|
|
65602
|
+
"api_key",
|
|
65603
|
+
"onboarding"
|
|
65604
|
+
]);
|
|
65605
|
+
BOOT_DIALOG_KINDS = new Set([
|
|
65606
|
+
"trust",
|
|
65607
|
+
"bypass",
|
|
65608
|
+
"api_key",
|
|
65609
|
+
"onboarding"
|
|
65610
|
+
]);
|
|
65611
|
+
});
|
|
65612
|
+
|
|
65613
|
+
// src/pane/gate-binding.ts
|
|
65614
|
+
import { realpathSync as realpathSync2 } from "fs";
|
|
65615
|
+
import { basename as basename2, dirname as dirname14, join as join45, resolve as resolve4 } from "path";
|
|
65616
|
+
function normaliseTranscriptPath(p) {
|
|
65617
|
+
const abs = resolve4(p);
|
|
65618
|
+
const tail = [];
|
|
65619
|
+
let cur = abs;
|
|
65620
|
+
for (;; ) {
|
|
65621
|
+
try {
|
|
65622
|
+
return tail.length ? join45(realpathSync2(cur), ...tail.reverse()) : realpathSync2(cur);
|
|
65623
|
+
} catch {
|
|
65624
|
+
const parent = dirname14(cur);
|
|
65625
|
+
if (parent === cur)
|
|
65626
|
+
return abs;
|
|
65627
|
+
tail.push(basename2(cur));
|
|
65628
|
+
cur = parent;
|
|
65629
|
+
}
|
|
65630
|
+
}
|
|
65631
|
+
}
|
|
65632
|
+
function checkGateBinding(listResult, expected) {
|
|
65633
|
+
const v = expected.magmuxVersion || "?";
|
|
65634
|
+
const basis = gateBasisOf(listResult);
|
|
65635
|
+
if (basis !== "declared" || !parseGateInput(listResult, 0)) {
|
|
65636
|
+
return {
|
|
65637
|
+
ok: false,
|
|
65638
|
+
detail: `input_gate_unavailable: magmux ${v} did not gate pane 0 (gateBasis ${basis ?? "none"})`
|
|
65639
|
+
};
|
|
65640
|
+
}
|
|
65641
|
+
const b = parseGateBinding(listResult);
|
|
65642
|
+
const ours = normaliseTranscriptPath(expected.transcriptPath);
|
|
65643
|
+
const theirs = b?.transcriptPath ? normaliseTranscriptPath(b.transcriptPath) : null;
|
|
65644
|
+
const differs = [];
|
|
65645
|
+
if (b?.bound !== "named" && b?.boundRaw !== "named")
|
|
65646
|
+
differs.push(`bound ${b?.boundRaw ?? "none"}`);
|
|
65647
|
+
if (b?.sessionId !== expected.sessionUuid)
|
|
65648
|
+
differs.push(`sessionId ${b?.sessionId ?? "none"}, not ${expected.sessionUuid}`);
|
|
65649
|
+
if (theirs !== ours)
|
|
65650
|
+
differs.push(`transcriptPath ${theirs ?? "none"}, not ${ours}`);
|
|
65651
|
+
if (b?.bound === "named" && differs.length === 0)
|
|
65652
|
+
return { ok: true };
|
|
65653
|
+
return {
|
|
65654
|
+
ok: false,
|
|
65655
|
+
detail: `input_gate_unbound: magmux ${v} bound pane 0 to ${theirs ?? "none"} (${b?.boundRaw ?? "none"}), not ${ours}: ${differs.join("; ")}`
|
|
65656
|
+
};
|
|
65657
|
+
}
|
|
65658
|
+
var init_gate_binding = __esm(() => {
|
|
65659
|
+
init_input_gate();
|
|
65660
|
+
});
|
|
65661
|
+
|
|
65250
65662
|
// src/pane/screen-model.ts
|
|
65251
65663
|
function emptyScreen(cols, rows) {
|
|
65252
65664
|
return {
|
|
@@ -65264,7 +65676,7 @@ function emptyScreen(cols, rows) {
|
|
|
65264
65676
|
function isBoxRule(line, cols) {
|
|
65265
65677
|
if (!line || !/^\u2500+(?: [^\u2500]+ \u2500+)?$/.test(line))
|
|
65266
65678
|
return false;
|
|
65267
|
-
return line.length >= Math.max(20,
|
|
65679
|
+
return line.length >= Math.max(20, cols - 1);
|
|
65268
65680
|
}
|
|
65269
65681
|
function boxTopRow(lines, cols) {
|
|
65270
65682
|
for (let i = lines.length - 2;i >= 0; i--) {
|
|
@@ -65288,22 +65700,26 @@ function withSize(s, rows) {
|
|
|
65288
65700
|
spans.push([]);
|
|
65289
65701
|
return { lines, spans };
|
|
65290
65702
|
}
|
|
65291
|
-
function aboveBoxText(
|
|
65292
|
-
const
|
|
65293
|
-
return
|
|
65294
|
-
`);
|
|
65703
|
+
function aboveBoxText(s) {
|
|
65704
|
+
const box = locateBox(s);
|
|
65705
|
+
return box ? s.lines.slice(0, box.top).join(`
|
|
65706
|
+
`) : null;
|
|
65295
65707
|
}
|
|
65296
65708
|
function finish(prev, next, now) {
|
|
65297
65709
|
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
65710
|
if (!visible)
|
|
65299
65711
|
return prev;
|
|
65300
|
-
const
|
|
65301
|
-
return {
|
|
65712
|
+
const out = {
|
|
65302
65713
|
...next,
|
|
65303
65714
|
seq: prev.seq + 1,
|
|
65304
65715
|
changedAt: now,
|
|
65305
|
-
aboveBoxChangedAt:
|
|
65716
|
+
aboveBoxChangedAt: prev.aboveBoxChangedAt
|
|
65306
65717
|
};
|
|
65718
|
+
const before = prev.seq === 0 ? null : aboveBoxText(prev);
|
|
65719
|
+
const after = aboveBoxText(out);
|
|
65720
|
+
if (before === null || after === null || before !== after)
|
|
65721
|
+
out.aboveBoxChangedAt = now;
|
|
65722
|
+
return out;
|
|
65307
65723
|
}
|
|
65308
65724
|
function applyFrame(s, frame, now = Date.now()) {
|
|
65309
65725
|
const rows = frame.rows;
|
|
@@ -65328,6 +65744,9 @@ function applyFrame(s, frame, now = Date.now()) {
|
|
|
65328
65744
|
alt: frame.alt ?? s.alt
|
|
65329
65745
|
}, now);
|
|
65330
65746
|
}
|
|
65747
|
+
var init_screen_model = __esm(() => {
|
|
65748
|
+
init_box_locate();
|
|
65749
|
+
});
|
|
65331
65750
|
|
|
65332
65751
|
// src/pane/screen-classifier.ts
|
|
65333
65752
|
function screenText(s) {
|
|
@@ -65337,18 +65756,44 @@ function screenText(s) {
|
|
|
65337
65756
|
return lines.join(`
|
|
65338
65757
|
`);
|
|
65339
65758
|
}
|
|
65340
|
-
function
|
|
65759
|
+
function flatText(lines) {
|
|
65760
|
+
return lines.join(" ").replace(/\s+/g, " ").trim();
|
|
65761
|
+
}
|
|
65762
|
+
function squash(s) {
|
|
65763
|
+
return s.replace(/\s+/g, "");
|
|
65764
|
+
}
|
|
65765
|
+
function echoHeadLength(cols) {
|
|
65766
|
+
return Math.max(1, Math.min(40, cols - 4));
|
|
65767
|
+
}
|
|
65768
|
+
function echoHead(line, cols) {
|
|
65769
|
+
return line.slice(0, echoHeadLength(cols));
|
|
65770
|
+
}
|
|
65771
|
+
function visibleText2(line, spans) {
|
|
65341
65772
|
if (!spans?.length)
|
|
65342
65773
|
return line;
|
|
65343
65774
|
const chars = Array.from(line);
|
|
65344
65775
|
for (const [col, len, , , attr] of spans) {
|
|
65345
|
-
if ((attr &
|
|
65776
|
+
if ((attr & ATTR_FAINT2) === 0)
|
|
65346
65777
|
continue;
|
|
65347
65778
|
for (let c = col;c < col + len && c < chars.length; c++)
|
|
65348
65779
|
chars[c] = " ";
|
|
65349
65780
|
}
|
|
65350
65781
|
return chars.join("");
|
|
65351
65782
|
}
|
|
65783
|
+
function echoAt(lines, i, head) {
|
|
65784
|
+
const first = lines[i] ?? "";
|
|
65785
|
+
if (!first.startsWith("\u276F "))
|
|
65786
|
+
return false;
|
|
65787
|
+
const want = squash(head);
|
|
65788
|
+
let got = squash(first.slice(2));
|
|
65789
|
+
for (let j = i + 1;got.length < want.length && j < lines.length; j++) {
|
|
65790
|
+
const row = lines[j] ?? "";
|
|
65791
|
+
if (!/^ {2}\S/.test(row))
|
|
65792
|
+
break;
|
|
65793
|
+
got += squash(row);
|
|
65794
|
+
}
|
|
65795
|
+
return got.startsWith(want);
|
|
65796
|
+
}
|
|
65352
65797
|
function inputBox(s) {
|
|
65353
65798
|
const top = boxTopRow(s.lines, s.cols);
|
|
65354
65799
|
if (top < 0)
|
|
@@ -65367,7 +65812,7 @@ function boxBottomRow(s, top) {
|
|
|
65367
65812
|
function boxText(s, top, bottom) {
|
|
65368
65813
|
const parts = [];
|
|
65369
65814
|
for (let i = top + 1;i < bottom; i++) {
|
|
65370
|
-
const raw =
|
|
65815
|
+
const raw = visibleText2(s.lines[i] ?? "", s.spans[i]);
|
|
65371
65816
|
const body = i === top + 1 ? raw.replace(/^\u276F\s?/, "") : raw.replace(/^ {2}/, "");
|
|
65372
65817
|
parts.push(body.replace(/\s+$/, ""));
|
|
65373
65818
|
}
|
|
@@ -65400,7 +65845,8 @@ function choiceDialog(s) {
|
|
|
65400
65845
|
const lines = s.lines;
|
|
65401
65846
|
const start = lastBulletRow(lines) + 1;
|
|
65402
65847
|
const below = lines.slice(start);
|
|
65403
|
-
const
|
|
65848
|
+
const flat = flatText(below);
|
|
65849
|
+
const kind = CHOICE_DIALOGS.find((d) => d.header.test(flat))?.kind;
|
|
65404
65850
|
if (!kind)
|
|
65405
65851
|
return null;
|
|
65406
65852
|
if (!below.some((l) => FIRST_OPTION.test(l)))
|
|
@@ -65408,14 +65854,19 @@ function choiceDialog(s) {
|
|
|
65408
65854
|
return { kind, text: below.filter((l) => l.trim()).join(`
|
|
65409
65855
|
`) };
|
|
65410
65856
|
}
|
|
65411
|
-
function
|
|
65412
|
-
return
|
|
65857
|
+
function dialogText(s) {
|
|
65858
|
+
return s.lines.slice(lastBulletRow(s.lines) + 1).filter((l) => l.trim()).join(`
|
|
65859
|
+
`);
|
|
65413
65860
|
}
|
|
65414
65861
|
function isWorking(s) {
|
|
65415
65862
|
const top = boxTopRow(s.lines, s.cols);
|
|
65416
65863
|
const region = top >= 0 ? s.lines.slice(0, top) : s.lines;
|
|
65417
65864
|
return region.some((l) => WORKING_ROW.test(l));
|
|
65418
65865
|
}
|
|
65866
|
+
function workingAboveBox(s) {
|
|
65867
|
+
const box = locateBox(s);
|
|
65868
|
+
return box ? s.lines.slice(0, box.top).some((l) => WORKING_ROW.test(l)) : null;
|
|
65869
|
+
}
|
|
65419
65870
|
function stopHookRunning(s) {
|
|
65420
65871
|
return s.lines.some((l) => /\(running Stop hook\b/.test(l));
|
|
65421
65872
|
}
|
|
@@ -65447,7 +65898,7 @@ function screenAnswer(s, echo) {
|
|
|
65447
65898
|
const lines = s.lines;
|
|
65448
65899
|
const top = boxTopRow(lines, s.cols);
|
|
65449
65900
|
const end = top >= 0 ? top : lines.length;
|
|
65450
|
-
const start = echoRow(lines, end,
|
|
65901
|
+
const start = echoRow(lines, end, echoHead(echo, s.cols)) + 1;
|
|
65451
65902
|
if (start <= 0)
|
|
65452
65903
|
return "";
|
|
65453
65904
|
const out = [];
|
|
@@ -65462,8 +65913,9 @@ function screenAnswer(s, echo) {
|
|
|
65462
65913
|
`).trim();
|
|
65463
65914
|
}
|
|
65464
65915
|
function echoRow(lines, end, head) {
|
|
65916
|
+
const above = lines.slice(0, end);
|
|
65465
65917
|
for (let i = end - 1;i >= 0; i--)
|
|
65466
|
-
if ((
|
|
65918
|
+
if (echoAt(above, i, head))
|
|
65467
65919
|
return i;
|
|
65468
65920
|
return -1;
|
|
65469
65921
|
}
|
|
@@ -65485,9 +65937,9 @@ function agentRejectedLine(text) {
|
|
|
65485
65937
|
const m = text.match(/--agent '([^']+)' not found\.(?: Available agents:[^\n]*)?/);
|
|
65486
65938
|
return m ? m[0] : null;
|
|
65487
65939
|
}
|
|
65488
|
-
function namedDialog(
|
|
65940
|
+
function namedDialog(flat) {
|
|
65489
65941
|
for (const d of NAMED_DIALOGS)
|
|
65490
|
-
if (
|
|
65942
|
+
if (flat.includes(d.marker))
|
|
65491
65943
|
return d.name;
|
|
65492
65944
|
return null;
|
|
65493
65945
|
}
|
|
@@ -65496,22 +65948,20 @@ function isUnnamedChoice(lines) {
|
|
|
65496
65948
|
const yesNo = lines.some((l) => /^\s*(\u276F\s*)?(\d+\.\s+)?(Yes|No)\b|\(esc\)/.test(l));
|
|
65497
65949
|
if (numbered && yesNo)
|
|
65498
65950
|
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" };
|
|
65951
|
+
return lines.some((l) => /Press Enter to continue/.test(l) || SELECT_FOOTER2.test(l));
|
|
65952
|
+
}
|
|
65953
|
+
function nameBootScreen(s) {
|
|
65954
|
+
const named = namedDialog(flatText(s.lines));
|
|
65507
65955
|
if (named)
|
|
65508
|
-
return { kind: "dialog", name: named, text };
|
|
65956
|
+
return { kind: "dialog", name: named, text: screenText(s) };
|
|
65509
65957
|
if (isUnnamedChoice(s.lines))
|
|
65510
|
-
return { kind: "choice", text };
|
|
65958
|
+
return { kind: "choice", text: screenText(s) };
|
|
65511
65959
|
return { kind: "booting" };
|
|
65512
65960
|
}
|
|
65513
|
-
var NAMED_DIALOGS, CHOICE_DIALOGS, NUMBERED_OPTION, FIRST_OPTION,
|
|
65961
|
+
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
65962
|
var init_screen_classifier = __esm(() => {
|
|
65963
|
+
init_box_locate();
|
|
65964
|
+
init_screen_model();
|
|
65515
65965
|
NAMED_DIALOGS = [
|
|
65516
65966
|
{ name: "onboarding", marker: "Choose the text style" },
|
|
65517
65967
|
{ name: "trust", marker: "Is this a project you created or one you trust" },
|
|
@@ -65522,15 +65972,15 @@ var init_screen_classifier = __esm(() => {
|
|
|
65522
65972
|
{ kind: "permission", header: /\bDo you want to proceed\?/ },
|
|
65523
65973
|
{
|
|
65524
65974
|
kind: "permission",
|
|
65525
|
-
header: /\bDo you want to (create|make this edit to|overwrite|delete)
|
|
65975
|
+
header: /\bDo you want to (create|make this edit to|overwrite|delete) .{1,300}?\?/
|
|
65526
65976
|
},
|
|
65527
65977
|
{ kind: "plan", header: /\bWould you like to proceed\?/ },
|
|
65528
65978
|
{ kind: "question", header: /Enter to select \u00B7 \u2191\/\u2193 to navigate/ }
|
|
65529
65979
|
];
|
|
65530
65980
|
NUMBERED_OPTION = /^\s*(\u276F\s*)?\d+\.\s+\S/;
|
|
65531
65981
|
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+\(
|
|
65982
|
+
SELECT_FOOTER2 = /Enter to (confirm|select)\b.*Esc to cancel/;
|
|
65983
|
+
WORKING_ROW = /^\s*[\u00B7\u2722\u2733\u2736\u273B\u273D*\u25CF\u2217]\s+[A-Z][\w'-]*\u2026(\s+\((?:.*\)|[^)]*))?\s*$/;
|
|
65534
65984
|
BULLET = /^\u23FA(\s|$)/;
|
|
65535
65985
|
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
65986
|
MENU_ROW = /^\s{2}\u276F \/\S|^\s{4}\/\S|^\s{4}[*+] \S/;
|
|
@@ -65539,7 +65989,7 @@ var init_screen_classifier = __esm(() => {
|
|
|
65539
65989
|
|
|
65540
65990
|
// src/pane/session-registry.ts
|
|
65541
65991
|
import { readFileSync as readFileSync29, readdirSync as readdirSync6 } from "fs";
|
|
65542
|
-
import { join as
|
|
65992
|
+
import { join as join46 } from "path";
|
|
65543
65993
|
function parseRegistryRecord(raw) {
|
|
65544
65994
|
let parsed;
|
|
65545
65995
|
try {
|
|
@@ -65584,7 +66034,7 @@ class SessionRegistry {
|
|
|
65584
66034
|
isAlive;
|
|
65585
66035
|
constructor(o) {
|
|
65586
66036
|
this.o = o;
|
|
65587
|
-
this.dir =
|
|
66037
|
+
this.dir = join46(o.configDir, "sessions");
|
|
65588
66038
|
this.now = o.now ?? Date.now;
|
|
65589
66039
|
this.isAlive = o.isAlive ?? pidAlive;
|
|
65590
66040
|
}
|
|
@@ -65620,7 +66070,7 @@ class SessionRegistry {
|
|
|
65620
66070
|
readPid(pid) {
|
|
65621
66071
|
let raw;
|
|
65622
66072
|
try {
|
|
65623
|
-
raw = readFileSync29(
|
|
66073
|
+
raw = readFileSync29(join46(this.dir, `${pid}.json`), "utf8");
|
|
65624
66074
|
} catch {
|
|
65625
66075
|
return null;
|
|
65626
66076
|
}
|
|
@@ -65665,14 +66115,28 @@ function activityOf(t) {
|
|
|
65665
66115
|
return "finishing";
|
|
65666
66116
|
return "thinking";
|
|
65667
66117
|
}
|
|
66118
|
+
function unconfirmedBy(f) {
|
|
66119
|
+
const g = f.gate;
|
|
66120
|
+
if (g === null)
|
|
66121
|
+
return "gate_unknown";
|
|
66122
|
+
if (!g.ready || g.dialog !== null)
|
|
66123
|
+
return (g.reason ?? "not_ready").slice(0, 48);
|
|
66124
|
+
if (f.working === true)
|
|
66125
|
+
return "working";
|
|
66126
|
+
return null;
|
|
66127
|
+
}
|
|
65668
66128
|
function corroborated(input) {
|
|
65669
66129
|
const quiet = input.corroborationMs ?? CORROBORATION_MS;
|
|
65670
66130
|
if (input.chatQuietMs < quiet)
|
|
65671
66131
|
return { ok: false };
|
|
65672
|
-
if (!input.
|
|
66132
|
+
if (!input.facts)
|
|
65673
66133
|
return { ok: true, anomaly: "screen_unverified" };
|
|
65674
|
-
const
|
|
65675
|
-
|
|
66134
|
+
const why = unconfirmedBy(input.facts);
|
|
66135
|
+
if (why === null)
|
|
66136
|
+
return { ok: true };
|
|
66137
|
+
if (input.chatQuietMs >= (input.corroborationGraceMs ?? CORROBORATION_GRACE_MS))
|
|
66138
|
+
return { ok: true, anomaly: `settle_gate_unconfirmed:${why}` };
|
|
66139
|
+
return { ok: false };
|
|
65676
66140
|
}
|
|
65677
66141
|
function settledAs(by, stopReason, c, extra = []) {
|
|
65678
66142
|
return {
|
|
@@ -65705,10 +66169,13 @@ function pathPrimary(t, input) {
|
|
|
65705
66169
|
function pathSecondary(t, input) {
|
|
65706
66170
|
if (!endingStop(t) || !stopHooksFinished(t, input.session))
|
|
65707
66171
|
return null;
|
|
65708
|
-
if (!input.
|
|
66172
|
+
if (!input.facts)
|
|
65709
66173
|
return null;
|
|
65710
66174
|
const window2 = input.secondaryQuietMs ?? SECONDARY_QUIET_MS;
|
|
65711
|
-
if (input.transcriptQuietMs < window2
|
|
66175
|
+
if (input.transcriptQuietMs < window2)
|
|
66176
|
+
return null;
|
|
66177
|
+
const above = input.facts.aboveBoxQuietMs;
|
|
66178
|
+
if (above !== null && above < window2)
|
|
65712
66179
|
return null;
|
|
65713
66180
|
const c = corroborated(input);
|
|
65714
66181
|
return c.ok ? settledAs("quiet", t.lastAssistant?.stopReason ?? null, c, ["settled_without_turn_duration"]) : null;
|
|
@@ -65739,9 +66206,10 @@ function decideSettle(input) {
|
|
|
65739
66206
|
return endingStop(t) ? settledAs("exit", t.lastAssistant.stopReason, {}) : notYet;
|
|
65740
66207
|
return pathSecondary(t, input) ?? notYet;
|
|
65741
66208
|
}
|
|
65742
|
-
var SECONDARY_QUIET_MS = 32000, CORROBORATION_MS = 500, CONTINUING;
|
|
66209
|
+
var SECONDARY_QUIET_MS = 32000, CORROBORATION_MS = 500, CONTINUING, CORROBORATION_GRACE_MS;
|
|
65743
66210
|
var init_settle_rule = __esm(() => {
|
|
65744
66211
|
CONTINUING = new Set(["tool_use", "pause_turn"]);
|
|
66212
|
+
CORROBORATION_GRACE_MS = SECONDARY_QUIET_MS;
|
|
65745
66213
|
});
|
|
65746
66214
|
|
|
65747
66215
|
// src/pane/slot-state.ts
|
|
@@ -65882,10 +66350,10 @@ import {
|
|
|
65882
66350
|
openSync as openSync8,
|
|
65883
66351
|
readSync as readSync3,
|
|
65884
66352
|
readdirSync as readdirSync7,
|
|
65885
|
-
realpathSync as
|
|
66353
|
+
realpathSync as realpathSync3,
|
|
65886
66354
|
statSync as statSync9
|
|
65887
66355
|
} from "fs";
|
|
65888
|
-
import { join as
|
|
66356
|
+
import { join as join47 } from "path";
|
|
65889
66357
|
function initialFollowerState(resolvePath = safeRealpath) {
|
|
65890
66358
|
return {
|
|
65891
66359
|
turns: [],
|
|
@@ -65900,7 +66368,7 @@ function initialFollowerState(resolvePath = safeRealpath) {
|
|
|
65900
66368
|
}
|
|
65901
66369
|
function safeRealpath(p) {
|
|
65902
66370
|
try {
|
|
65903
|
-
return
|
|
66371
|
+
return realpathSync3(p);
|
|
65904
66372
|
} catch {
|
|
65905
66373
|
return p;
|
|
65906
66374
|
}
|
|
@@ -66413,7 +66881,7 @@ class TranscriptFollower {
|
|
|
66413
66881
|
for (const f of this.subagentFiles()) {
|
|
66414
66882
|
let tail = this.subs.get(f);
|
|
66415
66883
|
if (!tail) {
|
|
66416
|
-
tail = new Tail(
|
|
66884
|
+
tail = new Tail(join47(this.subagentsDir, f));
|
|
66417
66885
|
this.subs.set(f, tail);
|
|
66418
66886
|
}
|
|
66419
66887
|
for (const { line } of tail.read()) {
|
|
@@ -66496,8 +66964,8 @@ var init_transcript_follower = __esm(() => {
|
|
|
66496
66964
|
});
|
|
66497
66965
|
|
|
66498
66966
|
// src/pane/pane-session.ts
|
|
66499
|
-
import { readFileSync as readFileSync30, realpathSync as
|
|
66500
|
-
import { join as
|
|
66967
|
+
import { readFileSync as readFileSync30, realpathSync as realpathSync4, rmSync as rmSync6, statSync as statSync10, writeFileSync as writeFileSync21 } from "fs";
|
|
66968
|
+
import { join as join48 } from "path";
|
|
66501
66969
|
function iso(ms) {
|
|
66502
66970
|
return new Date(ms).toISOString();
|
|
66503
66971
|
}
|
|
@@ -66534,7 +67002,7 @@ class PaneSessionImpl {
|
|
|
66534
67002
|
initialPending;
|
|
66535
67003
|
shape;
|
|
66536
67004
|
queue = [];
|
|
66537
|
-
screen
|
|
67005
|
+
screen;
|
|
66538
67006
|
final = false;
|
|
66539
67007
|
turnIndex = 0;
|
|
66540
67008
|
admission = null;
|
|
@@ -66570,8 +67038,25 @@ class PaneSessionImpl {
|
|
|
66570
67038
|
disagreeCounted = new Set;
|
|
66571
67039
|
exitScrollback = "";
|
|
66572
67040
|
exitLastLine = "";
|
|
66573
|
-
|
|
66574
|
-
|
|
67041
|
+
desiredSize;
|
|
67042
|
+
appliedSize;
|
|
67043
|
+
supportsResize = false;
|
|
67044
|
+
resizeWaiters = [];
|
|
67045
|
+
resizeDraining = false;
|
|
67046
|
+
lastSentSize = null;
|
|
67047
|
+
resizeQuietFrom = 0;
|
|
67048
|
+
resizeQuietUntil = 0;
|
|
67049
|
+
activityChangedAt = 0;
|
|
67050
|
+
gate = null;
|
|
67051
|
+
gateTrusted = false;
|
|
67052
|
+
gateInFlight = false;
|
|
67053
|
+
gateTimer = null;
|
|
67054
|
+
gateDeadSince = 0;
|
|
67055
|
+
lastSend = null;
|
|
67056
|
+
turnAcceptedAt = null;
|
|
67057
|
+
turnErrorLogSize = 0;
|
|
67058
|
+
witnessMissingCounted = false;
|
|
67059
|
+
abandonedIndex = null;
|
|
66575
67060
|
magmux = null;
|
|
66576
67061
|
watcher = null;
|
|
66577
67062
|
client = null;
|
|
@@ -66602,12 +67087,16 @@ class PaneSessionImpl {
|
|
|
66602
67087
|
this.turnDir = ids.turnDir;
|
|
66603
67088
|
this.identity = { paneId: ids.paneId, sessionUuid: o.sessionUuid, ctlDir: ids.ctlDir };
|
|
66604
67089
|
this.shape = o.shape;
|
|
67090
|
+
const size = launchSize(o);
|
|
67091
|
+
this.desiredSize = size;
|
|
67092
|
+
this.appliedSize = { ...size };
|
|
67093
|
+
this.screen = emptyScreen(size.cols, size.rows);
|
|
66605
67094
|
this.initialPending = !!o.initialPrompt;
|
|
66606
67095
|
if (o.initialPrompt)
|
|
66607
67096
|
this.queue.push(o.initialPrompt);
|
|
66608
67097
|
this.secondaryQuietMs = o.timings?.secondaryQuietMs ?? SECONDARY_QUIET_MS;
|
|
66609
67098
|
this.corroborationMs = o.timings?.corroborationMs ?? CORROBORATION_MS;
|
|
66610
|
-
this.follower = new TranscriptFollower(o.transcriptPath,
|
|
67099
|
+
this.follower = new TranscriptFollower(o.transcriptPath, join48(o.transcriptPath.replace(/\.jsonl$/, ""), "subagents"));
|
|
66611
67100
|
this.registry = new SessionRegistry({
|
|
66612
67101
|
configDir: claudeConfigDir(o.parentEnv ?? process.env),
|
|
66613
67102
|
sessionUuid: o.sessionUuid
|
|
@@ -66643,7 +67132,9 @@ class PaneSessionImpl {
|
|
|
66643
67132
|
sockRoot: this.root,
|
|
66644
67133
|
ctlDir: this.ctlDir,
|
|
66645
67134
|
cwd: input.cwd,
|
|
66646
|
-
env: input.env
|
|
67135
|
+
env: input.env,
|
|
67136
|
+
sessionUuid: this.o.sessionUuid,
|
|
67137
|
+
transcriptPath: this.o.transcriptPath
|
|
66647
67138
|
});
|
|
66648
67139
|
} catch (e) {
|
|
66649
67140
|
return this.spawnFailed(e);
|
|
@@ -66652,7 +67143,7 @@ class PaneSessionImpl {
|
|
|
66652
67143
|
return this.spawnFailed(new Error("magmux did not start"));
|
|
66653
67144
|
this.magmux = proc;
|
|
66654
67145
|
try {
|
|
66655
|
-
writeFileSync21(
|
|
67146
|
+
writeFileSync21(join48(this.ctlDir, "magmux.pid"), `${proc.pid}
|
|
66656
67147
|
`, { mode: 384 });
|
|
66657
67148
|
} catch {}
|
|
66658
67149
|
updateRecord(this.root, this.paneId, { magmuxPid: proc.pid });
|
|
@@ -66660,6 +67151,7 @@ class PaneSessionImpl {
|
|
|
66660
67151
|
proc.stderr?.on("data", (d) => this.onStderr(d));
|
|
66661
67152
|
proc.on("exit", (code, sig) => this.onMagmuxExit(code, sig));
|
|
66662
67153
|
this.ticker = setInterval(() => this.step(() => this.evaluate()), TICK_MS);
|
|
67154
|
+
this.gateTimer = setInterval(() => this.pollGate(), GATE_POLL_MS);
|
|
66663
67155
|
if (this.o.timeoutMs !== undefined)
|
|
66664
67156
|
this.timeoutTimer = setTimeout(() => this.step(() => this.fire("timeout")), Math.max(0, this.o.timeoutMs));
|
|
66665
67157
|
await this.connectFirst();
|
|
@@ -66689,7 +67181,6 @@ class PaneSessionImpl {
|
|
|
66689
67181
|
client.close();
|
|
66690
67182
|
return;
|
|
66691
67183
|
}
|
|
66692
|
-
this.client = client;
|
|
66693
67184
|
client.on("snapshot", (e) => this.onSnapshot(e));
|
|
66694
67185
|
client.on("frame", (f) => this.onFrame(f));
|
|
66695
67186
|
client.on("exit", (e) => void this.onPaneExit(e));
|
|
@@ -66701,8 +67192,15 @@ class PaneSessionImpl {
|
|
|
66701
67192
|
const caps = await client.request({
|
|
66702
67193
|
type: "capabilities"
|
|
66703
67194
|
});
|
|
67195
|
+
this.supportsResize = caps.ok && Array.isArray(caps.result.verbs) && caps.result.verbs.includes("resize");
|
|
67196
|
+
if (client.isClosed)
|
|
67197
|
+
return;
|
|
67198
|
+
this.client = client;
|
|
67199
|
+
this.gateTrusted = false;
|
|
67200
|
+
this.gate = null;
|
|
67201
|
+
const magmuxVersion = caps.ok ? String(caps.result.version ?? "") : "";
|
|
66704
67202
|
if (caps.ok) {
|
|
66705
|
-
const v =
|
|
67203
|
+
const v = magmuxVersion;
|
|
66706
67204
|
if (caps.result.protocol !== 1 || !versionAtLeast(v, MIN_MAGMUX_VERSION)) {
|
|
66707
67205
|
this.step(() => this.fire("pane_lost", {
|
|
66708
67206
|
detail: `magmux_unavailable: magmux ${v || "?"} protocol ${caps.result.protocol ?? "?"}; panes need >= ${MIN_MAGMUX_VERSION}, protocol 1`
|
|
@@ -66710,6 +67208,9 @@ class PaneSessionImpl {
|
|
|
66710
67208
|
return;
|
|
66711
67209
|
}
|
|
66712
67210
|
}
|
|
67211
|
+
this.lastSentSize = null;
|
|
67212
|
+
if (this.supportsResize && !samePaneSize(this.appliedSize, this.desiredSize))
|
|
67213
|
+
this.kickResize();
|
|
66713
67214
|
await client.request({ type: "watch", pane: 0, mode: "frames", fps: WATCH_FPS });
|
|
66714
67215
|
const list = await client.request({ type: "list" });
|
|
66715
67216
|
const p0 = list.ok ? list.result.panes?.find((p) => p.pane === 0) : undefined;
|
|
@@ -66719,7 +67220,76 @@ class PaneSessionImpl {
|
|
|
66719
67220
|
if (!reconnect)
|
|
66720
67221
|
await this.nextFrame(500);
|
|
66721
67222
|
this.onPaneExit({ exitCode: p0.exitCode ?? null, lastLine: "" });
|
|
67223
|
+
return;
|
|
67224
|
+
}
|
|
67225
|
+
if (!this.verifyGateBinding(client, list, magmuxVersion) || !list.ok)
|
|
67226
|
+
return;
|
|
67227
|
+
this.gateTrusted = true;
|
|
67228
|
+
this.onGateList(client, list.result);
|
|
67229
|
+
}
|
|
67230
|
+
verifyGateBinding(client, list, magmuxVersion) {
|
|
67231
|
+
if (client.isClosed || isTerminalPhase(this.phase))
|
|
67232
|
+
return false;
|
|
67233
|
+
if (!list.ok) {
|
|
67234
|
+
this.step(() => this.fire("pane_lost", {
|
|
67235
|
+
detail: `input_gate_unbound: magmux ${magmuxVersion || "?"} list failed (${list.code}: ${list.error}), so the binding of pane 0 is unknown`
|
|
67236
|
+
}));
|
|
67237
|
+
return false;
|
|
67238
|
+
}
|
|
67239
|
+
if (!list.result.panes?.some((p) => p.pane === 0))
|
|
67240
|
+
return false;
|
|
67241
|
+
const check = checkGateBinding(list.result, {
|
|
67242
|
+
sessionUuid: this.o.sessionUuid,
|
|
67243
|
+
transcriptPath: this.o.transcriptPath,
|
|
67244
|
+
magmuxVersion
|
|
67245
|
+
});
|
|
67246
|
+
if (!check.ok) {
|
|
67247
|
+
this.step(() => this.fire("pane_lost", { detail: check.detail }));
|
|
67248
|
+
return false;
|
|
66722
67249
|
}
|
|
67250
|
+
return true;
|
|
67251
|
+
}
|
|
67252
|
+
pollGate() {
|
|
67253
|
+
const c = this.client;
|
|
67254
|
+
if (!c || !this.gateTrusted || this.gateInFlight)
|
|
67255
|
+
return;
|
|
67256
|
+
if (this.reaping || isTerminalPhase(this.phase))
|
|
67257
|
+
return;
|
|
67258
|
+
this.gateInFlight = true;
|
|
67259
|
+
c.request({ type: "list" }, GATE_REPLY_MS).then((r) => {
|
|
67260
|
+
this.gateInFlight = false;
|
|
67261
|
+
if (r.ok)
|
|
67262
|
+
this.onGateList(c, r.result);
|
|
67263
|
+
});
|
|
67264
|
+
}
|
|
67265
|
+
onGateList(c, result) {
|
|
67266
|
+
if (c !== this.client || !this.gateTrusted || isTerminalPhase(this.phase))
|
|
67267
|
+
return;
|
|
67268
|
+
const now = Date.now();
|
|
67269
|
+
const p0 = result.panes?.find((p) => p.pane === 0);
|
|
67270
|
+
if (typeof p0?.pid === "number" && !this.panePidValue)
|
|
67271
|
+
this.setPanePid(p0.pid);
|
|
67272
|
+
if (p0?.dead === true && !this.paneExited) {
|
|
67273
|
+
if (this.gateDeadSince === 0)
|
|
67274
|
+
this.gateDeadSince = now;
|
|
67275
|
+
else if (now - this.gateDeadSince >= GATE_DEAD_BACKSTOP_MS) {
|
|
67276
|
+
this.anomaly("exit_event_missing");
|
|
67277
|
+
this.onPaneExit({ exitCode: p0.exitCode ?? null, lastLine: "" });
|
|
67278
|
+
return;
|
|
67279
|
+
}
|
|
67280
|
+
} else
|
|
67281
|
+
this.gateDeadSince = 0;
|
|
67282
|
+
const prev = this.gate;
|
|
67283
|
+
this.gate = parseGateInput(result, now);
|
|
67284
|
+
const g = this.gate;
|
|
67285
|
+
if (prev?.ready !== g?.ready || prev?.reason !== g?.reason)
|
|
67286
|
+
this.step(() => this.evaluate());
|
|
67287
|
+
}
|
|
67288
|
+
gateNow() {
|
|
67289
|
+
const g = this.gate;
|
|
67290
|
+
if (!g || !this.client || !this.gateTrusted)
|
|
67291
|
+
return null;
|
|
67292
|
+
return Date.now() - g.receivedAt <= GATE_STALE_MS ? g : null;
|
|
66723
67293
|
}
|
|
66724
67294
|
onStderr(d) {
|
|
66725
67295
|
if (this.stderrHead.length < 8192)
|
|
@@ -66742,7 +67312,10 @@ class PaneSessionImpl {
|
|
|
66742
67312
|
onFrame(f) {
|
|
66743
67313
|
if (f.pane !== undefined && f.pane !== 0)
|
|
66744
67314
|
return;
|
|
67315
|
+
const seq = this.screen.seq;
|
|
66745
67316
|
this.screen = applyFrame(this.screen, f);
|
|
67317
|
+
if (this.screen.seq !== seq && !this.inResizeQuiet(this.screen.changedAt))
|
|
67318
|
+
this.activityChangedAt = this.screen.changedAt;
|
|
66746
67319
|
this.framePending = true;
|
|
66747
67320
|
if (!this.claudeCodeVersion) {
|
|
66748
67321
|
const m = this.screen.lines.join(`
|
|
@@ -66753,8 +67326,11 @@ class PaneSessionImpl {
|
|
|
66753
67326
|
this.step(() => this.evaluate());
|
|
66754
67327
|
}
|
|
66755
67328
|
onDisconnected(client) {
|
|
66756
|
-
if (this.client === client)
|
|
67329
|
+
if (this.client === client) {
|
|
66757
67330
|
this.client = null;
|
|
67331
|
+
this.gate = null;
|
|
67332
|
+
this.gateTrusted = false;
|
|
67333
|
+
}
|
|
66758
67334
|
if (this.reaping || !alive(this.magmux))
|
|
66759
67335
|
return;
|
|
66760
67336
|
if (isTerminalPhase(this.phase))
|
|
@@ -66946,11 +67522,15 @@ class PaneSessionImpl {
|
|
|
66946
67522
|
if (!this.client)
|
|
66947
67523
|
return;
|
|
66948
67524
|
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
67525
|
this.disagree("registry_idle_screen_working", this.phase === "RUNNING" && idle && isWorking(this.screen), now);
|
|
66952
|
-
this.
|
|
66953
|
-
|
|
67526
|
+
const g = this.gateNow();
|
|
67527
|
+
if (!g)
|
|
67528
|
+
return;
|
|
67529
|
+
this.disagree("registry_idle_gate_starting", this.phase === "BOOTING" && idle && (g.reason === "starting" || g.reason === "no_input_box"), now, REGISTRY_GATE_BOOT_DISAGREE_MS);
|
|
67530
|
+
this.disagree("registry_waiting_gate_no_dialog", status === "waiting" && g.ready, now);
|
|
67531
|
+
this.disagree("gate_dialog_registry_not_waiting", g.dialog !== null && RUNTIME_DIALOG_KINDS.has(g.dialog) && (idle || status === "busy"), now);
|
|
67532
|
+
this.disagree("gate_ready_box_not_located", g.ready && locateBox(this.screen) === null, now);
|
|
67533
|
+
this.disagree("gate_dialog_screen_unrecognised", (g.dialog === "permission" || g.dialog === "plan" || g.dialog === "question") && choiceDialog(this.screen) === null, now);
|
|
66954
67534
|
}
|
|
66955
67535
|
disagree(key, holds, now, forMs = REGISTRY_DISAGREE_MS) {
|
|
66956
67536
|
if (!holds) {
|
|
@@ -66986,33 +67566,42 @@ class PaneSessionImpl {
|
|
|
66986
67566
|
}
|
|
66987
67567
|
evalBoot() {
|
|
66988
67568
|
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)) {
|
|
67569
|
+
const g = this.gateNow();
|
|
67570
|
+
if (g?.ready) {
|
|
66997
67571
|
this.bootReady();
|
|
66998
67572
|
return;
|
|
66999
67573
|
}
|
|
67000
|
-
|
|
67001
|
-
|
|
67002
|
-
|
|
67003
|
-
|
|
67004
|
-
|
|
67005
|
-
this.fire("boot_blocked", { detail: r.text });
|
|
67574
|
+
const staticFor = this.screen.seq === 0 ? 0 : now - this.screen.changedAt;
|
|
67575
|
+
const settled = staticFor >= this.t("bootStaticMs", BOOT_STATIC_MS);
|
|
67576
|
+
const block = g && settled ? this.bootBlock(g) : null;
|
|
67577
|
+
if (block) {
|
|
67578
|
+
this.fire(block.ev, { detail: block.detail });
|
|
67006
67579
|
return;
|
|
67007
67580
|
}
|
|
67008
67581
|
if (now - this.startedAtMs >= (this.o.bootTimeoutMs ?? BOOT_TIMEOUT_MS)) {
|
|
67009
|
-
const blocked = this.screen.seq > 0 &&
|
|
67582
|
+
const blocked = this.screen.seq > 0 && settled && (g?.reason?.startsWith("dialog:") === true || nameBootScreen(this.screen).kind !== "booting");
|
|
67583
|
+
const gate = g ? `gate: ${g.reason ?? "ready"}${g.detail ? ` (${g.detail})` : ""}` : "gate: unknown";
|
|
67010
67584
|
this.fire("boot_deadline", {
|
|
67011
67585
|
reason: blocked ? "boot_blocked" : "boot_timeout",
|
|
67012
|
-
detail: screenTailOf(this.screen)
|
|
67586
|
+
detail: `${screenTailOf(this.screen)}
|
|
67587
|
+
${gate}`
|
|
67013
67588
|
});
|
|
67014
67589
|
}
|
|
67015
67590
|
}
|
|
67591
|
+
bootBlock(g) {
|
|
67592
|
+
if (g.dialog && BOOT_DIALOG_KINDS.has(g.dialog))
|
|
67593
|
+
return { ev: "boot_dialog", detail: dialogText(this.screen) };
|
|
67594
|
+
const named = nameBootScreen(this.screen);
|
|
67595
|
+
if (named.kind === "dialog")
|
|
67596
|
+
return { ev: "boot_dialog", detail: named.text };
|
|
67597
|
+
if (g.reason === "vim_mode")
|
|
67598
|
+
return { ev: "boot_blocked", detail: "vim editing mode is on (-- INSERT -- under the box)" };
|
|
67599
|
+
if (g.reason?.startsWith("dialog:"))
|
|
67600
|
+
return { ev: "boot_blocked", detail: screenText(this.screen) };
|
|
67601
|
+
if (named.kind === "choice" && g.reason !== null && GATE_KINDLESS_REASONS.has(g.reason))
|
|
67602
|
+
return { ev: "boot_blocked", detail: named.text };
|
|
67603
|
+
return null;
|
|
67604
|
+
}
|
|
67016
67605
|
bootReady() {
|
|
67017
67606
|
this.bootReadyAtMs = Date.now();
|
|
67018
67607
|
if (this.queue.length === 0) {
|
|
@@ -67038,7 +67627,7 @@ class PaneSessionImpl {
|
|
|
67038
67627
|
const head = this.queue.shift();
|
|
67039
67628
|
if (isControl(head)) {
|
|
67040
67629
|
this.exitRequested = true;
|
|
67041
|
-
this.
|
|
67630
|
+
this.submitControl(head.trim());
|
|
67042
67631
|
return;
|
|
67043
67632
|
}
|
|
67044
67633
|
this.fire("admit");
|
|
@@ -67062,6 +67651,9 @@ class PaneSessionImpl {
|
|
|
67062
67651
|
this.screenTurn = null;
|
|
67063
67652
|
this.rewakeOfSettled = false;
|
|
67064
67653
|
this.settledChatOffset = null;
|
|
67654
|
+
this.turnAcceptedAt = null;
|
|
67655
|
+
this.witnessMissingCounted = false;
|
|
67656
|
+
this.abandonedIndex = null;
|
|
67065
67657
|
if (plan.mode === "refused" || plan.mode === "control") {
|
|
67066
67658
|
this.anomaly(`delivery_refused:${plan.mode === "refused" ? plan.reason : "control"}`);
|
|
67067
67659
|
this.admission = null;
|
|
@@ -67077,79 +67669,385 @@ class PaneSessionImpl {
|
|
|
67077
67669
|
}
|
|
67078
67670
|
const delivery = (plan.mode === "file" || plan.mode === "command") && plan.file && plan.fileContent !== undefined ? { file: plan.file, text: plan.fileContent } : null;
|
|
67079
67671
|
this.follower.openTurn({ index, offset, witness: plan.witness, delivery });
|
|
67080
|
-
this.
|
|
67081
|
-
|
|
67082
|
-
|
|
67083
|
-
|
|
67084
|
-
|
|
67085
|
-
|
|
67086
|
-
|
|
67087
|
-
resent: false,
|
|
67088
|
-
panelEscaped: false,
|
|
67089
|
-
degraded: false
|
|
67090
|
-
};
|
|
67091
|
-
this.deliver(this.admission);
|
|
67672
|
+
const bound = initial ? this.o.admitTimeoutMs ?? ADMIT_TIMEOUT_MS : ADMIT_TIMEOUT_MS;
|
|
67673
|
+
const adm = newAdmission({ index, text, plan, initial, bound });
|
|
67674
|
+
this.admission = adm;
|
|
67675
|
+
this.runAdmission(adm);
|
|
67676
|
+
}
|
|
67677
|
+
admitting(adm) {
|
|
67678
|
+
return this.admission === adm && this.phase === "ADMITTING";
|
|
67092
67679
|
}
|
|
67093
|
-
async
|
|
67094
|
-
|
|
67095
|
-
adm.
|
|
67680
|
+
async runAdmission(adm) {
|
|
67681
|
+
try {
|
|
67682
|
+
while (this.admitting(adm) && adm.submittedUnproven === null && !adm.stopped) {
|
|
67683
|
+
if (Date.now() >= adm.deadline)
|
|
67684
|
+
return;
|
|
67685
|
+
if (adm.panel) {
|
|
67686
|
+
await this.pause(adm, TICK_MS);
|
|
67687
|
+
continue;
|
|
67688
|
+
}
|
|
67689
|
+
if (!this.client || !this.gateTrusted) {
|
|
67690
|
+
await this.awaitTrustedClient(adm);
|
|
67691
|
+
continue;
|
|
67692
|
+
}
|
|
67693
|
+
if (await this.beforeSend(adm) !== "send")
|
|
67694
|
+
continue;
|
|
67695
|
+
if (!this.admitting(adm) || !await this.attemptOnce(adm))
|
|
67696
|
+
return;
|
|
67697
|
+
}
|
|
67698
|
+
} finally {
|
|
67699
|
+
adm.inFlight = false;
|
|
67700
|
+
}
|
|
67096
67701
|
}
|
|
67097
|
-
|
|
67098
|
-
|
|
67702
|
+
awaitTrustedClient(adm) {
|
|
67703
|
+
return this.waitFor(() => !this.admitting(adm) || !!this.client && this.gateTrusted, Math.max(0, adm.deadline - Date.now()));
|
|
67704
|
+
}
|
|
67705
|
+
async attemptOnce(adm) {
|
|
67706
|
+
const c = this.client;
|
|
67707
|
+
if (!c)
|
|
67708
|
+
return true;
|
|
67709
|
+
const step = adm.step;
|
|
67710
|
+
const shape = sendShape(step, adm.line);
|
|
67711
|
+
const rt = readyTimeoutFor(step, adm.line, adm.deadline - Date.now());
|
|
67712
|
+
if (rt === null)
|
|
67099
67713
|
return false;
|
|
67100
|
-
|
|
67101
|
-
|
|
67102
|
-
|
|
67103
|
-
|
|
67104
|
-
|
|
67105
|
-
|
|
67106
|
-
|
|
67107
|
-
|
|
67108
|
-
|
|
67109
|
-
await this.typeLine(plan.line, true);
|
|
67714
|
+
const timeout = sendBudgetMs({ ...shape.budget, readyTimeoutMs: rt }) + SEND_CLIENT_SLACK_MS;
|
|
67715
|
+
const sentAt = Date.now();
|
|
67716
|
+
adm.inFlight = true;
|
|
67717
|
+
adm.attempts++;
|
|
67718
|
+
let reply;
|
|
67719
|
+
try {
|
|
67720
|
+
reply = await c.request({ ...shape.msg, readyTimeoutMs: rt }, timeout);
|
|
67721
|
+
} finally {
|
|
67722
|
+
adm.inFlight = false;
|
|
67110
67723
|
}
|
|
67724
|
+
const out = classifySendReply(reply);
|
|
67725
|
+
adm.last = out;
|
|
67726
|
+
this.noteLastSend(out, adm.attempts);
|
|
67727
|
+
if (!this.admitting(adm))
|
|
67728
|
+
return false;
|
|
67729
|
+
await this.onSendOutcome(adm, out, step, { client: c, until: sentAt + timeout });
|
|
67111
67730
|
return true;
|
|
67112
67731
|
}
|
|
67113
|
-
async
|
|
67114
|
-
|
|
67115
|
-
|
|
67116
|
-
|
|
67117
|
-
|
|
67118
|
-
|
|
67119
|
-
if (
|
|
67120
|
-
|
|
67121
|
-
|
|
67122
|
-
|
|
67123
|
-
if (await this.landedAfterLostReply(text, enter))
|
|
67124
|
-
return true;
|
|
67732
|
+
async onSendOutcome(adm, out, step, sent) {
|
|
67733
|
+
switch (out.kind) {
|
|
67734
|
+
case "accepted":
|
|
67735
|
+
this.onGateAccepted(adm, out);
|
|
67736
|
+
return;
|
|
67737
|
+
case "in_box":
|
|
67738
|
+
if (step !== "type") {
|
|
67739
|
+
this.anomaly("send_unexpected:in_box");
|
|
67740
|
+
this.stopAdmission(adm, "magmux answered in_box to a send that carried an Enter");
|
|
67741
|
+
return;
|
|
67125
67742
|
}
|
|
67743
|
+
if (out.retyped)
|
|
67744
|
+
this.anomaly(`gate_retyped:${out.retypeCause ?? "unknown"}`);
|
|
67745
|
+
await this.menuCheck(adm);
|
|
67746
|
+
adm.step = "enter";
|
|
67747
|
+
return;
|
|
67748
|
+
case "busy":
|
|
67749
|
+
await this.onBusy(adm, out, step);
|
|
67750
|
+
return;
|
|
67751
|
+
case "not_accepted":
|
|
67752
|
+
await this.onNotAccepted(adm, out, step);
|
|
67753
|
+
return;
|
|
67754
|
+
case "bad_request":
|
|
67755
|
+
this.anomaly("send_bad_request");
|
|
67756
|
+
this.stopAdmission(adm, `send_bad_request: ${out.error}`);
|
|
67757
|
+
return;
|
|
67758
|
+
case "reply_lost":
|
|
67759
|
+
this.anomaly("send_reply_lost");
|
|
67760
|
+
if (step === "type") {
|
|
67761
|
+
adm.lostType = sent;
|
|
67762
|
+
markClearFirst(adm);
|
|
67763
|
+
return;
|
|
67764
|
+
}
|
|
67765
|
+
adm.submittedUnproven = "reply_lost";
|
|
67766
|
+
return;
|
|
67767
|
+
case "unsent":
|
|
67768
|
+
await this.pause(adm, BUSY_RETRY_MS);
|
|
67769
|
+
return;
|
|
67770
|
+
case "pane_gone":
|
|
67771
|
+
adm.stopped = true;
|
|
67772
|
+
return;
|
|
67773
|
+
case "unexpected":
|
|
67774
|
+
this.anomaly(`send_unexpected:${out.code}`);
|
|
67775
|
+
this.stopAdmission(adm, `send_unexpected: ${out.code}${out.error ? `: ${out.error}` : ""}`);
|
|
67776
|
+
return;
|
|
67777
|
+
default:
|
|
67778
|
+
assertNever(out);
|
|
67779
|
+
}
|
|
67780
|
+
}
|
|
67781
|
+
onGateAccepted(adm, out) {
|
|
67782
|
+
if (out.accept === "resent_enter")
|
|
67783
|
+
this.anomaly("gate_resent_enter");
|
|
67784
|
+
if (out.accept === "submitted_by_other")
|
|
67785
|
+
this.anomaly("gate_submitted_by_other");
|
|
67786
|
+
if (out.retyped)
|
|
67787
|
+
this.anomaly(`gate_retyped:${out.retypeCause ?? "unknown"}`);
|
|
67788
|
+
if (out.dismissed.length > 0)
|
|
67789
|
+
this.anomaly("gate_dismissed_unexpected");
|
|
67790
|
+
if (out.evidence === "transcript") {
|
|
67791
|
+
this.anomaly("gate_transcript_evidence");
|
|
67792
|
+
if (!this.witnessNow()) {
|
|
67793
|
+
this.anomaly("gate_transcript_evidence_unwitnessed");
|
|
67794
|
+
adm.submittedUnproven = "unconfirmed";
|
|
67795
|
+
return;
|
|
67126
67796
|
}
|
|
67127
|
-
await Bun.sleep(500);
|
|
67128
67797
|
}
|
|
67129
|
-
this.
|
|
67798
|
+
this.acceptAdmission(adm);
|
|
67799
|
+
}
|
|
67800
|
+
async onBusy(adm, out, step) {
|
|
67801
|
+
const reason = out.reason || "unknown";
|
|
67802
|
+
if (this.stopOnGateBlock(adm, reason, out.dialog))
|
|
67803
|
+
return;
|
|
67804
|
+
if (out.dialog === "select" && step === "enter") {
|
|
67805
|
+
this.noteOnce(adm, "gate_dialog_at_admission:select");
|
|
67806
|
+
adm.panel = { showingSince: null, escaped: false, entered: false };
|
|
67807
|
+
return;
|
|
67808
|
+
}
|
|
67809
|
+
if (out.dialog) {
|
|
67810
|
+
this.noteOnce(adm, `gate_dialog_at_admission:${out.dialog}`);
|
|
67811
|
+
} else if (out.typed) {
|
|
67812
|
+
this.anomaly("gate_typed_withheld");
|
|
67813
|
+
markClearFirst(adm);
|
|
67814
|
+
} else if (reason === "box_not_empty") {
|
|
67815
|
+
this.anomaly("gate_box_not_empty");
|
|
67816
|
+
markClearFirst(adm);
|
|
67817
|
+
} else {
|
|
67818
|
+
this.noteOnce(adm, `gate_busy:${reason}`);
|
|
67819
|
+
}
|
|
67820
|
+
await this.pause(adm, BUSY_RETRY_MS);
|
|
67821
|
+
}
|
|
67822
|
+
stopOnGateBlock(adm, reason, dialog) {
|
|
67823
|
+
if (dialog && BOOT_DIALOG_KINDS.has(dialog)) {
|
|
67824
|
+
this.anomaly(`gate_boot_dialog:${dialog}`);
|
|
67825
|
+
this.stopAdmission(adm, dialogText(this.screen) || `busy ${reason}`, "first_run_dialog");
|
|
67826
|
+
return true;
|
|
67827
|
+
}
|
|
67828
|
+
if (reason === "vim_mode") {
|
|
67829
|
+
this.anomaly("gate_vim_mode");
|
|
67830
|
+
this.stopAdmission(adm, "busy vim_mode: vim editing mode is on (-- INSERT -- under the box)");
|
|
67831
|
+
return true;
|
|
67832
|
+
}
|
|
67130
67833
|
return false;
|
|
67131
67834
|
}
|
|
67132
|
-
async
|
|
67133
|
-
|
|
67134
|
-
|
|
67135
|
-
|
|
67136
|
-
|
|
67137
|
-
|
|
67138
|
-
|
|
67139
|
-
if (
|
|
67140
|
-
|
|
67141
|
-
|
|
67142
|
-
|
|
67835
|
+
async precheckGate(adm) {
|
|
67836
|
+
const g = this.gateNow();
|
|
67837
|
+
if (!g || g.ready)
|
|
67838
|
+
return "send";
|
|
67839
|
+
if (this.stopOnGateBlock(adm, g.reason ?? "unknown", g.dialog))
|
|
67840
|
+
return "stopped";
|
|
67841
|
+
const kind = g.dialog;
|
|
67842
|
+
if (kind !== "permission" && kind !== "question" && kind !== "plan")
|
|
67843
|
+
return "send";
|
|
67844
|
+
this.noteOnce(adm, `gate_dialog_at_admission:${kind}`);
|
|
67845
|
+
await this.waitFor(() => !this.admitting(adm) || this.gateNow()?.dialog !== kind, Math.max(0, adm.deadline - Date.now()));
|
|
67846
|
+
return "waited";
|
|
67847
|
+
}
|
|
67848
|
+
async beforeSend(adm) {
|
|
67849
|
+
if (adm.step === "enter")
|
|
67850
|
+
return "send";
|
|
67851
|
+
await this.clearLeftover(adm);
|
|
67852
|
+
if (!this.admitting(adm))
|
|
67853
|
+
return "stopped";
|
|
67854
|
+
return this.precheckGate(adm);
|
|
67855
|
+
}
|
|
67856
|
+
async onNotAccepted(adm, out, step) {
|
|
67857
|
+
switch (out.reason) {
|
|
67858
|
+
case "text_mismatch":
|
|
67859
|
+
if (out.maybeSubmitted) {
|
|
67860
|
+
this.anomaly("gate_maybe_submitted_by_other");
|
|
67861
|
+
adm.submittedUnproven = "maybe_submitted_by_other";
|
|
67862
|
+
return;
|
|
67863
|
+
}
|
|
67864
|
+
this.anomaly("gate_text_mismatch");
|
|
67865
|
+
markClearFirst(adm);
|
|
67866
|
+
if (adm.plan.mode === "command")
|
|
67867
|
+
adm.step = "type";
|
|
67868
|
+
await this.pause(adm, MISMATCH_SETTLE_MS);
|
|
67869
|
+
return;
|
|
67870
|
+
case "empty_box":
|
|
67871
|
+
if (step === "enter") {
|
|
67872
|
+
this.anomaly("gate_command_left_box");
|
|
67873
|
+
adm.submittedUnproven = "maybe_submitted_by_other";
|
|
67874
|
+
return;
|
|
67875
|
+
}
|
|
67876
|
+
this.anomaly("gate_empty_box");
|
|
67877
|
+
await this.pause(adm, BUSY_RETRY_MS);
|
|
67878
|
+
return;
|
|
67879
|
+
case "still_in_box":
|
|
67880
|
+
if (this.witnessNow()) {
|
|
67881
|
+
this.acceptAdmission(adm);
|
|
67882
|
+
return;
|
|
67883
|
+
}
|
|
67884
|
+
this.anomaly("gate_still_in_box");
|
|
67885
|
+
if (adm.stuckRetried) {
|
|
67886
|
+
adm.submittedUnproven = "still_in_box_twice";
|
|
67887
|
+
return;
|
|
67888
|
+
}
|
|
67889
|
+
adm.stuckRetried = true;
|
|
67890
|
+
await this.clearBox(adm);
|
|
67891
|
+
if (adm.plan.mode === "command")
|
|
67892
|
+
adm.step = "type";
|
|
67893
|
+
return;
|
|
67894
|
+
case "unconfirmed":
|
|
67895
|
+
this.anomaly("gate_unconfirmed");
|
|
67896
|
+
adm.submittedUnproven = "unconfirmed";
|
|
67897
|
+
if (step === "enter")
|
|
67898
|
+
adm.panel = { showingSince: null, escaped: false, entered: true };
|
|
67899
|
+
return;
|
|
67900
|
+
default:
|
|
67901
|
+
assertNever(out.reason);
|
|
67902
|
+
}
|
|
67903
|
+
}
|
|
67904
|
+
acceptAdmission(adm) {
|
|
67905
|
+
this.step(() => {
|
|
67906
|
+
if (this.admitting(adm))
|
|
67907
|
+
this.accept();
|
|
67908
|
+
});
|
|
67909
|
+
}
|
|
67910
|
+
stopAdmission(adm, detail, reason) {
|
|
67911
|
+
adm.stopped = true;
|
|
67912
|
+
this.step(() => {
|
|
67913
|
+
if (!this.admitting(adm))
|
|
67914
|
+
return;
|
|
67915
|
+
this.admission = null;
|
|
67916
|
+
if (adm.initial) {
|
|
67917
|
+
this.fire("admit_deadline", { reason, detail: `${detail}
|
|
67918
|
+
${screenTailOf(this.screen)}` });
|
|
67919
|
+
return;
|
|
67920
|
+
}
|
|
67921
|
+
this.anomaly("send_not_accepted");
|
|
67922
|
+
this.abandonedIndex = adm.index;
|
|
67923
|
+
this.fire("admit_abandoned");
|
|
67924
|
+
});
|
|
67925
|
+
}
|
|
67926
|
+
witnessNow() {
|
|
67927
|
+
return this.witnessed(this.pollFollower(true).current);
|
|
67928
|
+
}
|
|
67929
|
+
noteOnce(adm, key) {
|
|
67930
|
+
if (adm.noted.has(key))
|
|
67931
|
+
return;
|
|
67932
|
+
adm.noted.add(key);
|
|
67933
|
+
this.anomaly(key);
|
|
67934
|
+
}
|
|
67935
|
+
pause(adm, ms) {
|
|
67936
|
+
return this.waitFor(() => !this.admitting(adm), ms);
|
|
67937
|
+
}
|
|
67938
|
+
freshReady(after) {
|
|
67939
|
+
const g = this.gateNow();
|
|
67940
|
+
return !!g && g.receivedAt > after && g.ready;
|
|
67941
|
+
}
|
|
67942
|
+
async clearBox(adm) {
|
|
67943
|
+
const at = Date.now();
|
|
67944
|
+
await this.key("ctrl-u");
|
|
67945
|
+
await this.waitFor(() => !this.admitting(adm) || this.freshReady(at), CLEAR_WAIT_MS);
|
|
67946
|
+
}
|
|
67947
|
+
async clearLeftover(adm) {
|
|
67948
|
+
const lost = adm.lostType;
|
|
67949
|
+
if (lost) {
|
|
67950
|
+
adm.lostType = null;
|
|
67951
|
+
if (lost.client !== this.client || lost.client.isClosed)
|
|
67952
|
+
await this.pause(adm, Math.max(0, lost.until - Date.now()));
|
|
67953
|
+
if (!this.admitting(adm))
|
|
67954
|
+
return;
|
|
67955
|
+
}
|
|
67956
|
+
if (adm.clearFirst)
|
|
67957
|
+
await this.clearOwnLeftover(adm);
|
|
67958
|
+
else if (this.gateNow()?.reason === "box_not_empty")
|
|
67959
|
+
await this.clearBox(adm);
|
|
67960
|
+
}
|
|
67961
|
+
async clearOwnLeftover(adm) {
|
|
67962
|
+
const after = adm.clearAfter + GATE_POLL_MS;
|
|
67963
|
+
const newer = () => {
|
|
67964
|
+
const g = this.gateNow();
|
|
67965
|
+
return g && g.receivedAt > after ? g : null;
|
|
67966
|
+
};
|
|
67967
|
+
await this.waitFor(() => !this.admitting(adm) || newer() !== null, CLEAR_WAIT_MS + GATE_POLL_MS);
|
|
67968
|
+
if (!this.admitting(adm))
|
|
67969
|
+
return;
|
|
67970
|
+
const g = newer();
|
|
67971
|
+
if (g?.ready) {
|
|
67972
|
+
adm.clearFirst = false;
|
|
67973
|
+
return;
|
|
67974
|
+
}
|
|
67975
|
+
if (g && (g.dialog !== null || g.reason === "vim_mode"))
|
|
67976
|
+
return;
|
|
67977
|
+
adm.clearFirst = false;
|
|
67978
|
+
await this.clearBox(adm);
|
|
67979
|
+
}
|
|
67980
|
+
async menuCheck(adm) {
|
|
67981
|
+
const name = adm.line.match(/^\/\S+/)?.[0] ?? "";
|
|
67982
|
+
await this.waitFor(() => {
|
|
67983
|
+
if (!this.admitting(adm))
|
|
67984
|
+
return true;
|
|
67985
|
+
const box = locateBox(this.screen);
|
|
67986
|
+
return !!box && locatedBoxText(this.screen, box).startsWith(name);
|
|
67987
|
+
}, 2 * TICK_MS);
|
|
67988
|
+
if (!this.admitting(adm))
|
|
67989
|
+
return;
|
|
67990
|
+
const box = locateBox(this.screen);
|
|
67991
|
+
if (!box) {
|
|
67992
|
+
this.anomaly("menu_unverified");
|
|
67993
|
+
return;
|
|
67994
|
+
}
|
|
67995
|
+
const menu = menuAbove(this.screen.lines, box.top);
|
|
67996
|
+
if (menu.menuOpen && menu.menuItem !== name)
|
|
67997
|
+
await this.key("escape");
|
|
67998
|
+
}
|
|
67999
|
+
noteLastSend(out, attempts) {
|
|
68000
|
+
const s = { kind: out.kind, attempts };
|
|
68001
|
+
switch (out.kind) {
|
|
68002
|
+
case "accepted":
|
|
68003
|
+
s.accept = out.accept;
|
|
68004
|
+
s.evidence = out.evidence;
|
|
68005
|
+
if (out.retypeCause)
|
|
68006
|
+
s.retypeCause = out.retypeCause;
|
|
68007
|
+
break;
|
|
68008
|
+
case "in_box":
|
|
68009
|
+
s.accept = "in_box";
|
|
68010
|
+
if (out.retypeCause)
|
|
68011
|
+
s.retypeCause = out.retypeCause;
|
|
68012
|
+
break;
|
|
68013
|
+
case "busy":
|
|
68014
|
+
case "not_accepted":
|
|
68015
|
+
s.reason = out.reason;
|
|
68016
|
+
break;
|
|
68017
|
+
case "bad_request":
|
|
68018
|
+
s.reason = "bad_request";
|
|
68019
|
+
break;
|
|
68020
|
+
case "reply_lost":
|
|
68021
|
+
case "unsent":
|
|
68022
|
+
case "pane_gone":
|
|
68023
|
+
case "unexpected":
|
|
68024
|
+
s.reason = out.code;
|
|
68025
|
+
break;
|
|
68026
|
+
default:
|
|
68027
|
+
assertNever(out);
|
|
68028
|
+
}
|
|
68029
|
+
this.lastSend = s;
|
|
68030
|
+
return s;
|
|
68031
|
+
}
|
|
68032
|
+
async submitControl(line) {
|
|
68033
|
+
const c = this.client;
|
|
68034
|
+
if (!c) {
|
|
68035
|
+
this.anomaly("control_send:unsent");
|
|
68036
|
+
return;
|
|
67143
68037
|
}
|
|
67144
|
-
|
|
67145
|
-
|
|
67146
|
-
|
|
68038
|
+
const rt = SEND_READY_WAIT_DEFAULT_MS;
|
|
68039
|
+
const shape = sendShape("submit", line);
|
|
68040
|
+
const r = await c.request({ ...shape.msg, readyTimeoutMs: rt }, sendBudgetMs({ ...shape.budget, readyTimeoutMs: rt }) + SEND_CLIENT_SLACK_MS);
|
|
68041
|
+
const out = classifySendReply(r);
|
|
68042
|
+
const s = this.noteLastSend(out, 1);
|
|
68043
|
+
if (out.kind !== "accepted")
|
|
68044
|
+
this.anomaly(`control_send:${out.kind}${s.reason ? `:${s.reason}` : ""}`);
|
|
67147
68045
|
}
|
|
67148
68046
|
async key(k) {
|
|
67149
68047
|
const c = this.client;
|
|
67150
68048
|
if (!c)
|
|
67151
68049
|
return false;
|
|
67152
|
-
const r = await c.request({ type: "send", pane: 0, keys: [k], enter: false }, 1e4);
|
|
68050
|
+
const r = await c.request({ type: "send", pane: 0, keys: [k], enter: false, noGate: true }, 1e4);
|
|
67153
68051
|
return r.ok;
|
|
67154
68052
|
}
|
|
67155
68053
|
nextFrame(ms) {
|
|
@@ -67169,139 +68067,134 @@ class PaneSessionImpl {
|
|
|
67169
68067
|
const adm = this.admission;
|
|
67170
68068
|
if (!adm)
|
|
67171
68069
|
return;
|
|
67172
|
-
|
|
67173
|
-
if (cur && cur.index === adm.index && cur.acceptedAt !== null) {
|
|
68070
|
+
if (this.witnessed(view.current)) {
|
|
67174
68071
|
this.accept();
|
|
67175
68072
|
return;
|
|
67176
68073
|
}
|
|
67177
|
-
|
|
67178
|
-
|
|
67179
|
-
if (
|
|
68074
|
+
if (adm.panel)
|
|
68075
|
+
this.panelStep(adm);
|
|
68076
|
+
if (!this.admitting(adm))
|
|
67180
68077
|
return;
|
|
67181
|
-
if (adm.
|
|
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")
|
|
67186
|
-
return;
|
|
67187
|
-
if (now - adm.startedAt >= (this.o.admitTimeoutMs ?? ADMIT_TIMEOUT_MS))
|
|
68078
|
+
if (Date.now() >= adm.deadline && !adm.inFlight)
|
|
67188
68079
|
this.admitExpired(adm);
|
|
67189
68080
|
}
|
|
67190
|
-
|
|
67191
|
-
return
|
|
68081
|
+
panelShowing(g) {
|
|
68082
|
+
return !!g && (g.reason === "no_input_box" || g.dialog === "select") && /Esc to cancel/.test(flatText(this.screen.lines));
|
|
67192
68083
|
}
|
|
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
|
-
})();
|
|
68084
|
+
panelStep(adm) {
|
|
68085
|
+
const p = adm.panel;
|
|
68086
|
+
if (!p)
|
|
67254
68087
|
return;
|
|
67255
|
-
|
|
67256
|
-
if (!
|
|
67257
|
-
|
|
67258
|
-
|
|
68088
|
+
const g = this.gateNow();
|
|
68089
|
+
if (!p.escaped) {
|
|
68090
|
+
if (!this.panelShowing(g)) {
|
|
68091
|
+
p.showingSince = null;
|
|
68092
|
+
return;
|
|
68093
|
+
}
|
|
68094
|
+
const now = Date.now();
|
|
68095
|
+
p.showingSince ??= now;
|
|
68096
|
+
if (now - p.showingSince < PANEL_SETTLE_MS)
|
|
68097
|
+
return;
|
|
68098
|
+
p.escaped = true;
|
|
68099
|
+
this.anomaly(g?.dialog === "select" ? "picker_dismissed" : "panel_dismissed");
|
|
67259
68100
|
this.key("escape");
|
|
67260
|
-
}
|
|
67261
|
-
}
|
|
67262
|
-
maybeDegradedAccept(adm, view) {
|
|
67263
|
-
if (view.availability === "ok")
|
|
67264
68101
|
return;
|
|
67265
|
-
|
|
67266
|
-
if (!
|
|
68102
|
+
}
|
|
68103
|
+
if (!g)
|
|
67267
68104
|
return;
|
|
67268
|
-
|
|
67269
|
-
|
|
67270
|
-
|
|
67271
|
-
|
|
68105
|
+
if (g.ready) {
|
|
68106
|
+
this.admission = null;
|
|
68107
|
+
this.anomaly("panel_command");
|
|
68108
|
+
if (adm.initial)
|
|
68109
|
+
this.fire("admit_deadline", {
|
|
68110
|
+
detail: `${adm.text.trim()} opened a panel and wrote no transcript record`
|
|
68111
|
+
});
|
|
68112
|
+
else
|
|
68113
|
+
this.fire("admit_abandoned");
|
|
67272
68114
|
return;
|
|
67273
|
-
|
|
67274
|
-
|
|
67275
|
-
|
|
67276
|
-
this.accept();
|
|
68115
|
+
}
|
|
68116
|
+
if (!p.entered && g.reason === "box_not_empty")
|
|
68117
|
+
adm.panel = null;
|
|
67277
68118
|
}
|
|
67278
68119
|
accept() {
|
|
67279
68120
|
this.admission = null;
|
|
67280
68121
|
this.initialDelivery = false;
|
|
67281
|
-
|
|
68122
|
+
const now = Date.now();
|
|
68123
|
+
this.lastChatSeenAt = now;
|
|
68124
|
+
this.turnAcceptedAt = now;
|
|
68125
|
+
this.turnErrorLogSize = this.errorLogSize();
|
|
67282
68126
|
this.fire("prompt_accepted");
|
|
67283
68127
|
}
|
|
67284
68128
|
admitExpired(adm) {
|
|
67285
68129
|
this.admission = null;
|
|
67286
68130
|
if (adm.initial) {
|
|
67287
|
-
this.fire("admit_deadline", {
|
|
68131
|
+
this.fire("admit_deadline", {
|
|
68132
|
+
detail: `${this.notAcceptedLine(adm)}
|
|
68133
|
+
${screenTailOf(this.screen)}`
|
|
68134
|
+
});
|
|
67288
68135
|
return;
|
|
67289
68136
|
}
|
|
67290
68137
|
this.anomaly("send_not_accepted");
|
|
68138
|
+
this.abandonedIndex = adm.index;
|
|
67291
68139
|
this.fire("admit_abandoned");
|
|
67292
68140
|
}
|
|
67293
|
-
|
|
68141
|
+
notAcceptedLine(adm) {
|
|
68142
|
+
const secs = Math.round((Date.now() - adm.startedAt) / 1000);
|
|
68143
|
+
switch (adm.submittedUnproven) {
|
|
68144
|
+
case "maybe_submitted_by_other":
|
|
68145
|
+
return "magmux could not tell whether the prompt was submitted (the box emptied without its Enter) and no transcript record of it appeared";
|
|
68146
|
+
case "unconfirmed":
|
|
68147
|
+
return `magmux not_accepted unconfirmed: Enter was pressed with no evidence it was submitted, and no transcript record appeared in ${secs} s`;
|
|
68148
|
+
case "reply_lost": {
|
|
68149
|
+
const code = adm.last?.kind === "reply_lost" ? adm.last.code : "client_lost";
|
|
68150
|
+
return `the magmux send reply was lost (${code}) and no transcript record of the prompt appeared in ${secs} s`;
|
|
68151
|
+
}
|
|
68152
|
+
case "still_in_box_twice":
|
|
68153
|
+
return "magmux not_accepted still_in_box: the prompt stayed in the input box after Enter, twice";
|
|
68154
|
+
case null:
|
|
68155
|
+
return `prompt not accepted in ${secs} s; ${describeLastReply(adm, this.gateNow())}`;
|
|
68156
|
+
default:
|
|
68157
|
+
return assertNever(adm.submittedUnproven);
|
|
68158
|
+
}
|
|
68159
|
+
}
|
|
68160
|
+
corroborationFacts() {
|
|
67294
68161
|
if (!this.client)
|
|
67295
68162
|
return null;
|
|
67296
|
-
const
|
|
68163
|
+
const g = this.gateNow();
|
|
67297
68164
|
return {
|
|
67298
|
-
|
|
67299
|
-
|
|
67300
|
-
|
|
67301
|
-
aboveBoxQuietMs: Date.now() - this.screen.aboveBoxChangedAt
|
|
68165
|
+
gate: g ? { ready: g.ready, dialog: g.dialog, reason: g.reason } : null,
|
|
68166
|
+
working: workingAboveBox(this.screen),
|
|
68167
|
+
aboveBoxQuietMs: this.aboveBoxQuietMs()
|
|
67302
68168
|
};
|
|
67303
68169
|
}
|
|
68170
|
+
aboveBoxQuietMs() {
|
|
68171
|
+
return locateBox(this.screen) ? Date.now() - this.screen.aboveBoxChangedAt : null;
|
|
68172
|
+
}
|
|
68173
|
+
checkUnwitnessed(view) {
|
|
68174
|
+
const at = this.turnAcceptedAt;
|
|
68175
|
+
if (at === null || this.rewakeOfSettled || this.witnessed(view.current))
|
|
68176
|
+
return;
|
|
68177
|
+
const since = Date.now() - at;
|
|
68178
|
+
const missing = view.availability === "absent" || view.availability === "empty";
|
|
68179
|
+
if (view.availability === "off" || missing && since >= this.t("degradedEntryMs", DEGRADED_ENTRY_MS)) {
|
|
68180
|
+
const d = this.currentDelivery;
|
|
68181
|
+
this.turnSource = "screen";
|
|
68182
|
+
this.anomaly("degraded_mode");
|
|
68183
|
+
this.screenTurn = {
|
|
68184
|
+
echo: d && d.mode !== "refused" ? d.line : "",
|
|
68185
|
+
acceptedAt: at,
|
|
68186
|
+
errorLogSize: this.turnErrorLogSize
|
|
68187
|
+
};
|
|
68188
|
+
return;
|
|
68189
|
+
}
|
|
68190
|
+
if (view.availability === "ok" && since >= ADMIT_TIMEOUT_MS && !this.witnessMissingCounted) {
|
|
68191
|
+
this.witnessMissingCounted = true;
|
|
68192
|
+
this.anomaly("witness_missing");
|
|
68193
|
+
}
|
|
68194
|
+
}
|
|
67304
68195
|
evalRunning(view) {
|
|
68196
|
+
if (this.turnSource === "transcript")
|
|
68197
|
+
this.checkUnwitnessed(view);
|
|
67305
68198
|
if (this.turnSource === "screen") {
|
|
67306
68199
|
this.evalScreenTurn(view);
|
|
67307
68200
|
return;
|
|
@@ -67321,22 +68214,24 @@ class PaneSessionImpl {
|
|
|
67321
68214
|
if (this.detectBlocked(t))
|
|
67322
68215
|
return;
|
|
67323
68216
|
const now = Date.now();
|
|
68217
|
+
const transcriptQuietMs = now - (view.lastAppendAt ?? this.startedAtMs);
|
|
67324
68218
|
const decision = decideSettle({
|
|
67325
68219
|
turn: t,
|
|
67326
68220
|
session: view.session,
|
|
67327
|
-
transcriptQuietMs
|
|
68221
|
+
transcriptQuietMs,
|
|
67328
68222
|
chatQuietMs: now - this.lastChatSeenAt,
|
|
67329
|
-
|
|
68223
|
+
facts: this.corroborationFacts(),
|
|
67330
68224
|
paneExited: false,
|
|
67331
68225
|
secondaryQuietMs: this.secondaryQuietMs,
|
|
67332
|
-
corroborationMs: this.corroborationMs
|
|
68226
|
+
corroborationMs: this.corroborationMs,
|
|
68227
|
+
corroborationGraceMs: this.t("gateGraceMs", GATE_GRACE_MS)
|
|
67333
68228
|
});
|
|
67334
68229
|
if (decision.settled) {
|
|
67335
68230
|
this.settle(t, decision, null);
|
|
67336
68231
|
return;
|
|
67337
68232
|
}
|
|
67338
68233
|
this.activity = decision.activity;
|
|
67339
|
-
this.checkTurnEndMissing();
|
|
68234
|
+
this.checkTurnEndMissing(t, transcriptQuietMs);
|
|
67340
68235
|
this.checkAgentCountMismatch(t);
|
|
67341
68236
|
}
|
|
67342
68237
|
checkEscape() {
|
|
@@ -67347,14 +68242,14 @@ class PaneSessionImpl {
|
|
|
67347
68242
|
this.anomaly("escape_not_effective");
|
|
67348
68243
|
this.escapeSentAt = null;
|
|
67349
68244
|
}
|
|
67350
|
-
checkTurnEndMissing() {
|
|
67351
|
-
if (this.activity !== "finishing") {
|
|
68245
|
+
checkTurnEndMissing(t, transcriptQuietMs) {
|
|
68246
|
+
if (this.activity !== "finishing" || t.turnDurationAfterLast || t.interruptAfterLast) {
|
|
67352
68247
|
this.turnEndMissing = false;
|
|
67353
68248
|
return;
|
|
67354
68249
|
}
|
|
67355
68250
|
if (!this.client)
|
|
67356
68251
|
return;
|
|
67357
|
-
const quiet =
|
|
68252
|
+
const quiet = this.aboveBoxQuietMs() ?? transcriptQuietMs;
|
|
67358
68253
|
const missing = quiet >= TURN_END_MISSING_FACTOR * this.secondaryQuietMs && !stopHookRunning(this.screen);
|
|
67359
68254
|
if (missing && !this.turnEndMissing)
|
|
67360
68255
|
this.anomaly("turn_end_record_missing");
|
|
@@ -67374,14 +68269,19 @@ class PaneSessionImpl {
|
|
|
67374
68269
|
let kind = null;
|
|
67375
68270
|
if (pending.name === "AskUserQuestion")
|
|
67376
68271
|
kind = "question";
|
|
67377
|
-
else
|
|
67378
|
-
|
|
68272
|
+
else {
|
|
68273
|
+
const dialog = this.gateNow()?.dialog ?? null;
|
|
68274
|
+
if (dialog === "permission" || dialog === "plan")
|
|
68275
|
+
kind = "permission";
|
|
68276
|
+
else if (dialog === "question")
|
|
68277
|
+
kind = "question";
|
|
68278
|
+
}
|
|
67379
68279
|
if (!kind)
|
|
67380
68280
|
return false;
|
|
67381
68281
|
this.blockedToolId = pending.id;
|
|
67382
68282
|
this.fire(kind === "question" ? "blocked_question" : "blocked_permission");
|
|
67383
68283
|
this.activity = pending.name;
|
|
67384
|
-
const text = blockText3(pending,
|
|
68284
|
+
const text = blockText3(pending, this.screen.seq > 0 ? dialogText(this.screen) || null : null);
|
|
67385
68285
|
let v;
|
|
67386
68286
|
try {
|
|
67387
68287
|
v = this.o.onBlocked({ kind, tool: pending.name, text });
|
|
@@ -67394,6 +68294,16 @@ class PaneSessionImpl {
|
|
|
67394
68294
|
}
|
|
67395
68295
|
evalIdle(view) {
|
|
67396
68296
|
const t = view.current;
|
|
68297
|
+
if (t && this.abandonedIndex !== null && t.index === this.abandonedIndex && t.acceptedAt !== null && !this.exitRequested) {
|
|
68298
|
+
this.abandonedIndex = null;
|
|
68299
|
+
this.anomaly("late_witness");
|
|
68300
|
+
this.turnAcceptedAt = Date.now();
|
|
68301
|
+
this.turnErrorLogSize = this.errorLogSize();
|
|
68302
|
+
this.lastChatSeenAt = Date.now();
|
|
68303
|
+
this.fire("rewake");
|
|
68304
|
+
this.activity = "thinking";
|
|
68305
|
+
return;
|
|
68306
|
+
}
|
|
67397
68307
|
if (!t || this.settledChatOffset === null || this.exitRequested)
|
|
67398
68308
|
return;
|
|
67399
68309
|
if (t.lastChatOffset !== null && t.lastChatOffset > this.settledChatOffset) {
|
|
@@ -67472,10 +68382,10 @@ class PaneSessionImpl {
|
|
|
67472
68382
|
return !!t && t.index === this.turnIndex && t.acceptedAt !== null;
|
|
67473
68383
|
}
|
|
67474
68384
|
screenSettleReady(view, answer, apiError) {
|
|
67475
|
-
const
|
|
67476
|
-
if (!
|
|
68385
|
+
const g = this.gateNow();
|
|
68386
|
+
if (!g || !g.ready || g.dialog !== null || workingAboveBox(this.screen) === true)
|
|
67477
68387
|
return false;
|
|
67478
|
-
const quiet = Date.now() - this.screen.
|
|
68388
|
+
const quiet = this.aboveBoxQuietMs() ?? Date.now() - this.screen.changedAt;
|
|
67479
68389
|
if (view.availability === "off" && quiet >= this.secondaryQuietMs)
|
|
67480
68390
|
return true;
|
|
67481
68391
|
return (!!answer || !!apiError) && quiet >= 2 * this.t("screenSettleQuietMs", SCREEN_SETTLE_QUIET_MS);
|
|
@@ -67554,7 +68464,7 @@ class PaneSessionImpl {
|
|
|
67554
68464
|
session: view.session,
|
|
67555
68465
|
transcriptQuietMs: Number.MAX_SAFE_INTEGER,
|
|
67556
68466
|
chatQuietMs: Number.MAX_SAFE_INTEGER,
|
|
67557
|
-
|
|
68467
|
+
facts: null,
|
|
67558
68468
|
paneExited: true,
|
|
67559
68469
|
secondaryQuietMs: this.secondaryQuietMs,
|
|
67560
68470
|
corroborationMs: 0
|
|
@@ -67604,7 +68514,7 @@ ${screenTailOf(this.screen)}`
|
|
|
67604
68514
|
snapshot() {
|
|
67605
68515
|
const view = this.follower.view();
|
|
67606
68516
|
const terminal = isTerminalPhase(this.phase);
|
|
67607
|
-
const lastAct = Math.max(this.
|
|
68517
|
+
const lastAct = Math.max(this.activityChangedAt, view.lastAppendAt ?? 0);
|
|
67608
68518
|
const cur = view.current;
|
|
67609
68519
|
const hasTranscript = view.availability === "ok" && view.usage.tokensIn + view.usage.tokensOut > 0;
|
|
67610
68520
|
return {
|
|
@@ -67689,6 +68599,115 @@ ${screenTailOf(this.screen)}`
|
|
|
67689
68599
|
return { ok: false, reason: "terminal" };
|
|
67690
68600
|
return { ok: true, queued: this.queue.length };
|
|
67691
68601
|
}
|
|
68602
|
+
async resize(cols, rows) {
|
|
68603
|
+
const size = clampPaneSize(cols, rows);
|
|
68604
|
+
if (isTerminalPhase(this.phase))
|
|
68605
|
+
return this.lastSizeOutcome();
|
|
68606
|
+
if (!this.supportsResize)
|
|
68607
|
+
throw new ContractErrorException("resize_unsupported", 'this magmux has no resize op (capabilities.verbs lacks "resize"); a newer magmux is needed');
|
|
68608
|
+
if (!this.client)
|
|
68609
|
+
return this.pendingOutcome(size);
|
|
68610
|
+
if (samePaneSize(this.appliedSize, size) && samePaneSize(this.desiredSize, size) && !this.resizeDraining)
|
|
68611
|
+
return { ...size, changed: false, seq: this.screen.seq };
|
|
68612
|
+
this.desiredSize = size;
|
|
68613
|
+
return new Promise((resolve, reject) => {
|
|
68614
|
+
this.resizeWaiters.push({ resolve, reject });
|
|
68615
|
+
this.kickResize();
|
|
68616
|
+
});
|
|
68617
|
+
}
|
|
68618
|
+
pendingOutcome(size) {
|
|
68619
|
+
this.desiredSize = { ...size };
|
|
68620
|
+
return { ...size, changed: true, seq: this.screen.seq, pending: true };
|
|
68621
|
+
}
|
|
68622
|
+
lastSizeOutcome() {
|
|
68623
|
+
return { cols: this.screen.cols, rows: this.screen.rows, changed: false, seq: this.screen.seq };
|
|
68624
|
+
}
|
|
68625
|
+
inResizeQuiet(at) {
|
|
68626
|
+
return this.resizeQuietFrom > 0 && at >= this.resizeQuietFrom && at < this.resizeQuietUntil;
|
|
68627
|
+
}
|
|
68628
|
+
extendResizeQuiet() {
|
|
68629
|
+
const now = Date.now();
|
|
68630
|
+
if (now >= this.resizeQuietUntil)
|
|
68631
|
+
this.resizeQuietFrom = now;
|
|
68632
|
+
this.resizeQuietUntil = Math.max(this.resizeQuietUntil, now + RESIZE_QUIET_MS);
|
|
68633
|
+
}
|
|
68634
|
+
resizeOwed() {
|
|
68635
|
+
return !!this.client && this.supportsResize && !isTerminalPhase(this.phase) && !samePaneSize(this.appliedSize, this.desiredSize) && !samePaneSize(this.lastSentSize, this.desiredSize);
|
|
68636
|
+
}
|
|
68637
|
+
kickResize() {
|
|
68638
|
+
if (this.resizeDraining)
|
|
68639
|
+
return;
|
|
68640
|
+
this.resizeDraining = true;
|
|
68641
|
+
this.drainResize().finally(() => {
|
|
68642
|
+
this.resizeDraining = false;
|
|
68643
|
+
if (this.resizeWaiters.length > 0 || this.resizeOwed())
|
|
68644
|
+
this.kickResize();
|
|
68645
|
+
});
|
|
68646
|
+
}
|
|
68647
|
+
async drainResize() {
|
|
68648
|
+
let first = true;
|
|
68649
|
+
while (first || this.resizeWaiters.length > 0 || this.resizeOwed()) {
|
|
68650
|
+
first = false;
|
|
68651
|
+
const batch = this.resizeWaiters.splice(0);
|
|
68652
|
+
const answer = (r) => {
|
|
68653
|
+
for (const w of batch)
|
|
68654
|
+
w.resolve(r);
|
|
68655
|
+
};
|
|
68656
|
+
const fail = (e) => {
|
|
68657
|
+
for (const w of batch)
|
|
68658
|
+
w.reject(e);
|
|
68659
|
+
};
|
|
68660
|
+
if (isTerminalPhase(this.phase)) {
|
|
68661
|
+
answer(this.lastSizeOutcome());
|
|
68662
|
+
continue;
|
|
68663
|
+
}
|
|
68664
|
+
const want = { ...this.desiredSize };
|
|
68665
|
+
const c = this.client;
|
|
68666
|
+
if (!c) {
|
|
68667
|
+
answer(this.pendingOutcome(want));
|
|
68668
|
+
continue;
|
|
68669
|
+
}
|
|
68670
|
+
if (!this.supportsResize) {
|
|
68671
|
+
fail(new ContractErrorException("resize_unsupported", "this magmux has no resize op"));
|
|
68672
|
+
continue;
|
|
68673
|
+
}
|
|
68674
|
+
this.lastSentSize = want;
|
|
68675
|
+
this.extendResizeQuiet();
|
|
68676
|
+
const r = await c.request({ type: "resize", pane: 0, cols: want.cols, rows: want.rows }, RESIZE_REPLY_MS);
|
|
68677
|
+
if (isTerminalPhase(this.phase)) {
|
|
68678
|
+
answer(this.lastSizeOutcome());
|
|
68679
|
+
continue;
|
|
68680
|
+
}
|
|
68681
|
+
if (!r.ok) {
|
|
68682
|
+
if (r.code === "client_lost" || r.code === "client_timeout") {
|
|
68683
|
+
this.appliedSize = null;
|
|
68684
|
+
this.extendResizeQuiet();
|
|
68685
|
+
}
|
|
68686
|
+
if (r.code === "client_lost" || r.code === "client_closed") {
|
|
68687
|
+
answer(this.pendingOutcome(this.desiredSize));
|
|
68688
|
+
continue;
|
|
68689
|
+
}
|
|
68690
|
+
fail(new ContractErrorException("delivery_unavailable", `magmux did not resize the pane: ${r.code}${r.error ? `: ${r.error}` : ""}`));
|
|
68691
|
+
continue;
|
|
68692
|
+
}
|
|
68693
|
+
const set = {
|
|
68694
|
+
cols: typeof r.result.cols === "number" ? r.result.cols : want.cols,
|
|
68695
|
+
rows: typeof r.result.rows === "number" ? r.result.rows : want.rows
|
|
68696
|
+
};
|
|
68697
|
+
this.appliedSize = set;
|
|
68698
|
+
if (r.result.changed !== true) {
|
|
68699
|
+
answer({ ...set, changed: false, seq: this.screen.seq });
|
|
68700
|
+
continue;
|
|
68701
|
+
}
|
|
68702
|
+
this.extendResizeQuiet();
|
|
68703
|
+
await this.waitFor(() => isTerminalPhase(this.phase) || this.screen.cols === set.cols && this.screen.rows === set.rows, RESIZE_SCREEN_MS);
|
|
68704
|
+
if (isTerminalPhase(this.phase)) {
|
|
68705
|
+
answer(this.lastSizeOutcome());
|
|
68706
|
+
continue;
|
|
68707
|
+
}
|
|
68708
|
+
answer({ ...set, changed: true, seq: this.screen.seq });
|
|
68709
|
+
}
|
|
68710
|
+
}
|
|
67692
68711
|
turnAnswer(index) {
|
|
67693
68712
|
const done = this.answers.get(index);
|
|
67694
68713
|
if (done !== undefined)
|
|
@@ -67704,6 +68723,7 @@ ${screenTailOf(this.screen)}`
|
|
|
67704
68723
|
diagnostics() {
|
|
67705
68724
|
const cur = this.follower.view().current;
|
|
67706
68725
|
const rec = this.registryRec;
|
|
68726
|
+
const g = this.gate;
|
|
67707
68727
|
return {
|
|
67708
68728
|
magmuxStderr: this.stderrHead,
|
|
67709
68729
|
registry: rec ? { status: rec.status, waitingFor: rec.waitingFor, version: rec.version } : null,
|
|
@@ -67713,7 +68733,9 @@ ${screenTailOf(this.screen)}`
|
|
|
67713
68733
|
linesReturned: cur.readCoverage.linesReturned,
|
|
67714
68734
|
complete: cur.readCoverage.complete,
|
|
67715
68735
|
reads: cur.readCoverage.reads
|
|
67716
|
-
} : null
|
|
68736
|
+
} : null,
|
|
68737
|
+
gate: g && this.client ? { ready: g.ready, reason: g.reason, detail: g.detail, ageMs: Date.now() - g.receivedAt } : null,
|
|
68738
|
+
lastSend: this.lastSend ? { ...this.lastSend } : null
|
|
67717
68739
|
};
|
|
67718
68740
|
}
|
|
67719
68741
|
cancel() {
|
|
@@ -67770,6 +68792,9 @@ ${screenTailOf(this.screen)}`
|
|
|
67770
68792
|
if (this.ticker)
|
|
67771
68793
|
clearInterval(this.ticker);
|
|
67772
68794
|
this.ticker = null;
|
|
68795
|
+
if (this.gateTimer)
|
|
68796
|
+
clearInterval(this.gateTimer);
|
|
68797
|
+
this.gateTimer = null;
|
|
67773
68798
|
await this.captureGroupBeforeReap();
|
|
67774
68799
|
const c = this.client;
|
|
67775
68800
|
if (c && !c.isClosed && !this.paneClosed) {
|
|
@@ -67881,6 +68906,94 @@ function signalQuietly(target, sig) {
|
|
|
67881
68906
|
process.kill(target, sig);
|
|
67882
68907
|
} catch {}
|
|
67883
68908
|
}
|
|
68909
|
+
function launchSize(o) {
|
|
68910
|
+
return o.initialSize ? clampPaneSize(o.initialSize.cols, o.initialSize.rows) : { cols: DEFAULT_PANE_COLS, rows: DEFAULT_PANE_ROWS };
|
|
68911
|
+
}
|
|
68912
|
+
function newAdmission(a) {
|
|
68913
|
+
const now = Date.now();
|
|
68914
|
+
return {
|
|
68915
|
+
index: a.index,
|
|
68916
|
+
text: a.text,
|
|
68917
|
+
plan: a.plan,
|
|
68918
|
+
line: a.plan.line,
|
|
68919
|
+
initial: a.initial,
|
|
68920
|
+
startedAt: now,
|
|
68921
|
+
deadline: now + a.bound,
|
|
68922
|
+
step: a.plan.mode === "command" ? "type" : "submit",
|
|
68923
|
+
inFlight: false,
|
|
68924
|
+
attempts: 0,
|
|
68925
|
+
submittedUnproven: null,
|
|
68926
|
+
stuckRetried: false,
|
|
68927
|
+
panel: null,
|
|
68928
|
+
stopped: false,
|
|
68929
|
+
clearFirst: false,
|
|
68930
|
+
clearAfter: 0,
|
|
68931
|
+
lostType: null,
|
|
68932
|
+
last: null,
|
|
68933
|
+
noted: new Set
|
|
68934
|
+
};
|
|
68935
|
+
}
|
|
68936
|
+
function markClearFirst(adm) {
|
|
68937
|
+
adm.clearFirst = true;
|
|
68938
|
+
adm.clearAfter = Date.now();
|
|
68939
|
+
}
|
|
68940
|
+
function sendShape(step, line) {
|
|
68941
|
+
switch (step) {
|
|
68942
|
+
case "submit":
|
|
68943
|
+
return {
|
|
68944
|
+
msg: { type: "send", pane: 0, text: line, typed: true, enter: true },
|
|
68945
|
+
budget: { text: line, keys: 1, submit: true }
|
|
68946
|
+
};
|
|
68947
|
+
case "type":
|
|
68948
|
+
return {
|
|
68949
|
+
msg: { type: "send", pane: 0, text: line, typed: true, enter: false },
|
|
68950
|
+
budget: { text: line, keys: 0, submit: false }
|
|
68951
|
+
};
|
|
68952
|
+
case "enter":
|
|
68953
|
+
return {
|
|
68954
|
+
msg: { type: "send", pane: 0, keys: ["enter"], enter: false },
|
|
68955
|
+
budget: { text: "", keys: 1, submit: true }
|
|
68956
|
+
};
|
|
68957
|
+
default:
|
|
68958
|
+
return assertNever(step);
|
|
68959
|
+
}
|
|
68960
|
+
}
|
|
68961
|
+
function fixedSendMs(step, line) {
|
|
68962
|
+
const rt = SEND_READY_WAIT_DEFAULT_MS;
|
|
68963
|
+
return sendBudgetMs({ ...sendShape(step, line).budget, readyTimeoutMs: rt }) - rt;
|
|
68964
|
+
}
|
|
68965
|
+
function readyTimeoutFor(step, line, leftMs) {
|
|
68966
|
+
const reserve = step === "type" ? fixedSendMs("enter", line) + SEND_CLIENT_SLACK_MS + MIN_READY_TIMEOUT_MS : 0;
|
|
68967
|
+
const rt = Math.min(SEND_READY_WAIT_DEFAULT_MS, leftMs - fixedSendMs(step, line) - SEND_CLIENT_SLACK_MS - reserve);
|
|
68968
|
+
return rt < MIN_READY_TIMEOUT_MS ? null : Math.floor(rt);
|
|
68969
|
+
}
|
|
68970
|
+
function describeLastReply(adm, gate) {
|
|
68971
|
+
const o = adm.last;
|
|
68972
|
+
if (!o) {
|
|
68973
|
+
const g = gate ? gate.ready ? "ready" : gate.reason ?? "not ready" : "unknown";
|
|
68974
|
+
return adm.attempts === 0 ? `no gated send fitted before the deadline (gate: ${g})` : `no magmux reply (gate: ${g})`;
|
|
68975
|
+
}
|
|
68976
|
+
switch (o.kind) {
|
|
68977
|
+
case "busy":
|
|
68978
|
+
return `last magmux reply: busy ${o.reason || "unknown"}${o.typed ? " (typed, Enter withheld)" : ""}${gate?.detail ? ` (${gate.detail})` : ""}`;
|
|
68979
|
+
case "not_accepted":
|
|
68980
|
+
return `last magmux reply: not_accepted ${o.reason}`;
|
|
68981
|
+
case "accepted":
|
|
68982
|
+
return `last magmux reply: ok ${o.accept} (${o.evidence})`;
|
|
68983
|
+
case "in_box":
|
|
68984
|
+
return "last magmux reply: in_box (the command was typed, its Enter never sent)";
|
|
68985
|
+
case "bad_request":
|
|
68986
|
+
return `last magmux reply: bad_request ${o.error}`;
|
|
68987
|
+
case "reply_lost":
|
|
68988
|
+
case "unsent":
|
|
68989
|
+
case "pane_gone":
|
|
68990
|
+
return `last magmux reply: ${o.code}`;
|
|
68991
|
+
case "unexpected":
|
|
68992
|
+
return `last magmux reply: ${o.code}`;
|
|
68993
|
+
default:
|
|
68994
|
+
return assertNever(o);
|
|
68995
|
+
}
|
|
68996
|
+
}
|
|
67884
68997
|
function isControl(text) {
|
|
67885
68998
|
const t = text.trim();
|
|
67886
68999
|
return t === "/exit" || t === "/quit";
|
|
@@ -67900,12 +69013,18 @@ function preparePane(o, root, parentEnv) {
|
|
|
67900
69013
|
try {
|
|
67901
69014
|
const paneId = mintPaneId(o.kind, o.label);
|
|
67902
69015
|
const sockPath = sockPathFor(root, paneId);
|
|
67903
|
-
const cwd =
|
|
69016
|
+
const cwd = realpathSync4(o.cwd);
|
|
67904
69017
|
const launch = o.claudishSpawn ?? resolveClaudishLaunch(parentEnv);
|
|
67905
69018
|
dirs = createLaunchDirs(root);
|
|
67906
69019
|
const argv = buildClaudishPaneArgv(o.spawnModel, o.sessionUuid, dirs.turnDir, o.callerFlags);
|
|
67907
69020
|
writeLauncherFiles(dirs.ctlDir, launcherScript(cwd, launch, argv));
|
|
67908
|
-
const { magmuxEnv } = buildPaneEnv({
|
|
69021
|
+
const { magmuxEnv } = buildPaneEnv({
|
|
69022
|
+
parentEnv,
|
|
69023
|
+
slotEnv: o.slotEnv,
|
|
69024
|
+
cwd,
|
|
69025
|
+
ctlDir: dirs.ctlDir,
|
|
69026
|
+
...launchSize(o)
|
|
69027
|
+
});
|
|
67909
69028
|
return { paneId, sockPath, cwd, ...dirs, magmuxEnv };
|
|
67910
69029
|
} catch (e) {
|
|
67911
69030
|
for (const d of dirs ? [dirs.ctlDir, dirs.turnDir] : [])
|
|
@@ -67974,21 +69093,38 @@ async function startPaneSession(o) {
|
|
|
67974
69093
|
await session.start({ magmuxBinary: magmux.binary, env: p.magmuxEnv, cwd: p.cwd });
|
|
67975
69094
|
return session;
|
|
67976
69095
|
}
|
|
67977
|
-
var BOOT_TIMEOUT_MS = 90000, ADMIT_TIMEOUT_MS = 30000,
|
|
69096
|
+
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
69097
|
var init_pane_session = __esm(() => {
|
|
67979
69098
|
init_parent_session();
|
|
67980
69099
|
init_process_tree();
|
|
67981
69100
|
init_redact();
|
|
69101
|
+
init_box_locate();
|
|
69102
|
+
init_contract();
|
|
69103
|
+
init_gate_binding();
|
|
69104
|
+
init_input_gate();
|
|
67982
69105
|
init_magmux_client();
|
|
67983
69106
|
init_pane_launch();
|
|
67984
69107
|
init_pane_registry();
|
|
67985
69108
|
init_process_identity();
|
|
67986
69109
|
init_prompt_delivery();
|
|
67987
69110
|
init_screen_classifier();
|
|
69111
|
+
init_screen_model();
|
|
67988
69112
|
init_session_registry();
|
|
67989
69113
|
init_settle_rule();
|
|
67990
69114
|
init_slot_state();
|
|
67991
69115
|
init_transcript_follower();
|
|
69116
|
+
GATE_GRACE_MS = SECONDARY_QUIET_MS;
|
|
69117
|
+
GATE_KINDLESS_REASONS = new Set([
|
|
69118
|
+
"starting",
|
|
69119
|
+
"terminal_not_ready",
|
|
69120
|
+
"no_input_box"
|
|
69121
|
+
]);
|
|
69122
|
+
RUNTIME_DIALOG_KINDS = new Set([
|
|
69123
|
+
"permission",
|
|
69124
|
+
"question",
|
|
69125
|
+
"plan",
|
|
69126
|
+
"select"
|
|
69127
|
+
]);
|
|
67992
69128
|
EVENT_REASON = {
|
|
67993
69129
|
boot_dialog: "first_run_dialog",
|
|
67994
69130
|
boot_blocked: "boot_blocked",
|
|
@@ -68040,10 +69176,10 @@ __export(exports_session_discovery, {
|
|
|
68040
69176
|
transcriptPathFor: () => transcriptPathFor
|
|
68041
69177
|
});
|
|
68042
69178
|
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
|
|
69179
|
+
import { closeSync as closeSync9, openSync as openSync9, readSync as readSync4, readdirSync as readdirSync8, realpathSync as realpathSync5, statSync as statSync11 } from "fs";
|
|
69180
|
+
import { basename as basename3, join as join49 } from "path";
|
|
68045
69181
|
function projectsDir(env = process.env) {
|
|
68046
|
-
return
|
|
69182
|
+
return join49(claudeConfigDir(env), "projects");
|
|
68047
69183
|
}
|
|
68048
69184
|
function slugForPath(absPath) {
|
|
68049
69185
|
return projectDirNameFor(absPath);
|
|
@@ -68051,9 +69187,9 @@ function slugForPath(absPath) {
|
|
|
68051
69187
|
function transcriptPathFor(cwd, sessionUuid, projectsRoot = projectsDir()) {
|
|
68052
69188
|
let real = cwd;
|
|
68053
69189
|
try {
|
|
68054
|
-
real =
|
|
69190
|
+
real = realpathSync5(cwd);
|
|
68055
69191
|
} catch {}
|
|
68056
|
-
return
|
|
69192
|
+
return join49(projectsRoot, slugForPath(real), `${sessionUuid}.jsonl`);
|
|
68057
69193
|
}
|
|
68058
69194
|
function isAgentSession(row) {
|
|
68059
69195
|
return row.entrypoint !== undefined && row.entrypoint !== "cli";
|
|
@@ -68100,7 +69236,7 @@ function projectDirs() {
|
|
|
68100
69236
|
}
|
|
68101
69237
|
}
|
|
68102
69238
|
function sessionsIn(dirName) {
|
|
68103
|
-
const dir =
|
|
69239
|
+
const dir = join49(projectsDir(), dirName);
|
|
68104
69240
|
let names;
|
|
68105
69241
|
try {
|
|
68106
69242
|
names = readdirSync8(dir).filter((n) => n.endsWith(".jsonl"));
|
|
@@ -68109,13 +69245,13 @@ function sessionsIn(dirName) {
|
|
|
68109
69245
|
}
|
|
68110
69246
|
const rows = [];
|
|
68111
69247
|
for (const n of names) {
|
|
68112
|
-
const file =
|
|
69248
|
+
const file = join49(dir, n);
|
|
68113
69249
|
try {
|
|
68114
69250
|
const st = statSync11(file);
|
|
68115
69251
|
if (st.size === 0)
|
|
68116
69252
|
continue;
|
|
68117
69253
|
const row = {
|
|
68118
|
-
id:
|
|
69254
|
+
id: basename3(n, ".jsonl"),
|
|
68119
69255
|
file,
|
|
68120
69256
|
mtimeMs: st.mtimeMs,
|
|
68121
69257
|
birthtimeMs: st.birthtimeMs,
|
|
@@ -68217,7 +69353,7 @@ function discoverWorktreeGroups(repo) {
|
|
|
68217
69353
|
if (hit) {
|
|
68218
69354
|
path = hit.path;
|
|
68219
69355
|
live = true;
|
|
68220
|
-
name = hit.path === repo.root ? "(root)" :
|
|
69356
|
+
name = hit.path === repo.root ? "(root)" : basename3(hit.path);
|
|
68221
69357
|
} else if (at !== -1 && dir.startsWith(rootSlug)) {
|
|
68222
69358
|
path = null;
|
|
68223
69359
|
live = false;
|
|
@@ -68487,7 +69623,7 @@ var init_session_discovery = __esm(() => {
|
|
|
68487
69623
|
// src/team-orchestrator.ts
|
|
68488
69624
|
import { randomBytes as randomBytes8, randomUUID as randomUUID5 } from "crypto";
|
|
68489
69625
|
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
|
|
69626
|
+
import { basename as basename4, join as join50, resolve as resolve5 } from "path";
|
|
68491
69627
|
function slotTerminal(e) {
|
|
68492
69628
|
if (!e.session)
|
|
68493
69629
|
return true;
|
|
@@ -68524,13 +69660,13 @@ function addressRun(path, runId) {
|
|
|
68524
69660
|
pruneRuns();
|
|
68525
69661
|
if (runId) {
|
|
68526
69662
|
const run = teamRuns.get(runId) ?? null;
|
|
68527
|
-
if (run && path !== undefined &&
|
|
69663
|
+
if (run && path !== undefined && resolve5(path) !== run.path)
|
|
68528
69664
|
return null;
|
|
68529
69665
|
return run;
|
|
68530
69666
|
}
|
|
68531
69667
|
if (path === undefined)
|
|
68532
69668
|
return null;
|
|
68533
|
-
const id = newestRunByPath.get(
|
|
69669
|
+
const id = newestRunByPath.get(resolve5(path));
|
|
68534
69670
|
return id ? teamRuns.get(id) ?? null : null;
|
|
68535
69671
|
}
|
|
68536
69672
|
function activeRunAt(path) {
|
|
@@ -68556,7 +69692,7 @@ function notableAnomalies(snap) {
|
|
|
68556
69692
|
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
69693
|
}
|
|
68558
69694
|
function upstreamLogPath(path, id) {
|
|
68559
|
-
return
|
|
69695
|
+
return join50(path, "errors", `${id}-upstream.jsonl`);
|
|
68560
69696
|
}
|
|
68561
69697
|
function neverSpawnedRow(e, m) {
|
|
68562
69698
|
return {
|
|
@@ -68649,9 +69785,9 @@ function teamRunRowFromDisk(path, status) {
|
|
|
68649
69785
|
const settled = slots.length > 0 && slots.every((s) => isTerminalState(s.state));
|
|
68650
69786
|
const completions = Object.values(status.models ?? {}).map((m) => m?.completedAt ? Date.parse(m.completedAt) : Number.NaN).filter(Number.isFinite);
|
|
68651
69787
|
return {
|
|
68652
|
-
run_id: status.runId ??
|
|
69788
|
+
run_id: status.runId ?? basename4(path),
|
|
68653
69789
|
path,
|
|
68654
|
-
kind: status.kind ?? (
|
|
69790
|
+
kind: status.kind ?? (basename4(path) === "judging" ? "judge" : "run"),
|
|
68655
69791
|
started_at: status.startedAt,
|
|
68656
69792
|
finished_at: settled ? new Date(completions.length ? Math.max(...completions) : statusMtimeMs(path) ?? Date.parse(status.startedAt)).toISOString() : null,
|
|
68657
69793
|
state: settled ? "SETTLED" : "ACTIVE",
|
|
@@ -68661,14 +69797,14 @@ function teamRunRowFromDisk(path, status) {
|
|
|
68661
69797
|
}
|
|
68662
69798
|
function statusMtimeMs(path) {
|
|
68663
69799
|
try {
|
|
68664
|
-
return statSync12(
|
|
69800
|
+
return statSync12(join50(path, "status.json")).mtimeMs;
|
|
68665
69801
|
} catch {
|
|
68666
69802
|
return null;
|
|
68667
69803
|
}
|
|
68668
69804
|
}
|
|
68669
69805
|
function readManifestOrNull(path) {
|
|
68670
69806
|
try {
|
|
68671
|
-
return JSON.parse(readFileSync31(
|
|
69807
|
+
return JSON.parse(readFileSync31(join50(path, "manifest.json"), "utf-8"));
|
|
68672
69808
|
} catch {
|
|
68673
69809
|
return null;
|
|
68674
69810
|
}
|
|
@@ -68702,10 +69838,10 @@ async function cancelTeamRun(path, slot, runId) {
|
|
|
68702
69838
|
function neverSpawnedCapture() {
|
|
68703
69839
|
return {
|
|
68704
69840
|
seq: 0,
|
|
68705
|
-
cols:
|
|
68706
|
-
rows:
|
|
69841
|
+
cols: DEFAULT_PANE_COLS,
|
|
69842
|
+
rows: DEFAULT_PANE_ROWS,
|
|
68707
69843
|
cursor: { x: 0, y: 0 },
|
|
68708
|
-
lines: Array.from({ length:
|
|
69844
|
+
lines: Array.from({ length: DEFAULT_PANE_ROWS }, () => ""),
|
|
68709
69845
|
final: true
|
|
68710
69846
|
};
|
|
68711
69847
|
}
|
|
@@ -68722,6 +69858,18 @@ function captureTeamSlot(path, slot, sinceSeq, spans, runId) {
|
|
|
68722
69858
|
}
|
|
68723
69859
|
return e.session.capture(sinceSeq, { spans: spans === true });
|
|
68724
69860
|
}
|
|
69861
|
+
async function resizeTeamSlot(path, slot, cols, rows, runId) {
|
|
69862
|
+
const run = addressRun(path, runId);
|
|
69863
|
+
if (!run)
|
|
69864
|
+
throw unknownRun(path, runId);
|
|
69865
|
+
const e = run.slots.get(slot);
|
|
69866
|
+
if (!e)
|
|
69867
|
+
throw new ContractErrorException("unknown_slot", `run ${run.runId} has no slot ${JSON.stringify(slot)}`);
|
|
69868
|
+
const where = { run_id: run.runId, path: run.path, slot };
|
|
69869
|
+
if (!e.session)
|
|
69870
|
+
return { ...where, cols: DEFAULT_PANE_COLS, rows: DEFAULT_PANE_ROWS, changed: false, seq: 0 };
|
|
69871
|
+
return { ...where, ...await e.session.resize(cols, rows) };
|
|
69872
|
+
}
|
|
68725
69873
|
function teamLiveMaps(path, runId) {
|
|
68726
69874
|
const run = addressRun(path, runId);
|
|
68727
69875
|
if (!run)
|
|
@@ -68860,7 +70008,7 @@ function persistErrorLog(errorLogPath, header, sections) {
|
|
|
68860
70008
|
} catch {}
|
|
68861
70009
|
}
|
|
68862
70010
|
function validateSessionPath(sessionPath) {
|
|
68863
|
-
const resolved =
|
|
70011
|
+
const resolved = resolve5(sessionPath);
|
|
68864
70012
|
const cwd = process.cwd();
|
|
68865
70013
|
if (!resolved.startsWith(`${cwd}/`) && resolved !== cwd) {
|
|
68866
70014
|
throw new Error(`Session path must be within current directory: ${sessionPath}`);
|
|
@@ -68868,7 +70016,7 @@ function validateSessionPath(sessionPath) {
|
|
|
68868
70016
|
return resolved;
|
|
68869
70017
|
}
|
|
68870
70018
|
function readTeamInputFile(inputPath) {
|
|
68871
|
-
const resolved =
|
|
70019
|
+
const resolved = resolve5(inputPath);
|
|
68872
70020
|
const cwd = process.cwd();
|
|
68873
70021
|
if (!resolved.startsWith(`${cwd}/`) && resolved !== cwd) {
|
|
68874
70022
|
throw new Error(`Input file must be within current directory: ${inputPath}`);
|
|
@@ -68886,14 +70034,14 @@ function setupSession(sessionPath, models, input) {
|
|
|
68886
70034
|
if (models.length === 0) {
|
|
68887
70035
|
throw new Error("At least one model is required");
|
|
68888
70036
|
}
|
|
68889
|
-
if (existsSync31(
|
|
70037
|
+
if (existsSync31(join50(sessionPath, "manifest.json"))) {
|
|
68890
70038
|
throw new Error(`Session already exists at ${sessionPath}. Use a new directory path or delete the existing session first.`);
|
|
68891
70039
|
}
|
|
68892
|
-
mkdirSync21(
|
|
68893
|
-
mkdirSync21(
|
|
70040
|
+
mkdirSync21(join50(sessionPath, "work"), { recursive: true });
|
|
70041
|
+
mkdirSync21(join50(sessionPath, "errors"), { recursive: true });
|
|
68894
70042
|
if (input !== undefined) {
|
|
68895
|
-
writeFileSync22(
|
|
68896
|
-
} else if (!existsSync31(
|
|
70043
|
+
writeFileSync22(join50(sessionPath, "input.md"), input, "utf-8");
|
|
70044
|
+
} else if (!existsSync31(join50(sessionPath, "input.md"))) {
|
|
68897
70045
|
throw new Error(`No input.md found at ${sessionPath} and no input provided`);
|
|
68898
70046
|
}
|
|
68899
70047
|
const ids = models.map((_, i) => String(i + 1).padStart(2, "0"));
|
|
@@ -68910,9 +70058,9 @@ function setupSession(sessionPath, models, input) {
|
|
|
68910
70058
|
model: models[i],
|
|
68911
70059
|
assignedAt: now
|
|
68912
70060
|
};
|
|
68913
|
-
mkdirSync21(
|
|
70061
|
+
mkdirSync21(join50(sessionPath, "work", anonId), { recursive: true });
|
|
68914
70062
|
}
|
|
68915
|
-
writeFileSync22(
|
|
70063
|
+
writeFileSync22(join50(sessionPath, "manifest.json"), JSON.stringify(manifest, null, 2), "utf-8");
|
|
68916
70064
|
const status = {
|
|
68917
70065
|
startedAt: now,
|
|
68918
70066
|
models: Object.fromEntries(Object.keys(manifest.models).map((id) => [
|
|
@@ -68927,7 +70075,7 @@ function setupSession(sessionPath, models, input) {
|
|
|
68927
70075
|
}
|
|
68928
70076
|
]))
|
|
68929
70077
|
};
|
|
68930
|
-
writeFileSync22(
|
|
70078
|
+
writeFileSync22(join50(sessionPath, "status.json"), JSON.stringify(status, null, 2), "utf-8");
|
|
68931
70079
|
return manifest;
|
|
68932
70080
|
}
|
|
68933
70081
|
function assertValidRequirePattern(pattern) {
|
|
@@ -68955,14 +70103,14 @@ async function preflightTeamRun(opts) {
|
|
|
68955
70103
|
throw new Error(`invalid_args: ${refusal}`);
|
|
68956
70104
|
}
|
|
68957
70105
|
await assertMagmuxAvailable();
|
|
68958
|
-
assertNoActiveRun(
|
|
70106
|
+
assertNoActiveRun(resolve5(opts.path));
|
|
68959
70107
|
const root = sockRootFor(opts.parentEnv ?? process.env);
|
|
68960
70108
|
const live = livePaneCount(root);
|
|
68961
70109
|
if (live + opts.slots > MAX_LIVE_PANES)
|
|
68962
70110
|
throw new Error(`pane_limit: ${live} live panes for this user, ${opts.slots} more would exceed ${MAX_LIVE_PANES}`);
|
|
68963
70111
|
}
|
|
68964
70112
|
function mintRunId(path, startMs) {
|
|
68965
|
-
return `${
|
|
70113
|
+
return `${basename4(path)}-${startMs.toString(36)}-${randomBytes8(3).toString("hex")}`;
|
|
68966
70114
|
}
|
|
68967
70115
|
function startModels(sessionPath, opts = {}) {
|
|
68968
70116
|
const flight = { aborted: false };
|
|
@@ -68986,10 +70134,10 @@ async function startModelsIn(flight, sessionPath, opts) {
|
|
|
68986
70134
|
const flagCheck = checkChildFlags(claudeFlags);
|
|
68987
70135
|
if (!flagCheck.ok)
|
|
68988
70136
|
throw new Error(`invalid_args: ${flagCheck.message}`);
|
|
68989
|
-
const path =
|
|
68990
|
-
const manifest = JSON.parse(readFileSync31(
|
|
68991
|
-
const statusPath =
|
|
68992
|
-
const inputContent = readFileSync31(
|
|
70137
|
+
const path = resolve5(sessionPath);
|
|
70138
|
+
const manifest = JSON.parse(readFileSync31(join50(path, "manifest.json"), "utf-8"));
|
|
70139
|
+
const statusPath = join50(path, "status.json");
|
|
70140
|
+
const inputContent = readFileSync31(join50(path, "input.md"), "utf-8");
|
|
68993
70141
|
const readAvailable = !flagsRemoveRead(claudeFlags);
|
|
68994
70142
|
const refusal = deliveryRefusal(inputContent, readAvailable);
|
|
68995
70143
|
if (refusal)
|
|
@@ -69027,13 +70175,13 @@ async function startModelsIn(flight, sessionPath, opts) {
|
|
|
69027
70175
|
mkdirSync21(statsDir(path), { recursive: true });
|
|
69028
70176
|
const entries = new Map;
|
|
69029
70177
|
let run = null;
|
|
69030
|
-
const errorLogPathOf = (id) =>
|
|
70178
|
+
const errorLogPathOf = (id) => join50(path, "errors", `${id}.log`);
|
|
69031
70179
|
const upstreamLogOf = (id) => upstreamLogPath(path, id);
|
|
69032
70180
|
const commandOf = (e) => ["claudish", "-i", "--model", e.spawnModel ?? e.model, "-y", "--quiet", ...claudeFlags].join(" ");
|
|
69033
70181
|
function writeResponse(e, text) {
|
|
69034
70182
|
e.answer = text;
|
|
69035
70183
|
try {
|
|
69036
|
-
writeFileSync22(
|
|
70184
|
+
writeFileSync22(join50(path, `response-${e.id}.md`), text, "utf-8");
|
|
69037
70185
|
} catch (err) {
|
|
69038
70186
|
persistErrorLog(errorLogPathOf(e.id), `response file not written: ${String(err)}`, []);
|
|
69039
70187
|
}
|
|
@@ -69350,7 +70498,7 @@ async function startModelsIn(flight, sessionPath, opts) {
|
|
|
69350
70498
|
done.catch(() => {});
|
|
69351
70499
|
return {
|
|
69352
70500
|
runId,
|
|
69353
|
-
teamSessionId:
|
|
70501
|
+
teamSessionId: basename4(path),
|
|
69354
70502
|
sessionPath: path,
|
|
69355
70503
|
slots: Object.fromEntries(Object.entries(manifest.models).map(([anonId, entry]) => [entry.model, anonId])),
|
|
69356
70504
|
done
|
|
@@ -69361,9 +70509,9 @@ async function runModels(sessionPath, opts = {}) {
|
|
|
69361
70509
|
return handle.done;
|
|
69362
70510
|
}
|
|
69363
70511
|
async function judgeResponses(sessionPath, opts = {}) {
|
|
69364
|
-
const active = activeRunAt(
|
|
70512
|
+
const active = activeRunAt(resolve5(sessionPath));
|
|
69365
70513
|
if (active)
|
|
69366
|
-
throw new Error(`invalid_args: the team run at ${
|
|
70514
|
+
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
70515
|
const responseFiles = readdirSync9(sessionPath).filter((f) => f.startsWith("response-") && f.endsWith(".md")).sort();
|
|
69368
70516
|
if (responseFiles.length < 2) {
|
|
69369
70517
|
throw new Error(`Need at least 2 responses to judge, found ${responseFiles.length}`);
|
|
@@ -69371,13 +70519,13 @@ async function judgeResponses(sessionPath, opts = {}) {
|
|
|
69371
70519
|
const responses = {};
|
|
69372
70520
|
for (const file of responseFiles) {
|
|
69373
70521
|
const id = file.replace(/^response-/, "").replace(/\.md$/, "");
|
|
69374
|
-
responses[id] = readFileSync31(
|
|
70522
|
+
responses[id] = readFileSync31(join50(sessionPath, file), "utf-8");
|
|
69375
70523
|
}
|
|
69376
|
-
const input = readFileSync31(
|
|
70524
|
+
const input = readFileSync31(join50(sessionPath, "input.md"), "utf-8");
|
|
69377
70525
|
const judgePrompt = buildJudgePrompt(input, responses);
|
|
69378
|
-
writeFileSync22(
|
|
70526
|
+
writeFileSync22(join50(sessionPath, "judge-prompt.md"), judgePrompt, "utf-8");
|
|
69379
70527
|
const judgeModels = opts.judges ?? getDefaultJudgeModels(sessionPath);
|
|
69380
|
-
const judgePath =
|
|
70528
|
+
const judgePath = join50(sessionPath, "judging");
|
|
69381
70529
|
mkdirSync21(judgePath, { recursive: true });
|
|
69382
70530
|
setupSession(judgePath, judgeModels, judgePrompt);
|
|
69383
70531
|
await runModels(judgePath, {
|
|
@@ -69388,11 +70536,11 @@ async function judgeResponses(sessionPath, opts = {}) {
|
|
|
69388
70536
|
});
|
|
69389
70537
|
const votes = parseJudgeVotes(judgePath, Object.keys(responses));
|
|
69390
70538
|
const verdict = aggregateVerdict(votes, Object.keys(responses));
|
|
69391
|
-
writeFileSync22(
|
|
70539
|
+
writeFileSync22(join50(sessionPath, "verdict.md"), formatVerdict(verdict, sessionPath), "utf-8");
|
|
69392
70540
|
return verdict;
|
|
69393
70541
|
}
|
|
69394
70542
|
function getStatus(sessionPath) {
|
|
69395
|
-
return JSON.parse(readFileSync31(
|
|
70543
|
+
return JSON.parse(readFileSync31(join50(sessionPath, "status.json"), "utf-8"));
|
|
69396
70544
|
}
|
|
69397
70545
|
function readTeamStatus(sessionPath) {
|
|
69398
70546
|
try {
|
|
@@ -69428,7 +70576,7 @@ function fisherYatesShuffle(arr) {
|
|
|
69428
70576
|
return arr;
|
|
69429
70577
|
}
|
|
69430
70578
|
function getDefaultJudgeModels(sessionPath) {
|
|
69431
|
-
const manifest = JSON.parse(readFileSync31(
|
|
70579
|
+
const manifest = JSON.parse(readFileSync31(join50(sessionPath, "manifest.json"), "utf-8"));
|
|
69432
70580
|
return Object.values(manifest.models).map((e) => e.model);
|
|
69433
70581
|
}
|
|
69434
70582
|
function buildJudgePrompt(input, responses) {
|
|
@@ -69491,7 +70639,7 @@ function parseJudgeVotes(judgePath, responseIds) {
|
|
|
69491
70639
|
const judgeId = file.replace(/^response-/, "").replace(/\.md$/, "");
|
|
69492
70640
|
let content;
|
|
69493
70641
|
try {
|
|
69494
|
-
content = readFileSync31(
|
|
70642
|
+
content = readFileSync31(join50(judgePath, file), "utf-8");
|
|
69495
70643
|
} catch {
|
|
69496
70644
|
continue;
|
|
69497
70645
|
}
|
|
@@ -69543,7 +70691,7 @@ function aggregateVerdict(votes, responseIds) {
|
|
|
69543
70691
|
function formatVerdict(verdict, sessionPath) {
|
|
69544
70692
|
let manifest = null;
|
|
69545
70693
|
try {
|
|
69546
|
-
manifest = JSON.parse(readFileSync31(
|
|
70694
|
+
manifest = JSON.parse(readFileSync31(join50(sessionPath, "manifest.json"), "utf-8"));
|
|
69547
70695
|
} catch {}
|
|
69548
70696
|
let output = `# Team Verdict
|
|
69549
70697
|
|
|
@@ -69605,7 +70753,7 @@ import {
|
|
|
69605
70753
|
statSync as statSync13,
|
|
69606
70754
|
writeFileSync as writeFileSync23
|
|
69607
70755
|
} from "fs";
|
|
69608
|
-
import { join as
|
|
70756
|
+
import { join as join51, resolve as resolve6, sep } from "path";
|
|
69609
70757
|
function normaliseTimeoutSeconds(raw) {
|
|
69610
70758
|
const n = typeof raw === "string" && raw.trim() !== "" ? Number(raw) : raw;
|
|
69611
70759
|
if (typeof n !== "number" || !Number.isFinite(n))
|
|
@@ -69771,7 +70919,7 @@ function dropLeadingFragment(tail) {
|
|
|
69771
70919
|
return firstBreak === -1 ? tail.text : tail.text.slice(firstBreak + 1);
|
|
69772
70920
|
}
|
|
69773
70921
|
function diskAccounting(sessionDir) {
|
|
69774
|
-
const stats = readTokenStatsAt(
|
|
70922
|
+
const stats = readTokenStatsAt(join51(sessionDir, "tokens.json"));
|
|
69775
70923
|
return {
|
|
69776
70924
|
tokensIn: stats?.billed_input_tokens ?? null,
|
|
69777
70925
|
tokensOut: stats?.output_tokens ?? null,
|
|
@@ -69794,10 +70942,10 @@ function diskProseBytes(tail, fileBytes) {
|
|
|
69794
70942
|
function blankFinalCapture() {
|
|
69795
70943
|
return {
|
|
69796
70944
|
seq: 0,
|
|
69797
|
-
cols:
|
|
69798
|
-
rows:
|
|
70945
|
+
cols: DEFAULT_PANE_COLS,
|
|
70946
|
+
rows: DEFAULT_PANE_ROWS,
|
|
69799
70947
|
cursor: { x: 0, y: 0 },
|
|
69800
|
-
lines: Array.from({ length:
|
|
70948
|
+
lines: Array.from({ length: DEFAULT_PANE_ROWS }, () => ""),
|
|
69801
70949
|
final: true
|
|
69802
70950
|
};
|
|
69803
70951
|
}
|
|
@@ -69842,7 +70990,7 @@ class SessionManager {
|
|
|
69842
70990
|
let dir = "";
|
|
69843
70991
|
for (let attempt = 0;; attempt++) {
|
|
69844
70992
|
id = `team-${randomUUID6().replace(/-/g, "").slice(0, 8)}`;
|
|
69845
|
-
dir =
|
|
70993
|
+
dir = join51(this.sessionsDir, id);
|
|
69846
70994
|
try {
|
|
69847
70995
|
mkdirSync22(dir);
|
|
69848
70996
|
break;
|
|
@@ -69857,7 +71005,7 @@ class SessionManager {
|
|
|
69857
71005
|
sessionId: id,
|
|
69858
71006
|
parentClaudeSessionId: opts.parentClaudeSessionId,
|
|
69859
71007
|
startedAt,
|
|
69860
|
-
teamPath:
|
|
71008
|
+
teamPath: resolve6(opts.teamPath),
|
|
69861
71009
|
slots: opts.slots
|
|
69862
71010
|
});
|
|
69863
71011
|
this.teamRunStarts.set(id, startedAt);
|
|
@@ -69874,9 +71022,9 @@ class SessionManager {
|
|
|
69874
71022
|
if (dir === null)
|
|
69875
71023
|
throw new Error("not a record id");
|
|
69876
71024
|
const completedAt = new Date().toISOString();
|
|
69877
|
-
const startedAt = this.teamRunStarts.get(record) ?? metaString(readJsonObject(
|
|
71025
|
+
const startedAt = this.teamRunStarts.get(record) ?? metaString(readJsonObject(join51(dir, "spawn.json"), META_READ_LIMIT)?.startedAt) ?? completedAt;
|
|
69878
71026
|
const elapsedMs = Date.parse(completedAt) - Date.parse(startedAt);
|
|
69879
|
-
writeJsonAtomic(
|
|
71027
|
+
writeJsonAtomic(join51(dir, "meta.json"), {
|
|
69880
71028
|
kind: "team",
|
|
69881
71029
|
status: outcome.status,
|
|
69882
71030
|
startedAt,
|
|
@@ -69908,7 +71056,7 @@ class SessionManager {
|
|
|
69908
71056
|
startedAt,
|
|
69909
71057
|
...rest
|
|
69910
71058
|
};
|
|
69911
|
-
writeJsonAtomic(
|
|
71059
|
+
writeJsonAtomic(join51(dir, "spawn.json"), body);
|
|
69912
71060
|
}
|
|
69913
71061
|
async createSession(opts) {
|
|
69914
71062
|
if (this.activeSessions + this.starting >= this.maxSessions) {
|
|
@@ -69967,10 +71115,10 @@ class SessionManager {
|
|
|
69967
71115
|
const claudeSessionId = randomUUID6();
|
|
69968
71116
|
const timeout = normaliseTimeoutSeconds(opts.timeoutSeconds);
|
|
69969
71117
|
const startedAt = new Date().toISOString();
|
|
69970
|
-
const sessionDir = opts.sessionDir ??
|
|
71118
|
+
const sessionDir = opts.sessionDir ?? join51(this.sessionsDir, sessionId);
|
|
69971
71119
|
mkdirSync22(sessionDir, { recursive: true });
|
|
69972
71120
|
if (opts.prompt)
|
|
69973
|
-
writeFileSync23(
|
|
71121
|
+
writeFileSync23(join51(sessionDir, "prompt.md"), opts.prompt, "utf-8");
|
|
69974
71122
|
this.writeSpawnRecord(sessionDir, {
|
|
69975
71123
|
kind: "session",
|
|
69976
71124
|
sessionId,
|
|
@@ -69983,7 +71131,7 @@ class SessionManager {
|
|
|
69983
71131
|
const cwd = opts.cwd ?? process.cwd();
|
|
69984
71132
|
const parentEnv = opts.parentEnv ?? this.parentEnv;
|
|
69985
71133
|
const spawnModel = opts.spawnModel ?? null;
|
|
69986
|
-
const tokenFile = opts.tokenFile ??
|
|
71134
|
+
const tokenFile = opts.tokenFile ?? join51(sessionDir, "tokens.json");
|
|
69987
71135
|
return {
|
|
69988
71136
|
info: {
|
|
69989
71137
|
sessionId,
|
|
@@ -70019,28 +71167,30 @@ class SessionManager {
|
|
|
70019
71167
|
},
|
|
70020
71168
|
session: null,
|
|
70021
71169
|
scrollback: new ScrollbackBuffer(this.scrollbackCapacity),
|
|
70022
|
-
outputLogStream: createWriteStream(
|
|
71170
|
+
outputLogStream: createWriteStream(join51(sessionDir, "output.log")),
|
|
70023
71171
|
sessionDir,
|
|
70024
71172
|
cwd,
|
|
70025
71173
|
tokenFile,
|
|
70026
|
-
eventLogPath:
|
|
71174
|
+
eventLogPath: join51(sessionDir, "events.jsonl"),
|
|
70027
71175
|
eventLogBytes: 0,
|
|
70028
|
-
upstreamErrorLogPath:
|
|
71176
|
+
upstreamErrorLogPath: join51(sessionDir, "upstream-errors.jsonl"),
|
|
70029
71177
|
eventRing: [],
|
|
70030
71178
|
proseBytes: 0,
|
|
70031
71179
|
answeredTurns: new Map,
|
|
70032
|
-
waitLogPath:
|
|
71180
|
+
waitLogPath: join51(sessionDir, "waits.jsonl"),
|
|
70033
71181
|
waitLogBytes: 0,
|
|
70034
71182
|
waitSince: null,
|
|
70035
71183
|
ended: false,
|
|
70036
71184
|
evictHandle: null,
|
|
70037
71185
|
lastLoggedTool: null,
|
|
70038
71186
|
assistantIdsLogged: 0,
|
|
70039
|
-
anomaliesLogged: new Set
|
|
71187
|
+
anomaliesLogged: new Set,
|
|
71188
|
+
requestedSize: null
|
|
70040
71189
|
};
|
|
70041
71190
|
}
|
|
70042
71191
|
async startPane(entry, opts, p) {
|
|
70043
71192
|
const info = entry.info;
|
|
71193
|
+
const launch = entry.requestedSize;
|
|
70044
71194
|
const paneOpts = {
|
|
70045
71195
|
kind: "s",
|
|
70046
71196
|
label: info.sessionId,
|
|
@@ -70055,6 +71205,7 @@ class SessionManager {
|
|
|
70055
71205
|
},
|
|
70056
71206
|
shape: info.shape,
|
|
70057
71207
|
...opts.prompt ? { initialPrompt: opts.prompt } : {},
|
|
71208
|
+
...launch ? { initialSize: launch } : {},
|
|
70058
71209
|
readAvailable: p.readAvailable,
|
|
70059
71210
|
decide: (turn) => this.decide(entry, turn),
|
|
70060
71211
|
onBlocked: (b) => this.onBlocked(entry, b),
|
|
@@ -70070,6 +71221,12 @@ class SessionManager {
|
|
|
70070
71221
|
this.failNeverSpawned(entry, err);
|
|
70071
71222
|
throw err;
|
|
70072
71223
|
}
|
|
71224
|
+
const asked = entry.requestedSize;
|
|
71225
|
+
entry.requestedSize = null;
|
|
71226
|
+
if (asked && (asked.cols !== launch?.cols || asked.rows !== launch?.rows))
|
|
71227
|
+
entry.session.resize(asked.cols, asked.rows).catch(() => {
|
|
71228
|
+
return;
|
|
71229
|
+
});
|
|
70073
71230
|
if (!entry.ended)
|
|
70074
71231
|
this.applySnapshot(entry, entry.session.snapshot());
|
|
70075
71232
|
}
|
|
@@ -70163,7 +71320,7 @@ class SessionManager {
|
|
|
70163
71320
|
try {
|
|
70164
71321
|
const text = screenLines.join(`
|
|
70165
71322
|
`).replace(/\s+$/, "");
|
|
70166
|
-
writeFileSync23(
|
|
71323
|
+
writeFileSync23(join51(entry.sessionDir, "screen.txt"), `${redactSecrets2(text)}
|
|
70167
71324
|
`, "utf-8");
|
|
70168
71325
|
} catch {}
|
|
70169
71326
|
}
|
|
@@ -70177,7 +71334,7 @@ class SessionManager {
|
|
|
70177
71334
|
entry.waitSince = null;
|
|
70178
71335
|
}
|
|
70179
71336
|
try {
|
|
70180
|
-
writeJsonAtomic(
|
|
71337
|
+
writeJsonAtomic(join51(entry.sessionDir, "meta.json"), toMetaRecord(entry.info, entry.cwd));
|
|
70181
71338
|
} catch (err) {
|
|
70182
71339
|
process.stderr.write(`[claudish] session ${entry.info.sessionId}: could not write meta.json: ` + `${err instanceof Error ? err.message : String(err)}
|
|
70183
71340
|
`);
|
|
@@ -70321,6 +71478,8 @@ class SessionManager {
|
|
|
70321
71478
|
registry: null,
|
|
70322
71479
|
preambleBytes: 0,
|
|
70323
71480
|
readCoverage: null,
|
|
71481
|
+
gate: null,
|
|
71482
|
+
lastSend: null,
|
|
70324
71483
|
claudeCodeVersion: null,
|
|
70325
71484
|
anomalies: entry.info.detail ? [entry.info.detail] : []
|
|
70326
71485
|
};
|
|
@@ -70335,6 +71494,8 @@ class SessionManager {
|
|
|
70335
71494
|
registry: pane.registry,
|
|
70336
71495
|
preambleBytes: pane.preambleBytes,
|
|
70337
71496
|
readCoverage: pane.readCoverage,
|
|
71497
|
+
gate: pane.gate,
|
|
71498
|
+
lastSend: pane.lastSend,
|
|
70338
71499
|
claudeCodeVersion: snap.claudeCodeVersion,
|
|
70339
71500
|
anomalies: snap.anomalies
|
|
70340
71501
|
};
|
|
@@ -70348,6 +71509,26 @@ class SessionManager {
|
|
|
70348
71509
|
const r = entry.session.cancel();
|
|
70349
71510
|
return { session_id: sessionId, state: r.state, changed: r.changed };
|
|
70350
71511
|
}
|
|
71512
|
+
async resizeSession(sessionId, cols, rows) {
|
|
71513
|
+
const entry = this.liveEntry(sessionId);
|
|
71514
|
+
if (!entry)
|
|
71515
|
+
throw unknownSession(sessionId);
|
|
71516
|
+
if (!entry.session) {
|
|
71517
|
+
if (isTerminalState(entry.info.state))
|
|
71518
|
+
return {
|
|
71519
|
+
session_id: sessionId,
|
|
71520
|
+
cols: DEFAULT_PANE_COLS,
|
|
71521
|
+
rows: DEFAULT_PANE_ROWS,
|
|
71522
|
+
changed: false,
|
|
71523
|
+
seq: 0
|
|
71524
|
+
};
|
|
71525
|
+
const size = clampPaneSize(cols, rows);
|
|
71526
|
+
entry.requestedSize = size;
|
|
71527
|
+
return { session_id: sessionId, ...size, changed: true, seq: 0, pending: true };
|
|
71528
|
+
}
|
|
71529
|
+
const r = await entry.session.resize(cols, rows);
|
|
71530
|
+
return { session_id: sessionId, ...r };
|
|
71531
|
+
}
|
|
70351
71532
|
captureSession(sessionId, sinceSeq, spans) {
|
|
70352
71533
|
const entry = this.liveEntry(sessionId);
|
|
70353
71534
|
if (!entry)
|
|
@@ -70411,9 +71592,9 @@ class SessionManager {
|
|
|
70411
71592
|
diskSessionDir(sessionId) {
|
|
70412
71593
|
if (!SESSION_ID_RE.test(sessionId))
|
|
70413
71594
|
return null;
|
|
70414
|
-
const root =
|
|
70415
|
-
const dir =
|
|
70416
|
-
if (dir !==
|
|
71595
|
+
const root = resolve6(this.sessionsDir);
|
|
71596
|
+
const dir = resolve6(root, sessionId);
|
|
71597
|
+
if (dir !== join51(root, sessionId))
|
|
70417
71598
|
return null;
|
|
70418
71599
|
if (!dir.startsWith(root + sep))
|
|
70419
71600
|
return null;
|
|
@@ -70432,10 +71613,10 @@ class SessionManager {
|
|
|
70432
71613
|
} catch {
|
|
70433
71614
|
return null;
|
|
70434
71615
|
}
|
|
70435
|
-
const spawnRecord = readJsonObject(
|
|
71616
|
+
const spawnRecord = readJsonObject(join51(sessionDir, "spawn.json"), META_READ_LIMIT);
|
|
70436
71617
|
if (spawnRecord?.kind === "team")
|
|
70437
71618
|
return null;
|
|
70438
|
-
const meta = readJsonObject(
|
|
71619
|
+
const meta = readJsonObject(join51(sessionDir, "meta.json"), META_READ_LIMIT);
|
|
70439
71620
|
if (meta?.kind === "team")
|
|
70440
71621
|
return null;
|
|
70441
71622
|
const partial = meta === null;
|
|
@@ -70457,7 +71638,7 @@ class SessionManager {
|
|
|
70457
71638
|
return stored;
|
|
70458
71639
|
}
|
|
70459
71640
|
diskOutput(record, tailLines) {
|
|
70460
|
-
const tail = readTailText(
|
|
71641
|
+
const tail = readTailText(join51(record.sessionDir, "output.log"), OUTPUT_TAIL_BYTES);
|
|
70461
71642
|
const buffer = new ScrollbackBuffer(this.scrollbackCapacity);
|
|
70462
71643
|
if (tail?.text)
|
|
70463
71644
|
buffer.append(dropLeadingFragment(tail));
|
|
@@ -70477,12 +71658,12 @@ class SessionManager {
|
|
|
70477
71658
|
}
|
|
70478
71659
|
diskDiagnostics(record, limit) {
|
|
70479
71660
|
const { sessionDir, info } = record;
|
|
70480
|
-
const eventLogPath =
|
|
70481
|
-
const upstreamErrorLogPath =
|
|
70482
|
-
const outputLogPath =
|
|
71661
|
+
const eventLogPath = join51(sessionDir, "events.jsonl");
|
|
71662
|
+
const upstreamErrorLogPath = join51(sessionDir, "upstream-errors.jsonl");
|
|
71663
|
+
const outputLogPath = join51(sessionDir, "output.log");
|
|
70483
71664
|
const events = readTailLines2(eventLogPath, EVENT_TAIL_BYTES);
|
|
70484
71665
|
const outputTail = readTailText(outputLogPath, OUTPUT_TAIL_BYTES);
|
|
70485
|
-
const screen = readTailText(
|
|
71666
|
+
const screen = readTailText(join51(sessionDir, "screen.txt"), SCREEN_READ_BYTES);
|
|
70486
71667
|
return {
|
|
70487
71668
|
sessionId: info.sessionId,
|
|
70488
71669
|
state: info.state,
|
|
@@ -70515,6 +71696,8 @@ class SessionManager {
|
|
|
70515
71696
|
turnSource: info.turnSource,
|
|
70516
71697
|
preambleBytes: 0,
|
|
70517
71698
|
readCoverage: null,
|
|
71699
|
+
gate: null,
|
|
71700
|
+
lastSend: null,
|
|
70518
71701
|
claudeCodeVersion: null,
|
|
70519
71702
|
anomalies: record.partial ? [
|
|
70520
71703
|
`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 +72050,7 @@ var init_progress_heartbeat = __esm(() => {
|
|
|
70867
72050
|
import { spawn as spawn2 } from "child_process";
|
|
70868
72051
|
import { mkdirSync as mkdirSync23, mkdtempSync as mkdtempSync3, rmSync as rmSync7, writeFileSync as writeFileSync24 } from "fs";
|
|
70869
72052
|
import { tmpdir as tmpdir2 } from "os";
|
|
70870
|
-
import { join as
|
|
72053
|
+
import { join as join52 } from "path";
|
|
70871
72054
|
function claudeCodePrintArgv(model, systemPromptFile) {
|
|
70872
72055
|
const head = [PRINT_FLAGS[0], "--model", model, ...PRINT_FLAGS.slice(1)];
|
|
70873
72056
|
return systemPromptFile !== undefined ? [...head, "--system-prompt-file", systemPromptFile] : [...head, "--system-prompt", ""];
|
|
@@ -70985,13 +72168,13 @@ async function runPromptViaClaudeCode(model, prompt, systemPrompt, opts = {}) {
|
|
|
70985
72168
|
} catch (e) {
|
|
70986
72169
|
throw new Error(`cannot start claudish (${parentEnv.CLAUDISH_BIN?.trim() || "claudish"}): ${e instanceof Error ? e.message : String(e)}`);
|
|
70987
72170
|
}
|
|
70988
|
-
const root = mkdtempSync3(
|
|
72171
|
+
const root = mkdtempSync3(join52(tmpdir2(), "claudish-run-prompt-"));
|
|
70989
72172
|
try {
|
|
70990
|
-
const cwd =
|
|
72173
|
+
const cwd = join52(root, "cwd");
|
|
70991
72174
|
mkdirSync23(cwd, { mode: 448 });
|
|
70992
72175
|
let systemPromptFile;
|
|
70993
72176
|
if (typeof systemPrompt === "string" && systemPrompt.length > 0) {
|
|
70994
|
-
systemPromptFile =
|
|
72177
|
+
systemPromptFile = join52(root, "system-prompt.txt");
|
|
70995
72178
|
writeFileSync24(systemPromptFile, systemPrompt, { mode: 384 });
|
|
70996
72179
|
}
|
|
70997
72180
|
const argv = claudeCodePrintArgv(model, systemPromptFile);
|
|
@@ -71099,7 +72282,7 @@ var init_run_prompt_claude_code = __esm(() => {
|
|
|
71099
72282
|
// src/mcp-server.ts
|
|
71100
72283
|
import { existsSync as existsSync33, mkdirSync as mkdirSync24, readFileSync as readFileSync33, readdirSync as readdirSync10, writeFileSync as writeFileSync25 } from "fs";
|
|
71101
72284
|
import { homedir as homedir35 } from "os";
|
|
71102
|
-
import { dirname as
|
|
72285
|
+
import { dirname as dirname15, join as join53, resolve as resolve7 } from "path";
|
|
71103
72286
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
71104
72287
|
async function loadAllModels(forceRefresh = false) {
|
|
71105
72288
|
if (!forceRefresh && existsSync33(OPENROUTER_MODELS_CACHE_PATH)) {
|
|
@@ -71394,6 +72577,12 @@ function optionalInteger(raw, name) {
|
|
|
71394
72577
|
throw new ContractErrorException("invalid_args", `'${name}' must be an integer`);
|
|
71395
72578
|
return raw;
|
|
71396
72579
|
}
|
|
72580
|
+
function requiredInteger(raw, name, mode) {
|
|
72581
|
+
const n = optionalInteger(raw, name);
|
|
72582
|
+
if (n === undefined)
|
|
72583
|
+
throw new ContractErrorException("invalid_args", `'${name}' is required${mode ? ` for mode '${mode}'` : ""}`);
|
|
72584
|
+
return n;
|
|
72585
|
+
}
|
|
71397
72586
|
function teamStatusAnswer(path, runId) {
|
|
71398
72587
|
let row = null;
|
|
71399
72588
|
if (runId) {
|
|
@@ -71433,6 +72622,8 @@ async function teamContractVerb(mode, args) {
|
|
|
71433
72622
|
const slot = optionalString(args.slot, "slot");
|
|
71434
72623
|
const since = optionalInteger(args.since_seq, "since_seq");
|
|
71435
72624
|
const spans = optionalBoolean(args.spans, "spans");
|
|
72625
|
+
const cols = mode === "resize" ? requiredInteger(args.cols, "cols", mode) : undefined;
|
|
72626
|
+
const rows = mode === "resize" ? requiredInteger(args.rows, "rows", mode) : undefined;
|
|
71436
72627
|
switch (mode) {
|
|
71437
72628
|
case "status":
|
|
71438
72629
|
return contractAnswer(teamStatusAnswer(path, runId));
|
|
@@ -71443,6 +72634,11 @@ async function teamContractVerb(mode, args) {
|
|
|
71443
72634
|
throw new ContractErrorException("invalid_args", "'slot' is required for mode 'capture'");
|
|
71444
72635
|
return contractAnswer(captureTeamSlot(path, slot, since, spans, runId));
|
|
71445
72636
|
}
|
|
72637
|
+
case "resize": {
|
|
72638
|
+
if (slot === undefined)
|
|
72639
|
+
throw new ContractErrorException("invalid_args", "'slot' is required for mode 'resize'");
|
|
72640
|
+
return contractAnswer(await resizeTeamSlot(path, slot, cols, rows, runId));
|
|
72641
|
+
}
|
|
71446
72642
|
}
|
|
71447
72643
|
} catch (e) {
|
|
71448
72644
|
return contractErrorAnswer(e);
|
|
@@ -71816,18 +73012,18 @@ Use with: run_prompt(model="${suggested}", prompt="your prompt")`;
|
|
|
71816
73012
|
});
|
|
71817
73013
|
tools.push({
|
|
71818
73014
|
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), '
|
|
73015
|
+
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
73016
|
inputSchema: {
|
|
71821
73017
|
type: "object",
|
|
71822
73018
|
properties: {
|
|
71823
73019
|
mode: {
|
|
71824
73020
|
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
|
|
73021
|
+
enum: ["run", "judge", "run-and-judge", "status", "cancel", "list", "capture", "resize"],
|
|
73022
|
+
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
73023
|
},
|
|
71828
73024
|
slot: {
|
|
71829
73025
|
type: "string",
|
|
71830
|
-
description: "For 'cancel' and '
|
|
73026
|
+
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
73027
|
},
|
|
71832
73028
|
path: {
|
|
71833
73029
|
type: "string",
|
|
@@ -71835,7 +73031,7 @@ Use with: run_prompt(model="${suggested}", prompt="your prompt")`;
|
|
|
71835
73031
|
},
|
|
71836
73032
|
run_id: {
|
|
71837
73033
|
type: "string",
|
|
71838
|
-
description: "For 'status', 'cancel' and '
|
|
73034
|
+
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
73035
|
},
|
|
71840
73036
|
since_seq: {
|
|
71841
73037
|
type: "number",
|
|
@@ -71845,6 +73041,14 @@ Use with: run_prompt(model="${suggested}", prompt="your prompt")`;
|
|
|
71845
73041
|
type: "boolean",
|
|
71846
73042
|
description: "For 'capture': also return the colour/attribute spans of each line."
|
|
71847
73043
|
},
|
|
73044
|
+
cols: {
|
|
73045
|
+
type: "integer",
|
|
73046
|
+
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."
|
|
73047
|
+
},
|
|
73048
|
+
rows: {
|
|
73049
|
+
type: "integer",
|
|
73050
|
+
description: "For 'resize' (required): the terminal height in rows, clamped to 24\u20139999 and to " + "at most 4 000 000 cells (cols \xD7 rows)."
|
|
73051
|
+
},
|
|
71848
73052
|
models: {
|
|
71849
73053
|
type: "array",
|
|
71850
73054
|
items: { type: "string" },
|
|
@@ -71886,7 +73090,7 @@ Use with: run_prompt(model="${suggested}", prompt="your prompt")`;
|
|
|
71886
73090
|
heartbeat: true,
|
|
71887
73091
|
handler: async (args, ctx) => {
|
|
71888
73092
|
const mode = args.mode;
|
|
71889
|
-
if (mode === "list" || mode === "status" || mode === "cancel" || mode === "capture") {
|
|
73093
|
+
if (mode === "list" || mode === "status" || mode === "cancel" || mode === "capture" || mode === "resize") {
|
|
71890
73094
|
return teamContractVerb(mode, args);
|
|
71891
73095
|
}
|
|
71892
73096
|
try {
|
|
@@ -71918,7 +73122,7 @@ Use with: run_prompt(model="${suggested}", prompt="your prompt")`;
|
|
|
71918
73122
|
const promptText = () => {
|
|
71919
73123
|
if (input !== undefined)
|
|
71920
73124
|
return input;
|
|
71921
|
-
const existing =
|
|
73125
|
+
const existing = join53(resolved, "input.md");
|
|
71922
73126
|
return existsSync33(existing) ? readFileSync33(existing, "utf-8") : undefined;
|
|
71923
73127
|
};
|
|
71924
73128
|
switch (mode) {
|
|
@@ -72077,16 +73281,16 @@ Use with: run_prompt(model="${suggested}", prompt="your prompt")`;
|
|
|
72077
73281
|
const sp = session_path;
|
|
72078
73282
|
for (const file of ["status.json", "manifest.json", "input.md"]) {
|
|
72079
73283
|
try {
|
|
72080
|
-
sessionData[file] = readFileSync33(
|
|
73284
|
+
sessionData[file] = readFileSync33(join53(sp, file), "utf-8");
|
|
72081
73285
|
} catch {}
|
|
72082
73286
|
}
|
|
72083
73287
|
try {
|
|
72084
|
-
const errorDir =
|
|
73288
|
+
const errorDir = join53(sp, "errors");
|
|
72085
73289
|
if (existsSync33(errorDir)) {
|
|
72086
73290
|
for (const f of readdirSync10(errorDir)) {
|
|
72087
73291
|
if (f.endsWith(".log")) {
|
|
72088
73292
|
try {
|
|
72089
|
-
sessionData[`errors/${f}`] = readFileSync33(
|
|
73293
|
+
sessionData[`errors/${f}`] = readFileSync33(join53(errorDir, f), "utf-8");
|
|
72090
73294
|
} catch {}
|
|
72091
73295
|
}
|
|
72092
73296
|
}
|
|
@@ -72096,7 +73300,7 @@ Use with: run_prompt(model="${suggested}", prompt="your prompt")`;
|
|
|
72096
73300
|
for (const f of readdirSync10(sp)) {
|
|
72097
73301
|
if (f.startsWith("response-") && f.endsWith(".md")) {
|
|
72098
73302
|
try {
|
|
72099
|
-
const content = readFileSync33(
|
|
73303
|
+
const content = readFileSync33(join53(sp, f), "utf-8");
|
|
72100
73304
|
sessionData[f] = content.slice(0, 200) + (content.length > 200 ? "... (truncated)" : "");
|
|
72101
73305
|
} catch {}
|
|
72102
73306
|
}
|
|
@@ -72105,7 +73309,7 @@ Use with: run_prompt(model="${suggested}", prompt="your prompt")`;
|
|
|
72105
73309
|
}
|
|
72106
73310
|
let version = "unknown";
|
|
72107
73311
|
try {
|
|
72108
|
-
const pkgPath =
|
|
73312
|
+
const pkgPath = join53(__dirname3, "../package.json");
|
|
72109
73313
|
if (existsSync33(pkgPath)) {
|
|
72110
73314
|
version = JSON.parse(readFileSync33(pkgPath, "utf-8")).version;
|
|
72111
73315
|
}
|
|
@@ -72185,7 +73389,7 @@ Report manually at https://github.com/anthropics/claudish/issues${autoSendHint}`
|
|
|
72185
73389
|
});
|
|
72186
73390
|
tools.push({
|
|
72187
73391
|
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 " + "settles); without one it is interactive and waits for send_input. Needs magmux >= 0.
|
|
73392
|
+
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 >= 0.15.1 " + "(darwin and linux).",
|
|
72189
73393
|
inputSchema: {
|
|
72190
73394
|
type: "object",
|
|
72191
73395
|
properties: {
|
|
@@ -72229,7 +73433,7 @@ Report manually at https://github.com/anthropics/claudish/issues${autoSendHint}`
|
|
|
72229
73433
|
const requestedModel = args.model;
|
|
72230
73434
|
const workDir = args.work_dir;
|
|
72231
73435
|
const plan = await prehydrateCredentialsForSpawn([requestedModel], {
|
|
72232
|
-
pin: workDir === undefined ||
|
|
73436
|
+
pin: workDir === undefined || resolve7(workDir) === process.cwd()
|
|
72233
73437
|
});
|
|
72234
73438
|
const parentClaudeSessionId = await parentSessionForCall({
|
|
72235
73439
|
hostPid: sessionManager.hostPid
|
|
@@ -72411,7 +73615,7 @@ Report manually at https://github.com/anthropics/claudish/issues${autoSendHint}`
|
|
|
72411
73615
|
});
|
|
72412
73616
|
tools.push({
|
|
72413
73617
|
name: "capture_session",
|
|
72414
|
-
description: "Read a session's current terminal screen
|
|
73618
|
+
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
73619
|
inputSchema: {
|
|
72416
73620
|
type: "object",
|
|
72417
73621
|
properties: {
|
|
@@ -72441,6 +73645,35 @@ Report manually at https://github.com/anthropics/claudish/issues${autoSendHint}`
|
|
|
72441
73645
|
}
|
|
72442
73646
|
}
|
|
72443
73647
|
});
|
|
73648
|
+
tools.push({
|
|
73649
|
+
name: "resize_session",
|
|
73650
|
+
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).",
|
|
73651
|
+
inputSchema: {
|
|
73652
|
+
type: "object",
|
|
73653
|
+
properties: {
|
|
73654
|
+
session_id: { type: "string", description: "Session ID from create_session" },
|
|
73655
|
+
cols: { type: "integer", description: "Terminal width in columns (clamped to 80\u20139999)" },
|
|
73656
|
+
rows: {
|
|
73657
|
+
type: "integer",
|
|
73658
|
+
description: "Terminal height in rows (clamped to 24\u20139999 and 4 000 000 cells)"
|
|
73659
|
+
}
|
|
73660
|
+
},
|
|
73661
|
+
required: ["session_id", "cols", "rows"]
|
|
73662
|
+
},
|
|
73663
|
+
group: "session",
|
|
73664
|
+
handler: async (args) => {
|
|
73665
|
+
try {
|
|
73666
|
+
const sessionId = optionalString(args.session_id, "session_id");
|
|
73667
|
+
if (sessionId === undefined)
|
|
73668
|
+
throw new ContractErrorException("invalid_args", "'session_id' is required");
|
|
73669
|
+
const cols = requiredInteger(args.cols, "cols");
|
|
73670
|
+
const rows = requiredInteger(args.rows, "rows");
|
|
73671
|
+
return contractAnswer(await sessionManager.resizeSession(sessionId, cols, rows));
|
|
73672
|
+
} catch (e) {
|
|
73673
|
+
return contractErrorAnswer(e);
|
|
73674
|
+
}
|
|
73675
|
+
}
|
|
73676
|
+
});
|
|
72444
73677
|
return tools;
|
|
72445
73678
|
}
|
|
72446
73679
|
function resolveToolGroups(mode) {
|
|
@@ -72566,7 +73799,7 @@ Each session is an interactive Claude Code running the model in its own headless
|
|
|
72566
73799
|
3. send_input may be called at any time; it is queued until the session is idle.
|
|
72567
73800
|
4. COMPLETED: call get_output for the answer.
|
|
72568
73801
|
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.
|
|
73802
|
+
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
73803
|
|
|
72571
73804
|
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
73805
|
var init_mcp_server = __esm(() => {
|
|
@@ -72599,9 +73832,9 @@ var init_mcp_server = __esm(() => {
|
|
|
72599
73832
|
import_dotenv2 = __toESM(require_main(), 1);
|
|
72600
73833
|
import_dotenv2.config({ quiet: true });
|
|
72601
73834
|
__filename3 = fileURLToPath3(import.meta.url);
|
|
72602
|
-
__dirname3 =
|
|
72603
|
-
CLAUDISH_CACHE_DIR =
|
|
72604
|
-
OPENROUTER_MODELS_CACHE_PATH =
|
|
73835
|
+
__dirname3 = dirname15(__filename3);
|
|
73836
|
+
CLAUDISH_CACHE_DIR = join53(homedir35(), ".claudish");
|
|
73837
|
+
OPENROUTER_MODELS_CACHE_PATH = join53(CLAUDISH_CACHE_DIR, "openrouter-models.json");
|
|
72605
73838
|
NEXT_STEP = {
|
|
72606
73839
|
cancelled: "you stopped this slot; nothing is wrong with it. Re-run it if you still want its vote",
|
|
72607
73840
|
timeout: "grid mode only \u2014 magmux ended the pane. The orchestrator has no deadline",
|
|
@@ -72612,7 +73845,7 @@ var init_mcp_server = __esm(() => {
|
|
|
72612
73845
|
prompt_not_accepted: "the REPL never took the prompt \u2014 read the evidence screen; retry",
|
|
72613
73846
|
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
73847
|
child_exited: "read the evidence screen, then retry or drop the model",
|
|
72615
|
-
pane_lost: "magmux died \u2014 check `magmux --version` \u2265 0.
|
|
73848
|
+
pane_lost: "magmux died \u2014 check `magmux --version` \u2265 0.15.1 and retry",
|
|
72616
73849
|
blocked: "the child asked a question team cannot answer \u2014 make the prompt self-contained or use " + "create_session",
|
|
72617
73850
|
api_error: "retry once, or route via a different provider (or@<model>)",
|
|
72618
73851
|
refused: "the model refused \u2014 rephrase or drop the model",
|
|
@@ -72928,7 +74161,7 @@ var init_behavior_command = __esm(() => {
|
|
|
72928
74161
|
import { spawn as spawn3 } from "child_process";
|
|
72929
74162
|
import { existsSync as existsSync36, readFileSync as readFileSync36, writeFileSync as writeFileSync27 } from "fs";
|
|
72930
74163
|
import { connect as netConnect2 } from "net";
|
|
72931
|
-
import { join as
|
|
74164
|
+
import { join as join54 } from "path";
|
|
72932
74165
|
import { setTimeout as wait } from "timers/promises";
|
|
72933
74166
|
function paneRouteLine(explanation) {
|
|
72934
74167
|
const origin = describeRouteExplanation(explanation);
|
|
@@ -73078,9 +74311,9 @@ async function runWithGrid(sessionPath, models, input, opts) {
|
|
|
73078
74311
|
const keep = opts?.keep ?? false;
|
|
73079
74312
|
const manifest = setupSession(sessionPath, models, input);
|
|
73080
74313
|
const startedAt = new Date().toISOString();
|
|
73081
|
-
const gridfilePath =
|
|
73082
|
-
const prompt = readFileSync36(
|
|
73083
|
-
const rawPrompt = readFileSync36(
|
|
74314
|
+
const gridfilePath = join54(sessionPath, "gridfile.txt");
|
|
74315
|
+
const prompt = readFileSync36(join54(sessionPath, "input.md"), "utf-8").replace(/'/g, "'\\''").replace(/\n/g, " ");
|
|
74316
|
+
const rawPrompt = readFileSync36(join54(sessionPath, "input.md"), "utf-8");
|
|
73084
74317
|
const usedBannerColors = new Set;
|
|
73085
74318
|
const routeLines = mode === "interactive" ? new Map : await resolvePaneRouteLines(Object.values(manifest.models).map((entry) => entry.model));
|
|
73086
74319
|
const gridLines = Object.entries(manifest.models).map(([anonId]) => {
|
|
@@ -73112,7 +74345,7 @@ async function runWithGrid(sessionPath, models, input, opts) {
|
|
|
73112
74345
|
});
|
|
73113
74346
|
const [{ results }] = await Promise.all([subscription, procExit]);
|
|
73114
74347
|
const status = buildTeamStatus(manifest, startedAt, results?.panes ?? null);
|
|
73115
|
-
const statusPath =
|
|
74348
|
+
const statusPath = join54(sessionPath, "status.json");
|
|
73116
74349
|
writeFileSync27(statusPath, JSON.stringify(status, null, 2), "utf-8");
|
|
73117
74350
|
return status;
|
|
73118
74351
|
}
|
|
@@ -73133,7 +74366,7 @@ var init_team_grid = __esm(() => {
|
|
|
73133
74366
|
|
|
73134
74367
|
// src/team-cli.ts
|
|
73135
74368
|
import { readFileSync as readFileSync37 } from "fs";
|
|
73136
|
-
import { join as
|
|
74369
|
+
import { join as join55 } from "path";
|
|
73137
74370
|
async function runPaneTeam(sessionPath, models, input, opts) {
|
|
73138
74371
|
installPaneShutdownHooks({ exitAfter: true });
|
|
73139
74372
|
try {
|
|
@@ -73185,7 +74418,7 @@ Options (run / run-and-judge):
|
|
|
73185
74418
|
--timeout <secs> Grid modes only: magmux's own per-pane timeout (default: 300).
|
|
73186
74419
|
json mode has no deadline \u2014 nothing kills a working model.
|
|
73187
74420
|
json mode runs each model as an interactive pane in a headless
|
|
73188
|
-
magmux (>= 0.
|
|
74421
|
+
magmux (>= 0.15.1; darwin and linux).
|
|
73189
74422
|
--grid Show all models in a magmux grid with live output + status bar
|
|
73190
74423
|
--mode <m> run only: json (default, panes), default (the grid, as --grid)
|
|
73191
74424
|
or interactive (as --interactive)
|
|
@@ -73278,7 +74511,7 @@ async function teamCommand(args) {
|
|
|
73278
74511
|
}
|
|
73279
74512
|
case "judge": {
|
|
73280
74513
|
await judgeResponses(sessionPath, { judges });
|
|
73281
|
-
console.log(readFileSync37(
|
|
74514
|
+
console.log(readFileSync37(join55(sessionPath, "verdict.md"), "utf-8"));
|
|
73282
74515
|
break;
|
|
73283
74516
|
}
|
|
73284
74517
|
case "run-and-judge": {
|
|
@@ -73294,7 +74527,7 @@ async function teamCommand(args) {
|
|
|
73294
74527
|
});
|
|
73295
74528
|
printStatus(status);
|
|
73296
74529
|
await judgeResponses(sessionPath, { judges });
|
|
73297
|
-
console.log(readFileSync37(
|
|
74530
|
+
console.log(readFileSync37(join55(sessionPath, "verdict.md"), "utf-8"));
|
|
73298
74531
|
break;
|
|
73299
74532
|
}
|
|
73300
74533
|
case "status": {
|
|
@@ -73883,7 +75116,7 @@ var init_keychain_command = __esm(() => {
|
|
|
73883
75116
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
73884
75117
|
import { existsSync as existsSync37, unlinkSync as unlinkSync9 } from "fs";
|
|
73885
75118
|
import { homedir as homedir36 } from "os";
|
|
73886
|
-
import { join as
|
|
75119
|
+
import { join as join56 } from "path";
|
|
73887
75120
|
async function defaultSuggestModel() {
|
|
73888
75121
|
try {
|
|
73889
75122
|
const tok = readSharedAntigravityToken();
|
|
@@ -74004,7 +75237,7 @@ No session detected yet. Starting the Antigravity CLI interactively \u2014
|
|
|
74004
75237
|
async logout(deps) {
|
|
74005
75238
|
deleteSharedAntigravityToken(deps);
|
|
74006
75239
|
try {
|
|
74007
|
-
const tokenFile =
|
|
75240
|
+
const tokenFile = join56(homedir36(), ".gemini", "antigravity-cli", "antigravity-oauth-token");
|
|
74008
75241
|
if (existsSync37(tokenFile))
|
|
74009
75242
|
unlinkSync9(tokenFile);
|
|
74010
75243
|
} catch {}
|
|
@@ -82490,7 +83723,7 @@ import {
|
|
|
82490
83723
|
writeFileSync as writeFileSync28
|
|
82491
83724
|
} from "fs";
|
|
82492
83725
|
import { homedir as homedir37, tmpdir as tmpdir3 } from "os";
|
|
82493
|
-
import { dirname as
|
|
83726
|
+
import { dirname as dirname16, join as join57 } from "path";
|
|
82494
83727
|
import { isatty } from "tty";
|
|
82495
83728
|
function releaseTerminalIsolation() {
|
|
82496
83729
|
if (!restoreTerminal)
|
|
@@ -82555,7 +83788,7 @@ function hasResolvableAnthropicAuth(deps = {}) {
|
|
|
82555
83788
|
if (isRealAnthropicEnvCredential(env, "ANTHROPIC_API_KEY") || isRealAnthropicEnvCredential(env, "ANTHROPIC_AUTH_TOKEN")) {
|
|
82556
83789
|
return true;
|
|
82557
83790
|
}
|
|
82558
|
-
if (fileExists(
|
|
83791
|
+
if (fileExists(join57(homedir37(), ".claude", ".credentials.json")))
|
|
82559
83792
|
return true;
|
|
82560
83793
|
return keychainProbe();
|
|
82561
83794
|
}
|
|
@@ -82570,7 +83803,7 @@ function isProxyAuthMode(config) {
|
|
|
82570
83803
|
}
|
|
82571
83804
|
function managedSettingsPath() {
|
|
82572
83805
|
if (isWindows2()) {
|
|
82573
|
-
return
|
|
83806
|
+
return join57(process.env.PROGRAMDATA || "C:\\ProgramData", "ClaudeCode", "managed-settings.json");
|
|
82574
83807
|
}
|
|
82575
83808
|
if (process.platform === "darwin") {
|
|
82576
83809
|
return "/Library/Application Support/ClaudeCode/managed-settings.json";
|
|
@@ -82591,9 +83824,9 @@ function isWindows2() {
|
|
|
82591
83824
|
}
|
|
82592
83825
|
function createStatusLineScript(tokenFilePath) {
|
|
82593
83826
|
const homeDir = process.env.HOME || process.env.USERPROFILE || tmpdir3();
|
|
82594
|
-
const claudishDir =
|
|
83827
|
+
const claudishDir = join57(homeDir, ".claudish");
|
|
82595
83828
|
const timestamp = Date.now();
|
|
82596
|
-
const scriptPath =
|
|
83829
|
+
const scriptPath = join57(claudishDir, `status-${timestamp}.js`);
|
|
82597
83830
|
const escapedTokenPath = tokenFilePath.replace(/\\/g, "\\\\");
|
|
82598
83831
|
const light = getThemeMode() === "light";
|
|
82599
83832
|
const cyanCode = light ? "38;2;14;116;144" : "96";
|
|
@@ -82731,7 +83964,7 @@ process.stdin.on('end', () => {
|
|
|
82731
83964
|
}
|
|
82732
83965
|
function initializeTokenFile(tokenFilePath) {
|
|
82733
83966
|
try {
|
|
82734
|
-
mkdirSync25(
|
|
83967
|
+
mkdirSync25(dirname16(tokenFilePath), { recursive: true });
|
|
82735
83968
|
writeFileSync28(tokenFilePath, JSON.stringify({
|
|
82736
83969
|
input_tokens: 0,
|
|
82737
83970
|
output_tokens: 0,
|
|
@@ -82763,7 +83996,7 @@ function cleanupStaleTokenFiles(dir, now = Date.now(), maxAgeMs = STALE_TOKEN_FI
|
|
|
82763
83996
|
if (!name.startsWith("tokens-") || !name.endsWith(".json"))
|
|
82764
83997
|
continue;
|
|
82765
83998
|
scanned++;
|
|
82766
|
-
const full =
|
|
83999
|
+
const full = join57(dir, name);
|
|
82767
84000
|
try {
|
|
82768
84001
|
if (statSync14(full).mtimeMs >= cutoff)
|
|
82769
84002
|
continue;
|
|
@@ -82792,9 +84025,9 @@ function parseSettingsArgSafe(value) {
|
|
|
82792
84025
|
}
|
|
82793
84026
|
function userSettingsFileCandidates(cwd) {
|
|
82794
84027
|
return [
|
|
82795
|
-
|
|
82796
|
-
|
|
82797
|
-
|
|
84028
|
+
join57(homedir37(), ".claude", "settings.json"),
|
|
84029
|
+
join57(cwd, ".claude", "settings.json"),
|
|
84030
|
+
join57(cwd, ".claude", "settings.local.json")
|
|
82798
84031
|
];
|
|
82799
84032
|
}
|
|
82800
84033
|
function discoverUserStatusLineCommand(claudeArgs = [], cwd = process.cwd()) {
|
|
@@ -82835,12 +84068,12 @@ function buildChainedStatusCommand(userCommand, claudishBody, claudishSegment) {
|
|
|
82835
84068
|
}
|
|
82836
84069
|
function createTempSettingsFile(_modelDisplay, port, proxyAuthMode, userStatusLineCommand) {
|
|
82837
84070
|
const homeDir = process.env.HOME || process.env.USERPROFILE || tmpdir3();
|
|
82838
|
-
const claudishDir =
|
|
84071
|
+
const claudishDir = join57(homeDir, ".claudish");
|
|
82839
84072
|
try {
|
|
82840
84073
|
mkdirSync25(claudishDir, { recursive: true });
|
|
82841
84074
|
} catch {}
|
|
82842
84075
|
const timestamp = Date.now();
|
|
82843
|
-
const tempPath =
|
|
84076
|
+
const tempPath = join57(claudishDir, `settings-${timestamp}.json`);
|
|
82844
84077
|
const assignedFile = assignedTokenFile(process.env) !== null;
|
|
82845
84078
|
const tokenFilePath = resolveTokenFilePath(port);
|
|
82846
84079
|
cleanupStaleTokenFiles(claudishDir);
|
|
@@ -83219,7 +84452,7 @@ async function runClaudeWithProxy(config, proxyUrl, onCleanup) {
|
|
|
83219
84452
|
console.error(`
|
|
83220
84453
|
Or set CLAUDE_PATH to your custom installation:`);
|
|
83221
84454
|
const home = homedir37();
|
|
83222
|
-
const localPath = isWindows2() ?
|
|
84455
|
+
const localPath = isWindows2() ? join57(home, ".claude", "local", "claude.exe") : join57(home, ".claude", "local", "claude");
|
|
83223
84456
|
console.error(` export CLAUDE_PATH=${localPath}`);
|
|
83224
84457
|
process.exit(1);
|
|
83225
84458
|
}
|
|
@@ -83332,15 +84565,15 @@ async function findClaudeBinary() {
|
|
|
83332
84565
|
}
|
|
83333
84566
|
}
|
|
83334
84567
|
const home = homedir37();
|
|
83335
|
-
const localPath = isWindows ?
|
|
84568
|
+
const localPath = isWindows ? join57(home, ".claude", "local", "claude.exe") : join57(home, ".claude", "local", "claude");
|
|
83336
84569
|
if (existsSync39(localPath)) {
|
|
83337
84570
|
return localPath;
|
|
83338
84571
|
}
|
|
83339
84572
|
if (isWindows) {
|
|
83340
84573
|
const windowsPaths = [
|
|
83341
|
-
|
|
83342
|
-
|
|
83343
|
-
|
|
84574
|
+
join57(home, "AppData", "Roaming", "npm", "claude.cmd"),
|
|
84575
|
+
join57(home, ".npm-global", "claude.cmd"),
|
|
84576
|
+
join57(home, "node_modules", ".bin", "claude.cmd")
|
|
83344
84577
|
];
|
|
83345
84578
|
for (const path of windowsPaths) {
|
|
83346
84579
|
if (existsSync39(path)) {
|
|
@@ -83351,11 +84584,11 @@ async function findClaudeBinary() {
|
|
|
83351
84584
|
const commonPaths = [
|
|
83352
84585
|
"/usr/local/bin/claude",
|
|
83353
84586
|
"/opt/homebrew/bin/claude",
|
|
83354
|
-
|
|
83355
|
-
|
|
83356
|
-
|
|
84587
|
+
join57(home, ".npm-global/bin/claude"),
|
|
84588
|
+
join57(home, ".local/bin/claude"),
|
|
84589
|
+
join57(home, "node_modules/.bin/claude"),
|
|
83357
84590
|
"/data/data/com.termux/files/usr/bin/claude",
|
|
83358
|
-
|
|
84591
|
+
join57(home, "../usr/bin/claude")
|
|
83359
84592
|
];
|
|
83360
84593
|
for (const path of commonPaths) {
|
|
83361
84594
|
if (existsSync39(path)) {
|
|
@@ -83440,16 +84673,16 @@ var init_claude_runner = __esm(() => {
|
|
|
83440
84673
|
// src/diag-output.ts
|
|
83441
84674
|
import { createWriteStream as createWriteStream2, mkdirSync as mkdirSync26, unlinkSync as unlinkSync11, writeFileSync as writeFileSync29 } from "fs";
|
|
83442
84675
|
import { homedir as homedir38 } from "os";
|
|
83443
|
-
import { join as
|
|
84676
|
+
import { join as join58 } from "path";
|
|
83444
84677
|
function getClaudishDir() {
|
|
83445
|
-
const dir =
|
|
84678
|
+
const dir = join58(homedir38(), ".claudish");
|
|
83446
84679
|
try {
|
|
83447
84680
|
mkdirSync26(dir, { recursive: true });
|
|
83448
84681
|
} catch {}
|
|
83449
84682
|
return dir;
|
|
83450
84683
|
}
|
|
83451
84684
|
function getDiagLogPath() {
|
|
83452
|
-
return
|
|
84685
|
+
return join58(getClaudishDir(), `diag-${process.pid}.log`);
|
|
83453
84686
|
}
|
|
83454
84687
|
|
|
83455
84688
|
class LogFileDiagOutput {
|
|
@@ -86064,7 +87297,7 @@ init_startup_trace();
|
|
|
86064
87297
|
init_picker_cancelled();
|
|
86065
87298
|
var import_dotenv3 = __toESM(require_main(), 1);
|
|
86066
87299
|
import { existsSync as existsSync40, readFileSync as readFileSync40 } from "fs";
|
|
86067
|
-
import { join as
|
|
87300
|
+
import { join as join59, resolve as resolve8 } from "path";
|
|
86068
87301
|
|
|
86069
87302
|
// src/tui/runtime/should-open-picker.ts
|
|
86070
87303
|
function noModelConfigured(gate) {
|
|
@@ -86176,7 +87409,7 @@ async function applyOpImport() {
|
|
|
86176
87409
|
async function applyConfigOverride() {
|
|
86177
87410
|
await Promise.resolve();
|
|
86178
87411
|
const plan = planConfigOverride(process.argv.slice(2), process.env, {
|
|
86179
|
-
resolve:
|
|
87412
|
+
resolve: resolve8,
|
|
86180
87413
|
exists: existsSync40
|
|
86181
87414
|
});
|
|
86182
87415
|
if (plan.kind === "none")
|
|
@@ -86380,7 +87613,7 @@ async function runCli() {
|
|
|
86380
87613
|
process.exit(1);
|
|
86381
87614
|
}
|
|
86382
87615
|
const mode = cliConfig.teamMode ?? "default";
|
|
86383
|
-
const sessionPath =
|
|
87616
|
+
const sessionPath = join59(process.cwd(), `.claudish-team-${Date.now()}`);
|
|
86384
87617
|
if (mode === "json") {
|
|
86385
87618
|
await Promise.resolve().then(() => init_pane());
|
|
86386
87619
|
await Promise.resolve().then(() => init_team_orchestrator());
|
|
@@ -86400,7 +87633,7 @@ async function runCli() {
|
|
|
86400
87633
|
const status = await runModels(sessionPath);
|
|
86401
87634
|
const result = { ...status, responses: {} };
|
|
86402
87635
|
for (const anonId of Object.keys(status.models)) {
|
|
86403
|
-
const responsePath =
|
|
87636
|
+
const responsePath = join59(sessionPath, `response-${anonId}.md`);
|
|
86404
87637
|
try {
|
|
86405
87638
|
const raw = readFileSync40(responsePath, "utf-8").trim();
|
|
86406
87639
|
try {
|