Skip to main content

ralph_workflow/config/
mod.rs

1//! Configuration Module
2//!
3//! Handles environment variables and configuration for Ralph.
4//!
5//! # Module Structure
6//!
7//! - [`types`]: Core configuration types (Config, `ReviewDepth`, Verbosity)
8//! - [`truncation`]: Truncation limits for verbosity levels
9//! - [`parser`]: Environment variable parsing (legacy)
10//! - [`unified`]: Unified configuration format types
11//! - [`loader`]: Unified configuration loader with env overrides
12//!
13//! # Configuration Sources
14//!
15//! Ralph configuration is loaded from (in order of priority):
16//! 1. `~/.config/ralph-workflow.toml` (primary, unified config)
17//! 2. Environment variables (RALPH_*) as overrides
18//! 3. CLI arguments (final override)
19//!
20//! # Usage
21//!
22//! ```ignore
23//! use crate::config::Config;
24//!
25//! let config = Config::from_env();
26//! println!("Developer iterations: {}", config.developer_iters);
27//! ```
28
29pub mod loader;
30pub mod parser;
31pub mod path_resolver;
32pub mod truncation;
33pub mod types;
34pub mod unified;
35
36// Re-export main types at module level for convenience
37pub use types::{Config, ReviewDepth, Verbosity};
38
39// Re-export unified config types for --init-global handling
40pub use unified::{
41    unified_config_path, CcsAliasConfig, CcsConfig, ConfigInitResult as UnifiedConfigInitResult,
42    UnifiedConfig,
43};
44
45// Re-export config environment types for dependency injection
46pub use path_resolver::{ConfigEnvironment, MemoryConfigEnvironment, RealConfigEnvironment};
47
48// Backward compatibility type aliases
49pub type ConfigPathResolver = dyn ConfigEnvironment;
50pub type RealConfigPathResolver = RealConfigEnvironment;
51pub type TestConfigPathResolver = MemoryConfigEnvironment;
52pub type MemoryConfigPathResolver = MemoryConfigEnvironment;
53
54#[cfg(test)]
55mod tests {
56    use super::*;
57
58    #[test]
59    fn test_verbosity_from_u8() {
60        assert_eq!(Verbosity::from(0), Verbosity::Quiet);
61        assert_eq!(Verbosity::from(1), Verbosity::Normal);
62        assert_eq!(Verbosity::from(2), Verbosity::Verbose);
63        assert_eq!(Verbosity::from(3), Verbosity::Full);
64        assert_eq!(Verbosity::from(4), Verbosity::Debug);
65        assert_eq!(Verbosity::from(100), Verbosity::Debug);
66    }
67
68    #[test]
69    fn test_truncate_limits() {
70        // Quiet has reduced limits
71        assert_eq!(Verbosity::Quiet.truncate_limit("text"), 80);
72        assert_eq!(Verbosity::Quiet.truncate_limit("tool_input"), 40);
73
74        // Normal has conservative limits for manageable output
75        assert_eq!(Verbosity::Normal.truncate_limit("text"), 1000);
76        assert_eq!(Verbosity::Normal.truncate_limit("tool_input"), 300);
77        assert_eq!(Verbosity::Normal.truncate_limit("tool_result"), 500);
78
79        // Verbose (default) has conservative limits for reasonable output
80        assert_eq!(Verbosity::Verbose.truncate_limit("text"), 2000);
81        assert_eq!(Verbosity::Verbose.truncate_limit("tool_input"), 300);
82        assert_eq!(Verbosity::Verbose.truncate_limit("tool_result"), 500);
83
84        // Full and Debug have unlimited
85        assert_eq!(Verbosity::Full.truncate_limit("text"), 999_999);
86        assert_eq!(Verbosity::Debug.truncate_limit("text"), 999_999);
87    }
88
89    #[test]
90    fn test_verbosity_helpers() {
91        assert!(!Verbosity::Quiet.is_debug());
92        assert!(!Verbosity::Normal.is_debug());
93        assert!(!Verbosity::Verbose.is_debug());
94        assert!(!Verbosity::Full.is_debug());
95        assert!(Verbosity::Debug.is_debug());
96
97        assert!(!Verbosity::Quiet.is_verbose());
98        assert!(!Verbosity::Normal.is_verbose());
99        assert!(Verbosity::Verbose.is_verbose());
100        assert!(Verbosity::Full.is_verbose());
101        assert!(Verbosity::Debug.is_verbose());
102
103        // show_tool_input: true for Normal and above, false for Quiet
104        assert!(!Verbosity::Quiet.show_tool_input());
105        assert!(Verbosity::Normal.show_tool_input());
106        assert!(Verbosity::Verbose.show_tool_input());
107        assert!(Verbosity::Full.show_tool_input());
108        assert!(Verbosity::Debug.show_tool_input());
109    }
110
111    #[test]
112    fn test_review_depth_from_str() {
113        // Standard aliases
114        assert_eq!(
115            ReviewDepth::from_str("standard"),
116            Some(ReviewDepth::Standard)
117        );
118        assert_eq!(
119            ReviewDepth::from_str("default"),
120            Some(ReviewDepth::Standard)
121        );
122        assert_eq!(ReviewDepth::from_str("normal"), Some(ReviewDepth::Standard));
123
124        // Comprehensive aliases
125        assert_eq!(
126            ReviewDepth::from_str("comprehensive"),
127            Some(ReviewDepth::Comprehensive)
128        );
129        assert_eq!(
130            ReviewDepth::from_str("thorough"),
131            Some(ReviewDepth::Comprehensive)
132        );
133        assert_eq!(
134            ReviewDepth::from_str("full"),
135            Some(ReviewDepth::Comprehensive)
136        );
137
138        // Security aliases
139        assert_eq!(
140            ReviewDepth::from_str("security"),
141            Some(ReviewDepth::Security)
142        );
143        assert_eq!(ReviewDepth::from_str("secure"), Some(ReviewDepth::Security));
144        assert_eq!(
145            ReviewDepth::from_str("security-focused"),
146            Some(ReviewDepth::Security)
147        );
148
149        // Incremental aliases
150        assert_eq!(
151            ReviewDepth::from_str("incremental"),
152            Some(ReviewDepth::Incremental)
153        );
154        assert_eq!(
155            ReviewDepth::from_str("diff"),
156            Some(ReviewDepth::Incremental)
157        );
158        assert_eq!(
159            ReviewDepth::from_str("changed"),
160            Some(ReviewDepth::Incremental)
161        );
162
163        // Case insensitivity
164        assert_eq!(
165            ReviewDepth::from_str("SECURITY"),
166            Some(ReviewDepth::Security)
167        );
168        assert_eq!(
169            ReviewDepth::from_str("Comprehensive"),
170            Some(ReviewDepth::Comprehensive)
171        );
172
173        // Invalid values
174        assert_eq!(ReviewDepth::from_str("invalid"), None);
175        assert_eq!(ReviewDepth::from_str(""), None);
176    }
177
178    #[test]
179    fn test_review_depth_default() {
180        assert_eq!(ReviewDepth::default(), ReviewDepth::Standard);
181    }
182
183    #[test]
184    fn test_review_depth_description() {
185        assert!(ReviewDepth::Standard.description().contains("Balanced"));
186        assert!(ReviewDepth::Comprehensive
187            .description()
188            .contains("In-depth"));
189        assert!(ReviewDepth::Security.description().contains("OWASP"));
190        assert!(ReviewDepth::Incremental.description().contains("git diff"));
191    }
192}