1pub mod aggregate;
6pub mod commands;
7pub mod pidfile;
8pub mod state;
9pub mod status;
10
11#[cfg(unix)]
12pub mod fork;
13#[cfg(unix)]
14pub mod lifecycle;
15#[cfg(unix)]
16pub mod logging;
17
18pub use commands::{DaemonAction, handle_daemon_command};
19
20use crate::daemon::pidfile::{Pidfile, process_alive};
21use crate::daemon::state::{CURRENT_VERSION, DaemonState};
22
23pub fn version_mismatch_warning() -> Option<String> {
30 let home = dirs::home_dir()?;
31 let cc_switch_dir = home.join(".cc-switch");
32 let state = DaemonState::load(&cc_switch_dir.join("daemon-state.json")).ok()??;
33
34 let pidfile = Pidfile::new(cc_switch_dir.join("daemon.pid"));
36 let pid = pidfile.read().ok()??;
37 if !matches!(process_alive(pid), Ok(true)) {
38 return None;
39 }
40
41 if !state.version_mismatch() {
42 return None;
43 }
44
45 let running = if state.version.is_empty() {
46 "unknown (pre-version)".to_string()
47 } else {
48 state.version.clone()
49 };
50 Some(format!(
51 "cc daemon is running an outdated version (daemon {running}, CLI {CURRENT_VERSION}) — proxy ports/capture may be stale. Run `cc-switch daemon restart`."
52 ))
53}
54
55pub fn print_version_mismatch_warning() {
57 use colored::Colorize;
58 if let Some(msg) = version_mismatch_warning() {
59 eprintln!("{}", format!("\u{26a0} {msg}").red().bold());
60 }
61}
62
63pub enum ProxyResolution {
65 Proxied { proxy_url: String },
67 Direct,
69}
70
71pub fn try_resolve_proxy(upstream: &str) -> ProxyResolution {
74 let home = match dirs::home_dir() {
75 Some(h) => h,
76 None => return ProxyResolution::Direct,
77 };
78 let cc_switch_dir = home.join(".cc-switch");
79 let state_path = cc_switch_dir.join("daemon-state.json");
80 let pidfile_path = cc_switch_dir.join("daemon.pid");
81
82 try_resolve_proxy_from_paths(upstream, &state_path, &pidfile_path)
83}
84
85fn try_resolve_proxy_from_paths(
86 upstream: &str,
87 state_path: &std::path::Path,
88 pidfile_path: &std::path::Path,
89) -> ProxyResolution {
90 let state = match DaemonState::load(state_path) {
91 Ok(Some(s)) => s,
92 _ => return ProxyResolution::Direct,
93 };
94
95 let pidfile = Pidfile::new(pidfile_path.to_path_buf());
96 let pid = match pidfile.read() {
97 Ok(Some(pid)) => pid,
98 _ => return ProxyResolution::Direct,
99 };
100
101 match process_alive(pid) {
102 Ok(true) => {}
103 _ => return ProxyResolution::Direct,
104 }
105
106 match state.find_proxy("claude", upstream) {
107 Some(entry) => ProxyResolution::Proxied {
108 proxy_url: format!("http://127.0.0.1:{}", entry.proxy_port),
109 },
110 None => ProxyResolution::Direct,
111 }
112}