use crate::config::Config;
pub fn startup_warnings(config: &Config, raw_toml: Option<&str>) -> Vec<String> {
let mut warns = Vec::new();
if let Some(raw) = raw_toml
&& let Ok(value) = raw.parse::<toml::Value>()
{
let candidates = [
value.get("working_directory"),
value.get("agent").and_then(|a| a.get("working_directory")),
];
for c in candidates.into_iter().flatten() {
if let Some(path) = c.as_str() {
let expanded = expand_home(path);
let missing = if std::path::Path::new(&expanded).is_dir() {
""
} else {
" — and the path does not exist on disk"
};
warns.push(format!(
"config: working_directory = \"{path}\" has NO effect — the schema has \
no such key (unknown keys are silently ignored). The working directory \
is per-session: use /cd, or set it when creating the session{missing}"
));
}
}
}
if let Some(dp) = config.agent.default_provider.as_deref() {
match crate::brain::provider::factory::provider_config_by_name(config, dp) {
None => warns.push(format!(
"config: [agent] default_provider = \"{dp}\" does not match any configured \
provider section — new sessions will fall back to the priority list"
)),
Some(section) if !section.force_default => warns.push(format!(
"config: default_provider = \"{dp}\" applies to NEW sessions only; existing \
sessions keep their stored pair. Add force_default = true under \
[providers.{dp}] to push the default to all sessions on config reload"
)),
Some(_) => {}
}
}
if let Some(fb) = config.providers.fallback.as_ref() {
for (field, names) in [("providers", &fb.providers), ("vision", &fb.vision)] {
for name in names {
if crate::brain::provider::factory::provider_config_by_name(config, name).is_some()
{
continue;
}
let hint = nearest_provider_name(config, name)
.map(|near| format!(" — did you mean \"{near}\"?"))
.unwrap_or_default();
warns.push(format!(
"config: [providers.fallback] {field} lists \"{name}\", which matches no \
configured provider — it will be skipped silently{hint}"
));
}
}
}
warns
}
fn nearest_provider_name<'a>(config: &'a Config, name: &str) -> Option<&'a str> {
let squash = |s: &str| {
s.chars()
.filter(|c| c.is_ascii_alphanumeric())
.flat_map(char::to_lowercase)
.collect::<String>()
};
let target = squash(name);
config
.providers
.custom
.as_ref()?
.keys()
.find(|candidate| squash(candidate) == target)
.map(String::as_str)
}
fn expand_home(path: &str) -> String {
if let Some(rest) = path.strip_prefix("~/")
&& let Some(home) = dirs::home_dir()
{
return home.join(rest).to_string_lossy().to_string();
}
path.to_string()
}