agtrace_runtime/client/
workspace.rs1use crate::client::{InsightOps, MonitorBuilder, ProjectOps, SessionOps, WatchService};
2use crate::config::Config;
3use crate::init::{InitConfig, InitProgress, InitResult, InitService};
4use crate::ops::{CheckResult, DoctorService, InspectResult};
5use agtrace_engine::DiagnoseResult;
6use agtrace_index::Database;
7use agtrace_providers::ProviderAdapter;
8use anyhow::Result;
9use std::path::PathBuf;
10use std::sync::{Arc, Mutex};
11
12pub struct AgTrace {
13 db: Arc<Mutex<Database>>,
14 config: Arc<Config>,
15 provider_configs: Arc<Vec<(String, PathBuf)>>,
16}
17
18impl AgTrace {
19 pub fn setup<F>(config: InitConfig, progress_fn: Option<F>) -> Result<InitResult>
20 where
21 F: FnMut(InitProgress),
22 {
23 InitService::run(config, progress_fn)
24 }
25
26 pub fn open(data_dir: PathBuf) -> Result<Self> {
27 let db_path = data_dir.join("agtrace.db");
28 let config_path = data_dir.join("config.toml");
29
30 let db = Database::open(&db_path).map_err(|e| {
31 if !db_path.exists() {
32 anyhow::anyhow!(
33 "Database not found. Please run 'agtrace init' to initialize the workspace.\n\
34 Database path: {}",
35 db_path.display()
36 )
37 } else {
38 e
39 }
40 })?;
41
42 let config = if config_path.exists() {
43 Config::load_from(&config_path)?
44 } else {
45 let detected = Config::detect_providers()?;
46 detected.save_to(&config_path)?;
47 detected
48 };
49
50 let provider_configs: Vec<(String, PathBuf)> = config
51 .enabled_providers()
52 .into_iter()
53 .map(|(name, cfg)| (name.clone(), cfg.log_root.clone()))
54 .collect();
55
56 Ok(Self {
57 db: Arc::new(Mutex::new(db)),
58 config: Arc::new(config),
59 provider_configs: Arc::new(provider_configs),
60 })
61 }
62
63 pub fn diagnose(&self) -> Result<Vec<DiagnoseResult>> {
64 let providers: Vec<(ProviderAdapter, PathBuf)> = self
65 .provider_configs
66 .iter()
67 .filter_map(|(name, path)| {
68 agtrace_providers::create_adapter(name)
69 .ok()
70 .map(|p| (p, path.clone()))
71 })
72 .collect();
73 DoctorService::diagnose_all(&providers)
74 }
75
76 pub fn projects(&self) -> ProjectOps {
77 ProjectOps::new(self.db.clone(), self.provider_configs.clone())
78 }
79
80 pub fn sessions(&self) -> SessionOps {
81 SessionOps::new(self.db.clone(), self.provider_configs.clone())
82 }
83
84 pub fn insights(&self) -> InsightOps {
85 InsightOps::new(self.db.clone(), self.provider_configs.clone())
86 }
87
88 pub fn watch_service(&self) -> WatchService {
89 WatchService::new(
90 self.db.clone(),
91 self.config.clone(),
92 self.provider_configs.clone(),
93 )
94 }
95
96 pub fn workspace_monitor(&self) -> Result<MonitorBuilder> {
97 Ok(MonitorBuilder::new(
98 self.db.clone(),
99 self.provider_configs.clone(),
100 ))
101 }
102
103 pub fn database(&self) -> Arc<Mutex<Database>> {
104 self.db.clone()
105 }
106
107 pub fn config(&self) -> &Config {
108 &self.config
109 }
110
111 pub fn check_file(
112 file_path: &str,
113 provider: &ProviderAdapter,
114 provider_name: &str,
115 ) -> Result<CheckResult> {
116 DoctorService::check_file(file_path, provider, provider_name)
117 }
118
119 pub fn inspect_file(file_path: &str, lines: usize, json_format: bool) -> Result<InspectResult> {
120 DoctorService::inspect_file(file_path, lines, json_format)
121 }
122}