claude-utils 0.2.0

Cross-platform companion toolkit for Anthropic's Claude Code CLI
Documentation
use futures::future::join_all;
use serde_json::Value;
use std::collections::VecDeque;
use std::sync::Arc;
use tokio::sync::{Mutex, Semaphore};
use tokio::time::{sleep, Duration};
use tracing::{error, info};

pub struct ParallelExecutor {
    semaphore: Arc<Semaphore>,
    retry_queue: Arc<Mutex<VecDeque<Value>>>,
}

impl ParallelExecutor {
    pub fn new(parallel_limit: usize) -> Self {
        Self {
            semaphore: Arc::new(Semaphore::new(parallel_limit)),
            retry_queue: Arc::new(Mutex::new(VecDeque::new())),
        }
    }

    /// Execute multiple operations in parallel
    pub async fn execute_parallel(&self, operations: Vec<Value>) -> Vec<Result<Value, String>> {
        info!("🚀 Turbo: Executing {} operations in parallel", operations.len());
        
        let tasks: Vec<_> = operations
            .into_iter()
            .map(|op| {
                let sem = self.semaphore.clone();
                async move {
                    let _permit = match sem.acquire().await {
                        Ok(permit) => permit,
                        Err(e) => {
                            error!("Failed to acquire semaphore: {}", e);
                            return Err(format!("Semaphore error: {e}"));
                        }
                    };
                    self.execute_single(op).await
                }
            })
            .collect();

        join_all(tasks).await
    }

    /// Execute a single operation with retry logic
    async fn execute_single(&self, operation: Value) -> Result<Value, String> {
        let mut retry_count = 0;
        const MAX_RETRIES: u32 = 3;

        loop {
            match self.perform_operation(&operation).await {
                Ok(result) => return Ok(result),
                Err(e) if retry_count < MAX_RETRIES => {
                    retry_count += 1;
                    let delay = Duration::from_millis(100 * (2_u64.pow(retry_count)));
                    info!("Retry {}/{} after {:?}: {}", retry_count, MAX_RETRIES, delay, e);
                    sleep(delay).await;
                }
                Err(e) => {
                    error!("Operation failed after {} retries: {}", MAX_RETRIES, e);
                    return Err(e);
                }
            }
        }
    }

    /// Perform the actual operation (placeholder - will integrate with MCP)
    async fn perform_operation(&self, operation: &Value) -> Result<Value, String> {
        // This will be integrated with the actual MCP server
        // For now, simulate processing
        if let Some(method) = operation.get("method").and_then(|m| m.as_str()) {
            match method {
                "file.edit" => {
                    // Simulate file edit
                    Ok(serde_json::json!({
                        "success": true,
                        "file": operation.get("params").and_then(|p| p.get("file")),
                        "turbo": true
                    }))
                }
                "command.execute" => {
                    // Simulate command execution
                    Ok(serde_json::json!({
                        "success": true,
                        "output": "Command executed",
                        "turbo": true
                    }))
                }
                _ => Err(format!("Unknown method: {method}")),
            }
        } else {
            Err("No method specified".to_string())
        }
    }

    /// Queue operation for retry
    pub async fn queue_retry(&self, operation: Value) {
        self.retry_queue.lock().await.push_back(operation);
    }

    /// Process retry queue
    pub async fn process_retries(&self) -> Vec<Result<Value, String>> {
        let mut queue = self.retry_queue.lock().await;
        let operations: Vec<Value> = queue.drain(..).collect();
        drop(queue);

        if !operations.is_empty() {
            info!("Processing {} queued retries", operations.len());
            self.execute_parallel(operations).await
        } else {
            Vec::new()
        }
    }
}