use serde::{Deserialize, Serialize};
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum PresetType {
Quick,
Rapid,
Long,
Standard,
Thorough,
}
impl PresetType {
#[must_use]
pub const fn iteration_counts(self) -> (u32, u32) {
match self {
Self::Quick => (1, 1),
Self::Rapid => (2, 1),
Self::Long => (15, 10),
Self::Standard => (5, 2),
Self::Thorough => (10, 5),
}
}
#[must_use]
pub const fn developer_iters(self) -> u32 {
self.iteration_counts().0
}
#[must_use]
pub const fn reviewer_reviews(self) -> u32 {
self.iteration_counts().1
}
}
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct CliState {
pub verbosity: Option<u8>,
pub quiet_mode: bool,
pub full_mode: bool,
pub debug_mode: bool,
pub preset_applied: Option<PresetType>,
pub developer_iters: Option<u32>,
pub reviewer_reviews: Option<u32>,
pub developer_agent: Option<String>,
pub reviewer_agent: Option<String>,
pub developer_model: Option<String>,
pub reviewer_model: Option<String>,
pub developer_provider: Option<String>,
pub reviewer_provider: Option<String>,
pub reviewer_json_parser: Option<String>,
pub isolation_mode: Option<bool>,
pub review_depth: Option<String>,
pub git_user_name: Option<String>,
pub git_user_email: Option<String>,
pub streaming_metrics: bool,
pub agent_preset: Option<String>,
pub complete: bool,
}
impl CliState {
#[must_use]
pub fn initial() -> Self {
Self::default()
}
#[must_use]
pub fn resolved_developer_iters(&self, config_default: u32) -> u32 {
self.developer_iters.unwrap_or_else(|| {
self.preset_applied
.map_or(config_default, PresetType::developer_iters)
})
}
#[must_use]
pub fn resolved_reviewer_reviews(&self, config_default: u32) -> u32 {
self.reviewer_reviews.unwrap_or_else(|| {
self.preset_applied
.map_or(config_default, PresetType::reviewer_reviews)
})
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_preset_iteration_counts() {
assert_eq!(PresetType::Quick.iteration_counts(), (1, 1));
assert_eq!(PresetType::Rapid.iteration_counts(), (2, 1));
assert_eq!(PresetType::Long.iteration_counts(), (15, 10));
assert_eq!(PresetType::Standard.iteration_counts(), (5, 2));
assert_eq!(PresetType::Thorough.iteration_counts(), (10, 5));
}
#[test]
fn test_preset_individual_accessors() {
assert_eq!(PresetType::Quick.developer_iters(), 1);
assert_eq!(PresetType::Quick.reviewer_reviews(), 1);
assert_eq!(PresetType::Long.developer_iters(), 15);
assert_eq!(PresetType::Long.reviewer_reviews(), 10);
}
#[test]
fn test_initial_state() {
let state = CliState::initial();
assert!(!state.complete);
assert!(state.preset_applied.is_none());
assert!(state.developer_iters.is_none());
assert!(state.reviewer_reviews.is_none());
assert!(!state.quiet_mode);
assert!(!state.streaming_metrics);
}
#[test]
fn test_resolved_iters_explicit_override() {
let state = CliState {
preset_applied: Some(PresetType::Quick),
developer_iters: Some(10),
reviewer_reviews: Some(5),
..CliState::initial()
};
assert_eq!(state.resolved_developer_iters(99), 10);
assert_eq!(state.resolved_reviewer_reviews(99), 5);
}
#[test]
fn test_resolved_iters_preset_fallback() {
let state = CliState {
preset_applied: Some(PresetType::Long),
..CliState::initial()
};
assert_eq!(state.resolved_developer_iters(99), 15);
assert_eq!(state.resolved_reviewer_reviews(99), 10);
}
#[test]
fn test_resolved_iters_config_fallback() {
let state = CliState::initial();
assert_eq!(state.resolved_developer_iters(5), 5);
assert_eq!(state.resolved_reviewer_reviews(2), 2);
}
#[test]
fn test_state_serialization() {
let state = CliState {
preset_applied: Some(PresetType::Thorough),
developer_agent: Some("claude".to_string()),
..CliState::initial()
};
let json = serde_json::to_string(&state).unwrap();
let deserialized: CliState = serde_json::from_str(&json).unwrap();
assert_eq!(state.preset_applied, deserialized.preset_applied);
assert_eq!(state.developer_agent, deserialized.developer_agent);
}
}