Skip to main content

codetether_agent/cli/
mod.rs

1//! CLI command definitions and handlers
2
3pub mod config;
4pub mod run;
5
6use clap::{Parser, Subcommand};
7use std::path::PathBuf;
8
9/// CodeTether Agent - A2A-native AI coding agent
10///
11/// By default, runs as an A2A worker connecting to the CodeTether server.
12/// Use the 'tui' subcommand for interactive terminal mode.
13#[derive(Parser, Debug)]
14#[command(name = "codetether")]
15#[command(version, about, long_about = None)]
16pub struct Cli {
17    /// Project directory to operate on
18    #[arg(global = true)]
19    pub project: Option<PathBuf>,
20
21    /// Print logs to stderr
22    #[arg(long, global = true)]
23    pub print_logs: bool,
24
25    /// Log level
26    #[arg(long, global = true, value_parser = ["DEBUG", "INFO", "WARN", "ERROR"])]
27    pub log_level: Option<String>,
28
29    // Default A2A args (when no subcommand)
30    /// A2A server URL (default mode)
31    #[arg(short, long, env = "CODETETHER_SERVER")]
32    pub server: Option<String>,
33
34    /// Authentication token
35    #[arg(short, long, env = "CODETETHER_TOKEN")]
36    pub token: Option<String>,
37
38    /// Worker name
39    #[arg(short, long, env = "CODETETHER_WORKER_NAME")]
40    pub name: Option<String>,
41
42    #[command(subcommand)]
43    pub command: Option<Command>,
44}
45
46#[derive(Subcommand, Debug)]
47pub enum Command {
48    /// Start interactive terminal UI
49    Tui(TuiArgs),
50
51    /// Start a headless API server
52    Serve(ServeArgs),
53
54    /// Run with a message (non-interactive)
55    Run(RunArgs),
56
57    /// Manage configuration
58    Config(ConfigArgs),
59
60    /// A2A worker mode (explicit - also the default)
61    Worker(A2aArgs),
62
63    /// Execute task with parallel sub-agents (swarm mode)
64    Swarm(SwarmArgs),
65
66    /// Analyze large content with RLM (Recursive Language Model)
67    Rlm(RlmArgs),
68
69    /// Autonomous PRD-driven agent loop (Ralph)
70    Ralph(RalphArgs),
71
72    /// Model Context Protocol (MCP) server/client
73    Mcp(McpArgs),
74}
75
76#[derive(Parser, Debug)]
77pub struct TuiArgs {
78    /// Project directory
79    pub project: Option<PathBuf>,
80}
81
82#[derive(Parser, Debug)]
83pub struct ServeArgs {
84    /// Port to listen on
85    #[arg(short, long, default_value = "4096")]
86    pub port: u16,
87
88    /// Hostname to bind to
89    #[arg(long, default_value = "127.0.0.1")]
90    pub hostname: String,
91
92    /// Enable mDNS discovery
93    #[arg(long)]
94    pub mdns: bool,
95}
96
97#[derive(Parser, Debug)]
98pub struct RunArgs {
99    /// Message to send (can be multiple words, quoted or unquoted)
100    pub message: String,
101
102    /// Continue the last session
103    #[arg(short, long)]
104    pub continue_session: bool,
105
106    /// Session ID to continue
107    #[arg(short, long)]
108    pub session: Option<String>,
109
110    /// Model to use (provider/model format)
111    #[arg(short, long)]
112    pub model: Option<String>,
113
114    /// Agent to use
115    #[arg(long)]
116    pub agent: Option<String>,
117
118    /// Output format
119    #[arg(long, default_value = "default", value_parser = ["default", "json"])]
120    pub format: String,
121
122    /// Files to attach
123    #[arg(short, long)]
124    pub file: Vec<PathBuf>,
125}
126
127#[derive(Parser, Debug, Clone)]
128pub struct A2aArgs {
129    /// A2A server URL
130    #[arg(short, long, env = "CODETETHER_SERVER")]
131    pub server: String,
132
133    /// Authentication token
134    #[arg(short, long, env = "CODETETHER_TOKEN")]
135    pub token: Option<String>,
136
137    /// Worker name
138    #[arg(short, long, env = "CODETETHER_WORKER_NAME")]
139    pub name: Option<String>,
140
141    /// Comma-separated list of codebase paths
142    #[arg(short, long)]
143    pub codebases: Option<String>,
144
145    /// Auto-approve policy: all, safe (read-only), none
146    #[arg(long, default_value = "safe", value_parser = ["all", "safe", "none"])]
147    pub auto_approve: String,
148
149    /// Email for task completion reports
150    #[arg(short, long)]
151    pub email: Option<String>,
152
153    /// Push notification endpoint URL
154    #[arg(long)]
155    pub push_url: Option<String>,
156}
157
158#[derive(Parser, Debug)]
159pub struct ConfigArgs {
160    /// Show current configuration
161    #[arg(long)]
162    pub show: bool,
163
164    /// Initialize default configuration
165    #[arg(long)]
166    pub init: bool,
167
168    /// Set a configuration value
169    #[arg(long)]
170    pub set: Option<String>,
171}
172
173#[derive(Parser, Debug)]
174pub struct SwarmArgs {
175    /// Task to execute with swarm
176    pub task: String,
177
178    /// Model to use (provider/model format, e.g. openrouter/stepfun/step-3.5-flash:free)
179    #[arg(short, long)]
180    pub model: Option<String>,
181
182    /// Decomposition strategy: auto, domain, data, stage, none
183    #[arg(short = 's', long, default_value = "auto")]
184    pub strategy: String,
185
186    /// Maximum number of concurrent sub-agents
187    #[arg(long, default_value = "100")]
188    pub max_subagents: usize,
189
190    /// Maximum steps per sub-agent
191    #[arg(long, default_value = "100")]
192    pub max_steps: usize,
193
194    /// Timeout per sub-agent (seconds)
195    #[arg(long, default_value = "300")]
196    pub timeout: u64,
197
198    /// Output as JSON
199    #[arg(long)]
200    pub json: bool,
201}
202
203#[derive(Parser, Debug)]
204pub struct RlmArgs {
205    /// Query to answer about the content
206    pub query: String,
207
208    /// File paths to analyze
209    #[arg(short, long)]
210    pub file: Vec<PathBuf>,
211
212    /// Direct content to analyze (use - for stdin)
213    #[arg(long)]
214    pub content: Option<String>,
215
216    /// Content type hint: code, logs, conversation, documents, auto
217    #[arg(long, default_value = "auto")]
218    pub content_type: String,
219
220    /// Maximum tokens for output
221    #[arg(long, default_value = "4000")]
222    pub max_tokens: usize,
223
224    /// Output as JSON
225    #[arg(long)]
226    pub json: bool,
227
228    /// Enable verbose output (shows context summary)
229    #[arg(short, long)]
230    pub verbose: bool,
231}
232
233#[derive(Parser, Debug)]
234pub struct RalphArgs {
235    /// Action to perform
236    #[arg(value_parser = ["run", "status", "create-prd"])]
237    pub action: String,
238
239    /// Path to prd.json file
240    #[arg(short, long, default_value = "prd.json")]
241    pub prd: PathBuf,
242
243    /// Feature name (for create-prd)
244    #[arg(short, long)]
245    pub feature: Option<String>,
246
247    /// Project name (for create-prd)
248    #[arg(long = "project-name")]
249    pub project_name: Option<String>,
250
251    /// Maximum iterations
252    #[arg(long, default_value = "10")]
253    pub max_iterations: usize,
254
255    /// Model to use
256    #[arg(short, long)]
257    pub model: Option<String>,
258
259    /// Output as JSON
260    #[arg(long)]
261    pub json: bool,
262}
263
264#[derive(Parser, Debug)]
265pub struct McpArgs {
266    /// Action to perform
267    #[arg(value_parser = ["serve", "connect", "list-tools", "call"])]
268    pub action: String,
269
270    /// Command to spawn for connecting to MCP server
271    #[arg(short, long)]
272    pub command: Option<String>,
273
274    /// Server name for registry
275    #[arg(long)]
276    pub server_name: Option<String>,
277
278    /// Tool name for call action
279    #[arg(long)]
280    pub tool: Option<String>,
281
282    /// JSON arguments for tool call
283    #[arg(long)]
284    pub arguments: Option<String>,
285
286    /// Output as JSON
287    #[arg(long)]
288    pub json: bool,
289}