mecha10-cli 0.1.47

Mecha10 CLI tool
Documentation
//! Mecha10 CLI
//!
//! Command-line interface for managing Mecha10 robot projects.
//!
//! # Commands
//!
//! - `mecha10 init` - Initialize a new robot project
//! - `mecha10 dev` - Start development mode with hot-reload
//! - `mecha10 run` - Run the robot in production mode
//! - `mecha10 build` - Build the project
//! - `mecha10 deploy` - Deploy to production
//! - `mecha10 train` - Submit a training job
//! - `mecha10 logs` - View logs from nodes, framework, and services (watch mode by default)
//! - `mecha10 sim` - Generate Godot simulations

mod commands;
mod component_catalog;
mod context;
mod dev;
mod framework;
mod handlers;
mod infrastructure;
mod init;
mod paths;
mod run;
mod services;
mod sim;
mod templates;
mod types;
mod ui;
mod utils;

use anyhow::Result;
use clap::Parser;
use context::CliContextBuilder;
use types::{Cli, Commands};

#[tokio::main]
async fn main() -> Result<()> {
    // Load .env file if it exists (for MECHA10_FRAMEWORK_PATH, etc.)
    // Ignore errors if .env doesn't exist
    let _ = dotenvy::dotenv();

    let cli = Cli::parse();

    // Initialize logging
    let log_level = match cli.log_level.as_str() {
        "debug" => tracing::Level::DEBUG,
        "info" => tracing::Level::INFO,
        "warn" => tracing::Level::WARN,
        "error" => tracing::Level::ERROR,
        _ => tracing::Level::INFO,
    };

    tracing_subscriber::fmt()
        .with_max_level(log_level)
        .with_target(false)
        .init();

    // Create CLI context
    let mut ctx = CliContextBuilder::new()
        .config_path(cli.config.clone())
        .log_level(log_level)
        .build()?;

    // All commands now use the handler-based architecture
    //
    // NOTE: Some handlers still define their own Args types that differ from commands::*Args.
    // This is a transitional state. Future work will migrate all handlers to use commands::*Args.
    // For now, we adapt cli_types args to handler args in main.rs.
    match &cli.command {
        Commands::Add { command } => {
            handlers::add::handle_add(&mut ctx, command).await?;
        }

        Commands::Auth { command } => {
            use commands::auth::AuthCommand;
            match command {
                AuthCommand::Login(args) => {
                    handlers::auth::handle_login(args).await?;
                }
                AuthCommand::Logout => {
                    handlers::auth::handle_logout().await?;
                }
                AuthCommand::Whoami(args) => {
                    handlers::auth::handle_whoami(args).await?;
                }
            }
        }

        Commands::Build { command } => {
            handlers::build::handle_build(&mut ctx, command).await?;
        }

        Commands::Config { command } => {
            use commands::config::ConfigCommand;
            match command {
                ConfigCommand::Push(args) => {
                    handlers::config::handle_config_push(&mut ctx, args).await?;
                }
                ConfigCommand::Pull(args) => {
                    handlers::config::handle_config_pull(&mut ctx, args).await?;
                }
                ConfigCommand::List(args) => {
                    handlers::config::handle_config_list(&mut ctx, args).await?;
                }
            }
        }

        Commands::Dev(dev_args) => {
            handlers::dev::handle_dev(&mut ctx, dev_args).await?;
        }

        Commands::Diagnostics(args) => {
            handlers::diagnostics::handle_diagnostics(&mut ctx, args).await?;
        }

        Commands::Format(format_args) => {
            use handlers::format::FormatArgs;
            let args = FormatArgs {
                check: format_args.check,
            };
            handlers::format::handle_format(&mut ctx, &args).await?;
        }

        Commands::Init(init_args) => {
            handlers::init::handle_init(&mut ctx, init_args).await?;
        }

        Commands::Lint(lint_args) => {
            use handlers::lint::LintArgs;
            let args = LintArgs { fix: lint_args.fix };
            handlers::lint::handle_lint(&mut ctx, &args).await?;
        }

        Commands::Logs(args) => {
            handlers::logs::handle_logs(&mut ctx, args).await?;
        }

        Commands::Models { command } => {
            handlers::models::handle_models(&mut ctx, command).await?;
        }

        Commands::Node(node_args) => {
            handlers::node::handle_node(node_args).await?;
        }

        Commands::Remote { command } => {
            use commands::remote::RemoteCommand;
            match command {
                RemoteCommand::Up(args) => {
                    handlers::remote::handle_remote_up(&mut ctx, args).await?;
                }
                RemoteCommand::Down => {
                    handlers::remote::handle_remote_down(&mut ctx).await?;
                }
                RemoteCommand::Logs(args) => {
                    handlers::remote::handle_remote_logs(&mut ctx, args).await?;
                }
                RemoteCommand::Ps => {
                    handlers::remote::handle_remote_ps(&mut ctx).await?;
                }
                RemoteCommand::Build => {
                    handlers::remote::handle_remote_build(&mut ctx).await?;
                }
            }
        }

        Commands::Run { command } => {
            handlers::run::handle_run(&mut ctx, command).await?;
        }

        Commands::Setup(setup_args) => {
            use handlers::setup::SetupArgs;
            let args = SetupArgs {
                check_only: setup_args.check_only,
                install_deps: !setup_args.non_interactive, // Install deps if interactive mode
            };
            handlers::setup::handle_setup(&mut ctx, &args).await?;
        }

        Commands::Status => {
            handlers::status::handle_status(&mut ctx).await?;
        }

        Commands::Topics { command } => {
            use commands::TopicsCommand;
            use handlers::topics::TopicsListArgs;

            match command {
                TopicsCommand::List {
                    pattern,
                    verbose,
                    grouped,
                } => {
                    let args = TopicsListArgs {
                        pattern: pattern.clone(),
                        verbose: *verbose,
                        grouped: *grouped,
                    };
                    handlers::topics::handle_topics_list(&mut ctx, &args).await?;
                }
            }
        }

        Commands::Topology(topology_args) => {
            handlers::topology::handle_topology(&mut ctx, topology_args).await?;
        }

        Commands::Upload(upload_args) => {
            handlers::upload::handle_upload(&mut ctx, upload_args).await?;
        }
    }

    Ok(())
}