use crate::{CodememError, GraphConfig, ScoringWeights, VectorConfig};
use serde::{Deserialize, Serialize};
use std::path::{Path, PathBuf};
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(default)]
pub struct CodememConfig {
pub scoring: ScoringWeights,
pub vector: VectorConfig,
pub graph: GraphConfig,
pub embedding: EmbeddingConfig,
pub storage: StorageConfig,
pub chunking: ChunkingConfig,
pub enrichment: EnrichmentConfig,
}
impl CodememConfig {
pub fn load(path: &Path) -> Result<Self, CodememError> {
let content = std::fs::read_to_string(path)?;
toml::from_str(&content).map_err(|e| CodememError::Config(e.to_string()))
}
pub fn save(&self, path: &Path) -> Result<(), CodememError> {
let content =
toml::to_string_pretty(self).map_err(|e| CodememError::Config(e.to_string()))?;
if let Some(parent) = path.parent() {
std::fs::create_dir_all(parent)?;
}
std::fs::write(path, content)?;
Ok(())
}
pub fn load_or_default() -> Self {
let path = Self::default_path();
if path.exists() {
Self::load(&path).unwrap_or_default()
} else {
Self::default()
}
}
pub fn default_path() -> PathBuf {
dirs::home_dir()
.unwrap_or_else(|| PathBuf::from("."))
.join(".codemem")
.join("config.toml")
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(default)]
pub struct EmbeddingConfig {
pub provider: String,
pub model: String,
pub url: String,
pub dimensions: usize,
pub cache_capacity: usize,
}
impl Default for EmbeddingConfig {
fn default() -> Self {
Self {
provider: "candle".to_string(),
model: "BAAI/bge-base-en-v1.5".to_string(),
url: String::new(),
dimensions: 768,
cache_capacity: 10_000,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(default)]
pub struct StorageConfig {
pub db_path: String,
pub cache_size_mb: u32,
pub busy_timeout_secs: u64,
}
impl Default for StorageConfig {
fn default() -> Self {
Self {
db_path: dirs::home_dir()
.unwrap_or_else(|| PathBuf::from("."))
.join(".codemem")
.join("codemem.db")
.to_string_lossy()
.into_owned(),
cache_size_mb: 64,
busy_timeout_secs: 5,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(default)]
pub struct ChunkingConfig {
pub enabled: bool,
pub max_chunk_size: usize,
pub min_chunk_size: usize,
pub auto_compact: bool,
pub max_retained_chunks_per_file: usize,
pub min_chunk_score_threshold: f64,
pub max_retained_symbols_per_file: usize,
pub min_symbol_score_threshold: f64,
}
impl Default for ChunkingConfig {
fn default() -> Self {
Self {
enabled: true,
max_chunk_size: 1500,
min_chunk_size: 50,
auto_compact: true,
max_retained_chunks_per_file: 10,
min_chunk_score_threshold: 0.2,
max_retained_symbols_per_file: 15,
min_symbol_score_threshold: 0.15,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(default)]
pub struct EnrichmentConfig {
pub git_min_commit_count: usize,
pub git_min_co_change_count: usize,
pub perf_min_coupling_degree: usize,
pub perf_min_symbol_count: usize,
pub insight_confidence: f64,
pub dedup_similarity_threshold: f64,
}
impl Default for EnrichmentConfig {
fn default() -> Self {
Self {
git_min_commit_count: 25,
git_min_co_change_count: 5,
perf_min_coupling_degree: 25,
perf_min_symbol_count: 30,
insight_confidence: 0.5,
dedup_similarity_threshold: 0.90,
}
}
}
#[cfg(test)]
#[path = "tests/config_tests.rs"]
mod tests;