use std::path::Path;
use crate::core::doctor::{CheckStatus, DoctorCheck};
pub(super) fn check_legacy_instruction_sources(home: &Path) -> DoctorCheck {
let mut findings: Vec<String> = Vec::new();
let tm_skill_count = count_legacy_tm_skills(&home.join(".claude").join("skills"));
if tm_skill_count > 0 {
findings.push(format!(
"{tm_skill_count} `tm-*` skill copy(ies) in ~/.claude/skills (legacy global \
deploy — remove them or run `tm install` to refresh; project-local \
.claude/skills is now authoritative)"
));
}
let legacy_config = home.join(".trusty-mpm").join("claude-config");
if legacy_config.is_dir() {
findings.push(
"legacy ~/.trusty-mpm/claude-config directory (superseded by the tm-owned \
~/.trusty-tools config home — safe to delete once no session references it)"
.to_string(),
);
}
if findings.is_empty() {
DoctorCheck::new(
"legacy_sources",
CheckStatus::Ok,
"no legacy global instruction sources found",
)
} else {
DoctorCheck::new(
"legacy_sources",
CheckStatus::Warn,
format!(
"legacy instruction source(s) may serve stale guidance: {}",
findings.join("; ")
),
)
}
}
fn count_legacy_tm_skills(skills_dir: &Path) -> usize {
let Ok(entries) = std::fs::read_dir(skills_dir) else {
return 0;
};
entries
.flatten()
.filter(|entry| {
entry
.file_name()
.to_str()
.is_some_and(|n| n.starts_with("tm-"))
})
.count()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn legacy_sources_ok_when_absent() {
let tmp = tempfile::tempdir().unwrap();
let check = check_legacy_instruction_sources(tmp.path());
assert_eq!(check.status, CheckStatus::Ok);
}
#[test]
fn legacy_sources_warns_on_tm_skills() {
let tmp = tempfile::tempdir().unwrap();
let skills = tmp.path().join(".claude").join("skills");
let skill_dir = skills.join("tm-pr-workflow");
std::fs::create_dir_all(&skill_dir).unwrap();
std::fs::write(skill_dir.join("SKILL.md"), "old attribution").unwrap();
std::fs::create_dir_all(skills.join("my-skill")).unwrap();
let check = check_legacy_instruction_sources(tmp.path());
assert_eq!(check.status, CheckStatus::Warn);
assert!(check.message.contains(".claude/skills"));
assert!(check.message.contains('1'));
}
#[test]
fn legacy_sources_warns_on_claude_config() {
let tmp = tempfile::tempdir().unwrap();
std::fs::create_dir_all(tmp.path().join(".trusty-mpm").join("claude-config")).unwrap();
let check = check_legacy_instruction_sources(tmp.path());
assert_eq!(check.status, CheckStatus::Warn);
assert!(check.message.contains("claude-config"));
}
}