Skip to main content

hh_cli/cli/
mod.rs

1pub mod agent_init;
2pub mod chat;
3pub mod commands;
4pub mod render;
5pub mod replay;
6pub mod tui;
7
8use crate::cli::commands::{Cli, Commands, ConfigCommand};
9use crate::cli::render::LiveRender;
10use crate::config::{load_settings, write_default_project_config};
11use clap::Parser;
12
13pub async fn run() -> anyhow::Result<()> {
14    let cli = Cli::parse();
15    let cwd = std::env::current_dir()?;
16
17    match cli.command {
18        Commands::Chat {
19            debug,
20            max_turns,
21            agent,
22        } => {
23            let settings = load_settings(&cwd, agent)?;
24            let settings = apply_max_turns(settings, max_turns);
25            if let Some(debug_path) = debug {
26                // Interactive mode with debug dumping
27                chat::run_chat_with_debug(settings, &cwd, debug_path).await
28            } else {
29                chat::run_chat(settings, &cwd).await
30            }
31        }
32        Commands::Replay {
33            dir,
34            delay,
35            loop_replay,
36        } => {
37            replay::replay_frames(&dir, delay, loop_replay)?;
38            Ok(())
39        }
40        Commands::Run {
41            prompt,
42            debug,
43            max_turns,
44            agent,
45        } => {
46            let settings = load_settings(&cwd, agent)?;
47            let settings = apply_max_turns(settings, max_turns);
48            if let Some(debug_path) = debug {
49                chat::run_prompt_with_debug(settings, &cwd, debug_path, prompt).await
50            } else {
51                let render = LiveRender::new();
52                render.begin_turn();
53                chat::run_single_prompt_with_events(settings, &cwd, prompt, render).await?;
54                Ok(())
55            }
56        }
57        Commands::Tools => {
58            let settings = load_settings(&cwd, None)?;
59            let registry = crate::tool::registry::ToolRegistry::new(&settings, &cwd);
60            for name in registry.names() {
61                println!("{}", name);
62            }
63            Ok(())
64        }
65        Commands::Config { command } => match command {
66            ConfigCommand::Init => {
67                let path = write_default_project_config(&cwd)?;
68                println!("wrote {}", path.display());
69                Ok(())
70            }
71            ConfigCommand::Show => {
72                let settings = load_settings(&cwd, None)?;
73                let txt = serde_json::to_string_pretty(&settings)?;
74                println!("{}", txt);
75                Ok(())
76            }
77        },
78        Commands::Agents => {
79            let loader = crate::agent::AgentLoader::new()?;
80            let agents = loader.load_agents()?;
81            let registry = crate::agent::AgentRegistry::new(agents);
82
83            println!("Available agents:");
84            for agent in registry.list_agents() {
85                let mode = if agent.mode == crate::agent::AgentMode::Primary {
86                    "primary"
87                } else {
88                    "subagent"
89                };
90                println!(
91                    "  {} ({}) - {} - {}",
92                    agent.name, agent.display_name, mode, agent.description
93                );
94            }
95            Ok(())
96        }
97    }
98}
99
100fn apply_max_turns(
101    mut settings: crate::config::Settings,
102    max_turns: Option<usize>,
103) -> crate::config::Settings {
104    if let Some(max_turns) = max_turns {
105        settings.agent.max_steps = max_turns;
106    }
107    settings
108}