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