use anyhow::Result;
use std::process::Command;
use crate::session::Session;
use crate::util::pgrep_f;
pub mod claude;
pub mod codex;
pub mod gemini;
pub trait Backend: Send + Sync {
fn name(&self) -> &'static str;
fn scan(&self) -> Result<Vec<Session>>;
fn resume(&self, s: &Session) -> Command;
fn running(&self, s: &Session) -> Vec<String> {
pgrep_f(&s.id)
}
fn trash(&self, s: &Session) -> Result<()> {
crate::trash::move_to_trash(&s.origin, self.name(), &s.id)?;
Ok(())
}
}
pub fn all() -> Vec<Box<dyn Backend>> {
vec![
Box::new(claude::ClaudeBackend),
Box::new(codex::CodexBackend),
Box::new(gemini::GeminiBackend),
]
}
pub fn scan_all(backends: &[Box<dyn Backend>]) -> Vec<Session> {
let mut out = Vec::new();
for b in backends {
match b.scan() {
Ok(sessions) => out.extend(sessions),
Err(e) => eprintln!("ccr: {} backend scan failed: {e}", b.name()),
}
}
out.sort_by_key(|s| std::cmp::Reverse(s.last_activity));
out
}
pub fn by_name<'a>(backends: &'a [Box<dyn Backend>], name: &str) -> Option<&'a dyn Backend> {
backends
.iter()
.find(|b| b.name() == name)
.map(|b| b.as_ref())
}