diff --git a/src/claude/poc-hook.rs b/src/claude/poc-hook.rs index 415f575..b02a53d 100644 --- a/src/claude/poc-hook.rs +++ b/src/claude/poc-hook.rs @@ -85,6 +85,8 @@ fn check_notifications() { /// Check for stale agent processes in a state dir. /// Cleans up pid files for dead processes and kills timed-out ones. +/// Also detects PID reuse by checking if the process is actually a +/// claude/poc-memory process (reads /proc/pid/cmdline). fn reap_agent_pids(state_dir: &std::path::Path, timeout_secs: u64) { let Ok(entries) = fs::read_dir(state_dir) else { return }; for entry in entries.flatten() { @@ -93,11 +95,23 @@ fn reap_agent_pids(state_dir: &std::path::Path, timeout_secs: u64) { let Some(pid_str) = name_str.strip_prefix("pid-") else { continue }; let Ok(pid) = pid_str.parse::() else { continue }; + // Check if the process is actually alive if unsafe { libc::kill(pid, 0) } != 0 { fs::remove_file(entry.path()).ok(); continue; } + // Check if the PID still belongs to a claude/poc-memory process. + // PID reuse by an unrelated process would otherwise block the + // agent from being re-launched. + let is_ours = fs::read_to_string(format!("/proc/{}/cmdline", pid)) + .map(|cmd| cmd.contains("claude") || cmd.contains("poc-memory")) + .unwrap_or(false); + if !is_ours { + fs::remove_file(entry.path()).ok(); + continue; + } + if timeout_secs > 0 { if let Ok(meta) = entry.metadata() { if let Ok(modified) = meta.modified() {