use std::path::PathBuf;
use tftio_cli_common::{DoctorCheck, DoctorChecks, RepoInfo};
use crate::config::load_config;
pub struct Doctor {
config_path: Option<PathBuf>,
current_dir: PathBuf,
home: Option<PathBuf>,
}
impl Doctor {
#[must_use]
pub const fn new(
config_path: Option<PathBuf>,
current_dir: PathBuf,
home: Option<PathBuf>,
) -> Self {
Self {
config_path,
current_dir,
home,
}
}
}
impl DoctorChecks for Doctor {
fn repo_info() -> RepoInfo {
RepoInfo::new("tftio-stuff", "clanker")
}
fn current_version() -> &'static str {
env!("CARGO_PKG_VERSION")
}
fn tool_checks(&self) -> Vec<DoctorCheck> {
let mut checks = self.config_path.as_ref().map_or_else(
|| {
vec![DoctorCheck::fail(
"Clanker config",
"$HOME is not set and CLANKER_CONFIG was not provided",
)]
},
|path| match load_config(path) {
Ok(loaded) => {
let mut checks = vec![DoctorCheck::pass(format!(
"Config file: {}",
loaded.base_path.display()
))];
if let Some(overlay) = loaded.overlay_path {
checks.push(DoctorCheck::pass(format!(
"Local overlay: {}",
overlay.display()
)));
}
checks.push(DoctorCheck::pass("Runtime config schema and invariants"));
if let Some(home) = &self.home {
let filesystem_issues = loaded.config.filesystem_issues(home);
if filesystem_issues.is_empty() {
checks.push(DoctorCheck::pass("Skill bundle and configured skills"));
} else {
checks.extend(
filesystem_issues.into_iter().map(|issue| {
DoctorCheck::fail("Skill bundle", issue.to_string())
}),
);
}
} else {
checks.push(DoctorCheck::fail(
"Skill bundle",
"$HOME is not set; cannot resolve defaults.skills_bundle",
));
}
checks
}
Err(error) => vec![DoctorCheck::fail("Clanker config", error.to_string())],
},
);
let legacy_context = self.current_dir.join(".context");
if legacy_context.exists() {
checks.push(DoctorCheck::fail(
"Legacy context file",
format!(
"{} exists; replace it with .clanker TOML",
legacy_context.display()
),
));
} else {
checks.push(DoctorCheck::pass("No legacy .context file in cwd"));
}
checks
}
}