From 0276e913ba24e31ce5add008eab952322db69a76 Mon Sep 17 00:00:00 2001 From: Neil <4138956+nwparker@users.noreply.github.com> Date: Mon, 24 Aug 2026 19:22:26 -0700 Subject: [PATCH] docs(pty): correct headless-path comments the #15172 rebase left stale MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #15927 made `registerPtyHandlers` accept `BrowserWindow | null` so the headless path could pass null instead of faking a window. #15172 reverted that signature while splitting the PTY monolith, but the comments describing it survived, so three of them now document an API that does not exist. - orcad-entry.ts: the module docstring claimed orcad installs its controller via `registerPtyHandlers(null, …)`. It uses `registerHeadlessPtyRuntime`, and null is not accepted. It also claimed desktop surfaces are "declared rather than faked" — true except for the renderer window, which is still faked. - register-headless-runtime.ts: record why the fake is safe rather than leaving `isDestroyed: () => true` looking arbitrary. It is load-bearing: every renderer-liveness guard reads it and skips, so no send is attempted. Also gives the fake a `webContents.isDestroyed`. The real guards check both, and a missing method reads as "alive" — the same gap this PR fixes in the test fake. No behavior change: the window-level check already short-circuits. Verified: 45 tests across the liveness-guard, startup-barrier, management and kill/exit suites; pnpm typecheck clean; oxlint clean. --- src/main/ipc/pty/register-headless-runtime.ts | 4 ++++ src/main/orcad/orcad-entry.ts | 10 ++++++---- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/main/ipc/pty/register-headless-runtime.ts b/src/main/ipc/pty/register-headless-runtime.ts index d1a10871178..f380482a079 100644 --- a/src/main/ipc/pty/register-headless-runtime.ts +++ b/src/main/ipc/pty/register-headless-runtime.ts @@ -23,9 +23,13 @@ export function registerHeadlessPtyRuntime( } ): void { // Why: headless `orca serve` has no renderer window but still needs the same PTY handlers so remote clients can drive terminals. + // Why a fake rather than null: `registerPtyHandlers` takes a non-null BrowserWindow. `isDestroyed: () => true` + // is what makes that safe — every renderer-liveness guard reads it and skips, so no send is ever attempted. + // Keep `webContents.isDestroyed` in step with it: guards check both, and a missing method reads as "alive". const headlessWindow = { isDestroyed: () => true, webContents: { + isDestroyed: () => true, send: () => {}, on: () => {}, removeListener: () => {} diff --git a/src/main/orcad/orcad-entry.ts b/src/main/orcad/orcad-entry.ts index bab68282e53..94a7f4267da 100644 --- a/src/main/orcad/orcad-entry.ts +++ b/src/main/orcad/orcad-entry.ts @@ -2,12 +2,14 @@ * `orcad` — the Orca runtime served from plain Node, with no Electron. * * Installs the Node host adapters, constructs the same `OrcaRuntimeService` the - * desktop uses, installs a PTY controller via `registerPtyHandlers(null, …)`, and + * desktop uses, installs a PTY controller via `registerHeadlessPtyRuntime`, and * serves runtime RPC. See docs/design/node-only-runtime-backend.html. * * The desktop-only surfaces are deliberately left uninstalled: no notifications, no - * renderer window, no browser panes. Those are declared rather than faked — see - * `runtime-desktop-surface.ts` and `pty-host-bindings.ts`. + * renderer window, no browser panes. Most are declared rather than faked — see + * `runtime-desktop-surface.ts` and `pty-host-bindings.ts`. The renderer window is the + * exception: `registerPtyHandlers` takes a non-null `BrowserWindow`, so the headless + * path still fakes one that reports itself destroyed. */ import { homedir, tmpdir } from 'node:os' import { join } from 'node:path' @@ -144,7 +146,7 @@ export async function startOrcad(options: OrcadOptions = {}): Promise 'blocked' }) - // Why the headless entry point rather than registerPtyHandlers(null, …): this is the + // Why the headless entry point rather than registerPtyHandlers directly: this is the // same call `--serve` makes, and it threads the store through. Without the store the // handlers install fine and every terminal.create then fails at persistence time. //