diff --git a/src/main/agent-hooks/managed-hook-local-filesystem.test.ts b/src/main/agent-hooks/managed-hook-local-filesystem.test.ts index 91a1ca62eb6..f6dcf14471a 100644 --- a/src/main/agent-hooks/managed-hook-local-filesystem.test.ts +++ b/src/main/agent-hooks/managed-hook-local-filesystem.test.ts @@ -6,9 +6,11 @@ import { installRemoteManagedAgentHooks } from './remote-managed-hook-installers import { createManagedHookLocalFilesystem } from './managed-hook-local-filesystem' const tempHomes: string[] = [] +const tempRoot = process.platform === 'win32' ? tmpdir() : '/tmp' async function createTempHome(): Promise { - const home = await mkdtemp(join(tmpdir(), 'orca-managed-hooks-')) + // Why: mkdir-p probes ancestors; macOS's per-user temp directory can contain hundreds of thousands of entries. + const home = await mkdtemp(join(tempRoot, 'orca-managed-hooks-')) tempHomes.push(home) return home } diff --git a/src/main/agent-hooks/wsl-hook-relay-live.integration.test.ts b/src/main/agent-hooks/wsl-hook-relay-live.integration.test.ts index a7c25f02cc2..ab6d6a03e45 100644 --- a/src/main/agent-hooks/wsl-hook-relay-live.integration.test.ts +++ b/src/main/agent-hooks/wsl-hook-relay-live.integration.test.ts @@ -7,7 +7,6 @@ // exercises minus the wsl.exe byte transport (validated separately on-rig). import { execFileSync, spawn, type ChildProcessWithoutNullStreams } from 'node:child_process' import { existsSync, mkdtempSync, readFileSync, rmSync } from 'node:fs' -import { tmpdir } from 'node:os' import { join } from 'node:path' import { createServer } from 'node:net' import { afterEach, beforeAll, describe, expect, it, vi } from 'vitest' @@ -59,7 +58,7 @@ describe.skipIf(process.platform === 'win32')( }) it('delivers a Claude hook POST from the live relay into ingestRemote and installs guest hooks', async () => { - fakeHome = mkdtempSync(join(tmpdir(), 'wsl-live-home-')) + fakeHome = mkdtempSync(join('/tmp', 'wsl-live-home-')) const preferredPort = await pickFreePort() const version = readFileSync(join(BUNDLE_DIR, '.version'), 'utf8').trim() diff --git a/src/main/agent-hooks/wsl-hook-relay-manager.test.ts b/src/main/agent-hooks/wsl-hook-relay-manager.test.ts index 60bb3cbb2f9..39a9736a526 100644 --- a/src/main/agent-hooks/wsl-hook-relay-manager.test.ts +++ b/src/main/agent-hooks/wsl-hook-relay-manager.test.ts @@ -3,7 +3,6 @@ // the per-distro relay manager state machine with fault injection. import { EventEmitter } from 'node:events' import { existsSync, mkdtempSync, readFileSync, rmSync } from 'node:fs' -import { tmpdir } from 'node:os' import { join } from 'node:path' import type { ChildProcessWithoutNullStreams } from 'node:child_process' import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' @@ -34,9 +33,13 @@ function createGuestHarness(): GuestHarness { const clientDataCallbacks: ((data: Buffer) => void)[] = [] const closeCallbacks: (() => void)[] = [] const transport: MultiplexerTransport = { - write: (data) => { - setImmediate(() => relayFeed?.(data)) + write: (data, onSettled) => { + setImmediate(() => { + relayFeed?.(data) + onSettled?.({ ok: true }) + }) }, + supportsWriteSettlement: true, onData: (cb) => { clientDataCallbacks.push(cb) }, @@ -44,21 +47,24 @@ function createGuestHarness(): GuestHarness { closeCallbacks.push(cb) } } - const guestDispatcher = new RelayDispatcher((data: Buffer) => { - setImmediate(() => { - for (const cb of clientDataCallbacks) { - cb(data) - } - }) - }) + const guestDispatcher = new RelayDispatcher( + (data: Buffer, onSettled) => { + setImmediate(() => { + for (const cb of clientDataCallbacks) { + cb(data) + } + onSettled({ ok: true }) + }) + }, + { supportsWriteCallback: true } + ) relayFeed = (data) => guestDispatcher.feed(data) const mux = new SshChannelMultiplexer(transport) return { transport, guestDispatcher, mux } } -// Why skipIf: the fs bridge runs inside the Linux guest and is POSIX-only by -// design (posix.resolve). On a Windows dev host tmpdir() yields C:\ paths the -// bridge correctly refuses; Windows coverage comes from the live rig runs. +// Why skipIf: the fs bridge runs inside the Linux guest and is POSIX-only; +// Windows coverage comes from the live rig runs. describe.skipIf(process.platform === 'win32')( 'createWslHookSftpAdapter over the guest fs bridge', () => { @@ -66,7 +72,7 @@ describe.skipIf(process.platform === 'win32')( let harness: GuestHarness beforeEach(() => { - home = mkdtempSync(join(tmpdir(), 'wsl-guest-home-')) + home = mkdtempSync(join('/tmp', 'wsl-guest-home-')) harness = createGuestHarness() registerWslHookFsHandlers(harness.guestDispatcher, home) }) diff --git a/src/main/ssh/ssh-relay-session-managed-hooks.test.ts b/src/main/ssh/ssh-relay-session-managed-hooks.test.ts index f225b113436..95492aa3a3a 100644 --- a/src/main/ssh/ssh-relay-session-managed-hooks.test.ts +++ b/src/main/ssh/ssh-relay-session-managed-hooks.test.ts @@ -7,15 +7,24 @@ import { SshRelaySession } from './ssh-relay-session' import type { SshConnection } from './ssh-connection' import { createMockDeps, mockDeploySuccess } from './ssh-relay-session-test-fixtures' -const { muxRequestMock } = vi.hoisted(() => ({ muxRequestMock: vi.fn() })) +const { muxRequestMock, openConsumerSessionMock } = vi.hoisted(() => ({ + muxRequestMock: vi.fn(), + openConsumerSessionMock: vi.fn() +})) vi.mock('./ssh-relay-deploy', () => ({ deployAndLaunchRelay: vi.fn() })) vi.mock('./ssh-relay-deploy-helpers', () => ({ execCommand: vi.fn().mockResolvedValue('') })) +vi.mock('./ssh-pty-consumer-session', () => ({ + SSH_PTY_SOURCE_WINDOW_SU: 256 * 1024, + openSshPtyConsumerSession: openConsumerSessionMock +})) vi.mock('./ssh-channel-multiplexer', () => ({ SshChannelMultiplexer: class MockSshChannelMultiplexer { notify = vi.fn() + notifyWithSettlement = vi.fn() request = muxRequestMock onNotification = vi.fn().mockReturnValue(() => {}) + onNotificationByMethod = vi.fn().mockReturnValue(() => {}) onRequest = vi.fn().mockReturnValue(() => {}) onDispose = vi.fn().mockReturnValue(() => {}) dispose = vi.fn() @@ -68,6 +77,11 @@ describe('SshRelaySession managed hooks', () => { beforeEach(() => { vi.clearAllMocks() process.env.ORCA_FEATURE_REMOTE_AGENT_HOOKS = '1' + openConsumerSessionMock.mockImplementation(async (_mux, options) => ({ + mode: 'legacy-fallback', + clientInstanceId: options.clientInstanceId, + serverBuildId: 'test-relay-build' + })) mockDeploySuccess() })