use anyhow::Result;
use colored::Colorize;
async fn build_embedder() -> Option<std::sync::Arc<dyn crate::core::Embedder>> {
match crate::core::FastEmbedder::new().await {
Ok(e) => Some(std::sync::Arc::new(e)),
Err(e) => {
tracing::warn!("FastEmbedder init failed ({e}); daemon falling back to BM25-only mode");
None
}
}
}
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 embedder = build_embedder().await;
let cfg = crate::service::load_user_config();
let mut 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);
if let Some(e) = embedder {
state = state.with_embedder(e);
}
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(())
}