1use serde::{Deserialize, Serialize};
4
5use crate::provider::ProviderType;
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Deserialize, Serialize)]
9#[serde(rename_all = "snake_case")]
10pub enum RotationStrategy {
11 #[default]
12 None,
13 Random,
14 RoundRobin,
15}
16
17pub(crate) fn default_rotation_strategy_enum() -> RotationStrategy {
18 RotationStrategy::None
19}
20
21macro_rules! default_fn {
23 ($name:ident, $type:ty, $value:expr) => {
24 pub(crate) fn $name() -> $type {
25 $value
26 }
27 };
28}
29
30default_fn!(default_complexity_criteria, usize, 10);
35default_fn!(default_complexity_files, usize, 5);
36default_fn!(default_complexity_words, usize, 150);
37default_fn!(default_simple_criteria, usize, 1);
38default_fn!(default_simple_files, usize, 1);
39default_fn!(default_simple_words, usize, 3);
40default_fn!(default_max_retries, usize, 3);
41default_fn!(default_retry_delay_ms, u64, 60_000); default_fn!(default_backoff_multiplier, f64, 2.0);
43default_fn!(default_poll_interval_ms, u64, 5000); default_fn!(default_site_output_dir, String, "./public/".to_string());
45default_fn!(default_site_base_url, String, "/".to_string());
46default_fn!(default_site_title, String, "Project Specs".to_string());
47default_fn!(
48 default_include_statuses,
49 Vec<String>,
50 vec![
51 "completed".to_string(),
52 "in_progress".to_string(),
53 "pending".to_string(),
54 ]
55);
56default_fn!(default_true, bool, true);
57default_fn!(default_agent_weight, usize, 1);
58default_fn!(default_agent_name, String, "main".to_string());
59default_fn!(default_agent_command, String, "claude".to_string());
60default_fn!(default_max_concurrent, usize, 2);
61default_fn!(default_stagger_delay_ms, u64, 1000); default_fn!(default_stagger_jitter_ms, u64, 200); default_fn!(default_prompt, String, "bootstrap".to_string());
64default_fn!(default_branch_prefix, String, "chant/".to_string());
65default_fn!(default_main_branch, String, "main".to_string());
66
67#[derive(Debug, Clone, Deserialize, Serialize)]
73pub struct LintThresholds {
74 #[serde(default = "default_complexity_criteria")]
76 pub complexity_criteria: usize,
77 #[serde(default = "default_complexity_files")]
79 pub complexity_files: usize,
80 #[serde(default = "default_complexity_words")]
82 pub complexity_words: usize,
83 #[serde(default = "default_simple_criteria")]
85 pub simple_criteria: usize,
86 #[serde(default = "default_simple_files")]
88 pub simple_files: usize,
89 #[serde(default = "default_simple_words")]
91 pub simple_words: usize,
92}
93
94impl Default for LintThresholds {
95 fn default() -> Self {
96 Self {
97 complexity_criteria: default_complexity_criteria(),
98 complexity_files: default_complexity_files(),
99 complexity_words: default_complexity_words(),
100 simple_criteria: default_simple_criteria(),
101 simple_files: default_simple_files(),
102 simple_words: default_simple_words(),
103 }
104 }
105}
106
107fn default_lint_disable() -> Vec<String> {
109 vec!["complexity_words".to_string()]
110}
111
112#[derive(Debug, Clone, Deserialize, Serialize)]
114pub struct LintConfig {
115 #[serde(default)]
117 pub thresholds: LintThresholds,
118 #[serde(default = "default_lint_disable")]
120 pub disable: Vec<String>,
121}
122
123impl Default for LintConfig {
124 fn default() -> Self {
125 Self {
126 thresholds: LintThresholds::default(),
127 disable: default_lint_disable(),
128 }
129 }
130}
131
132#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Deserialize, Serialize)]
134#[serde(rename_all = "lowercase")]
135pub enum OnPermanentFailure {
136 #[default]
138 Skip,
139 Stop,
141}
142
143#[derive(Debug, Clone, Deserialize, Serialize)]
145pub struct FailureConfig {
146 #[serde(default = "default_max_retries")]
148 pub max_retries: usize,
149 #[serde(default = "default_retry_delay_ms")]
151 pub retry_delay_ms: u64,
152 #[serde(default = "default_backoff_multiplier")]
154 pub backoff_multiplier: f64,
155 #[serde(default)]
157 pub retryable_patterns: Vec<String>,
158 #[serde(default)]
160 pub on_permanent_failure: OnPermanentFailure,
161}
162
163impl Default for FailureConfig {
164 fn default() -> Self {
165 Self {
166 max_retries: default_max_retries(),
167 retry_delay_ms: default_retry_delay_ms(),
168 backoff_multiplier: default_backoff_multiplier(),
169 retryable_patterns: vec![],
170 on_permanent_failure: OnPermanentFailure::default(),
171 }
172 }
173}
174
175#[derive(Debug, Clone, Deserialize, Serialize)]
177pub struct WatchConfig {
178 #[serde(default = "default_poll_interval_ms")]
180 pub poll_interval_ms: u64,
181 #[serde(default)]
183 pub failure: FailureConfig,
184 #[serde(default = "default_idle_timeout_minutes")]
186 pub idle_timeout_minutes: u64,
187}
188
189fn default_idle_timeout_minutes() -> u64 {
190 5
191}
192
193impl Default for WatchConfig {
194 fn default() -> Self {
195 Self {
196 poll_interval_ms: default_poll_interval_ms(),
197 failure: FailureConfig::default(),
198 idle_timeout_minutes: default_idle_timeout_minutes(),
199 }
200 }
201}
202
203#[derive(Debug, Clone, Deserialize, Serialize)]
205pub struct SiteIncludeConfig {
206 #[serde(default = "default_include_statuses")]
208 pub statuses: Vec<String>,
209 #[serde(default)]
211 pub labels: Vec<String>,
212}
213
214impl Default for SiteIncludeConfig {
215 fn default() -> Self {
216 Self {
217 statuses: default_include_statuses(),
218 labels: vec![],
219 }
220 }
221}
222
223#[derive(Debug, Clone, Deserialize, Serialize, Default)]
225pub struct SiteExcludeConfig {
226 #[serde(default)]
228 pub labels: Vec<String>,
229 #[serde(default)]
231 pub fields: Vec<String>,
232}
233
234#[derive(Debug, Clone, Deserialize, Serialize)]
236pub struct SiteFeaturesConfig {
237 #[serde(default = "default_true")]
239 pub changelog: bool,
240 #[serde(default = "default_true")]
242 pub dependency_graph: bool,
243 #[serde(default = "default_true")]
245 pub timeline: bool,
246 #[serde(default = "default_true")]
248 pub status_indexes: bool,
249 #[serde(default = "default_true")]
251 pub label_indexes: bool,
252}
253
254impl Default for SiteFeaturesConfig {
255 fn default() -> Self {
256 Self {
257 changelog: true,
258 dependency_graph: true,
259 timeline: true,
260 status_indexes: true,
261 label_indexes: true,
262 }
263 }
264}
265
266#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Deserialize, Serialize)]
268#[serde(rename_all = "lowercase")]
269pub enum GraphDetailLevel {
270 Minimal,
272 Titles,
274 #[default]
276 Full,
277}
278
279#[derive(Debug, Clone, Deserialize, Serialize)]
281pub struct SiteGraphConfig {
282 #[serde(default)]
284 pub detail: GraphDetailLevel,
285}
286
287impl Default for SiteGraphConfig {
288 fn default() -> Self {
289 Self {
290 detail: GraphDetailLevel::Full,
291 }
292 }
293}
294
295#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Deserialize, Serialize)]
297#[serde(rename_all = "lowercase")]
298pub enum TimelineGroupBy {
299 #[default]
301 Day,
302 Week,
304 Month,
306}
307
308#[derive(Debug, Clone, Deserialize, Serialize)]
310pub struct SiteTimelineConfig {
311 #[serde(default)]
313 pub group_by: TimelineGroupBy,
314 #[serde(default)]
316 pub include_pending: bool,
317}
318
319impl Default for SiteTimelineConfig {
320 fn default() -> Self {
321 Self {
322 group_by: TimelineGroupBy::Day,
323 include_pending: false,
324 }
325 }
326}
327
328#[derive(Debug, Clone, Deserialize, Serialize, Default)]
330pub struct SiteConfig {
331 #[serde(default = "default_site_output_dir")]
333 pub output_dir: String,
334 #[serde(default = "default_site_base_url")]
336 pub base_url: String,
337 #[serde(default = "default_site_title")]
339 pub title: String,
340 #[serde(default)]
342 pub include: SiteIncludeConfig,
343 #[serde(default)]
345 pub exclude: SiteExcludeConfig,
346 #[serde(default)]
348 pub features: SiteFeaturesConfig,
349 #[serde(default)]
351 pub graph: SiteGraphConfig,
352 #[serde(default)]
354 pub timeline: SiteTimelineConfig,
355}
356
357#[derive(Debug, Deserialize, Clone)]
359pub struct AgentConfig {
360 #[serde(default = "default_agent_name")]
362 pub name: String,
363 #[serde(default = "default_agent_command")]
365 pub command: String,
366 #[serde(default = "default_max_concurrent")]
368 pub max_concurrent: usize,
369 #[serde(default = "default_agent_weight")]
371 pub weight: usize,
372}
373
374impl Default for AgentConfig {
375 fn default() -> Self {
376 Self {
377 name: default_agent_name(),
378 command: default_agent_command(),
379 max_concurrent: default_max_concurrent(),
380 weight: default_agent_weight(),
381 }
382 }
383}
384
385#[derive(Debug, Deserialize, Clone)]
387pub struct ParallelConfig {
388 #[serde(default)]
390 pub agents: Vec<AgentConfig>,
391 #[serde(default = "default_stagger_delay_ms")]
393 pub stagger_delay_ms: u64,
394 #[serde(default = "default_stagger_jitter_ms")]
396 pub stagger_jitter_ms: u64,
397}
398
399impl ParallelConfig {
400 pub fn total_capacity(&self) -> usize {
402 self.agents.iter().map(|a| a.max_concurrent).sum()
403 }
404}
405
406impl Default for ParallelConfig {
407 fn default() -> Self {
408 Self {
409 agents: vec![AgentConfig::default()],
410 stagger_delay_ms: default_stagger_delay_ms(),
411 stagger_jitter_ms: default_stagger_jitter_ms(),
412 }
413 }
414}
415
416#[derive(Debug, Clone, Deserialize)]
417pub struct DefaultsConfig {
418 #[serde(default = "default_prompt")]
419 pub prompt: String,
420 #[serde(default = "default_branch_prefix")]
421 pub branch_prefix: String,
422 #[serde(default)]
424 pub model: Option<String>,
425 #[serde(default)]
427 pub split_model: Option<String>,
428 #[serde(default = "default_main_branch")]
430 pub main_branch: String,
431 #[serde(default)]
433 pub provider: ProviderType,
434 #[serde(default = "default_rotation_strategy_enum")]
436 pub rotation_strategy: RotationStrategy,
437 #[serde(default)]
439 pub prompt_extensions: Vec<String>,
440}
441
442impl Default for DefaultsConfig {
443 fn default() -> Self {
444 Self {
445 prompt: default_prompt(),
446 branch_prefix: default_branch_prefix(),
447 model: None,
448 split_model: None,
449 main_branch: default_main_branch(),
450 provider: ProviderType::Claude,
451 rotation_strategy: default_rotation_strategy_enum(),
452 prompt_extensions: vec![],
453 }
454 }
455}