diff --git a/config/reliability-gates.jsonc b/config/reliability-gates.jsonc index a9d1bd4c1e1..2d9dcf0fd89 100644 --- a/config/reliability-gates.jsonc +++ b/config/reliability-gates.jsonc @@ -9351,7 +9351,7 @@ "invariant": "Shift+Enter key recognition follows the client OS, while emitted bytes follow the active application and PTY host: active Kitty keyboard protocol authorizes CSI-u on every host; otherwise Windows hosts use Esc+CR except when allowlisted Droid ownership or fresh routing-trusted Droid process evidence authorizes CSI-u, and non-Windows hosts use Esc+CR. The active SSH connection, remote-runtime PTY owner, or live local session outranks later worktree ownership changes, and missing host-platform metadata falls back to the client. Every new command and PTY replacement revokes stale agent routing until current evidence settles; split or reused panes cannot inherit sibling or prior-PTY authority; unrelated keys perform no host, agent, protocol, or ConPTY lookup.", "oracle": "Renderer tests assert exact bytes across client/PTY-host combinations, including Kitty keyboard protocol active and inactive on Windows and non-Windows hosts, and prove SSH identity, the environment encoded in an active remote-runtime PTY id, and live local-session identity outrank current worktree ownership, while unavailable platform metadata falls back to the client. A live linux-arm64 SSH PTY independently captured Esc+CR with KKP inactive and CSI-u with KKP active. Fresh Windows process evidence authorizes Droid bytes only after a recognized global candidate is intersected with the exact ConPTY console process list; detached descendants, helper failure/timeout/root-only fallback, stale PTY exit/rebind results, typed text, and hook/OSC output fail closed. A new OSC 133;C immediately publishes a routing-neutral generation, including during D-to-C races. In cmd.exe/Git Bash/custom shells without OSC 133, accepted inferred commands start the same fresh generation; accepted submit/interrupt, title exit, focus, and visibility revoke trusted Droid bytes while one bounded confirmation runs. Detach preserves the live PTY's source shell override so WSL/native classification cannot change with the current default. Ordinary fast shell commands use cached/no-scan paths; routing-relevant confirmation bypasses cached process snapshots and keeps the bounded three-read ladder. Daemon protocol v21 persists only an allowlisted launchAgent; warm reattach uses it as a display/confirmation hint and restores routing only after current process proof. The Windows Electron test focuses the real xterm textarea and records exact renderer-to-main PTY writes.", "commands": [ - "pnpm exec vitest run --config config/vitest.config.ts src/main/daemon/daemon-foreground-confirmation-protocol.test.ts src/main/daemon/daemon-pty-adapter.test.ts src/main/daemon/daemon-pty-router.test.ts src/main/daemon/daemon-server.test.ts src/main/daemon/degraded-daemon-pty-provider.test.ts src/main/daemon/pty-subprocess-foreground-scan-cadence.test.ts src/main/daemon/pty-subprocess.test.ts src/main/ipc/pty-runtime-kill-and-exit.test.ts src/main/providers/agent-foreground-process.test.ts src/main/providers/local-pty-provider-foreground-process.test.ts src/main/providers/windows-conpty-process-membership.test.ts src/renderer/src/components/terminal-pane/pane-foreground-agent-tracker.test.ts src/renderer/src/components/terminal-pane/pty-connection-command-finished-cleanup.test.ts src/renderer/src/components/terminal-pane/pty-connection-foreground-agent-routing.test.ts src/renderer/src/components/terminal-pane/pty-connection-foreground-agent-sampling.test.ts src/renderer/src/components/terminal-pane/pty-transport-reattach-admission.test.ts src/renderer/src/components/terminal-pane/terminal-pane-tab-detach.test.ts src/renderer/src/components/terminal-pane/terminal-shortcut-policy.test.ts src/renderer/src/components/terminal-pane/terminal-windows-shift-enter.test.ts src/renderer/src/store/slices/store-active-worktree-terminal-creation.test.ts src/renderer/src/store/slices/terminal-pane-detach-agent-identity.test.ts src/shared/agent-process-recognition.test.ts src/shared/process-table-snapshot.test.ts tests/e2e/terminal-foreground-confirmation.unit.test.ts", + "pnpm exec vitest run --config config/vitest.config.ts src/main/daemon/daemon-foreground-confirmation-protocol.test.ts src/main/daemon/daemon-pty-adapter.test.ts src/main/daemon/daemon-pty-router.test.ts src/main/daemon/daemon-server.test.ts src/main/daemon/degraded-daemon-pty-provider.test.ts src/main/daemon/pty-subprocess-foreground-scan-cadence.test.ts src/main/daemon/pty-subprocess.test.ts src/main/ipc/pty-runtime-kill-and-exit.test.ts src/main/providers/agent-foreground-process.test.ts src/main/providers/local-pty-provider-foreground-process.test.ts src/main/providers/windows-console-attached-processes.test.ts src/renderer/src/components/terminal-pane/pane-foreground-agent-tracker.test.ts src/renderer/src/components/terminal-pane/pty-connection-command-finished-cleanup.test.ts src/renderer/src/components/terminal-pane/pty-connection-foreground-agent-routing.test.ts src/renderer/src/components/terminal-pane/pty-connection-foreground-agent-sampling.test.ts src/renderer/src/components/terminal-pane/pty-transport-reattach-admission.test.ts src/renderer/src/components/terminal-pane/terminal-pane-tab-detach.test.ts src/renderer/src/components/terminal-pane/terminal-shortcut-policy.test.ts src/renderer/src/components/terminal-pane/terminal-windows-shift-enter.test.ts src/renderer/src/store/slices/store-active-worktree-terminal-creation.test.ts src/renderer/src/store/slices/terminal-pane-detach-agent-identity.test.ts src/shared/agent-process-recognition.test.ts src/shared/process-table-snapshot.test.ts tests/e2e/terminal-foreground-confirmation.unit.test.ts", "pnpm run test:e2e -- tests/e2e/terminal-shortcuts.spec.ts", "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/terminal-pane/keyboard-handlers.test.ts src/renderer/src/components/terminal-pane/remote-runtime-pty-transport-pane-handle-resolution.test.ts src/renderer/src/components/terminal-pane/terminal-input-host-platform.test.ts" ], @@ -9366,7 +9366,7 @@ "src/main/ipc/pty-runtime-kill-and-exit.test.ts", "src/main/providers/agent-foreground-process.test.ts", "src/main/providers/local-pty-provider-foreground-process.test.ts", - "src/main/providers/windows-conpty-process-membership.test.ts", + "src/main/providers/windows-console-attached-processes.test.ts", "src/renderer/src/components/terminal-pane/pane-foreground-agent-tracker.test.ts", "src/renderer/src/components/terminal-pane/keyboard-handlers.test.ts", "src/renderer/src/components/terminal-pane/pty-connection-command-finished-cleanup.test.ts", @@ -9405,7 +9405,7 @@ ] }, { - "file": "src/main/providers/windows-conpty-process-membership.test.ts", + "file": "src/main/providers/windows-console-attached-processes.test.ts", "assertions": [ "the fixed node-pty helper returns validated integer console membership containing the PTY root", "root-only fallback, malformed/missing-root messages, spawn errors, and a silent helper timeout all fail closed", @@ -9562,7 +9562,7 @@ "date": "2026-07-10", "runner": "local", "platform": "macos", - "command": "pnpm exec vitest run --config config/vitest.config.ts src/main/daemon/daemon-foreground-confirmation-protocol.test.ts src/main/daemon/daemon-pty-adapter.test.ts src/main/daemon/daemon-pty-router.test.ts src/main/daemon/daemon-server.test.ts src/main/daemon/degraded-daemon-pty-provider.test.ts src/main/daemon/pty-subprocess-foreground-scan-cadence.test.ts src/main/daemon/pty-subprocess.test.ts src/main/ipc/pty-runtime-kill-and-exit.test.ts src/main/providers/agent-foreground-process.test.ts src/main/providers/local-pty-provider-foreground-process.test.ts src/main/providers/windows-conpty-process-membership.test.ts src/renderer/src/components/terminal-pane/pane-foreground-agent-tracker.test.ts src/renderer/src/components/terminal-pane/pty-connection-command-finished-cleanup.test.ts src/renderer/src/components/terminal-pane/pty-connection-foreground-agent-routing.test.ts src/renderer/src/components/terminal-pane/pty-connection-foreground-agent-sampling.test.ts src/renderer/src/components/terminal-pane/pty-transport-reattach-admission.test.ts src/renderer/src/components/terminal-pane/terminal-pane-tab-detach.test.ts src/renderer/src/components/terminal-pane/terminal-shortcut-policy.test.ts src/renderer/src/components/terminal-pane/terminal-windows-shift-enter.test.ts src/renderer/src/store/slices/store-active-worktree-terminal-creation.test.ts src/renderer/src/store/slices/terminal-pane-detach-agent-identity.test.ts src/shared/agent-process-recognition.test.ts src/shared/process-table-snapshot.test.ts tests/e2e/terminal-foreground-confirmation.unit.test.ts", + "command": "pnpm exec vitest run --config config/vitest.config.ts src/main/daemon/daemon-foreground-confirmation-protocol.test.ts src/main/daemon/daemon-pty-adapter.test.ts src/main/daemon/daemon-pty-router.test.ts src/main/daemon/daemon-server.test.ts src/main/daemon/degraded-daemon-pty-provider.test.ts src/main/daemon/pty-subprocess-foreground-scan-cadence.test.ts src/main/daemon/pty-subprocess.test.ts src/main/ipc/pty-runtime-kill-and-exit.test.ts src/main/providers/agent-foreground-process.test.ts src/main/providers/local-pty-provider-foreground-process.test.ts src/main/providers/windows-console-attached-processes.test.ts src/renderer/src/components/terminal-pane/pane-foreground-agent-tracker.test.ts src/renderer/src/components/terminal-pane/pty-connection-command-finished-cleanup.test.ts src/renderer/src/components/terminal-pane/pty-connection-foreground-agent-routing.test.ts src/renderer/src/components/terminal-pane/pty-connection-foreground-agent-sampling.test.ts src/renderer/src/components/terminal-pane/pty-transport-reattach-admission.test.ts src/renderer/src/components/terminal-pane/terminal-pane-tab-detach.test.ts src/renderer/src/components/terminal-pane/terminal-shortcut-policy.test.ts src/renderer/src/components/terminal-pane/terminal-windows-shift-enter.test.ts src/renderer/src/store/slices/store-active-worktree-terminal-creation.test.ts src/renderer/src/store/slices/terminal-pane-detach-agent-identity.test.ts src/shared/agent-process-recognition.test.ts src/shared/process-table-snapshot.test.ts tests/e2e/terminal-foreground-confirmation.unit.test.ts", "result": "passed", "durationSeconds": 8.71, "summary": "Twenty-two focused test files passed (1206 tests) on current main, covering fresh-scan ordering/deduplication, exact ConPTY membership and detached-child rejection, stale PTY guards, daemon v21 launch ownership with current-process confirmation, no-OSC command/exit recovery, preserved detach shell classification, unavailable evidence, routing-neutral command generations, exact shortcut bytes, and the composed daemon-plus-tracker contract; the Windows Electron byte test remains platform-gated and is not counted as local macOS evidence." @@ -9624,7 +9624,7 @@ "oracle": "A quarter-circle Claude task title authorizes without a provider lookup only on the exact PTY incarnation carrying verified managed-Claude launch identity; the same title in a bare pane, with an unverified launch hint, or after PTY incarnation replacement is refused while current Claude activity remains a working signal. Fresh explicit state plus ordinary PowerShell plus confirmed recognized agent is sendable on the same PTY. Confirmed shell/non-agent, unavailable confirmation, PTY exit, handle rebind, or a callback PTY mismatch returns a refusal or not-writable result and writes zero bytes.", "commands": [ "pnpm exec vitest run --config config/vitest.config.ts src/main/runtime/quarter-circle-title-send-authorization.test.ts", - "pnpm exec vitest run --config config/vitest.config.ts src/main/runtime/orca-runtime.test.ts src/main/runtime/rpc/terminal-send.test.ts src/main/ipc/pty-runtime-kill-and-exit.test.ts src/main/providers/agent-foreground-process.test.ts src/main/providers/local-pty-provider-foreground-process.test.ts src/main/providers/windows-conpty-process-membership.test.ts src/main/daemon/daemon-foreground-confirmation-protocol.test.ts src/main/daemon/pty-subprocess.test.ts src/renderer/src/lib/active-agent-note-send-explicit-target.test.ts src/renderer/src/components/browser-pane/annotate/BrowserAnnotationSendMenuContent.test.tsx" + "pnpm exec vitest run --config config/vitest.config.ts src/main/runtime/orca-runtime.test.ts src/main/runtime/rpc/terminal-send.test.ts src/main/ipc/pty-runtime-kill-and-exit.test.ts src/main/providers/agent-foreground-process.test.ts src/main/providers/local-pty-provider-foreground-process.test.ts src/main/providers/windows-console-attached-processes.test.ts src/main/daemon/daemon-foreground-confirmation-protocol.test.ts src/main/daemon/pty-subprocess.test.ts src/renderer/src/lib/active-agent-note-send-explicit-target.test.ts src/renderer/src/components/browser-pane/annotate/BrowserAnnotationSendMenuContent.test.tsx" ], "testFiles": [ "src/main/runtime/quarter-circle-title-send-authorization.test.ts", @@ -9633,7 +9633,7 @@ "src/main/ipc/pty-runtime-kill-and-exit.test.ts", "src/main/providers/agent-foreground-process.test.ts", "src/main/providers/local-pty-provider-foreground-process.test.ts", - "src/main/providers/windows-conpty-process-membership.test.ts", + "src/main/providers/windows-console-attached-processes.test.ts", "src/main/daemon/daemon-foreground-confirmation-protocol.test.ts", "src/main/daemon/pty-subprocess.test.ts", "src/renderer/src/lib/active-agent-note-send-explicit-target.test.ts", @@ -9684,7 +9684,7 @@ "assertions": ["fresh confirmation is discarded when its owning local PTY exits"] }, { - "file": "src/main/providers/windows-conpty-process-membership.test.ts", + "file": "src/main/providers/windows-console-attached-processes.test.ts", "assertions": [ "exact ConPTY console membership comes from the fixed node-pty helper", "malformed, incomplete, timed-out, and spawn-error membership reads fail closed" @@ -9728,7 +9728,7 @@ "date": "2026-07-11", "runner": "local", "platform": "macos", - "command": "pnpm exec vitest run --config config/vitest.config.ts src/main/runtime/orca-runtime.test.ts src/main/runtime/rpc/terminal-send.test.ts src/main/ipc/pty-runtime-kill-and-exit.test.ts src/main/providers/agent-foreground-process.test.ts src/main/providers/local-pty-provider-foreground-process.test.ts src/main/providers/windows-conpty-process-membership.test.ts src/main/daemon/daemon-foreground-confirmation-protocol.test.ts src/main/daemon/pty-subprocess.test.ts src/renderer/src/lib/active-agent-note-send-explicit-target.test.ts src/renderer/src/components/browser-pane/annotate/BrowserAnnotationSendMenuContent.test.tsx", + "command": "pnpm exec vitest run --config config/vitest.config.ts src/main/runtime/orca-runtime.test.ts src/main/runtime/rpc/terminal-send.test.ts src/main/ipc/pty-runtime-kill-and-exit.test.ts src/main/providers/agent-foreground-process.test.ts src/main/providers/local-pty-provider-foreground-process.test.ts src/main/providers/windows-console-attached-processes.test.ts src/main/daemon/daemon-foreground-confirmation-protocol.test.ts src/main/daemon/pty-subprocess.test.ts src/renderer/src/lib/active-agent-note-send-explicit-target.test.ts src/renderer/src/components/browser-pane/annotate/BrowserAnnotationSendMenuContent.test.tsx", "result": "passed", "durationSeconds": 9.58, "summary": "Ten focused test files passed (1183 tests), covering runtime confirmation and PTY revalidation, guarded RPC zero-write behavior, PTY controller routing, local/daemon fresh scans, exact ConPTY membership, and unchanged renderer note routing." diff --git a/src/main/daemon/pty-subprocess/foreground-process-tracker.ts b/src/main/daemon/pty-subprocess/foreground-process-tracker.ts index 83ed57874b2..cd560be753f 100644 --- a/src/main/daemon/pty-subprocess/foreground-process-tracker.ts +++ b/src/main/daemon/pty-subprocess/foreground-process-tracker.ts @@ -150,8 +150,10 @@ export function createPtyForegroundProcessTracker(args: { } if (!processName || !recognizeAgentProcess(processName)) { if (process.platform === 'win32' && fallbackIsShell && cachedAgentForeground !== null) { - const consoleProcessIds = readWindowsConptyProcessIds(proc) - if (consoleProcessIds === null || consoleProcessIds.size > 1) { + // Job, not console: "is anything besides the shell alive?" needs no + // console attachment, so it needs no forked helper (#10857). + const paneProcessIds = readWindowsConptyProcessIds(proc) + if (paneProcessIds === null || paneProcessIds.size > 1) { return } retireStaleForegroundIdentity() diff --git a/src/main/providers/agent-foreground-process.test.ts b/src/main/providers/agent-foreground-process.test.ts index 47115fa6031..10f4863b3f4 100644 --- a/src/main/providers/agent-foreground-process.test.ts +++ b/src/main/providers/agent-foreground-process.test.ts @@ -513,6 +513,32 @@ describe('resolveAgentForegroundProcess', () => { ).resolves.toEqual({ available: true, processName: 'droid' }) }) + it('fails closed when console attachment cannot be read', async () => { + // The filter exists to DROP descendants that left the console. If it cannot + // tell which ones those are, publishing the unfiltered list would grant a + // detached process the pane's identity. #16419 briefly made this fall open + // and nothing caught it, because no test drove the null. + Object.defineProperty(process, 'platform', { value: 'win32' }) + mockWindowsRows([ + { pid: 200, ppid: 199, name: 'powershell.exe', commandLine: 'powershell.exe' }, + { pid: 201, ppid: 200, name: 'droid.exe', commandLine: 'droid' }, + { pid: 202, ppid: 200, name: 'agy.exe', commandLine: 'agy' } + ]) + + const reader = vi.fn(async () => null) + + const resolution = await resolveAgentForegroundProcessWithAvailability(200, 'powershell.exe', { + fresh: true, + readWindowsConsoleAttachedProcessIds: reader + }) + + expect(reader).toHaveBeenCalledTimes(1) + // available:false is the fail-closed signal; the wrapper then substitutes + // the shell fallback rather than publishing an unverified agent identity. + expect(resolution.available).toBe(false) + expect(resolution.processName).not.toBe('droid') + }) + it('recognizes a Windows shell-rooted agent when only one candidate matches the worktree path', async () => { Object.defineProperty(process, 'platform', { value: 'win32' }) mockWindowsRows([ diff --git a/src/main/providers/local-pty-provider.ts b/src/main/providers/local-pty-provider.ts index d6c48c0306b..68ae5411e77 100644 --- a/src/main/providers/local-pty-provider.ts +++ b/src/main/providers/local-pty-provider.ts @@ -1408,23 +1408,26 @@ export class LocalPtyProvider implements IPtyProvider { ptyShellName.get(id) ) const cachedAgent = ptyLastRecognizedForeground.get(id) ?? null - let consoleMembershipUnavailable = false - // Why: console membership preserves a live cached agent without the whole-table scan (incomplete under Windows load). + let paneMembershipUnavailable = false + // Why: job membership preserves a live cached agent without the whole-table + // scan (incomplete under Windows load). Job, not console: this asks "is + // anything besides the shell alive?", which needs no console attachment and + // so needs no forked helper (#10857). if ( process.platform === 'win32' && canConfirmAgentFromConsolePresence(cachedAgent, fallbackProcess) ) { try { - const consoleProcessIds = readWindowsConptyProcessIds(proc) + const paneProcessIds = readWindowsConptyProcessIds(proc) if (ptyProcesses.get(id) !== proc) { return null } - if (consoleProcessIds !== null && consoleProcessIds.size > 1 && cachedAgent !== null) { + if (paneProcessIds !== null && paneProcessIds.size > 1 && cachedAgent !== null) { return cachedAgent } - consoleMembershipUnavailable = consoleProcessIds === null + paneMembershipUnavailable = paneProcessIds === null } catch { - consoleMembershipUnavailable = true + paneMembershipUnavailable = true } } try { @@ -1446,7 +1449,7 @@ export class LocalPtyProvider implements IPtyProvider { : null // Why: incomplete snapshot + unavailable console probe isn't exit proof; only shell-only membership may clear the cache. const stable = resolveStableForegroundProcess( - consoleMembershipUnavailable && resolvedAgent === null + paneMembershipUnavailable && resolvedAgent === null ? { ...resolution, available: false } : resolution, lastRecognizedAgent diff --git a/src/main/providers/windows-console-attached-processes.test.ts b/src/main/providers/windows-console-attached-processes.test.ts new file mode 100644 index 00000000000..e3c9e93d240 --- /dev/null +++ b/src/main/providers/windows-console-attached-processes.test.ts @@ -0,0 +1,111 @@ +/* + * Coverage for the FORKING console-attachment reader. + * + * These assertions moved here with the code when the job-object reader took + * over the polling path (#16419). They cover the module that caused #10857 -- + * the bounded timeout, the single kill, spawn errors, malformed messages and + * helper-pid removal -- so none of it is left untested just because the file + * it used to live in now answers a different question. + */ +import { EventEmitter } from 'node:events' +import { describe, expect, it, vi } from 'vitest' +import { readWindowsConsoleAttachedProcessIds } from './windows-console-attached-processes' + +function forkWith(event: 'message' | 'error' | 'none', value?: unknown, pid?: number) { + const child = new EventEmitter() as EventEmitter & { + kill: ReturnType + pid?: number + } + child.kill = vi.fn() + if (pid !== undefined) { + child.pid = pid + } + const forkProcess = vi.fn(() => { + queueMicrotask(() => { + if (event === 'message') { + child.emit('message', { consoleProcessList: value }) + } else if (event === 'error') { + child.emit('error', new Error('spawn failed')) + } + }) + return child + }) + return { child, forkProcess: forkProcess as never } +} + +describe('readWindowsConsoleAttachedProcessIds', () => { + it('returns exact console membership from the fixed node-pty helper', async () => { + const { forkProcess } = forkWith('message', [999, 101, 202, 303], 999) + + await expect( + readWindowsConsoleAttachedProcessIds(101, { + forkProcess, + resolveAgentPath: () => '/fixed/node-pty/conpty_console_list_agent.js' + }) + ).resolves.toEqual(new Set([101, 202, 303])) + expect(forkProcess).toHaveBeenCalledWith( + '/fixed/node-pty/conpty_console_list_agent.js', + ['101'], + { silent: true } + ) + }) + + it.each([ + ['root-only failure fallback', [101], 999], + ['malformed response', [999, 101, '202'], 999], + ['missing PTY root', [999, 202, 303], 999], + ['missing helper pid', [101, 202], 999], + ['unavailable helper pid', [101, 202], undefined] + ])('fails closed for %s', async (_label, processIds, helperPid) => { + const { forkProcess } = forkWith('message', processIds, helperPid) + await expect(readWindowsConsoleAttachedProcessIds(101, { forkProcess })).resolves.toBeNull() + }) + + it('returns root-only membership when only the helper and shell are attached', async () => { + const { forkProcess } = forkWith('message', [999, 101], 999) + await expect(readWindowsConsoleAttachedProcessIds(101, { forkProcess })).resolves.toEqual( + new Set([101]) + ) + }) + + it('reports membership excluding the helper when a real child is attached', async () => { + const { forkProcess } = forkWith('message', [999, 101, 202], 999) + await expect(readWindowsConsoleAttachedProcessIds(101, { forkProcess })).resolves.toEqual( + new Set([101, 202]) + ) + }) + + it('handles helper spawn errors without an unhandled child error', async () => { + const { forkProcess } = forkWith('error') + await expect(readWindowsConsoleAttachedProcessIds(101, { forkProcess })).resolves.toBeNull() + }) + + it('kills a silent helper at the bounded timeout', async () => { + vi.useFakeTimers() + try { + const { child, forkProcess } = forkWith('none') + const result = readWindowsConsoleAttachedProcessIds(101, { forkProcess, timeoutMs: 10 }) + await vi.advanceTimersByTimeAsync(10) + await expect(result).resolves.toBeNull() + expect(child.kill).toHaveBeenCalledTimes(1) + } finally { + vi.useRealTimers() + } + }) + + it('absorbs an asynchronous kill error after timeout settlement', async () => { + vi.useFakeTimers() + try { + const { child, forkProcess } = forkWith('none') + child.kill.mockImplementation(() => { + queueMicrotask(() => child.emit('error', new Error('kill failed'))) + }) + const result = readWindowsConsoleAttachedProcessIds(101, { forkProcess, timeoutMs: 10 }) + await vi.advanceTimersByTimeAsync(10) + await expect(result).resolves.toBeNull() + expect(child.listenerCount('error')).toBe(0) + } finally { + vi.useRealTimers() + } + }) +}) diff --git a/src/main/providers/windows-console-attached-processes.ts b/src/main/providers/windows-console-attached-processes.ts index 0ab462c4a6f..8439156de9c 100644 --- a/src/main/providers/windows-console-attached-processes.ts +++ b/src/main/providers/windows-console-attached-processes.ts @@ -4,7 +4,7 @@ const CONPTY_PROCESS_LIST_TIMEOUT_MS = 3_000 type ProcessListMessage = { consoleProcessList?: unknown } -type WindowsConptyMembershipDeps = { +type WindowsConsoleAttachedProcessDeps = { forkProcess?: typeof fork resolveAgentPath?: () => string timeoutMs?: number @@ -33,7 +33,7 @@ function resolveNodePtyConsoleListAgent(): string { */ export function readWindowsConsoleAttachedProcessIds( rootPid: number, - deps: WindowsConptyMembershipDeps = {} + deps: WindowsConsoleAttachedProcessDeps = {} ): Promise | null> { if (!Number.isSafeInteger(rootPid) || rootPid <= 0) { return Promise.resolve(null) diff --git a/src/shared/child-process/__fixtures__/child-process-import-allowlist.txt b/src/shared/child-process/__fixtures__/child-process-import-allowlist.txt index d0933a1203e..4076a760b70 100644 --- a/src/shared/child-process/__fixtures__/child-process-import-allowlist.txt +++ b/src/shared/child-process/__fixtures__/child-process-import-allowlist.txt @@ -100,7 +100,7 @@ src/main/plugins/plugin-host-process.ts src/main/ports/port-scan-command-execution.ts src/main/providers/macos-login-session-pty-probe.ts src/main/providers/process-cwd.ts -src/main/providers/windows-conpty-process-membership.ts +src/main/providers/windows-console-attached-processes.ts src/main/pty-descendant-termination.ts src/main/pty/posix-pty-foreground-group.ts src/main/pty/posix-pty-process-groups.ts