diff --git a/src/main/ipc/pty-startup-swap-window-presence.test.ts b/src/main/ipc/pty-startup-swap-window-presence.test.ts index 383e9037bce..519a56eddc4 100644 --- a/src/main/ipc/pty-startup-swap-window-presence.test.ts +++ b/src/main/ipc/pty-startup-swap-window-presence.test.ts @@ -151,15 +151,18 @@ describe('registerPtyHandlers daemon-swap-window presence', () => { // authoritatively answer for a remote host's PTY, so remote-scoped ids // stay unknown, never absent. let controller: { hasPty: (ptyId: string) => boolean | null } | undefined - registerPtyHandlers(mainWindow as never, { - setPtyController: vi.fn((next) => { - controller = next - }), - registerPty: vi.fn(), - onPtySpawned: vi.fn(), - onPtyExit: vi.fn(), - onPtyData: vi.fn() - } as never) + registerPtyHandlers( + mainWindow as never, + { + setPtyController: vi.fn((next) => { + controller = next + }), + registerPty: vi.fn(), + onPtySpawned: vi.fn(), + onPtyExit: vi.fn(), + onPtyData: vi.fn() + } as never + ) expect(controller?.hasPty('remote:environment@@pty-1')).toBe(null) }) @@ -184,15 +187,18 @@ describe('registerPtyHandlers daemon-swap-window presence', () => { // no barrier; the installed provider is then the sole owner (#12393) and // its false stays an observed absence. let controller: { hasPty: (ptyId: string) => boolean | null } | undefined - registerPtyHandlers(mainWindow as never, { - setPtyController: vi.fn((next) => { - controller = next - }), - registerPty: vi.fn(), - onPtySpawned: vi.fn(), - onPtyExit: vi.fn(), - onPtyData: vi.fn() - } as never) + registerPtyHandlers( + mainWindow as never, + { + setPtyController: vi.fn((next) => { + controller = next + }), + registerPty: vi.fn(), + onPtySpawned: vi.fn(), + onPtyExit: vi.fn(), + onPtyData: vi.fn() + } as never + ) expect(controller?.hasPty('never-spawned-pty')).toBe(false) await expect(handlers.get('pty:hasPty')!(null, { id: 'never-spawned-pty' })).resolves.toBe( diff --git a/src/main/ipc/pty/runtime/operations.ts b/src/main/ipc/pty/runtime/operations.ts index d28bcc702c6..bb8032f9cfb 100644 --- a/src/main/ipc/pty/runtime/operations.ts +++ b/src/main/ipc/pty/runtime/operations.ts @@ -153,6 +153,7 @@ export async function clearBufferFromRuntimeController( } const settledLocalPtyProviderStartups = new WeakSet>() +const watchedLocalPtyProviderStartups = new WeakSet>() export function hasPtyFromRuntimeController( deps: PtyRuntimeControllerDeps, @@ -171,10 +172,13 @@ export function hasPtyFromRuntimeController( // probePtyLiveness does, and the pre-swap provider's "no PTY" for a // daemon-restored id is fabricated — answer unverifiable until the swap // settles (docs/reference/ssh-execution-boundary.md rule 2). - startupPromise.then( - () => settledLocalPtyProviderStartups.add(startupPromise), - () => settledLocalPtyProviderStartups.add(startupPromise) - ) + if (!watchedLocalPtyProviderStartups.has(startupPromise)) { + watchedLocalPtyProviderStartups.add(startupPromise) + const markSettled = (): void => { + settledLocalPtyProviderStartups.add(startupPromise) + } + startupPromise.then(markSettled, markSettled) + } return null } return getProviderForPty(ptyId).hasPty?.(ptyId) ?? null