fix(terminal): ask before closing a tab when Orca can't tell if an agent is running (#38697)

This commit is contained in:
Kelvin Amoaba
2026-11-05 22:44:53 +00:00
committed by GitHub
parent c884428609
commit 7ae45fb656
3 changed files with 13 additions and 19 deletions
@@ -190,7 +190,7 @@ export function useTerminalPaneCloseActions(controller: TerminalPaneBindingContr
clearTimeout(probeTimeout)
decide(() => {
if (
(pending ? probes[0]?.verdict === 'exited' : probes[0]?.verdict !== 'live') ||
probes[0]?.verdict === 'exited' ||
settings?.skipCloseTerminalWithRunningProcessConfirm
) {
close()
@@ -183,31 +183,20 @@ describe('guardRunningTerminalClose', () => {
expect(onClose).not.toHaveBeenCalled()
})
it('fails open and closes when the probe rejects (wedged relay / legacy provider)', async () => {
inspectRuntimeTerminalProcessMock.mockRejectedValue(new Error('rpc_timeout'))
const onClose = vi.fn()
guard(onClose)
await settleProbe()
expect(onClose).toHaveBeenCalledTimes(1)
expect(visibleRequest()).toBeNull()
})
it('fails open when a remote handle reports client-only unverifiable inspection', async () => {
// #33265: a host that cannot read its child processes must not let a close kill a running agent.
it('prompts when the host cannot observe child processes', async () => {
inspectRuntimeTerminalProcessMock.mockResolvedValue({
foregroundProcess: null,
hasChildProcesses: false,
verdict: 'unverifiable',
reason: 'transport_loss'
childProcessEvidence: 'unverifiable'
})
const onClose = vi.fn()
guard(onClose)
await settleProbe()
expect(onClose).toHaveBeenCalledTimes(1)
expect(visibleRequest()).toBeNull()
expect(onClose).not.toHaveBeenCalled()
expect(visibleRequest()).toMatchObject({ terminalTabId: 'tab-1' })
})
it('prompts once for a split tab where only the second pane is busy', async () => {
@@ -106,9 +106,14 @@ export function guardRunningTerminalClose(params: {
confirmClose(ptyIds)
return
}
// Answered probe failures/stale handles fail open like Cmd+W; they provide no live-child evidence and must not disable closing.
// "Could not tell" must not kill a bound pty's work (#33265); layout-only ids are often stale leaves that never answer.
const boundPtyIds = new Set(useAppStore.getState().ptyIdsByTabId?.[terminalTabId] ?? [])
const busyPtyIds = probes
.filter((probe) => probe.verdict === 'live')
.filter(
(probe) =>
probe.verdict === 'live' ||
(probe.verdict === 'unverifiable' && boundPtyIds.has(probe.ptyId))
)
.map((probe) => probe.ptyId)
if (busyPtyIds.length === 0) {
closeNow()