Skip to main content

rover/cli/
meta.rs

1//! `rover meta use <harness>` and the runtime hook handler `rover meta hook <harness>`.
2
3use std::io::Read;
4
5use anyhow::Context;
6
7use crate::meta::{self, Harness, Scope};
8
9#[derive(Debug, clap::Subcommand)]
10pub enum MetaCommand {
11    /// Wire Rover into an agent harness (MCP config, hooks, rules file).
12    Use {
13        /// Target harness.
14        harness: Harness,
15        /// Configuration scope (local, user, or project).
16        #[arg(short = 's', long, default_value = "local")]
17        scope: Scope,
18    },
19    /// Runtime hook handler invoked by the harness (reads the hook JSON on stdin).
20    Hook {
21        /// Harness whose hook contract to speak.
22        harness: Harness,
23    },
24}
25
26pub fn run(cmd: MetaCommand) -> anyhow::Result<i32> {
27    match cmd {
28        MetaCommand::Use { harness, scope } => {
29            let root = std::env::current_dir().context("resolving the current directory")?;
30            meta::run_use(harness, scope, &root)
31        }
32        MetaCommand::Hook { harness } => match harness {
33            Harness::Claude => {
34                let mut buf = String::new();
35                std::io::stdin()
36                    .read_to_string(&mut buf)
37                    .context("reading hook input from stdin")?;
38                let out = meta::hook::handle_claude_hook(&buf);
39                if !out.is_empty() {
40                    println!("{out}");
41                }
42                Ok(0)
43            }
44            Harness::General => {
45                anyhow::bail!("`general` has no hooks; there is nothing for `meta hook` to do")
46            }
47        },
48    }
49}