Skip to main content

rusty_commit/
cli.rs

1use clap::{Parser, Subcommand};
2
3use crate::output::prelude::OutputFormat;
4
5#[derive(Parser)]
6#[command(
7    name = "rco",
8    version,
9    author,
10    about = "Rusty Commit - AI-powered commit message generator written in Rust 🚀🤖",
11    after_help = r#"EXAMPLES:
12    # Generate a commit message for staged changes
13    rco
14
15    # Generate with context and copy to clipboard
16    rco -c "Focus on auth changes" --clipboard
17
18    # Generate 3 variations and skip confirmation
19    rco -g 3 -y
20
21    # Use GitMoji format
22    rco --fgm
23
24    # Authenticate with Anthropic
25    rco auth login
26
27    # Setup git hooks
28    rco hook set
29
30    # Generate PR description
31    rco pr generate --base main
32
33    # Generate shell completions
34    rco completions bash
35    rco completions zsh
36    rco completions fish
37"#
38)]
39pub struct Cli {
40    #[command(subcommand)]
41    pub command: Option<Commands>,
42
43    #[command(flatten)]
44    pub global: GlobalOptions,
45}
46
47#[derive(Parser, Clone)]
48pub struct GlobalOptions {
49    /// Use full GitMoji specification
50    #[arg(long = "fgm", default_value = "false")]
51    pub full_gitmoji: bool,
52
53    /// Additional user input context for the commit message
54    #[arg(short = 'c', long = "context")]
55    pub context: Option<String>,
56
57    /// Skip commit confirmation prompt
58    #[arg(short = 'y', long = "yes", default_value = "false")]
59    pub skip_confirmation: bool,
60
61    /// Show the prompt that would be used without generating commit
62    #[arg(long = "show-prompt", default_value = "false")]
63    pub show_prompt: bool,
64
65    /// Disable running pre-hooks
66    #[arg(long = "no-pre-hooks", default_value = "false")]
67    pub no_pre_hooks: bool,
68
69    /// Disable running post-hooks
70    #[arg(long = "no-post-hooks", default_value = "false")]
71    pub no_post_hooks: bool,
72
73    /// Number of commit message variations to generate (1-5)
74    #[arg(short = 'g', long = "generate", default_value = "1")]
75    pub generate_count: u8,
76
77    /// Copy generated message to clipboard instead of committing
78    #[arg(short = 'C', long = "clipboard", default_value = "false")]
79    pub clipboard: bool,
80
81    /// Exclude specific files from the diff sent to AI
82    #[arg(short = 'x', long = "exclude")]
83    pub exclude_files: Option<Vec<String>>,
84
85    /// Show detailed timing information
86    #[arg(long = "timing", default_value = "false")]
87    pub timing: bool,
88
89    /// Strip <thinking> tags from AI responses (for reasoning models)
90    #[arg(long = "strip-thinking", default_value = "false")]
91    pub strip_thinking: bool,
92
93    /// Output commit message to stdout instead of committing (for hooks)
94    #[arg(long = "print", default_value = "false")]
95    pub print_message: bool,
96
97    /// Output format (pretty, json, markdown)
98    #[arg(long = "output-format", default_value = "pretty")]
99    pub output_format: OutputFormat,
100}
101
102#[derive(Parser)]
103pub struct SetupCommand {
104    /// Skip interactive prompts and use defaults
105    #[arg(long, default_value = "false")]
106    pub defaults: bool,
107}
108
109#[derive(Subcommand)]
110pub enum Commands {
111    /// Manage Rusty Commit configuration
112    Config(ConfigCommand),
113
114    /// Setup git hooks
115    Hook(HookCommand),
116
117    /// Generate commitlint configuration
118    #[command(name = "commitlint")]
119    CommitLint(CommitLintCommand),
120
121    /// Authenticate with Claude using OAuth
122    Auth(AuthCommand),
123
124    /// Start MCP (Model Context Protocol) server
125    Mcp(McpCommand),
126
127    /// Check for updates and update rusty-commit
128    Update(UpdateCommand),
129
130    /// Generate PR description
131    Pr(PrCommand),
132
133    /// Interactive model selection
134    Model(ModelCommand),
135
136    /// Interactive setup wizard
137    Setup(SetupCommand),
138
139    /// Generate shell completions
140    Completions(CompletionsCommand),
141}
142
143#[derive(Parser)]
144pub struct PrCommand {
145    #[command(subcommand)]
146    pub action: PrAction,
147}
148
149#[derive(Subcommand)]
150pub enum PrAction {
151    /// Generate a PR description
152    Generate {
153        /// Base branch to compare against (default: main)
154        #[arg(short, long)]
155        base: Option<String>,
156    },
157    /// Open PR creation page in browser
158    Browse {
159        /// Base branch to compare against (default: main)
160        #[arg(short, long)]
161        base: Option<String>,
162    },
163}
164
165#[derive(Parser)]
166pub struct ConfigCommand {
167    #[command(subcommand)]
168    pub action: ConfigAction,
169}
170
171#[derive(Subcommand)]
172pub enum ConfigAction {
173    /// Set a configuration value
174    Set {
175        /// Configuration key=value pairs
176        #[arg(required = true)]
177        pairs: Vec<String>,
178    },
179    /// Get a configuration value
180    Get {
181        /// Configuration key
182        key: String,
183    },
184    /// Reset configuration to defaults
185    Reset {
186        /// Reset all configuration
187        #[arg(long)]
188        all: bool,
189        /// Specific keys to reset
190        keys: Vec<String>,
191    },
192    /// Show secure storage status
193    Status,
194    /// Describe all configuration options with examples and descriptions
195    Describe,
196    /// Add a new provider account
197    AddProvider {
198        /// Provider to add (openai, anthropic, claude-code, qwen, ollama, xai, gemini, perplexity, azure)
199        #[arg(short, long)]
200        provider: Option<String>,
201        /// Account alias (e.g., "work", "personal")
202        #[arg(short, long)]
203        alias: Option<String>,
204    },
205    /// List all configured accounts
206    ListAccounts,
207    /// Switch to a different account
208    UseAccount {
209        /// Account alias to use
210        alias: String,
211    },
212    /// Remove an account
213    RemoveAccount {
214        /// Account alias to remove
215        alias: String,
216    },
217    /// Show account details
218    ShowAccount {
219        /// Account alias (defaults to "default")
220        alias: Option<String>,
221    },
222}
223
224#[derive(Parser)]
225pub struct HookCommand {
226    #[command(subcommand)]
227    pub action: HookAction,
228}
229
230#[derive(Subcommand)]
231pub enum HookAction {
232    /// Install prepare-commit-msg git hook
233    PrepareCommitMsg,
234    /// Install commit-msg git hook (non-interactive)
235    CommitMsg,
236    /// Uninstall git hooks
237    Unset,
238    /// Install or uninstall pre-commit hooks
239    Precommit {
240        /// Install pre-commit hooks
241        #[arg(long)]
242        set: bool,
243        /// Uninstall pre-commit hooks
244        #[arg(long)]
245        unset: bool,
246    },
247}
248
249#[derive(Parser)]
250pub struct CommitLintCommand {
251    /// Set configuration non-interactively
252    #[arg(long)]
253    pub set: bool,
254}
255
256#[derive(Parser)]
257pub struct AuthCommand {
258    #[command(subcommand)]
259    pub action: AuthAction,
260}
261
262#[derive(Subcommand)]
263pub enum AuthAction {
264    /// Login with Claude OAuth
265    Login,
266    /// Logout and remove stored tokens
267    Logout,
268    /// Check authentication status
269    Status,
270}
271
272#[derive(Parser)]
273pub struct McpCommand {
274    #[command(subcommand)]
275    pub action: McpAction,
276}
277
278#[derive(Subcommand)]
279pub enum McpAction {
280    /// Start MCP server on TCP port (for Cursor integration)
281    Server {
282        /// Port to listen on
283        #[arg(short, long, default_value = "3000")]
284        port: Option<u16>,
285    },
286    /// Start MCP server over STDIO (for direct integration)
287    Stdio,
288}
289
290#[derive(Parser)]
291pub struct UpdateCommand {
292    /// Check for updates without installing
293    #[arg(short, long)]
294    pub check: bool,
295
296    /// Force update even if already on latest version
297    #[arg(short, long)]
298    pub force: bool,
299
300    /// Specify version to update to (e.g., "1.0.2")
301    #[arg(short, long)]
302    pub version: Option<String>,
303}
304
305#[derive(Parser)]
306pub struct ModelCommand {
307    /// List available models for current provider
308    #[arg(long = "list")]
309    pub list: bool,
310    /// Specify provider to list models for
311    #[arg(short, long)]
312    pub provider: Option<String>,
313}
314
315#[derive(Parser)]
316pub struct CompletionsCommand {
317    /// Shell to generate completions for
318    #[arg(value_enum)]
319    pub shell: clap_complete::Shell,
320}