pub mod claude;
pub mod codex;
use serde::{Deserialize, Serialize};
use std::collections::{BTreeMap, HashMap};
#[derive(Debug, Default, Serialize, Deserialize)]
pub struct DailyActivity {
pub sessions: u32,
pub active_minutes: u32,
pub input_tokens: u64,
pub output_tokens: u64,
pub cache_read_tokens: u64,
pub cache_creation_tokens: u64,
pub models: BTreeMap<String, u64>,
pub longest_session_minutes: u32,
pub message_count: u32,
pub tool_uses: u32,
}
pub trait Harness: Sync {
fn id(&self) -> &'static str;
#[allow(dead_code)] fn display_name(&self) -> &'static str;
#[allow(dead_code)] fn is_installed(&self) -> bool;
fn parse_date_range(&self, start: &str, end: &str) -> HashMap<String, DailyActivity>;
}
static REGISTRY: &[&dyn Harness] = &[&claude::Claude, &codex::Codex];
pub fn all() -> &'static [&'static dyn Harness] {
REGISTRY
}
pub fn by_id(id: &str) -> Option<&'static dyn Harness> {
REGISTRY.iter().copied().find(|h| h.id() == id)
}
pub fn ids() -> Vec<&'static str> {
REGISTRY.iter().map(|h| h.id()).collect()
}