Skip to main content

hypha/skill_admin/
mod.rs

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}