use anyhow::Result;
use clap::{CommandFactory, Parser, Subcommand};
use clap_complete::{generate, Shell};
use octomind::config::Config;
mod commands;
#[derive(Parser)]
#[command(name = "octomind")]
#[command(version = env!("CARGO_PKG_VERSION"))]
#[command(about = "Octomind is a smart AI developer assistant with configurable MCP support")]
struct CliArgs {
#[command(subcommand)]
command: Commands,
}
#[derive(Subcommand)]
enum Commands {
Config(commands::ConfigArgs),
Run(commands::RunArgs),
Server(commands::ServerArgs),
Acp(commands::AcpArgs),
Tap(commands::TapArgs),
Untap(commands::UntapArgs),
Vars(commands::VarsArgs),
Completion {
#[arg(value_enum)]
shell: Shell,
},
}
#[tokio::main]
async fn main() -> Result<(), anyhow::Error> {
let _tracker = octomind::config::get_env_tracker();
if let Err(e) = octomind::config::get_env_tracker()
.lock()
.unwrap()
.load_dotenv_override()
{
octomind::log_debug!("Failed to load .env file: {}", e);
}
let launch_cwd = std::env::current_dir().unwrap_or_default();
octomind::mcp::set_session_working_directory(launch_cwd);
let args = CliArgs::parse();
let config = Config::load()?;
let result = run_with_cleanup(args, config).await;
if let Err(e) = octomind::mcp::server::cleanup_servers() {
octomind::log_error!("Warning: Error cleaning up MCP servers: {}", e);
}
result
}
async fn run_with_cleanup(args: CliArgs, config: Config) -> Result<(), anyhow::Error> {
let log_level = config.log_level.as_str();
if let Commands::Run(_) = &args.command {
if let Err(e) = octomind::logging::tracing_setup::init_tracing(
octomind::logging::tracing_setup::LoggingMode::Cli,
log_level,
) {
eprintln!("Warning: Failed to initialize tracing: {e}");
}
}
let sandbox_enabled = match &args.command {
Commands::Run(a) => config.sandbox || a.sandbox,
Commands::Server(a) => config.sandbox || a.sandbox,
Commands::Acp(a) => config.sandbox || a.sandbox,
_ => false,
};
if sandbox_enabled {
let cwd = std::env::current_dir()?;
octomind::sandbox::apply(&cwd)?;
}
match args.command {
Commands::Config(config_args) => commands::config::execute(&config_args, config)?,
Commands::Run(run_args) => commands::run::execute(&run_args, &config).await?,
Commands::Server(server_args) => commands::server::execute(&server_args, &config).await?,
Commands::Acp(acp_args) => commands::acp::execute(&acp_args, &config).await?,
Commands::Tap(tap_args) => commands::tap::execute(&tap_args)?,
Commands::Untap(untap_args) => commands::untap::execute(&untap_args)?,
Commands::Vars(vars_args) => commands::vars::execute(&vars_args, &config).await?,
Commands::Completion { shell } => {
let mut app = CliArgs::command();
let name = app.get_name().to_string();
generate(shell, &mut app, name, &mut std::io::stdout());
}
}
Ok(())
}