use std::io;
use std::path::PathBuf;
#[ derive( Debug ) ]
pub struct ProcessInfo
{
pub pid : u32,
pub cmdline : String,
pub cwd : PathBuf,
}
#[ inline ]
#[ must_use ]
pub fn find_claude_processes() -> Vec< ProcessInfo >
{
let self_pid = std::process::id();
let mut result = vec![];
let Ok( proc_dir ) = std::fs::read_dir( "/proc" ) else { return result; };
for entry in proc_dir
{
let Ok( entry ) = entry else { continue; };
let name = entry.file_name();
let name_str = name.to_string_lossy();
let Ok( pid ) : Result< u32, _ > = name_str.parse() else { continue; };
if pid == self_pid { continue; }
let cmdline_path = format!( "/proc/{pid}/cmdline" );
let Ok( cmdline_raw ) = std::fs::read( &cmdline_path ) else { continue; };
let first_field = cmdline_raw.split( | &b | b == 0 ).next().unwrap_or( &[] );
let binary_path = core::str::from_utf8( first_field ).unwrap_or( "" );
let binary_name = std::path::Path::new( binary_path )
.file_name()
.and_then( | s | s.to_str() )
.unwrap_or( "" );
if binary_name != "claude" { continue; }
let cwd_path = format!( "/proc/{pid}/cwd" );
let cwd = std::fs::read_link( &cwd_path ).unwrap_or_default();
let cmdline = cmdline_raw
.iter()
.map( | &b | if b == 0 { b' ' } else { b } )
.collect::< Vec< u8 > >();
let cmdline = String::from_utf8_lossy( &cmdline ).trim_end().to_string();
result.push( ProcessInfo { pid, cmdline, cwd } );
}
result
}
#[ inline ]
pub fn send_sigterm( pid : u32 ) -> Result< (), io::Error >
{
run_kill( &[ "-TERM", &pid.to_string() ] )
}
#[ inline ]
pub fn send_sigkill( pid : u32 ) -> Result< (), io::Error >
{
run_kill( &[ "-KILL", &pid.to_string() ] )
}
fn run_kill( args : &[ &str ] ) -> Result< (), io::Error >
{
let status = std::process::Command::new( "kill" )
.args( args )
.status()
.map_err( | e | io::Error::other( e.to_string() ) )?;
if status.success()
{
Ok( () )
}
else
{
Err( io::Error::other(
format!( "kill {} exited with: {status}", args.join( " " ) ),
) )
}
}