feat(doctor): surface skill directory health in diagnostics

This commit is contained in:
William Valentin
2026-02-12 17:05:04 -08:00
parent fc3d2ab4d8
commit 0a19f01639
3 changed files with 84 additions and 7 deletions
+22 -4
View File
@@ -189,13 +189,31 @@ const checkSkills: Check = async (ctx) => {
return { status: 'skip', label: 'Skills loaded', detail: '(config invalid)' };
}
try {
const skillDirs = {
bundled: ctx.config.skills.bundled_dir,
managed: ctx.config.skills.managed_dir,
workspace: ctx.config.skills.workspace_dir,
};
const missingDirs = Object.entries(skillDirs)
.filter(([, dir]) => Boolean(dir) && !existsSync(dir as string))
.map(([tier, dir]) => `${tier}:${dir as string}`);
const { loadAllSkills } = await import('../skills/index.js');
const skills = loadAllSkills({
bundledDir: ctx.config.skills.bundled_dir,
managedDir: ctx.config.skills.managed_dir,
workspaceDir: ctx.config.skills.workspace_dir,
bundledDir: skillDirs.bundled,
managedDir: skillDirs.managed,
workspaceDir: skillDirs.workspace,
});
return { status: 'pass', label: 'Skills loaded', detail: `(${skills.length} skill(s))` };
const available = skills.filter((skill) => skill.available).length;
const unavailable = skills.length - available;
const detailParts = [`${skills.length} skill(s), ${available} available, ${unavailable} unavailable`];
if (missingDirs.length > 0) {
detailParts.push(`missing dirs: ${missingDirs.join(', ')}`);
return { status: 'warn', label: 'Skills loaded', detail: detailParts.join(' — ') };
}
return { status: 'pass', label: 'Skills loaded', detail: detailParts.join(' — ') };
} catch (err) {
return { status: 'fail', label: 'Skills loaded', detail: err instanceof Error ? err.message : String(err) };
}