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    },
230    /// Generate shell completion scripts
231    ///
232    /// Generates completion scripts for supported shells
233    #[command(alias = "C")]
234    Completion {
235        /// Shell type (fish, zsh, bash, elvish, powershell)
236        #[arg(default_value = "fish")]
237        shell: String,
238    },
239    /// Switch to a configuration and optionally send a prompt to Claude
240    ///
241    /// Quickly switches to the specified configuration and launches Claude.
242    /// Any additional arguments after the alias name are joined and sent as a prompt.
243    /// Use --resume to resume a previous Claude session by ID.
244    /// Use --continue to continue the most recent Claude session.
245    #[command(trailing_var_arg = true)]
246    Use {
247        /// Configuration alias name to switch to
248        alias_name: String,
249
250        /// Resume a previous Claude session by ID
251        #[arg(long, short = 'r')]
252        resume: Option<String>,
253
254        /// Continue the most recent Claude session
255        #[arg(long, short = 'c')]
256        r#continue: bool,
257
258        /// Prompt to send to Claude (all remaining arguments)
259        #[arg(trailing_var_arg = true, allow_hyphen_values = true)]
260        prompt: Vec<String>,
261    },
262    /// Manage Codex (OpenAI CLI) configurations
263    Codex {
264        #[command(subcommand)]
265        command: Option<CodexCommands>,
266    },
267}
268
269/// Available subcommands for Codex configuration management
270#[derive(Subcommand)]
271pub enum CodexCommands {
272    /// Add a new Codex (OpenAI CLI) configuration
273    Add {
274        #[arg(help = "Configuration alias name")]
275        alias_name: String,
276        #[arg(long = "api-key", help = "OpenAI API key (optional)")]
277        api_key: Option<String>,
278        #[arg(long = "force", short = 'f', help = "Overwrite existing configuration")]
279        force: bool,
280        #[arg(
281            long = "interactive",
282            short = 'i',
283            help = "Enter configuration values interactively"
284        )]
285        interactive: bool,
286        #[arg(long = "from-file", help = "Import from existing auth.json file")]
287        from_file: Option<String>,
288    },
289    List {
290        #[arg(long = "plain", short = 'p')]
291        plain: bool,
292    },
293    #[command(trailing_var_arg = true)]
294    Use {
295        alias_name: String,
296        #[arg(long = "continue", short = 'c')]
297        r#continue: bool,
298        #[arg(long = "resume", short = 'r')]
299        resume: Option<String>,
300        #[arg(trailing_var_arg = true, allow_hyphen_values = true)]
301        prompt: Vec<String>,
302    },
303    Remove {
304        #[arg(required = true)]
305        alias_names: Vec<String>,
306    },
307}