refactor(agent-hooks): launch the WSL hook relay through the process host (#34051)

Build the wsl.exe argv with buildWslExecArgs and start it with spawnProcess
from @orca/process-host instead of a hand-built node:child_process spawn.
This commit is contained in:
Neil
2026-10-26 13:17:06 -07:00
committed by GitHub
parent 9ae33a96f9
commit b7ad8be42e
2 changed files with 24 additions and 15 deletions
@@ -1,18 +1,21 @@
import { describe, expect, it, vi } from 'vitest'
import { execFileSync } from 'node:child_process'
import type * as ChildProcess from 'node:child_process'
import type * as ProcessHost from '@orca/process-host'
import { chmodSync, mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs'
import { tmpdir } from 'node:os'
import { join } from 'node:path'
import { resetWslInteropSpawnDirectoryCache } from '../wsl-interop-spawn-directory'
const { spawnMock } = vi.hoisted(() => ({
spawnMock: vi.fn((..._args: unknown[]) => ({ pid: 1 }))
const { spawnProcessMock } = vi.hoisted(() => ({
spawnProcessMock: vi.fn((..._args: unknown[]) => ({ pid: 1 }))
}))
vi.mock('node:child_process', async (importOriginal) => ({
...(await importOriginal<typeof ChildProcess>()),
spawn: spawnMock
vi.mock('@orca/process-host', async (importOriginal) => ({
...(await importOriginal<typeof ProcessHost>()),
spawnProcess: spawnProcessMock
}))
vi.mock('../wsl/wsl-executable-path', () => ({
resolveWslExecutablePath: () => 'C:\\Windows\\System32\\wsl.exe'
}))
import {
@@ -31,9 +34,9 @@ describe('spawnWslRelayProcess', () => {
try {
spawnWslRelayProcess('Ubuntu', env, '1.2.3')
expect(spawnMock).toHaveBeenCalledExactlyOnceWith(
'wsl.exe',
[
expect(spawnProcessMock).toHaveBeenCalledExactlyOnceWith({
program: 'C:\\Windows\\System32\\wsl.exe',
args: [
'-d',
'Ubuntu',
'--exec',
@@ -41,8 +44,10 @@ describe('spawnWslRelayProcess', () => {
'-c',
'exec sh "$HOME/.orca-wsl/hook-relay/1.2.3/launch.sh"'
],
{ env, stdio: ['pipe', 'pipe', 'pipe'], windowsHide: true, cwd: systemRoot }
)
env,
stdio: 'pipe',
cwd: systemRoot
})
} finally {
vi.unstubAllEnvs()
resetWslInteropSpawnDirectoryCache()
@@ -1,6 +1,7 @@
import { spawn, type ChildProcessWithoutNullStreams } from 'node:child_process'
import type { ChildProcessWithoutNullStreams } from 'node:child_process'
import { existsSync, readFileSync } from 'node:fs'
import { join } from 'node:path'
import { spawnProcess } from '@orca/process-host'
import { relayBundleCandidates } from '../ssh/relay-bundle-paths'
import { withWslGuestLauncherRevision } from '../wsl/wsl-guest-launcher-revision'
import { orcadPosixNodeRuntimeGlobs } from '../managed-server/install/orcad-node-runtime-globs'
@@ -13,6 +14,8 @@ import {
} from './wsl-hook-relay-sentinel'
import { addOrcaWslInteropEnv } from '../pty/wsl-orca-env'
import { runWslProcess } from '../wsl/wsl-runner'
import { resolveWslExecutablePath } from '../wsl/wsl-executable-path'
import { buildWslExecArgs } from '../../shared/wsl-login-shell-command'
import { resolveWslInteropSpawnCwd } from '../wsl-interop-spawn-directory'
import {
WSL_HOOK_RELAY_BUNDLE_NAME,
@@ -102,10 +105,11 @@ export function spawnWslRelayProcess(
): ChildProcessWithoutNullStreams {
// --exec bypasses login-shell rewriting and passes $HOME verbatim for guest-side expansion.
const command = `exec sh "${guestRelayDirExpr(version)}/launch.sh"`
return spawn('wsl.exe', ['-d', distro, '--exec', 'sh', '-c', command], {
return spawnProcess({
program: resolveWslExecutablePath(),
args: buildWslExecArgs(distro, ['sh', '-c', command]),
env,
stdio: ['pipe', 'pipe', 'pipe'],
windowsHide: true,
stdio: 'pipe',
// Use a stable Windows cwd so deleting the current worktree cannot break later relay launches.
cwd: resolveWslInteropSpawnCwd()
})