Skip to main content

hh_cli/cli/
commands.rs

1use std::path::PathBuf;
2
3use clap::{Parser, Subcommand};
4
5#[derive(Debug, Parser)]
6#[command(name = "hh", about = "Happy Harness", version)]
7pub struct Cli {
8    #[command(subcommand)]
9    pub command: Commands,
10}
11
12#[derive(Debug, Subcommand)]
13pub enum Commands {
14    /// Start interactive chat session
15    Chat {
16        /// Also dump frames to files while running interactive TUI
17        #[arg(long)]
18        debug: Option<PathBuf>,
19        /// Limit autonomous turns; unlimited when omitted
20        #[arg(long, value_parser = parse_positive_usize)]
21        max_turns: Option<usize>,
22        /// Select agent to use
23        #[arg(long)]
24        agent: Option<String>,
25    },
26    /// Replay debug frames from a directory
27    Replay {
28        /// Directory containing screen dump files
29        dir: PathBuf,
30        /// Delay between frames in milliseconds (default: 100)
31        #[arg(short, long, default_value = "100")]
32        delay: u64,
33        /// Loop replay continuously
34        #[arg(short, long)]
35        loop_replay: bool,
36    },
37    /// Run one prompt and exit
38    Run {
39        prompt: String,
40        /// Dump headless debug frames to this directory
41        #[arg(long)]
42        debug: Option<PathBuf>,
43        /// Limit autonomous turns; unlimited when omitted
44        #[arg(long, value_parser = parse_positive_usize)]
45        max_turns: Option<usize>,
46        /// Select agent to use
47        #[arg(long)]
48        agent: Option<String>,
49    },
50    /// List available agents
51    Agents,
52    /// List available tools
53    Tools,
54    /// Manage configuration
55    Config {
56        #[command(subcommand)]
57        command: ConfigCommand,
58    },
59}
60
61#[derive(Debug, Subcommand)]
62pub enum ConfigCommand {
63    Init,
64    Show,
65}
66
67fn parse_positive_usize(raw: &str) -> Result<usize, String> {
68    let value = raw
69        .parse::<usize>()
70        .map_err(|_| format!("invalid integer: {raw}"))?;
71    if value == 0 {
72        return Err("value must be greater than 0".to_string());
73    }
74    Ok(value)
75}