1use serde::{Deserialize, Serialize};
2use std::path::PathBuf;
3
4#[derive(Debug, Clone, Serialize, Deserialize)]
5#[serde(default)]
6pub struct Config {
7 pub ultra_compact: bool,
8 pub tee_on_error: bool,
9 pub checkpoint_interval: u32,
10 pub excluded_commands: Vec<String>,
11 pub custom_aliases: Vec<AliasEntry>,
12 pub slow_command_threshold_ms: u64,
15 #[serde(default)]
16 pub cloud: CloudConfig,
17}
18
19#[derive(Debug, Clone, Serialize, Deserialize, Default)]
20#[serde(default)]
21pub struct CloudConfig {
22 pub contribute_enabled: bool,
23 pub last_contribute: Option<String>,
24 pub last_sync: Option<String>,
25 pub last_model_pull: Option<String>,
26}
27
28#[derive(Debug, Clone, Serialize, Deserialize)]
29pub struct AliasEntry {
30 pub command: String,
31 pub alias: String,
32}
33
34impl Default for Config {
35 fn default() -> Self {
36 Self {
37 ultra_compact: false,
38 tee_on_error: false,
39 checkpoint_interval: 15,
40 excluded_commands: Vec::new(),
41 custom_aliases: Vec::new(),
42 slow_command_threshold_ms: 5000,
43 cloud: CloudConfig::default(),
44 }
45 }
46}
47
48impl Config {
49 pub fn path() -> Option<PathBuf> {
50 dirs::home_dir().map(|h| h.join(".lean-ctx").join("config.toml"))
51 }
52
53 pub fn load() -> Self {
54 let path = match Self::path() {
55 Some(p) => p,
56 None => return Self::default(),
57 };
58 match std::fs::read_to_string(&path) {
59 Ok(content) => toml::from_str(&content).unwrap_or_default(),
60 Err(_) => Self::default(),
61 }
62 }
63
64 pub fn save(&self) -> Result<(), String> {
65 let path = Self::path().ok_or("cannot determine home directory")?;
66 if let Some(parent) = path.parent() {
67 std::fs::create_dir_all(parent).map_err(|e| e.to_string())?;
68 }
69 let content = toml::to_string_pretty(self).map_err(|e| e.to_string())?;
70 std::fs::write(&path, content).map_err(|e| e.to_string())
71 }
72
73 pub fn show(&self) -> String {
74 let path = Self::path()
75 .map(|p| p.to_string_lossy().to_string())
76 .unwrap_or_else(|| "~/.lean-ctx/config.toml".to_string());
77 let content = toml::to_string_pretty(self).unwrap_or_default();
78 format!("Config: {path}\n\n{content}")
79 }
80}