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 --force # Overwrite existing config
20 cc-switch list
21 cc-switch remove config1 config2 config3
22 cc-switch current # Interactive mode to view and switch configurations
23 cc-switch # Enter interactive mode (same as 'current' without arguments)
24
25CODEX CONFIGURATIONS:
26 cc-switch codex add work --from-file ~/.codex/auth.json
27 cc-switch codex add personal -i # Interactive mode
28 cc-switch codex list
29 cc-switch codex use work # Switch and launch Codex
30 cc-switch codex remove work
31
32SHELL COMPLETION AND ALIASES:
33 cc-switch completion fish # Generates shell completions
34 cc-switch alias fish # Generates aliases for eval
35
36 These aliases are available:
37 - cs='cc-switch' # Quick access to cc-switch
38 - ccd='claude --dangerously-skip-permissions' # Quick Claude launch
39
40 To use aliases immediately:
41 eval \"$(cc-switch alias fish)\" # Add aliases to current session
42
43 Or add them permanently:
44 cc-switch completion fish > ~/.config/fish/completions/cc-switch.fish
45 echo \"alias cs='cc-switch'\" >> ~/.config/fish/config.fish
46 echo \"alias ccd='claude --dangerously-skip-permissions'\" >> ~/.config/fish/config.fish
47
48 Then use:
49 cs current # Instead of cc-switch current
50 ccd # Quick Claude launch"
51)]
52pub struct Cli {
53 #[command(subcommand)]
54 pub command: Option<Commands>,
55
56 #[arg(long = "list-aliases", hide = true)]
58 pub list_aliases: bool,
59
60 #[arg(long = "list-codex-aliases", hide = true)]
62 pub list_codex_aliases: bool,
63
64 #[arg(
66 long = "migrate",
67 help = "Migrate old config path to new path and exit"
68 )]
69 pub migrate: bool,
70
71 #[arg(
73 long = "store",
74 help = "Storage mode for writing configuration (env: write to env field, config: write to root with camelCase)",
75 global = true
76 )]
77 pub store: Option<String>,
78}
79
80#[derive(Subcommand)]
82#[allow(clippy::large_enum_variant)]
83pub enum Commands {
84 Add {
88 #[arg(
90 help = "Configuration alias name (cannot be 'cc')",
91 required_unless_present = "from_file"
92 )]
93 alias_name: Option<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 = "force",
185 short = 'f',
186 help = "Overwrite existing configuration with same alias"
187 )]
188 force: bool,
189
190 #[arg(
192 long = "interactive",
193 short = 'i',
194 help = "Enter configuration values interactively"
195 )]
196 interactive: bool,
197
198 #[arg(help = "API token (if not using -t flag)")]
200 token_arg: Option<String>,
201
202 #[arg(help = "API endpoint URL (if not using -u flag)")]
204 url_arg: Option<String>,
205
206 #[arg(
208 long = "from-file",
209 short = 'j',
210 help = "Import configuration from a JSON file (filename becomes alias name)"
211 )]
212 from_file: Option<String>,
213 },
214 Remove {
218 #[arg(required = true)]
220 alias_names: Vec<String>,
221 },
222 List {
226 #[arg(long = "plain", short = 'p')]
228 plain: bool,
229 #[arg(long = "name", short = 'n')]
231 name: bool,
232 },
233 #[command(alias = "C")]
237 Completion {
238 #[arg(default_value = "fish")]
240 shell: String,
241 },
242 #[command(trailing_var_arg = true)]
249 Use {
250 alias_name: String,
252
253 #[arg(long, short = 'r')]
255 resume: Option<String>,
256
257 #[arg(long, short = 'c')]
259 r#continue: bool,
260
261 #[arg(trailing_var_arg = true, allow_hyphen_values = true)]
263 prompt: Vec<String>,
264 },
265 Codex {
267 #[command(subcommand)]
268 command: Option<CodexCommands>,
269 },
270 #[command(name = "statusline")]
279 Statusline {
280 #[arg(value_enum, default_value = "install")]
282 action: StatuslineAction,
283 },
284}
285
286#[derive(Clone, Copy, clap::ValueEnum)]
288pub enum StatuslineAction {
289 Install,
291 Uninstall,
293}
294
295#[derive(Subcommand)]
297pub enum CodexCommands {
298 Add {
300 #[arg(help = "Configuration alias name")]
301 alias_name: String,
302 #[arg(long = "api-key", help = "OpenAI API key (optional)")]
303 api_key: Option<String>,
304 #[arg(long = "force", short = 'f', help = "Overwrite existing configuration")]
305 force: bool,
306 #[arg(
307 long = "interactive",
308 short = 'i',
309 help = "Enter configuration values interactively"
310 )]
311 interactive: bool,
312 #[arg(long = "from-file", help = "Import from existing auth.json file")]
313 from_file: Option<String>,
314 },
315 List {
316 #[arg(long = "plain", short = 'p')]
317 plain: bool,
318 #[arg(long = "name", short = 'n', help = "Show only name and auth mode")]
319 name: bool,
320 },
321 #[command(trailing_var_arg = true)]
322 Use {
323 alias_name: String,
324 #[arg(long = "continue", short = 'c')]
325 r#continue: bool,
326 #[arg(long = "resume", short = 'r')]
327 resume: Option<String>,
328 #[arg(trailing_var_arg = true, allow_hyphen_values = true)]
329 prompt: Vec<String>,
330 },
331 Remove {
332 #[arg(required = true)]
333 alias_names: Vec<String>,
334 },
335}