1use serde::{Deserialize, Serialize};
4
5use crate::provider::ProviderType;
6
7macro_rules! default_fn {
9 ($name:ident, $type:ty, $value:expr) => {
10 pub(crate) fn $name() -> $type {
11 $value
12 }
13 };
14}
15
16default_fn!(default_complexity_criteria, usize, 10);
21default_fn!(default_complexity_files, usize, 5);
22default_fn!(default_complexity_words, usize, 150);
23default_fn!(default_simple_criteria, usize, 1);
24default_fn!(default_simple_files, usize, 1);
25default_fn!(default_simple_words, usize, 3);
26default_fn!(default_max_retries, usize, 3);
27default_fn!(default_retry_delay_ms, u64, 60_000); default_fn!(default_backoff_multiplier, f64, 2.0);
29default_fn!(default_poll_interval_ms, u64, 5000); default_fn!(default_site_output_dir, String, "./public/".to_string());
31default_fn!(default_site_base_url, String, "/".to_string());
32default_fn!(default_site_title, String, "Project Specs".to_string());
33default_fn!(
34 default_include_statuses,
35 Vec<String>,
36 vec![
37 "completed".to_string(),
38 "in_progress".to_string(),
39 "pending".to_string(),
40 ]
41);
42default_fn!(default_true, bool, true);
43default_fn!(default_agent_weight, usize, 1);
44default_fn!(default_agent_name, String, "main".to_string());
45default_fn!(default_agent_command, String, "claude".to_string());
46default_fn!(default_max_concurrent, usize, 2);
47default_fn!(default_stagger_delay_ms, u64, 1000); default_fn!(default_stagger_jitter_ms, u64, 200); default_fn!(default_rotation_strategy, String, "none".to_string());
50default_fn!(default_prompt, String, "bootstrap".to_string());
51default_fn!(default_branch_prefix, String, "chant/".to_string());
52default_fn!(default_main_branch, String, "main".to_string());
53
54#[derive(Debug, Clone, Deserialize, Serialize)]
60pub struct LintThresholds {
61 #[serde(default = "default_complexity_criteria")]
63 pub complexity_criteria: usize,
64 #[serde(default = "default_complexity_files")]
66 pub complexity_files: usize,
67 #[serde(default = "default_complexity_words")]
69 pub complexity_words: usize,
70 #[serde(default = "default_simple_criteria")]
72 pub simple_criteria: usize,
73 #[serde(default = "default_simple_files")]
75 pub simple_files: usize,
76 #[serde(default = "default_simple_words")]
78 pub simple_words: usize,
79}
80
81impl Default for LintThresholds {
82 fn default() -> Self {
83 Self {
84 complexity_criteria: default_complexity_criteria(),
85 complexity_files: default_complexity_files(),
86 complexity_words: default_complexity_words(),
87 simple_criteria: default_simple_criteria(),
88 simple_files: default_simple_files(),
89 simple_words: default_simple_words(),
90 }
91 }
92}
93
94fn default_lint_disable() -> Vec<String> {
96 vec!["complexity_words".to_string()]
97}
98
99#[derive(Debug, Clone, Deserialize, Serialize)]
101pub struct LintConfig {
102 #[serde(default)]
104 pub thresholds: LintThresholds,
105 #[serde(default = "default_lint_disable")]
107 pub disable: Vec<String>,
108}
109
110impl Default for LintConfig {
111 fn default() -> Self {
112 Self {
113 thresholds: LintThresholds::default(),
114 disable: default_lint_disable(),
115 }
116 }
117}
118
119#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Deserialize, Serialize)]
121#[serde(rename_all = "lowercase")]
122pub enum OnPermanentFailure {
123 #[default]
125 Skip,
126 Stop,
128}
129
130#[derive(Debug, Clone, Deserialize, Serialize)]
132pub struct FailureConfig {
133 #[serde(default = "default_max_retries")]
135 pub max_retries: usize,
136 #[serde(default = "default_retry_delay_ms")]
138 pub retry_delay_ms: u64,
139 #[serde(default = "default_backoff_multiplier")]
141 pub backoff_multiplier: f64,
142 #[serde(default)]
144 pub retryable_patterns: Vec<String>,
145 #[serde(default)]
147 pub on_permanent_failure: OnPermanentFailure,
148}
149
150impl Default for FailureConfig {
151 fn default() -> Self {
152 Self {
153 max_retries: default_max_retries(),
154 retry_delay_ms: default_retry_delay_ms(),
155 backoff_multiplier: default_backoff_multiplier(),
156 retryable_patterns: vec![],
157 on_permanent_failure: OnPermanentFailure::default(),
158 }
159 }
160}
161
162#[derive(Debug, Clone, Deserialize, Serialize)]
164pub struct WatchConfig {
165 #[serde(default = "default_poll_interval_ms")]
167 pub poll_interval_ms: u64,
168 #[serde(default)]
170 pub failure: FailureConfig,
171 #[serde(default = "default_idle_timeout_minutes")]
173 pub idle_timeout_minutes: u64,
174}
175
176fn default_idle_timeout_minutes() -> u64 {
177 5
178}
179
180impl Default for WatchConfig {
181 fn default() -> Self {
182 Self {
183 poll_interval_ms: default_poll_interval_ms(),
184 failure: FailureConfig::default(),
185 idle_timeout_minutes: default_idle_timeout_minutes(),
186 }
187 }
188}
189
190#[derive(Debug, Clone, Deserialize, Serialize)]
192pub struct SiteIncludeConfig {
193 #[serde(default = "default_include_statuses")]
195 pub statuses: Vec<String>,
196 #[serde(default)]
198 pub labels: Vec<String>,
199}
200
201impl Default for SiteIncludeConfig {
202 fn default() -> Self {
203 Self {
204 statuses: default_include_statuses(),
205 labels: vec![],
206 }
207 }
208}
209
210#[derive(Debug, Clone, Deserialize, Serialize, Default)]
212pub struct SiteExcludeConfig {
213 #[serde(default)]
215 pub labels: Vec<String>,
216 #[serde(default)]
218 pub fields: Vec<String>,
219}
220
221#[derive(Debug, Clone, Deserialize, Serialize)]
223pub struct SiteFeaturesConfig {
224 #[serde(default = "default_true")]
226 pub changelog: bool,
227 #[serde(default = "default_true")]
229 pub dependency_graph: bool,
230 #[serde(default = "default_true")]
232 pub timeline: bool,
233 #[serde(default = "default_true")]
235 pub status_indexes: bool,
236 #[serde(default = "default_true")]
238 pub label_indexes: bool,
239}
240
241impl Default for SiteFeaturesConfig {
242 fn default() -> Self {
243 Self {
244 changelog: true,
245 dependency_graph: true,
246 timeline: true,
247 status_indexes: true,
248 label_indexes: true,
249 }
250 }
251}
252
253#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Deserialize, Serialize)]
255#[serde(rename_all = "lowercase")]
256pub enum GraphDetailLevel {
257 Minimal,
259 Titles,
261 #[default]
263 Full,
264}
265
266#[derive(Debug, Clone, Deserialize, Serialize)]
268pub struct SiteGraphConfig {
269 #[serde(default)]
271 pub detail: GraphDetailLevel,
272}
273
274impl Default for SiteGraphConfig {
275 fn default() -> Self {
276 Self {
277 detail: GraphDetailLevel::Full,
278 }
279 }
280}
281
282#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Deserialize, Serialize)]
284#[serde(rename_all = "lowercase")]
285pub enum TimelineGroupBy {
286 #[default]
288 Day,
289 Week,
291 Month,
293}
294
295#[derive(Debug, Clone, Deserialize, Serialize)]
297pub struct SiteTimelineConfig {
298 #[serde(default)]
300 pub group_by: TimelineGroupBy,
301 #[serde(default)]
303 pub include_pending: bool,
304}
305
306impl Default for SiteTimelineConfig {
307 fn default() -> Self {
308 Self {
309 group_by: TimelineGroupBy::Day,
310 include_pending: false,
311 }
312 }
313}
314
315#[derive(Debug, Clone, Deserialize, Serialize, Default)]
317pub struct SiteConfig {
318 #[serde(default = "default_site_output_dir")]
320 pub output_dir: String,
321 #[serde(default = "default_site_base_url")]
323 pub base_url: String,
324 #[serde(default = "default_site_title")]
326 pub title: String,
327 #[serde(default)]
329 pub include: SiteIncludeConfig,
330 #[serde(default)]
332 pub exclude: SiteExcludeConfig,
333 #[serde(default)]
335 pub features: SiteFeaturesConfig,
336 #[serde(default)]
338 pub graph: SiteGraphConfig,
339 #[serde(default)]
341 pub timeline: SiteTimelineConfig,
342}
343
344#[derive(Debug, Deserialize, Clone)]
346pub struct AgentConfig {
347 #[serde(default = "default_agent_name")]
349 pub name: String,
350 #[serde(default = "default_agent_command")]
352 pub command: String,
353 #[serde(default = "default_max_concurrent")]
355 pub max_concurrent: usize,
356 #[serde(default = "default_agent_weight")]
358 pub weight: usize,
359}
360
361impl Default for AgentConfig {
362 fn default() -> Self {
363 Self {
364 name: default_agent_name(),
365 command: default_agent_command(),
366 max_concurrent: default_max_concurrent(),
367 weight: default_agent_weight(),
368 }
369 }
370}
371
372#[derive(Debug, Deserialize, Clone)]
374pub struct ParallelConfig {
375 #[serde(default)]
377 pub agents: Vec<AgentConfig>,
378 #[serde(default = "default_stagger_delay_ms")]
380 pub stagger_delay_ms: u64,
381 #[serde(default = "default_stagger_jitter_ms")]
383 pub stagger_jitter_ms: u64,
384}
385
386impl ParallelConfig {
387 pub fn total_capacity(&self) -> usize {
389 self.agents.iter().map(|a| a.max_concurrent).sum()
390 }
391}
392
393impl Default for ParallelConfig {
394 fn default() -> Self {
395 Self {
396 agents: vec![AgentConfig::default()],
397 stagger_delay_ms: default_stagger_delay_ms(),
398 stagger_jitter_ms: default_stagger_jitter_ms(),
399 }
400 }
401}
402
403#[derive(Debug, Clone, Deserialize)]
404pub struct DefaultsConfig {
405 #[serde(default = "default_prompt")]
406 pub prompt: String,
407 #[serde(default = "default_branch_prefix")]
408 pub branch_prefix: String,
409 #[serde(default)]
411 pub model: Option<String>,
412 #[serde(default)]
414 pub split_model: Option<String>,
415 #[serde(default = "default_main_branch")]
417 pub main_branch: String,
418 #[serde(default)]
420 pub provider: ProviderType,
421 #[serde(default = "default_rotation_strategy")]
423 pub rotation_strategy: String,
424 #[serde(default)]
426 pub prompt_extensions: Vec<String>,
427}
428
429impl Default for DefaultsConfig {
430 fn default() -> Self {
431 Self {
432 prompt: default_prompt(),
433 branch_prefix: default_branch_prefix(),
434 model: None,
435 split_model: None,
436 main_branch: default_main_branch(),
437 provider: ProviderType::Claude,
438 rotation_strategy: default_rotation_strategy(),
439 prompt_extensions: vec![],
440 }
441 }
442}