This commit is contained in:
Chris Tate
2026-01-11 10:08:08 -06:00
parent ee4eacff27
commit 3bd331b97f
2 changed files with 70 additions and 11 deletions
+51 -11
View File
@@ -172,20 +172,60 @@ pub fn ensure_daemon(session: &str, headed: bool) -> Result<(), String> {
.find(|p| p.exists()) .find(|p| p.exists())
.ok_or("Daemon not found. Run from project directory or ensure daemon.js is alongside binary.")?; .ok_or("Daemon not found. Run from project directory or ensure daemon.js is alongside binary.")?;
let mut cmd = Command::new("node"); // Spawn daemon as a fully detached background process
cmd.arg(daemon_path) #[cfg(unix)]
.env("AGENT_BROWSER_DAEMON", "1") {
.env("AGENT_BROWSER_SESSION", session); use std::os::unix::process::CommandExt;
if headed { let mut cmd = Command::new("node");
cmd.env("AGENT_BROWSER_HEADED", "1"); cmd.arg(daemon_path)
.env("AGENT_BROWSER_DAEMON", "1")
.env("AGENT_BROWSER_SESSION", session);
if headed {
cmd.env("AGENT_BROWSER_HEADED", "1");
}
// Create new process group and session to fully detach
unsafe {
cmd.pre_exec(|| {
// Create new session (detach from terminal)
libc::setsid();
Ok(())
});
}
cmd.stdin(Stdio::null())
.stdout(Stdio::null())
.stderr(Stdio::null())
.spawn()
.map_err(|e| format!("Failed to start daemon: {}", e))?;
} }
cmd.stdin(Stdio::null()) #[cfg(windows)]
.stdout(Stdio::null()) {
.stderr(Stdio::null()) use std::os::windows::process::CommandExt;
.spawn()
.map_err(|e| format!("Failed to start daemon: {}", e))?; let mut cmd = Command::new("node");
cmd.arg(daemon_path)
.env("AGENT_BROWSER_DAEMON", "1")
.env("AGENT_BROWSER_SESSION", session);
if headed {
cmd.env("AGENT_BROWSER_HEADED", "1");
}
// CREATE_NEW_PROCESS_GROUP | DETACHED_PROCESS
const CREATE_NEW_PROCESS_GROUP: u32 = 0x00000200;
const DETACHED_PROCESS: u32 = 0x00000008;
cmd.creation_flags(CREATE_NEW_PROCESS_GROUP | DETACHED_PROCESS)
.stdin(Stdio::null())
.stdout(Stdio::null())
.stderr(Stdio::null())
.spawn()
.map_err(|e| format!("Failed to start daemon: {}", e))?;
}
for _ in 0..50 { for _ in 0..50 {
if daemon_ready(session) { if daemon_ready(session) {
+19
View File
@@ -228,6 +228,25 @@ export async function startDaemon(): Promise<void> {
process.on('SIGINT', shutdown); process.on('SIGINT', shutdown);
process.on('SIGTERM', shutdown); process.on('SIGTERM', shutdown);
process.on('SIGHUP', shutdown);
// Handle unexpected errors - always cleanup
process.on('uncaughtException', (err) => {
console.error('Uncaught exception:', err);
cleanupSocket();
process.exit(1);
});
process.on('unhandledRejection', (reason) => {
console.error('Unhandled rejection:', reason);
cleanupSocket();
process.exit(1);
});
// Cleanup on normal exit
process.on('exit', () => {
cleanupSocket();
});
// Keep process alive // Keep process alive
process.stdin.resume(); process.stdin.resume();