From 39d15d52c0ff11062400d6fd846596316e28d0de Mon Sep 17 00:00:00 2001 From: Brennan Benson <79079362+brennanb2025@users.noreply.github.com> Date: Sun, 4 Oct 2026 15:55:24 -0700 Subject: [PATCH] docs(agent-launch): say when a replayed handle is re-derived, and what a gone pane reads as The comments claimed a recorded terminal handle is dead after any restart and that a gone pane's handle resolves to not-found. Neither is what the code does: the terminal daemon and the SSH relay keep each PTY's handle and a restarted runtime re-adopts it, so re-deriving it from the pane key changes it only when that re-adoption does not happen (the PTY's incarnation changed, the runtime had already issued the pane another handle, or the PTY stored none). A gone pane's recorded handle reads as an exited terminal. Comments only. --- src/main/runtime/rpc/methods/agent-launch-replay.ts | 10 ++++++---- .../rpc/methods/agent-launch-restart-replay.test.ts | 10 ++++++---- .../runtime/rpc/methods/agent-launch.test-fixture.ts | 4 ++-- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/main/runtime/rpc/methods/agent-launch-replay.ts b/src/main/runtime/rpc/methods/agent-launch-replay.ts index 8e16ffdf991..ea8d79fad5f 100644 --- a/src/main/runtime/rpc/methods/agent-launch-replay.ts +++ b/src/main/runtime/rpc/methods/agent-launch-replay.ts @@ -113,10 +113,12 @@ function readsUnconfirmedLaunchPrompt( } /** - * A terminal handle is issued by the process that answered, so a recorded one is dead after a - * restart. The pane key is the durable name: the handle is re-derived from it in this runtime. A - * pane this runtime no longer knows keeps the recorded handle, which then resolves to not-found — - * the truth about a terminal that is gone. The handle stays because shipped clients require one. + * The handle this runtime uses for the recorded pane now. Usually that is the recorded handle: the + * daemon and the SSH relay keep each PTY's handle, and a restarted runtime re-adopts it. It does not + * when the PTY's incarnation changed, when it already issued that pane another handle before reading + * the inventory, or when the PTY stored none; the pane key, the durable name, finds it then. A pane + * this runtime no longer knows keeps the recorded handle, which reads as an exited terminal — the + * truth about one that is gone. The handle stays because shipped clients require one. */ function withLiveTerminalHandle( recorded: AgentLaunchResult, diff --git a/src/main/runtime/rpc/methods/agent-launch-restart-replay.test.ts b/src/main/runtime/rpc/methods/agent-launch-restart-replay.test.ts index 3865afebd90..037da9ca86a 100644 --- a/src/main/runtime/rpc/methods/agent-launch-restart-replay.test.ts +++ b/src/main/runtime/rpc/methods/agent-launch-restart-replay.test.ts @@ -4,8 +4,9 @@ * The record is written twice: once when the surface exists and once when the prompt's fate is * known. A host that dies at any point leaves the replay a truthful answer — the running agent once * its surface is recorded, an honest "unknown" before — and never a second agent. A "restart" here - * is what a new process sees: the store reopened from disk and a runtime with no in-flight launches, - * which issues its own handles, so a surviving pane comes back under a new one. + * is what a new process sees: the store reopened from disk and a runtime with no in-flight launches. + * Its runtime issues a surviving pane a new handle — the case where the daemon's or relay's handle + * was not re-adopted, the only one in which re-deriving the handle from the pane key changes it. */ import { mkdtemp, rm } from 'node:fs/promises' @@ -74,7 +75,8 @@ const DESKTOP_IPC = { clientKind: 'runtime' as const, clientCapabilities: DESKTOP_RENDERER_RUNTIME_CLIENT_CAPABILITIES } -/** The handle a restarted host issues the pane that outlived the old one. */ +/** The handle a restarted host issues a pane that outlived the old one, when it could not + * re-adopt that pane's recorded handle. */ const ADOPTED_HANDLE = 'term_adopted' let directory: string @@ -210,7 +212,7 @@ describe('a host restart mid-launch', () => { await restartHost() const restarted = restartedHostRuntime() - // The dead host's `term_1` names nothing now; the pane is the durable name. + // The dead host's `term_1` was not re-adopted; the pane is the durable name. await expect(launch(restarted, PROMPTED_LAUNCH, UPGRADED_PHONE)).resolves.toEqual( UNCONFIRMED_AGENT ) diff --git a/src/main/runtime/rpc/methods/agent-launch.test-fixture.ts b/src/main/runtime/rpc/methods/agent-launch.test-fixture.ts index dcd6e0e6bda..c0aeb4436ce 100644 --- a/src/main/runtime/rpc/methods/agent-launch.test-fixture.ts +++ b/src/main/runtime/rpc/methods/agent-launch.test-fixture.ts @@ -40,7 +40,7 @@ export type AgentLaunchRuntimeStubOptions = { /** What the runtime reports about an offered prompt's typed line; unset reports nothing. */ lineCarriesPrompt?: boolean /** Panes this runtime found already running, by the handle it issued them: a restarted host - * adopting a surviving PTY issues a new handle for the same pane. */ + * that could not re-adopt a surviving PTY's handle issues a new one for the same pane. */ adoptedPanes?: Record } @@ -63,7 +63,7 @@ export function setAgentLaunchRecordStore(store: AgentSessionRecordStore | null) export function runtimeStub(options: AgentLaunchRuntimeStubOptions = {}) { const worktreeCreateResults = new Map>() - // Only the panes this runtime created or adopted: a handle is process-scoped, a pane key is not. + // Only the panes this runtime created or adopted, under the handle it issued them. const handlesByPaneKey = new Map(Object.entries(options.adoptedPanes ?? {})) const waitForSetupTerminalCompletion = vi.fn( async (_handle: string, _signal?: AbortSignal): Promise<{ exitCode: number | null }> => ({