Skip to main content

rho_coding_agent/
cli.rs

1use std::{num::NonZeroUsize, path::PathBuf, time::Duration};
2
3use clap::{Parser, Subcommand, ValueEnum};
4
5use rho_providers::{credentials::CredentialStoreBackend, reasoning::ReasoningLevel};
6
7use crate::app::automation_protocol::parse_duration;
8
9fn parse_credential_store_backend(value: &str) -> Result<CredentialStoreBackend, String> {
10    CredentialStoreBackend::parse(value).map_err(|error| error.to_string())
11}
12
13/// Output contract used by a non-interactive `rho run` invocation.
14#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, ValueEnum)]
15pub enum OutputFormat {
16    /// Print only the authoritative final assistant answer.
17    #[default]
18    Text,
19    /// Stream independently versioned JSON Lines events.
20    Jsonl,
21}
22
23#[derive(Parser, Debug)]
24#[command(name = "rho")]
25pub struct Cli {
26    #[arg(long)]
27    pub provider: Option<String>,
28    #[arg(long)]
29    pub model: Option<String>,
30    #[arg(long)]
31    pub config: Option<PathBuf>,
32    #[arg(long, value_parser = ["api-key", "codex", "anthropic-api-key", "google-api-key", "github-copilot", "xai-api-key", "xai-oauth", "moonshot-api-key", "poolside-api-key", "openrouter-api-key", "openrouter-oauth", "kimi-oauth"])]
33    pub auth: Option<String>,
34    /// Do not send rho's system prompt, including AGENTS.md and skill context.
35    #[arg(long)]
36    pub no_system_prompt: bool,
37    /// Do not expose any tools to the model.
38    #[arg(long)]
39    pub no_tools: bool,
40    /// Do not expose the delegated-agent tools (agent/agents) to the model.
41    #[arg(long, global = true)]
42    pub no_subagents: bool,
43    /// Select the agent definition used for this session or automation run.
44    #[arg(long, global = true, value_name = "ID")]
45    pub agent: Option<String>,
46    /// Override reasoning level: off, minimal, low, medium, high, xhigh, or max.
47    #[arg(long)]
48    pub reasoning: Option<ReasoningLevel>,
49    /// Resume an existing session by UUID or UUID prefix. Omit the ID to choose from a picker.
50    #[arg(short = 'R', long, value_name = "ID", num_args = 0..=1)]
51    pub resume: Option<Option<String>>,
52    #[command(subcommand)]
53    pub command: Option<Command>,
54}
55
56#[derive(Subcommand, Debug)]
57pub enum Command {
58    /// Run one non-interactive automation prompt and print the final answer.
59    Run {
60        /// Read additional prompt text from stdin.
61        #[arg(long)]
62        stdin: bool,
63        /// Stream progress to stdout and write a structured status/result
64        /// file (JSON) that is updated during the run and finalized on exit.
65        #[arg(long, value_name = "PATH")]
66        output_file: Option<PathBuf>,
67        /// Select plain final-answer output or a JSON Lines event stream.
68        #[arg(long, value_enum, default_value_t)]
69        output: OutputFormat,
70        /// Override the model-step budget for this run.
71        #[arg(long, value_name = "N")]
72        max_steps: Option<NonZeroUsize>,
73        /// Cancel the run after this wall-clock duration.
74        #[arg(long, value_name = "DURATION", value_parser = parse_duration)]
75        timeout: Option<Duration>,
76        /// Prompt text to send to the agent.
77        #[arg(value_name = "PROMPT", num_args = 0..)]
78        prompt: Vec<String>,
79    },
80    /// Watch a delegated agent run in a read-only TUI.
81    Attach {
82        /// Delegated run ID shown when the agent was started.
83        #[arg(value_name = "ID")]
84        id: String,
85    },
86    /// Log in to a provider from a browser or device-code flow.
87    Login {
88        /// Provider to authenticate, for example openai-codex or github-copilot.
89        #[arg(value_name = "PROVIDER")]
90        provider: String,
91        /// Use device-code login instead of opening a local browser callback.
92        #[arg(long)]
93        device_auth: bool,
94    },
95    /// Configure or probe provider credential storage.
96    CredentialStore {
97        #[command(subcommand)]
98        command: CredentialStoreCommand,
99    },
100    /// Update rho using the detected installation method.
101    Update,
102}
103
104#[derive(Subcommand, Debug)]
105pub enum CredentialStoreCommand {
106    /// Test a credential backend by writing and deleting a temporary secret.
107    Probe {
108        /// Backend to test: os or file (`auto` is accepted as an alias for os).
109        #[arg(
110            value_name = "BACKEND",
111            default_value = "os",
112            value_parser = parse_credential_store_backend
113        )]
114        backend: CredentialStoreBackend,
115    },
116    /// Show the configured credential backend (unset, os, or file).
117    Status,
118    /// Save the credential backend used by future rho processes.
119    Set {
120        /// Backend to use: os or file (`auto` is accepted as an alias for os).
121        #[arg(value_name = "BACKEND", value_parser = parse_credential_store_backend)]
122        backend: CredentialStoreBackend,
123    },
124}
125
126#[cfg(test)]
127#[path = "cli_tests.rs"]
128mod tests;