claude_code_acp/session/
wrapped_child.rs

1//! Wrapped child process with process group support
2//!
3//! Provides a unified interface over process-wrap's ChildWrapper
4//! while maintaining compatibility with existing Arc<Mutex<>> pattern.
5
6use process_wrap::tokio::ChildWrapper;
7use std::io;
8use std::pin::Pin;
9
10/// Wrapper around Box<dyn ChildWrapper> that provides
11/// a stable interface compatible with Arc<Mutex<>>
12///
13/// This wraps the process-wrap ChildWrapper trait to work
14/// with our existing Arc<Mutex<>> storage pattern in BackgroundTerminal.
15#[derive(Debug)]
16pub struct WrappedChild {
17    inner: Box<dyn ChildWrapper>,
18}
19
20impl WrappedChild {
21    /// Create a new wrapped child from a process-wrap ChildWrapper
22    pub fn new(inner: Box<dyn ChildWrapper>) -> Self {
23        Self { inner }
24    }
25
26    /// Get mutable reference to inner ChildWrapper
27    pub fn inner_mut(&mut self) -> &mut dyn ChildWrapper {
28        self.inner.as_mut()
29    }
30
31    /// Kill the process group and wait for exit
32    ///
33    /// This will terminate the entire process group, not just the parent process.
34    pub async fn kill(&mut self) -> io::Result<()> {
35        Pin::from(self.inner.kill()).await
36    }
37
38    /// Start killing without waiting for exit
39    ///
40    /// This initiates the kill operation but returns immediately.
41    pub fn start_kill(&mut self) -> io::Result<()> {
42        self.inner.start_kill()
43    }
44
45    /// Wait for the process to exit
46    pub async fn wait(&mut self) -> io::Result<std::process::ExitStatus> {
47        Pin::from(self.inner.wait()).await
48    }
49
50    /// Try to wait without blocking
51    ///
52    /// Returns Some(status) if the process has exited, None if still running.
53    pub fn try_wait(&mut self) -> io::Result<Option<std::process::ExitStatus>> {
54        self.inner.try_wait()
55    }
56
57    /// Send a specific signal to the process group (Unix only)
58    ///
59    /// # Arguments
60    /// * `sig` - Signal number (e.g., libc::SIGTERM, libc::SIGKILL)
61    #[cfg(unix)]
62    pub fn signal(&self, sig: i32) -> io::Result<()> {
63        self.inner.signal(sig)
64    }
65
66    /// Get the process ID
67    pub fn id(&self) -> u32 {
68        self.inner.id().unwrap_or(0)
69    }
70}
71
72#[cfg(test)]
73mod tests {
74    #[test]
75    fn test_wrapped_child_creation() {
76        // This is a placeholder test
77        // Real tests would require spawning an actual process
78        // which is better done as integration tests
79    }
80}