use clap::{Parser, Subcommand}; use std::env; use std::path::{Path, PathBuf}; use std::process::Command; /// PROMETEU Dispatcher (CLI). /// /// The main entry point for the user. This binary does not implement /// compilation or execution logic itself; instead, it acts as a smart /// front-end that locates and dispatches commands to specialized /// components like `prometeu-runtime` or `prometeuc`. #[derive(Parser)] #[command(name = "prometeu")] #[command(about = "Dispatcher for the Prometeu ecosystem", long_about = None)] struct Cli { #[command(subcommand)] command: Option, } #[derive(Subcommand)] enum Commands { /// Executes a cartridge using the available runtime. Run { /// Path to the cartridge (directory or .pmc file). cart: String, }, /// Executes a cartridge in Assisted Mode (Debug). /// The runtime will wait for a DevTools connection before starting. Debug { /// Path to the cartridge. cart: String, /// TCP port for the DevTools server (default: 7777). #[arg(long, default_value_t = 7777)] port: u16, }, /// Compiles a source project into a cartridge (PBC). Build { /// Project source directory. project_dir: String, }, /// Packages a cartridge directory into a distributable .pmc file. Pack { /// Cartridge directory. cart_dir: String, }, /// Diagnostic commands to verify project or cartridge integrity. Verify { #[command(subcommand)] target: VerifyCommands, }, } #[derive(Subcommand)] enum VerifyCommands { /// Verifies a project C { /// Project directory project_dir: String, }, /// Verifies a cartridge or PMC file P { /// Path to the cartridge or PMC cart_or_pmc: String, }, } fn main() { let cli = Cli::parse(); let exe_dir = match env::current_exe() { Ok(exe_path) => exe_path.parent().unwrap_or_else(|| Path::new(".")).to_path_buf(), Err(e) => { eprintln!("Error obtaining executable path: {}", e); std::process::exit(1); } }; match cli.command { Some(Commands::Run { cart }) => { dispatch(&exe_dir, "prometeu-runtime", &["--run", &cart]); } Some(Commands::Debug { cart, port }) => { dispatch( &exe_dir, "prometeu-runtime", &["--debug", &cart, "--port", &port.to_string()], ); } Some(Commands::Build { .. }) => { not_implemented("build", "prometeuc"); } Some(Commands::Pack { .. }) => { not_implemented("pack", "prometeup"); } Some(Commands::Verify { target }) => match target { VerifyCommands::C { .. } => not_implemented("verify c", "prometeuc"), VerifyCommands::P { .. } => not_implemented("verify p", "prometeup"), }, None => { use clap::CommandFactory; Cli::command().print_help().unwrap(); println!(); } } } fn get_binary_path(dir: &Path, name: &str) -> PathBuf { let mut path = dir.join(name); if cfg!(target_os = "windows") { path.set_extension("exe"); } path } fn dispatch(exe_dir: &Path, bin_name: &str, args: &[&str]) { let bin_path = get_binary_path(exe_dir, bin_name); if !bin_path.exists() { eprintln!( "prometeu: command '{}' is not yet available in this distribution", match bin_name { "prometeu-runtime" => "run/debug", "prometeuc" => "build/verify c", "prometeup" => "pack/verify p", _ => bin_name, } ); std::process::exit(1); } execute_bin(&bin_path, args); } fn execute_bin(bin_path: &Path, args: &[&str]) { let status = Command::new(bin_path) .args(args) .stdin(std::process::Stdio::inherit()) .stdout(std::process::Stdio::inherit()) .stderr(std::process::Stdio::inherit()) .status(); match status { Ok(status) => { std::process::exit(status.code().unwrap_or(0)); } Err(e) => { eprintln!("Error executing {}: {}", bin_path.display(), e); std::process::exit(1); } } } fn not_implemented(cmd: &str, _bin_name: &str) { eprintln!( "prometeu: command '{}' is not yet available in this distribution", cmd ); std::process::exit(1); }