mod init;
use std::sync::Arc;
use algocline_app::{AppConfig, AppService, EngineApi};
use algocline_engine::Executor;
use algocline_mcp::AlcService;
use rmcp::{transport::stdio, ServiceExt};
fn setup_tracing(log_dir: Option<&std::path::Path>) -> anyhow::Result<()> {
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, EnvFilter};
let stderr_layer = tracing_subscriber::fmt::layer()
.with_writer(std::io::stderr)
.with_ansi(false);
let registry = tracing_subscriber::registry()
.with(EnvFilter::from_default_env())
.with(stderr_layer);
if let Some(dir) = log_dir {
let file_appender = tracing_appender::rolling::daily(dir, "tracing.log");
let file_layer = tracing_subscriber::fmt::layer()
.with_writer(file_appender)
.with_ansi(false);
registry.with(file_layer).try_init()?;
} else {
registry.try_init()?;
}
Ok(())
}
fn resolve_lib_paths() -> Vec<algocline_app::SearchPath> {
use algocline_app::SearchPath;
let mut paths = Vec::new();
if let Ok(env_paths) = std::env::var("ALC_PACKAGES_PATH") {
for p in env_paths.split(':') {
let path = std::path::PathBuf::from(p);
if path.is_dir() {
paths.push(SearchPath::env(path));
}
}
}
if let Some(home) = dirs::home_dir() {
let packages = home.join(".algocline").join("packages");
if packages.is_dir() {
paths.push(SearchPath::default_global(packages));
}
}
paths
}
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let args: Vec<String> = std::env::args().collect();
if args.get(1).is_some_and(|a| a == "init") {
return init::run(&args[2..], false).await;
}
if args.get(1).is_some_and(|a| a == "update") {
return init::run(&args[2..], true).await;
}
let config = AppConfig::from_env();
setup_tracing(config.log_dir.as_deref())?;
algocline_engine::card::init_event_bus();
match init::distribute_types() {
Ok(init::DistributedTypes { alc, alc_shapes }) => {
tracing::debug!(
"types installed: {} + {}",
alc.display(),
alc_shapes.display()
)
}
Err(e) => tracing::warn!("failed to install type stubs: {e}"),
}
tracing::info!("algocline server starting");
let search_paths = resolve_lib_paths();
let lib_paths: Vec<_> = search_paths.iter().map(|sp| sp.path.clone()).collect();
let executor = Arc::new(Executor::new(lib_paths).await?);
let app_dir = config.app_dir(); let app = Arc::new(AppService::new(executor, config, search_paths));
let server = AlcService::new(app as Arc<dyn EngineApi>, app_dir);
let service = server.serve(stdio()).await?;
service.waiting().await?;
Ok(())
}