const { spawn } = require("child_process"); const net = require("net"); const path = require("path"); function waitForPort(host, port, timeoutMs = 30_000) { const start = Date.now(); return new Promise((resolve, reject) => { const tick = () => { const socket = net.createConnection({ host, port }); const timer = setTimeout(() => { socket.destroy(); if (Date.now() - start > timeoutMs) { reject(new Error(`等待端口超时:${host}:${port}`)); return; } setTimeout(tick, 200); }, 500); socket.once("connect", () => { clearTimeout(timer); socket.end(); resolve(); }); socket.once("error", () => { clearTimeout(timer); if (Date.now() - start > timeoutMs) { reject(new Error(`等待端口超时:${host}:${port}`)); return; } setTimeout(tick, 200); }); }; tick(); }); } function spawnTask(name, command, cwd, extraEnv) { console.log(`[${name}] ${command}`); const child = spawn(command, { cwd, stdio: "inherit", shell: true, env: { ...process.env, ...extraEnv }, }); return child; } async function main() { const rootDir = process.cwd(); const frontendDir = path.join(rootDir, "wolai-frontend"); const frontendPort = Number(process.env.FRONTEND_PORT || 3000); const frontend = spawnTask( "frontend", `pnpm -C wolai-frontend dev -p ${frontendPort}`, rootDir, {}, ); await waitForPort("127.0.0.1", frontendPort); const electron = spawnTask( "electron", "electron desktop-electron/main.js", rootDir, { MNOTE_LOAD_URL: `http://127.0.0.1:${frontendPort}` }, ); const shutdown = () => { try { if (!electron.killed) electron.kill("SIGINT"); } catch {} try { if (!frontend.killed) frontend.kill("SIGINT"); } catch {} }; process.on("SIGINT", shutdown); process.on("SIGTERM", shutdown); electron.on("exit", () => shutdown()); frontend.on("exit", () => shutdown()); } main().catch((err) => { console.error(err instanceof Error ? err.stack : String(err)); process.exit(1); });