From 2a3fc8372bb0d6f69f710bb0de0080d5dd323718 Mon Sep 17 00:00:00 2001 From: Neil <4138956+nwparker@users.noreply.github.com> Date: Wed, 28 Oct 2026 07:10:03 -0700 Subject: [PATCH] perf(terminal): a clean WSL bridge exit skips the boot-id read (#35138) On awin a wsl --terminate exited each bridge pane with -1, while exit and exit 0 gave 0, so a terminate never yields 0. A clean exit keeps today's verdict without the extra wsl.exe spawn. Co-authored-by: Claude --- .../daemon-pty-adapter-wsl-distro-loss.test.ts | 15 +++++++++++++++ src/main/daemon/daemon-pty-adapter.ts | 13 ++++++++++--- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/src/main/daemon/daemon-pty-adapter-wsl-distro-loss.test.ts b/src/main/daemon/daemon-pty-adapter-wsl-distro-loss.test.ts index 270c8978a26..1f452f03177 100644 --- a/src/main/daemon/daemon-pty-adapter-wsl-distro-loss.test.ts +++ b/src/main/daemon/daemon-pty-adapter-wsl-distro-loss.test.ts @@ -168,6 +168,21 @@ describe('a WSL bridge pane exit', () => { expect(exits[1]).not.toHaveProperty('hostLost') }) + // awin: a terminate exited each bridge pane with -1, never 0; a user's `exit` gives 0. + it('reads no boot id for a clean exit, which stays an exit even across a reboot', async () => { + bootIds = ['boot-1', 'boot-2'] + const exits = collectExits() + const id = await spawnBridgePane() + await waitFor(() => readBootId.mock.calls.length === 1) + + subprocesses[0]!._simulateExit(0) + + await waitFor(() => exits.length > 0) + expect(exits[0]).toMatchObject({ id, code: 0 }) + expect(exits[0]).not.toHaveProperty('hostLost') + expect(readBootId).toHaveBeenCalledOnce() + }) + it('stays a normal exit when the running list cannot answer', async () => { running = async () => ({ status: 'unavailable' }) const exits = collectExits() diff --git a/src/main/daemon/daemon-pty-adapter.ts b/src/main/daemon/daemon-pty-adapter.ts index dad2fed546d..273b10d1867 100644 --- a/src/main/daemon/daemon-pty-adapter.ts +++ b/src/main/daemon/daemon-pty-adapter.ts @@ -250,11 +250,18 @@ export class DaemonPtyAdapter extends DaemonPtyDaemonRecovery implements IPtyPro wslDistro: string, exitAt: number ): Promise { - const verdict = await classifyWslBridgeExit(wslDistro, exitAt, this.readRunningWslDistros, () => - this.wslBridgeBootIdentity.rebootedSinceSpawn(sessionId, wslDistro) + // A terminate never exits 0 (awin: -1 for each bridge pane; `exit`/`exit 0` gave 0), so a clean + // exit skips the boot-id read and stays an exit. + const verdict = await classifyWslBridgeExit( + wslDistro, + exitAt, + this.readRunningWslDistros, + async () => + exit.code !== 0 && + (await this.wslBridgeBootIdentity.rebootedSinceSpawn(sessionId, wslDistro)) ) // Lost, or booted again since the spawn, keeps the tab; an unanswered check reads as an exit. - // The code lets a verify run show which codes a terminate yields (only 1 is on record). + // The code shows a verify run which codes a terminate yields. console.info( `[pty] WSL bridge exit: ${verdict} (distro ${wslDistro}, code ${exit.code}, probe ${Math.round(performance.now() - exitAt)}ms)` )