use std::path::Path;
use anyhow::{bail, Result};
use async_trait::async_trait;
use tokio::process::Command;
use crate::types::{CliResponse, SessionState};
pub mod claude;
pub mod codex;
pub mod gemini;
#[async_trait]
pub trait CliBackend: Send + Sync {
fn build_command(&self, prompt: &str, working_dir: &Path, session: &SessionState) -> Command;
fn parse_output(
&self,
stdout: String,
stderr: String,
exit_code: i32,
duration: std::time::Duration,
) -> CliResponse;
fn name(&self) -> &'static str;
}
pub fn build(backend_name: &str) -> Result<Box<dyn CliBackend>> {
match backend_name {
"claude-cli" => Ok(Box::new(claude::ClaudeCodeBackend)),
"codex-cli" => Ok(Box::new(codex::CodexBackend)),
"gemini-cli" => Ok(Box::new(gemini::GeminiBackend)),
other => bail!("unknown backend: `{other}`"),
}
}
#[cfg(test)]
#[path = "../tests/backend/registry_test.rs"]
mod registry_tests;