use crate::context::CliContext;
use anyhow::Result;
use std::process::Command;
#[derive(Debug, Clone)]
pub struct SetupArgs {
pub check_only: bool,
pub install_deps: bool,
}
pub async fn handle_setup(ctx: &mut CliContext, args: &SetupArgs) -> Result<()> {
println!();
println!("🔧 Mecha10 Environment Setup");
println!("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
println!();
let mut all_ok = true;
println!("Checking prerequisites...");
println!();
println!("1. Rust toolchain:");
let rust_ok = check_rust()?;
if rust_ok {
println!(" ✅ Rust installed");
} else {
println!(" ❌ Rust not found");
all_ok = false;
}
println!("2. Cargo:");
let cargo_ok = check_cargo()?;
if cargo_ok {
println!(" ✅ Cargo installed");
} else {
println!(" ❌ Cargo not found");
all_ok = false;
}
println!("3. Docker:");
let docker = ctx.docker();
let docker_installed = docker.check_installation().is_ok();
let docker_daemon = docker.check_daemon().is_ok();
let docker_ok = docker_installed && docker_daemon;
if docker_ok {
println!(" ✅ Docker installed and running");
} else if docker_installed {
println!(" ⚠️ Docker installed but daemon not running");
println!(" Start Docker Desktop or run: sudo systemctl start docker");
all_ok = false;
} else {
println!(" ⚠️ Docker not available");
println!(" Required for control plane services (Redis, PostgreSQL)");
all_ok = false;
}
println!("4. Redis CLI (optional):");
let redis_cli_ok = check_redis_cli()?;
if redis_cli_ok {
println!(" ✅ redis-cli installed");
} else {
println!(" ⬜ redis-cli not found (optional)");
}
println!("5. pnpm (optional):");
let pnpm_ok = check_pnpm()?;
if pnpm_ok {
println!(" ✅ pnpm installed");
} else {
println!(" ⬜ pnpm not found (needed for dashboard development)");
}
println!("6. Python 3:");
let python_ok = check_python()?;
if python_ok {
println!(" ✅ Python 3 installed");
} else {
println!(" ⚠️ Python 3 not found (needed for AI model quantization)");
all_ok = false;
}
println!();
if !args.check_only && python_ok {
println!("7. Python Virtual Environment:");
match setup_venv().await {
Ok(true) => println!(" ✅ Virtual environment ready (.venv)"),
Ok(false) => println!(" ✅ Using existing virtual environment (.venv)"),
Err(e) => {
println!(" ⚠️ Failed to create virtual environment: {}", e);
println!(" Create manually with: python3 -m venv .venv");
}
}
println!();
println!("8. Python Dependencies:");
match install_python_deps(ctx).await {
Ok(true) => {
println!(" ✅ Python dependencies installed in venv");
println!();
println!(" 📝 To activate the virtual environment:");
println!(" source .venv/bin/activate");
}
Ok(false) => println!(" ⬜ No requirements.txt found (skipping)"),
Err(e) => {
println!(" ⚠️ Failed to install Python dependencies: {}", e);
println!(" Install manually with:");
println!(" source .venv/bin/activate");
println!(" pip install -r requirements.txt");
}
}
println!();
}
if !args.check_only {
println!("9. AI Models:");
let models_result = check_and_download_models(ctx).await;
match models_result {
Ok(downloaded) => {
if downloaded > 0 {
println!(" ✅ Downloaded {} recommended models", downloaded);
} else {
println!(" ✅ Recommended models already installed");
}
}
Err(e) => {
println!(" ⚠️ Failed to download models: {}", e);
println!(" You can download models later with: mecha10 models pull --all");
}
}
println!();
}
if all_ok {
println!("✨ Environment setup complete!");
println!();
println!("You're ready to use Mecha10:");
println!(" • Create a project: mecha10 init");
println!(" • Download AI models: mecha10 models pull --all");
println!(" • Start services: mecha10 infrastructure start");
println!(" • Start development: mecha10 dev");
} else {
println!("⚠️ Some prerequisites are missing");
println!();
if !rust_ok || !cargo_ok {
println!("Install Rust:");
println!(" curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh");
println!();
}
if !docker_ok {
println!("Install Docker:");
println!(" https://docs.docker.com/get-docker/");
println!();
}
if args.install_deps {
println!("Attempting to install optional dependencies...");
install_optional_deps().await?;
} else {
println!("Run with --install-deps to install optional dependencies");
}
println!();
if args.check_only {
return Err(anyhow::anyhow!("Prerequisites check failed"));
}
}
println!();
Ok(())
}
fn check_rust() -> Result<bool> {
let output = Command::new("rustc").arg("--version").output();
Ok(output.map(|o| o.status.success()).unwrap_or(false))
}
fn check_cargo() -> Result<bool> {
let output = Command::new("cargo").arg("--version").output();
Ok(output.map(|o| o.status.success()).unwrap_or(false))
}
fn check_redis_cli() -> Result<bool> {
let output = Command::new("redis-cli").arg("--version").output();
Ok(output.map(|o| o.status.success()).unwrap_or(false))
}
fn check_pnpm() -> Result<bool> {
let output = Command::new("pnpm").arg("--version").output();
Ok(output.map(|o| o.status.success()).unwrap_or(false))
}
fn check_python() -> Result<bool> {
for candidate in &["python3", "python"] {
if let Ok(output) = Command::new(candidate).arg("--version").output() {
if output.status.success() {
let version = String::from_utf8_lossy(&output.stdout);
if version.contains("Python 3.") {
return Ok(true);
}
}
}
}
Ok(false)
}
async fn install_optional_deps() -> Result<()> {
let npm_available = Command::new("npm")
.arg("--version")
.output()
.map(|o| o.status.success())
.unwrap_or(false);
if npm_available {
println!("Installing pnpm via npm...");
let output = Command::new("npm").args(["install", "-g", "pnpm"]).output()?;
if output.status.success() {
println!("✅ pnpm installed");
} else {
println!("❌ Failed to install pnpm");
}
} else {
println!("⚠️ npm not available, cannot install pnpm");
println!(" Install Node.js: https://nodejs.org/");
}
Ok(())
}
async fn setup_venv() -> Result<bool> {
let venv_path = std::path::Path::new(".venv");
if venv_path.exists() {
return Ok(false); }
let python = find_python_executable()?;
println!(" Creating virtual environment...");
let output = tokio::process::Command::new(&python)
.args(["-m", "venv", ".venv"])
.output()
.await?;
if !output.status.success() {
let stderr = String::from_utf8_lossy(&output.stderr);
anyhow::bail!("venv creation failed: {}", stderr);
}
Ok(true) }
async fn install_python_deps(_ctx: &CliContext) -> Result<bool> {
let requirements_path = std::path::Path::new("requirements.txt");
if !requirements_path.exists() {
return Ok(false);
}
let python = if std::path::Path::new(".venv/bin/python").exists() {
".venv/bin/python"
} else if std::path::Path::new(".venv/Scripts/python.exe").exists() {
".venv/Scripts/python.exe" } else {
&find_python_executable()?
};
println!(" Installing from requirements.txt...");
let output = tokio::process::Command::new(python)
.args(["-m", "pip", "install", "-r", "requirements.txt"])
.output()
.await?;
if !output.status.success() {
let stderr = String::from_utf8_lossy(&output.stderr);
anyhow::bail!("pip install failed: {}", stderr);
}
Ok(true)
}
fn find_python_executable() -> Result<String> {
for candidate in &["python3", "python"] {
if let Ok(output) = Command::new(candidate).arg("--version").output() {
if output.status.success() {
let version = String::from_utf8_lossy(&output.stdout);
if version.contains("Python 3.") {
return Ok(candidate.to_string());
}
}
}
}
anyhow::bail!("Python 3 not found. Install with: brew install python3 (macOS) or apt install python3 (Linux)")
}
async fn check_and_download_models(_ctx: &CliContext) -> Result<usize> {
Ok(0)
}