use crate::*;
use carryctx::adapter::xdg::XdgPaths;
use carryctx::application::runtime::InvocationContext;
use carryctx::error::ExitCode;
use clap::Parser;
#[derive(Parser, Debug)]
pub enum SkillCommand {
Install { source: String },
List,
Path,
Doctor,
}
#[derive(Parser, Debug)]
pub struct SkillArgs {
#[command(subcommand)]
pub command: SkillCommand,
}
pub fn handle_skill(
args: &SkillArgs,
ctx: &InvocationContext,
is_json: bool,
) -> Result<ExitCode, ExitCode> {
let xdg = XdgPaths::new();
let skills_dir = xdg.data_home.join("carryctx").join("skills");
match &args.command {
SkillCommand::Install { source } => {
let data = serde_json::json!({
"source": source,
"target": skills_dir.to_string_lossy(),
"status": "placeholder",
});
render_and_print("skill.install", Ok(data), is_json, ctx.quiet)
}
SkillCommand::List => {
let installed = if skills_dir.exists() {
let entries: Vec<String> = std::fs::read_dir(&skills_dir)
.map(|rd| {
rd.filter_map(|e| e.ok())
.filter(|e| e.path().is_dir())
.filter_map(|e| e.file_name().into_string().ok())
.collect()
})
.unwrap_or_default();
entries
} else {
Vec::new()
};
let data = serde_json::json!({
"skillsDir": skills_dir.to_string_lossy(),
"installed": installed,
});
render_and_print("skill.list", Ok(data), is_json, ctx.quiet)
}
SkillCommand::Path => {
let data = serde_json::json!({ "path": skills_dir.to_string_lossy() });
render_and_print("skill.path", Ok(data), is_json, ctx.quiet)
}
SkillCommand::Doctor => {
let exists = skills_dir.exists();
let entries = if exists {
std::fs::read_dir(&skills_dir)
.map(|rd| {
rd.filter_map(|e| e.ok())
.filter(|e| e.path().is_dir())
.count()
})
.unwrap_or(0)
} else {
0
};
let data = serde_json::json!({
"exists": exists,
"path": skills_dir.to_string_lossy(),
"installedCount": entries,
"status": if exists { "ok" } else { "not_found" },
});
render_and_print("skill.doctor", Ok(data), is_json, ctx.quiet)
}
}
}