1use clap::{Parser, Subcommand, ValueEnum};
4use std::path::PathBuf;
5
6#[derive(Clone, Copy, Debug, Eq, PartialEq, ValueEnum)]
7pub enum CliMode {
8 Interactive,
9 Rpc,
10}
11
12#[derive(Parser, Debug)]
14#[command(name = "uira-agent")]
15#[command(author, version, about, long_about = None)]
16pub struct Cli {
17 #[arg(long, value_enum, default_value_t = CliMode::Interactive)]
19 pub mode: CliMode,
20
21 #[arg(trailing_var_arg = true)]
23 pub prompt: Vec<String>,
24
25 #[arg(short, long)]
27 pub model: Option<String>,
28
29 #[arg(short, long)]
31 pub provider: Option<String>,
32
33 #[arg(long, default_value = "workspace-write")]
35 pub sandbox: String,
36
37 #[arg(long)]
39 pub sandbox_rules: Option<PathBuf>,
40
41 #[arg(long)]
43 pub full_auto: bool,
44
45 #[arg(short, long)]
47 pub verbose: bool,
48
49 #[arg(long)]
51 pub ralph: bool,
52
53 #[arg(short, long)]
56 pub agent: Option<String>,
57
58 #[arg(long, default_value = "text")]
60 pub output: String,
61
62 #[command(subcommand)]
63 pub command: Option<Commands>,
64}
65
66#[derive(Subcommand, Debug)]
67pub enum Commands {
68 Exec {
70 prompt: String,
72
73 #[arg(long)]
75 json: bool,
76 },
77
78 Resume {
80 session_id: Option<String>,
82
83 #[arg(long)]
85 fork: bool,
86
87 #[arg(long)]
89 fork_at: Option<usize>,
90 },
91
92 Sessions {
94 #[command(subcommand)]
95 command: SessionsCommands,
96 },
97
98 Auth {
100 #[command(subcommand)]
101 command: AuthCommands,
102 },
103
104 Config {
106 #[command(subcommand)]
107 command: ConfigCommands,
108 },
109
110 Goals {
112 #[command(subcommand)]
113 command: GoalsCommands,
114 },
115
116 Tasks {
118 #[command(subcommand)]
119 command: TasksCommands,
120 },
121
122 Completion {
124 #[arg(value_enum)]
126 shell: clap_complete::Shell,
127 },
128
129 Gateway {
131 #[command(subcommand)]
132 command: GatewayCommands,
133 },
134
135 Skills {
137 #[command(subcommand)]
138 command: SkillsCommands,
139 },
140}
141
142#[derive(Subcommand, Debug)]
143pub enum AuthCommands {
144 Login {
146 provider: Option<String>,
148 },
149 Logout {
151 provider: String,
153 },
154 Status,
156}
157
158#[derive(Subcommand, Debug)]
159pub enum ConfigCommands {
160 Show,
162 Set {
164 key: String,
166 value: String,
168 },
169 Get {
171 key: String,
173 },
174 Reset,
176}
177
178#[derive(Subcommand, Debug)]
179pub enum GoalsCommands {
180 Check,
182 List,
184 Status,
186}
187
188#[derive(Subcommand, Debug)]
189pub enum TasksCommands {
190 List,
192 Status {
194 task_id: String,
196 },
197 Cancel {
199 task_id: String,
201 },
202}
203
204#[derive(Subcommand, Debug)]
205pub enum SessionsCommands {
206 List {
208 #[arg(short, long, default_value = "20")]
210 limit: usize,
211
212 #[arg(long)]
214 tree: bool,
215 },
216 Info {
218 session_id: String,
220 },
221 Delete {
223 session_id: String,
225 },
226}
227
228#[derive(Subcommand, Debug)]
229pub enum GatewayCommands {
230 Start {
232 #[arg(long)]
234 host: Option<String>,
235 #[arg(long)]
237 port: Option<u16>,
238 #[arg(long)]
240 auth_token: Option<String>,
241 },
242}
243
244#[derive(Subcommand, Debug)]
245pub enum SkillsCommands {
246 List,
248 Show {
250 name: String,
252 },
253 Install {
255 path: String,
257 },
258}
259
260impl Cli {
261 pub fn get_prompt(&self) -> Option<String> {
262 if self.prompt.is_empty() {
263 None
264 } else {
265 Some(self.prompt.join(" "))
266 }
267 }
268}
269
270#[cfg(test)]
271mod tests {
272 use super::*;
273 use clap::Parser;
274
275 #[test]
276 fn defaults_to_interactive_mode() {
277 let cli = Cli::parse_from(["uira-agent"]);
278 assert_eq!(cli.mode, CliMode::Interactive);
279 }
280
281 #[test]
282 fn parses_rpc_mode_flag() {
283 let cli = Cli::parse_from(["uira-agent", "--mode", "rpc"]);
284 assert_eq!(cli.mode, CliMode::Rpc);
285 }
286
287 #[test]
288 fn parses_custom_sandbox_rules_flag() {
289 let cli = Cli::parse_from([
290 "uira-agent",
291 "--sandbox",
292 "custom",
293 "--sandbox-rules",
294 "./sandbox-rules.json",
295 ]);
296 assert_eq!(cli.sandbox, "custom");
297 assert_eq!(
298 cli.sandbox_rules,
299 Some(PathBuf::from("./sandbox-rules.json"))
300 );
301 }
302}