MCPcopy Create free account
hub / github.com/cortexkit/magic-context / spawnOpencode

Function spawnOpencode

packages/e2e-tests/src/opencode-runner/spawn.ts:220–307  ·  view source on GitHub ↗
(opts: SpawnOptions)

Source from the content-addressed store, hash-verified

218}
219
220export async function spawnOpencode(opts: SpawnOptions): Promise<SpawnedOpencode> {
221 const env = createIsolatedEnv();
222 const port = opts.port ?? (await pickFreePort());
223
224 writeConfigs(env, opts.mockProviderURL, opts);
225
226 // Explicitly strip any inherited OPENCODE_SERVER_PASSWORD from the parent shell —
227 // our tests run unsecured on a random localhost port, and inherited auth would
228 // force every SDK request to carry Basic auth headers we don't set.
229 // Also strip NODE_ENV=test: Bun's test runner sets it automatically and the
230 // plugin's logger (src/shared/logger.ts) silences all output when NODE_ENV=test.
231 // We want the subprocess to behave like a real install, so the log file gets
232 // populated normally for diagnostics.
233 const childEnv: Record<string, string> = {};
234 for (const [key, value] of Object.entries(process.env)) {
235 if (value === undefined) continue;
236 if (key === "OPENCODE_SERVER_PASSWORD") continue;
237 if (key === "OPENCODE_SERVER_USERNAME") continue;
238 if (key === "NODE_ENV") continue;
239 childEnv[key] = value;
240 }
241 childEnv.OPENCODE_CONFIG_DIR = env.configDir;
242 childEnv.XDG_CONFIG_HOME = env.configDir;
243 childEnv.XDG_DATA_HOME = env.dataDir;
244 childEnv.XDG_CACHE_HOME = env.cacheDir;
245 // Ensure anthropic doesn't bail for missing env vars — we use a fake key.
246 childEnv.ANTHROPIC_API_KEY = "test-key-not-real";
247
248 // Bind to 0.0.0.0 (all interfaces) instead of 127.0.0.1 — empirically on
249 // GitHub-hosted runners, opencode binding to 127.0.0.1 sometimes results
250 // in Bun's `fetch()` timing out even though `curl` succeeds. Binding all
251 // interfaces removes any loopback-specific stack-resolution edge case
252 // (IPv4-only AF_INET vs IPv4-mapped IPv6, AF_UNSPEC name resolution, etc.).
253 // Clients still connect to `127.0.0.1:${port}` — only the listen socket
254 // changes. Safe locally too: process is short-lived, port is random.
255 const child: ChildProcess = spawn(
256 "opencode",
257 ["serve", "--port", String(port), "--hostname", "0.0.0.0"],
258 {
259 cwd: env.workdir,
260 env: childEnv,
261 stdio: ["ignore", "pipe", "pipe"],
262 },
263 );
264
265 let stdoutBuf = "";
266 let stderrBuf = "";
267 child.stdout?.on("data", (chunk: Buffer) => {
268 stdoutBuf += chunk.toString();
269 });
270 child.stderr?.on("data", (chunk: Buffer) => {
271 stderrBuf += chunk.toString();
272 });
273
274 const url = `http://127.0.0.1:${port}`;
275 try {
276 await waitForReady(url);
277 } catch (err) {

Callers 1

createMethod · 0.90

Calls 4

createIsolatedEnvFunction · 0.85
pickFreePortFunction · 0.85
waitForReadyFunction · 0.85
writeConfigsFunction · 0.70

Tested by

no test coverage detected