import { releaseLock } from "./lock"; import { logUtil } from "./logger"; /** * Daemonize the current process: spawns a detached child and exits the parent. * * When __IS_DAEMON is already set this is a no-op (the child continues). * Otherwise the parent releases its lock, spawns the child via Bun.spawn, * unrefs it so the child outlives the parent, and exits once the child * process is confirmed running (polls PID existence, 1s max). */ export function daemonize(): void { if (process.env["__IS_DAEMON"]) return; // child — keep running releaseLock(); const child = Bun.spawn({ cmd: [process.execPath, ...process.argv.slice(1)], stdout: "ignore", stderr: "ignore", stdin: "ignore", env: { ...process.env, __IS_DAEMON: "1" }, cwd: process.cwd(), }); child.unref(); logUtil.log(`Backgrounded with PID ${child.pid}`); // Poll until the child process actually exists, then exit the parent. // Falls back to a hard exit after 1 second in case the child fails to start. const start = Date.now(); const poll = setInterval(() => { try { process.kill(child.pid, 0); // signal 0 = existence check only clearInterval(poll); process.exit(0); } catch { if (Date.now() - start > 1000) { clearInterval(poll); process.exit(0); } } }, 50); }