ccswarm 0.9.1

AI Agent Workflow DevOps toolchain complementing Claude Code Agent Teams
Documentation
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::path::PathBuf;

/// Core agent identity information
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AgentIdentity {
    /// Unique agent identifier
    pub agent_id: String,

    /// Agent's specialization role
    pub specialization: AgentRole,

    /// Workspace path for this agent
    pub workspace_path: PathBuf,

    /// Environment variables for role identification
    pub env_vars: HashMap<String, String>,

    /// Session identifier (unique per startup)
    pub session_id: String,

    /// Parent orchestrator process ID
    pub parent_process_id: String,

    /// Timestamp of agent initialization
    pub initialized_at: DateTime<Utc>,
}

/// Agent specialization roles with their specific configurations
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Hash, Eq)]
pub enum AgentRole {
    Frontend {
        technologies: Vec<String>,
        responsibilities: Vec<String>,
        boundaries: Vec<String>,
    },
    Backend {
        technologies: Vec<String>,
        responsibilities: Vec<String>,
        boundaries: Vec<String>,
    },
    DevOps {
        technologies: Vec<String>,
        responsibilities: Vec<String>,
        boundaries: Vec<String>,
    },
    QA {
        technologies: Vec<String>,
        responsibilities: Vec<String>,
        boundaries: Vec<String>,
    },
    Master {
        oversight_roles: Vec<String>,
        quality_standards: QualityStandards,
    },
    Search {
        technologies: Vec<String>,
        responsibilities: Vec<String>,
        boundaries: Vec<String>,
    },
}

impl AgentRole {
    /// Get the name of the role
    pub fn name(&self) -> &str {
        match self {
            AgentRole::Frontend { .. } => "Frontend",
            AgentRole::Backend { .. } => "Backend",
            AgentRole::DevOps { .. } => "DevOps",
            AgentRole::QA { .. } => "QA",
            AgentRole::Master { .. } => "Master",
            AgentRole::Search { .. } => "Search",
        }
    }

    /// Get the string representation of the role
    /// This is an alias for the `name()` method following Rust conventions
    pub fn as_str(&self) -> &str {
        self.name()
    }

    /// Get the technologies associated with this role
    pub fn technologies(&self) -> Vec<String> {
        match self {
            AgentRole::Frontend { technologies, .. }
            | AgentRole::Backend { technologies, .. }
            | AgentRole::DevOps { technologies, .. }
            | AgentRole::QA { technologies, .. }
            | AgentRole::Search { technologies, .. } => technologies.clone(),
            AgentRole::Master { .. } => vec!["Orchestration".to_string()],
        }
    }

    /// Get the responsibilities for this role
    pub fn responsibilities(&self) -> Vec<String> {
        match self {
            AgentRole::Frontend {
                responsibilities, ..
            }
            | AgentRole::Backend {
                responsibilities, ..
            }
            | AgentRole::DevOps {
                responsibilities, ..
            }
            | AgentRole::QA {
                responsibilities, ..
            }
            | AgentRole::Search {
                responsibilities, ..
            } => responsibilities.clone(),
            AgentRole::Master {
                oversight_roles, ..
            } => oversight_roles.clone(),
        }
    }

    /// Get the boundaries for this role
    pub fn boundaries(&self) -> Vec<String> {
        match self {
            AgentRole::Frontend { boundaries, .. }
            | AgentRole::Backend { boundaries, .. }
            | AgentRole::DevOps { boundaries, .. }
            | AgentRole::QA { boundaries, .. }
            | AgentRole::Search { boundaries, .. } => boundaries.clone(),
            AgentRole::Master { .. } => vec!["No direct code implementation".to_string()],
        }
    }
}

/// Quality standards for code review and acceptance
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct QualityStandards {
    pub min_test_coverage: f64,
    pub max_complexity: u32,
    pub security_scan_required: bool,
    pub performance_threshold_secs: u64,
}

// Manual implementations for Hash and Eq that handle f64 properly
impl std::hash::Hash for QualityStandards {
    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
        // Convert f64 to bits for hashing
        self.min_test_coverage.to_bits().hash(state);
        self.max_complexity.hash(state);
        self.security_scan_required.hash(state);
        self.performance_threshold_secs.hash(state);
    }
}

impl Eq for QualityStandards {}

