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, 50);
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_cleanup_enabled, bool, true);
50default_fn!(
51 default_cleanup_prompt,
52 String,
53 "parallel-cleanup".to_string()
54);
55default_fn!(default_rotation_strategy, String, "none".to_string());
56default_fn!(default_prompt, String, "bootstrap".to_string());
57default_fn!(default_branch_prefix, String, "chant/".to_string());
58default_fn!(default_main_branch, String, "main".to_string());
59
60#[derive(Debug, Clone, Deserialize, Serialize)]
66pub struct LintThresholds {
67 #[serde(default = "default_complexity_criteria")]
69 pub complexity_criteria: usize,
70 #[serde(default = "default_complexity_files")]
72 pub complexity_files: usize,
73 #[serde(default = "default_complexity_words")]
75 pub complexity_words: usize,
76 #[serde(default = "default_simple_criteria")]
78 pub simple_criteria: usize,
79 #[serde(default = "default_simple_files")]
81 pub simple_files: usize,
82 #[serde(default = "default_simple_words")]
84 pub simple_words: usize,
85}
86
87impl Default for LintThresholds {
88 fn default() -> Self {
89 Self {
90 complexity_criteria: default_complexity_criteria(),
91 complexity_files: default_complexity_files(),
92 complexity_words: default_complexity_words(),
93 simple_criteria: default_simple_criteria(),
94 simple_files: default_simple_files(),
95 simple_words: default_simple_words(),
96 }
97 }
98}
99
100#[derive(Debug, Clone, Deserialize, Serialize, Default)]
102pub struct LintConfig {
103 #[serde(default)]
105 pub thresholds: LintThresholds,
106 #[serde(default)]
108 pub disable: Vec<String>,
109}
110
111#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Deserialize, Serialize)]
113#[serde(rename_all = "lowercase")]
114pub enum OnPermanentFailure {
115 #[default]
117 Skip,
118 Stop,
120}
121
122#[derive(Debug, Clone, Deserialize, Serialize)]
124pub struct FailureConfig {
125 #[serde(default = "default_max_retries")]
127 pub max_retries: usize,
128 #[serde(default = "default_retry_delay_ms")]
130 pub retry_delay_ms: u64,
131 #[serde(default = "default_backoff_multiplier")]
133 pub backoff_multiplier: f64,
134 #[serde(default)]
136 pub retryable_patterns: Vec<String>,
137 #[serde(default)]
139 pub on_permanent_failure: OnPermanentFailure,
140}
141
142impl Default for FailureConfig {
143 fn default() -> Self {
144 Self {
145 max_retries: default_max_retries(),
146 retry_delay_ms: default_retry_delay_ms(),
147 backoff_multiplier: default_backoff_multiplier(),
148 retryable_patterns: vec![],
149 on_permanent_failure: OnPermanentFailure::default(),
150 }
151 }
152}
153
154#[derive(Debug, Clone, Deserialize, Serialize)]
156pub struct WatchConfig {
157 #[serde(default = "default_poll_interval_ms")]
159 pub poll_interval_ms: u64,
160 #[serde(default)]
162 pub failure: FailureConfig,
163}
164
165impl Default for WatchConfig {
166 fn default() -> Self {
167 Self {
168 poll_interval_ms: default_poll_interval_ms(),
169 failure: FailureConfig::default(),
170 }
171 }
172}
173
174#[derive(Debug, Clone, Deserialize, Serialize)]
176pub struct SiteIncludeConfig {
177 #[serde(default = "default_include_statuses")]
179 pub statuses: Vec<String>,
180 #[serde(default)]
182 pub labels: Vec<String>,
183}
184
185impl Default for SiteIncludeConfig {
186 fn default() -> Self {
187 Self {
188 statuses: default_include_statuses(),
189 labels: vec![],
190 }
191 }
192}
193
194#[derive(Debug, Clone, Deserialize, Serialize, Default)]
196pub struct SiteExcludeConfig {
197 #[serde(default)]
199 pub labels: Vec<String>,
200 #[serde(default)]
202 pub fields: Vec<String>,
203}
204
205#[derive(Debug, Clone, Deserialize, Serialize)]
207pub struct SiteFeaturesConfig {
208 #[serde(default = "default_true")]
210 pub changelog: bool,
211 #[serde(default = "default_true")]
213 pub dependency_graph: bool,
214 #[serde(default = "default_true")]
216 pub timeline: bool,
217 #[serde(default = "default_true")]
219 pub status_indexes: bool,
220 #[serde(default = "default_true")]
222 pub label_indexes: bool,
223}
224
225impl Default for SiteFeaturesConfig {
226 fn default() -> Self {
227 Self {
228 changelog: true,
229 dependency_graph: true,
230 timeline: true,
231 status_indexes: true,
232 label_indexes: true,
233 }
234 }
235}
236
237#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Deserialize, Serialize)]
239#[serde(rename_all = "lowercase")]
240pub enum GraphDetailLevel {
241 Minimal,
243 Titles,
245 #[default]
247 Full,
248}
249
250#[derive(Debug, Clone, Deserialize, Serialize)]
252pub struct SiteGraphConfig {
253 #[serde(default)]
255 pub detail: GraphDetailLevel,
256}
257
258impl Default for SiteGraphConfig {
259 fn default() -> Self {
260 Self {
261 detail: GraphDetailLevel::Full,
262 }
263 }
264}
265
266#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Deserialize, Serialize)]
268#[serde(rename_all = "lowercase")]
269pub enum TimelineGroupBy {
270 #[default]
272 Day,
273 Week,
275 Month,
277}
278
279#[derive(Debug, Clone, Deserialize, Serialize)]
281pub struct SiteTimelineConfig {
282 #[serde(default)]
284 pub group_by: TimelineGroupBy,
285 #[serde(default)]
287 pub include_pending: bool,
288}
289
290impl Default for SiteTimelineConfig {
291 fn default() -> Self {
292 Self {
293 group_by: TimelineGroupBy::Day,
294 include_pending: false,
295 }
296 }
297}
298
299#[derive(Debug, Clone, Deserialize, Serialize, Default)]
301pub struct SiteConfig {
302 #[serde(default = "default_site_output_dir")]
304 pub output_dir: String,
305 #[serde(default = "default_site_base_url")]
307 pub base_url: String,
308 #[serde(default = "default_site_title")]
310 pub title: String,
311 #[serde(default)]
313 pub include: SiteIncludeConfig,
314 #[serde(default)]
316 pub exclude: SiteExcludeConfig,
317 #[serde(default)]
319 pub features: SiteFeaturesConfig,
320 #[serde(default)]
322 pub graph: SiteGraphConfig,
323 #[serde(default)]
325 pub timeline: SiteTimelineConfig,
326}
327
328#[derive(Debug, Deserialize, Clone)]
330pub struct AgentConfig {
331 #[serde(default = "default_agent_name")]
333 pub name: String,
334 #[serde(default = "default_agent_command")]
336 pub command: String,
337 #[serde(default = "default_max_concurrent")]
339 pub max_concurrent: usize,
340 #[serde(default = "default_agent_weight")]
342 pub weight: usize,
343}
344
345impl Default for AgentConfig {
346 fn default() -> Self {
347 Self {
348 name: default_agent_name(),
349 command: default_agent_command(),
350 max_concurrent: default_max_concurrent(),
351 weight: default_agent_weight(),
352 }
353 }
354}
355
356#[derive(Debug, Deserialize, Clone)]
358pub struct CleanupConfig {
359 #[serde(default = "default_cleanup_enabled")]
361 pub enabled: bool,
362 #[serde(default = "default_cleanup_prompt")]
364 pub prompt: String,
365 #[serde(default)]
367 pub auto_run: bool,
368}
369
370impl Default for CleanupConfig {
371 fn default() -> Self {
372 Self {
373 enabled: default_cleanup_enabled(),
374 prompt: default_cleanup_prompt(),
375 auto_run: false,
376 }
377 }
378}
379
380#[derive(Debug, Deserialize, Clone)]
382pub struct ParallelConfig {
383 #[serde(default)]
385 pub agents: Vec<AgentConfig>,
386 #[serde(default)]
388 pub cleanup: CleanupConfig,
389 #[serde(default = "default_stagger_delay_ms")]
391 pub stagger_delay_ms: u64,
392 #[serde(default = "default_stagger_jitter_ms")]
394 pub stagger_jitter_ms: u64,
395}
396
397impl ParallelConfig {
398 pub fn total_capacity(&self) -> usize {
400 self.agents.iter().map(|a| a.max_concurrent).sum()
401 }
402}
403
404impl Default for ParallelConfig {
405 fn default() -> Self {
406 Self {
407 agents: vec![AgentConfig::default()],
408 cleanup: CleanupConfig::default(),
409 stagger_delay_ms: default_stagger_delay_ms(),
410 stagger_jitter_ms: default_stagger_jitter_ms(),
411 }
412 }
413}
414
415#[derive(Debug, Clone, Deserialize)]
416pub struct DefaultsConfig {
417 #[serde(default = "default_prompt")]
418 pub prompt: String,
419 #[serde(default = "default_branch_prefix")]
420 pub branch_prefix: String,
421 #[serde(default)]
423 pub model: Option<String>,
424 #[serde(default)]
426 pub split_model: Option<String>,
427 #[serde(default = "default_main_branch")]
429 pub main_branch: String,
430 #[serde(default)]
432 pub provider: ProviderType,
433 #[serde(default = "default_rotation_strategy")]
435 pub rotation_strategy: String,
436 #[serde(default)]
438 pub prompt_extensions: Vec<String>,
439}
440
441impl Default for DefaultsConfig {
442 fn default() -> Self {
443 Self {
444 prompt: default_prompt(),
445 branch_prefix: default_branch_prefix(),
446 model: None,
447 split_model: None,
448 main_branch: default_main_branch(),
449 provider: ProviderType::Claude,
450 rotation_strategy: default_rotation_strategy(),
451 prompt_extensions: vec![],
452 }
453 }
454}