mirror of
https://github.com/stablyai/orca.git
synced 2026-10-18 00:03:20 +00:00
await provider proof for remote terminal close
This commit is contained in:
@@ -3883,6 +3883,7 @@
|
||||
"file": "src/main/runtime/orca-runtime.test.ts",
|
||||
"assertions": [
|
||||
"terminal.stop awaits stopAndWait and fresh post-stop liveness before acknowledging provider shutdown",
|
||||
"remote terminal.close rejects until provider stopAndWait verifies shutdown",
|
||||
"provider shutdown rejection fails terminal.stop closed",
|
||||
"project removal fences paired terminal admission through provider stop and repo mutation",
|
||||
"project removal drains create-first headless, renderer-backed mobile, renderer split, and selector-less renderer admissions before its liveness snapshot",
|
||||
|
||||
@@ -17690,12 +17690,13 @@ describe('OrcaRuntimeService', () => {
|
||||
|
||||
it('operates PTY-backed mobile session terminals without a renderer graph', async () => {
|
||||
const spawn = vi.fn().mockResolvedValue({ id: 'laptop-created-pty' })
|
||||
const kill = vi.fn(() => true)
|
||||
const stopAndWait = vi.fn(async () => true)
|
||||
const runtime = new OrcaRuntimeService(store)
|
||||
runtime.setPtyController({
|
||||
spawn,
|
||||
write: () => true,
|
||||
kill,
|
||||
kill: () => false,
|
||||
stopAndWait,
|
||||
getForegroundProcess: async () => null
|
||||
})
|
||||
|
||||
@@ -17719,7 +17720,29 @@ describe('OrcaRuntimeService', () => {
|
||||
tabId: 'laptop-tab',
|
||||
ptyKilled: true
|
||||
})
|
||||
expect(kill).toHaveBeenCalledWith('laptop-created-pty')
|
||||
expect(stopAndWait).toHaveBeenCalledWith('laptop-created-pty')
|
||||
})
|
||||
|
||||
it('rejects remote terminal close until provider shutdown is verified', async () => {
|
||||
const runtime = new OrcaRuntimeService(store)
|
||||
runtime.setPtyController({
|
||||
spawn: vi.fn().mockResolvedValue({ id: 'laptop-created-pty' }),
|
||||
write: () => true,
|
||||
kill: () => true,
|
||||
stopAndWait: async () => false,
|
||||
getForegroundProcess: async () => null
|
||||
})
|
||||
const terminal = await runtime.createTerminal(`id:${TEST_WORKTREE_ID}`, {
|
||||
tabId: 'laptop-tab',
|
||||
leafId: HEADLESS_LEAF_ID
|
||||
})
|
||||
|
||||
await expect(runtime.closeTerminal(terminal.handle)).rejects.toThrow(
|
||||
'terminal_verified_stop_failed'
|
||||
)
|
||||
await expect(runtime.readTerminal(terminal.handle)).resolves.toMatchObject({
|
||||
status: 'running'
|
||||
})
|
||||
})
|
||||
|
||||
it('lists PTY-backed mobile session terminals without a renderer graph', async () => {
|
||||
|
||||
@@ -18913,17 +18913,29 @@ export class OrcaRuntimeService {
|
||||
|
||||
async closeTerminal(handle: string): Promise<RuntimeTerminalClose> {
|
||||
const pty = this.getLivePtyForHandle(handle)
|
||||
this.claudeAgentTeams.removeTeamForLeaderHandle(handle)
|
||||
if (pty) {
|
||||
const ptyKilled = this.ptyController?.kill(pty.pty.ptyId) ?? false
|
||||
return { handle, tabId: pty.pty.tabId ?? pty.record.tabId, ptyKilled }
|
||||
if (!this.ptyController?.stopAndWait) {
|
||||
throw new Error('terminal_verified_stop_unavailable')
|
||||
}
|
||||
if (!(await this.ptyController.stopAndWait(pty.pty.ptyId))) {
|
||||
throw new Error('terminal_verified_stop_failed')
|
||||
}
|
||||
this.claudeAgentTeams.removeTeamForLeaderHandle(handle)
|
||||
return { handle, tabId: pty.pty.tabId ?? pty.record.tabId, ptyKilled: true }
|
||||
}
|
||||
this.assertGraphReady()
|
||||
const { leaf } = this.getLiveLeafForHandle(handle)
|
||||
let ptyKilled = false
|
||||
if (leaf.ptyId) {
|
||||
ptyKilled = this.ptyController?.kill(leaf.ptyId) ?? false
|
||||
if (!this.ptyController?.stopAndWait) {
|
||||
throw new Error('terminal_verified_stop_unavailable')
|
||||
}
|
||||
ptyKilled = await this.ptyController.stopAndWait(leaf.ptyId)
|
||||
if (!ptyKilled) {
|
||||
throw new Error('terminal_verified_stop_failed')
|
||||
}
|
||||
}
|
||||
this.claudeAgentTeams.removeTeamForLeaderHandle(handle)
|
||||
// Why: killing the PTY in a multi-pane tab is sufficient — the renderer's
|
||||
// PTY exit handler already calls PaneManager.closePane() for split layouts.
|
||||
// Sending an additional IPC close would race with the exit handler and
|
||||
|
||||
Reference in New Issue
Block a user