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 Sessions {
104 #[command(subcommand)]
105 command: SessionsCommand,
106 },
107}
108
109#[derive(Subcommand, Debug)]
110pub enum SessionsCommand {
111 List {
113 #[arg(long)]
115 all_projects: bool,
116 },
117 Rm {
119 #[arg(value_name = "ID", required = true, num_args = 1..)]
121 ids: Vec<String>,
122 #[arg(long)]
126 force: bool,
127 #[arg(short = 'y', long)]
129 yes: bool,
130 },
131}
132
133#[derive(Subcommand, Debug)]
134pub enum CredentialStoreCommand {
135 Probe {
137 #[arg(
139 value_name = "BACKEND",
140 default_value = "os",
141 value_parser = parse_credential_store_backend
142 )]
143 backend: CredentialStoreBackend,
144 },
145 Status,
147 Set {
149 #[arg(value_name = "BACKEND", value_parser = parse_credential_store_backend)]
151 backend: CredentialStoreBackend,
152 },
153}
154
155#[cfg(test)]
156#[path = "cli_tests.rs"]
157mod tests;