1use std::process::ExitCode;
2
3use agent_first_data::skill::{
4 run_skill_admin, SkillAction as AfSkillAction, SkillAgentSelection, SkillOptions, SkillScope,
5 SkillSpec,
6};
7
8use crate::api::Output;
9use crate::cli::{SkillAgentArg, SkillCommand, SkillOptionsArg, SkillScopeArg};
10
11const HYPHA_SKILL: &str = include_str!("SKILL.md");
12
13fn spec() -> SkillSpec<'static> {
14 SkillSpec {
15 name: "hypha",
16 source: HYPHA_SKILL,
17 title: "Hypha",
18 marker_slug: "hypha",
19 }
20}
21
22pub fn handle_skill(out: &Output, command: SkillCommand) -> ExitCode {
23 let (action, options) = match command {
24 SkillCommand::Status(options) => (AfSkillAction::Status, options),
25 SkillCommand::Install(options) => (AfSkillAction::Install, options),
26 SkillCommand::Uninstall(options) => (AfSkillAction::Uninstall, options),
27 };
28
29 let options = to_afdata_options(options);
30 match run_skill_admin(&spec(), action, &options) {
31 Ok(report) => match serde_json::to_value(report) {
32 Ok(value) => out.value(value),
33 Err(err) => out.error_hint(
34 "serialize_error",
35 &format!("Failed to serialize skill report: {err}"),
36 Some("report this bug with the command and --output value used"),
37 ),
38 },
39 Err(err) => out.error_hint(
40 "skill_error",
41 &err.message,
42 err.hint.as_deref().or(Some(
43 "check hypha skill --help and retry with the suggested options",
44 )),
45 ),
46 }
47}
48
49fn to_afdata_options(options: SkillOptionsArg) -> SkillOptions {
50 SkillOptions {
51 agent: match options.agent {
52 SkillAgentArg::All => SkillAgentSelection::All,
53 SkillAgentArg::Codex => SkillAgentSelection::Codex,
54 SkillAgentArg::ClaudeCode => SkillAgentSelection::ClaudeCode,
55 SkillAgentArg::Opencode => SkillAgentSelection::Opencode,
56 },
57 scope: match options.scope {
58 SkillScopeArg::Personal => SkillScope::Personal,
59 SkillScopeArg::Project => SkillScope::Project,
60 },
61 skills_dir: options.skills_dir,
62 force: options.force,
63 }
64}