use std::path::{Path, PathBuf}; use serde::{Deserialize, Serialize}; use chrono::Utc; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Session { pub id: String, pub created_at: i64, pub updated_at: i64, pub title: String, pub model: String, pub workspace_roots: Vec, pub message_count: u32, pub token_count: u32, pub archived: bool, pub summary: Option, } impl Session { pub fn new(id: String, title: String) -> Self { let now = Utc::now().timestamp_millis(); Session { id, created_at: now, updated_at: now, title, model: "anthropic/claude-opus-4-8".to_string(), workspace_roots: vec![std::env::current_dir().unwrap_or_default()], message_count: 0, token_count: 0, archived: false, summary: None, } } pub fn session_dir(&self, base_dir: &Path) -> PathBuf { base_dir.join("sessions").join(&self.id) } pub fn conversation_path(&self, base_dir: &Path) -> PathBuf { self.session_dir(base_dir).join("conversation.json") } pub fn edit_log_path(&self, base_dir: &Path) -> PathBuf { self.session_dir(base_dir).join("edits.jsonl") } pub fn msglog_path(&self, base_dir: &Path) -> PathBuf { self.session_dir(base_dir).join("msglog.db") } pub fn save(&self, base_dir: &Path) -> std::io::Result<()> { let dir = self.session_dir(base_dir); std::fs::create_dir_all(&dir)?; let path = dir.join("session.json"); let data = serde_json::to_string_pretty(self)?; let tmp = dir.join("session.json.tmp"); std::fs::write(&tmp, data)?; std::fs::rename(&tmp, path)?; Ok(()) } pub fn load(id: &str, base_dir: &Path) -> std::io::Result { let path = base_dir.join("sessions").join(id).join("session.json"); let data = std::fs::read_to_string(path)?; let session: Session = serde_json::from_str(&data)?; Ok(session) } pub fn list(base_dir: &Path) -> Vec { let sessions_dir = base_dir.join("sessions"); let entries = match std::fs::read_dir(&sessions_dir) { Ok(e) => e, Err(_) => return Vec::new(), }; entries .filter_map(|e| e.ok()) .filter(|e| e.path().is_dir()) .filter_map(|e| { let id = e.file_name().to_string_lossy().to_string(); Session::load(&id, base_dir).ok() }) .collect() } }