diff options
| author | Luke Parker <[email protected]> | 2026-04-03 13:18:50 +1000 |
|---|---|---|
| committer | GitHub <[email protected]> | 2026-04-03 13:18:50 +1000 |
| commit | 7b8dc8065e63b3bfee9dd56dad5548f1706b5acc (patch) | |
| tree | 5d5f0aa4337471c089c3d70e012841cd57bbf50e /packages/sdk/js/src/v2 | |
| parent | e89527c9f0eba6c7aa866f3ba39ce9f6809023a7 (diff) | |
| download | opencode-7b8dc8065e63b3bfee9dd56dad5548f1706b5acc.tar.gz opencode-7b8dc8065e63b3bfee9dd56dad5548f1706b5acc.zip | |
fix(sdk): handle Windows opencode spawn and shutdown (#20772)
Diffstat (limited to 'packages/sdk/js/src/v2')
| -rw-r--r-- | packages/sdk/js/src/v2/server.ts | 39 |
1 files changed, 25 insertions, 14 deletions
diff --git a/packages/sdk/js/src/v2/server.ts b/packages/sdk/js/src/v2/server.ts index 174131ccf..48f1a253d 100644 --- a/packages/sdk/js/src/v2/server.ts +++ b/packages/sdk/js/src/v2/server.ts @@ -1,5 +1,6 @@ -import { spawn } from "node:child_process" +import launch from "cross-spawn" import { type Config } from "./gen/types.gen.js" +import { stop, bindAbort } from "../process.js" export type ServerOptions = { hostname?: string @@ -31,29 +32,38 @@ export async function createOpencodeServer(options?: ServerOptions) { const args = [`serve`, `--hostname=${options.hostname}`, `--port=${options.port}`] if (options.config?.logLevel) args.push(`--log-level=${options.config.logLevel}`) - const proc = spawn(`opencode`, args, { - signal: options.signal, + const proc = launch(`opencode`, args, { env: { ...process.env, OPENCODE_CONFIG_CONTENT: JSON.stringify(options.config ?? {}), }, }) + let clear = () => {} const url = await new Promise<string>((resolve, reject) => { const id = setTimeout(() => { + clear() + stop(proc) reject(new Error(`Timeout waiting for server to start after ${options.timeout}ms`)) }, options.timeout) let output = "" + let resolved = false proc.stdout?.on("data", (chunk) => { + if (resolved) return output += chunk.toString() const lines = output.split("\n") for (const line of lines) { if (line.startsWith("opencode server listening")) { const match = line.match(/on\s+(https?:\/\/[^\s]+)/) if (!match) { - throw new Error(`Failed to parse server url from output: ${line}`) + clear() + stop(proc) + clearTimeout(id) + reject(new Error(`Failed to parse server url from output: ${line}`)) + return } clearTimeout(id) + resolved = true resolve(match[1]!) return } @@ -74,18 +84,17 @@ export async function createOpencodeServer(options?: ServerOptions) { clearTimeout(id) reject(error) }) - if (options.signal) { - options.signal.addEventListener("abort", () => { - clearTimeout(id) - reject(new Error("Aborted")) - }) - } + clear = bindAbort(proc, options.signal, () => { + clearTimeout(id) + reject(options.signal?.reason) + }) }) return { url, close() { - proc.kill() + clear() + stop(proc) }, } } @@ -106,8 +115,7 @@ export function createOpencodeTui(options?: TuiOptions) { args.push(`--agent=${options.agent}`) } - const proc = spawn(`opencode`, args, { - signal: options?.signal, + const proc = launch(`opencode`, args, { stdio: "inherit", env: { ...process.env, @@ -115,9 +123,12 @@ export function createOpencodeTui(options?: TuiOptions) { }, }) + const clear = bindAbort(proc, options?.signal) + return { close() { - proc.kill() + clear() + stop(proc) }, } } |
