use anyhow::Result;
use indicatif::{ProgressBar, ProgressStyle};
use octomind::agent::resolver;
use octomind::config::Config;
use std::time::Duration;
pub async fn startup(
tag: Option<&str>,
config: &Config,
is_interactive: bool,
) -> Result<(Config, String)> {
if is_interactive {
let spinner = make_spinner();
let spinner_ref = &spinner;
let status_cb = |msg: &str| spinner_ref.set_message(msg.to_string());
let resolve_result = resolver::resolve_config_and_role(tag, config, Some(&status_cb)).await;
let (run_config, role) = match resolve_result {
Ok(v) => v,
Err(e) => {
spinner.finish_and_clear();
print!("\x1B[2K\r");
std::io::Write::flush(&mut std::io::stdout()).ok();
return Err(e);
}
};
if let Err(e) = mcp_init_with_spinner(&role, &run_config, &spinner).await {
spinner.finish_and_clear();
print!("\x1B[2K\r");
std::io::Write::flush(&mut std::io::stdout()).ok();
return Err(e);
}
spinner.finish_and_clear();
print!("\x1B[2K\r");
std::io::Write::flush(&mut std::io::stdout()).ok();
Ok((run_config, role))
} else {
let (run_config, role) = resolver::resolve_config_and_role(tag, config, None).await?;
octomind::mcp::initialize_mcp_for_role(&role, &run_config).await?;
Ok((run_config, role))
}
}
pub async fn startup_mcp_only(role: &str, config: &Config, is_interactive: bool) -> Result<()> {
if is_interactive {
let spinner = make_spinner();
let result = mcp_init_with_spinner(role, config, &spinner).await;
spinner.finish_and_clear();
print!("\x1B[2K\r");
std::io::Write::flush(&mut std::io::stdout()).ok();
result
} else {
octomind::mcp::initialize_mcp_for_role(role, config).await
}
}
fn make_spinner() -> ProgressBar {
let spinner = ProgressBar::new_spinner();
spinner.set_style(
ProgressStyle::default_spinner()
.template(" {spinner:.cyan} {msg:.cyan}")
.unwrap()
.tick_chars("⠋⠙⠹⠸⠼⠴⠦⠧"),
);
spinner.enable_steady_tick(Duration::from_millis(80));
spinner
}
async fn mcp_init_with_spinner(role: &str, config: &Config, spinner: &ProgressBar) -> Result<()> {
use octomind::mcp::McpInitProgress;
use std::sync::{Arc, Mutex};
let pending: Arc<Mutex<Vec<String>>> = Arc::new(Mutex::new(Vec::new()));
let total = Arc::new(Mutex::new(0usize));
let cb = |progress: McpInitProgress| match &progress {
McpInitProgress::Starting { servers } => {
*total.lock().unwrap() = servers.len();
if servers.is_empty() {
spinner.set_message("Starting MCP...".to_string());
} else {
*pending.lock().unwrap() = servers.clone();
spinner.set_message(format!(
"Starting MCP: {} [0/{}]",
servers.join(", "),
servers.len()
));
}
}
McpInitProgress::Completed { server, .. } => {
let mut pending_guard = pending.lock().unwrap();
pending_guard.retain(|s| s != server);
let done = *total.lock().unwrap() - pending_guard.len();
let total_count = *total.lock().unwrap();
if pending_guard.is_empty() {
spinner.set_message(format!("Starting MCP: done [{}/{}]", done, total_count));
} else {
spinner.set_message(format!(
"Starting MCP: {} [{}/{}]",
pending_guard.join(", "),
done,
total_count
));
}
}
};
octomind::mcp::initialize_mcp_for_role_with_callback(role, config, Some(&cb)).await
}