(&mut self)
| 254 | } |
| 255 | |
| 256 | fn load_sessions(&mut self) -> Result<()> { |
| 257 | self.conn.execute( |
| 258 | "CREATE TABLE IF NOT EXISTS sessions ( |
| 259 | session_id TEXT, |
| 260 | project TEXT, |
| 261 | cwd TEXT, |
| 262 | git_branch TEXT, |
| 263 | version TEXT, |
| 264 | title TEXT, |
| 265 | first_timestamp TEXT, |
| 266 | last_timestamp TEXT, |
| 267 | user_message_count INTEGER, |
| 268 | assistant_message_count INTEGER, |
| 269 | subagent_count INTEGER, |
| 270 | total_input_tokens INTEGER, |
| 271 | total_output_tokens INTEGER, |
| 272 | total_cache_read_input_tokens INTEGER, |
| 273 | total_cache_creation_input_tokens INTEGER, |
| 274 | pr_url TEXT, |
| 275 | pr_number INTEGER |
| 276 | )", |
| 277 | [], |
| 278 | )?; |
| 279 | |
| 280 | let Some(config) = self.ccql_config() else { |
| 281 | return Ok(()); |
| 282 | }; |
| 283 | |
| 284 | let files = discover_transcript_files(&config); |
| 285 | |
| 286 | // Subagent file counts keyed by (project, parent session id) |
| 287 | let mut subagent_counts: HashMap<(Option<String>, String), i64> = HashMap::new(); |
| 288 | for file in &files { |
| 289 | if file.agent_id.is_some() { |
| 290 | *subagent_counts |
| 291 | .entry((file.project.clone(), file.session_id.clone())) |
| 292 | .or_insert(0) += 1; |
| 293 | } |
| 294 | } |
| 295 | |
| 296 | let tx = self.conn.transaction()?; |
| 297 | { |
| 298 | let mut stmt = tx.prepare( |
| 299 | "INSERT INTO sessions VALUES |
| 300 | (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13, ?14, ?15, ?16, ?17)", |
| 301 | )?; |
| 302 | |
| 303 | for file in files.iter().filter(|f| f.agent_id.is_none()) { |
| 304 | let content = match std::fs::read_to_string(&file.path) { |
| 305 | Ok(c) => c, |
| 306 | Err(_) => continue, |
| 307 | }; |
| 308 | |
| 309 | let mut agg = SessionAggregate::default(); |
| 310 | for line in content.lines() { |
| 311 | if let Ok(json) = serde_json::from_str::<Value>(line) { |
| 312 | agg.observe(&json); |
| 313 | } |
no test coverage detected