hive-agent: /cancel matches claude's cmdline, not the kernel comm name
This commit is contained in:
parent
3512e4b019
commit
96ef592fee
1 changed files with 29 additions and 16 deletions
|
|
@ -291,13 +291,24 @@ enum SigintOutcome {
|
|||
/// process, if any. `hive-claude`'s driver spawns the turn's claude
|
||||
/// directly (`Command::new(program).spawn()`, no shell in between), so the
|
||||
/// harness is always the immediate parent of any claude turn it started —
|
||||
/// scanning `/proc/*/status` for `Name: claude` + `PPid: <our own pid>`
|
||||
/// finds *that* specific process without needing the driver to surface its
|
||||
/// pid through any extra plumbing. Distinguishes the harness's own tracked
|
||||
/// turn from an unrelated `claude` someone is running interactively in the
|
||||
/// same container (a manually shelled-in "choom" session) — that one's
|
||||
/// parent is a login shell, not us. Best-effort: a process that exits
|
||||
/// mid-scan (its `/proc/<pid>/status` read fails, ESRCH) is just skipped.
|
||||
/// scanning `/proc/*/status` for `PPid: <our own pid>` plus `/proc/*/cmdline`
|
||||
/// for an argv[0] of `claude` finds *that* specific process without needing
|
||||
/// the driver to surface its pid through any extra plumbing. Distinguishes
|
||||
/// the harness's own tracked turn from an unrelated `claude` someone is
|
||||
/// running interactively in the same container (a manually shelled-in
|
||||
/// "choom" session) — that one's parent is a login shell, not us.
|
||||
///
|
||||
/// **Matches on `cmdline`, not `status`'s `Name:` field.** The nixpkgs
|
||||
/// `claude-code` package wraps its real binary (`wrapProgram`-style: the
|
||||
/// executable on `PATH` is a thin `exec -a claude .../.claude-wrapped ...`
|
||||
/// shim) — `exec -a` only overrides argv[0] as the process itself/`cmdline`
|
||||
/// see it, not the kernel's own `comm` (what `status`'s `Name:` line
|
||||
/// reports, set from the executed binary's own basename at `execve` time).
|
||||
/// So `Name:` shows `.claude-wrapped`, not `claude`, on a wrapped package —
|
||||
/// `cmdline`'s first argument still carries the bare name
|
||||
/// `Command::new("claude")` resolved on `PATH`, which is what actually
|
||||
/// matters here. Best-effort: a process that exits mid-scan (its
|
||||
/// `/proc/<pid>/{status,cmdline}` read fails, ESRCH) is just skipped.
|
||||
fn find_claude_child() -> Option<u32> {
|
||||
let own_pid = std::process::id();
|
||||
for entry in std::fs::read_dir("/proc").ok()?.flatten() {
|
||||
|
|
@ -307,16 +318,18 @@ fn find_claude_child() -> Option<u32> {
|
|||
let Ok(status) = std::fs::read_to_string(entry.path().join("status")) else {
|
||||
continue;
|
||||
};
|
||||
let mut name = None;
|
||||
let mut parent_pid = None;
|
||||
for line in status.lines() {
|
||||
if let Some(v) = line.strip_prefix("Name:") {
|
||||
name = Some(v.trim());
|
||||
} else if let Some(v) = line.strip_prefix("PPid:") {
|
||||
parent_pid = v.trim().parse::<u32>().ok();
|
||||
}
|
||||
let parent_pid = status
|
||||
.lines()
|
||||
.find_map(|line| line.strip_prefix("PPid:"))
|
||||
.and_then(|v| v.trim().parse::<u32>().ok());
|
||||
if parent_pid != Some(own_pid) {
|
||||
continue;
|
||||
}
|
||||
if name == Some("claude") && parent_pid == Some(own_pid) {
|
||||
let Ok(cmdline) = std::fs::read(entry.path().join("cmdline")) else {
|
||||
continue;
|
||||
};
|
||||
let argv0 = cmdline.split(|&b| b == 0).next().unwrap_or_default();
|
||||
if argv0 == b"claude" {
|
||||
return Some(pid);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue