()
| 525 | // ─── Startup ───────────────────────────────────────────────────── |
| 526 | |
| 527 | export function start(): { port: number } { |
| 528 | const portArg = process.env.DESIGN_DAEMON_PORT; |
| 529 | const port = portArg ? parseInt(portArg, 10) : 0; |
| 530 | serverRef = Bun.serve({ |
| 531 | port, |
| 532 | hostname: "127.0.0.1", |
| 533 | fetch: fetchHandler, |
| 534 | }); |
| 535 | const actualPort = serverRef.port; |
| 536 | const state: DaemonState = { |
| 537 | pid: process.pid, |
| 538 | port: actualPort, |
| 539 | startedAt: new Date().toISOString(), |
| 540 | version: VERSION, |
| 541 | serverPath: process.argv[1] || "", |
| 542 | cmdlineMarker: CMDLINE_MARKER, |
| 543 | }; |
| 544 | writeStateFile(state); |
| 545 | dlog(`DAEMON_STARTED port=${actualPort} pid=${process.pid} version=${VERSION}`); |
| 546 | // Stdout line the spawning CLI parses to learn the port quickly. |
| 547 | console.log(`DAEMON_STARTED port=${actualPort}`); |
| 548 | |
| 549 | idleInterval = setInterval(idleCheckTick, IDLE_CHECK_INTERVAL_MS); |
| 550 | |
| 551 | process.on("SIGTERM", () => { |
| 552 | void gracefulShutdown(0); |
| 553 | }); |
| 554 | process.on("SIGINT", () => { |
| 555 | void gracefulShutdown(0); |
| 556 | }); |
| 557 | process.on("uncaughtException", (e) => { |
| 558 | dlog(`uncaughtException: ${(e as Error).stack || (e as Error).message}`); |
| 559 | void gracefulShutdown(1); |
| 560 | }); |
| 561 | |
| 562 | return { port: actualPort }; |
| 563 | } |
| 564 | |
| 565 | if (import.meta.main) { |
| 566 | start(); |
no test coverage detected