Skip to main content

yarp_cli/
agent_skill.rs

1use std::fs;
2use std::io;
3use std::path::Path;
4
5use skillflag::{Options, handle_skillflag};
6
7const SKILL_ID: &str = "yarp";
8const SKILL_MD: &str = include_str!("../skills/yarp/SKILL.md");
9
10/// Handle a top-level `yarp --skill ...` invocation.
11///
12/// Returns `None` when the invocation belongs to the regular YARP CLI.
13#[must_use]
14pub fn maybe_run(arguments: &[String]) -> Option<i32> {
15    if arguments.get(1).map(String::as_str) != Some("--skill") {
16        return None;
17    }
18    Some(match materialize_and_run(arguments) {
19        Ok(code) => code,
20        Err(error) => {
21            eprintln!("yarp: could not prepare bundled skill: {error}");
22            1
23        }
24    })
25}
26
27fn materialize_and_run(arguments: &[String]) -> io::Result<i32> {
28    let temporary = tempfile::Builder::new().prefix("yarp-skill-").tempdir()?;
29    let bundle_root = temporary.path().join("skills");
30    let yarp_dir = bundle_root.join(SKILL_ID);
31    fs::create_dir_all(&yarp_dir)?;
32    let skill_path = yarp_dir.join("SKILL.md");
33    fs::write(&skill_path, SKILL_MD)?;
34    set_export_permissions(&bundle_root, &yarp_dir, &skill_path)?;
35
36    let options = Options {
37        skills_roots: vec![bundle_root],
38        include_bundled_skill: false,
39        ..Options::default()
40    };
41    Ok(handle_skillflag(arguments, &options))
42}
43
44#[cfg(unix)]
45fn set_export_permissions(
46    bundle_root: &Path,
47    yarp_dir: &Path,
48    skill_path: &Path,
49) -> io::Result<()> {
50    use std::os::unix::fs::PermissionsExt as _;
51
52    fs::set_permissions(bundle_root, fs::Permissions::from_mode(0o755))?;
53    fs::set_permissions(yarp_dir, fs::Permissions::from_mode(0o755))?;
54    fs::set_permissions(skill_path, fs::Permissions::from_mode(0o644))
55}
56
57#[cfg(not(unix))]
58fn set_export_permissions(
59    _bundle_root: &Path,
60    _yarp_dir: &Path,
61    _skill_path: &Path,
62) -> io::Result<()> {
63    Ok(())
64}