1use crate::{CodememError, GraphConfig, ScoringWeights, VectorConfig};
6use serde::{Deserialize, Serialize};
7use std::path::{Path, PathBuf};
8
9#[derive(Debug, Clone, Default, Serialize, Deserialize)]
11#[serde(default)]
12pub struct CodememConfig {
13 pub scoring: ScoringWeights,
14 pub vector: VectorConfig,
15 pub graph: GraphConfig,
16 pub embedding: EmbeddingConfig,
17 pub storage: StorageConfig,
18 pub chunking: ChunkingConfig,
19 pub enrichment: EnrichmentConfig,
20}
21
22impl CodememConfig {
23 pub fn load(path: &Path) -> Result<Self, CodememError> {
25 let content = std::fs::read_to_string(path)?;
26 toml::from_str(&content).map_err(|e| CodememError::Config(e.to_string()))
27 }
28
29 pub fn save(&self, path: &Path) -> Result<(), CodememError> {
31 let content =
32 toml::to_string_pretty(self).map_err(|e| CodememError::Config(e.to_string()))?;
33 if let Some(parent) = path.parent() {
34 std::fs::create_dir_all(parent)?;
35 }
36 std::fs::write(path, content)?;
37 Ok(())
38 }
39
40 pub fn load_or_default() -> Self {
42 let path = Self::default_path();
43 if path.exists() {
44 Self::load(&path).unwrap_or_default()
45 } else {
46 Self::default()
47 }
48 }
49
50 pub fn default_path() -> PathBuf {
52 dirs::home_dir()
53 .unwrap_or_else(|| PathBuf::from("."))
54 .join(".codemem")
55 .join("config.toml")
56 }
57}
58
59#[derive(Debug, Clone, Serialize, Deserialize)]
61#[serde(default)]
62pub struct EmbeddingConfig {
63 pub provider: String,
65 pub model: String,
67 pub url: String,
69 pub dimensions: usize,
71 pub cache_capacity: usize,
73}
74
75impl Default for EmbeddingConfig {
76 fn default() -> Self {
77 Self {
78 provider: "candle".to_string(),
79 model: "BAAI/bge-base-en-v1.5".to_string(),
80 url: String::new(),
81 dimensions: 768,
82 cache_capacity: 10_000,
83 }
84 }
85}
86
87#[derive(Debug, Clone, Serialize, Deserialize)]
89#[serde(default)]
90pub struct StorageConfig {
91 pub db_path: String,
93 pub cache_size_mb: u32,
95 pub busy_timeout_secs: u64,
97}
98
99impl Default for StorageConfig {
100 fn default() -> Self {
101 Self {
102 db_path: dirs::home_dir()
103 .unwrap_or_else(|| PathBuf::from("."))
104 .join(".codemem")
105 .join("codemem.db")
106 .to_string_lossy()
107 .into_owned(),
108 cache_size_mb: 64,
109 busy_timeout_secs: 5,
110 }
111 }
112}
113
114#[derive(Debug, Clone, Serialize, Deserialize)]
116#[serde(default)]
117pub struct ChunkingConfig {
118 pub enabled: bool,
120 pub max_chunk_size: usize,
122 pub min_chunk_size: usize,
124 pub auto_compact: bool,
126 pub max_retained_chunks_per_file: usize,
128 pub min_chunk_score_threshold: f64,
130 pub max_retained_symbols_per_file: usize,
132 pub min_symbol_score_threshold: f64,
134}
135
136impl Default for ChunkingConfig {
137 fn default() -> Self {
138 Self {
139 enabled: true,
140 max_chunk_size: 1500,
141 min_chunk_size: 50,
142 auto_compact: true,
143 max_retained_chunks_per_file: 10,
144 min_chunk_score_threshold: 0.2,
145 max_retained_symbols_per_file: 15,
146 min_symbol_score_threshold: 0.15,
147 }
148 }
149}
150
151#[derive(Debug, Clone, Serialize, Deserialize)]
153#[serde(default)]
154pub struct EnrichmentConfig {
155 pub git_min_commit_count: usize,
157 pub git_min_co_change_count: usize,
159 pub perf_min_coupling_degree: usize,
161 pub perf_min_symbol_count: usize,
163 pub insight_confidence: f64,
165 pub dedup_similarity_threshold: f64,
167}
168
169impl Default for EnrichmentConfig {
170 fn default() -> Self {
171 Self {
172 git_min_commit_count: 25,
173 git_min_co_change_count: 5,
174 perf_min_coupling_degree: 25,
175 perf_min_symbol_count: 30,
176 insight_confidence: 0.5,
177 dedup_similarity_threshold: 0.90,
178 }
179 }
180}
181
182#[cfg(test)]
183#[path = "tests/config_tests.rs"]
184mod tests;