mi6_cli/args.rs
1use clap::{Args, Parser, Subcommand};
2use mi6_core::OtelMode;
3use std::path::PathBuf;
4
5/// Build the long version string with git commit.
6fn long_version() -> &'static str {
7 concat!(env!("CARGO_PKG_VERSION"), " (", env!("MI6_GIT_COMMIT"), ")")
8}
9
10/// A unified CLI for monitoring and managing agentic coding sessions.
11///
12/// Run without arguments to launch the interactive TUI.
13#[derive(Parser, Debug)]
14#[command(name = "mi6", version = long_version(), about)]
15#[command(args_conflicts_with_subcommands = true)]
16#[command(disable_help_subcommand = true)]
17pub struct Cli {
18 #[command(subcommand)]
19 pub command: Option<Commands>,
20
21 /// TUI arguments (used when no subcommand is provided)
22 #[command(flatten)]
23 pub tui_args: TuiArgs,
24}
25
26/// Arguments for the TUI interface.
27#[derive(Args, Debug, Default, Clone, PartialEq, Eq)]
28pub struct TuiArgs {
29 /// Refresh interval in milliseconds
30 #[arg(short, long, value_name = "MS")]
31 pub interval: Option<u64>,
32
33 /// Transcript poll interval in milliseconds
34 #[arg(long = "transcript-poll", value_name = "MS")]
35 pub transcript_poll: Option<u64>,
36
37 /// Show all sessions including dead ones
38 #[arg(short, long)]
39 pub all: bool,
40
41 /// Color theme (default, minimal, dracula)
42 #[arg(short, long, value_name = "THEME")]
43 pub theme: Option<String>,
44
45 /// Columns to display (comma or space separated)
46 #[arg(short = 'c', long, value_name = "COLS", num_args = 1..)]
47 pub columns: Option<Vec<String>>,
48}
49
50#[derive(Subcommand, Debug)]
51pub enum Commands {
52 /// Enable mi6 for each agent framework
53 Enable {
54 /// Frameworks to enable (claude, cursor, codex, etc.)
55 #[arg(value_name = "FRAMEWORKS")]
56 frameworks: Vec<String>,
57
58 /// Install hooks to project config instead of global
59 #[arg(long, conflicts_with = "settings_local")]
60 local: bool,
61
62 /// Install hooks to project local config (not committed to git)
63 #[arg(long, conflicts_with = "local")]
64 settings_local: bool,
65
66 /// Print hooks to stdout instead of writing to file
67 #[arg(long)]
68 print: bool,
69
70 /// Only initialize database, skip hook installation
71 #[arg(long)]
72 db_only: bool,
73
74 /// Only install hooks, skip database initialization
75 #[arg(long)]
76 hooks_only: bool,
77
78 /// Configure OpenTelemetry for token tracking
79 #[arg(long, conflicts_with = "no_otel")]
80 otel: bool,
81
82 /// Port for OTel server
83 #[arg(long, default_value = "4318")]
84 otel_port: u16,
85
86 /// Remove OTel configuration
87 #[arg(long, conflicts_with = "otel")]
88 no_otel: bool,
89 },
90
91 /// Disable mi6 for each agent framework
92 Disable {
93 /// Frameworks to disable
94 #[arg(value_name = "FRAMEWORKS")]
95 frameworks: Vec<String>,
96
97 /// Remove from project config instead of global
98 #[arg(long, conflicts_with = "settings_local")]
99 local: bool,
100
101 /// Remove from project local config
102 #[arg(long, conflicts_with = "local")]
103 settings_local: bool,
104
105 /// Print what would be removed without modifying files
106 #[arg(long)]
107 print: bool,
108 },
109
110 /// Ingest data into mi6
111 #[command(subcommand)]
112 Ingest(IngestCommands),
113
114 /// Show session details
115 Session {
116 /// Session ID or PID
117 session_or_pid: String,
118
119 /// Filter by machine ID (for multi-machine scenarios)
120 #[arg(long, short = 'm')]
121 machine: Option<String>,
122
123 /// Output as JSON (all fields)
124 #[arg(long)]
125 json: bool,
126
127 /// Filter to specific fields (comma-separated)
128 #[arg(long, value_delimiter = ',')]
129 fields: Option<Vec<String>>,
130 },
131
132 /// Show mi6 status
133 Status {
134 /// Output as JSON
135 #[arg(long)]
136 json: bool,
137 },
138
139 /// Launch interactive TUI
140 Tui(TuiArgs),
141
142 /// Display event stream
143 Watch {
144 /// Filter by session ID
145 #[arg(short, long)]
146 session: Option<String>,
147
148 /// Filter by event type
149 #[arg(short = 't', long = "type")]
150 event_type: Option<String>,
151
152 /// Filter by permission mode
153 #[arg(short, long)]
154 mode: Option<String>,
155
156 /// Filter by framework
157 #[arg(long, short = 'f')]
158 framework: Option<String>,
159
160 /// Poll interval in milliseconds
161 #[arg(long, default_value = "500")]
162 poll_ms: u64,
163 },
164
165 /// Run garbage collection to remove old data
166 #[command(hide = true)]
167 Gc {
168 /// Show what would be removed without actually removing
169 #[arg(long)]
170 dry_run: bool,
171
172 /// Retention period (e.g., "30d", "7d", "24h")
173 #[arg(short, long)]
174 retention: Option<String>,
175 },
176
177 /// Manage the OpenTelemetry server
178 #[command(hide = true, subcommand)]
179 Otel(OtelCommands),
180
181 /// Upgrade mi6 to the latest version
182 Upgrade {
183 /// Target version (only for cargo installs)
184 #[arg(short = 'V', long)]
185 version: Option<String>,
186
187 /// Skip confirmation prompt
188 #[arg(short, long)]
189 yes: bool,
190
191 /// Check for updates without installing
192 #[arg(long)]
193 dry_run: bool,
194 },
195
196 /// Uninstall mi6 from the system
197 Uninstall {
198 /// Skip confirmation prompt
199 #[arg(long)]
200 confirm: bool,
201
202 /// Keep mi6 data (database, config, TUI settings)
203 #[arg(long)]
204 keep_data: bool,
205
206 /// Show what would happen without actually doing it
207 #[arg(long)]
208 dry_run: bool,
209 },
210}
211
212/// Subcommands for ingesting data into mi6.
213#[derive(Subcommand, Debug)]
214pub enum IngestCommands {
215 /// Ingest an event from AI framework hooks
216 Event {
217 /// Event type (SessionStart, PreToolUse, etc.)
218 event_type: Option<String>,
219
220 /// JSON payload (reads from stdin if not provided)
221 json_payload: Option<String>,
222
223 /// AI framework logging the event
224 #[arg(long, short = 'f')]
225 framework: Option<String>,
226 },
227
228 /// Ingest events from a transcript file
229 Transcript {
230 /// Path to the JSONL transcript file
231 path: PathBuf,
232 },
233
234 /// Ingest OpenTelemetry data from stdin
235 Otel,
236}
237
238/// Subcommands for managing the OpenTelemetry server.
239#[derive(Subcommand, Debug)]
240pub enum OtelCommands {
241 /// Start the OTel server (daemonized)
242 Start {
243 /// Port to listen on
244 #[arg(short, long, default_value = "4318")]
245 port: u16,
246
247 /// Processing mode
248 #[arg(short, long)]
249 mode: Option<OtelMode>,
250 },
251
252 /// Stop the running OTel server
253 Stop {
254 /// Port to stop
255 #[arg(short, long, default_value = "4318")]
256 port: u16,
257 },
258
259 /// Restart the OTel server
260 Restart {
261 /// Port to restart on
262 #[arg(short, long, default_value = "4318")]
263 port: u16,
264
265 /// Processing mode
266 #[arg(short, long)]
267 mode: Option<OtelMode>,
268 },
269
270 /// Show OTel server status
271 Status {
272 /// Port to check
273 #[arg(short, long, default_value = "4318")]
274 port: u16,
275 },
276
277 /// Run OTel server in foreground (for debugging)
278 Run {
279 /// Port to listen on
280 #[arg(short, long, default_value = "4318")]
281 port: u16,
282
283 /// Processing mode
284 #[arg(short, long)]
285 mode: Option<OtelMode>,
286 },
287}