mod analyzers;
mod detector;
#[cfg(test)]
mod property_tests;
pub use analyzers::*;
pub use detector::ScaleDetector;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum ProjectScale {
BugFix,
Feature,
Product,
Enterprise,
}
impl std::fmt::Display for ProjectScale {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
ProjectScale::BugFix => write!(f, "Bug Fix"),
ProjectScale::Feature => write!(f, "Feature"),
ProjectScale::Product => write!(f, "Product"),
ProjectScale::Enterprise => write!(f, "Enterprise"),
}
}
}
impl ProjectScale {
pub fn recommended_workflows(&self) -> Vec<&'static str> {
match self {
ProjectScale::BugFix => vec!["quick-bug-fix", "quick-refactor"],
ProjectScale::Feature => vec!["quick-feature", "tech-spec", "dev-story", "code-review"],
ProjectScale::Product => vec![
"product-brief",
"prd",
"architecture",
"epics-and-stories",
"sprint-planning",
"dev-story",
"code-review",
"retrospective",
],
ProjectScale::Enterprise => vec![
"product-brief",
"competitive-analysis",
"prd",
"architecture",
"api-design",
"data-model",
"security-review",
"epics-and-stories",
"implementation-readiness",
"sprint-planning",
"dev-story",
"code-review",
"test-design",
"test-automation",
"deployment",
"retrospective",
],
}
}
pub fn recommended_agents(&self) -> Vec<&'static str> {
match self {
ProjectScale::BugFix => vec!["developer", "reviewer"],
ProjectScale::Feature => vec!["developer", "architect", "reviewer", "test-architect"],
ProjectScale::Product => vec![
"pm",
"architect",
"developer",
"ux-designer",
"test-architect",
"reviewer",
"scrum-master",
],
ProjectScale::Enterprise => vec![
"pm",
"architect",
"developer",
"ux-designer",
"test-architect",
"analyst",
"tech-writer",
"scrum-master",
"security",
"performance",
"devops",
"data-engineer",
"reviewer",
],
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ScaleRecommendation {
pub detected_scale: ProjectScale,
pub confidence: f32,
pub reasoning: Vec<String>,
pub suggested_workflows: Vec<String>,
pub suggested_agents: Vec<String>,
}
impl ScaleRecommendation {
pub fn new(scale: ProjectScale, confidence: f32) -> Self {
Self {
detected_scale: scale,
confidence,
reasoning: Vec::new(),
suggested_workflows: scale
.recommended_workflows()
.iter()
.map(|s| s.to_string())
.collect(),
suggested_agents: scale
.recommended_agents()
.iter()
.map(|s| s.to_string())
.collect(),
}
}
pub fn with_reason(mut self, reason: impl Into<String>) -> Self {
self.reasoning.push(reason.into());
self
}
pub fn with_reasons(mut self, reasons: Vec<String>) -> Self {
self.reasoning.extend(reasons);
self
}
}
#[derive(Debug, Clone, Default)]
pub struct ProjectContext {
pub root_path: Option<std::path::PathBuf>,
pub lines_of_code: Option<usize>,
pub file_count: Option<usize>,
pub dependency_count: Option<usize>,
pub contributor_count: Option<usize>,
pub commit_count: Option<usize>,
pub has_ci_cd: bool,
pub has_tests: bool,
pub has_docs: bool,
pub project_type: Option<String>,
pub scale_override: Option<ProjectScale>,
}
impl ProjectContext {
pub fn new() -> Self {
Self::default()
}
pub fn with_root_path(mut self, path: impl Into<std::path::PathBuf>) -> Self {
self.root_path = Some(path.into());
self
}
pub fn with_lines_of_code(mut self, loc: usize) -> Self {
self.lines_of_code = Some(loc);
self
}
pub fn with_file_count(mut self, count: usize) -> Self {
self.file_count = Some(count);
self
}
pub fn with_dependency_count(mut self, count: usize) -> Self {
self.dependency_count = Some(count);
self
}
pub fn with_contributor_count(mut self, count: usize) -> Self {
self.contributor_count = Some(count);
self
}
pub fn with_commit_count(mut self, count: usize) -> Self {
self.commit_count = Some(count);
self
}
pub fn with_ci_cd(mut self, has_ci_cd: bool) -> Self {
self.has_ci_cd = has_ci_cd;
self
}
pub fn with_tests(mut self, has_tests: bool) -> Self {
self.has_tests = has_tests;
self
}
pub fn with_docs(mut self, has_docs: bool) -> Self {
self.has_docs = has_docs;
self
}
pub fn with_project_type(mut self, project_type: impl Into<String>) -> Self {
self.project_type = Some(project_type.into());
self
}
pub fn with_scale_override(mut self, scale: ProjectScale) -> Self {
self.scale_override = Some(scale);
self
}
}