lean_ctx/core/providers/
init.rs1use std::path::Path;
12use std::sync::Arc;
13
14use super::config_provider::ConfigProvider;
15use super::config_provider::discovery::discover_configs;
16use super::github::GitHubProvider;
17use super::gitlab::GitLabProvider;
18use super::jira::JiraProvider;
19use super::mcp_bridge::McpBridgeProvider;
20use super::postgres::PostgresProvider;
21use super::provider_trait::ContextProvider;
22use super::registry::global_registry;
23
24pub fn init_builtin_providers() {
28 init_with_project_root(None);
29}
30
31pub fn init_with_project_root(project_root: Option<&Path>) {
33 let cfg = crate::core::config::Config::load();
34
35 if !cfg.providers.enabled {
36 tracing::debug!("[providers] subsystem disabled via config");
37 return;
38 }
39
40 let registry = global_registry();
41
42 if cfg.providers.github.enabled {
44 registry.register(Arc::new(GitHubProvider::new()));
45 }
46
47 if cfg.providers.gitlab.enabled {
48 registry.register(Arc::new(GitLabProvider::new()));
49 }
50
51 registry.register(Arc::new(JiraProvider::new()));
52 registry.register(Arc::new(PostgresProvider::new()));
53
54 for (name, entry) in &cfg.providers.mcp_bridges {
56 if let Some(url) = &entry.url
57 && !url.is_empty()
58 {
59 registry.register(Arc::new(McpBridgeProvider::new(name, url)));
60 continue;
61 }
62 if let Some(command) = &entry.command
63 && !command.is_empty()
64 {
65 registry.register(Arc::new(McpBridgeProvider::new_stdio(
66 name,
67 command,
68 &entry.args,
69 )));
70 continue;
71 }
72 tracing::warn!("[providers] MCP bridge '{name}' has neither url nor command — skipping");
73 }
74
75 let discovered = discover_configs(project_root);
77 let mut config_count = 0;
78 for entry in discovered {
79 match ConfigProvider::from_config(entry.config) {
80 Ok(provider) => {
81 tracing::info!(
82 "[providers] registered config provider '{}' from {}",
83 provider.id(),
84 entry.source_path.display()
85 );
86 registry.register(Arc::new(provider));
87 config_count += 1;
88 }
89 Err(e) => {
90 tracing::warn!("[providers] skipping {}: {e}", entry.source_path.display());
91 }
92 }
93 }
94
95 #[cfg(feature = "wasm")]
99 if let Ok(dir) = std::env::var("LEAN_CTX_WASM_DIR") {
100 let ids = crate::core::wasm_ext::register_providers_from_dir(registry, &dir);
101 if !ids.is_empty() {
102 tracing::info!(
103 "[providers] registered {} WASM provider(s): {ids:?}",
104 ids.len()
105 );
106 }
107 }
108
109 tracing::debug!(
110 "[providers] initialized {} provider(s) ({} config-based), {} available",
111 registry.provider_count(),
112 config_count,
113 registry.available_provider_ids().len(),
114 );
115}
116
117#[cfg(test)]
118mod tests {
119 use super::*;
120
121 #[test]
122 fn init_registers_github_when_enabled() {
123 init_builtin_providers();
124 let reg = global_registry();
125 assert!(reg.get("github").is_some());
126 }
127}