fix(terminal): a parked local tab whose process exits closes as a pty-exit, not a user close (#34083)

The parked watcher passes only hostCloseReason 'pty-exit' (so the pinned
guard still applies), and the local branch then let closeTab default the
reason to 'user': a process exit wrote a user tombstone and retired the
session. The local close now carries the pty-exit reason.

Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
Neil
2026-10-26 15:56:28 -07:00
committed by GitHub
co-authored by Claude
parent ccfe30a05f
commit 1d1c6da582
2 changed files with 13 additions and 1 deletions
@@ -88,4 +88,15 @@ describe('closeTerminalTab before the worktree catalog names a host', () => {
expect(onClosed).toHaveBeenCalled()
expect(closeWebRuntimeSessionTabMock).not.toHaveBeenCalled()
})
it('closes a parked local tab whose process exited as a pty-exit, never a user close', () => {
// A user close would tombstone the tab and retire its session (verify-15a 5e).
isWebRuntimeSessionActiveMock.mockReturnValue(false)
const closeTab = vi.fn()
getStateMock.mockReturnValue(unhydratedState('pty-1', closeTab))
closeTerminalTab('tab-1', { hostCloseReason: 'pty-exit', lifecyclePtyId: 'pty-1' })
expect(closeTab).toHaveBeenCalledWith('tab-1', expect.objectContaining({ reason: 'pty-exit' }))
})
})
@@ -199,7 +199,8 @@ export function closeTerminalTab(
}
closeLocalTerminalTabState(terminalTabId, {
reason: options?.reason,
// A parked tab's process exit carries only the host reason, to keep the pin guard above.
reason: options?.reason ?? (options?.hostCloseReason === 'pty-exit' ? 'pty-exit' : undefined),
...(options?.captureRecentlyClosed !== undefined
? { captureRecentlyClosed: options.captureRecentlyClosed }
: {}),