import assert from "node:assert/strict"; import { describe, it } from "node:test"; import { HerdrExternalNeedsAttentionError, HerdrExternalSession, createHerdrExternalAdapter, createHerdrExternalAdapterLaunch, monitorHerdrCodex, prepareInternalHerdrExternalAdapter, reconcileHerdrExternalRun, runHerdrExternalPreflight, validateHerdrExternalPreflight, type HerdrCodexSnapshot, type HerdrExternalLaunch } from "../../src/runs/shared/herdr-external-adapters.ts"; import { HerdrPlacedRunOwner } from "../../src/runs/shared/herdr-placed-run.ts"; import { settleHerdrExternalRunnerError } from "../../src/runs/background/subagent-runner.ts"; import { HerdrRpcError, HerdrTransportError } from "../../src/runs/shared/herdr-connection.ts"; const session = "01a090f1-5c0a-7b63-8c0d-6ffc1fabbe7d", task = "M2B_ROOT_Q7N4L2 return exactly 41", cwd = "/remote/repo"; const common = { runId: "run-m2b", requestId: "request-1", task, cwd, nativeSessionId: session, initialGit: { head: "abcd1234", branch: "main", dirty: false }, finalGit: { head: "bcde2345", dirty: true } }; const claudeHelp = "Claude Code\n--session-id --restricted --permission-mode plan acceptEdits --tools --strict-mcp-config --mcp-config --disable-slash-commands --no-chrome"; const codexHelp = "Codex\n--sandbox read-only --ask-for-approval never --no-alt-screen"; const cursorHelp = "Start the Cursor Agent\n--mode ask --sandbox enabled --workspace path --trust"; const preflight = (name: "claude" | "codex" | "cursor-agent", version: string, help: string) => ({ version: { binary: `/remote/bin/${name}`, args: ["--version"], status: 0, stdout: version + "\n", stderr: "" }, help: { binary: `/remote/bin/${name}`, args: ["--help"], status: 0, stdout: help, stderr: "" } }); function argvFor(launch: HerdrExternalLaunch) { return [launch.kind, ...launch.args]; } function processFor(launch: HerdrExternalLaunch, overrides: Record = {}) { return { pid: 42, name: launch.kind === "claude" ? "2.1.269" : `diagnostic-${launch.kind}`, argv0: launch.kind === "cursor" ? "cursor-agent" : launch.kind, cwd, argv: argvFor(launch), ...overrides }; } function readyAgent(launch: HerdrExternalLaunch, name = "a", overrides: Record = {}) { return { type: "agent_info", agent: { terminal_id: "term", pane_id: "p", name, agent: launch.kind, agent_status: "idle", interactive_ready: true, ...overrides } }; } function monitorFixture(sequence: Array<{ at: number; text: string; pid?: number; source?: "visible" | "recent_unwrapped" }>, timeoutMs = 40_000) { let now = 0, index = 0, stops = 0; const identity = { workspaceId: "w1", paneId: "w1:p1", terminalId: "term1", pid: 42 }; return { identity, get stops() { return stops; }, run: () => monitorHerdrCodex({ machineId: "machine", task, preSubmitText: "> Ask anything", identity, timeoutMs, clock: { now: () => now, async wait(ms) { now += ms; } }, async snapshot(): Promise { const item = sequence[Math.min(index++, sequence.length - 1)]!; now = Math.max(now, item.at); return { at: now, ...identity, pid: item.pid ?? identity.pid, text: item.text, source: item.source }; }, async stop() { stops++; } }) }; } function workspaceIdentity() { return JSON.stringify({ realpath: cwd, device: 1, inode: 2, uid: 501 }); } describe("internal Herdr pane-native M2b adapters", () => { it("splits exact restricted Claude reader and writer ceilings", () => { const reader = createHerdrExternalAdapterLaunch({ adapter: "claude-code", remoteRuntimeDir: "/tmp/pi-subagents-herdr-run", nativeSessionId: session }), writer = createHerdrExternalAdapterLaunch({ adapter: "claude-code-writer", remoteRuntimeDir: "/tmp/pi-subagents-herdr-run", nativeSessionId: session }); assert.deepEqual(reader.args, ["--session-id", session, "--restricted", "--permission-mode", "plan", "--tools", "", "--strict-mcp-config", "--mcp-config", "{\"mcpServers\":{}}", "--disable-slash-commands", "--no-chrome"]); assert.equal(reader.args.includes("acceptEdits"), false); assert.equal(reader.args.some((arg) => /Write|Edit/u.test(arg)), false); assert.deepEqual(writer.args, ["--session-id", session, "--restricted", "--permission-mode", "acceptEdits", "--tools", "Read,Write,Edit,Glob,Grep", "--strict-mcp-config", "--mcp-config", "{\"mcpServers\":{}}", "--disable-slash-commands", "--no-chrome"]); for (const forbidden of ["--setting-sources", "--settings", "--model", "--add-dir", "--trust"]) assert.equal(writer.args.includes(forbidden), false); }); it("builds exact Cursor and distinct Codex reader/writer launches", () => { assert.deepEqual(createHerdrExternalAdapterLaunch({ adapter: "cursor-agent", remoteRuntimeDir: "/tmp/pi-subagents-herdr-run", cwd, nativeSessionId: session }).args, ["--mode", "ask", "--sandbox", "enabled", "--workspace", cwd]); assert.deepEqual(createHerdrExternalAdapterLaunch({ adapter: "cursor-agent-writer", remoteRuntimeDir: "/tmp/pi-subagents-herdr-run", cwd, nativeSessionId: session }).args, ["--sandbox", "enabled", "--workspace", cwd]); assert.deepEqual(createHerdrExternalAdapterLaunch({ adapter: "codex-exec", remoteRuntimeDir: "/tmp/pi-subagents-herdr-run", nativeSessionId: session }).args, ["--sandbox", "read-only", "--ask-for-approval", "never", "--no-alt-screen"]); assert.deepEqual(createHerdrExternalAdapterLaunch({ adapter: "codex-exec-writer", remoteRuntimeDir: "/tmp/pi-subagents-herdr-run", nativeSessionId: session }).args, ["--sandbox", "workspace-write", "--ask-for-approval", "never", "--no-alt-screen"]); }); it("normalizes every placed external profile only as sanitized partial terminal evidence", () => { for (const adapter of ["claude-code", "claude-code-writer", "cursor-agent", "cursor-agent-writer", "codex-exec", "codex-exec-writer"] as const) { const result = createHerdrExternalAdapter(adapter).normalize(common, "\u001b[31mRESULT=41\u001b[0m\r\n"); assert.equal(result.adapter, adapter); assert.equal(result.outcome, "partial"); assert.equal(result.output, "[best-effort/unverified]\nRESULT=41"); assert.deepEqual(result.settlement, { verification: "best-effort/unverified", evidence: "sanitized-terminal-snapshots" }); assert.equal(result.nativeSessionId, "unverified"); } }); it("allows Codex writer preparation to reach the shared owner seam", async () => { let reached = false; await assert.rejects(prepareInternalHerdrExternalAdapter({ adapter: "codex-exec-writer", machine: { id: "m", target: "unused", cwd: "/r" }, runId: "writer-gate" }, { nativeSessionId: session }, (async () => { reached = true; throw new Error("owner seam reached"); }) as typeof HerdrPlacedRunOwner.create), /owner seam reached/u); assert.equal(reached, true); }); it("preserves preparation and cleanup failures together", async () => { const owner = { runtimeDir: "/tmp/pi-subagents-herdr-owned", connection: { endpoint: { session: null } }, async subscribe() {}, async provision() { return { workspaceId: "w", tabId: "t", paneId: "p" }; }, async start() { throw new Error("available shell timeout"); }, async cleanup() { throw new Error("cleanup ownership uncertain"); } } as never; await assert.rejects(prepareInternalHerdrExternalAdapter({ adapter: "codex-exec", machine: { id: "m", target: "unused", cwd }, runId: "aggregate" }, { nativeSessionId: session }, (async () => owner) as typeof HerdrPlacedRunOwner.create), (error) => error instanceof AggregateError && error.errors.some((item) => /available shell timeout/u.test(String(item))) && error.errors.some((item) => /cleanup ownership uncertain/u.test(String(item)))); }); it("cleans once after an available-shell timeout without retrying start", async () => { let starts = 0, cleanups = 0; const owner = { runtimeDir: "/tmp/pi-subagents-herdr-owned", connection: { endpoint: { session: null } }, async subscribe() {}, async provision() { return { workspaceId: "w", tabId: "t", paneId: "p" }; }, async start() { starts++; throw new Error("available shell timeout"); }, async cleanup() { cleanups++; } } as never; await assert.rejects(prepareInternalHerdrExternalAdapter({ adapter: "codex-exec", machine: { id: "m", target: "unused", cwd }, runId: "timeout" }, { nativeSessionId: session }, (async () => owner) as typeof HerdrPlacedRunOwner.create), /available shell timeout/u); assert.equal(starts, 1); assert.equal(cleanups, 1); }); it("requires proper help tokens while allowing duplicate documentation", () => { validateHerdrExternalPreflight("claude-code-writer", preflight("claude", "2.1.269 (Claude Code)", `${claudeHelp} --tools VALUE`)); validateHerdrExternalPreflight("cursor-agent", preflight("cursor-agent", "2026.09.10-fd3934a", cursorHelp)); validateHerdrExternalPreflight("codex-exec", preflight("codex", "codex-cli 0.154.0", codexHelp)); assert.throws(() => validateHerdrExternalPreflight("claude-code", preflight("claude", "2.1.268 (Claude Code)", claudeHelp)), /below/u); for (const help of [claudeHelp.replace("--tools", ""), claudeHelp.replace("--tools", "--tools-extra")]) assert.throws(() => validateHerdrExternalPreflight("claude-code", preflight("claude", "2.1.269 (Claude Code)", help)), /required interactive option "--tools"/u); assert.throws(() => validateHerdrExternalPreflight("claude-code", preflight("claude", "2.1.269 (Claude Code)", `bad header\n${claudeHelp}`)), /unsupported header/u); }); it("uses the fixed credential-store override only for Cursor preflight probes", () => { const commands = new Map(); for (const [adapter, name, version, help] of [["claude-code", "claude", "2.1.269 (Claude Code)", claudeHelp], ["cursor-agent", "cursor-agent", "2026.09.10-fd3934a", cursorHelp], ["codex-exec", "codex", "codex-cli 0.154.0", codexHelp]] as const) { const seen: string[] = []; commands.set(adapter, seen); const owner = { runRemote(command: string) { seen.push(command); if (seen.length === 1) return { status: 0, stdout: `/remote/bin/${name}\n`, stderr: "" }; return { status: 0, stdout: command.includes("--version") ? `${version}\n` : help, stderr: "" }; } } as never; runHerdrExternalPreflight(owner, adapter); } const cursor = commands.get("cursor-agent")!, claude = commands.get("claude-code")!, codex = commands.get("codex-exec")!; assert.equal(cursor.slice(1).every((command) => command.includes("exec /usr/bin/env AGENT_CLI_CREDENTIAL_STORE=file") && command.includes("/remote/bin/cursor-agent")), true); assert.equal(cursor[0]!.includes("AGENT_CLI_CREDENTIAL_STORE"), false); assert.equal([...claude, ...codex].some((command) => command.includes("AGENT_CLI_CREDENTIAL_STORE")), false); }); it("rejects Cursor trust UI before task input", async () => { let prompts = 0; const owner = { machine: { id: "m", cwd }, agentName: "cursor-r", terminalId: "term", owned: { workspaceId: "w", tabId: "t", paneId: "p" }, runRemote() { return { status: 0, stdout: workspaceIdentity(), stderr: "" }; }, connection: { client: { async call(method: string) { if (method === "pane.read") return { type: "pane_read", read: { pane_id: "p", text: "Trust this workspace?" } }; prompts++; return {}; } } }, async cleanup() {} } as never; const launch = createHerdrExternalAdapterLaunch({ adapter: "cursor-agent", remoteRuntimeDir: "/tmp/pi-subagents-herdr-run", cwd, nativeSessionId: session }), placed = new HerdrExternalSession(owner, launch, preflight("cursor-agent", "2026.09.10-fd3934a", cursorHelp)); await assert.rejects(placed.promptAndSettle(common), /requires trust/u); assert.equal(prompts, 0); }); it("retains and normalizes Codex startup trust UI without prompting", async () => { const launch = createHerdrExternalAdapterLaunch({ adapter: "codex-exec", remoteRuntimeDir: "/tmp/pi-subagents-herdr-run", nativeSessionId: session }); let prompts = 0, retained = 0; const owner = { machine: { id: "m", cwd }, agentName: "codex-r", terminalId: "term", startedArgv: argvFor(launch), owned: { workspaceId: "w", tabId: "t", paneId: "p" }, connection: { client: { async call(method: string, params: Record) { if (method === "pane.read") return { type: "pane_read", read: { pane_id: "p", source: params.source, text: "Do you trust the contents of this directory?" } }; if (method === "agent.prompt") prompts++; throw new Error(method); } } }, async cleanup(close: boolean) { assert.equal(close, false); retained++; } } as never; const placed = new HerdrExternalSession(owner, launch, preflight("codex", "codex-cli 0.154.0", codexHelp)); let failure: unknown; try { await placed.promptAndSettle(common); } catch (error) { failure = error; } assert.ok(failure instanceof HerdrExternalNeedsAttentionError); const result = await settleHerdrExternalRunnerError(failure, "codex-exec", common, () => placed.retain()); assert.equal(prompts, 0); assert.equal(retained, 1); assert.equal(result.outcome, "partial"); assert.match(result.output, /^\[best-effort\/unverified\]/u); }); it("treats Herdr unknown as retained ambiguous Cursor settlement", async () => { const launch = createHerdrExternalAdapterLaunch({ adapter: "cursor-agent", remoteRuntimeDir: "/tmp/pi-subagents-herdr-run", cwd, nativeSessionId: session }), events: string[] = []; let workspaceReads = 0, retained = 0; const owner = { machine: { id: "m", cwd }, agentName: "cursor-r", terminalId: "term", startedArgv: argvFor(launch), owned: { workspaceId: "w", tabId: "t", paneId: "p" }, snapshot: { connection: "connected" }, connection: { client: { async call(method: string, params: Record) { events.push(method); if (method === "pane.read") return { type: "pane_read", read: { pane_id: "p", source: params.source, text: params.source === "visible" ? "Cursor Agent Ask" : "Cursor Agent\nRESULT=41" } }; if (method === "pane.process_info") return { type: "pane_process_info", process_info: { pane_id: "p", foreground_processes: [processFor(launch)] } }; if (method === "agent.get") return readyAgent(launch, "cursor-r"); if (method === "agent.prompt") { assert.deepEqual(params.wait, { until: ["idle", "done", "blocked"], timeout_ms: 90_000 }); return { type: "agent_prompted", agent: { terminal_id: "term", pane_id: "p", agent_status: "unknown" } }; } throw new Error(method); } } }, runRemote(command: string) { events.push("remote"); if (command.includes("device:s.dev")) { workspaceReads++; return { status: 0, stdout: workspaceIdentity(), stderr: "" }; } if (command.includes("out.sort")) return { status: 0, stdout: "[]", stderr: "" }; throw new Error("private transcript access is forbidden"); }, async cleanup(close: boolean) { assert.equal(close, false); retained++; } } as never; const placed = new HerdrExternalSession(owner, launch, preflight("cursor-agent", "2026.09.10-fd3934a", cursorHelp)); let ambiguous: unknown; try { await placed.promptAndSettle(common); } catch (error) { ambiguous = error; } assert.ok(ambiguous instanceof HerdrExternalNeedsAttentionError); assert.equal((await settleHerdrExternalRunnerError(ambiguous, "cursor-agent", common, () => placed.retain())).outcome, "partial"); assert.equal(retained, 1); assert.equal(workspaceReads, 1); assert.ok(events.lastIndexOf("pane.read") < events.lastIndexOf("agent.prompt")); }); it("runner seam retains both branches but downgrades only explicit needs-attention errors", async () => { let retained = 0; const retain = async () => { retained++; }; const attention = new HerdrExternalNeedsAttentionError("ambiguous", { machineId: "m", workspaceId: "w", paneId: "p", terminalId: "t" }); assert.equal((await settleHerdrExternalRunnerError(attention, "claude-code", common, retain)).outcome, "partial"); const protocol = new Error("invalid agent_prompted envelope"); await assert.rejects(settleHerdrExternalRunnerError(protocol, "claude-code", common, retain), /invalid agent_prompted/u); assert.equal(retained, 2); }); it("fails Cursor settlement on workspace object replacement before terminal read", async () => { const launch = createHerdrExternalAdapterLaunch({ adapter: "cursor-agent", remoteRuntimeDir: "/tmp/pi-subagents-herdr-run", cwd, nativeSessionId: session }); let workspaceReads = 0; const owner = { machine: { id: "m", cwd }, agentName: "cursor-r", terminalId: "term", startedArgv: argvFor(launch), owned: { workspaceId: "w", tabId: "t", paneId: "p" }, snapshot: { connection: "connected" }, connection: { client: { async call(method: string) { if (method === "pane.read") return { type: "pane_read", read: { pane_id: "p", text: "Cursor Agent Ask" } }; if (method === "pane.process_info") return { type: "pane_process_info", process_info: { pane_id: "p", foreground_processes: [processFor(launch)] } }; if (method === "agent.get") return readyAgent(launch, "cursor-r"); return { type: "agent_prompted", agent: { terminal_id: "term", pane_id: "p", agent_status: "done" } }; } } }, runRemote() { return { status: 0, stdout: JSON.stringify({ realpath: cwd, device: 1, inode: ++workspaceReads, uid: 501 }), stderr: "" }; } } as never; await assert.rejects(new HerdrExternalSession(owner, launch, preflight("cursor-agent", "2026.09.10-fd3934a", cursorHelp)).promptAndSettle(common), /workspace identity changed/u); }); it("retains blocked and timed-out panes while explicit stop cleans", async () => { for (const state of ["blocked", "timeout"] as const) { let cleanups = 0; const launch = createHerdrExternalAdapterLaunch({ adapter: "claude-code", remoteRuntimeDir: "/tmp/pi-subagents-herdr-run", nativeSessionId: session }); const owner = { machine: { id: "m", cwd }, agentName: "claude-r", terminalId: "term", startedArgv: argvFor(launch), owned: { workspaceId: "w", tabId: "t", paneId: "p" }, snapshot: { connection: "connected" }, connection: { client: { async call(method: string) { if (method === "pane.process_info") return { type: "pane_process_info", process_info: { pane_id: "p", foreground_processes: [processFor(launch, { pid: 9 })] } }; if (state === "timeout") throw new HerdrTransportError("prompt timeout"); return { type: "agent_prompted", agent: { terminal_id: "term", pane_id: "p", agent_status: "blocked" } }; } } }, async cleanup() { cleanups++; } } as never; const placed = new HerdrExternalSession(owner, launch, preflight("claude", "2.1.269 (Claude Code)", claudeHelp)); await assert.rejects(placed.promptAndSettle(common), (error) => error instanceof HerdrExternalNeedsAttentionError); assert.equal(cleanups, 0); await placed.abort(); assert.equal(cleanups, 1); } }); it("uses agent.start as profile argv authority while process_info binds only canonical PID, argv0, and cwd", async () => { const launch = createHerdrExternalAdapterLaunch({ adapter: "claude-code", remoteRuntimeDir: "/tmp/runtimedir", nativeSessionId: session }); let prompts = 0; const owner = { machine: { id: "m", cwd }, agentName: "a", terminalId: "term", startedArgv: argvFor(launch), owned: { workspaceId: "w", tabId: "t", paneId: "p" }, snapshot: { connection: "connected" }, connection: { client: { async call(method: string) { if (method === "pane.process_info") return { type: "pane_process_info", process_info: { pane_id: "p", foreground_processes: [processFor(launch, { argv: ["implementation-wrapper", "--private-detail"] }), { pid: 43, name: "descendant", argv0: "node", cwd }] } }; if (method === "agent.prompt") { prompts++; return { type: "agent_prompted", agent: { terminal_id: "term", pane_id: "p", agent_status: "blocked" } }; } throw new Error(method); } } } } as never; await assert.rejects(new HerdrExternalSession(owner, launch, preflight("claude", "2.1.269 (Claude Code)", claudeHelp)).promptAndSettle(common), /did not settle safely/u); assert.equal(prompts, 1); }); it("rejects wrong canonical argv0 or cwd with otherwise live-shaped process rows", async () => { for (const [adapter, evidence] of [["claude-code", preflight("claude", "2.1.269 (Claude Code)", claudeHelp)], ["cursor-agent", preflight("cursor-agent", "2026.09.10-fd3934a", cursorHelp)], ["codex-exec", preflight("codex", "codex-cli 0.154.0", codexHelp)]] as const) { const launch = createHerdrExternalAdapterLaunch({ adapter, remoteRuntimeDir: "/tmp/runtimedir", cwd, nativeSessionId: session }); for (const overrides of [{ argv0: "evil" }, { cwd: "/other" }]) { let now = 0; const owner = { machine: { id: "m", cwd }, agentName: "a", terminalId: "term", startedArgv: argvFor(launch), owned: { workspaceId: "w", tabId: "t", paneId: "p" }, connection: { client: { async call(method: string) { if (method === "pane.read") return { type: "pane_read", read: { pane_id: "p", text: adapter === "cursor-agent" ? "Cursor Agent Ask" : "> Ask anything" } }; if (method === "agent.get") return readyAgent(launch); return { type: "pane_process_info", process_info: { pane_id: "p", foreground_processes: [processFor(launch, { argv: undefined, ...overrides })] } }; } } }, runRemote() { return { status: 0, stdout: workspaceIdentity(), stderr: "" }; } } as never; await assert.rejects(new HerdrExternalSession(owner, launch, evidence).promptAndSettle(common, { clock: { now: () => now, async wait(ms) { now += ms; } } }), /canonical|did not stabilize/u); } } }); it("rejects agent_info returned directly by agent.prompt", async () => { const launch = createHerdrExternalAdapterLaunch({ adapter: "claude-code", remoteRuntimeDir: "/tmp/runtimedir", nativeSessionId: session }); const owner = { machine: { id: "m", cwd }, agentName: "a", terminalId: "term", startedArgv: argvFor(launch), owned: { workspaceId: "w", tabId: "t", paneId: "p" }, snapshot: { connection: "connected" }, connection: { client: { async call(method: string) { if (method === "pane.process_info") return { type: "pane_process_info", process_info: { pane_id: "p", foreground_processes: [processFor(launch)] } }; return { type: "agent_info", agent: { terminal_id: "term", pane_id: "p", agent_status: "done" } }; } } } } as never; await assert.rejects(new HerdrExternalSession(owner, launch, preflight("claude", "2.1.269 (Claude Code)", claudeHelp)).promptAndSettle(common), /invalid agent_prompted/u); }); it("rejects widened agent_started argv before prompt", async () => { const launch = createHerdrExternalAdapterLaunch({ adapter: "claude-code", remoteRuntimeDir: "/tmp/runtimedir", nativeSessionId: session }); let calls = 0; const owner = { machine: { id: "m", cwd }, agentName: "a", terminalId: "term", startedArgv: [...argvFor(launch), "--add-dir", "/tmp"], owned: { workspaceId: "w", tabId: "t", paneId: "p" }, connection: { client: { async call() { calls++; return {}; } } } } as never; await assert.rejects(new HerdrExternalSession(owner, launch, preflight("claude", "2.1.269 (Claude Code)", claudeHelp)).promptAndSettle(common), /unexpected native argv/u); assert.equal(calls, 0); }); it("polls blank Cursor startup without redispatch and accepts descendants around one cursor-agent", async () => { const launch = createHerdrExternalAdapterLaunch({ adapter: "cursor-agent", remoteRuntimeDir: "/tmp/runtimedir", cwd, nativeSessionId: session }); let now = 0, reads = 0, processReads = 0, prompts = 0; const owner = { machine: { id: "m", cwd }, agentName: "a", terminalId: "term", startedArgv: argvFor(launch), owned: { workspaceId: "w", tabId: "t", paneId: "p" }, snapshot: { connection: "connected" }, runRemote() { return { status: 0, stdout: workspaceIdentity(), stderr: "" }; }, connection: { client: { async call(method: string, params: Record) { if (method === "pane.read") { reads++; return { type: "pane_read", read: { pane_id: "p", source: params.source, text: params.source === "recent_unwrapped" ? "RESULT=41" : reads === 1 ? "" : "Cursor Agent Ask" } }; } if (method === "pane.process_info") { processReads++; return { type: "pane_process_info", process_info: { pane_id: "p", foreground_processes: processReads === 1 ? [] : [processFor(launch), { pid: 77, name: "language server", argv0: "node", cwd }] } }; } if (method === "agent.get") return readyAgent(launch); if (method === "agent.prompt") { prompts++; return { type: "agent_prompted", agent: { terminal_id: "term", pane_id: "p", agent_status: "done" } }; } throw new Error(method); } } } } as never; const result = await new HerdrExternalSession(owner, launch, preflight("cursor-agent", "2026.09.10-fd3934a", cursorHelp)).promptAndSettle(common, { clock: { now: () => now, async wait(ms) { now += ms; } } }); assert.equal(result.outcome, "partial"); assert.equal(prompts, 1); assert.ok(reads >= 3); }); it("waits for exact public interactive readiness in the existing startup loop", async () => { const launch = createHerdrExternalAdapterLaunch({ adapter: "cursor-agent", remoteRuntimeDir: "/tmp/runtimedir", cwd, nativeSessionId: session }); let now = 0, gets = 0, prompts = 0; const owner = { machine: { id: "m", cwd }, agentName: "a", terminalId: "term", startedArgv: argvFor(launch), owned: { workspaceId: "w", tabId: "t", paneId: "p" }, snapshot: { connection: "connected" }, runRemote() { return { status: 0, stdout: workspaceIdentity(), stderr: "" }; }, connection: { client: { async call(method: string, params: Record) { if (method === "pane.read") return { type: "pane_read", read: { pane_id: "p", source: params.source, text: params.source === "recent_unwrapped" ? "RESULT=41" : "Cursor Agent Ask" } }; if (method === "pane.process_info") return { type: "pane_process_info", process_info: { pane_id: "p", foreground_processes: [processFor(launch)] } }; if (method === "agent.get") return readyAgent(launch, "a", ++gets < 4 ? { agent_status: "unknown", launch_pending: true, interactive_ready: undefined } : {}); if (method === "agent.prompt") { prompts++; return { type: "agent_prompted", agent: { terminal_id: "term", pane_id: "p", agent_status: "done" } }; } throw new Error(method); } } } } as never; await new HerdrExternalSession(owner, launch, preflight("cursor-agent", "2026.09.10-fd3934a", cursorHelp)).promptAndSettle(common, { clock: { now: () => now, async wait(ms) { assert.equal(prompts, 0); now += ms; } } }); assert.equal(gets, 4); assert.equal(prompts, 1); }); it("never prompts for omitted readiness, blocked state, or owner kind/name mismatch", async () => { for (const override of [{ interactive_ready: undefined }, { agent_status: "blocked" }, { agent: "codex" }, { name: "other" }]) { const launch = createHerdrExternalAdapterLaunch({ adapter: "cursor-agent", remoteRuntimeDir: "/tmp/runtimedir", cwd, nativeSessionId: session }); let now = 0, prompts = 0; const owner = { machine: { id: "m", cwd }, agentName: "a", terminalId: "term", startedArgv: argvFor(launch), owned: { workspaceId: "w", tabId: "t", paneId: "p" }, runRemote() { return { status: 0, stdout: workspaceIdentity(), stderr: "" }; }, connection: { client: { async call(method: string, params: Record) { if (method === "pane.read") return { type: "pane_read", read: { pane_id: "p", source: params.source, text: "Cursor Agent Ask" } }; if (method === "pane.process_info") return { type: "pane_process_info", process_info: { pane_id: "p", foreground_processes: [processFor(launch)] } }; if (method === "agent.get") return readyAgent(launch, "a", override); prompts++; return {}; } } } } as never; await assert.rejects(new HerdrExternalSession(owner, launch, preflight("cursor-agent", "2026.09.10-fd3934a", cursorHelp)).promptAndSettle(common, { clock: { now: () => now, async wait(ms) { now += ms; } } })); assert.equal(prompts, 0); } }); it("keeps one-second startup polling through 15 seconds, then backs off within the 45-second bound", async () => { const launch = createHerdrExternalAdapterLaunch({ adapter: "cursor-agent", remoteRuntimeDir: "/tmp/runtimedir", cwd, nativeSessionId: session }); let now = 0, prompts = 0; const waits: number[] = []; const owner = { machine: { id: "m", cwd }, agentName: "a", terminalId: "term", startedArgv: argvFor(launch), owned: { workspaceId: "w", tabId: "t", paneId: "p" }, snapshot: { connection: "connected" }, runRemote() { return { status: 0, stdout: workspaceIdentity(), stderr: "" }; }, connection: { client: { async call(method: string, params: Record) { if (method === "pane.read") return { type: "pane_read", read: { pane_id: "p", source: params.source, text: params.source === "recent_unwrapped" ? "RESULT=41" : now >= 32_500 ? "Cursor Agent Ask" : "" } }; if (method === "pane.process_info") return { type: "pane_process_info", process_info: { pane_id: "p", foreground_processes: now >= 32_500 ? [processFor(launch)] : [] } }; if (method === "agent.get") return readyAgent(launch); if (method === "agent.prompt") { prompts++; return { type: "agent_prompted", agent: { terminal_id: "term", pane_id: "p", agent_status: "done" } }; } throw new Error(method); } } } } as never; await new HerdrExternalSession(owner, launch, preflight("cursor-agent", "2026.09.10-fd3934a", cursorHelp)).promptAndSettle(common, { clock: { now: () => now, async wait(ms) { waits.push(ms); now += ms; } } }); assert.equal(prompts, 1); assert.deepEqual(waits.slice(0, 15), Array(15).fill(1_000)); assert.equal(waits.slice(15).every((ms) => ms === 2_500), true); assert.equal(now, 32_500); }); it("samples trust and exact process evidence at the 45-second startup boundary without sleeping", async () => { const launch = createHerdrExternalAdapterLaunch({ adapter: "codex-exec", remoteRuntimeDir: "/tmp/runtimedir", nativeSessionId: session }); let now = 0, reads = 0, processReads = 0, prompts = 0; const owner = { machine: { id: "m", cwd }, agentName: "a", terminalId: "term", startedArgv: argvFor(launch), owned: { workspaceId: "w", tabId: "t", paneId: "p" }, connection: { client: { async call(method: string) { if (method === "pane.read") { reads++; return { type: "pane_read", read: { pane_id: "p", text: now === 45_000 ? "Approval required" : "" } }; } if (method === "pane.process_info") { processReads++; return { type: "pane_process_info", process_info: { pane_id: "p", foreground_processes: [] } }; } if (method === "agent.get") return readyAgent(launch); prompts++; return {}; } } } } as never; await assert.rejects(new HerdrExternalSession(owner, launch, preflight("codex", "codex-cli 0.154.0", codexHelp)).promptAndSettle(common, { clock: { now: () => now, async wait(ms) { now += ms; } } }), /requires attention/u); assert.equal(now, 45_000); assert.equal(reads, 28); assert.equal(processReads, 27); assert.equal(prompts, 0); }); it("never prompts when duplicate canonical startup processes persist", async () => { const launch = createHerdrExternalAdapterLaunch({ adapter: "codex-exec", remoteRuntimeDir: "/tmp/runtimedir", nativeSessionId: session }); let now = 0, prompts = 0; const owner = { machine: { id: "m", cwd }, agentName: "a", terminalId: "term", startedArgv: argvFor(launch), owned: { workspaceId: "w", tabId: "t", paneId: "p" }, connection: { client: { async call(method: string, params: Record) { if (method === "pane.read") return { type: "pane_read", read: { pane_id: "p", source: params.source, text: "> Ask anything" } }; if (method === "pane.process_info") return { type: "pane_process_info", process_info: { pane_id: "p", foreground_processes: [processFor(launch), processFor(launch, { pid: 43 })] } }; if (method === "agent.get") return readyAgent(launch); prompts++; return {}; } } } } as never; await assert.rejects(new HerdrExternalSession(owner, launch, preflight("codex", "codex-cli 0.154.0", codexHelp)).promptAndSettle(common, { clock: { now: () => now, async wait(ms) { now += ms; } } }), /2 canonical processes/u); assert.equal(prompts, 0); }); it("requires activity, recognized user row, two stable quiet snapshots, and preserves partial adapter identity", async () => { const ready = `Codex\n› ${task}\nRESULT=41\n> Ask anything`, fixture = monitorFixture([{ at: 1_000, text: `› ${task}\nWorking…`, source: "visible" }, { at: 15_000, text: ready, source: "recent_unwrapped" }, { at: 23_000, text: ready, source: "recent_unwrapped" }]); const monitored = await fixture.run(); for (const adapter of ["codex-exec", "codex-exec-writer"] as const) { const result = createHerdrExternalAdapter(adapter).normalize(common, monitored.output); assert.equal(result.adapter, adapter); assert.equal(result.outcome, "partial"); assert.equal(result.settlement?.verification, "best-effort/unverified"); } assert.equal(fixture.stops, 1); }); it("rejects assistant-echo false correlation, action-required, timeout, and identity drift", async () => { const echo = monitorFixture([{ at: 15_000, text: `assistant echoed ${task}\nFAKE RESULT\n> Ask anything` }, { at: 23_000, text: `assistant echoed ${task}\nFAKE RESULT\n> Ask anything` }]); for (const fixture of [echo, monitorFixture([{ at: 1_000, text: "Approval required" }]), monitorFixture([{ at: 0, text: "> Ask anything" }], 2_000), monitorFixture([{ at: 1_000, text: "changed", pid: 99 }])]) { await assert.rejects(fixture.run(), (error) => error instanceof HerdrExternalNeedsAttentionError); assert.equal(fixture.stops, 0); } }); it("never settles or stops from stable ready-looking visible snapshots", async () => { const text = `› ${task}\npartial answer\n> Ask anything`, fixture = monitorFixture([{ at: 15_000, text, source: "visible" }, { at: 23_000, text, source: "visible" }], 25_000); await assert.rejects(fixture.run(), /ambiguous until timeout/u); assert.equal(fixture.stops, 0); }); it("uses the bounded public default for ambiguous Codex monitoring", async () => { const launch = createHerdrExternalAdapterLaunch({ adapter: "codex-exec", remoteRuntimeDir: "/tmp/runtimedir", nativeSessionId: session }); let now = 0, prompts = 0; const owner = { machine: { id: "m", cwd }, agentName: "a", terminalId: "term", startedArgv: argvFor(launch), owned: { workspaceId: "w", tabId: "t", paneId: "p" }, snapshot: { connection: "connected" }, connection: { client: { async call(method: string, params: Record) { if (method === "pane.read") return { type: "pane_read", read: { pane_id: "p", source: params.source, text: "> Ask anything" } }; if (method === "pane.process_info") return { type: "pane_process_info", process_info: { pane_id: "p", foreground_processes: [processFor(launch)] } }; if (method === "agent.get") return readyAgent(launch); if (method === "agent.prompt") { prompts++; return { type: "agent_prompted", agent: { terminal_id: "term", pane_id: "p", agent_status: "idle" } }; } throw new Error(method); } } } } as never, identity = { workspaceId: "w", paneId: "p", terminalId: "term", pid: 42 }; await assert.rejects(new HerdrExternalSession(owner, launch, preflight("codex", "codex-cli 0.154.0", codexHelp)).promptAndSettle(common, { clock: { now: () => now, async wait(ms) { now += ms; } }, async snapshot() { return { at: now, ...identity, text: `› ${task}\npartial answer\n> Ask anything`, source: "visible" }; } }), /ambiguous until timeout/u); assert.equal(prompts, 1); assert.equal(now, 91_000); }); it("default Codex observer uses visible while working and recent_unwrapped only after done", async () => { const launch = createHerdrExternalAdapterLaunch({ adapter: "codex-exec-writer", remoteRuntimeDir: "/tmp/pi-subagents-herdr-run", nativeSessionId: session }), calls: string[] = []; let status = "working", recent = 0, prompts = 0, now = 0; const owner = { machine: { id: "m", cwd }, agentName: "codex-r", terminalId: "term", startedArgv: argvFor(launch), owned: { workspaceId: "w", tabId: "t", paneId: "p" }, snapshot: { connection: "connected" }, connection: { client: { async call(method: string, params: Record) { if (method === "pane.process_info") return { type: "pane_process_info", process_info: { pane_id: "p", foreground_processes: [processFor(launch), { pid: 41, name: "npm launcher", argv0: "node", cwd }] } }; if (method === "agent.prompt") { prompts++; return { type: "agent_prompted", agent: { terminal_id: "term", pane_id: "p", agent_status: "working" } }; } if (method === "agent.get") { if (calls.filter((x) => x === "visible").length >= 3) status = "done"; return readyAgent(launch, "codex-r", { agent_status: status }); } if (method === "pane.read") { const source = String(params.source); calls.push(source); if (source === "recent_unwrapped" && status !== "done") throw new Error("agent_not_idle"); if (source === "visible" && prompts === 0) return { type: "pane_read", read: { pane_id: "p", source, text: calls.length === 1 ? "" : "> Ask anything" } }; if (source === "visible") return { type: "pane_read", read: { pane_id: "p", source, text: `› ${task}\nWorking…` } }; recent++; return { type: "pane_read", read: { pane_id: "p", source, text: `› ${task}\nRESULT=41\n> Ask anything` } }; } throw new Error(method); } } }, async cleanup() {} } as never; const result = await new HerdrExternalSession(owner, launch, preflight("codex", "codex-cli 0.154.0", codexHelp)).promptAndSettle(common, { timeoutMs: 40_000, clock: { now: () => now, async wait(ms) { now += ms; if (recent === 1) now = 15_000; if (recent >= 2) now = 23_000; } } }); assert.equal(result.adapter, "codex-exec-writer"); assert.equal(result.outcome, "partial"); assert.equal(result.settlement?.verification, "best-effort/unverified"); assert.equal(prompts, 1); assert.deepEqual(calls.slice(0, 3), ["visible", "visible", "visible"]); assert.ok(calls.includes("recent_unwrapped")); }); it("default Codex snapshot protocol errors retain and fail unchanged at the runner boundary", async () => { const launch = createHerdrExternalAdapterLaunch({ adapter: "codex-exec", remoteRuntimeDir: "/tmp/pi-subagents-herdr-run", nativeSessionId: session }); let retained = 0; const owner = { machine: { id: "m", cwd }, agentName: "codex-r", terminalId: "term", startedArgv: argvFor(launch), owned: { workspaceId: "w", tabId: "t", paneId: "p" }, snapshot: { connection: "connected" }, connection: { client: { async call(method: string, params: Record) { if (method === "pane.process_info") return { type: "pane_process_info", process_info: { pane_id: "p", foreground_processes: [processFor(launch)] } }; if (method === "pane.read") return { type: "pane_read", read: { pane_id: "p", source: params.source, text: "> Ask anything" } }; if (method === "agent.prompt") return { type: "agent_prompted", agent: { terminal_id: "term", pane_id: "p", agent_status: "working" } }; if (method === "agent.get") return { type: "malformed" }; throw new Error(method); } } }, async cleanup(close: boolean) { assert.equal(close, false); retained++; } } as never; const placed = new HerdrExternalSession(owner, launch, preflight("codex", "codex-cli 0.154.0", codexHelp)); let failure: unknown; try { await placed.promptAndSettle(common, { timeoutMs: 1 }); } catch (error) { failure = error; } assert.ok(failure instanceof Error); assert.equal(failure instanceof HerdrExternalNeedsAttentionError, false); assert.match(failure.message, /invalid agent_info envelope/u); await assert.rejects(settleHerdrExternalRunnerError(failure, "codex-exec", common, () => placed.retain()), (error) => error === failure); assert.equal(retained, 1); }); it("external reconnect rejects same terminal in a different pane", () => { const identity = { runId: "r", machineId: "m", target: "host", session: null, workspaceId: "w", tabId: "t", paneId: "p1", terminalId: "term", agentName: "claude-r", nativeSessionId: session, cwd, runtimeDir: "/tmp/r" }; const result = reconcileHerdrExternalRun(identity, { endpoint: { session: null, protocol: 22, version: "0.9.0" }, agents: [{ terminal_id: "term", pane_id: "p2", agent_status: "working" }], bridge: {} }); assert.equal(result.ok, false); if (!result.ok) assert.match(result.reason, /pane identity drift/u); }); it("keeps authoritative agent_not_ready rejection hard despite concurrent owner loss", async () => { const launch = createHerdrExternalAdapterLaunch({ adapter: "cursor-agent", remoteRuntimeDir: "/tmp/runtimedir", cwd, nativeSessionId: session }); let gets = 0, prompts = 0, connects = 0; const owner = { machine: { id: "m", cwd }, agentName: "a", terminalId: "term", startedArgv: argvFor(launch), owned: { workspaceId: "w", tabId: "t", paneId: "p" }, snapshot: { connection: "connected" }, runRemote() { return { status: 0, stdout: workspaceIdentity(), stderr: "" }; }, connection: { client: { async call(method: string, params: Record) { if (method === "pane.read") return { type: "pane_read", read: { pane_id: "p", source: params.source, text: "Cursor Agent Ask" } }; if (method === "pane.process_info") return { type: "pane_process_info", process_info: { pane_id: "p", foreground_processes: [processFor(launch)] } }; if (method === "agent.get") { gets++; return readyAgent(launch); } prompts++; owner.snapshot.connection = "unknown"; throw new HerdrRpcError("pending", "prompt-1", "agent_not_ready"); } } } } as never; const placed = new HerdrExternalSession(owner, launch, preflight("cursor-agent", "2026.09.10-fd3934a", cursorHelp), (async () => { connects++; throw new Error("must not recover"); }) as never); await assert.rejects(placed.promptAndSettle(common), (error) => error instanceof HerdrRpcError && error.code === "agent_not_ready"); assert.equal(prompts, 1); assert.equal(gets, 1); assert.equal(connects, 0); }); it("recovers a post-acceptance Codex observation from the disconnect lifecycle without redispatch", async () => { const launch = createHerdrExternalAdapterLaunch({ adapter: "codex-exec", remoteRuntimeDir: "/tmp/runtimedir", nativeSessionId: session }), identity = { runId: "r", machineId: "m", target: "host", session: null, workspaceId: "w", tabId: "t", paneId: "p", terminalId: "term", agentName: "codex-r", nativeSessionId: session, cwd, runtimeDir: "/tmp/r" }; let prompts = 0, replacements = 0, connects = 0, now = 0, disconnected = false, replacementDisconnected = () => {}; const replacement = { endpoint: { session: null, protocol: 22, version: "0.9.0" }, client: { async call(method: string, params: Record) { if (method === "session.snapshot") return { type: "session_snapshot", snapshot: { agents: [{ terminal_id: "term", pane_id: "p", agent_status: "done" }] } }; if (method === "agent.get") return { type: "agent_info", agent: { terminal_id: "term", pane_id: "p", agent_status: "done" } }; if (method === "pane.process_info") return { type: "pane_process_info", process_info: { pane_id: "p", foreground_processes: [processFor(launch)] } }; if (method === "pane.read") return { type: "pane_read", read: { pane_id: "p", source: params.source, text: `› ${task}\nRESULT=41\n> Ask anything` } }; throw new Error(method); }, async subscribe(_filters: unknown, _listener: unknown, lost: () => void) { replacementDisconnected = lost; return () => {}; } }, async close() {} }; let placed: HerdrExternalSession; const owner = { machine: { id: "m", target: "host", cwd }, agentName: "codex-r", terminalId: "term", startedArgv: argvFor(launch), owned: { workspaceId: "w", tabId: "t", paneId: "p" }, identity, snapshot: { connection: "connected" }, connection: { client: { async call(method: string, params: Record) { if (method === "pane.read") return { type: "pane_read", read: { pane_id: "p", source: params.source, text: "> Ask anything" } }; if (method === "pane.process_info") return { type: "pane_process_info", process_info: { pane_id: "p", foreground_processes: [processFor(launch)] } }; if (method === "agent.prompt") { prompts++; return { type: "agent_prompted", agent: { terminal_id: "term", pane_id: "p", agent_status: "working" } }; } if (method === "agent.get") { if (!prompts) return readyAgent(launch, "codex-r"); disconnected = true; owner.snapshot.connection = "unknown"; placed.handleDisconnect(); throw new HerdrTransportError("transport lost"); } throw new Error(method); } } }, async replaceConnection(input: typeof replacement & { connection: typeof replacement }) { replacements++; replacementDisconnected(); owner.connection = input.connection as never; owner.snapshot.connection = "connected"; }, async cleanup() {} } as never; placed = new HerdrExternalSession(owner, launch, preflight("codex", "codex-cli 0.154.0", codexHelp), (async () => { connects++; return replacement; }) as never); const result = await placed.promptAndSettle(common, { timeoutMs: 30_000, clock: { now: () => now, async wait(ms) { now = prompts ? 23_000 : now + ms; } } }); await new Promise((resolve) => setImmediate(resolve)); assert.equal(result.outcome, "partial"); assert.equal(disconnected, true); assert.equal(prompts, 1); assert.equal(replacements, 1); assert.equal(connects, 1); }); it("reports missing identity separately from disposal and swallows cleanup disconnect callbacks", async () => { const launch = createHerdrExternalAdapterLaunch({ adapter: "claude-code", remoteRuntimeDir: "/tmp/runtimedir", nativeSessionId: session }), owner = { machine: { id: "m", target: "host", cwd }, async cleanup() {} } as never, placed = new HerdrExternalSession(owner, launch, preflight("claude", "2.1.269 (Claude Code)", claudeHelp), (async () => { throw new Error("must not connect"); }) as never); await assert.rejects(placed.reconnect(), /no persisted owner identity/u); await placed.retain(); placed.handleDisconnect(); await new Promise((resolve) => setImmediate(resolve)); await assert.rejects(placed.reconnect(), /disposal or retention has begun/u); }); it("recovers transport loss during the immediate post-acceptance retained-PID proof", async () => { const launch = createHerdrExternalAdapterLaunch({ adapter: "codex-exec", remoteRuntimeDir: "/tmp/runtimedir", nativeSessionId: session }); const identity = { runId: "r", machineId: "m", target: "host", session: null, workspaceId: "w", tabId: "t", paneId: "p", terminalId: "term", agentName: "codex-r", nativeSessionId: session, cwd, runtimeDir: "/tmp/r" }; let prompts = 0, replacements = 0, connects = 0, now = 0; let placed: HerdrExternalSession; const replacement = { endpoint: { session: null, protocol: 22, version: "0.9.0" }, client: { async call(method: string, params: Record) { if (method === "session.snapshot") return { type: "session_snapshot", snapshot: { agents: [{ terminal_id: "term", pane_id: "p", agent_status: "done" }] } }; if (method === "pane.process_info") return { type: "pane_process_info", process_info: { pane_id: "p", foreground_processes: [processFor(launch)] } }; if (method === "agent.get") return { type: "agent_info", agent: { terminal_id: "term", pane_id: "p", agent_status: "done" } }; if (method === "pane.read") return { type: "pane_read", read: { pane_id: "p", source: params.source, text: `› ${task}\nRESULT=41\n> Ask anything` } }; throw new Error(method); }, async subscribe() { return () => {}; } }, async close() {} }; const owner = { machine: { id: "m", target: "host", cwd }, agentName: "codex-r", terminalId: "term", startedArgv: argvFor(launch), owned: { workspaceId: "w", tabId: "t", paneId: "p" }, identity, snapshot: { connection: "connected" }, connection: { client: { async call(method: string, params: Record) { if (method === "pane.read") return { type: "pane_read", read: { pane_id: "p", source: params.source, text: "> Ask anything" } }; if (method === "pane.process_info") { if (prompts) { owner.snapshot.connection = "unknown"; placed.handleDisconnect(); throw new HerdrTransportError("write EPIPE"); } return { type: "pane_process_info", process_info: { pane_id: "p", foreground_processes: [processFor(launch)] } }; } if (method === "agent.get") return readyAgent(launch, "codex-r"); if (method === "agent.prompt") { prompts++; return { type: "agent_prompted", agent: { terminal_id: "term", pane_id: "p", agent_status: "working" } }; } throw new Error(method); } } }, async replaceConnection(input: { connection: typeof replacement }) { replacements++; owner.connection = input.connection as never; owner.snapshot.connection = "connected"; }, async cleanup() {} } as never; placed = new HerdrExternalSession(owner, launch, preflight("codex", "codex-cli 0.154.0", codexHelp), (async () => { connects++; return replacement; }) as never); const result = await placed.promptAndSettle(common, { timeoutMs: 30_000, clock: { now: () => now, async wait() { now = 23_000; } } }); assert.equal(result.outcome, "partial"); assert.equal(prompts, 1); assert.equal(replacements, 1); assert.equal(connects, 1); }); it("reconnects the exact external pane and retained PID without redispatch", async () => { const launch = createHerdrExternalAdapterLaunch({ adapter: "claude-code", remoteRuntimeDir: "/tmp/runtimedir", nativeSessionId: session }), identity = { runId: "r", machineId: "m", target: "host", session: null, workspaceId: "w", tabId: "t", paneId: "p", terminalId: "term", agentName: "claude-r", nativeSessionId: session, cwd, runtimeDir: "/tmp/r" }; let prompts = 0, replacements = 0, subscribed = 0; const owner = { machine: { id: "m", target: "host", cwd }, agentName: "claude-r", terminalId: "term", startedArgv: argvFor(launch), owned: { workspaceId: "w", tabId: "t", paneId: "p" }, identity, snapshot: { connection: "connected" }, connection: { client: { async call(method: string, params: Record) { if (method === "pane.process_info") return { type: "pane_process_info", process_info: { pane_id: "p", foreground_processes: [processFor(launch), { pid: 77, name: "helper", argv0: "node", cwd }] } }; if (method === "pane.read") return { type: "pane_read", read: { pane_id: "p", source: params.source, text: "RESULT=41" } }; if (method === "agent.prompt") { prompts++; return { type: "agent_prompted", agent: { terminal_id: "term", pane_id: "p", agent_status: "done" } }; } throw new Error(method); } } }, async replaceConnection(input: Record) { replacements++; assert.equal(input.paneId, "p"); } } as never, connect = async () => ({ endpoint: { session: null, protocol: 22, version: "0.9.0" }, client: { async call(method: string) { if (method === "session.snapshot") return { type: "session_snapshot", snapshot: { agents: [{ terminal_id: "term", pane_id: "p", agent_status: "done" }] } }; return { type: "pane_process_info", process_info: { pane_id: "p", foreground_processes: [processFor(launch), { pid: 77, name: "helper", argv0: "node", cwd }] } }; }, async subscribe(filters: unknown) { assert.deepEqual(filters, [{ type: "pane.agent_status_changed", pane_id: "p" }, { type: "pane.closed" }, { type: "pane.moved" }]); subscribed++; return () => {}; } }, async close() {} }); const placed = new HerdrExternalSession(owner, launch, preflight("claude", "2.1.269 (Claude Code)", claudeHelp), connect as never); assert.equal((await placed.promptAndSettle(common)).outcome, "partial"); await placed.reconnect(); assert.equal(prompts, 1); assert.equal(replacements, 1); assert.equal(subscribed, 1); }); it("reconnect rejects changed PID, cwd, or canonical argv0", async () => { for (const overrides of [{ pid: 99 }, { cwd: "/other" }, { argv0: "evil" }]) { const launch = createHerdrExternalAdapterLaunch({ adapter: "claude-code", remoteRuntimeDir: "/tmp/runtimedir", nativeSessionId: session }), identity = { runId: "r", machineId: "m", target: "host", session: null, workspaceId: "w", tabId: "t", paneId: "p", terminalId: "term", agentName: "claude-r", nativeSessionId: session, cwd, runtimeDir: "/tmp/r" }, owner = { machine: { id: "m", target: "host", cwd }, agentName: "claude-r", terminalId: "term", startedArgv: argvFor(launch), owned: { workspaceId: "w", tabId: "t", paneId: "p" }, identity, snapshot: { connection: "connected" }, connection: { client: { async call(method: string, params: Record) { if (method === "pane.process_info") return { type: "pane_process_info", process_info: { pane_id: "p", foreground_processes: [processFor(launch, { argv: undefined })] } }; if (method === "pane.read") return { type: "pane_read", read: { pane_id: "p", source: params.source, text: "RESULT=41" } }; return { type: "agent_prompted", agent: { terminal_id: "term", pane_id: "p", agent_status: "done" } }; } } }, async replaceConnection() { throw new Error("must not replace"); } } as never, connect = async () => ({ endpoint: { session: null, protocol: 22, version: "0.9.0" }, client: { async call(method: string) { if (method === "session.snapshot") return { type: "session_snapshot", snapshot: { agents: [{ terminal_id: "term", pane_id: "p", agent_status: "done" }] } }; return { type: "pane_process_info", process_info: { pane_id: "p", foreground_processes: [processFor(launch, { argv: undefined, ...overrides })] } }; }, async subscribe() { return () => {}; } }, async close() {} }); const placed = new HerdrExternalSession(owner, launch, preflight("claude", "2.1.269 (Claude Code)", claudeHelp), connect as never); assert.equal((await placed.promptAndSettle(common)).outcome, "partial"); await assert.rejects(placed.reconnect(), /native PID/u); } }); it("bounds acknowledged replacement churn cumulatively and leaves the owner unknown", async () => { const launch = createHerdrExternalAdapterLaunch({ adapter: "claude-code", remoteRuntimeDir: "/tmp/runtimedir", nativeSessionId: session }), identity = { runId: "r", machineId: "m", target: "host", session: null, workspaceId: "w", tabId: "t", paneId: "p", terminalId: "term", agentName: "claude-r", nativeSessionId: session, cwd, runtimeDir: "/tmp/r" }; let connects = 0; const losses: Array<() => void> = []; const initial = {} as never; const owner = { machine: { id: "m", target: "host", cwd }, identity, owned: { workspaceId: "w", tabId: "t", paneId: "p" }, snapshot: { connection: "connected" }, connection: initial, markConnectionUnknown(observed: unknown) { if (this.connection !== observed) return false; this.snapshot.connection = "unknown"; return true; }, observeEvent() {}, async replaceConnection(input: { connection: unknown }) { this.connection = input.connection as never; this.snapshot.connection = "connected"; } } as never; const connect = async () => { connects++; return { endpoint: { session: null, protocol: 22, version: "0.9.0" }, client: { async call() { return { type: "session_snapshot", snapshot: { agents: [{ terminal_id: "term", pane_id: "p", agent_status: "done" }] } }; }, async subscribe(_filters: unknown, _listener: unknown, lost: () => void) { losses.push(lost); return () => {}; } }, async close() {} }; }; const placed = new HerdrExternalSession(owner, launch, preflight("claude", "2.1.269 (Claude Code)", claudeHelp), connect as never); placed.handleDisconnect(initial); for (let index = 0; index < 4; index++) { await new Promise((resolve) => setImmediate(resolve)); losses[index]?.(); } await new Promise((resolve) => setImmediate(resolve)); assert.equal(connects, 3); assert.equal(owner.snapshot.connection, "unknown"); await assert.rejects(placed.reconnect(), /reconnect remains unknown/u); }); it("never adopts external candidates lost after acknowledgement but before subscribe returns", async () => { const launch = createHerdrExternalAdapterLaunch({ adapter: "claude-code", remoteRuntimeDir: "/tmp/runtimedir", nativeSessionId: session }), identity = { runId: "r", machineId: "m", target: "host", session: null, workspaceId: "w", tabId: "t", paneId: "p", terminalId: "term", agentName: "claude-r", nativeSessionId: session, cwd, runtimeDir: "/tmp/r" }; let connects = 0, closes = 0, stops = 0, replacements = 0; const original = {} as never; const owner = { machine: { id: "m", target: "host", cwd }, identity, connection: original, observeEvent() {}, async replaceConnection() { replacements++; } } as never; const connect = async () => { connects++; return { endpoint: { session: null, protocol: 22, version: "0.9.0" }, client: { async call() { return { type: "session_snapshot", snapshot: { agents: [{ terminal_id: "term", pane_id: "p", agent_status: "done" }] } }; }, async subscribe(_filters: unknown, _listener: unknown, lost: (error: Error) => void) { lost(new Error("post-ack candidate loss")); return () => { stops++; }; } }, async close() { closes++; } }; }; const placed = new HerdrExternalSession(owner, launch, preflight("claude", "2.1.269 (Claude Code)", claudeHelp), connect as never); await assert.rejects(placed.reconnect(), /post-ack candidate loss/u); assert.equal(replacements, 0); assert.equal(connects, 3); assert.equal(closes, 3); assert.equal(stops, 3); }); it("caches cleanup rejection exactly once", async () => { let failures = 0; const owner = { async cleanup() { failures++; throw new Error("remove failed"); } } as never, launch = createHerdrExternalAdapterLaunch({ adapter: "claude-code", remoteRuntimeDir: "/tmp/pi-subagents-herdr-run", nativeSessionId: session }), placed = new HerdrExternalSession(owner, launch, preflight("claude", "2.1.269 (Claude Code)", claudeHelp)); const concurrent = await Promise.allSettled([placed.dispose(), placed.abort(), placed.dispose()]); assert.equal(concurrent.every((item) => item.status === "rejected"), true); await assert.rejects(placed.abort(), /remove failed/u); assert.equal(failures, 1); }); });