@rallycry/conveyor-agent 10.13.51 → 10.13.52
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{boot-BZE36LT6.js → boot-6X5ZZG3B.js} +3 -3
- package/dist/{chunk-HVSPADKP.js → chunk-DSP4KR4B.js} +2 -2
- package/dist/{chunk-KZQBYSMN.js → chunk-UAGIXPYD.js} +3 -6
- package/dist/chunk-UAGIXPYD.js.map +1 -0
- package/dist/{chunk-EQO7QFGN.js → chunk-ZTLGCN5G.js} +413 -161
- package/dist/chunk-ZTLGCN5G.js.map +1 -0
- package/dist/cli.js +4 -4
- package/dist/index.js +2 -2
- package/dist/{server-PPTELJWY.js → server-EQUCOLNY.js} +3 -3
- package/package.json +1 -1
- package/dist/chunk-EQO7QFGN.js.map +0 -1
- package/dist/chunk-KZQBYSMN.js.map +0 -1
- /package/dist/{boot-BZE36LT6.js.map → boot-6X5ZZG3B.js.map} +0 -0
- /package/dist/{chunk-HVSPADKP.js.map → chunk-DSP4KR4B.js.map} +0 -0
- /package/dist/{server-PPTELJWY.js.map → server-EQUCOLNY.js.map} +0 -0
|
@@ -15,8 +15,8 @@ import {
|
|
|
15
15
|
} from "./chunk-4VUQ2NPF.js";
|
|
16
16
|
import {
|
|
17
17
|
startWorkbenchServer
|
|
18
|
-
} from "./chunk-
|
|
19
|
-
import "./chunk-
|
|
18
|
+
} from "./chunk-DSP4KR4B.js";
|
|
19
|
+
import "./chunk-UAGIXPYD.js";
|
|
20
20
|
import {
|
|
21
21
|
DEFAULT_WORKBENCH_PORT
|
|
22
22
|
} from "./chunk-JIGG755T.js";
|
|
@@ -1297,4 +1297,4 @@ export {
|
|
|
1297
1297
|
runBoot,
|
|
1298
1298
|
workbenchBootSteps
|
|
1299
1299
|
};
|
|
1300
|
-
//# sourceMappingURL=boot-
|
|
1300
|
+
//# sourceMappingURL=boot-6X5ZZG3B.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
loadPtySpawn,
|
|
3
3
|
terminateProcessGroup
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-UAGIXPYD.js";
|
|
5
5
|
import {
|
|
6
6
|
FrameReader,
|
|
7
7
|
timingSafeTokenEqual,
|
|
@@ -296,4 +296,4 @@ async function runReaddir(socket, req) {
|
|
|
296
296
|
export {
|
|
297
297
|
startWorkbenchServer
|
|
298
298
|
};
|
|
299
|
-
//# sourceMappingURL=chunk-
|
|
299
|
+
//# sourceMappingURL=chunk-DSP4KR4B.js.map
|
|
@@ -115,10 +115,7 @@ function resolveRawTuiProbeTiming() {
|
|
|
115
115
|
ackMs: envMs("CONVEYOR_PTY_RAW_PROBE_ACK_MS", RAW_TUI_PROBE_ACK_MS),
|
|
116
116
|
retryMs: envMs("CONVEYOR_PTY_RAW_PROBE_RETRY_MS", RAW_TUI_PROBE_RETRY_MS),
|
|
117
117
|
pollMs: envMs("CONVEYOR_PTY_RAW_PROBE_POLL_MS", RAW_TUI_PROBE_POLL_MS),
|
|
118
|
-
firstOutputMaxMs: envMs(
|
|
119
|
-
"CONVEYOR_PTY_RAW_FIRST_OUTPUT_MAX_MS",
|
|
120
|
-
RAW_TUI_FIRST_OUTPUT_MAX_MS
|
|
121
|
-
),
|
|
118
|
+
firstOutputMaxMs: envMs("CONVEYOR_PTY_RAW_FIRST_OUTPUT_MAX_MS", RAW_TUI_FIRST_OUTPUT_MAX_MS),
|
|
122
119
|
maxMs: envMs("CONVEYOR_PTY_RAW_INPUT_LIVE_MAX_MS", RAW_TUI_INPUT_LIVE_MAX_MS)
|
|
123
120
|
};
|
|
124
121
|
}
|
|
@@ -130,7 +127,7 @@ function sawTerminalSetup(rawOutput) {
|
|
|
130
127
|
return DEC_PRIVATE_MODE.test(rawOutput);
|
|
131
128
|
}
|
|
132
129
|
function needsRawReadyGate(caps) {
|
|
133
|
-
return
|
|
130
|
+
return caps.rawPromptGate;
|
|
134
131
|
}
|
|
135
132
|
function resolveSubmitNudgeTiming() {
|
|
136
133
|
return {
|
|
@@ -407,4 +404,4 @@ export {
|
|
|
407
404
|
runAuthTokenCommand,
|
|
408
405
|
runStartCommand
|
|
409
406
|
};
|
|
410
|
-
//# sourceMappingURL=chunk-
|
|
407
|
+
//# sourceMappingURL=chunk-UAGIXPYD.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/harness/pty/pty-support.ts","../src/harness/pty/spawn-args.ts","../src/utils/sleep.ts","../src/setup/commands.ts"],"sourcesContent":["/**\n * Pure support helpers for PtySession — node-pty process loading, prompt-byte\n * encoding, the per-turn options projection, and the AskUserQuestion parser.\n * Extracted from `session.ts` so the orchestrator stays focused on lifecycle;\n * everything here is side-effect-free (or a thin wrapper over one) and unit\n * tested in isolation.\n */\n\nimport { stat } from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport type { HarnessQueryOptions, HarnessUserQuestion } from \"../types.js\";\n// spawn-args does not import this module, so this direction introduces no cycle.\nimport { cleanTerminalOutput } from \"./spawn-args.js\";\n\n// Cap on the rolling tail of raw terminal output retained for diagnostics when\n// `claude` exits without a result. Bounded so a long-running session can't grow\n// this unboundedly; only the most recent bytes (where a failure surfaces) matter.\nexport const MAX_DIAGNOSTIC_OUTPUT = 4000;\n\n// Cap on transcript events buffered while no turn is draining (the parked\n// window between a completed turn and the next beginTurn / a passive turn).\n// Bounded, drop-oldest — a stale buffered `result` must never terminate a\n// fresh turn, and beginTurn clears the buffer anyway.\nexport const MAX_BETWEEN_TURN_BUFFER = 500;\n\n/** Settle window between the paste write and the submitting Enter write. */\nexport const SUBMIT_SETTLE_MS = 300;\n// Re-press cadence/bounds for the submit nudge (see armSubmitNudge). Fast\n// presses cover the Enter-swallowed-at-startup race; the slow phase covers\n// startup dialogs that render tens of seconds in on a cold pod (folder\n// trust, onboarding) — observed live 2026-07-02 parking code reviews ~13min+\n// when the trust dialog mounted after the fast window had expired.\nexport const SUBMIT_NUDGE_INTERVAL_MS = 2000;\nexport const SUBMIT_NUDGE_MAX_PRESSES = 5;\nexport const SUBMIT_NUDGE_SLOW_INTERVAL_MS = 5000;\nexport const SUBMIT_NUDGE_WINDOW_MS = 90_000;\n\n// How many times a failed prompt submission is recovered by tearing the CLI\n// down and respawning it with the same prompt. The nudge only presses Enter,\n// which cannot clear a startup dialog needing an arrow-key selection (the\n// 2026-07-22 fable-model-picker outage parked TUIs exactly that way) — a fresh\n// process is the only in-pod escape from that state. Bounded because a spawn\n// that reliably parks will park again, and an unbounded respawn loop would burn\n// the pod instead of surfacing the failure.\nexport const SUBMIT_REDELIVERY_MAX_ATTEMPTS = 2;\n\n// Plan-dialog auto-accept press cadence/bounds (see armPlanDialogAutoAccept).\n// The dialog usually renders within a second of the ExitPlanMode hook verdict,\n// but the window is deliberately wide: the only stop signal is the ExitPlanMode\n// PostToolUse envelope, and a missed dialog parks an auto card indefinitely\n// (observed live 2026-07-07: an approval dialog sat 42 minutes until a human\n// pressed Enter).\nexport const PLAN_DIALOG_FIRST_PRESS_MS = 700;\nexport const PLAN_DIALOG_INTERVAL_MS = 1500;\nexport const PLAN_DIALOG_SLOW_INTERVAL_MS = 5000;\nexport const PLAN_DIALOG_FAST_WINDOW_MS = 10_000;\nexport const PLAN_DIALOG_WINDOW_MS = 90_000;\n\n// Input-readiness DETECTION before the FIRST prompt write to a raw-relay TUI.\n//\n// A structured-events TUI recovers a prompt lost to startup via the submit\n// nudge (re-press Enter until a transcript record proves the turn began). A raw\n// adapter has no such evidence, so the nudge is never armed for it (see\n// armSubmitNudge's caller) — the single paste + Enter it gets must therefore\n// land on an input box that is actually accepting keystrokes, or the turn is\n// lost silently with the prompt nowhere and the card parked on an empty box.\n//\n// We DETECT that state rather than infer it from elapsed time. The method:\n// type a short sentinel, and watch for the TUI to render THAT SENTINEL back.\n// Only a live input box echoes typed characters into its own repaint, so a\n// rendered sentinel is positive proof; then it is erased and the real prompt is\n// pasted exactly once.\n//\n// Signals that were measured and rejected (opencode 1.18.15 / Claude Code\n// 2.1.226, macOS, driving node-pty directly):\n// - DECSET 2004 (bracketed-paste enable). Both TUIs set it in their FIRST\n// paint — opencode at 554ms, Claude at 267ms — ~2s before opencode accepts\n// input. It reports terminal setup, not input readiness.\n// - \"quiet since the last output frame\". opencode's startup paint contains an\n// internal ~1175ms gap (1172/1174/1177ms over three runs), so any quiet\n// window short enough to be responsive fires INSIDE the paint.\n// - \"any output right after our keystroke\". While the app is still painting,\n// output arrives coincidentally rather than causally: this reported ready at\n// 981ms and the prompt was then dropped. The ack must be the sentinel\n// itself, not merely activity.\n// - echoing the PROMPT back. opencode renders a multi-line paste as\n// \"[Pasted ~4 lines]\" and never shows the text, so the prompt cannot serve\n// as its own acknowledgement.\n//\n// Sentinel content is deliberately three inert lowercase letters: no digits\n// (Claude Code's folder-trust dialog is a numbered menu, where a stray \"1\"\n// would select \"Yes, I trust this folder\"), and no Enter/Esc/arrow keys.\nexport const RAW_TUI_PROBE_SENTINEL = \"zqx\";\n/** How long a probe waits for the TUI to render the sentinel back. */\nexport const RAW_TUI_PROBE_ACK_MS = 500;\n/** Gap between unacknowledged probes. */\nexport const RAW_TUI_PROBE_RETRY_MS = 250;\n/** Poll cadence while watching for the sentinel / for first output. */\nexport const RAW_TUI_PROBE_POLL_MS = 20;\n/** Bound on waiting for the process to paint anything at all. */\nexport const RAW_TUI_FIRST_OUTPUT_MAX_MS = 10_000;\n// Overall cap. On expiry we paste anyway rather than hang the turn: the adapter's\n// own exit diagnostics are a better failure signal than a silent stall.\nexport const RAW_TUI_INPUT_LIVE_MAX_MS = 20_000;\n\nfunction envMs(name: string, fallback: number): number {\n const raw = Number(process.env[name]);\n return Number.isFinite(raw) && raw > 0 ? raw : fallback;\n}\n\nexport function resolveSubmitSettleMs(): number {\n return envMs(\"CONVEYOR_PTY_SUBMIT_SETTLE_MS\", SUBMIT_SETTLE_MS);\n}\n\n/**\n * Effective raw-TUI input-probe timing. Overridable for ops and so tests can\n * drive the detector in milliseconds instead of seconds of real wall-clock.\n * `sentinel` is overridable too, for a TUI that ever treats \"zqx\" specially.\n */\nexport function resolveRawTuiProbeTiming(): {\n sentinel: string;\n ackMs: number;\n retryMs: number;\n pollMs: number;\n firstOutputMaxMs: number;\n maxMs: number;\n} {\n const sentinel = process.env.CONVEYOR_PTY_RAW_PROBE_SENTINEL;\n return {\n // A sentinel must be non-empty (it is what we search for) and must stay\n // free of digits and control chars — see the note on menu dialogs above.\n sentinel: sentinel && /^[a-z]{1,8}$/.test(sentinel) ? sentinel : RAW_TUI_PROBE_SENTINEL,\n ackMs: envMs(\"CONVEYOR_PTY_RAW_PROBE_ACK_MS\", RAW_TUI_PROBE_ACK_MS),\n retryMs: envMs(\"CONVEYOR_PTY_RAW_PROBE_RETRY_MS\", RAW_TUI_PROBE_RETRY_MS),\n pollMs: envMs(\"CONVEYOR_PTY_RAW_PROBE_POLL_MS\", RAW_TUI_PROBE_POLL_MS),\n firstOutputMaxMs: envMs(\"CONVEYOR_PTY_RAW_FIRST_OUTPUT_MAX_MS\", RAW_TUI_FIRST_OUTPUT_MAX_MS),\n maxMs: envMs(\"CONVEYOR_PTY_RAW_INPUT_LIVE_MAX_MS\", RAW_TUI_INPUT_LIVE_MAX_MS),\n };\n}\n\n/**\n * Did a TUI render our probe sentinel back? Positive proof that a live input box\n * consumed the keystrokes — the one signal that discriminated correctly in\n * testing (see the rejected-signals note above).\n *\n * Pure so the matching rule is testable without a pty. Compares against ANSI-\n * stripped output because the sentinel is repainted inside styling runs.\n *\n * PRECONDITION: the child must already own the terminal. Until a TUI switches\n * the tty out of canonical mode the line discipline echoes our own keystrokes\n * straight back, which is indistinguishable from a repaint and false-positives\n * immediately. `sawTerminalSetup` is the gate for that — always wait for it\n * first.\n */\nexport function sentinelEchoed(rawOutput: string, sentinel: string): boolean {\n return cleanTerminalOutput(rawOutput, Number.MAX_SAFE_INTEGER).includes(sentinel);\n}\n\n/** DEC private mode set/reset — `ESC [ ? <params> h|l`. */\nconst DEC_PRIVATE_MODE = new RegExp(`${String.fromCharCode(27)}\\\\[\\\\?[0-9;]+[hl]`);\n\n/**\n * Has the child taken control of the terminal?\n *\n * A DEC private-mode write (alternate screen, bracketed paste, mouse tracking,\n * cursor visibility…) is the child reconfiguring the tty for full-screen use,\n * which is also when it drops canonical mode and echo. Both TUIs do it in their\n * first paint — opencode at 554ms, Claude Code at 267ms — so this is a cheap,\n * observed precondition rather than another timer.\n *\n * It is deliberately NOT used as a readiness signal on its own: opencode sets\n * bracketed-paste ~2s before it will accept input. It only tells us our own\n * keystrokes will no longer be echoed by the kernel, making a sentinel echo\n * attributable to the app.\n */\nexport function sawTerminalSetup(rawOutput: string): boolean {\n return DEC_PRIVATE_MODE.test(rawOutput);\n}\n\n/**\n * Does this adapter's first prompt write need the readiness gate?\n *\n * A per-adapter capability, NOT derived from structuredEvents: opencode keeps\n * the gate even with the events plugin wired, because its TUI silently\n * discards early stdin while painting — the pasted text itself is lost, which\n * no submit nudge can recover. Claude skips it (the nudge suffices, and its\n * numbered startup menus make stray probe keystrokes actively unsafe).\n * Exported so the contract is pinned by a test rather than resting on one\n * `if` inside the session.\n */\nexport function needsRawReadyGate(caps: { rawPromptGate: boolean }): boolean {\n return caps.rawPromptGate;\n}\n\n/**\n * Effective submit-nudge timing. The exported constants above are the production\n * defaults; `CONVEYOR_PTY_NUDGE_INTERVAL_MS` / `_SLOW_INTERVAL_MS` / `_WINDOW_MS`\n * override them. Resolved at nudge-arm time (not import) so an integration test\n * can drive the two-phase fast→slow behavior in milliseconds instead of ~15s of\n * real wall-clock. `maxPresses` is deliberately NOT overridable — the fast→slow\n * phase-boundary count is the behavior under test.\n */\nexport function resolveSubmitNudgeTiming(): {\n intervalMs: number;\n slowIntervalMs: number;\n maxPresses: number;\n windowMs: number;\n} {\n return {\n intervalMs: envMs(\"CONVEYOR_PTY_NUDGE_INTERVAL_MS\", SUBMIT_NUDGE_INTERVAL_MS),\n slowIntervalMs: envMs(\"CONVEYOR_PTY_NUDGE_SLOW_INTERVAL_MS\", SUBMIT_NUDGE_SLOW_INTERVAL_MS),\n maxPresses: SUBMIT_NUDGE_MAX_PRESSES,\n windowMs: envMs(\"CONVEYOR_PTY_NUDGE_WINDOW_MS\", SUBMIT_NUDGE_WINDOW_MS),\n };\n}\n\n/**\n * How many respawn-and-redeliver attempts a failed prompt submission gets.\n * `CONVEYOR_PTY_SUBMIT_REDELIVERY_MAX` overrides it; `0` disables recovery\n * entirely (the failure is still detected and reported). Resolved at use time\n * so tests and ops can change it without a restart-order dependency.\n */\nexport function resolveSubmitRedeliveryMaxAttempts(): number {\n const value = process.env.CONVEYOR_PTY_SUBMIT_REDELIVERY_MAX;\n // An empty string is \"unset\", not \"0\" — `Number(\"\")` is 0, which would\n // silently disable recovery for anyone exporting the var blank.\n if (!value) return SUBMIT_REDELIVERY_MAX_ATTEMPTS;\n const raw = Number(value);\n return Number.isFinite(raw) && raw >= 0 ? raw : SUBMIT_REDELIVERY_MAX_ATTEMPTS;\n}\n\nexport function resolvePlanDialogTiming(): {\n firstPressMs: number;\n intervalMs: number;\n slowIntervalMs: number;\n fastWindowMs: number;\n windowMs: number;\n} {\n return {\n firstPressMs: envMs(\"CONVEYOR_PTY_PLAN_DIALOG_FIRST_PRESS_MS\", PLAN_DIALOG_FIRST_PRESS_MS),\n intervalMs: envMs(\"CONVEYOR_PTY_PLAN_DIALOG_INTERVAL_MS\", PLAN_DIALOG_INTERVAL_MS),\n slowIntervalMs: envMs(\n \"CONVEYOR_PTY_PLAN_DIALOG_SLOW_INTERVAL_MS\",\n PLAN_DIALOG_SLOW_INTERVAL_MS,\n ),\n fastWindowMs: envMs(\"CONVEYOR_PTY_PLAN_DIALOG_FAST_WINDOW_MS\", PLAN_DIALOG_FAST_WINDOW_MS),\n windowMs: envMs(\"CONVEYOR_PTY_PLAN_DIALOG_WINDOW_MS\", PLAN_DIALOG_WINDOW_MS),\n };\n}\n\n/**\n * The per-turn subset of HarnessQueryOptions — everything that legitimately\n * changes from one turn to the next while the same `claude` process serves them\n * all. The process-level fields (model, cwd, sessionId, appendSystemPrompt, …)\n * are fixed at spawn and captured separately in the spawn options.\n */\nexport interface TurnOptions {\n canUseTool?: HarnessQueryOptions[\"canUseTool\"];\n promptDelivery?: \"submit\" | \"prefill\";\n planDialogAutoAccept?: boolean;\n abortController?: AbortController;\n}\n\nexport function turnOptionsFrom(options: HarnessQueryOptions): TurnOptions {\n return {\n canUseTool: options.canUseTool,\n promptDelivery: options.promptDelivery,\n planDialogAutoAccept: options.planDialogAutoAccept,\n abortController: options.abortController,\n };\n}\n\nexport interface PtyProcess {\n /** node-pty exposes the child's pid (its own session/process-group leader\n * via forkpty). Optional because test fakes don't model a real process. */\n pid?: number;\n onData(listener: (data: string) => void): void;\n onExit(listener: (event: { exitCode: number }) => void): void;\n write(data: string): void;\n resize(cols: number, rows: number): void;\n kill(signal?: string): void;\n}\n\nexport const KILL_ESCALATION_MS = 5_000;\n\n/**\n * Kill a pty, escalating to SIGKILL if it hasn't exited within `escalationMs`.\n * node-pty's default kill (SIGHUP) can be ignored by a wedged `claude` (e.g.\n * mid-OOM), and a fire-and-forget kill would then leak the ~1GB process on the\n * pod. `hasExited()` (backed by the caller's onExit handler) cancels the\n * escalation on a clean exit; the timer is unref'd so it never holds the\n * process open on its own.\n */\nexport function killPtyWithEscalation(\n pty: Pick<PtyProcess, \"kill\">,\n hasExited: () => boolean,\n escalationMs: number = KILL_ESCALATION_MS,\n): void {\n try {\n pty.kill();\n } catch {\n /* already exited */\n }\n const timer = setTimeout(() => {\n if (hasExited()) return;\n try {\n pty.kill(\"SIGKILL\");\n } catch {\n /* already exited */\n }\n }, escalationMs);\n timer.unref?.();\n}\n\nexport interface PtySpawnOptions {\n name: string;\n cols: number;\n rows: number;\n cwd: string;\n env: Record<string, string>;\n}\n\nexport type PtySpawn = (file: string, args: string[], options: PtySpawnOptions) => PtyProcess;\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null;\n}\n\nfunction extractSpawn(mod: unknown): PtySpawn | null {\n if (!isRecord(mod)) return null;\n if (typeof mod.spawn === \"function\") return mod.spawn as PtySpawn;\n const def = mod.default;\n if (isRecord(def) && typeof def.spawn === \"function\") return def.spawn as PtySpawn;\n return null;\n}\n\nexport async function loadPtySpawn(): Promise<PtySpawn> {\n const mod: unknown = await import(\"node-pty\");\n const spawn = extractSpawn(mod);\n if (!spawn) throw new Error(\"node-pty: spawn export not found\");\n return spawn;\n}\n\n/**\n * The spawn implementation for this pod topology: node-pty locally, or the\n * workbench launcher's remote PTY in split-mode pods (the CLI must run in the\n * workbench container, next to the repo and inside the restartable cgroup).\n * Same PtySpawn contract either way — PtySession is topology-blind.\n */\nexport async function resolvePtySpawn(): Promise<PtySpawn> {\n const { workbenchEnabled } = await import(\"../../workbench/mode.js\");\n if (!workbenchEnabled()) return loadPtySpawn();\n const { getWorkbenchClient } = await import(\"../../workbench/client.js\");\n return (file, args, options) => getWorkbenchClient().spawnPty(file, args, options);\n}\n\n/**\n * Base directory for a PTY session's control files (settings.json,\n * mcp-config, hook socket). In split-mode pods this MUST be the shared\n * emptyDir — the spawned CLI reads these paths from the workbench container,\n * and the hook helper connects back over the unix socket, which crosses\n * containers only on a shared volume.\n */\nexport function sessionTempBase(): string {\n return process.env.CONVEYOR_SHARED_DIR ?? tmpdir();\n}\n\nexport function inheritedEnv(socketPath?: string): Record<string, string> {\n const env: Record<string, string> = {};\n for (const [key, value] of Object.entries(process.env)) {\n if (typeof value === \"string\") env[key] = value;\n }\n // Do NOT force CLAUDE_CONFIG_DIR. Forcing it to ~/.claude makes the CLI read\n // <dir>/.claude.json — a fresh, un-onboarded config — instead of the user's\n // real ~/.claude.json, which re-triggers the first-run theme picker + login\n // even though valid credentials already exist in ~/.claude/. The loop above\n // already propagates an explicitly-set CLAUDE_CONFIG_DIR (pods/codespaces),\n // and the config dir is unchanged either way, so transcript tailing (which\n // uses claudeConfigHome()) still resolves to the same projects/ directory.\n // Belt-and-braces against the ANTHROPIC_API_KEY leak: when a subscription\n // OAuth token is in play, the TUI authenticates via the synthesized\n // credentials.json — an inherited ANTHROPIC_API_KEY would be treated as an\n // EXTERNAL API key and, once interactively approved, poison auth (the token\n // is sent via x-api-key → 401 forever). The API bundle already stops serving\n // the OAuth token under that name; stripping it here means no upstream leak\n // can reach the spawned CLI regardless. The two auth modes are mutually\n // exclusive (see session-runner's onApiKeyUpdate), so a real api_key launch\n // has no CLAUDE_CODE_OAUTH_TOKEN and keeps its ANTHROPIC_API_KEY.\n if (env.CLAUDE_CODE_OAUTH_TOKEN) {\n delete env.ANTHROPIC_API_KEY;\n }\n if (socketPath) {\n env.CONVEYOR_HOOK_SOCKET = socketPath;\n }\n // The conveyor MCP tool handlers proxy over the agent's API socket, and a\n // mid-flap call can block up to ~50s (20s reconnect-wait + 30s ack) before\n // failing with a retryable error. The CLI's default MCP timeouts are\n // shorter — hitting them made it abandon the MCP session mid-flap\n // (2026-07-08 wedge). Default both timeouts past the worst-case hang;\n // operator-set values win via the inherit loop above.\n env.MCP_TIMEOUT ??= \"60000\";\n env.MCP_TOOL_TIMEOUT ??= \"180000\";\n return env;\n}\n\n/**\n * The bracketed-paste bytes written to the CLI's stdin to deliver a prompt.\n * The text is wrapped in paste markers so embedded newlines land as literal\n * lines in the input box instead of submitting it early. The submitting Enter\n * is deliberately NOT part of these bytes: deliverPrompt() sends it as a\n * separate write after a settle window, because an Enter folded into the same\n * chunk as the paste can be swallowed by the CLI's paste-burst handling —\n * observed in production as an auto-mode prompt parked unsubmitted in the\n * input box. \"prefill\" delivery never sends an Enter at all.\n */\nexport function buildPromptBytes(text: string): string {\n return `\\x1b[200~${text}\\x1b[201~`;\n}\n\n/**\n * Render structured (multimodal) prompt content as pasteable text. Image\n * blocks are replaced with a tool reference — their base64 payload must NEVER\n * be pasted into the TUI input box. Upstream prompt builders already skip\n * image blocks for the PTY harness; this is the last line of defense.\n */\nexport function renderPromptContentText(content: unknown[]): string {\n return content\n .map((block) => {\n const b = block as { type?: string; text?: string };\n if (b?.type === \"text\" && typeof b.text === \"string\") return b.text;\n if (b?.type === \"image\") {\n return `[Image attachment — use list_task_files / get_attachment to view]`;\n }\n return JSON.stringify(block);\n })\n .join(\"\\n\\n\");\n}\n\nexport { sleep } from \"../../utils/sleep.js\";\n\n/** Current size of the transcript, or 0 if it does not exist yet. */\nexport async function transcriptSize(path: string): Promise<number> {\n try {\n return (await stat(path)).size;\n } catch {\n return 0;\n }\n}\n\n/**\n * Defensive extraction of AskUserQuestion's `questions` input from the hook\n * payload. Malformed entries are dropped rather than thrown — the event is\n * observe-only, so an empty list still arms the waiting_for_input report.\n */\nexport function parseUserQuestions(input: Record<string, unknown>): HarnessUserQuestion[] {\n if (!Array.isArray(input.questions)) return [];\n const questions: HarnessUserQuestion[] = [];\n for (const entry of input.questions) {\n if (!isRecord(entry)) continue;\n if (typeof entry.question !== \"string\") continue;\n const options = Array.isArray(entry.options)\n ? entry.options\n .filter(isRecord)\n .filter((o) => typeof o.label === \"string\")\n .map((o) => ({\n label: o.label as string,\n description: typeof o.description === \"string\" ? o.description : \"\",\n }))\n : [];\n questions.push({\n question: entry.question,\n header: typeof entry.header === \"string\" ? entry.header : \"\",\n options,\n ...(typeof entry.multiSelect === \"boolean\" ? { multiSelect: entry.multiSelect } : {}),\n });\n }\n return questions;\n}\n","/**\n * The `claude` CLI process boundary: resolve the binary, build its argv, and\n * interpret its exit when it dies before producing a result. Kept pure so it\n * can be unit-tested without a real spawn.\n */\n\nexport interface SpawnArgsInput {\n resume?: string;\n sessionId?: string;\n model: string;\n permissionMode: \"plan\" | \"bypassPermissions\";\n settingsPath: string;\n /** Extra system-prompt text appended via `--append-system-prompt`. */\n appendSystemPrompt?: string;\n mcpConfigPath?: string;\n /** When set with mcpConfigPath, the CLI uses ONLY that config and ignores the\n * user's `~/.claude.json` / project `.mcp.json` servers. */\n strictMcpConfig?: boolean;\n}\n\nexport function resolveClaudeBinary(): string {\n return process.env.CONVEYOR_CLAUDE_BIN ?? \"claude\";\n}\n\nexport function buildSpawnArgs(input: SpawnArgsInput): string[] {\n const args: string[] = [];\n if (input.resume) {\n args.push(\"--resume\", input.resume);\n } else if (input.sessionId) {\n args.push(\"--session-id\", input.sessionId);\n }\n args.push(\"--model\", input.model);\n if (input.permissionMode === \"bypassPermissions\") {\n args.push(\"--dangerously-skip-permissions\");\n } else {\n args.push(\"--permission-mode\", \"plan\");\n }\n args.push(\"--settings\", input.settingsPath);\n if (input.appendSystemPrompt) {\n args.push(\"--append-system-prompt\", input.appendSystemPrompt);\n }\n if (input.mcpConfigPath) {\n args.push(\"--mcp-config\", input.mcpConfigPath);\n if (input.strictMcpConfig) {\n args.push(\"--strict-mcp-config\");\n }\n }\n return args;\n}\n\n/**\n * A stable fingerprint of the spawn arguments that a REUSED (kept-alive) CLI\n * process cannot change — model, permission mode, appended system prompt, and\n * cwd are all baked into the live `claude` process at spawn. When a follow-up\n * turn would spawn with different values (most commonly a drifted\n * `appendSystemPrompt` after a plan/status edit), the parked process cannot\n * serve it, so the harness respawns instead of reusing. Keeping this beside\n * `buildSpawnArgs` ensures the two can't silently diverge.\n *\n * `settingsPath`, `mcpConfigPath`, and the hook socket path are deliberately\n * excluded: they are per-process resources that stay stable for the process's\n * whole life, so they never differentiate one turn from the next.\n */\nexport function spawnOptionsFingerprint(input: {\n model: string;\n permissionMode: \"plan\" | \"bypassPermissions\";\n appendSystemPrompt?: string;\n cwd: string;\n}): string {\n return JSON.stringify([\n input.model,\n input.permissionMode,\n input.appendSystemPrompt ?? \"\",\n input.cwd,\n ]);\n}\n\n// ─── Exit diagnostics ──────────────────────────────────────────────────────\n// The PTY harness never turns raw `claude` stdout/stderr into HarnessEvents —\n// it relays them to the S5 terminal instead. So when `claude` dies before\n// emitting a transcript result, the captured agent logs show only the generic\n// \"claude exited (code N) without a result\"; the real reason (a missing binary,\n// an auth/onboarding stop, an unknown CLI flag) scrolled past in the live\n// terminal only. These helpers fold a bounded, ANSI-stripped tail of that\n// scrollback back into the error so the failure is self-describing in the logs.\n\n// ESC (0x1B) built via fromCharCode so no control char appears as a source\n// literal (keeps the no-control-regex lint rule happy). Matches CSI sequences\n// (ESC [ ... final-byte) — the bulk of TUI escape noise; any stray ESC bytes\n// from other sequences are removed by the control-char pass below.\nconst ANSI_CSI = new RegExp(`${String.fromCharCode(27)}\\\\[[0-9;?]*[ -/]*[@-~]`, \"g\");\n\n/**\n * Strip ANSI escapes + terminal control noise and collapse to the last few\n * readable lines, capped at `maxChars`. Returns \"\" when nothing printable\n * remains (e.g. the process produced no output at all).\n */\nexport function cleanTerminalOutput(raw: string, maxChars = 1200): string {\n const noAnsi = raw.replace(ANSI_CSI, \"\");\n // Drop C0 control chars (and DEL) except tab; fold CR into newline.\n let out = \"\";\n for (const ch of noAnsi) {\n const code = ch.charCodeAt(0);\n if (ch === \"\\r\" || ch === \"\\n\") out += \"\\n\";\n else if (ch === \"\\t\") out += ch;\n else if (code < 0x20 || code === 0x7f) continue;\n else out += ch;\n }\n const lines = out\n .split(\"\\n\")\n .map((line) => line.trimEnd())\n .filter((line) => line.trim().length > 0);\n const text = lines.join(\"\\n\").trim();\n return text.length > maxChars ? `…${text.slice(-maxChars)}` : text;\n}\n\n/**\n * True when the terminal tail shows node-pty failed to exec the target binary\n * (missing `claude` CLI on PATH). node-pty prints `execvp(3) failed.: No such\n * file or directory` to the pty and the child exits with code 1.\n */\nexport function isMissingBinaryFailure(tail: string): boolean {\n return /execvp\\(\\d+\\) failed|no such file or directory|command not found/i.test(tail);\n}\n\n/**\n * Build the `errors[]` for a `claude` process that exited before emitting a\n * transcript result. The first entry is kept byte-for-byte stable so existing\n * consumers/log scrapers that key off it keep working; richer context is\n * appended after it.\n */\nexport function buildExitErrors(exitCode: number, rawOutput: string, binary: string): string[] {\n const errors = [`claude exited (code ${exitCode}) without a result`];\n const tail = cleanTerminalOutput(rawOutput);\n if (isMissingBinaryFailure(tail)) {\n errors.push(\n `The \\`${binary}\\` CLI could not be started — it is not installed or not on PATH. ` +\n `Install the Claude Code CLI in this environment (npm i -g @anthropic-ai/claude-code) ` +\n `or set CONVEYOR_CLAUDE_BIN to its absolute path.`,\n );\n }\n if (tail) {\n errors.push(`Last terminal output before exit:\\n${tail}`);\n }\n return errors;\n}\n","export function sleep(ms: number): Promise<void> {\n return new Promise((resolve) => {\n setTimeout(resolve, ms);\n });\n}\n","import { spawn, execSync, type ChildProcess } from \"node:child_process\";\n\n/**\n * The structural surface of a start-command child the supervisor manages —\n * satisfied by a local ChildProcess and by the workbench client's\n * RemoteProcessHandle (split-mode pods, where the process lives in the\n * workbench container).\n */\nexport interface ManagedChildProcess extends NodeJS.EventEmitter {\n pid?: number | undefined;\n exitCode: number | null;\n kill(signal?: NodeJS.Signals | number): boolean;\n}\n\nconst PROCESS_TERMINATION_GRACE_MS = 5_000;\n\nfunction abortError(): Error {\n const error = new Error(\"Operation aborted\");\n error.name = \"AbortError\";\n return error;\n}\n\nfunction signalProcessGroup(child: ManagedChildProcess, signal: NodeJS.Signals): void {\n try {\n if (child.pid) process.kill(-child.pid, signal);\n else child.kill(signal);\n } catch {\n try {\n child.kill(signal);\n } catch {\n // The process already exited.\n }\n }\n}\n\nexport function terminateProcessGroup(\n // ChildProcess structurally satisfies ManagedChildProcess, so the single type\n // covers both callers; keeping them as a union makes the shared EventEmitter\n // methods (once/removeListener) non-callable under @types/node's overloads.\n child: ManagedChildProcess,\n graceMs = PROCESS_TERMINATION_GRACE_MS,\n): Promise<void> {\n if (child.exitCode !== null) return Promise.resolve();\n return new Promise((resolve) => {\n let settled = false;\n const finish = (): void => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n child.removeListener(\"exit\", finish);\n resolve();\n };\n const timer = setTimeout(() => {\n signalProcessGroup(child, \"SIGKILL\");\n finish();\n }, graceMs);\n timer.unref();\n child.once(\"exit\", finish);\n signalProcessGroup(child, \"SIGTERM\");\n });\n}\n\nexport function runSetupCommand(\n cmd: string,\n cwd: string,\n onOutput: (stream: \"stdout\" | \"stderr\", data: string) => void,\n signal?: AbortSignal,\n): Promise<void> {\n if (signal?.aborted) return Promise.reject(abortError());\n return new Promise((resolve, reject) => {\n const child = spawn(\"sh\", [\"-c\", cmd], {\n cwd,\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n detached: true,\n env: { ...process.env },\n });\n let settled = false;\n let aborting = false;\n const cleanup = (): void => signal?.removeEventListener(\"abort\", onAbort);\n const settle = (error?: Error): void => {\n if (settled) return;\n settled = true;\n cleanup();\n if (error) reject(error);\n else resolve();\n };\n const onAbort = (): void => {\n if (settled || aborting) return;\n aborting = true;\n void terminateProcessGroup(child).then(() => settle(abortError()));\n };\n signal?.addEventListener(\"abort\", onAbort, { once: true });\n if (signal?.aborted) onAbort();\n\n child.stdout.on(\"data\", (chunk: Buffer) => {\n if (aborting || signal?.aborted) return;\n onOutput(\"stdout\", chunk.toString());\n });\n\n child.stderr.on(\"data\", (chunk: Buffer) => {\n if (aborting || signal?.aborted) return;\n onOutput(\"stderr\", chunk.toString());\n });\n\n child.on(\"close\", (code) => {\n if (aborting) return;\n settle(code === 0 ? undefined : new Error(`Setup command exited with code ${code}`));\n });\n\n child.on(\"error\", (err) => {\n if (!aborting) settle(err);\n });\n });\n}\n\nconst AUTH_TOKEN_TIMEOUT_MS = 30_000;\n\nexport function runAuthTokenCommand(cmd: string, userEmail: string, cwd: string): string | null {\n try {\n const output = execSync(`${cmd} ${JSON.stringify(userEmail)}`, {\n cwd,\n timeout: AUTH_TOKEN_TIMEOUT_MS,\n stdio: [\"ignore\", \"pipe\", \"ignore\"],\n env: { ...process.env },\n });\n const token = output.toString().trim();\n return token || null;\n } catch {\n return null;\n }\n}\n\nexport function runStartCommand(\n cmd: string,\n cwd: string,\n onOutput: (stream: \"stdout\" | \"stderr\", data: string) => void,\n): ChildProcess {\n const child = spawn(\"sh\", [\"-c\", cmd], {\n cwd,\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n detached: true,\n env: { ...process.env },\n });\n\n child.stdout.on(\"data\", (chunk: Buffer) => {\n onOutput(\"stdout\", chunk.toString());\n });\n\n child.stderr.on(\"data\", (chunk: Buffer) => {\n onOutput(\"stderr\", chunk.toString());\n });\n\n child.unref();\n return child;\n}\n"],"mappings":"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","names":["spawn"]}
|