use anyhow::Result;
use colored::Colorize;
async fn build_embedder() -> Result<std::sync::Arc<dyn crate::core::Embedder>> {
let embedder = crate::core::FastEmbedder::new().await.map_err(|e| {
tracing::error!("FastEmbedder init failed: {e:#}");
anyhow::anyhow!("FastEmbedder init failed: {e}")
})?;
let dim = <crate::core::FastEmbedder as crate::core::Embedder>::dimension(&embedder);
let provider = embedder.provider();
let metal_hint = match provider {
trusty_embedder::ExecutionProvider::CoreML => " (Metal GPU / ANE)",
trusty_embedder::ExecutionProvider::Cuda => " (CUDA GPU)",
trusty_embedder::ExecutionProvider::Cpu => "",
};
tracing::info!(
"embedder initialized: model=AllMiniLML6V2(Q) dim={dim} provider={provider}{metal_hint}"
);
Ok(std::sync::Arc::new(embedder))
}
pub async fn handle_start(port: u16, foreground: bool) -> Result<()> {
let _ = foreground;
if let Some(pid) = crate::service::running_daemon_pid() {
tracing::info!("daemon already running (pid {pid}), exiting cleanly");
eprintln!(
"{} trusty-search daemon already running (pid {pid}); nothing to do",
"✓".green()
);
return Ok(());
}
let cfg = crate::service::load_user_config();
let state = crate::service::SearchAppState::new(crate::core::registry::IndexRegistry::new())
.with_local_model(cfg.local_model)
.with_openrouter_model(cfg.openrouter_model)
.with_openrouter_api_key(cfg.openrouter_api_key);
let install_state = state.clone();
tokio::spawn(async move {
match build_embedder().await {
Ok(embedder) => {
install_state.install_embedder(embedder).await;
tracing::info!("embedder ready — vector lane online");
}
Err(e) => {
tracing::error!(
"embedder failed to initialize: {e:#} — daemon will continue in BM25-only mode"
);
eprintln!(
"{} embedder failed to initialize: {e}\n\
Daemon is up but running BM25-only. Check the model cache at \
~/Library/Caches/trusty-search/models/ and network access.",
"✗".red()
);
}
}
});
match crate::service::run_daemon(state, port).await {
Ok(()) => {}
Err(crate::service::DaemonError::AlreadyRunning(p)) => {
tracing::info!(
"daemon already running (lock at {}), exiting cleanly",
p.display()
);
eprintln!(
"{} trusty-search daemon already running (lock at {}); nothing to do",
"✓".green(),
p.display()
);
return Ok(());
}
Err(e) => {
eprintln!("{} daemon failed: {e}", "✗".red());
std::process::exit(1);
}
}
Ok(())
}