mirror of
https://github.com/stablyai/orca.git
synced 2026-11-01 01:27:35 +00:00
fix(terminal): quit no longer warns about terminals a paired Orca server keeps running (#30006)
A paired runtime (orca serve, managed SSH/WSL orcad) owns its terminals and keeps them after this client quits, so only SSH relay terminals, which a relay kills after its grace period, still raise the quit warning. Window close is unchanged. Fixes #29916
This commit is contained in:
@@ -81,22 +81,52 @@ describe('assessWindowCloseRunningWork', () => {
|
||||
})
|
||||
})
|
||||
|
||||
it('warns on quit about a live process on a paired runtime host', async () => {
|
||||
// #29916: a paired runtime owns its terminals and keeps them after this client quits.
|
||||
it('does not warn on quit, or probe, for a live process on a paired runtime host', async () => {
|
||||
setState([RUNTIME_PTY, OWNERLESS_RUNTIME_PTY])
|
||||
answerWith({ [RUNTIME_PTY]: BUSY, [OWNERLESS_RUNTIME_PTY]: BUSY })
|
||||
|
||||
await expect(assessWindowCloseRunningWork({ isQuitting: true })).resolves.toEqual({
|
||||
kind: 'none'
|
||||
})
|
||||
expect(inspectRuntimeTerminalProcessMock).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('does not warn on quit when a paired runtime host is unreachable', async () => {
|
||||
setState([RUNTIME_PTY])
|
||||
answerWith({ [RUNTIME_PTY]: UNVERIFIABLE })
|
||||
|
||||
await expect(assessWindowCloseRunningWork({ isQuitting: true })).resolves.toEqual({
|
||||
kind: 'none'
|
||||
})
|
||||
})
|
||||
|
||||
it('still warns when closing the window over a live process on a paired runtime host', async () => {
|
||||
setState([RUNTIME_PTY])
|
||||
answerWith({ [RUNTIME_PTY]: BUSY })
|
||||
|
||||
await expect(assessWindowCloseRunningWork({ isQuitting: true })).resolves.toEqual({
|
||||
await expect(assessWindowCloseRunningWork({ isQuitting: false })).resolves.toEqual({
|
||||
kind: 'running'
|
||||
})
|
||||
})
|
||||
|
||||
it('counts an owner-less remote pty as remote work', async () => {
|
||||
it('still warns when closing the window over an owner-less runtime pty', async () => {
|
||||
setState([OWNERLESS_RUNTIME_PTY])
|
||||
answerWith({ [OWNERLESS_RUNTIME_PTY]: BUSY })
|
||||
answerWith({ [OWNERLESS_RUNTIME_PTY]: UNVERIFIABLE })
|
||||
|
||||
await expect(assessWindowCloseRunningWork({ isQuitting: false })).resolves.toEqual({
|
||||
kind: 'unverifiable'
|
||||
})
|
||||
})
|
||||
|
||||
it('warns on quit about an SSH relay pty alongside a busy paired runtime pty', async () => {
|
||||
setState([SSH_PTY, RUNTIME_PTY])
|
||||
answerWith({ [SSH_PTY]: BUSY, [RUNTIME_PTY]: BUSY })
|
||||
|
||||
await expect(assessWindowCloseRunningWork({ isQuitting: true })).resolves.toEqual({
|
||||
kind: 'running'
|
||||
})
|
||||
expect(inspectRuntimeTerminalProcessMock).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
|
||||
// The crux of docs/reference/ssh-execution-boundary.md: an unreachable host is `unverifiable`,
|
||||
@@ -155,7 +185,7 @@ describe('assessWindowCloseRunningWork', () => {
|
||||
setState([SSH_PTY, RUNTIME_PTY])
|
||||
answerWith({ [SSH_PTY]: UNVERIFIABLE, [RUNTIME_PTY]: BUSY })
|
||||
|
||||
await expect(assessWindowCloseRunningWork({ isQuitting: true })).resolves.toEqual({
|
||||
await expect(assessWindowCloseRunningWork({ isQuitting: false })).resolves.toEqual({
|
||||
kind: 'running'
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useAppStore } from '@/store'
|
||||
import { isRemoteExecutionHostPtyId } from '../../../../shared/remote-execution-host-pty-id'
|
||||
import { parseAppSshPtyId } from '../../../../shared/ssh-pty-id'
|
||||
import { collectTabPtyIds } from './running-terminal-close-guard'
|
||||
import { probePtyRunningWork } from './pty-running-work-probe'
|
||||
|
||||
@@ -32,10 +32,12 @@ export type WindowCloseRunningWork =
|
||||
*
|
||||
* Two deliberate asymmetries:
|
||||
*
|
||||
* - **Quit only considers remote ptys.** Quitting is an unambiguous instruction to end this
|
||||
* - **Quit only considers SSH relay ptys.** Quitting is an unambiguous instruction to end this
|
||||
* machine's processes (#524), but it is not an instruction to end execution on someone else's:
|
||||
* the client detaches while the relay keeps running, and a target with a bounded grace period
|
||||
* then SIGKILLs that work once the countdown expires.
|
||||
* an SSH relay (`ssh:` ids) keeps its terminals only for its grace period after the client
|
||||
* detaches, then kills them. A paired runtime (`remote:` ids: `orca serve`, managed SSH/WSL
|
||||
* orcad) owns its terminals outright and keeps them after the client quits, so quitting
|
||||
* endangers nothing there, reachable or not (#29916).
|
||||
* - **Only a remote `unverifiable` warns.** A local probe has no transport to lose, so its failure
|
||||
* means the pty is gone. A remote one that cannot be reached is the case
|
||||
* `docs/reference/ssh-execution-boundary.md` exists to protect: loss of contact is not evidence
|
||||
@@ -51,7 +53,7 @@ export async function assessWindowCloseRunningWork(params: {
|
||||
.flatMap((tab) => collectTabPtyIds(state, tab.id))
|
||||
)
|
||||
const candidatePtyIds = params.isQuitting
|
||||
? [...ptyIds].filter(isRemoteExecutionHostPtyId)
|
||||
? [...ptyIds].filter((ptyId) => parseAppSshPtyId(ptyId) !== null)
|
||||
: [...ptyIds]
|
||||
if (candidatePtyIds.length === 0) {
|
||||
return { kind: 'none' }
|
||||
|
||||
Reference in New Issue
Block a user