#!/usr/bin/env node /** * Dev runner: starts the CLI content server (port 3000) and the rsbuild web * dev server (port 5173) together, then tears both down when either exits. * * npm run dev # both (this script) * npm run dev:cli # CLI content server only * npm run dev:web # web dev server only */ import { spawn } from "node:child_process"; const isWindows = process.platform === "win32"; const children = new Set(); let shuttingDown = false; /** Terminate a child and everything it spawned. */ function killTree(child) { if (child.exitCode !== null || child.signalCode !== null) return; if (isWindows) { spawn("taskkill", ["/pid", String(child.pid), "/T", "/F"], { stdio: "ignore", }); } else { try { // Negative pid targets the process group created via `detached`. process.kill(-child.pid, "SIGTERM"); } catch { child.kill("SIGTERM"); } } } function shutdown(code) { if (shuttingDown) return; shuttingDown = true; for (const child of children) killTree(child); process.exitCode = code ?? 0; } for (const script of ["dev:cli", "dev:web"]) { const child = spawn("npm", ["run", script], { stdio: "inherit", shell: true, detached: !isWindows, }); children.add(child); child.on("exit", (code) => shutdown(code ?? 0)); child.on("error", (error) => { console.error(`[dev] Failed to start ${script}: ${error.message}`); shutdown(1); }); } process.on("SIGINT", () => shutdown(0)); process.on("SIGTERM", () => shutdown(0));