use std::path::PathBuf;
use super::Config;
const LOCAL_OVERRIDABLE_KEYS: &[&str] = &["compression_level", "terse_agent", "tool_profile"];
const ENV_OVERRIDABLE: &[(&str, &str)] = &[
("compression_level", "LEAN_CTX_COMPRESSION"),
("terse_agent", "LEAN_CTX_TERSE_AGENT"),
("tool_profile", "LEAN_CTX_TOOL_PROFILE"),
("structure_first", "LEAN_CTX_STRUCTURE_FIRST"),
];
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct EnvOverride {
pub setting: &'static str,
pub var: &'static str,
}
#[derive(Debug, Clone)]
pub struct ConfigProvenance {
pub config_path: Option<PathBuf>,
pub config_exists: bool,
pub xdg_pinned: bool,
pub parse_error: Option<String>,
pub local_path: Option<PathBuf>,
pub local_exists: bool,
pub local_keys: Vec<&'static str>,
pub env_overrides: Vec<EnvOverride>,
}
impl ConfigProvenance {
#[must_use]
pub fn has_shadow(&self) -> bool {
!self.env_overrides.is_empty() || !self.local_keys.is_empty() || self.parse_error.is_some()
}
#[must_use]
#[allow(clippy::manual_contains)]
pub fn local_overrides(&self, setting: &str) -> bool {
self.local_keys.iter().any(|k| *k == setting)
}
}
impl Config {
#[must_use]
pub fn provenance() -> ConfigProvenance {
let config_path = Self::path();
let config_exists = config_path.as_ref().is_some_and(|p| p.exists());
let parse_error = config_path.as_ref().and_then(|p| {
let raw = std::fs::read_to_string(p).ok()?;
toml::from_str::<Config>(&raw).err().map(|e| e.to_string())
});
let local_path = Self::find_project_root().map(|r| Self::local_path(&r));
let local_content = local_path
.as_ref()
.filter(|p| crate::core::pathutil::may_probe_path(p.as_path()))
.and_then(|p| std::fs::read_to_string(p).ok());
let local_exists = local_content.is_some();
let local_keys = local_content
.as_deref()
.map(local_override_keys)
.unwrap_or_default();
let env_overrides = ENV_OVERRIDABLE
.iter()
.filter(|(_, var)| env_is_set(var))
.map(|&(setting, var)| EnvOverride { setting, var })
.collect();
ConfigProvenance {
config_path,
config_exists,
xdg_pinned: crate::core::layout_pin::is_xdg_pinned(),
parse_error,
local_path,
local_exists,
local_keys,
env_overrides,
}
}
}
fn local_override_keys(local_toml: &str) -> Vec<&'static str> {
let Ok(table) = local_toml.parse::<toml::Table>() else {
return Vec::new();
};
LOCAL_OVERRIDABLE_KEYS
.iter()
.filter(|k| table.contains_key(**k))
.copied()
.collect()
}
fn env_is_set(var: &str) -> bool {
std::env::var_os(var).is_some_and(|v| !v.is_empty())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn local_override_keys_detects_editable_keys() {
let toml =
"compression_level = \"max\"\nterse_agent = \"ultra\"\ntool_profile = \"power\"\n";
let keys = local_override_keys(toml);
assert!(keys.contains(&"compression_level"));
assert!(keys.contains(&"terse_agent"));
assert!(keys.contains(&"tool_profile"));
}
#[test]
fn local_override_keys_ignores_structure_first_and_unrelated() {
let toml = "structure_first = true\nultra_compact = true\n";
assert!(local_override_keys(toml).is_empty());
}
#[test]
fn local_override_keys_ignores_comment_mentions() {
let toml = "# compression_level = \"max\" was considered\nultra_compact = false\n";
assert!(local_override_keys(toml).is_empty());
}
#[test]
fn local_override_keys_empty_on_parse_error() {
assert!(local_override_keys("this is = = not toml").is_empty());
}
#[test]
fn has_shadow_reflects_each_source() {
let clean = ConfigProvenance {
config_path: None,
config_exists: false,
xdg_pinned: true,
parse_error: None,
local_path: None,
local_exists: false,
local_keys: vec![],
env_overrides: vec![],
};
assert!(!clean.has_shadow());
let with_local = ConfigProvenance {
local_keys: vec!["compression_level"],
..clean.clone()
};
assert!(with_local.has_shadow());
assert!(with_local.local_overrides("compression_level"));
assert!(!with_local.local_overrides("terse_agent"));
let with_env = ConfigProvenance {
env_overrides: vec![EnvOverride {
setting: "compression_level",
var: "LEAN_CTX_COMPRESSION",
}],
..clean.clone()
};
assert!(with_env.has_shadow());
let with_parse_err = ConfigProvenance {
parse_error: Some("bad".into()),
..clean
};
assert!(with_parse_err.has_shadow());
}
#[test]
fn provenance_reports_active_env_override() {
let _guard = crate::core::data_dir::test_env_lock();
crate::test_env::set_var("LEAN_CTX_COMPRESSION", "lite");
let prov = Config::provenance();
crate::test_env::remove_var("LEAN_CTX_COMPRESSION");
assert!(
prov.env_overrides
.iter()
.any(|e| e.setting == "compression_level" && e.var == "LEAN_CTX_COMPRESSION"),
"expected LEAN_CTX_COMPRESSION to be reported as an env override"
);
}
}