impl Default for QualityStandards {
    fn default() -> Self {
        Self {
            min_test_coverage: 0.85, // 85%
            max_complexity: 10,
            security_scan_required: true,
            performance_threshold_secs: 5,
        }
    }
}

/// Identity monitoring status
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum IdentityStatus {
    Healthy,
    DriftDetected(String),
    BoundaryViolation(String),
    CriticalFailure(String),
}

/// Default role configurations
pub fn default_frontend_role() -> AgentRole {
    AgentRole::Frontend {
        technologies: vec![
            "React".to_string(),
            "TypeScript".to_string(),
            "Tailwind CSS".to_string(),
            "Jest".to_string(),
            "Vite".to_string(),
        ],
        responsibilities: vec![
            "UI Component Development".to_string(),
            "State Management".to_string(),
            "Frontend Testing".to_string(),
            "User Experience".to_string(),
            "Accessibility".to_string(),
        ],
        boundaries: vec![
            "No backend API development".to_string(),
            "No database operations".to_string(),
            "No server-side logic".to_string(),
            "No infrastructure changes".to_string(),
            "No deployment scripts".to_string(),
        ],
    }
}

pub fn default_backend_role() -> AgentRole {
    AgentRole::Backend {
        technologies: vec![
            "Node.js".to_string(),
            "TypeScript".to_string(),
            "Express".to_string(),
            "PostgreSQL".to_string(),
            "Prisma".to_string(),
        ],
        responsibilities: vec![
            "API Development".to_string(),
            "Database Design".to_string(),
            "Authentication".to_string(),
            "Business Logic".to_string(),
            "Data Validation".to_string(),
        ],
        boundaries: vec![
            "No frontend UI code".to_string(),
            "No CSS styling".to_string(),
            "No infrastructure provisioning".to_string(),
            "No deployment automation".to_string(),
        ],
    }
}

pub fn default_devops_role() -> AgentRole {
    AgentRole::DevOps {
        technologies: vec![
            "Docker".to_string(),
            "Kubernetes".to_string(),
            "Terraform".to_string(),
            "AWS".to_string(),
            "GitHub Actions".to_string(),
        ],
        responsibilities: vec![
            "Infrastructure Provisioning".to_string(),
            "CI/CD Pipelines".to_string(),
            "Monitoring Setup".to_string(),
            "Security Configuration".to_string(),
            "Deployment Automation".to_string(),
        ],
        boundaries: vec![
            "No application code changes".to_string(),
            "No business logic implementation".to_string(),
            "No UI development".to_string(),
            "No database schema design".to_string(),
        ],
    }
}

pub fn default_qa_role() -> AgentRole {
    AgentRole::QA {
        technologies: vec![
            "Jest".to_string(),
            "Cypress".to_string(),
            "Playwright".to_string(),
            "Postman".to_string(),
            "K6".to_string(),
        ],
        responsibilities: vec![
            "Test Strategy".to_string(),
            "Test Implementation".to_string(),
            "Quality Assurance".to_string(),
            "Performance Testing".to_string(),
            "Security Testing".to_string(),
        ],
        boundaries: vec![
            "No production code changes".to_string(),
            "No feature implementation".to_string(),
            "No infrastructure changes".to_string(),
            "No deployment execution".to_string(),
        ],
    }
}

pub fn default_search_role() -> AgentRole {
    AgentRole::Search {
        technologies: vec![
            "Gemini CLI".to_string(),
            "Web Search".to_string(),
            "Information Retrieval".to_string(),
            "Search APIs".to_string(),
        ],
        responsibilities: vec![
            "Web Search".to_string(),
            "Information Gathering".to_string(),
            "Result Filtering".to_string(),
            "Query Optimization".to_string(),
            "Knowledge Discovery".to_string(),
        ],
        boundaries: vec![
            "No code implementation".to_string(),
            "No direct file modifications".to_string(),
            "Read-only information gathering".to_string(),
            "No execution of found code".to_string(),
            "No decision making beyond search".to_string(),
        ],
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_basic_role_functionality() {
        let frontend = default_frontend_role();
        assert_eq!(frontend.name(), "Frontend");
        assert!(!frontend.technologies().is_empty());
        assert!(!frontend.responsibilities().is_empty());
        assert!(!frontend.boundaries().is_empty());
    }
}