Skip to content

Commit d923387

Browse files
committed
add createOpencodeServer to js sdk and wait for readiness. always use random port for opencode serve. add /client and /server imports for js sdk
1 parent aa4dba1 commit d923387

3 files changed

Lines changed: 57 additions & 6 deletions

File tree

packages/opencode/src/cli/cmd/serve.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ export const ServeCommand = cmd({
1111
alias: ["p"],
1212
type: "number",
1313
describe: "port to listen on",
14-
default: 4096,
14+
default: 0,
1515
})
1616
.option("hostname", {
1717
alias: ["h"],

packages/sdk/js/src/server.ts

Lines changed: 51 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,68 @@
11
import { spawn } from "node:child_process"
22

33
export type ServerConfig = {
4-
host?: string
4+
hostname?: string
55
port?: number
6+
signal?: AbortSignal
7+
timeout?: number
68
}
79

810
export async function createOpencodeServer(config?: ServerConfig) {
911
config = Object.assign(
1012
{
11-
host: "127.0.0.1",
13+
hostname: "127.0.0.1",
1214
port: 4096,
15+
timeout: 5000,
1316
},
1417
config ?? {},
1518
)
1619

17-
const proc = spawn(`opencode`, [`serve`, `--host=${config.host}`, `--port=${config.port}`])
18-
const url = `http://${config.host}:${config.port}`
20+
const proc = spawn(`opencode`, [`servel`, `--hostname=${config.hostname}`, `--port=${config.port}`], {
21+
signal: config.signal,
22+
})
23+
24+
const url = await new Promise<string>((resolve, reject) => {
25+
const id = setTimeout(() => {
26+
reject(new Error(`Timeout waiting for server to start after ${config.timeout}ms`))
27+
}, config.timeout)
28+
let output = ""
29+
proc.stdout?.on("data", (chunk) => {
30+
output += chunk.toString()
31+
const lines = output.split("\n")
32+
for (const line of lines) {
33+
if (line.startsWith("opencode server listening")) {
34+
const match = line.match(/on\s+(https?:\/\/[^\s]+)/)
35+
if (!match) {
36+
throw new Error(`Failed to parse server url from output: ${line}`)
37+
}
38+
clearTimeout(id)
39+
resolve(match[1])
40+
return
41+
}
42+
}
43+
})
44+
proc.stderr?.on("data", (chunk) => {
45+
output += chunk.toString()
46+
})
47+
proc.on("exit", (code) => {
48+
clearTimeout(id)
49+
let msg = `Server exited with code ${code}`
50+
if (output.trim()) {
51+
msg += `\nServer output: ${output}`
52+
}
53+
reject(new Error(msg))
54+
})
55+
proc.on("error", (error) => {
56+
clearTimeout(id)
57+
reject(error)
58+
})
59+
if (config.signal) {
60+
config.signal.addEventListener("abort", () => {
61+
clearTimeout(id)
62+
reject(new Error("Aborted"))
63+
})
64+
}
65+
})
1966

2067
return {
2168
url,

tsconfig.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
{
22
"$schema": "https://json.schemastore.org/tsconfig",
33
"extends": "@tsconfig/bun/tsconfig.json",
4-
"compilerOptions": {}
4+
"compilerOptions": {
5+
"customConditions": [
6+
"development"
7+
],
8+
}
59
}

0 commit comments

Comments
 (0)