claudish 12.0.0 → 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/AI_AGENT_GUIDE.md +7 -2
- package/dist/index.js +1650 -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.
|
|
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",
|
|
@@ -46298,6 +46299,9 @@ function projectRecommendations(recommendations, catalog, richModels = [], now =
|
|
|
46298
46299
|
},
|
|
46299
46300
|
context: rich?.contextWindow ? String(rich.contextWindow) : model.contextWindow ? String(model.contextWindow) : "N/A",
|
|
46300
46301
|
releaseDate: model.releaseDate,
|
|
46302
|
+
...typeof model.supportsTools === "boolean" ? { supportsTools: model.supportsTools } : {},
|
|
46303
|
+
...typeof model.reasoning?.supported === "boolean" ? { supportsReasoning: model.reasoning.supported } : {},
|
|
46304
|
+
...typeof model.supportsVision === "boolean" ? { supportsVision: model.supportsVision } : {},
|
|
46301
46305
|
...subscription ? { subscription, subscriptions: [subscription] } : {}
|
|
46302
46306
|
});
|
|
46303
46307
|
}
|
|
@@ -63871,6 +63875,20 @@ function resolveClaudishSpawn(env = process.env) {
|
|
|
63871
63875
|
}
|
|
63872
63876
|
var CLAUDISH_BIN_ENV = "CLAUDISH_BIN";
|
|
63873
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
|
+
|
|
63874
63892
|
// src/pane/process-identity.ts
|
|
63875
63893
|
import { execFile, execFileSync as execFileSync2 } from "child_process";
|
|
63876
63894
|
import { lstatSync } from "fs";
|
|
@@ -64230,8 +64248,8 @@ function buildPaneEnv(input) {
|
|
|
64230
64248
|
continue;
|
|
64231
64249
|
env[k] = v;
|
|
64232
64250
|
}
|
|
64233
|
-
env.COLUMNS =
|
|
64234
|
-
env.LINES =
|
|
64251
|
+
env.COLUMNS = String(input.cols ?? DEFAULT_PANE_COLS);
|
|
64252
|
+
env.LINES = String(input.rows ?? DEFAULT_PANE_ROWS);
|
|
64235
64253
|
if (input.parentEnv.CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC === undefined)
|
|
64236
64254
|
env.CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC = "1";
|
|
64237
64255
|
Object.assign(env, input.slotEnv);
|
|
@@ -64357,24 +64375,46 @@ function versionAtLeast(v, min) {
|
|
|
64357
64375
|
return true;
|
|
64358
64376
|
}
|
|
64359
64377
|
async function assertMagmuxAvailable(binary) {
|
|
64360
|
-
const
|
|
64378
|
+
const key = binary ?? "";
|
|
64379
|
+
const cached = magmuxCache.get(key);
|
|
64361
64380
|
if (cached)
|
|
64362
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) {
|
|
64363
64398
|
const found = binary ?? findMagmuxBinaryOrNull();
|
|
64364
64399
|
if (!found)
|
|
64365
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) {
|
|
64366
64409
|
let out = "";
|
|
64367
64410
|
try {
|
|
64368
|
-
|
|
64411
|
+
const r = await execFileAsync(found, ["--version"], { encoding: "utf8", timeout: 5000 });
|
|
64412
|
+
out = `${r.stdout}
|
|
64413
|
+
${r.stderr}`;
|
|
64369
64414
|
} catch (e) {
|
|
64370
64415
|
throw new MagmuxUnavailableError(`magmux_unavailable: ${found} --version failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
64371
64416
|
}
|
|
64372
|
-
|
|
64373
|
-
if (!version || !versionAtLeast(version, MIN_MAGMUX_VERSION))
|
|
64374
|
-
throw new MagmuxUnavailableError(`magmux_unavailable: ${found} is version ${version || "unknown"}; panes need >= ${MIN_MAGMUX_VERSION}`);
|
|
64375
|
-
const result = { binary: found, version };
|
|
64376
|
-
magmuxCache.set(binary ?? "", result);
|
|
64377
|
-
return result;
|
|
64417
|
+
return out.match(/(\d+\.\d+\.\d+)/)?.[1] ?? "";
|
|
64378
64418
|
}
|
|
64379
64419
|
function resolveClaudishLaunch(parentEnv) {
|
|
64380
64420
|
const t = resolveClaudishSpawn(parentEnv);
|
|
@@ -64423,21 +64463,35 @@ function spawnPaneWatcher(args) {
|
|
|
64423
64463
|
proc.stdin?.unref?.();
|
|
64424
64464
|
return proc;
|
|
64425
64465
|
}
|
|
64426
|
-
function
|
|
64427
|
-
|
|
64466
|
+
function paneMagmuxArgv(input) {
|
|
64467
|
+
return [
|
|
64428
64468
|
"--headless",
|
|
64429
64469
|
"--no-status",
|
|
64470
|
+
"--controller",
|
|
64471
|
+
"claude-code",
|
|
64472
|
+
"--session-id",
|
|
64473
|
+
input.sessionUuid,
|
|
64474
|
+
"--transcript",
|
|
64475
|
+
resolve3(input.transcriptPath),
|
|
64430
64476
|
"--id",
|
|
64431
64477
|
input.paneId,
|
|
64432
64478
|
"--sock-dir",
|
|
64433
64479
|
input.sockRoot,
|
|
64434
64480
|
"-e",
|
|
64435
64481
|
paneCommand(input.ctlDir)
|
|
64436
|
-
]
|
|
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
|
+
});
|
|
64437
64491
|
proc.on("error", () => {});
|
|
64438
64492
|
return proc;
|
|
64439
64493
|
}
|
|
64440
|
-
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
|
|
64441
64495
|
[ "$1" = -l ] && shift
|
|
64442
64496
|
exec /bin/sh "$@"
|
|
64443
64497
|
`, FATAL_MAGMUX_STDERR;
|
|
@@ -64611,6 +64665,7 @@ var init_pane_launch = __esm(() => {
|
|
|
64611
64665
|
code = "magmux_unavailable";
|
|
64612
64666
|
};
|
|
64613
64667
|
magmuxCache = new Map;
|
|
64668
|
+
magmuxProbes = new Map;
|
|
64614
64669
|
execFileAsync = promisify5(execFile2);
|
|
64615
64670
|
ClaudishNotFoundError = class ClaudishNotFoundError extends Error {
|
|
64616
64671
|
code = "pane_lost";
|
|
@@ -64620,6 +64675,20 @@ var init_pane_launch = __esm(() => {
|
|
|
64620
64675
|
|
|
64621
64676
|
// src/pane/magmux-client.ts
|
|
64622
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
|
+
}
|
|
64623
64692
|
function dialOnce(sockPath) {
|
|
64624
64693
|
return new Promise((resolve, reject) => {
|
|
64625
64694
|
const s = new Socket;
|
|
@@ -64746,7 +64815,7 @@ class MagmuxClient {
|
|
|
64746
64815
|
return;
|
|
64747
64816
|
clearTimeout(p.timer);
|
|
64748
64817
|
this.pending.delete(m.id);
|
|
64749
|
-
p.resolve(m.ok === true ? { ok: true, result: m.result ?? {} } :
|
|
64818
|
+
p.resolve(m.ok === true ? { ok: true, result: m.result ?? {} } : failureOf(m));
|
|
64750
64819
|
return;
|
|
64751
64820
|
}
|
|
64752
64821
|
if (m.type === "shutdown")
|
|
@@ -65244,6 +65313,352 @@ var init_process_tree = __esm(() => {
|
|
|
65244
65313
|
KILL_PROCESS_GROUP = process.platform !== "win32";
|
|
65245
65314
|
});
|
|
65246
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
|
+
|
|
65247
65662
|
// src/pane/screen-model.ts
|
|
65248
65663
|
function emptyScreen(cols, rows) {
|
|
65249
65664
|
return {
|
|
@@ -65261,7 +65676,7 @@ function emptyScreen(cols, rows) {
|
|
|
65261
65676
|
function isBoxRule(line, cols) {
|
|
65262
65677
|
if (!line || !/^\u2500+(?: [^\u2500]+ \u2500+)?$/.test(line))
|
|
65263
65678
|
return false;
|
|
65264
|
-
return line.length >= Math.max(20,
|
|
65679
|
+
return line.length >= Math.max(20, cols - 1);
|
|
65265
65680
|
}
|
|
65266
65681
|
function boxTopRow(lines, cols) {
|
|
65267
65682
|
for (let i = lines.length - 2;i >= 0; i--) {
|
|
@@ -65285,22 +65700,26 @@ function withSize(s, rows) {
|
|
|
65285
65700
|
spans.push([]);
|
|
65286
65701
|
return { lines, spans };
|
|
65287
65702
|
}
|
|
65288
|
-
function aboveBoxText(
|
|
65289
|
-
const
|
|
65290
|
-
return
|
|
65291
|
-
`);
|
|
65703
|
+
function aboveBoxText(s) {
|
|
65704
|
+
const box = locateBox(s);
|
|
65705
|
+
return box ? s.lines.slice(0, box.top).join(`
|
|
65706
|
+
`) : null;
|
|
65292
65707
|
}
|
|
65293
65708
|
function finish(prev, next, now) {
|
|
65294
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]));
|
|
65295
65710
|
if (!visible)
|
|
65296
65711
|
return prev;
|
|
65297
|
-
const
|
|
65298
|
-
return {
|
|
65712
|
+
const out = {
|
|
65299
65713
|
...next,
|
|
65300
65714
|
seq: prev.seq + 1,
|
|
65301
65715
|
changedAt: now,
|
|
65302
|
-
aboveBoxChangedAt:
|
|
65716
|
+
aboveBoxChangedAt: prev.aboveBoxChangedAt
|
|
65303
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;
|
|
65304
65723
|
}
|
|
65305
65724
|
function applyFrame(s, frame, now = Date.now()) {
|
|
65306
65725
|
const rows = frame.rows;
|
|
@@ -65325,6 +65744,9 @@ function applyFrame(s, frame, now = Date.now()) {
|
|
|
65325
65744
|
alt: frame.alt ?? s.alt
|
|
65326
65745
|
}, now);
|
|
65327
65746
|
}
|
|
65747
|
+
var init_screen_model = __esm(() => {
|
|
65748
|
+
init_box_locate();
|
|
65749
|
+
});
|
|
65328
65750
|
|
|
65329
65751
|
// src/pane/screen-classifier.ts
|
|
65330
65752
|
function screenText(s) {
|
|
@@ -65334,18 +65756,44 @@ function screenText(s) {
|
|
|
65334
65756
|
return lines.join(`
|
|
65335
65757
|
`);
|
|
65336
65758
|
}
|
|
65337
|
-
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) {
|
|
65338
65772
|
if (!spans?.length)
|
|
65339
65773
|
return line;
|
|
65340
65774
|
const chars = Array.from(line);
|
|
65341
65775
|
for (const [col, len, , , attr] of spans) {
|
|
65342
|
-
if ((attr &
|
|
65776
|
+
if ((attr & ATTR_FAINT2) === 0)
|
|
65343
65777
|
continue;
|
|
65344
65778
|
for (let c = col;c < col + len && c < chars.length; c++)
|
|
65345
65779
|
chars[c] = " ";
|
|
65346
65780
|
}
|
|
65347
65781
|
return chars.join("");
|
|
65348
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
|
+
}
|
|
65349
65797
|
function inputBox(s) {
|
|
65350
65798
|
const top = boxTopRow(s.lines, s.cols);
|
|
65351
65799
|
if (top < 0)
|
|
@@ -65364,7 +65812,7 @@ function boxBottomRow(s, top) {
|
|
|
65364
65812
|
function boxText(s, top, bottom) {
|
|
65365
65813
|
const parts = [];
|
|
65366
65814
|
for (let i = top + 1;i < bottom; i++) {
|
|
65367
|
-
const raw =
|
|
65815
|
+
const raw = visibleText2(s.lines[i] ?? "", s.spans[i]);
|
|
65368
65816
|
const body = i === top + 1 ? raw.replace(/^\u276F\s?/, "") : raw.replace(/^ {2}/, "");
|
|
65369
65817
|
parts.push(body.replace(/\s+$/, ""));
|
|
65370
65818
|
}
|
|
@@ -65397,7 +65845,8 @@ function choiceDialog(s) {
|
|
|
65397
65845
|
const lines = s.lines;
|
|
65398
65846
|
const start = lastBulletRow(lines) + 1;
|
|
65399
65847
|
const below = lines.slice(start);
|
|
65400
|
-
const
|
|
65848
|
+
const flat = flatText(below);
|
|
65849
|
+
const kind = CHOICE_DIALOGS.find((d) => d.header.test(flat))?.kind;
|
|
65401
65850
|
if (!kind)
|
|
65402
65851
|
return null;
|
|
65403
65852
|
if (!below.some((l) => FIRST_OPTION.test(l)))
|
|
@@ -65405,14 +65854,19 @@ function choiceDialog(s) {
|
|
|
65405
65854
|
return { kind, text: below.filter((l) => l.trim()).join(`
|
|
65406
65855
|
`) };
|
|
65407
65856
|
}
|
|
65408
|
-
function
|
|
65409
|
-
return
|
|
65857
|
+
function dialogText(s) {
|
|
65858
|
+
return s.lines.slice(lastBulletRow(s.lines) + 1).filter((l) => l.trim()).join(`
|
|
65859
|
+
`);
|
|
65410
65860
|
}
|
|
65411
65861
|
function isWorking(s) {
|
|
65412
65862
|
const top = boxTopRow(s.lines, s.cols);
|
|
65413
65863
|
const region = top >= 0 ? s.lines.slice(0, top) : s.lines;
|
|
65414
65864
|
return region.some((l) => WORKING_ROW.test(l));
|
|
65415
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
|
+
}
|
|
65416
65870
|
function stopHookRunning(s) {
|
|
65417
65871
|
return s.lines.some((l) => /\(running Stop hook\b/.test(l));
|
|
65418
65872
|
}
|
|
@@ -65444,7 +65898,7 @@ function screenAnswer(s, echo) {
|
|
|
65444
65898
|
const lines = s.lines;
|
|
65445
65899
|
const top = boxTopRow(lines, s.cols);
|
|
65446
65900
|
const end = top >= 0 ? top : lines.length;
|
|
65447
|
-
const start = echoRow(lines, end,
|
|
65901
|
+
const start = echoRow(lines, end, echoHead(echo, s.cols)) + 1;
|
|
65448
65902
|
if (start <= 0)
|
|
65449
65903
|
return "";
|
|
65450
65904
|
const out = [];
|
|
@@ -65459,8 +65913,9 @@ function screenAnswer(s, echo) {
|
|
|
65459
65913
|
`).trim();
|
|
65460
65914
|
}
|
|
65461
65915
|
function echoRow(lines, end, head) {
|
|
65916
|
+
const above = lines.slice(0, end);
|
|
65462
65917
|
for (let i = end - 1;i >= 0; i--)
|
|
65463
|
-
if ((
|
|
65918
|
+
if (echoAt(above, i, head))
|
|
65464
65919
|
return i;
|
|
65465
65920
|
return -1;
|
|
65466
65921
|
}
|
|
@@ -65482,9 +65937,9 @@ function agentRejectedLine(text) {
|
|
|
65482
65937
|
const m = text.match(/--agent '([^']+)' not found\.(?: Available agents:[^\n]*)?/);
|
|
65483
65938
|
return m ? m[0] : null;
|
|
65484
65939
|
}
|
|
65485
|
-
function namedDialog(
|
|
65940
|
+
function namedDialog(flat) {
|
|
65486
65941
|
for (const d of NAMED_DIALOGS)
|
|
65487
|
-
if (
|
|
65942
|
+
if (flat.includes(d.marker))
|
|
65488
65943
|
return d.name;
|
|
65489
65944
|
return null;
|
|
65490
65945
|
}
|
|
@@ -65493,22 +65948,20 @@ function isUnnamedChoice(lines) {
|
|
|
65493
65948
|
const yesNo = lines.some((l) => /^\s*(\u276F\s*)?(\d+\.\s+)?(Yes|No)\b|\(esc\)/.test(l));
|
|
65494
65949
|
if (numbered && yesNo)
|
|
65495
65950
|
return true;
|
|
65496
|
-
return lines.some((l) => /Press Enter to continue/.test(l) ||
|
|
65497
|
-
}
|
|
65498
|
-
function
|
|
65499
|
-
const
|
|
65500
|
-
const box = inputBox(s);
|
|
65501
|
-
const named = namedDialog(text);
|
|
65502
|
-
if (box && !named)
|
|
65503
|
-
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));
|
|
65504
65955
|
if (named)
|
|
65505
|
-
return { kind: "dialog", name: named, text };
|
|
65956
|
+
return { kind: "dialog", name: named, text: screenText(s) };
|
|
65506
65957
|
if (isUnnamedChoice(s.lines))
|
|
65507
|
-
return { kind: "choice", text };
|
|
65958
|
+
return { kind: "choice", text: screenText(s) };
|
|
65508
65959
|
return { kind: "booting" };
|
|
65509
65960
|
}
|
|
65510
|
-
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;
|
|
65511
65962
|
var init_screen_classifier = __esm(() => {
|
|
65963
|
+
init_box_locate();
|
|
65964
|
+
init_screen_model();
|
|
65512
65965
|
NAMED_DIALOGS = [
|
|
65513
65966
|
{ name: "onboarding", marker: "Choose the text style" },
|
|
65514
65967
|
{ name: "trust", marker: "Is this a project you created or one you trust" },
|
|
@@ -65519,15 +65972,15 @@ var init_screen_classifier = __esm(() => {
|
|
|
65519
65972
|
{ kind: "permission", header: /\bDo you want to proceed\?/ },
|
|
65520
65973
|
{
|
|
65521
65974
|
kind: "permission",
|
|
65522
|
-
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}?\?/
|
|
65523
65976
|
},
|
|
65524
65977
|
{ kind: "plan", header: /\bWould you like to proceed\?/ },
|
|
65525
65978
|
{ kind: "question", header: /Enter to select \u00B7 \u2191\/\u2193 to navigate/ }
|
|
65526
65979
|
];
|
|
65527
65980
|
NUMBERED_OPTION = /^\s*(\u276F\s*)?\d+\.\s+\S/;
|
|
65528
65981
|
FIRST_OPTION = /^\s*(\u276F\s*)?1\.\s+\S/;
|
|
65529
|
-
|
|
65530
|
-
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*$/;
|
|
65531
65984
|
BULLET = /^\u23FA(\s|$)/;
|
|
65532
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/;
|
|
65533
65986
|
MENU_ROW = /^\s{2}\u276F \/\S|^\s{4}\/\S|^\s{4}[*+] \S/;
|
|
@@ -65536,7 +65989,7 @@ var init_screen_classifier = __esm(() => {
|
|
|
65536
65989
|
|
|
65537
65990
|
// src/pane/session-registry.ts
|
|
65538
65991
|
import { readFileSync as readFileSync29, readdirSync as readdirSync6 } from "fs";
|
|
65539
|
-
import { join as
|
|
65992
|
+
import { join as join46 } from "path";
|
|
65540
65993
|
function parseRegistryRecord(raw) {
|
|
65541
65994
|
let parsed;
|
|
65542
65995
|
try {
|
|
@@ -65581,7 +66034,7 @@ class SessionRegistry {
|
|
|
65581
66034
|
isAlive;
|
|
65582
66035
|
constructor(o) {
|
|
65583
66036
|
this.o = o;
|
|
65584
|
-
this.dir =
|
|
66037
|
+
this.dir = join46(o.configDir, "sessions");
|
|
65585
66038
|
this.now = o.now ?? Date.now;
|
|
65586
66039
|
this.isAlive = o.isAlive ?? pidAlive;
|
|
65587
66040
|
}
|
|
@@ -65617,7 +66070,7 @@ class SessionRegistry {
|
|
|
65617
66070
|
readPid(pid) {
|
|
65618
66071
|
let raw;
|
|
65619
66072
|
try {
|
|
65620
|
-
raw = readFileSync29(
|
|
66073
|
+
raw = readFileSync29(join46(this.dir, `${pid}.json`), "utf8");
|
|
65621
66074
|
} catch {
|
|
65622
66075
|
return null;
|
|
65623
66076
|
}
|
|
@@ -65662,14 +66115,28 @@ function activityOf(t) {
|
|
|
65662
66115
|
return "finishing";
|
|
65663
66116
|
return "thinking";
|
|
65664
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
|
+
}
|
|
65665
66128
|
function corroborated(input) {
|
|
65666
66129
|
const quiet = input.corroborationMs ?? CORROBORATION_MS;
|
|
65667
66130
|
if (input.chatQuietMs < quiet)
|
|
65668
66131
|
return { ok: false };
|
|
65669
|
-
if (!input.
|
|
66132
|
+
if (!input.facts)
|
|
65670
66133
|
return { ok: true, anomaly: "screen_unverified" };
|
|
65671
|
-
const
|
|
65672
|
-
|
|
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 };
|
|
65673
66140
|
}
|
|
65674
66141
|
function settledAs(by, stopReason, c, extra = []) {
|
|
65675
66142
|
return {
|
|
@@ -65702,10 +66169,13 @@ function pathPrimary(t, input) {
|
|
|
65702
66169
|
function pathSecondary(t, input) {
|
|
65703
66170
|
if (!endingStop(t) || !stopHooksFinished(t, input.session))
|
|
65704
66171
|
return null;
|
|
65705
|
-
if (!input.
|
|
66172
|
+
if (!input.facts)
|
|
65706
66173
|
return null;
|
|
65707
66174
|
const window2 = input.secondaryQuietMs ?? SECONDARY_QUIET_MS;
|
|
65708
|
-
if (input.transcriptQuietMs < window2
|
|
66175
|
+
if (input.transcriptQuietMs < window2)
|
|
66176
|
+
return null;
|
|
66177
|
+
const above = input.facts.aboveBoxQuietMs;
|
|
66178
|
+
if (above !== null && above < window2)
|
|
65709
66179
|
return null;
|
|
65710
66180
|
const c = corroborated(input);
|
|
65711
66181
|
return c.ok ? settledAs("quiet", t.lastAssistant?.stopReason ?? null, c, ["settled_without_turn_duration"]) : null;
|
|
@@ -65736,9 +66206,10 @@ function decideSettle(input) {
|
|
|
65736
66206
|
return endingStop(t) ? settledAs("exit", t.lastAssistant.stopReason, {}) : notYet;
|
|
65737
66207
|
return pathSecondary(t, input) ?? notYet;
|
|
65738
66208
|
}
|
|
65739
|
-
var SECONDARY_QUIET_MS = 32000, CORROBORATION_MS = 500, CONTINUING;
|
|
66209
|
+
var SECONDARY_QUIET_MS = 32000, CORROBORATION_MS = 500, CONTINUING, CORROBORATION_GRACE_MS;
|
|
65740
66210
|
var init_settle_rule = __esm(() => {
|
|
65741
66211
|
CONTINUING = new Set(["tool_use", "pause_turn"]);
|
|
66212
|
+
CORROBORATION_GRACE_MS = SECONDARY_QUIET_MS;
|
|
65742
66213
|
});
|
|
65743
66214
|
|
|
65744
66215
|
// src/pane/slot-state.ts
|
|
@@ -65879,10 +66350,10 @@ import {
|
|
|
65879
66350
|
openSync as openSync8,
|
|
65880
66351
|
readSync as readSync3,
|
|
65881
66352
|
readdirSync as readdirSync7,
|
|
65882
|
-
realpathSync as
|
|
66353
|
+
realpathSync as realpathSync3,
|
|
65883
66354
|
statSync as statSync9
|
|
65884
66355
|
} from "fs";
|
|
65885
|
-
import { join as
|
|
66356
|
+
import { join as join47 } from "path";
|
|
65886
66357
|
function initialFollowerState(resolvePath = safeRealpath) {
|
|
65887
66358
|
return {
|
|
65888
66359
|
turns: [],
|
|
@@ -65897,7 +66368,7 @@ function initialFollowerState(resolvePath = safeRealpath) {
|
|
|
65897
66368
|
}
|
|
65898
66369
|
function safeRealpath(p) {
|
|
65899
66370
|
try {
|
|
65900
|
-
return
|
|
66371
|
+
return realpathSync3(p);
|
|
65901
66372
|
} catch {
|
|
65902
66373
|
return p;
|
|
65903
66374
|
}
|
|
@@ -66410,7 +66881,7 @@ class TranscriptFollower {
|
|
|
66410
66881
|
for (const f of this.subagentFiles()) {
|
|
66411
66882
|
let tail = this.subs.get(f);
|
|
66412
66883
|
if (!tail) {
|
|
66413
|
-
tail = new Tail(
|
|
66884
|
+
tail = new Tail(join47(this.subagentsDir, f));
|
|
66414
66885
|
this.subs.set(f, tail);
|
|
66415
66886
|
}
|
|
66416
66887
|
for (const { line } of tail.read()) {
|
|
@@ -66493,8 +66964,8 @@ var init_transcript_follower = __esm(() => {
|
|
|
66493
66964
|
});
|
|
66494
66965
|
|
|
66495
66966
|
// src/pane/pane-session.ts
|
|
66496
|
-
import { readFileSync as readFileSync30, realpathSync as
|
|
66497
|
-
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";
|
|
66498
66969
|
function iso(ms) {
|
|
66499
66970
|
return new Date(ms).toISOString();
|
|
66500
66971
|
}
|
|
@@ -66531,7 +67002,7 @@ class PaneSessionImpl {
|
|
|
66531
67002
|
initialPending;
|
|
66532
67003
|
shape;
|
|
66533
67004
|
queue = [];
|
|
66534
|
-
screen
|
|
67005
|
+
screen;
|
|
66535
67006
|
final = false;
|
|
66536
67007
|
turnIndex = 0;
|
|
66537
67008
|
admission = null;
|
|
@@ -66567,8 +67038,25 @@ class PaneSessionImpl {
|
|
|
66567
67038
|
disagreeCounted = new Set;
|
|
66568
67039
|
exitScrollback = "";
|
|
66569
67040
|
exitLastLine = "";
|
|
66570
|
-
|
|
66571
|
-
|
|
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;
|
|
66572
67060
|
magmux = null;
|
|
66573
67061
|
watcher = null;
|
|
66574
67062
|
client = null;
|
|
@@ -66599,12 +67087,16 @@ class PaneSessionImpl {
|
|
|
66599
67087
|
this.turnDir = ids.turnDir;
|
|
66600
67088
|
this.identity = { paneId: ids.paneId, sessionUuid: o.sessionUuid, ctlDir: ids.ctlDir };
|
|
66601
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);
|
|
66602
67094
|
this.initialPending = !!o.initialPrompt;
|
|
66603
67095
|
if (o.initialPrompt)
|
|
66604
67096
|
this.queue.push(o.initialPrompt);
|
|
66605
67097
|
this.secondaryQuietMs = o.timings?.secondaryQuietMs ?? SECONDARY_QUIET_MS;
|
|
66606
67098
|
this.corroborationMs = o.timings?.corroborationMs ?? CORROBORATION_MS;
|
|
66607
|
-
this.follower = new TranscriptFollower(o.transcriptPath,
|
|
67099
|
+
this.follower = new TranscriptFollower(o.transcriptPath, join48(o.transcriptPath.replace(/\.jsonl$/, ""), "subagents"));
|
|
66608
67100
|
this.registry = new SessionRegistry({
|
|
66609
67101
|
configDir: claudeConfigDir(o.parentEnv ?? process.env),
|
|
66610
67102
|
sessionUuid: o.sessionUuid
|
|
@@ -66640,7 +67132,9 @@ class PaneSessionImpl {
|
|
|
66640
67132
|
sockRoot: this.root,
|
|
66641
67133
|
ctlDir: this.ctlDir,
|
|
66642
67134
|
cwd: input.cwd,
|
|
66643
|
-
env: input.env
|
|
67135
|
+
env: input.env,
|
|
67136
|
+
sessionUuid: this.o.sessionUuid,
|
|
67137
|
+
transcriptPath: this.o.transcriptPath
|
|
66644
67138
|
});
|
|
66645
67139
|
} catch (e) {
|
|
66646
67140
|
return this.spawnFailed(e);
|
|
@@ -66649,7 +67143,7 @@ class PaneSessionImpl {
|
|
|
66649
67143
|
return this.spawnFailed(new Error("magmux did not start"));
|
|
66650
67144
|
this.magmux = proc;
|
|
66651
67145
|
try {
|
|
66652
|
-
writeFileSync21(
|
|
67146
|
+
writeFileSync21(join48(this.ctlDir, "magmux.pid"), `${proc.pid}
|
|
66653
67147
|
`, { mode: 384 });
|
|
66654
67148
|
} catch {}
|
|
66655
67149
|
updateRecord(this.root, this.paneId, { magmuxPid: proc.pid });
|
|
@@ -66657,6 +67151,7 @@ class PaneSessionImpl {
|
|
|
66657
67151
|
proc.stderr?.on("data", (d) => this.onStderr(d));
|
|
66658
67152
|
proc.on("exit", (code, sig) => this.onMagmuxExit(code, sig));
|
|
66659
67153
|
this.ticker = setInterval(() => this.step(() => this.evaluate()), TICK_MS);
|
|
67154
|
+
this.gateTimer = setInterval(() => this.pollGate(), GATE_POLL_MS);
|
|
66660
67155
|
if (this.o.timeoutMs !== undefined)
|
|
66661
67156
|
this.timeoutTimer = setTimeout(() => this.step(() => this.fire("timeout")), Math.max(0, this.o.timeoutMs));
|
|
66662
67157
|
await this.connectFirst();
|
|
@@ -66686,7 +67181,6 @@ class PaneSessionImpl {
|
|
|
66686
67181
|
client.close();
|
|
66687
67182
|
return;
|
|
66688
67183
|
}
|
|
66689
|
-
this.client = client;
|
|
66690
67184
|
client.on("snapshot", (e) => this.onSnapshot(e));
|
|
66691
67185
|
client.on("frame", (f) => this.onFrame(f));
|
|
66692
67186
|
client.on("exit", (e) => void this.onPaneExit(e));
|
|
@@ -66698,8 +67192,15 @@ class PaneSessionImpl {
|
|
|
66698
67192
|
const caps = await client.request({
|
|
66699
67193
|
type: "capabilities"
|
|
66700
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 ?? "") : "";
|
|
66701
67202
|
if (caps.ok) {
|
|
66702
|
-
const v =
|
|
67203
|
+
const v = magmuxVersion;
|
|
66703
67204
|
if (caps.result.protocol !== 1 || !versionAtLeast(v, MIN_MAGMUX_VERSION)) {
|
|
66704
67205
|
this.step(() => this.fire("pane_lost", {
|
|
66705
67206
|
detail: `magmux_unavailable: magmux ${v || "?"} protocol ${caps.result.protocol ?? "?"}; panes need >= ${MIN_MAGMUX_VERSION}, protocol 1`
|
|
@@ -66707,6 +67208,9 @@ class PaneSessionImpl {
|
|
|
66707
67208
|
return;
|
|
66708
67209
|
}
|
|
66709
67210
|
}
|
|
67211
|
+
this.lastSentSize = null;
|
|
67212
|
+
if (this.supportsResize && !samePaneSize(this.appliedSize, this.desiredSize))
|
|
67213
|
+
this.kickResize();
|
|
66710
67214
|
await client.request({ type: "watch", pane: 0, mode: "frames", fps: WATCH_FPS });
|
|
66711
67215
|
const list = await client.request({ type: "list" });
|
|
66712
67216
|
const p0 = list.ok ? list.result.panes?.find((p) => p.pane === 0) : undefined;
|
|
@@ -66716,7 +67220,76 @@ class PaneSessionImpl {
|
|
|
66716
67220
|
if (!reconnect)
|
|
66717
67221
|
await this.nextFrame(500);
|
|
66718
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;
|
|
66719
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;
|
|
66720
67293
|
}
|
|
66721
67294
|
onStderr(d) {
|
|
66722
67295
|
if (this.stderrHead.length < 8192)
|
|
@@ -66739,7 +67312,10 @@ class PaneSessionImpl {
|
|
|
66739
67312
|
onFrame(f) {
|
|
66740
67313
|
if (f.pane !== undefined && f.pane !== 0)
|
|
66741
67314
|
return;
|
|
67315
|
+
const seq = this.screen.seq;
|
|
66742
67316
|
this.screen = applyFrame(this.screen, f);
|
|
67317
|
+
if (this.screen.seq !== seq && !this.inResizeQuiet(this.screen.changedAt))
|
|
67318
|
+
this.activityChangedAt = this.screen.changedAt;
|
|
66743
67319
|
this.framePending = true;
|
|
66744
67320
|
if (!this.claudeCodeVersion) {
|
|
66745
67321
|
const m = this.screen.lines.join(`
|
|
@@ -66750,8 +67326,11 @@ class PaneSessionImpl {
|
|
|
66750
67326
|
this.step(() => this.evaluate());
|
|
66751
67327
|
}
|
|
66752
67328
|
onDisconnected(client) {
|
|
66753
|
-
if (this.client === client)
|
|
67329
|
+
if (this.client === client) {
|
|
66754
67330
|
this.client = null;
|
|
67331
|
+
this.gate = null;
|
|
67332
|
+
this.gateTrusted = false;
|
|
67333
|
+
}
|
|
66755
67334
|
if (this.reaping || !alive(this.magmux))
|
|
66756
67335
|
return;
|
|
66757
67336
|
if (isTerminalPhase(this.phase))
|
|
@@ -66943,11 +67522,15 @@ class PaneSessionImpl {
|
|
|
66943
67522
|
if (!this.client)
|
|
66944
67523
|
return;
|
|
66945
67524
|
const idle = status === "idle";
|
|
66946
|
-
const dialog = hasChoiceDialog(this.screen);
|
|
66947
|
-
this.disagree("registry_idle_screen_booting", this.phase === "BOOTING" && idle && readBoot(this.screen).kind !== "repl", now);
|
|
66948
67525
|
this.disagree("registry_idle_screen_working", this.phase === "RUNNING" && idle && isWorking(this.screen), now);
|
|
66949
|
-
this.
|
|
66950
|
-
|
|
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);
|
|
66951
67534
|
}
|
|
66952
67535
|
disagree(key, holds, now, forMs = REGISTRY_DISAGREE_MS) {
|
|
66953
67536
|
if (!holds) {
|
|
@@ -66983,33 +67566,42 @@ class PaneSessionImpl {
|
|
|
66983
67566
|
}
|
|
66984
67567
|
evalBoot() {
|
|
66985
67568
|
const now = Date.now();
|
|
66986
|
-
const
|
|
66987
|
-
if (
|
|
66988
|
-
this.bootKind = r.kind;
|
|
66989
|
-
this.bootKindSince = now;
|
|
66990
|
-
}
|
|
66991
|
-
const staticFor = this.screen.seq === 0 ? 0 : now - this.screen.changedAt;
|
|
66992
|
-
const staticMs = this.t("bootStaticMs", BOOT_STATIC_MS);
|
|
66993
|
-
if (r.kind === "repl" && now - this.bootKindSince >= this.t("replStableMs", REPL_STABLE_MS)) {
|
|
67569
|
+
const g = this.gateNow();
|
|
67570
|
+
if (g?.ready) {
|
|
66994
67571
|
this.bootReady();
|
|
66995
67572
|
return;
|
|
66996
67573
|
}
|
|
66997
|
-
|
|
66998
|
-
|
|
66999
|
-
|
|
67000
|
-
|
|
67001
|
-
|
|
67002
|
-
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 });
|
|
67003
67579
|
return;
|
|
67004
67580
|
}
|
|
67005
67581
|
if (now - this.startedAtMs >= (this.o.bootTimeoutMs ?? BOOT_TIMEOUT_MS)) {
|
|
67006
|
-
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";
|
|
67007
67584
|
this.fire("boot_deadline", {
|
|
67008
67585
|
reason: blocked ? "boot_blocked" : "boot_timeout",
|
|
67009
|
-
detail: screenTailOf(this.screen)
|
|
67586
|
+
detail: `${screenTailOf(this.screen)}
|
|
67587
|
+
${gate}`
|
|
67010
67588
|
});
|
|
67011
67589
|
}
|
|
67012
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
|
+
}
|
|
67013
67605
|
bootReady() {
|
|
67014
67606
|
this.bootReadyAtMs = Date.now();
|
|
67015
67607
|
if (this.queue.length === 0) {
|
|
@@ -67035,7 +67627,7 @@ class PaneSessionImpl {
|
|
|
67035
67627
|
const head = this.queue.shift();
|
|
67036
67628
|
if (isControl(head)) {
|
|
67037
67629
|
this.exitRequested = true;
|
|
67038
|
-
this.
|
|
67630
|
+
this.submitControl(head.trim());
|
|
67039
67631
|
return;
|
|
67040
67632
|
}
|
|
67041
67633
|
this.fire("admit");
|
|
@@ -67059,6 +67651,9 @@ class PaneSessionImpl {
|
|
|
67059
67651
|
this.screenTurn = null;
|
|
67060
67652
|
this.rewakeOfSettled = false;
|
|
67061
67653
|
this.settledChatOffset = null;
|
|
67654
|
+
this.turnAcceptedAt = null;
|
|
67655
|
+
this.witnessMissingCounted = false;
|
|
67656
|
+
this.abandonedIndex = null;
|
|
67062
67657
|
if (plan.mode === "refused" || plan.mode === "control") {
|
|
67063
67658
|
this.anomaly(`delivery_refused:${plan.mode === "refused" ? plan.reason : "control"}`);
|
|
67064
67659
|
this.admission = null;
|
|
@@ -67074,79 +67669,385 @@ class PaneSessionImpl {
|
|
|
67074
67669
|
}
|
|
67075
67670
|
const delivery = (plan.mode === "file" || plan.mode === "command") && plan.file && plan.fileContent !== undefined ? { file: plan.file, text: plan.fileContent } : null;
|
|
67076
67671
|
this.follower.openTurn({ index, offset, witness: plan.witness, delivery });
|
|
67077
|
-
this.
|
|
67078
|
-
|
|
67079
|
-
|
|
67080
|
-
|
|
67081
|
-
|
|
67082
|
-
|
|
67083
|
-
|
|
67084
|
-
resent: false,
|
|
67085
|
-
panelEscaped: false,
|
|
67086
|
-
degraded: false
|
|
67087
|
-
};
|
|
67088
|
-
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";
|
|
67089
67679
|
}
|
|
67090
|
-
async
|
|
67091
|
-
|
|
67092
|
-
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
|
+
}
|
|
67093
67701
|
}
|
|
67094
|
-
|
|
67095
|
-
|
|
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)
|
|
67096
67713
|
return false;
|
|
67097
|
-
|
|
67098
|
-
|
|
67099
|
-
|
|
67100
|
-
|
|
67101
|
-
|
|
67102
|
-
|
|
67103
|
-
|
|
67104
|
-
|
|
67105
|
-
|
|
67106
|
-
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;
|
|
67107
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 });
|
|
67108
67730
|
return true;
|
|
67109
67731
|
}
|
|
67110
|
-
async
|
|
67111
|
-
|
|
67112
|
-
|
|
67113
|
-
|
|
67114
|
-
|
|
67115
|
-
|
|
67116
|
-
if (
|
|
67117
|
-
|
|
67118
|
-
|
|
67119
|
-
|
|
67120
|
-
if (await this.landedAfterLostReply(text, enter))
|
|
67121
|
-
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;
|
|
67122
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;
|
|
67123
67796
|
}
|
|
67124
|
-
await Bun.sleep(500);
|
|
67125
67797
|
}
|
|
67126
|
-
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
|
+
}
|
|
67127
67833
|
return false;
|
|
67128
67834
|
}
|
|
67129
|
-
async
|
|
67130
|
-
|
|
67131
|
-
|
|
67132
|
-
|
|
67133
|
-
|
|
67134
|
-
|
|
67135
|
-
|
|
67136
|
-
if (
|
|
67137
|
-
|
|
67138
|
-
|
|
67139
|
-
|
|
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;
|
|
67140
68037
|
}
|
|
67141
|
-
|
|
67142
|
-
|
|
67143
|
-
|
|
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}` : ""}`);
|
|
67144
68045
|
}
|
|
67145
68046
|
async key(k) {
|
|
67146
68047
|
const c = this.client;
|
|
67147
68048
|
if (!c)
|
|
67148
68049
|
return false;
|
|
67149
|
-
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);
|
|
67150
68051
|
return r.ok;
|
|
67151
68052
|
}
|
|
67152
68053
|
nextFrame(ms) {
|
|
@@ -67166,139 +68067,134 @@ class PaneSessionImpl {
|
|
|
67166
68067
|
const adm = this.admission;
|
|
67167
68068
|
if (!adm)
|
|
67168
68069
|
return;
|
|
67169
|
-
|
|
67170
|
-
if (cur && cur.index === adm.index && cur.acceptedAt !== null) {
|
|
68070
|
+
if (this.witnessed(view.current)) {
|
|
67171
68071
|
this.accept();
|
|
67172
68072
|
return;
|
|
67173
68073
|
}
|
|
67174
|
-
|
|
67175
|
-
|
|
67176
|
-
if (
|
|
68074
|
+
if (adm.panel)
|
|
68075
|
+
this.panelStep(adm);
|
|
68076
|
+
if (!this.admitting(adm))
|
|
67177
68077
|
return;
|
|
67178
|
-
if (adm.
|
|
67179
|
-
this.nudge(adm);
|
|
67180
|
-
if (adm.deliveredAt && (view.availability === "off" || since >= this.t("degradedEntryMs", DEGRADED_ENTRY_MS)))
|
|
67181
|
-
this.maybeDegradedAccept(adm, view);
|
|
67182
|
-
if (this.phase !== "ADMITTING")
|
|
67183
|
-
return;
|
|
67184
|
-
if (now - adm.startedAt >= (this.o.admitTimeoutMs ?? ADMIT_TIMEOUT_MS))
|
|
68078
|
+
if (Date.now() >= adm.deadline && !adm.inFlight)
|
|
67185
68079
|
this.admitExpired(adm);
|
|
67186
68080
|
}
|
|
67187
|
-
|
|
67188
|
-
return
|
|
68081
|
+
panelShowing(g) {
|
|
68082
|
+
return !!g && (g.reason === "no_input_box" || g.dialog === "select") && /Esc to cancel/.test(flatText(this.screen.lines));
|
|
67189
68083
|
}
|
|
67190
|
-
|
|
67191
|
-
|
|
67192
|
-
|
|
67193
|
-
return false;
|
|
67194
|
-
adm.panelEscaped = true;
|
|
67195
|
-
this.anomaly("panel_dismissed");
|
|
67196
|
-
this.key("escape");
|
|
67197
|
-
return true;
|
|
67198
|
-
}
|
|
67199
|
-
const box = inputBox(this.screen);
|
|
67200
|
-
if (!box || box.text !== "" || this.panelOpen())
|
|
67201
|
-
return false;
|
|
67202
|
-
this.admission = null;
|
|
67203
|
-
this.anomaly("panel_command");
|
|
67204
|
-
if (adm.initial)
|
|
67205
|
-
this.fire("admit_deadline", {
|
|
67206
|
-
detail: `${adm.text.trim()} opened a panel and wrote no transcript record`
|
|
67207
|
-
});
|
|
67208
|
-
else
|
|
67209
|
-
this.fire("admit_abandoned");
|
|
67210
|
-
return true;
|
|
67211
|
-
}
|
|
67212
|
-
async awaitClearedBox(adm, head) {
|
|
67213
|
-
const end = Date.now() + this.t("nudgeClearDeadlineMs", NUDGE_CLEAR_DEADLINE_MS);
|
|
67214
|
-
for (;; ) {
|
|
67215
|
-
if (this.admission !== adm || this.phase !== "ADMITTING")
|
|
67216
|
-
return "gone";
|
|
67217
|
-
const box = inputBox(this.screen);
|
|
67218
|
-
if (box && box.text === "")
|
|
67219
|
-
return "empty";
|
|
67220
|
-
if (box && !box.text.startsWith(head))
|
|
67221
|
-
return "other";
|
|
67222
|
-
const left = end - Date.now();
|
|
67223
|
-
if (left <= 0)
|
|
67224
|
-
return box ? "line" : "other";
|
|
67225
|
-
await this.nextFrame(left);
|
|
67226
|
-
}
|
|
67227
|
-
}
|
|
67228
|
-
nudge(adm) {
|
|
67229
|
-
const box = inputBox(this.screen);
|
|
67230
|
-
const line = adm.plan.mode === "control" || adm.plan.mode === "refused" ? "" : adm.plan.line;
|
|
67231
|
-
const head = line.slice(0, 40);
|
|
67232
|
-
if (!adm.resent && box && line && box.text.startsWith(head)) {
|
|
67233
|
-
adm.resent = true;
|
|
67234
|
-
this.anomaly("resent_enter");
|
|
67235
|
-
(async () => {
|
|
67236
|
-
if (box.menuOpen)
|
|
67237
|
-
await this.key("escape");
|
|
67238
|
-
await this.key("ctrl-u");
|
|
67239
|
-
const after = await this.awaitClearedBox(adm, head);
|
|
67240
|
-
if (after === "gone")
|
|
67241
|
-
return;
|
|
67242
|
-
if (after === "empty") {
|
|
67243
|
-
this.anomaly("retyped_prompt");
|
|
67244
|
-
await this.typeAndSubmit(adm.plan);
|
|
67245
|
-
} else if (after === "line") {
|
|
67246
|
-
await this.key("enter");
|
|
67247
|
-
} else {
|
|
67248
|
-
this.anomaly("clear_failed");
|
|
67249
|
-
}
|
|
67250
|
-
})();
|
|
68084
|
+
panelStep(adm) {
|
|
68085
|
+
const p = adm.panel;
|
|
68086
|
+
if (!p)
|
|
67251
68087
|
return;
|
|
67252
|
-
|
|
67253
|
-
if (!
|
|
67254
|
-
|
|
67255
|
-
|
|
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");
|
|
67256
68100
|
this.key("escape");
|
|
67257
|
-
}
|
|
67258
|
-
}
|
|
67259
|
-
maybeDegradedAccept(adm, view) {
|
|
67260
|
-
if (view.availability === "ok")
|
|
67261
68101
|
return;
|
|
67262
|
-
|
|
67263
|
-
if (!
|
|
68102
|
+
}
|
|
68103
|
+
if (!g)
|
|
67264
68104
|
return;
|
|
67265
|
-
|
|
67266
|
-
|
|
67267
|
-
|
|
67268
|
-
|
|
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");
|
|
67269
68114
|
return;
|
|
67270
|
-
|
|
67271
|
-
|
|
67272
|
-
|
|
67273
|
-
this.accept();
|
|
68115
|
+
}
|
|
68116
|
+
if (!p.entered && g.reason === "box_not_empty")
|
|
68117
|
+
adm.panel = null;
|
|
67274
68118
|
}
|
|
67275
68119
|
accept() {
|
|
67276
68120
|
this.admission = null;
|
|
67277
68121
|
this.initialDelivery = false;
|
|
67278
|
-
|
|
68122
|
+
const now = Date.now();
|
|
68123
|
+
this.lastChatSeenAt = now;
|
|
68124
|
+
this.turnAcceptedAt = now;
|
|
68125
|
+
this.turnErrorLogSize = this.errorLogSize();
|
|
67279
68126
|
this.fire("prompt_accepted");
|
|
67280
68127
|
}
|
|
67281
68128
|
admitExpired(adm) {
|
|
67282
68129
|
this.admission = null;
|
|
67283
68130
|
if (adm.initial) {
|
|
67284
|
-
this.fire("admit_deadline", {
|
|
68131
|
+
this.fire("admit_deadline", {
|
|
68132
|
+
detail: `${this.notAcceptedLine(adm)}
|
|
68133
|
+
${screenTailOf(this.screen)}`
|
|
68134
|
+
});
|
|
67285
68135
|
return;
|
|
67286
68136
|
}
|
|
67287
68137
|
this.anomaly("send_not_accepted");
|
|
68138
|
+
this.abandonedIndex = adm.index;
|
|
67288
68139
|
this.fire("admit_abandoned");
|
|
67289
68140
|
}
|
|
67290
|
-
|
|
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() {
|
|
67291
68161
|
if (!this.client)
|
|
67292
68162
|
return null;
|
|
67293
|
-
const
|
|
68163
|
+
const g = this.gateNow();
|
|
67294
68164
|
return {
|
|
67295
|
-
|
|
67296
|
-
|
|
67297
|
-
|
|
67298
|
-
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()
|
|
67299
68168
|
};
|
|
67300
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
|
+
}
|
|
67301
68195
|
evalRunning(view) {
|
|
68196
|
+
if (this.turnSource === "transcript")
|
|
68197
|
+
this.checkUnwitnessed(view);
|
|
67302
68198
|
if (this.turnSource === "screen") {
|
|
67303
68199
|
this.evalScreenTurn(view);
|
|
67304
68200
|
return;
|
|
@@ -67318,22 +68214,24 @@ class PaneSessionImpl {
|
|
|
67318
68214
|
if (this.detectBlocked(t))
|
|
67319
68215
|
return;
|
|
67320
68216
|
const now = Date.now();
|
|
68217
|
+
const transcriptQuietMs = now - (view.lastAppendAt ?? this.startedAtMs);
|
|
67321
68218
|
const decision = decideSettle({
|
|
67322
68219
|
turn: t,
|
|
67323
68220
|
session: view.session,
|
|
67324
|
-
transcriptQuietMs
|
|
68221
|
+
transcriptQuietMs,
|
|
67325
68222
|
chatQuietMs: now - this.lastChatSeenAt,
|
|
67326
|
-
|
|
68223
|
+
facts: this.corroborationFacts(),
|
|
67327
68224
|
paneExited: false,
|
|
67328
68225
|
secondaryQuietMs: this.secondaryQuietMs,
|
|
67329
|
-
corroborationMs: this.corroborationMs
|
|
68226
|
+
corroborationMs: this.corroborationMs,
|
|
68227
|
+
corroborationGraceMs: this.t("gateGraceMs", GATE_GRACE_MS)
|
|
67330
68228
|
});
|
|
67331
68229
|
if (decision.settled) {
|
|
67332
68230
|
this.settle(t, decision, null);
|
|
67333
68231
|
return;
|
|
67334
68232
|
}
|
|
67335
68233
|
this.activity = decision.activity;
|
|
67336
|
-
this.checkTurnEndMissing();
|
|
68234
|
+
this.checkTurnEndMissing(t, transcriptQuietMs);
|
|
67337
68235
|
this.checkAgentCountMismatch(t);
|
|
67338
68236
|
}
|
|
67339
68237
|
checkEscape() {
|
|
@@ -67344,14 +68242,14 @@ class PaneSessionImpl {
|
|
|
67344
68242
|
this.anomaly("escape_not_effective");
|
|
67345
68243
|
this.escapeSentAt = null;
|
|
67346
68244
|
}
|
|
67347
|
-
checkTurnEndMissing() {
|
|
67348
|
-
if (this.activity !== "finishing") {
|
|
68245
|
+
checkTurnEndMissing(t, transcriptQuietMs) {
|
|
68246
|
+
if (this.activity !== "finishing" || t.turnDurationAfterLast || t.interruptAfterLast) {
|
|
67349
68247
|
this.turnEndMissing = false;
|
|
67350
68248
|
return;
|
|
67351
68249
|
}
|
|
67352
68250
|
if (!this.client)
|
|
67353
68251
|
return;
|
|
67354
|
-
const quiet =
|
|
68252
|
+
const quiet = this.aboveBoxQuietMs() ?? transcriptQuietMs;
|
|
67355
68253
|
const missing = quiet >= TURN_END_MISSING_FACTOR * this.secondaryQuietMs && !stopHookRunning(this.screen);
|
|
67356
68254
|
if (missing && !this.turnEndMissing)
|
|
67357
68255
|
this.anomaly("turn_end_record_missing");
|
|
@@ -67371,14 +68269,19 @@ class PaneSessionImpl {
|
|
|
67371
68269
|
let kind = null;
|
|
67372
68270
|
if (pending.name === "AskUserQuestion")
|
|
67373
68271
|
kind = "question";
|
|
67374
|
-
else
|
|
67375
|
-
|
|
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
|
+
}
|
|
67376
68279
|
if (!kind)
|
|
67377
68280
|
return false;
|
|
67378
68281
|
this.blockedToolId = pending.id;
|
|
67379
68282
|
this.fire(kind === "question" ? "blocked_question" : "blocked_permission");
|
|
67380
68283
|
this.activity = pending.name;
|
|
67381
|
-
const text = blockText3(pending,
|
|
68284
|
+
const text = blockText3(pending, this.screen.seq > 0 ? dialogText(this.screen) || null : null);
|
|
67382
68285
|
let v;
|
|
67383
68286
|
try {
|
|
67384
68287
|
v = this.o.onBlocked({ kind, tool: pending.name, text });
|
|
@@ -67391,6 +68294,16 @@ class PaneSessionImpl {
|
|
|
67391
68294
|
}
|
|
67392
68295
|
evalIdle(view) {
|
|
67393
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
|
+
}
|
|
67394
68307
|
if (!t || this.settledChatOffset === null || this.exitRequested)
|
|
67395
68308
|
return;
|
|
67396
68309
|
if (t.lastChatOffset !== null && t.lastChatOffset > this.settledChatOffset) {
|
|
@@ -67469,10 +68382,10 @@ class PaneSessionImpl {
|
|
|
67469
68382
|
return !!t && t.index === this.turnIndex && t.acceptedAt !== null;
|
|
67470
68383
|
}
|
|
67471
68384
|
screenSettleReady(view, answer, apiError) {
|
|
67472
|
-
const
|
|
67473
|
-
if (!
|
|
68385
|
+
const g = this.gateNow();
|
|
68386
|
+
if (!g || !g.ready || g.dialog !== null || workingAboveBox(this.screen) === true)
|
|
67474
68387
|
return false;
|
|
67475
|
-
const quiet = Date.now() - this.screen.
|
|
68388
|
+
const quiet = this.aboveBoxQuietMs() ?? Date.now() - this.screen.changedAt;
|
|
67476
68389
|
if (view.availability === "off" && quiet >= this.secondaryQuietMs)
|
|
67477
68390
|
return true;
|
|
67478
68391
|
return (!!answer || !!apiError) && quiet >= 2 * this.t("screenSettleQuietMs", SCREEN_SETTLE_QUIET_MS);
|
|
@@ -67551,7 +68464,7 @@ class PaneSessionImpl {
|
|
|
67551
68464
|
session: view.session,
|
|
67552
68465
|
transcriptQuietMs: Number.MAX_SAFE_INTEGER,
|
|
67553
68466
|
chatQuietMs: Number.MAX_SAFE_INTEGER,
|
|
67554
|
-
|
|
68467
|
+
facts: null,
|
|
67555
68468
|
paneExited: true,
|
|
67556
68469
|
secondaryQuietMs: this.secondaryQuietMs,
|
|
67557
68470
|
corroborationMs: 0
|
|
@@ -67601,7 +68514,7 @@ ${screenTailOf(this.screen)}`
|
|
|
67601
68514
|
snapshot() {
|
|
67602
68515
|
const view = this.follower.view();
|
|
67603
68516
|
const terminal = isTerminalPhase(this.phase);
|
|
67604
|
-
const lastAct = Math.max(this.
|
|
68517
|
+
const lastAct = Math.max(this.activityChangedAt, view.lastAppendAt ?? 0);
|
|
67605
68518
|
const cur = view.current;
|
|
67606
68519
|
const hasTranscript = view.availability === "ok" && view.usage.tokensIn + view.usage.tokensOut > 0;
|
|
67607
68520
|
return {
|
|
@@ -67686,6 +68599,115 @@ ${screenTailOf(this.screen)}`
|
|
|
67686
68599
|
return { ok: false, reason: "terminal" };
|
|
67687
68600
|
return { ok: true, queued: this.queue.length };
|
|
67688
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
|
+
}
|
|
67689
68711
|
turnAnswer(index) {
|
|
67690
68712
|
const done = this.answers.get(index);
|
|
67691
68713
|
if (done !== undefined)
|
|
@@ -67701,6 +68723,7 @@ ${screenTailOf(this.screen)}`
|
|
|
67701
68723
|
diagnostics() {
|
|
67702
68724
|
const cur = this.follower.view().current;
|
|
67703
68725
|
const rec = this.registryRec;
|
|
68726
|
+
const g = this.gate;
|
|
67704
68727
|
return {
|
|
67705
68728
|
magmuxStderr: this.stderrHead,
|
|
67706
68729
|
registry: rec ? { status: rec.status, waitingFor: rec.waitingFor, version: rec.version } : null,
|
|
@@ -67710,7 +68733,9 @@ ${screenTailOf(this.screen)}`
|
|
|
67710
68733
|
linesReturned: cur.readCoverage.linesReturned,
|
|
67711
68734
|
complete: cur.readCoverage.complete,
|
|
67712
68735
|
reads: cur.readCoverage.reads
|
|
67713
|
-
} : 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
|
|
67714
68739
|
};
|
|
67715
68740
|
}
|
|
67716
68741
|
cancel() {
|
|
@@ -67767,6 +68792,9 @@ ${screenTailOf(this.screen)}`
|
|
|
67767
68792
|
if (this.ticker)
|
|
67768
68793
|
clearInterval(this.ticker);
|
|
67769
68794
|
this.ticker = null;
|
|
68795
|
+
if (this.gateTimer)
|
|
68796
|
+
clearInterval(this.gateTimer);
|
|
68797
|
+
this.gateTimer = null;
|
|
67770
68798
|
await this.captureGroupBeforeReap();
|
|
67771
68799
|
const c = this.client;
|
|
67772
68800
|
if (c && !c.isClosed && !this.paneClosed) {
|
|
@@ -67878,6 +68906,94 @@ function signalQuietly(target, sig) {
|
|
|
67878
68906
|
process.kill(target, sig);
|
|
67879
68907
|
} catch {}
|
|
67880
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
|
+
}
|
|
67881
68997
|
function isControl(text) {
|
|
67882
68998
|
const t = text.trim();
|
|
67883
68999
|
return t === "/exit" || t === "/quit";
|
|
@@ -67897,12 +69013,18 @@ function preparePane(o, root, parentEnv) {
|
|
|
67897
69013
|
try {
|
|
67898
69014
|
const paneId = mintPaneId(o.kind, o.label);
|
|
67899
69015
|
const sockPath = sockPathFor(root, paneId);
|
|
67900
|
-
const cwd =
|
|
69016
|
+
const cwd = realpathSync4(o.cwd);
|
|
67901
69017
|
const launch = o.claudishSpawn ?? resolveClaudishLaunch(parentEnv);
|
|
67902
69018
|
dirs = createLaunchDirs(root);
|
|
67903
69019
|
const argv = buildClaudishPaneArgv(o.spawnModel, o.sessionUuid, dirs.turnDir, o.callerFlags);
|
|
67904
69020
|
writeLauncherFiles(dirs.ctlDir, launcherScript(cwd, launch, argv));
|
|
67905
|
-
const { magmuxEnv } = buildPaneEnv({
|
|
69021
|
+
const { magmuxEnv } = buildPaneEnv({
|
|
69022
|
+
parentEnv,
|
|
69023
|
+
slotEnv: o.slotEnv,
|
|
69024
|
+
cwd,
|
|
69025
|
+
ctlDir: dirs.ctlDir,
|
|
69026
|
+
...launchSize(o)
|
|
69027
|
+
});
|
|
67906
69028
|
return { paneId, sockPath, cwd, ...dirs, magmuxEnv };
|
|
67907
69029
|
} catch (e) {
|
|
67908
69030
|
for (const d of dirs ? [dirs.ctlDir, dirs.turnDir] : [])
|
|
@@ -67971,21 +69093,38 @@ async function startPaneSession(o) {
|
|
|
67971
69093
|
await session.start({ magmuxBinary: magmux.binary, env: p.magmuxEnv, cwd: p.cwd });
|
|
67972
69094
|
return session;
|
|
67973
69095
|
}
|
|
67974
|
-
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;
|
|
67975
69097
|
var init_pane_session = __esm(() => {
|
|
67976
69098
|
init_parent_session();
|
|
67977
69099
|
init_process_tree();
|
|
67978
69100
|
init_redact();
|
|
69101
|
+
init_box_locate();
|
|
69102
|
+
init_contract();
|
|
69103
|
+
init_gate_binding();
|
|
69104
|
+
init_input_gate();
|
|
67979
69105
|
init_magmux_client();
|
|
67980
69106
|
init_pane_launch();
|
|
67981
69107
|
init_pane_registry();
|
|
67982
69108
|
init_process_identity();
|
|
67983
69109
|
init_prompt_delivery();
|
|
67984
69110
|
init_screen_classifier();
|
|
69111
|
+
init_screen_model();
|
|
67985
69112
|
init_session_registry();
|
|
67986
69113
|
init_settle_rule();
|
|
67987
69114
|
init_slot_state();
|
|
67988
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
|
+
]);
|
|
67989
69128
|
EVENT_REASON = {
|
|
67990
69129
|
boot_dialog: "first_run_dialog",
|
|
67991
69130
|
boot_blocked: "boot_blocked",
|
|
@@ -68037,10 +69176,10 @@ __export(exports_session_discovery, {
|
|
|
68037
69176
|
transcriptPathFor: () => transcriptPathFor
|
|
68038
69177
|
});
|
|
68039
69178
|
import { execFile as execFile3, execFileSync as execFileSync3 } from "child_process";
|
|
68040
|
-
import { closeSync as closeSync9, openSync as openSync9, readSync as readSync4, readdirSync as readdirSync8, realpathSync as
|
|
68041
|
-
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";
|
|
68042
69181
|
function projectsDir(env = process.env) {
|
|
68043
|
-
return
|
|
69182
|
+
return join49(claudeConfigDir(env), "projects");
|
|
68044
69183
|
}
|
|
68045
69184
|
function slugForPath(absPath) {
|
|
68046
69185
|
return projectDirNameFor(absPath);
|
|
@@ -68048,9 +69187,9 @@ function slugForPath(absPath) {
|
|
|
68048
69187
|
function transcriptPathFor(cwd, sessionUuid, projectsRoot = projectsDir()) {
|
|
68049
69188
|
let real = cwd;
|
|
68050
69189
|
try {
|
|
68051
|
-
real =
|
|
69190
|
+
real = realpathSync5(cwd);
|
|
68052
69191
|
} catch {}
|
|
68053
|
-
return
|
|
69192
|
+
return join49(projectsRoot, slugForPath(real), `${sessionUuid}.jsonl`);
|
|
68054
69193
|
}
|
|
68055
69194
|
function isAgentSession(row) {
|
|
68056
69195
|
return row.entrypoint !== undefined && row.entrypoint !== "cli";
|
|
@@ -68097,7 +69236,7 @@ function projectDirs() {
|
|
|
68097
69236
|
}
|
|
68098
69237
|
}
|
|
68099
69238
|
function sessionsIn(dirName) {
|
|
68100
|
-
const dir =
|
|
69239
|
+
const dir = join49(projectsDir(), dirName);
|
|
68101
69240
|
let names;
|
|
68102
69241
|
try {
|
|
68103
69242
|
names = readdirSync8(dir).filter((n) => n.endsWith(".jsonl"));
|
|
@@ -68106,13 +69245,13 @@ function sessionsIn(dirName) {
|
|
|
68106
69245
|
}
|
|
68107
69246
|
const rows = [];
|
|
68108
69247
|
for (const n of names) {
|
|
68109
|
-
const file =
|
|
69248
|
+
const file = join49(dir, n);
|
|
68110
69249
|
try {
|
|
68111
69250
|
const st = statSync11(file);
|
|
68112
69251
|
if (st.size === 0)
|
|
68113
69252
|
continue;
|
|
68114
69253
|
const row = {
|
|
68115
|
-
id:
|
|
69254
|
+
id: basename3(n, ".jsonl"),
|
|
68116
69255
|
file,
|
|
68117
69256
|
mtimeMs: st.mtimeMs,
|
|
68118
69257
|
birthtimeMs: st.birthtimeMs,
|
|
@@ -68214,7 +69353,7 @@ function discoverWorktreeGroups(repo) {
|
|
|
68214
69353
|
if (hit) {
|
|
68215
69354
|
path = hit.path;
|
|
68216
69355
|
live = true;
|
|
68217
|
-
name = hit.path === repo.root ? "(root)" :
|
|
69356
|
+
name = hit.path === repo.root ? "(root)" : basename3(hit.path);
|
|
68218
69357
|
} else if (at !== -1 && dir.startsWith(rootSlug)) {
|
|
68219
69358
|
path = null;
|
|
68220
69359
|
live = false;
|
|
@@ -68484,7 +69623,7 @@ var init_session_discovery = __esm(() => {
|
|
|
68484
69623
|
// src/team-orchestrator.ts
|
|
68485
69624
|
import { randomBytes as randomBytes8, randomUUID as randomUUID5 } from "crypto";
|
|
68486
69625
|
import { existsSync as existsSync31, mkdirSync as mkdirSync21, readFileSync as readFileSync31, readdirSync as readdirSync9, statSync as statSync12, writeFileSync as writeFileSync22 } from "fs";
|
|
68487
|
-
import { basename as
|
|
69626
|
+
import { basename as basename4, join as join50, resolve as resolve5 } from "path";
|
|
68488
69627
|
function slotTerminal(e) {
|
|
68489
69628
|
if (!e.session)
|
|
68490
69629
|
return true;
|
|
@@ -68521,13 +69660,13 @@ function addressRun(path, runId) {
|
|
|
68521
69660
|
pruneRuns();
|
|
68522
69661
|
if (runId) {
|
|
68523
69662
|
const run = teamRuns.get(runId) ?? null;
|
|
68524
|
-
if (run && path !== undefined &&
|
|
69663
|
+
if (run && path !== undefined && resolve5(path) !== run.path)
|
|
68525
69664
|
return null;
|
|
68526
69665
|
return run;
|
|
68527
69666
|
}
|
|
68528
69667
|
if (path === undefined)
|
|
68529
69668
|
return null;
|
|
68530
|
-
const id = newestRunByPath.get(
|
|
69669
|
+
const id = newestRunByPath.get(resolve5(path));
|
|
68531
69670
|
return id ? teamRuns.get(id) ?? null : null;
|
|
68532
69671
|
}
|
|
68533
69672
|
function activeRunAt(path) {
|
|
@@ -68553,7 +69692,7 @@ function notableAnomalies(snap) {
|
|
|
68553
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"));
|
|
68554
69693
|
}
|
|
68555
69694
|
function upstreamLogPath(path, id) {
|
|
68556
|
-
return
|
|
69695
|
+
return join50(path, "errors", `${id}-upstream.jsonl`);
|
|
68557
69696
|
}
|
|
68558
69697
|
function neverSpawnedRow(e, m) {
|
|
68559
69698
|
return {
|
|
@@ -68646,9 +69785,9 @@ function teamRunRowFromDisk(path, status) {
|
|
|
68646
69785
|
const settled = slots.length > 0 && slots.every((s) => isTerminalState(s.state));
|
|
68647
69786
|
const completions = Object.values(status.models ?? {}).map((m) => m?.completedAt ? Date.parse(m.completedAt) : Number.NaN).filter(Number.isFinite);
|
|
68648
69787
|
return {
|
|
68649
|
-
run_id: status.runId ??
|
|
69788
|
+
run_id: status.runId ?? basename4(path),
|
|
68650
69789
|
path,
|
|
68651
|
-
kind: status.kind ?? (
|
|
69790
|
+
kind: status.kind ?? (basename4(path) === "judging" ? "judge" : "run"),
|
|
68652
69791
|
started_at: status.startedAt,
|
|
68653
69792
|
finished_at: settled ? new Date(completions.length ? Math.max(...completions) : statusMtimeMs(path) ?? Date.parse(status.startedAt)).toISOString() : null,
|
|
68654
69793
|
state: settled ? "SETTLED" : "ACTIVE",
|
|
@@ -68658,14 +69797,14 @@ function teamRunRowFromDisk(path, status) {
|
|
|
68658
69797
|
}
|
|
68659
69798
|
function statusMtimeMs(path) {
|
|
68660
69799
|
try {
|
|
68661
|
-
return statSync12(
|
|
69800
|
+
return statSync12(join50(path, "status.json")).mtimeMs;
|
|
68662
69801
|
} catch {
|
|
68663
69802
|
return null;
|
|
68664
69803
|
}
|
|
68665
69804
|
}
|
|
68666
69805
|
function readManifestOrNull(path) {
|
|
68667
69806
|
try {
|
|
68668
|
-
return JSON.parse(readFileSync31(
|
|
69807
|
+
return JSON.parse(readFileSync31(join50(path, "manifest.json"), "utf-8"));
|
|
68669
69808
|
} catch {
|
|
68670
69809
|
return null;
|
|
68671
69810
|
}
|
|
@@ -68699,10 +69838,10 @@ async function cancelTeamRun(path, slot, runId) {
|
|
|
68699
69838
|
function neverSpawnedCapture() {
|
|
68700
69839
|
return {
|
|
68701
69840
|
seq: 0,
|
|
68702
|
-
cols:
|
|
68703
|
-
rows:
|
|
69841
|
+
cols: DEFAULT_PANE_COLS,
|
|
69842
|
+
rows: DEFAULT_PANE_ROWS,
|
|
68704
69843
|
cursor: { x: 0, y: 0 },
|
|
68705
|
-
lines: Array.from({ length:
|
|
69844
|
+
lines: Array.from({ length: DEFAULT_PANE_ROWS }, () => ""),
|
|
68706
69845
|
final: true
|
|
68707
69846
|
};
|
|
68708
69847
|
}
|
|
@@ -68719,6 +69858,18 @@ function captureTeamSlot(path, slot, sinceSeq, spans, runId) {
|
|
|
68719
69858
|
}
|
|
68720
69859
|
return e.session.capture(sinceSeq, { spans: spans === true });
|
|
68721
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
|
+
}
|
|
68722
69873
|
function teamLiveMaps(path, runId) {
|
|
68723
69874
|
const run = addressRun(path, runId);
|
|
68724
69875
|
if (!run)
|
|
@@ -68857,7 +70008,7 @@ function persistErrorLog(errorLogPath, header, sections) {
|
|
|
68857
70008
|
} catch {}
|
|
68858
70009
|
}
|
|
68859
70010
|
function validateSessionPath(sessionPath) {
|
|
68860
|
-
const resolved =
|
|
70011
|
+
const resolved = resolve5(sessionPath);
|
|
68861
70012
|
const cwd = process.cwd();
|
|
68862
70013
|
if (!resolved.startsWith(`${cwd}/`) && resolved !== cwd) {
|
|
68863
70014
|
throw new Error(`Session path must be within current directory: ${sessionPath}`);
|
|
@@ -68865,7 +70016,7 @@ function validateSessionPath(sessionPath) {
|
|
|
68865
70016
|
return resolved;
|
|
68866
70017
|
}
|
|
68867
70018
|
function readTeamInputFile(inputPath) {
|
|
68868
|
-
const resolved =
|
|
70019
|
+
const resolved = resolve5(inputPath);
|
|
68869
70020
|
const cwd = process.cwd();
|
|
68870
70021
|
if (!resolved.startsWith(`${cwd}/`) && resolved !== cwd) {
|
|
68871
70022
|
throw new Error(`Input file must be within current directory: ${inputPath}`);
|
|
@@ -68883,14 +70034,14 @@ function setupSession(sessionPath, models, input) {
|
|
|
68883
70034
|
if (models.length === 0) {
|
|
68884
70035
|
throw new Error("At least one model is required");
|
|
68885
70036
|
}
|
|
68886
|
-
if (existsSync31(
|
|
70037
|
+
if (existsSync31(join50(sessionPath, "manifest.json"))) {
|
|
68887
70038
|
throw new Error(`Session already exists at ${sessionPath}. Use a new directory path or delete the existing session first.`);
|
|
68888
70039
|
}
|
|
68889
|
-
mkdirSync21(
|
|
68890
|
-
mkdirSync21(
|
|
70040
|
+
mkdirSync21(join50(sessionPath, "work"), { recursive: true });
|
|
70041
|
+
mkdirSync21(join50(sessionPath, "errors"), { recursive: true });
|
|
68891
70042
|
if (input !== undefined) {
|
|
68892
|
-
writeFileSync22(
|
|
68893
|
-
} else if (!existsSync31(
|
|
70043
|
+
writeFileSync22(join50(sessionPath, "input.md"), input, "utf-8");
|
|
70044
|
+
} else if (!existsSync31(join50(sessionPath, "input.md"))) {
|
|
68894
70045
|
throw new Error(`No input.md found at ${sessionPath} and no input provided`);
|
|
68895
70046
|
}
|
|
68896
70047
|
const ids = models.map((_, i) => String(i + 1).padStart(2, "0"));
|
|
@@ -68907,9 +70058,9 @@ function setupSession(sessionPath, models, input) {
|
|
|
68907
70058
|
model: models[i],
|
|
68908
70059
|
assignedAt: now
|
|
68909
70060
|
};
|
|
68910
|
-
mkdirSync21(
|
|
70061
|
+
mkdirSync21(join50(sessionPath, "work", anonId), { recursive: true });
|
|
68911
70062
|
}
|
|
68912
|
-
writeFileSync22(
|
|
70063
|
+
writeFileSync22(join50(sessionPath, "manifest.json"), JSON.stringify(manifest, null, 2), "utf-8");
|
|
68913
70064
|
const status = {
|
|
68914
70065
|
startedAt: now,
|
|
68915
70066
|
models: Object.fromEntries(Object.keys(manifest.models).map((id) => [
|
|
@@ -68924,7 +70075,7 @@ function setupSession(sessionPath, models, input) {
|
|
|
68924
70075
|
}
|
|
68925
70076
|
]))
|
|
68926
70077
|
};
|
|
68927
|
-
writeFileSync22(
|
|
70078
|
+
writeFileSync22(join50(sessionPath, "status.json"), JSON.stringify(status, null, 2), "utf-8");
|
|
68928
70079
|
return manifest;
|
|
68929
70080
|
}
|
|
68930
70081
|
function assertValidRequirePattern(pattern) {
|
|
@@ -68952,14 +70103,14 @@ async function preflightTeamRun(opts) {
|
|
|
68952
70103
|
throw new Error(`invalid_args: ${refusal}`);
|
|
68953
70104
|
}
|
|
68954
70105
|
await assertMagmuxAvailable();
|
|
68955
|
-
assertNoActiveRun(
|
|
70106
|
+
assertNoActiveRun(resolve5(opts.path));
|
|
68956
70107
|
const root = sockRootFor(opts.parentEnv ?? process.env);
|
|
68957
70108
|
const live = livePaneCount(root);
|
|
68958
70109
|
if (live + opts.slots > MAX_LIVE_PANES)
|
|
68959
70110
|
throw new Error(`pane_limit: ${live} live panes for this user, ${opts.slots} more would exceed ${MAX_LIVE_PANES}`);
|
|
68960
70111
|
}
|
|
68961
70112
|
function mintRunId(path, startMs) {
|
|
68962
|
-
return `${
|
|
70113
|
+
return `${basename4(path)}-${startMs.toString(36)}-${randomBytes8(3).toString("hex")}`;
|
|
68963
70114
|
}
|
|
68964
70115
|
function startModels(sessionPath, opts = {}) {
|
|
68965
70116
|
const flight = { aborted: false };
|
|
@@ -68983,10 +70134,10 @@ async function startModelsIn(flight, sessionPath, opts) {
|
|
|
68983
70134
|
const flagCheck = checkChildFlags(claudeFlags);
|
|
68984
70135
|
if (!flagCheck.ok)
|
|
68985
70136
|
throw new Error(`invalid_args: ${flagCheck.message}`);
|
|
68986
|
-
const path =
|
|
68987
|
-
const manifest = JSON.parse(readFileSync31(
|
|
68988
|
-
const statusPath =
|
|
68989
|
-
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");
|
|
68990
70141
|
const readAvailable = !flagsRemoveRead(claudeFlags);
|
|
68991
70142
|
const refusal = deliveryRefusal(inputContent, readAvailable);
|
|
68992
70143
|
if (refusal)
|
|
@@ -69024,13 +70175,13 @@ async function startModelsIn(flight, sessionPath, opts) {
|
|
|
69024
70175
|
mkdirSync21(statsDir(path), { recursive: true });
|
|
69025
70176
|
const entries = new Map;
|
|
69026
70177
|
let run = null;
|
|
69027
|
-
const errorLogPathOf = (id) =>
|
|
70178
|
+
const errorLogPathOf = (id) => join50(path, "errors", `${id}.log`);
|
|
69028
70179
|
const upstreamLogOf = (id) => upstreamLogPath(path, id);
|
|
69029
70180
|
const commandOf = (e) => ["claudish", "-i", "--model", e.spawnModel ?? e.model, "-y", "--quiet", ...claudeFlags].join(" ");
|
|
69030
70181
|
function writeResponse(e, text) {
|
|
69031
70182
|
e.answer = text;
|
|
69032
70183
|
try {
|
|
69033
|
-
writeFileSync22(
|
|
70184
|
+
writeFileSync22(join50(path, `response-${e.id}.md`), text, "utf-8");
|
|
69034
70185
|
} catch (err) {
|
|
69035
70186
|
persistErrorLog(errorLogPathOf(e.id), `response file not written: ${String(err)}`, []);
|
|
69036
70187
|
}
|
|
@@ -69347,7 +70498,7 @@ async function startModelsIn(flight, sessionPath, opts) {
|
|
|
69347
70498
|
done.catch(() => {});
|
|
69348
70499
|
return {
|
|
69349
70500
|
runId,
|
|
69350
|
-
teamSessionId:
|
|
70501
|
+
teamSessionId: basename4(path),
|
|
69351
70502
|
sessionPath: path,
|
|
69352
70503
|
slots: Object.fromEntries(Object.entries(manifest.models).map(([anonId, entry]) => [entry.model, anonId])),
|
|
69353
70504
|
done
|
|
@@ -69358,9 +70509,9 @@ async function runModels(sessionPath, opts = {}) {
|
|
|
69358
70509
|
return handle.done;
|
|
69359
70510
|
}
|
|
69360
70511
|
async function judgeResponses(sessionPath, opts = {}) {
|
|
69361
|
-
const active = activeRunAt(
|
|
70512
|
+
const active = activeRunAt(resolve5(sessionPath));
|
|
69362
70513
|
if (active)
|
|
69363
|
-
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`);
|
|
69364
70515
|
const responseFiles = readdirSync9(sessionPath).filter((f) => f.startsWith("response-") && f.endsWith(".md")).sort();
|
|
69365
70516
|
if (responseFiles.length < 2) {
|
|
69366
70517
|
throw new Error(`Need at least 2 responses to judge, found ${responseFiles.length}`);
|
|
@@ -69368,13 +70519,13 @@ async function judgeResponses(sessionPath, opts = {}) {
|
|
|
69368
70519
|
const responses = {};
|
|
69369
70520
|
for (const file of responseFiles) {
|
|
69370
70521
|
const id = file.replace(/^response-/, "").replace(/\.md$/, "");
|
|
69371
|
-
responses[id] = readFileSync31(
|
|
70522
|
+
responses[id] = readFileSync31(join50(sessionPath, file), "utf-8");
|
|
69372
70523
|
}
|
|
69373
|
-
const input = readFileSync31(
|
|
70524
|
+
const input = readFileSync31(join50(sessionPath, "input.md"), "utf-8");
|
|
69374
70525
|
const judgePrompt = buildJudgePrompt(input, responses);
|
|
69375
|
-
writeFileSync22(
|
|
70526
|
+
writeFileSync22(join50(sessionPath, "judge-prompt.md"), judgePrompt, "utf-8");
|
|
69376
70527
|
const judgeModels = opts.judges ?? getDefaultJudgeModels(sessionPath);
|
|
69377
|
-
const judgePath =
|
|
70528
|
+
const judgePath = join50(sessionPath, "judging");
|
|
69378
70529
|
mkdirSync21(judgePath, { recursive: true });
|
|
69379
70530
|
setupSession(judgePath, judgeModels, judgePrompt);
|
|
69380
70531
|
await runModels(judgePath, {
|
|
@@ -69385,11 +70536,11 @@ async function judgeResponses(sessionPath, opts = {}) {
|
|
|
69385
70536
|
});
|
|
69386
70537
|
const votes = parseJudgeVotes(judgePath, Object.keys(responses));
|
|
69387
70538
|
const verdict = aggregateVerdict(votes, Object.keys(responses));
|
|
69388
|
-
writeFileSync22(
|
|
70539
|
+
writeFileSync22(join50(sessionPath, "verdict.md"), formatVerdict(verdict, sessionPath), "utf-8");
|
|
69389
70540
|
return verdict;
|
|
69390
70541
|
}
|
|
69391
70542
|
function getStatus(sessionPath) {
|
|
69392
|
-
return JSON.parse(readFileSync31(
|
|
70543
|
+
return JSON.parse(readFileSync31(join50(sessionPath, "status.json"), "utf-8"));
|
|
69393
70544
|
}
|
|
69394
70545
|
function readTeamStatus(sessionPath) {
|
|
69395
70546
|
try {
|
|
@@ -69425,7 +70576,7 @@ function fisherYatesShuffle(arr) {
|
|
|
69425
70576
|
return arr;
|
|
69426
70577
|
}
|
|
69427
70578
|
function getDefaultJudgeModels(sessionPath) {
|
|
69428
|
-
const manifest = JSON.parse(readFileSync31(
|
|
70579
|
+
const manifest = JSON.parse(readFileSync31(join50(sessionPath, "manifest.json"), "utf-8"));
|
|
69429
70580
|
return Object.values(manifest.models).map((e) => e.model);
|
|
69430
70581
|
}
|
|
69431
70582
|
function buildJudgePrompt(input, responses) {
|
|
@@ -69488,7 +70639,7 @@ function parseJudgeVotes(judgePath, responseIds) {
|
|
|
69488
70639
|
const judgeId = file.replace(/^response-/, "").replace(/\.md$/, "");
|
|
69489
70640
|
let content;
|
|
69490
70641
|
try {
|
|
69491
|
-
content = readFileSync31(
|
|
70642
|
+
content = readFileSync31(join50(judgePath, file), "utf-8");
|
|
69492
70643
|
} catch {
|
|
69493
70644
|
continue;
|
|
69494
70645
|
}
|
|
@@ -69540,7 +70691,7 @@ function aggregateVerdict(votes, responseIds) {
|
|
|
69540
70691
|
function formatVerdict(verdict, sessionPath) {
|
|
69541
70692
|
let manifest = null;
|
|
69542
70693
|
try {
|
|
69543
|
-
manifest = JSON.parse(readFileSync31(
|
|
70694
|
+
manifest = JSON.parse(readFileSync31(join50(sessionPath, "manifest.json"), "utf-8"));
|
|
69544
70695
|
} catch {}
|
|
69545
70696
|
let output = `# Team Verdict
|
|
69546
70697
|
|
|
@@ -69602,7 +70753,7 @@ import {
|
|
|
69602
70753
|
statSync as statSync13,
|
|
69603
70754
|
writeFileSync as writeFileSync23
|
|
69604
70755
|
} from "fs";
|
|
69605
|
-
import { join as
|
|
70756
|
+
import { join as join51, resolve as resolve6, sep } from "path";
|
|
69606
70757
|
function normaliseTimeoutSeconds(raw) {
|
|
69607
70758
|
const n = typeof raw === "string" && raw.trim() !== "" ? Number(raw) : raw;
|
|
69608
70759
|
if (typeof n !== "number" || !Number.isFinite(n))
|
|
@@ -69768,7 +70919,7 @@ function dropLeadingFragment(tail) {
|
|
|
69768
70919
|
return firstBreak === -1 ? tail.text : tail.text.slice(firstBreak + 1);
|
|
69769
70920
|
}
|
|
69770
70921
|
function diskAccounting(sessionDir) {
|
|
69771
|
-
const stats = readTokenStatsAt(
|
|
70922
|
+
const stats = readTokenStatsAt(join51(sessionDir, "tokens.json"));
|
|
69772
70923
|
return {
|
|
69773
70924
|
tokensIn: stats?.billed_input_tokens ?? null,
|
|
69774
70925
|
tokensOut: stats?.output_tokens ?? null,
|
|
@@ -69791,10 +70942,10 @@ function diskProseBytes(tail, fileBytes) {
|
|
|
69791
70942
|
function blankFinalCapture() {
|
|
69792
70943
|
return {
|
|
69793
70944
|
seq: 0,
|
|
69794
|
-
cols:
|
|
69795
|
-
rows:
|
|
70945
|
+
cols: DEFAULT_PANE_COLS,
|
|
70946
|
+
rows: DEFAULT_PANE_ROWS,
|
|
69796
70947
|
cursor: { x: 0, y: 0 },
|
|
69797
|
-
lines: Array.from({ length:
|
|
70948
|
+
lines: Array.from({ length: DEFAULT_PANE_ROWS }, () => ""),
|
|
69798
70949
|
final: true
|
|
69799
70950
|
};
|
|
69800
70951
|
}
|
|
@@ -69839,7 +70990,7 @@ class SessionManager {
|
|
|
69839
70990
|
let dir = "";
|
|
69840
70991
|
for (let attempt = 0;; attempt++) {
|
|
69841
70992
|
id = `team-${randomUUID6().replace(/-/g, "").slice(0, 8)}`;
|
|
69842
|
-
dir =
|
|
70993
|
+
dir = join51(this.sessionsDir, id);
|
|
69843
70994
|
try {
|
|
69844
70995
|
mkdirSync22(dir);
|
|
69845
70996
|
break;
|
|
@@ -69854,7 +71005,7 @@ class SessionManager {
|
|
|
69854
71005
|
sessionId: id,
|
|
69855
71006
|
parentClaudeSessionId: opts.parentClaudeSessionId,
|
|
69856
71007
|
startedAt,
|
|
69857
|
-
teamPath:
|
|
71008
|
+
teamPath: resolve6(opts.teamPath),
|
|
69858
71009
|
slots: opts.slots
|
|
69859
71010
|
});
|
|
69860
71011
|
this.teamRunStarts.set(id, startedAt);
|
|
@@ -69871,9 +71022,9 @@ class SessionManager {
|
|
|
69871
71022
|
if (dir === null)
|
|
69872
71023
|
throw new Error("not a record id");
|
|
69873
71024
|
const completedAt = new Date().toISOString();
|
|
69874
|
-
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;
|
|
69875
71026
|
const elapsedMs = Date.parse(completedAt) - Date.parse(startedAt);
|
|
69876
|
-
writeJsonAtomic(
|
|
71027
|
+
writeJsonAtomic(join51(dir, "meta.json"), {
|
|
69877
71028
|
kind: "team",
|
|
69878
71029
|
status: outcome.status,
|
|
69879
71030
|
startedAt,
|
|
@@ -69905,7 +71056,7 @@ class SessionManager {
|
|
|
69905
71056
|
startedAt,
|
|
69906
71057
|
...rest
|
|
69907
71058
|
};
|
|
69908
|
-
writeJsonAtomic(
|
|
71059
|
+
writeJsonAtomic(join51(dir, "spawn.json"), body);
|
|
69909
71060
|
}
|
|
69910
71061
|
async createSession(opts) {
|
|
69911
71062
|
if (this.activeSessions + this.starting >= this.maxSessions) {
|
|
@@ -69964,10 +71115,10 @@ class SessionManager {
|
|
|
69964
71115
|
const claudeSessionId = randomUUID6();
|
|
69965
71116
|
const timeout = normaliseTimeoutSeconds(opts.timeoutSeconds);
|
|
69966
71117
|
const startedAt = new Date().toISOString();
|
|
69967
|
-
const sessionDir = opts.sessionDir ??
|
|
71118
|
+
const sessionDir = opts.sessionDir ?? join51(this.sessionsDir, sessionId);
|
|
69968
71119
|
mkdirSync22(sessionDir, { recursive: true });
|
|
69969
71120
|
if (opts.prompt)
|
|
69970
|
-
writeFileSync23(
|
|
71121
|
+
writeFileSync23(join51(sessionDir, "prompt.md"), opts.prompt, "utf-8");
|
|
69971
71122
|
this.writeSpawnRecord(sessionDir, {
|
|
69972
71123
|
kind: "session",
|
|
69973
71124
|
sessionId,
|
|
@@ -69980,7 +71131,7 @@ class SessionManager {
|
|
|
69980
71131
|
const cwd = opts.cwd ?? process.cwd();
|
|
69981
71132
|
const parentEnv = opts.parentEnv ?? this.parentEnv;
|
|
69982
71133
|
const spawnModel = opts.spawnModel ?? null;
|
|
69983
|
-
const tokenFile = opts.tokenFile ??
|
|
71134
|
+
const tokenFile = opts.tokenFile ?? join51(sessionDir, "tokens.json");
|
|
69984
71135
|
return {
|
|
69985
71136
|
info: {
|
|
69986
71137
|
sessionId,
|
|
@@ -70016,28 +71167,30 @@ class SessionManager {
|
|
|
70016
71167
|
},
|
|
70017
71168
|
session: null,
|
|
70018
71169
|
scrollback: new ScrollbackBuffer(this.scrollbackCapacity),
|
|
70019
|
-
outputLogStream: createWriteStream(
|
|
71170
|
+
outputLogStream: createWriteStream(join51(sessionDir, "output.log")),
|
|
70020
71171
|
sessionDir,
|
|
70021
71172
|
cwd,
|
|
70022
71173
|
tokenFile,
|
|
70023
|
-
eventLogPath:
|
|
71174
|
+
eventLogPath: join51(sessionDir, "events.jsonl"),
|
|
70024
71175
|
eventLogBytes: 0,
|
|
70025
|
-
upstreamErrorLogPath:
|
|
71176
|
+
upstreamErrorLogPath: join51(sessionDir, "upstream-errors.jsonl"),
|
|
70026
71177
|
eventRing: [],
|
|
70027
71178
|
proseBytes: 0,
|
|
70028
71179
|
answeredTurns: new Map,
|
|
70029
|
-
waitLogPath:
|
|
71180
|
+
waitLogPath: join51(sessionDir, "waits.jsonl"),
|
|
70030
71181
|
waitLogBytes: 0,
|
|
70031
71182
|
waitSince: null,
|
|
70032
71183
|
ended: false,
|
|
70033
71184
|
evictHandle: null,
|
|
70034
71185
|
lastLoggedTool: null,
|
|
70035
71186
|
assistantIdsLogged: 0,
|
|
70036
|
-
anomaliesLogged: new Set
|
|
71187
|
+
anomaliesLogged: new Set,
|
|
71188
|
+
requestedSize: null
|
|
70037
71189
|
};
|
|
70038
71190
|
}
|
|
70039
71191
|
async startPane(entry, opts, p) {
|
|
70040
71192
|
const info = entry.info;
|
|
71193
|
+
const launch = entry.requestedSize;
|
|
70041
71194
|
const paneOpts = {
|
|
70042
71195
|
kind: "s",
|
|
70043
71196
|
label: info.sessionId,
|
|
@@ -70052,6 +71205,7 @@ class SessionManager {
|
|
|
70052
71205
|
},
|
|
70053
71206
|
shape: info.shape,
|
|
70054
71207
|
...opts.prompt ? { initialPrompt: opts.prompt } : {},
|
|
71208
|
+
...launch ? { initialSize: launch } : {},
|
|
70055
71209
|
readAvailable: p.readAvailable,
|
|
70056
71210
|
decide: (turn) => this.decide(entry, turn),
|
|
70057
71211
|
onBlocked: (b) => this.onBlocked(entry, b),
|
|
@@ -70067,6 +71221,12 @@ class SessionManager {
|
|
|
70067
71221
|
this.failNeverSpawned(entry, err);
|
|
70068
71222
|
throw err;
|
|
70069
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
|
+
});
|
|
70070
71230
|
if (!entry.ended)
|
|
70071
71231
|
this.applySnapshot(entry, entry.session.snapshot());
|
|
70072
71232
|
}
|
|
@@ -70160,7 +71320,7 @@ class SessionManager {
|
|
|
70160
71320
|
try {
|
|
70161
71321
|
const text = screenLines.join(`
|
|
70162
71322
|
`).replace(/\s+$/, "");
|
|
70163
|
-
writeFileSync23(
|
|
71323
|
+
writeFileSync23(join51(entry.sessionDir, "screen.txt"), `${redactSecrets2(text)}
|
|
70164
71324
|
`, "utf-8");
|
|
70165
71325
|
} catch {}
|
|
70166
71326
|
}
|
|
@@ -70174,7 +71334,7 @@ class SessionManager {
|
|
|
70174
71334
|
entry.waitSince = null;
|
|
70175
71335
|
}
|
|
70176
71336
|
try {
|
|
70177
|
-
writeJsonAtomic(
|
|
71337
|
+
writeJsonAtomic(join51(entry.sessionDir, "meta.json"), toMetaRecord(entry.info, entry.cwd));
|
|
70178
71338
|
} catch (err) {
|
|
70179
71339
|
process.stderr.write(`[claudish] session ${entry.info.sessionId}: could not write meta.json: ` + `${err instanceof Error ? err.message : String(err)}
|
|
70180
71340
|
`);
|
|
@@ -70318,6 +71478,8 @@ class SessionManager {
|
|
|
70318
71478
|
registry: null,
|
|
70319
71479
|
preambleBytes: 0,
|
|
70320
71480
|
readCoverage: null,
|
|
71481
|
+
gate: null,
|
|
71482
|
+
lastSend: null,
|
|
70321
71483
|
claudeCodeVersion: null,
|
|
70322
71484
|
anomalies: entry.info.detail ? [entry.info.detail] : []
|
|
70323
71485
|
};
|
|
@@ -70332,6 +71494,8 @@ class SessionManager {
|
|
|
70332
71494
|
registry: pane.registry,
|
|
70333
71495
|
preambleBytes: pane.preambleBytes,
|
|
70334
71496
|
readCoverage: pane.readCoverage,
|
|
71497
|
+
gate: pane.gate,
|
|
71498
|
+
lastSend: pane.lastSend,
|
|
70335
71499
|
claudeCodeVersion: snap.claudeCodeVersion,
|
|
70336
71500
|
anomalies: snap.anomalies
|
|
70337
71501
|
};
|
|
@@ -70345,6 +71509,26 @@ class SessionManager {
|
|
|
70345
71509
|
const r = entry.session.cancel();
|
|
70346
71510
|
return { session_id: sessionId, state: r.state, changed: r.changed };
|
|
70347
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
|
+
}
|
|
70348
71532
|
captureSession(sessionId, sinceSeq, spans) {
|
|
70349
71533
|
const entry = this.liveEntry(sessionId);
|
|
70350
71534
|
if (!entry)
|
|
@@ -70408,9 +71592,9 @@ class SessionManager {
|
|
|
70408
71592
|
diskSessionDir(sessionId) {
|
|
70409
71593
|
if (!SESSION_ID_RE.test(sessionId))
|
|
70410
71594
|
return null;
|
|
70411
|
-
const root =
|
|
70412
|
-
const dir =
|
|
70413
|
-
if (dir !==
|
|
71595
|
+
const root = resolve6(this.sessionsDir);
|
|
71596
|
+
const dir = resolve6(root, sessionId);
|
|
71597
|
+
if (dir !== join51(root, sessionId))
|
|
70414
71598
|
return null;
|
|
70415
71599
|
if (!dir.startsWith(root + sep))
|
|
70416
71600
|
return null;
|
|
@@ -70429,10 +71613,10 @@ class SessionManager {
|
|
|
70429
71613
|
} catch {
|
|
70430
71614
|
return null;
|
|
70431
71615
|
}
|
|
70432
|
-
const spawnRecord = readJsonObject(
|
|
71616
|
+
const spawnRecord = readJsonObject(join51(sessionDir, "spawn.json"), META_READ_LIMIT);
|
|
70433
71617
|
if (spawnRecord?.kind === "team")
|
|
70434
71618
|
return null;
|
|
70435
|
-
const meta = readJsonObject(
|
|
71619
|
+
const meta = readJsonObject(join51(sessionDir, "meta.json"), META_READ_LIMIT);
|
|
70436
71620
|
if (meta?.kind === "team")
|
|
70437
71621
|
return null;
|
|
70438
71622
|
const partial = meta === null;
|
|
@@ -70454,7 +71638,7 @@ class SessionManager {
|
|
|
70454
71638
|
return stored;
|
|
70455
71639
|
}
|
|
70456
71640
|
diskOutput(record, tailLines) {
|
|
70457
|
-
const tail = readTailText(
|
|
71641
|
+
const tail = readTailText(join51(record.sessionDir, "output.log"), OUTPUT_TAIL_BYTES);
|
|
70458
71642
|
const buffer = new ScrollbackBuffer(this.scrollbackCapacity);
|
|
70459
71643
|
if (tail?.text)
|
|
70460
71644
|
buffer.append(dropLeadingFragment(tail));
|
|
@@ -70474,12 +71658,12 @@ class SessionManager {
|
|
|
70474
71658
|
}
|
|
70475
71659
|
diskDiagnostics(record, limit) {
|
|
70476
71660
|
const { sessionDir, info } = record;
|
|
70477
|
-
const eventLogPath =
|
|
70478
|
-
const upstreamErrorLogPath =
|
|
70479
|
-
const outputLogPath =
|
|
71661
|
+
const eventLogPath = join51(sessionDir, "events.jsonl");
|
|
71662
|
+
const upstreamErrorLogPath = join51(sessionDir, "upstream-errors.jsonl");
|
|
71663
|
+
const outputLogPath = join51(sessionDir, "output.log");
|
|
70480
71664
|
const events = readTailLines2(eventLogPath, EVENT_TAIL_BYTES);
|
|
70481
71665
|
const outputTail = readTailText(outputLogPath, OUTPUT_TAIL_BYTES);
|
|
70482
|
-
const screen = readTailText(
|
|
71666
|
+
const screen = readTailText(join51(sessionDir, "screen.txt"), SCREEN_READ_BYTES);
|
|
70483
71667
|
return {
|
|
70484
71668
|
sessionId: info.sessionId,
|
|
70485
71669
|
state: info.state,
|
|
@@ -70512,6 +71696,8 @@ class SessionManager {
|
|
|
70512
71696
|
turnSource: info.turnSource,
|
|
70513
71697
|
preambleBytes: 0,
|
|
70514
71698
|
readCoverage: null,
|
|
71699
|
+
gate: null,
|
|
71700
|
+
lastSend: null,
|
|
70515
71701
|
claudeCodeVersion: null,
|
|
70516
71702
|
anomalies: record.partial ? [
|
|
70517
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."
|
|
@@ -70864,7 +72050,7 @@ var init_progress_heartbeat = __esm(() => {
|
|
|
70864
72050
|
import { spawn as spawn2 } from "child_process";
|
|
70865
72051
|
import { mkdirSync as mkdirSync23, mkdtempSync as mkdtempSync3, rmSync as rmSync7, writeFileSync as writeFileSync24 } from "fs";
|
|
70866
72052
|
import { tmpdir as tmpdir2 } from "os";
|
|
70867
|
-
import { join as
|
|
72053
|
+
import { join as join52 } from "path";
|
|
70868
72054
|
function claudeCodePrintArgv(model, systemPromptFile) {
|
|
70869
72055
|
const head = [PRINT_FLAGS[0], "--model", model, ...PRINT_FLAGS.slice(1)];
|
|
70870
72056
|
return systemPromptFile !== undefined ? [...head, "--system-prompt-file", systemPromptFile] : [...head, "--system-prompt", ""];
|
|
@@ -70982,13 +72168,13 @@ async function runPromptViaClaudeCode(model, prompt, systemPrompt, opts = {}) {
|
|
|
70982
72168
|
} catch (e) {
|
|
70983
72169
|
throw new Error(`cannot start claudish (${parentEnv.CLAUDISH_BIN?.trim() || "claudish"}): ${e instanceof Error ? e.message : String(e)}`);
|
|
70984
72170
|
}
|
|
70985
|
-
const root = mkdtempSync3(
|
|
72171
|
+
const root = mkdtempSync3(join52(tmpdir2(), "claudish-run-prompt-"));
|
|
70986
72172
|
try {
|
|
70987
|
-
const cwd =
|
|
72173
|
+
const cwd = join52(root, "cwd");
|
|
70988
72174
|
mkdirSync23(cwd, { mode: 448 });
|
|
70989
72175
|
let systemPromptFile;
|
|
70990
72176
|
if (typeof systemPrompt === "string" && systemPrompt.length > 0) {
|
|
70991
|
-
systemPromptFile =
|
|
72177
|
+
systemPromptFile = join52(root, "system-prompt.txt");
|
|
70992
72178
|
writeFileSync24(systemPromptFile, systemPrompt, { mode: 384 });
|
|
70993
72179
|
}
|
|
70994
72180
|
const argv = claudeCodePrintArgv(model, systemPromptFile);
|
|
@@ -71096,7 +72282,7 @@ var init_run_prompt_claude_code = __esm(() => {
|
|
|
71096
72282
|
// src/mcp-server.ts
|
|
71097
72283
|
import { existsSync as existsSync33, mkdirSync as mkdirSync24, readFileSync as readFileSync33, readdirSync as readdirSync10, writeFileSync as writeFileSync25 } from "fs";
|
|
71098
72284
|
import { homedir as homedir35 } from "os";
|
|
71099
|
-
import { dirname as
|
|
72285
|
+
import { dirname as dirname15, join as join53, resolve as resolve7 } from "path";
|
|
71100
72286
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
71101
72287
|
async function loadAllModels(forceRefresh = false) {
|
|
71102
72288
|
if (!forceRefresh && existsSync33(OPENROUTER_MODELS_CACHE_PATH)) {
|
|
@@ -71391,6 +72577,12 @@ function optionalInteger(raw, name) {
|
|
|
71391
72577
|
throw new ContractErrorException("invalid_args", `'${name}' must be an integer`);
|
|
71392
72578
|
return raw;
|
|
71393
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
|
+
}
|
|
71394
72586
|
function teamStatusAnswer(path, runId) {
|
|
71395
72587
|
let row = null;
|
|
71396
72588
|
if (runId) {
|
|
@@ -71430,6 +72622,8 @@ async function teamContractVerb(mode, args) {
|
|
|
71430
72622
|
const slot = optionalString(args.slot, "slot");
|
|
71431
72623
|
const since = optionalInteger(args.since_seq, "since_seq");
|
|
71432
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;
|
|
71433
72627
|
switch (mode) {
|
|
71434
72628
|
case "status":
|
|
71435
72629
|
return contractAnswer(teamStatusAnswer(path, runId));
|
|
@@ -71440,6 +72634,11 @@ async function teamContractVerb(mode, args) {
|
|
|
71440
72634
|
throw new ContractErrorException("invalid_args", "'slot' is required for mode 'capture'");
|
|
71441
72635
|
return contractAnswer(captureTeamSlot(path, slot, since, spans, runId));
|
|
71442
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
|
+
}
|
|
71443
72642
|
}
|
|
71444
72643
|
} catch (e) {
|
|
71445
72644
|
return contractErrorAnswer(e);
|
|
@@ -71813,18 +73012,18 @@ Use with: run_prompt(model="${suggested}", prompt="your prompt")`;
|
|
|
71813
73012
|
});
|
|
71814
73013
|
tools.push({
|
|
71815
73014
|
name: "team",
|
|
71816
|
-
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.",
|
|
71817
73016
|
inputSchema: {
|
|
71818
73017
|
type: "object",
|
|
71819
73018
|
properties: {
|
|
71820
73019
|
mode: {
|
|
71821
73020
|
type: "string",
|
|
71822
|
-
enum: ["run", "judge", "run-and-judge", "status", "cancel", "list", "capture"],
|
|
71823
|
-
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."
|
|
71824
73023
|
},
|
|
71825
73024
|
slot: {
|
|
71826
73025
|
type: "string",
|
|
71827
|
-
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."
|
|
71828
73027
|
},
|
|
71829
73028
|
path: {
|
|
71830
73029
|
type: "string",
|
|
@@ -71832,7 +73031,7 @@ Use with: run_prompt(model="${suggested}", prompt="your prompt")`;
|
|
|
71832
73031
|
},
|
|
71833
73032
|
run_id: {
|
|
71834
73033
|
type: "string",
|
|
71835
|
-
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'."
|
|
71836
73035
|
},
|
|
71837
73036
|
since_seq: {
|
|
71838
73037
|
type: "number",
|
|
@@ -71842,6 +73041,14 @@ Use with: run_prompt(model="${suggested}", prompt="your prompt")`;
|
|
|
71842
73041
|
type: "boolean",
|
|
71843
73042
|
description: "For 'capture': also return the colour/attribute spans of each line."
|
|
71844
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
|
+
},
|
|
71845
73052
|
models: {
|
|
71846
73053
|
type: "array",
|
|
71847
73054
|
items: { type: "string" },
|
|
@@ -71883,7 +73090,7 @@ Use with: run_prompt(model="${suggested}", prompt="your prompt")`;
|
|
|
71883
73090
|
heartbeat: true,
|
|
71884
73091
|
handler: async (args, ctx) => {
|
|
71885
73092
|
const mode = args.mode;
|
|
71886
|
-
if (mode === "list" || mode === "status" || mode === "cancel" || mode === "capture") {
|
|
73093
|
+
if (mode === "list" || mode === "status" || mode === "cancel" || mode === "capture" || mode === "resize") {
|
|
71887
73094
|
return teamContractVerb(mode, args);
|
|
71888
73095
|
}
|
|
71889
73096
|
try {
|
|
@@ -71915,7 +73122,7 @@ Use with: run_prompt(model="${suggested}", prompt="your prompt")`;
|
|
|
71915
73122
|
const promptText = () => {
|
|
71916
73123
|
if (input !== undefined)
|
|
71917
73124
|
return input;
|
|
71918
|
-
const existing =
|
|
73125
|
+
const existing = join53(resolved, "input.md");
|
|
71919
73126
|
return existsSync33(existing) ? readFileSync33(existing, "utf-8") : undefined;
|
|
71920
73127
|
};
|
|
71921
73128
|
switch (mode) {
|
|
@@ -72074,16 +73281,16 @@ Use with: run_prompt(model="${suggested}", prompt="your prompt")`;
|
|
|
72074
73281
|
const sp = session_path;
|
|
72075
73282
|
for (const file of ["status.json", "manifest.json", "input.md"]) {
|
|
72076
73283
|
try {
|
|
72077
|
-
sessionData[file] = readFileSync33(
|
|
73284
|
+
sessionData[file] = readFileSync33(join53(sp, file), "utf-8");
|
|
72078
73285
|
} catch {}
|
|
72079
73286
|
}
|
|
72080
73287
|
try {
|
|
72081
|
-
const errorDir =
|
|
73288
|
+
const errorDir = join53(sp, "errors");
|
|
72082
73289
|
if (existsSync33(errorDir)) {
|
|
72083
73290
|
for (const f of readdirSync10(errorDir)) {
|
|
72084
73291
|
if (f.endsWith(".log")) {
|
|
72085
73292
|
try {
|
|
72086
|
-
sessionData[`errors/${f}`] = readFileSync33(
|
|
73293
|
+
sessionData[`errors/${f}`] = readFileSync33(join53(errorDir, f), "utf-8");
|
|
72087
73294
|
} catch {}
|
|
72088
73295
|
}
|
|
72089
73296
|
}
|
|
@@ -72093,7 +73300,7 @@ Use with: run_prompt(model="${suggested}", prompt="your prompt")`;
|
|
|
72093
73300
|
for (const f of readdirSync10(sp)) {
|
|
72094
73301
|
if (f.startsWith("response-") && f.endsWith(".md")) {
|
|
72095
73302
|
try {
|
|
72096
|
-
const content = readFileSync33(
|
|
73303
|
+
const content = readFileSync33(join53(sp, f), "utf-8");
|
|
72097
73304
|
sessionData[f] = content.slice(0, 200) + (content.length > 200 ? "... (truncated)" : "");
|
|
72098
73305
|
} catch {}
|
|
72099
73306
|
}
|
|
@@ -72102,7 +73309,7 @@ Use with: run_prompt(model="${suggested}", prompt="your prompt")`;
|
|
|
72102
73309
|
}
|
|
72103
73310
|
let version = "unknown";
|
|
72104
73311
|
try {
|
|
72105
|
-
const pkgPath =
|
|
73312
|
+
const pkgPath = join53(__dirname3, "../package.json");
|
|
72106
73313
|
if (existsSync33(pkgPath)) {
|
|
72107
73314
|
version = JSON.parse(readFileSync33(pkgPath, "utf-8")).version;
|
|
72108
73315
|
}
|
|
@@ -72182,7 +73389,7 @@ Report manually at https://github.com/anthropics/claudish/issues${autoSendHint}`
|
|
|
72182
73389
|
});
|
|
72183
73390
|
tools.push({
|
|
72184
73391
|
name: "create_session",
|
|
72185
|
-
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).",
|
|
72186
73393
|
inputSchema: {
|
|
72187
73394
|
type: "object",
|
|
72188
73395
|
properties: {
|
|
@@ -72226,7 +73433,7 @@ Report manually at https://github.com/anthropics/claudish/issues${autoSendHint}`
|
|
|
72226
73433
|
const requestedModel = args.model;
|
|
72227
73434
|
const workDir = args.work_dir;
|
|
72228
73435
|
const plan = await prehydrateCredentialsForSpawn([requestedModel], {
|
|
72229
|
-
pin: workDir === undefined ||
|
|
73436
|
+
pin: workDir === undefined || resolve7(workDir) === process.cwd()
|
|
72230
73437
|
});
|
|
72231
73438
|
const parentClaudeSessionId = await parentSessionForCall({
|
|
72232
73439
|
hostPid: sessionManager.hostPid
|
|
@@ -72408,7 +73615,7 @@ Report manually at https://github.com/anthropics/claudish/issues${autoSendHint}`
|
|
|
72408
73615
|
});
|
|
72409
73616
|
tools.push({
|
|
72410
73617
|
name: "capture_session",
|
|
72411
|
-
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.",
|
|
72412
73619
|
inputSchema: {
|
|
72413
73620
|
type: "object",
|
|
72414
73621
|
properties: {
|
|
@@ -72438,6 +73645,35 @@ Report manually at https://github.com/anthropics/claudish/issues${autoSendHint}`
|
|
|
72438
73645
|
}
|
|
72439
73646
|
}
|
|
72440
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
|
+
});
|
|
72441
73677
|
return tools;
|
|
72442
73678
|
}
|
|
72443
73679
|
function resolveToolGroups(mode) {
|
|
@@ -72563,7 +73799,7 @@ Each session is an interactive Claude Code running the model in its own headless
|
|
|
72563
73799
|
3. send_input may be called at any time; it is queued until the session is idle.
|
|
72564
73800
|
4. COMPLETED: call get_output for the answer.
|
|
72565
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.
|
|
72566
|
-
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.
|
|
72567
73803
|
|
|
72568
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;
|
|
72569
73805
|
var init_mcp_server = __esm(() => {
|
|
@@ -72596,9 +73832,9 @@ var init_mcp_server = __esm(() => {
|
|
|
72596
73832
|
import_dotenv2 = __toESM(require_main(), 1);
|
|
72597
73833
|
import_dotenv2.config({ quiet: true });
|
|
72598
73834
|
__filename3 = fileURLToPath3(import.meta.url);
|
|
72599
|
-
__dirname3 =
|
|
72600
|
-
CLAUDISH_CACHE_DIR =
|
|
72601
|
-
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");
|
|
72602
73838
|
NEXT_STEP = {
|
|
72603
73839
|
cancelled: "you stopped this slot; nothing is wrong with it. Re-run it if you still want its vote",
|
|
72604
73840
|
timeout: "grid mode only \u2014 magmux ended the pane. The orchestrator has no deadline",
|
|
@@ -72609,7 +73845,7 @@ var init_mcp_server = __esm(() => {
|
|
|
72609
73845
|
prompt_not_accepted: "the REPL never took the prompt \u2014 read the evidence screen; retry",
|
|
72610
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",
|
|
72611
73847
|
child_exited: "read the evidence screen, then retry or drop the model",
|
|
72612
|
-
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",
|
|
72613
73849
|
blocked: "the child asked a question team cannot answer \u2014 make the prompt self-contained or use " + "create_session",
|
|
72614
73850
|
api_error: "retry once, or route via a different provider (or@<model>)",
|
|
72615
73851
|
refused: "the model refused \u2014 rephrase or drop the model",
|
|
@@ -72925,7 +74161,7 @@ var init_behavior_command = __esm(() => {
|
|
|
72925
74161
|
import { spawn as spawn3 } from "child_process";
|
|
72926
74162
|
import { existsSync as existsSync36, readFileSync as readFileSync36, writeFileSync as writeFileSync27 } from "fs";
|
|
72927
74163
|
import { connect as netConnect2 } from "net";
|
|
72928
|
-
import { join as
|
|
74164
|
+
import { join as join54 } from "path";
|
|
72929
74165
|
import { setTimeout as wait } from "timers/promises";
|
|
72930
74166
|
function paneRouteLine(explanation) {
|
|
72931
74167
|
const origin = describeRouteExplanation(explanation);
|
|
@@ -73075,9 +74311,9 @@ async function runWithGrid(sessionPath, models, input, opts) {
|
|
|
73075
74311
|
const keep = opts?.keep ?? false;
|
|
73076
74312
|
const manifest = setupSession(sessionPath, models, input);
|
|
73077
74313
|
const startedAt = new Date().toISOString();
|
|
73078
|
-
const gridfilePath =
|
|
73079
|
-
const prompt = readFileSync36(
|
|
73080
|
-
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");
|
|
73081
74317
|
const usedBannerColors = new Set;
|
|
73082
74318
|
const routeLines = mode === "interactive" ? new Map : await resolvePaneRouteLines(Object.values(manifest.models).map((entry) => entry.model));
|
|
73083
74319
|
const gridLines = Object.entries(manifest.models).map(([anonId]) => {
|
|
@@ -73109,7 +74345,7 @@ async function runWithGrid(sessionPath, models, input, opts) {
|
|
|
73109
74345
|
});
|
|
73110
74346
|
const [{ results }] = await Promise.all([subscription, procExit]);
|
|
73111
74347
|
const status = buildTeamStatus(manifest, startedAt, results?.panes ?? null);
|
|
73112
|
-
const statusPath =
|
|
74348
|
+
const statusPath = join54(sessionPath, "status.json");
|
|
73113
74349
|
writeFileSync27(statusPath, JSON.stringify(status, null, 2), "utf-8");
|
|
73114
74350
|
return status;
|
|
73115
74351
|
}
|
|
@@ -73130,7 +74366,7 @@ var init_team_grid = __esm(() => {
|
|
|
73130
74366
|
|
|
73131
74367
|
// src/team-cli.ts
|
|
73132
74368
|
import { readFileSync as readFileSync37 } from "fs";
|
|
73133
|
-
import { join as
|
|
74369
|
+
import { join as join55 } from "path";
|
|
73134
74370
|
async function runPaneTeam(sessionPath, models, input, opts) {
|
|
73135
74371
|
installPaneShutdownHooks({ exitAfter: true });
|
|
73136
74372
|
try {
|
|
@@ -73182,7 +74418,7 @@ Options (run / run-and-judge):
|
|
|
73182
74418
|
--timeout <secs> Grid modes only: magmux's own per-pane timeout (default: 300).
|
|
73183
74419
|
json mode has no deadline \u2014 nothing kills a working model.
|
|
73184
74420
|
json mode runs each model as an interactive pane in a headless
|
|
73185
|
-
magmux (>= 0.
|
|
74421
|
+
magmux (>= 0.15.1; darwin and linux).
|
|
73186
74422
|
--grid Show all models in a magmux grid with live output + status bar
|
|
73187
74423
|
--mode <m> run only: json (default, panes), default (the grid, as --grid)
|
|
73188
74424
|
or interactive (as --interactive)
|
|
@@ -73275,7 +74511,7 @@ async function teamCommand(args) {
|
|
|
73275
74511
|
}
|
|
73276
74512
|
case "judge": {
|
|
73277
74513
|
await judgeResponses(sessionPath, { judges });
|
|
73278
|
-
console.log(readFileSync37(
|
|
74514
|
+
console.log(readFileSync37(join55(sessionPath, "verdict.md"), "utf-8"));
|
|
73279
74515
|
break;
|
|
73280
74516
|
}
|
|
73281
74517
|
case "run-and-judge": {
|
|
@@ -73291,7 +74527,7 @@ async function teamCommand(args) {
|
|
|
73291
74527
|
});
|
|
73292
74528
|
printStatus(status);
|
|
73293
74529
|
await judgeResponses(sessionPath, { judges });
|
|
73294
|
-
console.log(readFileSync37(
|
|
74530
|
+
console.log(readFileSync37(join55(sessionPath, "verdict.md"), "utf-8"));
|
|
73295
74531
|
break;
|
|
73296
74532
|
}
|
|
73297
74533
|
case "status": {
|
|
@@ -73880,7 +75116,7 @@ var init_keychain_command = __esm(() => {
|
|
|
73880
75116
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
73881
75117
|
import { existsSync as existsSync37, unlinkSync as unlinkSync9 } from "fs";
|
|
73882
75118
|
import { homedir as homedir36 } from "os";
|
|
73883
|
-
import { join as
|
|
75119
|
+
import { join as join56 } from "path";
|
|
73884
75120
|
async function defaultSuggestModel() {
|
|
73885
75121
|
try {
|
|
73886
75122
|
const tok = readSharedAntigravityToken();
|
|
@@ -74001,7 +75237,7 @@ No session detected yet. Starting the Antigravity CLI interactively \u2014
|
|
|
74001
75237
|
async logout(deps) {
|
|
74002
75238
|
deleteSharedAntigravityToken(deps);
|
|
74003
75239
|
try {
|
|
74004
|
-
const tokenFile =
|
|
75240
|
+
const tokenFile = join56(homedir36(), ".gemini", "antigravity-cli", "antigravity-oauth-token");
|
|
74005
75241
|
if (existsSync37(tokenFile))
|
|
74006
75242
|
unlinkSync9(tokenFile);
|
|
74007
75243
|
} catch {}
|
|
@@ -82487,7 +83723,7 @@ import {
|
|
|
82487
83723
|
writeFileSync as writeFileSync28
|
|
82488
83724
|
} from "fs";
|
|
82489
83725
|
import { homedir as homedir37, tmpdir as tmpdir3 } from "os";
|
|
82490
|
-
import { dirname as
|
|
83726
|
+
import { dirname as dirname16, join as join57 } from "path";
|
|
82491
83727
|
import { isatty } from "tty";
|
|
82492
83728
|
function releaseTerminalIsolation() {
|
|
82493
83729
|
if (!restoreTerminal)
|
|
@@ -82552,7 +83788,7 @@ function hasResolvableAnthropicAuth(deps = {}) {
|
|
|
82552
83788
|
if (isRealAnthropicEnvCredential(env, "ANTHROPIC_API_KEY") || isRealAnthropicEnvCredential(env, "ANTHROPIC_AUTH_TOKEN")) {
|
|
82553
83789
|
return true;
|
|
82554
83790
|
}
|
|
82555
|
-
if (fileExists(
|
|
83791
|
+
if (fileExists(join57(homedir37(), ".claude", ".credentials.json")))
|
|
82556
83792
|
return true;
|
|
82557
83793
|
return keychainProbe();
|
|
82558
83794
|
}
|
|
@@ -82567,7 +83803,7 @@ function isProxyAuthMode(config) {
|
|
|
82567
83803
|
}
|
|
82568
83804
|
function managedSettingsPath() {
|
|
82569
83805
|
if (isWindows2()) {
|
|
82570
|
-
return
|
|
83806
|
+
return join57(process.env.PROGRAMDATA || "C:\\ProgramData", "ClaudeCode", "managed-settings.json");
|
|
82571
83807
|
}
|
|
82572
83808
|
if (process.platform === "darwin") {
|
|
82573
83809
|
return "/Library/Application Support/ClaudeCode/managed-settings.json";
|
|
@@ -82588,9 +83824,9 @@ function isWindows2() {
|
|
|
82588
83824
|
}
|
|
82589
83825
|
function createStatusLineScript(tokenFilePath) {
|
|
82590
83826
|
const homeDir = process.env.HOME || process.env.USERPROFILE || tmpdir3();
|
|
82591
|
-
const claudishDir =
|
|
83827
|
+
const claudishDir = join57(homeDir, ".claudish");
|
|
82592
83828
|
const timestamp = Date.now();
|
|
82593
|
-
const scriptPath =
|
|
83829
|
+
const scriptPath = join57(claudishDir, `status-${timestamp}.js`);
|
|
82594
83830
|
const escapedTokenPath = tokenFilePath.replace(/\\/g, "\\\\");
|
|
82595
83831
|
const light = getThemeMode() === "light";
|
|
82596
83832
|
const cyanCode = light ? "38;2;14;116;144" : "96";
|
|
@@ -82728,7 +83964,7 @@ process.stdin.on('end', () => {
|
|
|
82728
83964
|
}
|
|
82729
83965
|
function initializeTokenFile(tokenFilePath) {
|
|
82730
83966
|
try {
|
|
82731
|
-
mkdirSync25(
|
|
83967
|
+
mkdirSync25(dirname16(tokenFilePath), { recursive: true });
|
|
82732
83968
|
writeFileSync28(tokenFilePath, JSON.stringify({
|
|
82733
83969
|
input_tokens: 0,
|
|
82734
83970
|
output_tokens: 0,
|
|
@@ -82760,7 +83996,7 @@ function cleanupStaleTokenFiles(dir, now = Date.now(), maxAgeMs = STALE_TOKEN_FI
|
|
|
82760
83996
|
if (!name.startsWith("tokens-") || !name.endsWith(".json"))
|
|
82761
83997
|
continue;
|
|
82762
83998
|
scanned++;
|
|
82763
|
-
const full =
|
|
83999
|
+
const full = join57(dir, name);
|
|
82764
84000
|
try {
|
|
82765
84001
|
if (statSync14(full).mtimeMs >= cutoff)
|
|
82766
84002
|
continue;
|
|
@@ -82789,9 +84025,9 @@ function parseSettingsArgSafe(value) {
|
|
|
82789
84025
|
}
|
|
82790
84026
|
function userSettingsFileCandidates(cwd) {
|
|
82791
84027
|
return [
|
|
82792
|
-
|
|
82793
|
-
|
|
82794
|
-
|
|
84028
|
+
join57(homedir37(), ".claude", "settings.json"),
|
|
84029
|
+
join57(cwd, ".claude", "settings.json"),
|
|
84030
|
+
join57(cwd, ".claude", "settings.local.json")
|
|
82795
84031
|
];
|
|
82796
84032
|
}
|
|
82797
84033
|
function discoverUserStatusLineCommand(claudeArgs = [], cwd = process.cwd()) {
|
|
@@ -82832,12 +84068,12 @@ function buildChainedStatusCommand(userCommand, claudishBody, claudishSegment) {
|
|
|
82832
84068
|
}
|
|
82833
84069
|
function createTempSettingsFile(_modelDisplay, port, proxyAuthMode, userStatusLineCommand) {
|
|
82834
84070
|
const homeDir = process.env.HOME || process.env.USERPROFILE || tmpdir3();
|
|
82835
|
-
const claudishDir =
|
|
84071
|
+
const claudishDir = join57(homeDir, ".claudish");
|
|
82836
84072
|
try {
|
|
82837
84073
|
mkdirSync25(claudishDir, { recursive: true });
|
|
82838
84074
|
} catch {}
|
|
82839
84075
|
const timestamp = Date.now();
|
|
82840
|
-
const tempPath =
|
|
84076
|
+
const tempPath = join57(claudishDir, `settings-${timestamp}.json`);
|
|
82841
84077
|
const assignedFile = assignedTokenFile(process.env) !== null;
|
|
82842
84078
|
const tokenFilePath = resolveTokenFilePath(port);
|
|
82843
84079
|
cleanupStaleTokenFiles(claudishDir);
|
|
@@ -83216,7 +84452,7 @@ async function runClaudeWithProxy(config, proxyUrl, onCleanup) {
|
|
|
83216
84452
|
console.error(`
|
|
83217
84453
|
Or set CLAUDE_PATH to your custom installation:`);
|
|
83218
84454
|
const home = homedir37();
|
|
83219
|
-
const localPath = isWindows2() ?
|
|
84455
|
+
const localPath = isWindows2() ? join57(home, ".claude", "local", "claude.exe") : join57(home, ".claude", "local", "claude");
|
|
83220
84456
|
console.error(` export CLAUDE_PATH=${localPath}`);
|
|
83221
84457
|
process.exit(1);
|
|
83222
84458
|
}
|
|
@@ -83329,15 +84565,15 @@ async function findClaudeBinary() {
|
|
|
83329
84565
|
}
|
|
83330
84566
|
}
|
|
83331
84567
|
const home = homedir37();
|
|
83332
|
-
const localPath = isWindows ?
|
|
84568
|
+
const localPath = isWindows ? join57(home, ".claude", "local", "claude.exe") : join57(home, ".claude", "local", "claude");
|
|
83333
84569
|
if (existsSync39(localPath)) {
|
|
83334
84570
|
return localPath;
|
|
83335
84571
|
}
|
|
83336
84572
|
if (isWindows) {
|
|
83337
84573
|
const windowsPaths = [
|
|
83338
|
-
|
|
83339
|
-
|
|
83340
|
-
|
|
84574
|
+
join57(home, "AppData", "Roaming", "npm", "claude.cmd"),
|
|
84575
|
+
join57(home, ".npm-global", "claude.cmd"),
|
|
84576
|
+
join57(home, "node_modules", ".bin", "claude.cmd")
|
|
83341
84577
|
];
|
|
83342
84578
|
for (const path of windowsPaths) {
|
|
83343
84579
|
if (existsSync39(path)) {
|
|
@@ -83348,11 +84584,11 @@ async function findClaudeBinary() {
|
|
|
83348
84584
|
const commonPaths = [
|
|
83349
84585
|
"/usr/local/bin/claude",
|
|
83350
84586
|
"/opt/homebrew/bin/claude",
|
|
83351
|
-
|
|
83352
|
-
|
|
83353
|
-
|
|
84587
|
+
join57(home, ".npm-global/bin/claude"),
|
|
84588
|
+
join57(home, ".local/bin/claude"),
|
|
84589
|
+
join57(home, "node_modules/.bin/claude"),
|
|
83354
84590
|
"/data/data/com.termux/files/usr/bin/claude",
|
|
83355
|
-
|
|
84591
|
+
join57(home, "../usr/bin/claude")
|
|
83356
84592
|
];
|
|
83357
84593
|
for (const path of commonPaths) {
|
|
83358
84594
|
if (existsSync39(path)) {
|
|
@@ -83437,16 +84673,16 @@ var init_claude_runner = __esm(() => {
|
|
|
83437
84673
|
// src/diag-output.ts
|
|
83438
84674
|
import { createWriteStream as createWriteStream2, mkdirSync as mkdirSync26, unlinkSync as unlinkSync11, writeFileSync as writeFileSync29 } from "fs";
|
|
83439
84675
|
import { homedir as homedir38 } from "os";
|
|
83440
|
-
import { join as
|
|
84676
|
+
import { join as join58 } from "path";
|
|
83441
84677
|
function getClaudishDir() {
|
|
83442
|
-
const dir =
|
|
84678
|
+
const dir = join58(homedir38(), ".claudish");
|
|
83443
84679
|
try {
|
|
83444
84680
|
mkdirSync26(dir, { recursive: true });
|
|
83445
84681
|
} catch {}
|
|
83446
84682
|
return dir;
|
|
83447
84683
|
}
|
|
83448
84684
|
function getDiagLogPath() {
|
|
83449
|
-
return
|
|
84685
|
+
return join58(getClaudishDir(), `diag-${process.pid}.log`);
|
|
83450
84686
|
}
|
|
83451
84687
|
|
|
83452
84688
|
class LogFileDiagOutput {
|
|
@@ -86061,7 +87297,7 @@ init_startup_trace();
|
|
|
86061
87297
|
init_picker_cancelled();
|
|
86062
87298
|
var import_dotenv3 = __toESM(require_main(), 1);
|
|
86063
87299
|
import { existsSync as existsSync40, readFileSync as readFileSync40 } from "fs";
|
|
86064
|
-
import { join as
|
|
87300
|
+
import { join as join59, resolve as resolve8 } from "path";
|
|
86065
87301
|
|
|
86066
87302
|
// src/tui/runtime/should-open-picker.ts
|
|
86067
87303
|
function noModelConfigured(gate) {
|
|
@@ -86173,7 +87409,7 @@ async function applyOpImport() {
|
|
|
86173
87409
|
async function applyConfigOverride() {
|
|
86174
87410
|
await Promise.resolve();
|
|
86175
87411
|
const plan = planConfigOverride(process.argv.slice(2), process.env, {
|
|
86176
|
-
resolve:
|
|
87412
|
+
resolve: resolve8,
|
|
86177
87413
|
exists: existsSync40
|
|
86178
87414
|
});
|
|
86179
87415
|
if (plan.kind === "none")
|
|
@@ -86377,7 +87613,7 @@ async function runCli() {
|
|
|
86377
87613
|
process.exit(1);
|
|
86378
87614
|
}
|
|
86379
87615
|
const mode = cliConfig.teamMode ?? "default";
|
|
86380
|
-
const sessionPath =
|
|
87616
|
+
const sessionPath = join59(process.cwd(), `.claudish-team-${Date.now()}`);
|
|
86381
87617
|
if (mode === "json") {
|
|
86382
87618
|
await Promise.resolve().then(() => init_pane());
|
|
86383
87619
|
await Promise.resolve().then(() => init_team_orchestrator());
|
|
@@ -86397,7 +87633,7 @@ async function runCli() {
|
|
|
86397
87633
|
const status = await runModels(sessionPath);
|
|
86398
87634
|
const result = { ...status, responses: {} };
|
|
86399
87635
|
for (const anonId of Object.keys(status.models)) {
|
|
86400
|
-
const responsePath =
|
|
87636
|
+
const responsePath = join59(sessionPath, `response-${anonId}.md`);
|
|
86401
87637
|
try {
|
|
86402
87638
|
const raw = readFileSync40(responsePath, "utf-8").trim();
|
|
86403
87639
|
try {
|