Skip to content

spawnProcess

The spawnProcess action spawns a long-lived subprocess on the host IDE and returns a ProcessHandle for bidirectional communication over stdin/stdout. This enables web apps to interact with CLI tools (such as ACP-compatible agents) that communicate over stdio streams.

import { spawnProcess } from '@unextension/bridge'

Spawns a subprocess and returns a handle for interacting with it.

const proc = await spawnProcess('node', ['agent.js', '--stdio'])
console.log(proc.pid) // OS process ID
ParameterTypeDescription
commandstringThe command to execute
argsstring[]Arguments to pass to the command (default: [])
optionsSpawnProcessOptionsOptional spawn configuration
OptionTypeDescription
cwdstringWorking directory for the subprocess
envRecord<string, string>Environment variables to merge with the system environment

Promise<ProcessHandle>

The returned ProcessHandle provides methods and properties for interacting with the spawned subprocess.


Property/MethodTypeDescription
processIdstringUnique identifier for this process
pidnumberOperating system process ID
stdoutReadableStream<string>Stream of stdout output chunks
stderrReadableStream<string>Stream of stderr output chunks
exitCodePromise<number>Resolves with the exit code when process exits
send(data)(data: string) => voidWrite data to the subprocess stdin
kill(signal?)(signal?: string) => voidTerminate the subprocess with an optional signal

import { spawnProcess } from '@unextension/bridge'
const proc = await spawnProcess('echo', ['hello world'])
const reader = proc.stdout.getReader()
const { value } = await reader.read()
console.log(value) // 'hello world\n'
const code = await proc.exitCode
console.log('Exited with:', code) // 0
import { spawnProcess } from '@unextension/bridge'
const proc = await spawnProcess('cat')
proc.send('first line\n')
proc.send('second line\n')
const reader = proc.stdout.getReader()
const chunk1 = await reader.read()
console.log(chunk1.value) // 'first line\n'
proc.kill()
import { spawnProcess } from '@unextension/bridge'
const proc = await spawnProcess('node', ['long-running-script.js'], {
cwd: '/path/to/project',
env: { NODE_ENV: 'production' },
})
// Wait for the process to finish
const code = await proc.exitCode
if (code === 0) {
console.log('Process completed successfully')
} else {
console.log('Process failed with code:', code)
}
import { spawnProcess } from '@unextension/bridge'
const proc = await spawnProcess('node', ['-e', 'console.error("warning")'])
const reader = proc.stderr.getReader()
const { value } = await reader.read()
console.log('stderr:', value) // 'warning\n'

spawnProcess rejects the returned promise if the command cannot be found or the process fails to start.

ScenarioResult
Command spawns successfullyResolves with ProcessHandle
Command not foundPromise rejects with descriptive error
Process exits normallyexitCode resolves with exit code
Process crashesexitCode resolves with code 1, streams close
Kill calledProcess terminates, exit event delivered
try {
const proc = await spawnProcess('nonexistent-binary')
} catch (err) {
console.error('Failed to spawn:', err.message)
}

All types are exported from @unextension/bridge:

import type { SpawnProcessOptions, ProcessHandle } from '@unextension/bridge'
interface SpawnProcessOptions {
cwd?: string
env?: Record<string, string>
}
interface ProcessHandle {
readonly processId: string
readonly pid: number
readonly stdout: ReadableStream<string>
readonly stderr: ReadableStream<string>
readonly exitCode: Promise<number>
send(data: string): void
kill(signal?: string): void
}