pub mod aggregate;
pub mod commands;
pub mod pidfile;
pub mod state;
pub mod status;
#[cfg(unix)]
pub mod fork;
#[cfg(unix)]
pub mod lifecycle;
#[cfg(unix)]
pub mod logging;
pub use commands::{DaemonAction, handle_daemon_command};
use crate::daemon::pidfile::{Pidfile, process_alive};
use crate::daemon::state::{CURRENT_VERSION, DaemonState};
pub fn version_mismatch_warning() -> Option<String> {
let home = dirs::home_dir()?;
let cc_switch_dir = home.join(".cc-switch");
let state = DaemonState::load(&cc_switch_dir.join("daemon-state.json")).ok()??;
let pidfile = Pidfile::new(cc_switch_dir.join("daemon.pid"));
let pid = pidfile.read().ok()??;
if !matches!(process_alive(pid), Ok(true)) {
return None;
}
if !state.version_mismatch() {
return None;
}
let running = if state.version.is_empty() {
"unknown (pre-version)".to_string()
} else {
state.version.clone()
};
Some(format!(
"cc daemon is running an outdated version (daemon {running}, CLI {CURRENT_VERSION}) — proxy ports/capture may be stale. Run `cc-switch daemon restart`."
))
}
pub fn print_version_mismatch_warning() {
use colored::Colorize;
if let Some(msg) = version_mismatch_warning() {
eprintln!("{}", format!("\u{26a0} {msg}").red().bold());
}
}
pub enum ProxyResolution {
Proxied { proxy_url: String },
Direct,
}
pub fn try_resolve_proxy(upstream: &str) -> ProxyResolution {
let home = match dirs::home_dir() {
Some(h) => h,
None => return ProxyResolution::Direct,
};
let cc_switch_dir = home.join(".cc-switch");
let state_path = cc_switch_dir.join("daemon-state.json");
let pidfile_path = cc_switch_dir.join("daemon.pid");
try_resolve_proxy_from_paths(upstream, &state_path, &pidfile_path)
}
fn try_resolve_proxy_from_paths(
upstream: &str,
state_path: &std::path::Path,
pidfile_path: &std::path::Path,
) -> ProxyResolution {
let state = match DaemonState::load(state_path) {
Ok(Some(s)) => s,
_ => return ProxyResolution::Direct,
};
let pidfile = Pidfile::new(pidfile_path.to_path_buf());
let pid = match pidfile.read() {
Ok(Some(pid)) => pid,
_ => return ProxyResolution::Direct,
};
match process_alive(pid) {
Ok(true) => {}
_ => return ProxyResolution::Direct,
}
match state.find_proxy("claude", upstream) {
Some(entry) => ProxyResolution::Proxied {
proxy_url: format!("http://127.0.0.1:{}", entry.proxy_port),
},
None => ProxyResolution::Direct,
}
}