doum_cli/core/
config.rs

1use crate::system::{get_config_path, load_config, load_default_config, save_config};
2use anyhow::Result;
3
4pub struct ConfigManager;
5
6impl ConfigManager {
7    /// Get config value by key
8    pub fn get_value(key: &str) -> Result<String> {
9        let config = load_config()?;
10
11        let value = match key {
12            "llm.provider" => config.llm.provider,
13            "llm.model" => config.llm.model,
14            "llm.timeout" => config.llm.timeout.to_string(),
15            "llm.max_retries" => config.llm.max_retries.to_string(),
16            "llm.use_thinking" => config.llm.use_thinking.to_string(),
17            "llm.use_web_search" => config.llm.use_web_search.to_string(),
18            "context.max_lines" => config.context.max_lines.to_string(),
19            "context.max_size_kb" => config.context.max_size_kb.to_string(),
20            "logging.enabled" => config.logging.enabled.to_string(),
21            "logging.level" => config.logging.level,
22            _ => {
23                anyhow::bail!("Unknown config key: {}", key);
24            }
25        };
26
27        Ok(value)
28    }
29
30    /// Set config value by key
31    pub fn set_value(key: &str, value: &str) -> Result<()> {
32        let mut config = load_config()?;
33
34        match key {
35            "llm.provider" => {
36                Self::validate_provider(value)?;
37                config.llm.provider = value.to_string();
38            }
39            "llm.model" => {
40                config.llm.model = value.to_string();
41            }
42            "llm.timeout" => {
43                config.llm.timeout = Self::parse_value(value, "timeout")?;
44            }
45            "llm.max_retries" => {
46                config.llm.max_retries = Self::parse_value(value, "max_retries")?;
47            }
48            "llm.use_thinking" => {
49                config.llm.use_thinking = Self::parse_value(value, "use_thinking")?;
50            }
51            "llm.use_web_search" => {
52                config.llm.use_web_search = Self::parse_value(value, "use_web_search")?;
53            }
54            "context.max_lines" => {
55                config.context.max_lines = Self::parse_value(value, "max_lines")?;
56            }
57            "context.max_size_kb" => {
58                config.context.max_size_kb = Self::parse_value(value, "max_size_kb")?;
59            }
60            "logging.enabled" => {
61                config.logging.enabled = Self::parse_value(value, "logging.enabled")?;
62            }
63            "logging.level" => {
64                config.logging.level = value.to_string();
65            }
66            _ => {
67                anyhow::bail!("Unknown config key: {}", key);
68            }
69        }
70
71        save_config(&config)?;
72        Ok(())
73    }
74
75    /// Reset config to defaults
76    pub fn reset() -> Result<()> {
77        let default_config = load_default_config()?;
78        save_config(&default_config)
79    }
80
81    /// Unset a key (restore to default)
82    pub fn unset_value(key: &str) -> Result<()> {
83        let default_config = load_default_config()?;
84        let mut config = load_config()?;
85
86        match key {
87            "llm.provider" => config.llm.provider = default_config.llm.provider,
88            "llm.model" => config.llm.model = default_config.llm.model,
89            "llm.timeout" => config.llm.timeout = default_config.llm.timeout,
90            "llm.max_retries" => config.llm.max_retries = default_config.llm.max_retries,
91            "llm.use_thinking" => config.llm.use_thinking = default_config.llm.use_thinking,
92            "llm.use_web_search" => config.llm.use_web_search = default_config.llm.use_web_search,
93            "context.max_lines" => config.context.max_lines = default_config.context.max_lines,
94            "context.max_size_kb" => {
95                config.context.max_size_kb = default_config.context.max_size_kb
96            }
97            "logging.enabled" => config.logging.enabled = default_config.logging.enabled,
98            "logging.level" => config.logging.level = default_config.logging.level,
99            _ => {
100                anyhow::bail!("Unknown config key: {}", key);
101            }
102        }
103
104        save_config(&config)?;
105        Ok(())
106    }
107
108    /// Get all config as TOML string
109    pub fn get_all_as_toml() -> Result<String> {
110        let config = load_config()?;
111        toml::to_string_pretty(&config)
112            .map_err(|e| anyhow::anyhow!("Failed to serialize config to TOML: {}", e))
113    }
114
115    /// Get config file path
116    pub fn get_config_path() -> Result<std::path::PathBuf> {
117        get_config_path()
118    }
119
120    // Private helpers
121    fn validate_provider(provider: &str) -> Result<()> {
122        if provider != "openai" && provider != "anthropic" {
123            anyhow::bail!(
124                "Invalid provider: {}. Available: openai, anthropic",
125                provider
126            );
127        }
128        Ok(())
129    }
130
131    fn parse_value<T: std::str::FromStr>(value: &str, field_name: &str) -> Result<T>
132    where
133        T::Err: std::fmt::Display,
134    {
135        value
136            .parse()
137            .map_err(|e| anyhow::anyhow!("Invalid {} value: {} - {}", field_name, value, e))
138    }
139}