use super::{ACPError, ACPResult, ClaudeACPConfig};
use std::process::Stdio;
use tokio::process::Command;
use tracing::{debug, info};
pub struct SimplifiedClaudeAdapter {
session_id: Option<String>,
config: ClaudeACPConfig,
connected: bool,
}
impl SimplifiedClaudeAdapter {
pub fn new(config: ClaudeACPConfig) -> Self {
Self {
session_id: None,
config,
connected: false,
}
}
pub async fn connect_with_retry(&mut self) -> ACPResult<()> {
self.connect().await
}
pub async fn connect(&mut self) -> ACPResult<()> {
debug!("Verifying Claude CLI is available...");
let output = Command::new("claude")
.arg("--version")
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.output()
.await
.map_err(|e| ACPError::WebSocketError(format!("Claude CLI not found: {}", e)))?;
if output.status.success() {
let version = String::from_utf8_lossy(&output.stdout);
info!("✅ Claude CLI found: {}", version.trim());
let session_id = format!("cli-session-{}", uuid::Uuid::new_v4());
self.session_id = Some(session_id);
self.connected = true;
Ok(())
} else {
let stderr = String::from_utf8_lossy(&output.stderr);
Err(ACPError::WebSocketError(format!(
"Claude CLI error: {}",
stderr
)))
}
}
pub async fn send_task(&self, task: &str) -> ACPResult<String> {
if !self.connected {
return Err(ACPError::NotConnected);
}
info!("📤 Executing task via Claude CLI: {}", task);
let mut cmd = Command::new("claude");
cmd.arg("-p")
.arg(task)
.arg("--output-format")
.arg("text")
.arg("--dangerously-skip-permissions")
.stdout(Stdio::piped())
.stderr(Stdio::piped());
let output = tokio::time::timeout(
std::time::Duration::from_secs(self.config.timeout),
cmd.output(),
)
.await
.map_err(|_| ACPError::Timeout(self.config.timeout))?
.map_err(|e| ACPError::WebSocketError(format!("Failed to execute: {}", e)))?;
if output.status.success() {
let stdout = String::from_utf8_lossy(&output.stdout).to_string();
if stdout.trim().is_empty() {
let stderr = String::from_utf8_lossy(&output.stderr).to_string();
if !stderr.trim().is_empty() {
return Ok(stderr);
}
}
Ok(stdout)
} else {
let stderr = String::from_utf8_lossy(&output.stderr);
Err(ACPError::WebSocketError(format!(
"Claude CLI failed: {}",
stderr
)))
}
}
pub async fn disconnect(&mut self) {
self.session_id = None;
self.connected = false;
info!("👋 Claude CLI session ended");
}
pub async fn test_connection(&mut self) -> ACPResult<String> {
self.connect().await?;
let result = self
.send_task("Say 'Hello from ccswarm!' and nothing else.")
.await?;
Ok(format!("Connection test successful: {}", result.trim()))
}
pub fn is_connected(&self) -> bool {
self.connected
}
pub fn config(&self) -> &ClaudeACPConfig {
&self.config
}
pub fn session_id(&self) -> Option<&str> {
self.session_id.as_deref()
}
}