Skip to main content

ai_session/core/
process.rs

1//! Process management for AI sessions
2
3use anyhow::Result;
4use std::process::Stdio;
5use tokio::process::{Child, Command};
6
7/// Handle to a managed process
8pub struct ProcessHandle {
9    /// The underlying child process
10    child: Child,
11    /// Process ID
12    pid: u32,
13}
14
15impl ProcessHandle {
16    /// Create a new process
17    pub async fn spawn(
18        command: &str,
19        args: &[String],
20        working_dir: &std::path::Path,
21        env: &[(String, String)],
22    ) -> Result<Self> {
23        let mut cmd = Command::new(command);
24
25        cmd.args(args)
26            .current_dir(working_dir)
27            .stdin(Stdio::piped())
28            .stdout(Stdio::piped())
29            .stderr(Stdio::piped());
30
31        for (key, value) in env {
32            cmd.env(key, value);
33        }
34
35        let child = cmd.spawn()?;
36        let pid = child
37            .id()
38            .ok_or_else(|| anyhow::anyhow!("Failed to get process ID"))?;
39
40        Ok(Self { child, pid })
41    }
42
43    /// Get the process ID
44    pub fn pid(&self) -> u32 {
45        self.pid
46    }
47
48    /// Check if the process is still running
49    pub async fn is_running(&mut self) -> bool {
50        matches!(self.child.try_wait(), Ok(None))
51    }
52
53    /// Kill the process
54    pub async fn kill(&mut self) -> Result<()> {
55        self.child.kill().await?;
56        Ok(())
57    }
58
59    /// Wait for the process to exit
60    pub async fn wait(&mut self) -> Result<std::process::ExitStatus> {
61        Ok(self.child.wait().await?)
62    }
63}