use std::path::PathBuf;
use santui_core::Santui;
use santui_db::open_db;
use santui_registry::Registry;
#[cfg(feature = "auth")]
use santui_auth::AuthClient;
const VERSION: &str = env!("CARGO_PKG_VERSION");
fn data_dir() -> PathBuf {
let home = std::env::var("HOME")
.or_else(|_| std::env::var("USERPROFILE"))
.unwrap_or_else(|_| ".".into());
PathBuf::from(home).join(".santui")
}
fn list_plugins() -> Result<(), Box<dyn std::error::Error>> {
let mut reg = Registry::new(data_dir());
println!("santui v{VERSION}");
println!();
println!("Installed plugins:");
if reg.installed.is_empty() {
println!(" (none)");
} else {
for p in ®.installed {
let status = if p.enabled { "enabled" } else { "disabled" };
println!(" {} v{} [{}]", p.name, p.version, status);
if !p.capabilities.is_empty() {
println!(" capabilities: {}", p.capabilities.join(", "));
}
}
}
println!();
match reg.fetch_manifest() {
Ok(()) => {
let installed_ids: std::collections::HashSet<&str> =
reg.installed.iter().map(|p| p.id.as_str()).collect();
let not_installed: Vec<&santui_registry::PluginManifest> = reg
.available
.iter()
.filter(|m| !installed_ids.contains(m.id.as_str()))
.collect();
println!("Available plugins ({} not installed):", not_installed.len());
if not_installed.is_empty() {
println!(" (all installed)");
} else {
for m in ¬_installed {
println!(" {} v{} — {}", m.name, m.version, m.description);
}
}
}
Err(e) => {
println!("Available plugins:");
println!(" (could not fetch manifest: {e})");
}
}
Ok(())
}
#[cfg(test)]
mod tests {
#[test]
fn test_santui_crate_version_exists() {
let version = env!("CARGO_PKG_VERSION");
assert!(!version.is_empty());
let parts: Vec<&str> = version.split('.').collect();
assert_eq!(parts.len(), 3);
}
#[test]
fn test_santui_depends_on_core_crate() {
let _ = santui_core::Santui::new();
}
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let args: Vec<String> = std::env::args().collect();
if args.iter().any(|a| a == "--version" || a == "-V") {
println!("santui v{VERSION}");
return Ok(());
}
if args.iter().any(|a| a == "--list-plugins" || a == "plugins") {
return list_plugins();
}
let _ = env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("warn"))
.format_timestamp(None)
.format_target(false)
.try_init();
let mut app = Santui::new();
let _db = open_db()?;
let dir = data_dir();
app.set_data_dir(dir.clone());
app.set_config_dir(dir);
app.set_plugin_factory(std::sync::Arc::new(santui_ipc::IpcPluginHost::new_boxed));
let exe_dir = std::env::current_exe()
.ok()
.and_then(|p| p.parent().map(|d| d.to_path_buf()));
let registry_bin = exe_dir
.as_ref()
.map(|d| {
if cfg!(windows) {
d.join("santui-registry-plugin.exe")
} else {
d.join("santui-registry-plugin")
}
})
.unwrap_or_else(|| PathBuf::from("santui-registry-plugin"));
app.register_default_plugin("plugin-registry", "Plugin Registry", ®istry_bin);
app.set_plugin_persistent("plugin-registry", true);
#[cfg(feature = "auth")]
{
let mut providers = Vec::new();
let github_id = std::env::var("SANTUI_GITHUB_CLIENT_ID")
.unwrap_or_else(|_| "Ov23liQ8S6DliNvkWmoB".into());
let config = santui_auth::AuthConfig::github(github_id);
providers.push(("github".into(), config));
let vercel_url = std::env::var("SANTUI_VERCEL_URL")
.unwrap_or_else(|_| "https://santuiapp.vercel.app".to_string());
let auth: std::sync::Arc<dyn santui_core::AuthHandle> =
std::sync::Arc::new(AuthClient::new(providers).with_vercel(vercel_url));
app.set_auth(auth);
}
app.run()
}