ralph_workflow/cli/
presets.rs

1//! Preset configurations for common agent combinations.
2//!
3//! Presets allow users to quickly configure Ralph for common use cases
4//! without specifying individual agent options.
5
6use crate::config::{Config, ReviewDepth};
7use crate::logger::Colors;
8use clap::ValueEnum;
9
10/// Preset configurations for common agent combinations.
11#[derive(Clone, Debug, ValueEnum)]
12pub enum Preset {
13    /// Use `agent_chain` defaults (no explicit agent override)
14    Default,
15    /// Use opencode for both developer and reviewer
16    Opencode,
17}
18
19/// Apply CLI arguments to the configuration.
20///
21/// This function merges CLI arguments into the existing config, handling:
22/// - Verbosity flags (--quiet, --full, --debug, -v LEVEL)
23/// - Preset configurations (--preset)
24/// - Quick mode (--quick)
25/// - Agent and model overrides
26/// - Isolation mode
27pub fn apply_args_to_config(args: &super::Args, config: &mut Config, colors: Colors) {
28    // Handle verbosity shorthand flags (--quiet, --full, --debug take precedence)
29    let base_verbosity = config.verbosity;
30    config.verbosity = if args.verbosity_shorthand.quiet {
31        crate::config::Verbosity::Quiet
32    } else if args.debug_verbosity.debug {
33        crate::config::Verbosity::Debug
34    } else if args.verbosity_shorthand.full {
35        crate::config::Verbosity::Full
36    } else if let Some(v) = args.verbosity {
37        v.into()
38    } else {
39        base_verbosity
40    };
41
42    // Apply preset (CLI/env preset overrides env-selected agents, but can be overridden by
43    // explicit --developer-agent/--reviewer-agent flags below).
44    if let Some(preset) = args.preset.clone() {
45        match preset {
46            Preset::Default => {
47                // No override; use agent_chain defaults from the unified config / built-ins
48            }
49            Preset::Opencode => {
50                config.developer_agent = Some("opencode".to_string());
51                config.reviewer_agent = Some("opencode".to_string());
52            }
53        }
54    }
55
56    // Quick mode: 1 developer iteration, 1 review pass (explicit flags override)
57    if args.quick_presets.quick {
58        if args.developer_iters.is_none() {
59            config.developer_iters = 1;
60        }
61        if args.reviewer_reviews.is_none() {
62            config.reviewer_reviews = 1;
63        }
64    }
65
66    // Rapid mode: 2 developer iterations, 1 review pass (explicit flags override)
67    if args.quick_presets.rapid {
68        if args.developer_iters.is_none() {
69            config.developer_iters = 2;
70        }
71        if args.reviewer_reviews.is_none() {
72            config.reviewer_reviews = 1;
73        }
74    }
75
76    if let Some(iters) = args.developer_iters {
77        config.developer_iters = iters;
78    }
79    if let Some(reviews) = args.reviewer_reviews {
80        config.reviewer_reviews = reviews;
81    }
82    if let Some(agent) = args.developer_agent.clone() {
83        config.developer_agent = Some(agent);
84    }
85    if let Some(agent) = args.reviewer_agent.clone() {
86        config.reviewer_agent = Some(agent);
87    }
88    if let Some(model) = args.developer_model.clone() {
89        config.developer_model = Some(model);
90    }
91    if let Some(model) = args.reviewer_model.clone() {
92        config.reviewer_model = Some(model);
93    }
94    if let Some(provider) = args.developer_provider.clone() {
95        config.developer_provider = Some(provider);
96    }
97    if let Some(provider) = args.reviewer_provider.clone() {
98        config.reviewer_provider = Some(provider);
99    }
100    if let Some(parser) = args.reviewer_json_parser.clone() {
101        config.reviewer_json_parser = Some(parser);
102    }
103    if let Some(depth) = args.review_depth.clone() {
104        if let Some(parsed) = ReviewDepth::from_str(&depth) {
105            config.review_depth = parsed;
106        } else {
107            eprintln!(
108                "{}{}Warning:{} Unknown review depth '{}'. Using default (standard).",
109                colors.bold(),
110                colors.yellow(),
111                colors.reset(),
112                depth
113            );
114            eprintln!("Valid options: standard, comprehensive, security, incremental");
115        }
116    }
117
118    // Handle --no-isolation flag (CLI overrides env var)
119    if args.no_isolation {
120        config.isolation_mode = false;
121    }
122
123    // Git user identity (CLI args have highest priority)
124    if let Some(name) = args.git_user_name.clone() {
125        let name = name.trim();
126        if !name.is_empty() {
127            config.git_user_name = Some(name.to_string());
128        }
129    }
130    if let Some(email) = args.git_user_email.clone() {
131        let email = email.trim();
132        if !email.is_empty() {
133            config.git_user_email = Some(email.to_string());
134        }
135    }
136
137    // Streaming metrics display flag
138    if args.show_streaming_metrics {
139        config.show_streaming_metrics = true;
140    }
141}