import { spawn, type ChildProcess } from "node:child_process"; import { setTimeout as delay } from "node:timers/promises"; const children: ChildProcess[] = []; function run(command: string, args: string[]) { const child = spawn(command, args, { stdio: "inherit", shell: false, env: { ...process.env, PORT: process.env.PORT ?? "43210", BOSS_DATA_FILE: process.env.BOSS_DATA_FILE ?? ".boss-data/demo-store.json", }, }); child.on("exit", (code, signal) => { console.log(`[demo] child exited`, { code, signal, command, args: args.join(" ") }); if (code && code !== 0 && signal !== "SIGINT" && signal !== "SIGTERM") { shutdown("SIGTERM"); } }); children.push(child); return child; } async function waitForHealth(url: string) { for (let attempt = 0; attempt < 30; attempt += 1) { try { const response = await fetch(`${url}/api/health`); if (response.ok) { return; } } catch { // wait and retry } await delay(1_000); } throw new Error(`Server did not become healthy: ${url}`); } async function isHealthy(url: string) { try { const response = await fetch(`${url}/api/health`); if (!response.ok) { return false; } const payload = await response.json(); return payload?.status === "ok"; } catch { return false; } } function shutdown(signal: NodeJS.Signals) { for (const child of children) { if (!child.killed) { child.kill(signal); } } process.exit(0); } async function main() { const serverUrl = `http://127.0.0.1:${process.env.PORT ?? "43210"}`; const hasExisting = await isHealthy(serverUrl); if (!hasExisting) { run(process.execPath, ["./node_modules/tsx/dist/cli.mjs", "src/server.ts"]); await waitForHealth(serverUrl); } else { console.log(`Boss server already running at ${serverUrl}, reusing it.`); } run(process.execPath, [ "./node_modules/tsx/dist/cli.mjs", "src/worker.ts", "--name", "win-a", "--os", "windows", "--capability", "terminal", "--capability", "browser", "--server", serverUrl, ]); run(process.execPath, [ "./node_modules/tsx/dist/cli.mjs", "src/worker.ts", "--name", "win-b", "--os", "windows", "--capability", "terminal", "--capability", "test", "--server", serverUrl, ]); run(process.execPath, [ "./node_modules/tsx/dist/cli.mjs", "src/worker.ts", "--name", "mac-a", "--os", "macos", "--capability", "terminal", "--capability", "browser", "--capability", "test", "--server", serverUrl, ]); console.log(`Boss demo running at ${serverUrl}`); console.log("Press Ctrl+C to stop server and workers."); await new Promise(() => {}); } process.on("SIGINT", () => shutdown("SIGINT")); process.on("SIGTERM", () => shutdown("SIGTERM")); main().catch((error) => { console.error(error); shutdown("SIGTERM"); });