use clap::{Parser, Subcommand};
use colored::*;
use ferrum_cli::{commands::*, config::CliConfig, utils::setup_logging};
use std::process;
#[derive(Parser)]
#[command(name = "ferrum")]
#[command(about = "Ferrum - Fast LLM Inference Engine")]
#[command(version = env!("CARGO_PKG_VERSION"))]
#[command(
long_about = "A high-performance LLM inference engine with Metal/CUDA acceleration.\n\nExamples:\n ferrum doctor # Inspect this binary\n ferrum run qwen3.5:4b-q4_k_m # Metal chat\n ferrum run qwen3.5:4b # CUDA chat\n ferrum serve --model qwen3.5:4b --port 8000 # OpenAI-compatible server\n ferrum list # Show downloaded models"
)]
struct Cli {
#[command(subcommand)]
command: Commands,
#[arg(short, long, global = true)]
verbose: bool,
}
#[derive(Subcommand)]
enum Commands {
#[command(visible_alias = "r")]
Run(run::RunCommand),
#[command(hide = true)]
Bench(bench::BenchCommand),
#[command(hide = true)]
BenchServe(bench_serve::BenchServeCommand),
#[command(hide = true)]
ReplayBundle(replay_bundle::ReplayBundleCommand),
#[command(hide = true)]
VnextDeterminism(vnext_determinism::VNextDeterminismCommand),
#[command(visible_alias = "e", hide = true)]
Embed(embed::EmbedCommand),
#[command(visible_alias = "t", hide = true)]
Transcribe(transcribe::TranscribeCommand),
#[command(hide = true)]
Tts(tts::TtsCommand),
Serve(serve::ServeCommand),
Stop(stop::StopCommand),
Pull(pull::PullCommand),
#[command(visible_alias = "ls")]
List(list::ListCommand),
Doctor(doctor::DoctorCommand),
}
#[tokio::main]
async fn main() {
let cli = Cli::parse();
let suppress_chat_template_warnings = matches!(cli.command, Commands::Run(_)) && !cli.verbose;
if let Err(e) = setup_logging(cli.verbose, false, suppress_chat_template_warnings) {
eprintln!("{} Failed to setup logging: {}", "Error:".red().bold(), e);
process::exit(1);
}
let config = match CliConfig::load("ferrum.toml").await {
Ok(config) => config,
Err(e) => {
if cli.verbose {
eprintln!("{} Config: {}", "⚠️".yellow(), e);
}
CliConfig::default()
}
};
let result = match cli.command {
Commands::Run(cmd) => run::execute(cmd, config).await,
Commands::Bench(cmd) => bench::execute(cmd, config).await,
Commands::BenchServe(cmd) => bench_serve::execute(cmd, config).await,
Commands::ReplayBundle(cmd) => replay_bundle::execute(cmd, config).await,
Commands::VnextDeterminism(cmd) => vnext_determinism::execute(cmd).await,
Commands::Embed(cmd) => embed::execute(cmd, config).await,
Commands::Transcribe(cmd) => transcribe::execute(cmd, config).await,
Commands::Tts(cmd) => tts::execute(cmd, config).await,
Commands::Serve(cmd) => serve::execute(cmd, config).await,
Commands::Stop(cmd) => stop::execute(cmd).await,
Commands::Pull(cmd) => pull::execute(cmd, config).await,
Commands::List(cmd) => list::execute(cmd, config).await,
Commands::Doctor(cmd) => doctor::execute(cmd, config).await,
};
if let Err(e) = result {
eprintln!("{} {}", "Error:".red().bold(), e);
process::exit(1);
}
}