pforge-cli 0.2.1

Zero-boilerplate MCP server framework with EXTREME TDD methodology
mod commands;

use anyhow::Result;
use clap::{Parser, Subcommand};

#[derive(Parser)]
#[command(name = "pforge")]
// `version` is NOT implied by deriving Parser — clap emits --version/-V only
// when the command declares one, so pforge shipped without it and answered
// `error: unexpected argument '--version' found`.
//
// That is load-bearing beyond politeness: tooling establishes that an installed
// binary is present AND the expected build by running `<bin> --version`.
// paiml/infra's clean-room gate A4 does exactly that, and forjar's cargo
// package resource verifies every managed tool the same way — so without this,
// pforge could never be managed as a forjar stack tool.
#[command(version)]
#[command(about = "Declarative MCP server framework", long_about = None)]
struct Cli {
    #[command(subcommand)]
    command: Commands,
}

#[derive(Subcommand)]
enum Commands {
    /// Create a new pforge project
    New {
        /// Project name
        name: String,

        /// Target directory (defaults to current directory)
        #[arg(short, long)]
        path: Option<String>,
    },

    /// Build the pforge server
    Build {
        /// Build in release mode
        #[arg(short, long)]
        release: bool,
    },

    /// Run the pforge server
    Serve {
        /// Path to pforge.yaml config
        #[arg(short, long, default_value = "pforge.yaml")]
        config: String,
    },

    /// Development mode with hot reload
    Dev {
        /// Path to pforge.yaml config
        #[arg(short, long, default_value = "pforge.yaml")]
        config: String,

        /// Watch for changes
        #[arg(short, long, default_value_t = true)]
        watch: bool,
    },
}

#[tokio::main]
async fn main() -> Result<()> {
    let cli = Cli::parse();

    match cli.command {
        Commands::New { name, path } => {
            commands::new::execute(&name, path.as_deref())?;
        }
        Commands::Build { release } => {
            commands::build::execute(release)?;
        }
        Commands::Serve { config } => {
            commands::serve::execute(&config).await?;
        }
        Commands::Dev { config, watch } => {
            commands::dev::execute(&config, watch).await?;
        }
    }

    Ok(())
}