pub mod adapter;
pub mod builder;
pub mod claude;
pub mod error;
pub mod git;
pub mod mock;
pub mod runner;
pub mod streaming;
#[cfg(test)]
mod tests;
#[cfg(test)]
mod streaming_tests;
#[cfg(test)]
mod large_env_test;
#[cfg(test)]
pub use adapter::MockSubprocessExecutor;
pub use adapter::{RealSubprocessExecutor, SubprocessError, SubprocessExecutor};
pub use builder::ProcessCommandBuilder;
pub use claude::ClaudeRunner;
pub use error::ProcessError;
pub use git::GitRunner;
pub use mock::{MockCommandConfig, MockProcessRunner};
pub use runner::ProcessCommand;
pub use runner::{ExitStatusHelper, ProcessOutput, ProcessRunner, ProcessStream};
use std::sync::Arc;
#[derive(Clone)]
pub struct SubprocessManager {
runner: Arc<dyn ProcessRunner>,
}
impl std::fmt::Debug for SubprocessManager {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("SubprocessManager").finish()
}
}
impl SubprocessManager {
pub fn new(runner: Arc<dyn ProcessRunner>) -> Self {
Self { runner }
}
pub fn production() -> Self {
Self::new(Arc::new(runner::TokioProcessRunner))
}
#[cfg(test)]
pub fn mock() -> (Self, MockProcessRunner) {
let mock = MockProcessRunner::new();
let runner = Arc::new(mock.clone()) as Arc<dyn ProcessRunner>;
(Self::new(runner), mock)
}
pub fn runner(&self) -> Arc<dyn ProcessRunner> {
Arc::clone(&self.runner)
}
pub fn git(&self) -> git::GitRunnerImpl {
git::GitRunnerImpl::new(Arc::clone(&self.runner))
}
pub fn claude(&self) -> claude::ClaudeRunnerImpl {
claude::ClaudeRunnerImpl::new(Arc::clone(&self.runner))
}
pub async fn run_with_timeout(
&self,
command: &str,
timeout: std::time::Duration,
) -> Result<ProcessOutput, ProcessError> {
let cmd = ProcessCommandBuilder::new("sh")
.arg("-c")
.arg(command)
.timeout(timeout)
.build();
self.runner.run(cmd).await
}
}