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}