1use clap::{Parser, Subcommand};
2
3#[derive(Parser)]
5#[command(name = "cc-switch")]
6#[command(about = "A CLI tool for managing Claude API configurations")]
7#[command(version)]
8#[command(disable_help_subcommand = true)]
9#[command(
10 long_about = "cc-switch helps you manage multiple Claude API configurations and switch between them easily.
11
12EXAMPLES:
13 cc-switch add my-config sk-ant-xxx https://api.anthropic.com
14 cc-switch add my-config -t sk-ant-xxx -u https://api.anthropic.com
15 cc-switch add my-config -t sk-ant-xxx -u https://api.anthropic.com -m claude-3-5-sonnet-20241022
16 cc-switch add my-config -t sk-ant-xxx -u https://api.anthropic.com --small-fast-model claude-3-haiku-20240307
17 cc-switch add my-config -t sk-ant-xxx -u https://api.anthropic.com --max-thinking-tokens 8192
18 cc-switch add my-config -i # Interactive mode
19 cc-switch add my-config --from-file # Import from ~/.claude/settings.json
20 cc-switch add my-config --from-file ./other.json # Import from an explicit JSON file
21 cc-switch add my-config --force # Overwrite existing config
22 cc-switch list
23 cc-switch remove config1 config2 config3
24 cc-switch current # Interactive mode to view and switch configurations
25 cc-switch # Enter interactive mode (same as 'current' without arguments)
26
27CODEX CONFIGURATIONS:
28 cc-switch codex add work --from-file # Import from ~/.codex/auth.json
29 cc-switch codex add work --from-file ~/other/auth.json # Import from an explicit path
30 cc-switch codex add personal -i # Interactive mode
31 cc-switch codex list
32 cc-switch codex use work # Switch and launch Codex
33 cc-switch codex remove work
34
35SHELL COMPLETION AND ALIASES:
36 cc-switch completion fish # Generates shell completions
37 cc-switch alias fish # Generates aliases for eval
38
39 These aliases are available:
40 - cs='cc-switch' # Quick access to cc-switch
41 - ccd='claude --dangerously-skip-permissions' # Quick Claude launch
42
43 To use aliases immediately:
44 eval \"$(cc-switch alias fish)\" # Add aliases to current session
45
46 Or add them permanently:
47 cc-switch completion fish > ~/.config/fish/completions/cc-switch.fish
48 echo \"alias cs='cc-switch'\" >> ~/.config/fish/config.fish
49 echo \"alias ccd='claude --dangerously-skip-permissions'\" >> ~/.config/fish/config.fish
50
51 Then use:
52 cs current # Instead of cc-switch current
53 ccd # Quick Claude launch"
54)]
55pub struct Cli {
56 #[command(subcommand)]
57 pub command: Option<Commands>,
58
59 #[arg(long = "list-aliases", hide = true)]
61 pub list_aliases: bool,
62
63 #[arg(long = "list-codex-aliases", hide = true)]
65 pub list_codex_aliases: bool,
66
67 #[arg(
69 long = "migrate",
70 help = "Migrate old config path to new path and exit"
71 )]
72 pub migrate: bool,
73
74 #[arg(
76 long = "store",
77 help = "Storage mode for writing configuration (env: write to env field, config: write to root with camelCase)",
78 global = true
79 )]
80 pub store: Option<String>,
81}
82
83#[derive(Subcommand)]
85#[allow(clippy::large_enum_variant)]
86pub enum Commands {
87 Add {
91 #[arg(help = "Configuration alias name (cannot be 'cc')")]
93 alias_name: String,
94
95 #[arg(
97 long = "token",
98 short = 't',
99 help = "API token (optional if not using interactive mode)"
100 )]
101 token: Option<String>,
102
103 #[arg(
105 long = "url",
106 short = 'u',
107 help = "API endpoint URL (optional if not using interactive mode)"
108 )]
109 url: Option<String>,
110
111 #[arg(long = "model", short = 'm', help = "Custom model name (optional)")]
113 model: Option<String>,
114
115 #[arg(
117 long = "small-fast-model",
118 help = "Haiku-class model for background tasks (optional)"
119 )]
120 small_fast_model: Option<String>,
121
122 #[arg(
124 long = "max-thinking-tokens",
125 help = "Maximum thinking tokens limit (optional)"
126 )]
127 max_thinking_tokens: Option<u32>,
128
129 #[arg(
131 long = "api-timeout-ms",
132 help = "API timeout in milliseconds (optional)"
133 )]
134 api_timeout_ms: Option<u32>,
135
136 #[arg(
138 long = "disable-nonessential-traffic",
139 help = "Disable non-essential traffic flag (optional)"
140 )]
141 claude_code_disable_nonessential_traffic: Option<u32>,
142
143 #[arg(
145 long = "default-sonnet-model",
146 help = "Default Sonnet model name (optional)"
147 )]
148 anthropic_default_sonnet_model: Option<String>,
149
150 #[arg(
152 long = "default-opus-model",
153 help = "Default Opus model name (optional)"
154 )]
155 anthropic_default_opus_model: Option<String>,
156
157 #[arg(
159 long = "default-haiku-model",
160 help = "Default Haiku model name (optional)"
161 )]
162 anthropic_default_haiku_model: Option<String>,
163
164 #[arg(long = "subagent-model", help = "Subagent model name (optional)")]
166 claude_code_subagent_model: Option<String>,
167
168 #[arg(
170 long = "disable-nonstreaming-fallback",
171 help = "Disable non-streaming fallback flag (optional)"
172 )]
173 claude_code_disable_nonstreaming_fallback: Option<u32>,
174
175 #[arg(
177 long = "effort-level",
178 help = "Effort level for Claude Code (optional, e.g., 'max')"
179 )]
180 claude_code_effort_level: Option<String>,
181
182 #[arg(
184 long = "disable-prompt-caching",
185 help = "Disable prompt caching flag (optional)"
186 )]
187 disable_prompt_caching: Option<u32>,
188
189 #[arg(
191 long = "disable-experimental-betas",
192 help = "Disable experimental betas flag (optional)"
193 )]
194 claude_code_disable_experimental_betas: Option<u32>,
195
196 #[arg(
198 long = "disable-autoupdater",
199 help = "Disable auto-updater flag (optional)"
200 )]
201 disable_autoupdater: Option<u32>,
202
203 #[arg(
205 long = "force",
206 short = 'f',
207 help = "Overwrite existing configuration with same alias"
208 )]
209 force: bool,
210
211 #[arg(
213 long = "interactive",
214 short = 'i',
215 help = "Enter configuration values interactively"
216 )]
217 interactive: bool,
218
219 #[arg(help = "API token (if not using -t flag)")]
221 token_arg: Option<String>,
222
223 #[arg(help = "API endpoint URL (if not using -u flag)")]
225 url_arg: Option<String>,
226
227 #[arg(
232 long = "from-file",
233 num_args = 0..=1,
234 value_name = "PATH",
235 help = "Import configuration from JSON file (defaults to ~/.claude/settings.json if no path)"
236 )]
237 from_file: Option<Option<String>>,
238 },
239 Remove {
243 #[arg(required = true)]
245 alias_names: Vec<String>,
246 },
247 List {
251 #[arg(long = "plain", short = 'p')]
253 plain: bool,
254 #[arg(long = "name", short = 'n')]
256 name: bool,
257 },
258 #[command(alias = "C")]
262 Completion {
263 #[arg(default_value = "fish")]
265 shell: String,
266 },
267 #[command(trailing_var_arg = true)]
274 Use {
275 alias_name: String,
277
278 #[arg(long, short = 'r')]
280 resume: Option<String>,
281
282 #[arg(long, short = 'c')]
284 r#continue: bool,
285
286 #[arg(trailing_var_arg = true, allow_hyphen_values = true)]
288 prompt: Vec<String>,
289 },
290 Codex {
292 #[command(subcommand)]
293 command: Option<CodexCommands>,
294 },
295 Daemon {
300 #[command(subcommand)]
301 command: DaemonCommands,
302 },
303 #[command(name = "statusline")]
312 Statusline {
313 #[arg(value_enum, default_value = "install")]
315 action: StatuslineAction,
316 },
317}
318
319#[derive(Clone, Copy, clap::ValueEnum)]
321pub enum StatuslineAction {
322 Install,
324 Uninstall,
326}
327
328#[derive(Subcommand)]
330pub enum DaemonCommands {
331 Start {
333 #[arg(long)]
335 foreground: bool,
336
337 #[arg(long = "log-level", value_name = "LEVEL")]
339 log_level: Option<String>,
340
341 #[arg(short = 'v', long = "verbose", action = clap::ArgAction::Count)]
343 verbose: u8,
344 },
345 Stop,
347 Status {
349 #[arg(long)]
351 json: bool,
352 },
353 Restart {
355 #[arg(long)]
357 foreground: bool,
358
359 #[arg(long = "log-level", value_name = "LEVEL")]
361 log_level: Option<String>,
362
363 #[arg(short = 'v', long = "verbose", action = clap::ArgAction::Count)]
365 verbose: u8,
366 },
367}
368
369#[derive(Subcommand)]
371pub enum CodexCommands {
372 Add {
374 #[arg(help = "Configuration alias name")]
375 alias_name: String,
376 #[arg(long = "api-key", help = "OpenAI API key (optional)")]
377 api_key: Option<String>,
378 #[arg(long = "force", short = 'f', help = "Overwrite existing configuration")]
379 force: bool,
380 #[arg(
381 long = "interactive",
382 short = 'i',
383 help = "Enter configuration values interactively"
384 )]
385 interactive: bool,
386 #[arg(
391 long = "from-file",
392 num_args = 0..=1,
393 value_name = "PATH",
394 help = "Import from auth.json (defaults to ~/.codex/auth.json if no path)"
395 )]
396 from_file: Option<Option<String>>,
397 },
398 List {
399 #[arg(long = "plain", short = 'p')]
400 plain: bool,
401 #[arg(long = "name", short = 'n', help = "Show only name and auth mode")]
402 name: bool,
403 },
404 #[command(trailing_var_arg = true)]
405 Use {
406 alias_name: String,
407 #[arg(long = "continue", short = 'c')]
408 r#continue: bool,
409 #[arg(long = "resume", short = 'r')]
410 resume: Option<String>,
411 #[arg(trailing_var_arg = true, allow_hyphen_values = true)]
412 prompt: Vec<String>,
413 },
414 Remove {
415 #[arg(required = true)]
416 alias_names: Vec<String>,
417 },
418}