agtrace_runtime/client/
insights.rs1use crate::ops::{
2 CorpusStats, IndexProgress, IndexService, StatsResult, collect_tool_stats, get_corpus_overview,
3};
4use agtrace_index::Database;
5use agtrace_providers::{ProviderAdapter, ScanContext};
6use agtrace_types::{discover_project_root, project_hash_from_root};
7use anyhow::Result;
8use std::path::PathBuf;
9use std::sync::{Arc, Mutex};
10
11pub struct InsightOps {
12 db: Arc<Mutex<Database>>,
13 provider_configs: Arc<Vec<(String, PathBuf)>>,
14}
15
16impl InsightOps {
17 pub fn new(db: Arc<Mutex<Database>>, provider_configs: Arc<Vec<(String, PathBuf)>>) -> Self {
18 Self {
19 db,
20 provider_configs,
21 }
22 }
23
24 pub fn corpus_stats(&self, project_hash: Option<&str>, limit: usize) -> Result<CorpusStats> {
25 self.ensure_index_is_fresh()?;
26
27 let db = self.db.lock().unwrap();
28 get_corpus_overview(&db, project_hash, limit)
29 }
30
31 pub fn tool_usage(&self, limit: Option<usize>, source: Option<String>) -> Result<StatsResult> {
32 self.ensure_index_is_fresh()?;
33
34 let db = self.db.lock().unwrap();
35 collect_tool_stats(&db, limit, source)
36 }
37
38 fn ensure_index_is_fresh(&self) -> Result<()> {
39 let db = self.db.lock().unwrap();
40
41 let providers: Vec<(ProviderAdapter, PathBuf)> = self
42 .provider_configs
43 .iter()
44 .filter_map(|(name, path)| {
45 agtrace_providers::create_adapter(name)
46 .ok()
47 .map(|p| (p, path.clone()))
48 })
49 .collect();
50
51 let service = IndexService::new(&db, providers);
52
53 let project_hash = discover_project_root(None)
56 .ok()
57 .map(|root| project_hash_from_root(&root.display().to_string()))
58 .unwrap_or_else(|| "unknown".to_string());
59
60 let scan_context = ScanContext {
61 project_hash,
62 project_root: None,
63 provider_filter: None,
64 };
65
66 service.run(&scan_context, false, |_progress: IndexProgress| {})?;
67
68 Ok(())
69 }
70}