agtrace_runtime/client/
insights.rs

1use crate::Result;
2use crate::ops::{
3    CorpusStats, IndexProgress, IndexService, StatsResult, collect_tool_stats, get_corpus_overview,
4};
5use agtrace_index::Database;
6use agtrace_providers::ProviderAdapter;
7use std::path::PathBuf;
8use std::sync::{Arc, Mutex};
9
10pub struct InsightOps {
11    db: Arc<Mutex<Database>>,
12    provider_configs: Arc<Vec<(String, PathBuf)>>,
13}
14
15impl InsightOps {
16    pub fn new(db: Arc<Mutex<Database>>, provider_configs: Arc<Vec<(String, PathBuf)>>) -> Self {
17        Self {
18            db,
19            provider_configs,
20        }
21    }
22
23    pub fn corpus_stats(
24        &self,
25        project_hash: Option<&agtrace_types::ProjectHash>,
26        limit: usize,
27    ) -> Result<CorpusStats> {
28        self.ensure_index_is_fresh()?;
29
30        let db = self.db.lock().unwrap();
31        get_corpus_overview(&db, project_hash, limit)
32    }
33
34    pub fn tool_usage(
35        &self,
36        limit: Option<usize>,
37        provider: Option<String>,
38    ) -> Result<StatsResult> {
39        self.ensure_index_is_fresh()?;
40
41        let db = self.db.lock().unwrap();
42        collect_tool_stats(&db, limit, provider)
43    }
44
45    fn ensure_index_is_fresh(&self) -> Result<()> {
46        let db = self.db.lock().unwrap();
47
48        let providers: Vec<(ProviderAdapter, PathBuf)> = self
49            .provider_configs
50            .iter()
51            .filter_map(|(name, path)| {
52                agtrace_providers::create_adapter(name)
53                    .ok()
54                    .map(|p| (p, path.clone()))
55            })
56            .collect();
57
58        let service = IndexService::new(&db, providers);
59
60        // Scan all projects without filtering
61        let scope = agtrace_types::ProjectScope::All;
62
63        service.run(scope, false, |_progress: IndexProgress| {})?;
64
65        Ok(())
66    }
67}