Files
orca/src/main/windows-process-tree-kill.test.ts
T
Wooseong Kim dc18ba9cda fix(win): taskkill agent PTY descendant trees on stop (#10100)
* fix(win): taskkill agent PTY descendant trees on stop

Windows agent teardown previously degraded to shell-only kill because
descendant snapshot is POSIX-only. Orphaned claude/codex/MCP children
kept worktree cwd handles open and blocked worktree remove.

Use taskkill /T /F on the PTY root in killWithDescendantSweep (daemon +
local agent shutdown) so the ConPTY tree is cleared before teardown.

Fixes #10004

* fix(win): bound taskkill with timeout and windowsHide

Prevent a wedged taskkill from delaying killRoot, and hide the console
flash during agent PTY tree teardown (CodeRabbit on #10100).
2026-07-24 00:27:40 -07:00

56 lines
1.6 KiB
TypeScript

import { describe, expect, it, vi } from 'vitest'
import {
terminateWindowsProcessTree,
WINDOWS_PROCESS_TREE_KILL_TIMEOUT_MS
} from './windows-process-tree-kill'
describe('terminateWindowsProcessTree', () => {
it('invokes taskkill /T /F with timeout and windowsHide', async () => {
const execFileImpl = vi.fn(
(
_cmd: string,
_args: readonly string[],
_options: { timeout?: number; windowsHide?: boolean },
callback: (error: Error | null) => void
) => {
callback(null)
}
)
await terminateWindowsProcessTree(1234, {
execFileImpl: execFileImpl as never
})
expect(execFileImpl).toHaveBeenCalledWith(
'taskkill',
['/pid', '1234', '/T', '/F'],
{
timeout: WINDOWS_PROCESS_TREE_KILL_TIMEOUT_MS,
windowsHide: true
},
expect.any(Function)
)
})
it('resolves even when taskkill reports failure (already dead)', async () => {
const execFileImpl = vi.fn(
(
_cmd: string,
_args: readonly string[],
_options: { timeout?: number; windowsHide?: boolean },
callback: (error: Error | null) => void
) => {
callback(new Error('not found'))
}
)
await expect(
terminateWindowsProcessTree(55, { execFileImpl: execFileImpl as never })
).resolves.toBeUndefined()
})
it('skips taskkill for invalid pids', async () => {
const execFileImpl = vi.fn()
await terminateWindowsProcessTree(0, { execFileImpl: execFileImpl as never })
await terminateWindowsProcessTree(-1, { execFileImpl: execFileImpl as never })
expect(execFileImpl).not.toHaveBeenCalled()
})
})