Skip to main content

muster_cli/
cli.rs

1//! CLI type definitions for muster.
2//!
3//! This module defines the clap command structure used by the muster binary.
4//! It is exposed as a library target so that tools like `clap-markdown` can
5//! generate documentation from the type definitions.
6
7use std::path::PathBuf;
8
9use clap::{Parser, Subcommand};
10
11/// Terminal session group management built on tmux.
12///
13/// Muster organizes terminal sessions into named, color-coded groups with saved
14/// profiles, runtime theming, and push-based state synchronization via tmux
15/// control mode.
16#[derive(Parser)]
17#[command(name = "muster", version, about = "Terminal session group management")]
18pub struct Cli {
19    /// Path to the config directory
20    #[arg(long, env = "MUSTER_CONFIG_DIR")]
21    pub config_dir: Option<PathBuf>,
22
23    /// Output in JSON format
24    #[arg(long, global = true)]
25    pub json: bool,
26
27    #[command(subcommand)]
28    pub command: Command,
29}
30
31/// Top-level commands.
32#[derive(Subcommand)]
33pub enum Command {
34    /// List profiles and running sessions
35    List,
36
37    /// Create or attach to a profile's session
38    #[command(alias = "launch")]
39    Up {
40        /// Profile name or ID
41        profile: String,
42        /// Switch to this tab index on attach
43        #[arg(long)]
44        tab: Option<u32>,
45        /// Create session but don't attach
46        #[arg(long)]
47        detach: bool,
48    },
49
50    /// Attach to a running session
51    #[command(hide = true)]
52    Attach {
53        /// Profile name, ID, or session name
54        session: String,
55        /// Tab index to switch to
56        #[arg(long)]
57        tab: Option<u32>,
58    },
59
60    /// Destroy a session
61    #[command(alias = "kill")]
62    Down {
63        /// Profile name, ID, or session name
64        session: String,
65    },
66
67    /// Create an ad-hoc session
68    New {
69        /// Display name
70        name: String,
71        /// Tab definition (`name:cwd[:command]`), repeatable
72        #[arg(long)]
73        tab: Vec<String>,
74        /// Color (hex)
75        #[arg(long, default_value = "#808080")]
76        color: String,
77        /// Create session but don't attach
78        #[arg(long)]
79        detach: bool,
80    },
81
82    /// Manage session colors
83    #[command(alias = "colour")]
84    Color {
85        /// Profile name, ID, or session name
86        session: Option<String>,
87        /// New color (hex or named)
88        color: Option<String>,
89        /// List available named colors
90        #[arg(long)]
91        list: bool,
92    },
93
94    /// Show processes running inside sessions
95    Ps {
96        /// Profile name or ID (shows all sessions if omitted)
97        profile: Option<String>,
98    },
99
100    /// Show listening ports inside sessions
101    Ports {
102        /// Profile name or ID (shows all sessions if omitted)
103        profile: Option<String>,
104    },
105
106    /// Show resource usage (CPU, memory, GPU) for session processes
107    Top {
108        /// Profile name or ID (shows all sessions if omitted)
109        profile: Option<String>,
110    },
111
112    /// Show all sessions with details
113    Status,
114
115    /// Peek at recent terminal output
116    Peek {
117        /// Profile name, ID, or session name
118        session: String,
119        /// Tab names to show (all if omitted)
120        #[arg(value_name = "TABS")]
121        tabs: Vec<String>,
122        /// Lines of output per tab
123        #[arg(short = 'n', long, default_value = "50")]
124        lines: u32,
125    },
126
127    /// Pin the current tab to the session's profile
128    Pin,
129
130    /// Unpin the current tab from the session's profile
131    Unpin,
132
133    /// Sync a window rename to the profile (called by tmux hook)
134    #[command(hide = true)]
135    SyncRename {
136        /// Session name
137        session: String,
138        /// Window index
139        window: u32,
140        /// New window name
141        name: String,
142    },
143
144    /// Handle pane death notification (called by tmux hook)
145    #[command(name = "_pane-died", hide = true)]
146    PaneDied {
147        session_name: String,
148        window_name: String,
149        pane_id: String,
150        exit_code: i32,
151    },
152
153    /// Handle bell notification (called by tmux hook)
154    #[command(name = "_bell", hide = true)]
155    Bell {
156        session_name: String,
157        window_name: String,
158    },
159
160    /// Profile management
161    Profile {
162        #[command(subcommand)]
163        action: ProfileAction,
164    },
165
166    /// Notification management
167    Notifications {
168        #[command(subcommand)]
169        action: NotificationAction,
170    },
171
172    /// Release a muster-managed session back to plain tmux
173    Release {
174        /// Profile name, ID, or session name
175        session: String,
176        /// New name for the released session (defaults to session name without muster_ prefix)
177        #[arg(long)]
178        name: Option<String>,
179    },
180
181    /// Adopt an existing tmux session under muster management
182    Adopt {
183        /// Existing tmux session name
184        session: String,
185        /// Display name (defaults to session name)
186        #[arg(long)]
187        name: Option<String>,
188        /// Color (hex or named)
189        #[arg(long, default_value = "#808080")]
190        color: String,
191        /// Also save as a persistent profile
192        #[arg(long)]
193        save: bool,
194        /// Adopt without attaching
195        #[arg(long)]
196        detach: bool,
197    },
198
199    /// Output shell integration code for automatic profile suggestions on cd
200    #[command(name = "shell-init")]
201    ShellInit {
202        /// Shell type: fish, bash, or zsh
203        shell: String,
204    },
205
206    /// Suggest profiles matching a directory (used by shell integration)
207    #[command(name = "shell-suggest", hide = true)]
208    ShellSuggest {
209        /// Directory path to match against profile CWDs
210        dir: String,
211    },
212
213    /// Show or update settings
214    Settings {
215        /// Set terminal emulator (e.g. ghostty, alacritty, kitty, wezterm, terminal, iterm2)
216        #[arg(long)]
217        terminal: Option<String>,
218        /// Set default shell
219        #[arg(long)]
220        shell: Option<String>,
221        /// Set tmux binary path
222        #[arg(long)]
223        tmux_path: Option<String>,
224    },
225}
226
227/// Profile subcommands.
228#[derive(Subcommand)]
229pub enum ProfileAction {
230    /// List all profiles
231    List,
232
233    /// Delete a profile
234    Delete {
235        /// Profile name or ID
236        id: String,
237    },
238
239    /// Save a new profile (or snapshot a running session with --from-session)
240    Save {
241        /// Profile name
242        name: String,
243        /// Tab definition (`name:cwd[:command]`), repeatable
244        #[arg(long)]
245        tab: Vec<String>,
246        /// Color (hex or named)
247        #[arg(long, default_value = "#808080")]
248        color: String,
249        /// Snapshot tabs from a running tmux session
250        #[arg(long, value_name = "SESSION")]
251        from_session: Option<String>,
252    },
253
254    /// Add a tab to an existing profile
255    AddTab {
256        /// Profile name or ID
257        profile: String,
258        /// Tab name
259        #[arg(long)]
260        name: String,
261        /// Working directory
262        #[arg(long)]
263        cwd: String,
264        /// Startup command
265        #[arg(long)]
266        command: Option<String>,
267    },
268
269    /// Show a profile's full definition
270    Show {
271        /// Profile name or ID
272        id: String,
273    },
274
275    /// Edit a profile in $EDITOR
276    Edit {
277        /// Profile name or ID
278        id: String,
279    },
280
281    /// Update profile fields inline
282    Update {
283        /// Profile name or ID
284        id: String,
285        /// New display name
286        #[arg(long)]
287        name: Option<String>,
288        /// New color (hex or named)
289        #[arg(long)]
290        color: Option<String>,
291    },
292
293    /// Remove a tab from a profile
294    RemoveTab {
295        /// Profile name or ID
296        profile: String,
297        /// Tab name or 0-based index
298        tab: String,
299    },
300}
301
302/// Notification subcommands.
303#[derive(Subcommand)]
304pub enum NotificationAction {
305    /// Install macOS notification app bundle
306    Setup,
307    /// Remove macOS notification app bundle
308    Remove,
309    /// Send a test notification to verify the notification system works
310    Test,
311}