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#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, ValueEnum)]
15pub enum OutputFormat {
16 #[default]
18 Text,
19 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 #[arg(long)]
36 pub no_system_prompt: bool,
37 #[arg(long)]
39 pub no_tools: bool,
40 #[arg(long, global = true)]
42 pub no_subagents: bool,
43 #[arg(long, global = true, value_name = "ID")]
45 pub agent: Option<String>,
46 #[arg(long)]
48 pub reasoning: Option<ReasoningLevel>,
49 #[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 {
60 #[arg(long)]
62 stdin: bool,
63 #[arg(long, value_name = "PATH")]
66 output_file: Option<PathBuf>,
67 #[arg(long, value_enum, default_value_t)]
69 output: OutputFormat,
70 #[arg(long, value_name = "N")]
72 max_steps: Option<NonZeroUsize>,
73 #[arg(long, value_name = "DURATION", value_parser = parse_duration)]
75 timeout: Option<Duration>,
76 #[arg(value_name = "PROMPT", num_args = 0..)]
78 prompt: Vec<String>,
79 },
80 Attach {
82 #[arg(value_name = "ID")]
84 id: String,
85 },
86 Login {
88 #[arg(value_name = "PROVIDER")]
90 provider: String,
91 #[arg(long)]
93 device_auth: bool,
94 },
95 CredentialStore {
97 #[command(subcommand)]
98 command: CredentialStoreCommand,
99 },
100 Update,
102}
103
104#[derive(Subcommand, Debug)]
105pub enum CredentialStoreCommand {
106 Probe {
108 #[arg(
110 value_name = "BACKEND",
111 default_value = "os",
112 value_parser = parse_credential_store_backend
113 )]
114 backend: CredentialStoreBackend,
115 },
116 Status,
118 Set {
120 #[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;