1mod analyzers;
6mod detector;
7
8#[cfg(test)]
9mod property_tests;
10
11pub use analyzers::*;
12pub use detector::ScaleDetector;
13
14use serde::{Deserialize, Serialize};
15
16#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
18#[serde(rename_all = "lowercase")]
19pub enum ProjectScale {
20 BugFix,
22 Feature,
24 Product,
26 Enterprise,
28}
29
30impl std::fmt::Display for ProjectScale {
31 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
32 match self {
33 ProjectScale::BugFix => write!(f, "Bug Fix"),
34 ProjectScale::Feature => write!(f, "Feature"),
35 ProjectScale::Product => write!(f, "Product"),
36 ProjectScale::Enterprise => write!(f, "Enterprise"),
37 }
38 }
39}
40
41impl ProjectScale {
42 pub fn recommended_workflows(&self) -> Vec<&'static str> {
44 match self {
45 ProjectScale::BugFix => vec!["quick-bug-fix", "quick-refactor"],
46 ProjectScale::Feature => vec!["quick-feature", "tech-spec", "dev-story", "code-review"],
47 ProjectScale::Product => vec![
48 "product-brief",
49 "prd",
50 "architecture",
51 "epics-and-stories",
52 "sprint-planning",
53 "dev-story",
54 "code-review",
55 "retrospective",
56 ],
57 ProjectScale::Enterprise => vec![
58 "product-brief",
59 "competitive-analysis",
60 "prd",
61 "architecture",
62 "api-design",
63 "data-model",
64 "security-review",
65 "epics-and-stories",
66 "implementation-readiness",
67 "sprint-planning",
68 "dev-story",
69 "code-review",
70 "test-design",
71 "test-automation",
72 "deployment",
73 "retrospective",
74 ],
75 }
76 }
77
78 pub fn recommended_agents(&self) -> Vec<&'static str> {
80 match self {
81 ProjectScale::BugFix => vec!["developer", "reviewer"],
82 ProjectScale::Feature => vec!["developer", "architect", "reviewer", "test-architect"],
83 ProjectScale::Product => vec![
84 "pm",
85 "architect",
86 "developer",
87 "ux-designer",
88 "test-architect",
89 "reviewer",
90 "scrum-master",
91 ],
92 ProjectScale::Enterprise => vec![
93 "pm",
94 "architect",
95 "developer",
96 "ux-designer",
97 "test-architect",
98 "analyst",
99 "tech-writer",
100 "scrum-master",
101 "security",
102 "performance",
103 "devops",
104 "data-engineer",
105 "reviewer",
106 ],
107 }
108 }
109}
110
111#[derive(Debug, Clone, Serialize, Deserialize)]
113pub struct ScaleRecommendation {
114 pub detected_scale: ProjectScale,
116 pub confidence: f32,
118 pub reasoning: Vec<String>,
120 pub suggested_workflows: Vec<String>,
122 pub suggested_agents: Vec<String>,
124}
125
126impl ScaleRecommendation {
127 pub fn new(scale: ProjectScale, confidence: f32) -> Self {
129 Self {
130 detected_scale: scale,
131 confidence,
132 reasoning: Vec::new(),
133 suggested_workflows: scale
134 .recommended_workflows()
135 .iter()
136 .map(|s| s.to_string())
137 .collect(),
138 suggested_agents: scale
139 .recommended_agents()
140 .iter()
141 .map(|s| s.to_string())
142 .collect(),
143 }
144 }
145
146 pub fn with_reason(mut self, reason: impl Into<String>) -> Self {
148 self.reasoning.push(reason.into());
149 self
150 }
151
152 pub fn with_reasons(mut self, reasons: Vec<String>) -> Self {
154 self.reasoning.extend(reasons);
155 self
156 }
157}
158
159#[derive(Debug, Clone, Default)]
161pub struct ProjectContext {
162 pub root_path: Option<std::path::PathBuf>,
164 pub lines_of_code: Option<usize>,
166 pub file_count: Option<usize>,
168 pub dependency_count: Option<usize>,
170 pub contributor_count: Option<usize>,
172 pub commit_count: Option<usize>,
174 pub has_ci_cd: bool,
176 pub has_tests: bool,
178 pub has_docs: bool,
180 pub project_type: Option<String>,
182 pub scale_override: Option<ProjectScale>,
184}
185
186impl ProjectContext {
187 pub fn new() -> Self {
189 Self::default()
190 }
191
192 pub fn with_root_path(mut self, path: impl Into<std::path::PathBuf>) -> Self {
194 self.root_path = Some(path.into());
195 self
196 }
197
198 pub fn with_lines_of_code(mut self, loc: usize) -> Self {
200 self.lines_of_code = Some(loc);
201 self
202 }
203
204 pub fn with_file_count(mut self, count: usize) -> Self {
206 self.file_count = Some(count);
207 self
208 }
209
210 pub fn with_dependency_count(mut self, count: usize) -> Self {
212 self.dependency_count = Some(count);
213 self
214 }
215
216 pub fn with_contributor_count(mut self, count: usize) -> Self {
218 self.contributor_count = Some(count);
219 self
220 }
221
222 pub fn with_commit_count(mut self, count: usize) -> Self {
224 self.commit_count = Some(count);
225 self
226 }
227
228 pub fn with_ci_cd(mut self, has_ci_cd: bool) -> Self {
230 self.has_ci_cd = has_ci_cd;
231 self
232 }
233
234 pub fn with_tests(mut self, has_tests: bool) -> Self {
236 self.has_tests = has_tests;
237 self
238 }
239
240 pub fn with_docs(mut self, has_docs: bool) -> Self {
242 self.has_docs = has_docs;
243 self
244 }
245
246 pub fn with_project_type(mut self, project_type: impl Into<String>) -> Self {
248 self.project_type = Some(project_type.into());
249 self
250 }
251
252 pub fn with_scale_override(mut self, scale: ProjectScale) -> Self {
254 self.scale_override = Some(scale);
255 self
256 }
257}