Skip to main content

cc_switch/cli/
cli.rs

1use clap::{Parser, Subcommand};
2
3/// Command-line interface for managing Claude API configurations
4#[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    /// List available configuration aliases (for shell completion)
57    #[arg(long = "list-aliases", hide = true)]
58    pub list_aliases: bool,
59
60    /// List available Codex configuration aliases (for shell completion)
61    #[arg(long = "list-codex-aliases", hide = true)]
62    pub list_codex_aliases: bool,
63
64    /// Migrate old config path (~/.cc_auto_switch/configurations.json) to new path
65    #[arg(
66        long = "migrate",
67        help = "Migrate old config path to new path and exit"
68    )]
69    pub migrate: bool,
70
71    /// Storage mode for writing configuration (env or config)
72    #[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/// Available subcommands for configuration management
81#[derive(Subcommand)]
82#[allow(clippy::large_enum_variant)]
83pub enum Commands {
84    /// Add a new Claude API configuration
85    ///
86    /// Stores a new configuration with alias, API token, base URL, and optional model settings
87    Add {
88        /// Configuration alias name (used to identify this config)
89        #[arg(
90            help = "Configuration alias name (cannot be 'cc')",
91            required_unless_present = "from_file"
92        )]
93        alias_name: Option<String>,
94
95        /// ANTHROPIC_AUTH_TOKEN value (your Claude API token)
96        #[arg(
97            long = "token",
98            short = 't',
99            help = "API token (optional if not using interactive mode)"
100        )]
101        token: Option<String>,
102
103        /// ANTHROPIC_BASE_URL value (API endpoint URL)
104        #[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        /// ANTHROPIC_MODEL value (custom model name)
112        #[arg(long = "model", short = 'm', help = "Custom model name (optional)")]
113        model: Option<String>,
114
115        /// ANTHROPIC_SMALL_FAST_MODEL value (Haiku-class model for background tasks)
116        #[arg(
117            long = "small-fast-model",
118            help = "Haiku-class model for background tasks (optional)"
119        )]
120        small_fast_model: Option<String>,
121
122        /// ANTHROPIC_MAX_THINKING_TOKENS value (Maximum thinking tokens limit)
123        #[arg(
124            long = "max-thinking-tokens",
125            help = "Maximum thinking tokens limit (optional)"
126        )]
127        max_thinking_tokens: Option<u32>,
128
129        /// API timeout in milliseconds
130        #[arg(
131            long = "api-timeout-ms",
132            help = "API timeout in milliseconds (optional)"
133        )]
134        api_timeout_ms: Option<u32>,
135
136        /// Disable non-essential traffic flag
137        #[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        /// Default Sonnet model name
144        #[arg(
145            long = "default-sonnet-model",
146            help = "Default Sonnet model name (optional)"
147        )]
148        anthropic_default_sonnet_model: Option<String>,
149
150        /// Default Opus model name
151        #[arg(
152            long = "default-opus-model",
153            help = "Default Opus model name (optional)"
154        )]
155        anthropic_default_opus_model: Option<String>,
156
157        /// Default Haiku model name
158        #[arg(
159            long = "default-haiku-model",
160            help = "Default Haiku model name (optional)"
161        )]
162        anthropic_default_haiku_model: Option<String>,
163
164        /// CLAUDE_CODE_SUBAGENT_MODEL value (model for subagents)
165        #[arg(long = "subagent-model", help = "Subagent model name (optional)")]
166        claude_code_subagent_model: Option<String>,
167
168        /// CLAUDE_CODE_DISABLE_NONSTREAMING_FALLBACK flag
169        #[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        /// CLAUDE_CODE_EFFORT_LEVEL value
176        #[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        /// Force overwrite existing configuration
183        #[arg(
184            long = "force",
185            short = 'f',
186            help = "Overwrite existing configuration with same alias"
187        )]
188        force: bool,
189
190        /// Interactive mode for entering configuration values
191        #[arg(
192            long = "interactive",
193            short = 'i',
194            help = "Enter configuration values interactively"
195        )]
196        interactive: bool,
197
198        /// Positional token argument (for backward compatibility)
199        #[arg(help = "API token (if not using -t flag)")]
200        token_arg: Option<String>,
201
202        /// Positional URL argument (for backward compatibility)
203        #[arg(help = "API endpoint URL (if not using -u flag)")]
204        url_arg: Option<String>,
205
206        /// Import configuration from a JSON file (uses filename as alias)
207        #[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 one or more configurations by alias name
215    ///
216    /// Deletes stored configurations by their alias names
217    Remove {
218        /// Configuration alias name(s) to remove (one or more)
219        #[arg(required = true)]
220        alias_names: Vec<String>,
221    },
222    /// List all stored configurations
223    ///
224    /// Displays all saved configurations with their aliases, tokens, and URLs
225    List {
226        /// Output in plain text format (default is JSON)
227        #[arg(long = "plain", short = 'p')]
228        plain: bool,
229        /// Show only name and URL
230        #[arg(long = "name", short = 'n')]
231        name: bool,
232    },
233    /// Generate shell completion scripts
234    ///
235    /// Generates completion scripts for supported shells
236    #[command(alias = "C")]
237    Completion {
238        /// Shell type (fish, zsh, bash, elvish, powershell)
239        #[arg(default_value = "fish")]
240        shell: String,
241    },
242    /// Switch to a configuration and optionally send a prompt to Claude
243    ///
244    /// Quickly switches to the specified configuration and launches Claude.
245    /// Any additional arguments after the alias name are joined and sent as a prompt.
246    /// Use --resume to resume a previous Claude session by ID.
247    /// Use --continue to continue the most recent Claude session.
248    #[command(trailing_var_arg = true)]
249    Use {
250        /// Configuration alias name to switch to
251        alias_name: String,
252
253        /// Resume a previous Claude session by ID
254        #[arg(long, short = 'r')]
255        resume: Option<String>,
256
257        /// Continue the most recent Claude session
258        #[arg(long, short = 'c')]
259        r#continue: bool,
260
261        /// Prompt to send to Claude (all remaining arguments)
262        #[arg(trailing_var_arg = true, allow_hyphen_values = true)]
263        prompt: Vec<String>,
264    },
265    /// Manage Codex (OpenAI CLI) configurations
266    Codex {
267        #[command(subcommand)]
268        command: Option<CodexCommands>,
269    },
270}
271
272/// Available subcommands for Codex configuration management
273#[derive(Subcommand)]
274pub enum CodexCommands {
275    /// Add a new Codex (OpenAI CLI) configuration
276    Add {
277        #[arg(help = "Configuration alias name")]
278        alias_name: String,
279        #[arg(long = "api-key", help = "OpenAI API key (optional)")]
280        api_key: Option<String>,
281        #[arg(long = "force", short = 'f', help = "Overwrite existing configuration")]
282        force: bool,
283        #[arg(
284            long = "interactive",
285            short = 'i',
286            help = "Enter configuration values interactively"
287        )]
288        interactive: bool,
289        #[arg(long = "from-file", help = "Import from existing auth.json file")]
290        from_file: Option<String>,
291    },
292    List {
293        #[arg(long = "plain", short = 'p')]
294        plain: bool,
295        #[arg(long = "name", short = 'n', help = "Show only name and auth mode")]
296        name: bool,
297    },
298    #[command(trailing_var_arg = true)]
299    Use {
300        alias_name: String,
301        #[arg(long = "continue", short = 'c')]
302        r#continue: bool,
303        #[arg(long = "resume", short = 'r')]
304        resume: Option<String>,
305        #[arg(trailing_var_arg = true, allow_hyphen_values = true)]
306        prompt: Vec<String>,
307    },
308    Remove {
309        #[arg(required = true)]
310        alias_names: Vec<String>,
311    },
312}