use std::env;
use std::fs;
use std::path::PathBuf;
use clap::{Args, Subcommand};
use miette::{IntoDiagnostic, WrapErr, miette};
use crate::failure::Failure;
use crate::output::OutputTarget;
const SKILL_MARKDOWN: &str = include_str!("../skill/SKILL.md");
const SYNTAX_MARKDOWN: &str = include_str!("../skill/references/syntax.md");
const TROUBLESHOOT_MARKDOWN: &str = include_str!("../skill/references/troubleshoot.md");
const JSON_MARKDOWN: &str = include_str!("../skill/references/json.md");
const INSTALL_MARKDOWN: &str = include_str!("../skill/references/install.md");
const SKILL_FILES: [(&str, &str); 5] = [
("SKILL.md", SKILL_MARKDOWN),
("references/syntax.md", SYNTAX_MARKDOWN),
("references/troubleshoot.md", TROUBLESHOOT_MARKDOWN),
("references/json.md", JSON_MARKDOWN),
("references/install.md", INSTALL_MARKDOWN),
];
const SKILL_DIRECTORY: &str = ".claude/skills/svugy";
const REFERENCES_DIRECTORY: &str = "references";
#[derive(Args)]
pub struct SkillCommand {
#[command(subcommand)]
action: Option<SkillAction>,
}
#[derive(Subcommand)]
enum SkillAction {
Install(InstallSkill),
}
#[derive(Args)]
struct InstallSkill {
#[arg(long)]
user: bool,
}
impl SkillCommand {
pub fn run(self) -> Result<(), Failure> {
let Some(SkillAction::Install(install_skill)) = self.action else {
return OutputTarget::write_stdout(SKILL_MARKDOWN);
};
install_skill.run()
}
}
impl InstallSkill {
fn run(self) -> Result<(), Failure> {
let installation_root = self.installation_root()?;
let skill_directory = installation_root.join(SKILL_DIRECTORY);
let references_directory = skill_directory.join(REFERENCES_DIRECTORY);
let references_directory_path = references_directory.display();
fs::create_dir_all(&references_directory)
.into_diagnostic()
.wrap_err_with(|| format!("cannot create {references_directory_path}"))
.map_err(Failure::Io)?;
let mut written_paths = String::new();
for (file_name, contents) in SKILL_FILES {
let skill_file = skill_directory.join(file_name);
OutputTarget::write_file(&skill_file, contents)?;
let skill_file_path = skill_file.display();
let written_line = format!("wrote {skill_file_path}\n");
written_paths.push_str(&written_line);
}
OutputTarget::write_stdout(&written_paths)
}
fn installation_root(&self) -> Result<PathBuf, Failure> {
let is_user_installation = self.user;
if is_user_installation {
return env::home_dir()
.ok_or_else(|| miette!("cannot find the home directory"))
.map_err(Failure::Io);
}
env::current_dir()
.into_diagnostic()
.wrap_err_with(|| "cannot read the current directory")
.map_err(Failure::Io)
}
}