use std::path::Path;
use std::process::Command;
use std::sync::Arc;
use tracing::debug;
use crate::session_manager::ManagedTmuxDriver;
use super::RuntimeAdapter;
use super::RuntimeError;
const SPAWN_COMMAND: &str = "env -u ANTHROPIC_API_KEY claude";
pub struct ClaudeCodeAdapter {
tmux: Arc<dyn ManagedTmuxDriver + Send + Sync>,
}
impl ClaudeCodeAdapter {
pub fn new(tmux: Arc<dyn ManagedTmuxDriver + Send + Sync>) -> Self {
Self { tmux }
}
fn claude_available() -> bool {
Command::new("which")
.arg("claude")
.output()
.map(|o| o.status.success())
.unwrap_or(false)
}
}
impl RuntimeAdapter for ClaudeCodeAdapter {
fn spawn(&self, tmux_name: &str, cwd: &Path, task: &str) -> Result<(), RuntimeError> {
if !Self::claude_available() {
return Err(RuntimeError::BinaryNotFound(
"claude binary not found on PATH — install Claude Code first".into(),
));
}
debug!(
session = %tmux_name,
cwd = %cwd.display(),
task = %task,
"spawning claude-code in tmux pane"
);
self.tmux
.send_line(tmux_name, SPAWN_COMMAND)
.map_err(|e| RuntimeError::TmuxUnavailable(e.to_string()))
}
fn identify(&self) -> &str {
"claude-code"
}
}
#[cfg(test)]
mod tests {
use super::super::test_helpers::FakeTmux;
use super::*;
#[test]
fn claude_code_adapter_identifies() {
let fake = FakeTmux::new();
let adapter = ClaudeCodeAdapter::new(fake);
assert_eq!(adapter.identify(), "claude-code");
}
#[test]
fn spawn_command_constant_contains_env_scrub() {
assert!(
SPAWN_COMMAND.contains("env -u ANTHROPIC_API_KEY"),
"SPAWN_COMMAND must contain env scrub: {SPAWN_COMMAND}"
);
assert!(
SPAWN_COMMAND.ends_with("claude"),
"SPAWN_COMMAND must end with claude: {SPAWN_COMMAND}"
);
}
#[test]
fn claude_code_adapter_binary_check_returns_bool() {
let _ = ClaudeCodeAdapter::claude_available();
}
#[test]
fn spawn_sends_env_scrub_when_binary_available() {
if !ClaudeCodeAdapter::claude_available() {
return;
}
let fake = FakeTmux::new();
let adapter = ClaudeCodeAdapter::new(fake.clone());
adapter
.spawn("tmpm-test", Path::new("/tmp"), "some task")
.expect("spawn");
let sends = fake.sends.lock().unwrap();
assert_eq!(sends.len(), 1);
assert_eq!(sends[0].0, "tmpm-test");
assert_eq!(sends[0].1, SPAWN_COMMAND);
}
}