Skip to main content

cc_switch/
utils.rs

1use anyhow::{Context, Result};
2use std::io::{self, Write};
3use std::path::PathBuf;
4use std::process::{Command, Stdio};
5use std::thread;
6use std::time::Duration;
7
8/// Get the path to the configuration storage file
9///
10/// Returns `~/.claude/cc_auto_switch_setting.json`
11///
12/// # Errors
13/// Returns error if home directory cannot be found
14pub fn get_config_storage_path() -> Result<PathBuf> {
15    let home_dir = dirs::home_dir().context("Could not find home directory")?;
16    Ok(home_dir.join(".claude").join("cc_auto_switch_setting.json"))
17}
18
19/// Get the path to the Claude settings file
20///
21/// Returns the path to settings.json, using custom directory if configured
22/// Defaults to `~/.claude/settings.json`
23///
24/// # Errors
25/// Returns error if home directory cannot be found or path is invalid
26pub fn get_claude_settings_path(custom_dir: Option<&str>) -> Result<PathBuf> {
27    if let Some(dir) = custom_dir {
28        let custom_path = PathBuf::from(dir);
29        if custom_path.is_absolute() {
30            Ok(custom_path.join("settings.json"))
31        } else {
32            // If relative path, resolve from home directory
33            let home_dir = dirs::home_dir().context("Could not find home directory")?;
34            Ok(home_dir.join(custom_path).join("settings.json"))
35        }
36    } else {
37        // Default path
38        let home_dir = dirs::home_dir().context("Could not find home directory")?;
39        Ok(home_dir.join(".claude").join("settings.json"))
40    }
41}
42
43/// Read input from stdin with a prompt
44///
45/// # Arguments
46/// * `prompt` - The prompt to display to the user
47///
48/// # Returns
49/// The user's input as a String
50pub fn read_input(prompt: &str) -> Result<String> {
51    print!("{prompt}");
52    io::stdout().flush().context("Failed to flush stdout")?;
53    let mut input = String::new();
54    io::stdin()
55        .read_line(&mut input)
56        .context("Failed to read input")?;
57    Ok(input.trim().to_string())
58}
59
60/// Read sensitive input (token) with a prompt (without echoing)
61///
62/// # Arguments
63/// * `prompt` - The prompt to display to the user
64///
65/// # Returns
66/// The user's input as a String
67pub fn read_sensitive_input(prompt: &str) -> Result<String> {
68    print!("{prompt}");
69    io::stdout().flush().context("Failed to flush stdout")?;
70    let mut input = String::new();
71    io::stdin()
72        .read_line(&mut input)
73        .context("Failed to read input")?;
74    Ok(input.trim().to_string())
75}
76
77/// Execute claude command with or without --dangerously-skip-permissions
78///
79/// # Arguments
80/// * `skip_permissions` - Whether to add --dangerously-skip-permissions flag
81pub fn execute_claude_command(skip_permissions: bool) -> Result<()> {
82    let mut command = Command::new("claude");
83    if skip_permissions {
84        command.arg("--dangerously-skip-permissions");
85    }
86
87    command
88        .stdin(Stdio::inherit())
89        .stdout(Stdio::inherit())
90        .stderr(Stdio::inherit());
91
92    let mut child = command.spawn().with_context(
93        || "Failed to launch Claude CLI. Make sure 'claude' command is available in PATH",
94    )?;
95
96    let status = child
97        .wait()
98        .with_context(|| "Failed to wait for Claude CLI process")?;
99
100    if !status.success() {
101        anyhow::bail!("Claude CLI exited with error status: {}", status);
102    }
103
104    Ok(())
105}
106
107/// Launch Claude CLI with proper delay
108pub fn launch_claude() -> Result<()> {
109    println!("\nWaiting 0.5 seconds before launching Claude...");
110    thread::sleep(Duration::from_millis(500));
111
112    println!("Launching Claude CLI...");
113    let mut child = Command::new("claude")
114        .arg("--dangerously-skip-permissions")
115        .stdin(Stdio::inherit())
116        .stdout(Stdio::inherit())
117        .stderr(Stdio::inherit())
118        .spawn()
119        .with_context(
120            || "Failed to launch Claude CLI. Make sure 'claude' command is available in PATH",
121        )?;
122
123    let status = child.wait()?;
124
125    if !status.success() {
126        anyhow::bail!("Claude CLI exited with error status: {}", status);
127    }
128
129    Ok(())
130}