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