main-spex 0.20.0

AI-first development framework that turns specifications into deterministic, verifiable code
mod commands;
mod config;
mod error;
mod rule;
mod spec;
mod support;
mod templates;
mod tracing;

use std::process::ExitCode;

use clap::{Parser, Subcommand};

use commands::check::CheckArgs;
use commands::check_schema::CheckSchemaArgs;
use commands::coverage::CoverageArgs;
use commands::info::InfoArgs;
use commands::jq::JqArgs;
use commands::rules::RulesArgs;
use commands::specs::SpecsArgs;
use error::{Result, failure_report};

#[derive(Parser)]
#[command(
    name = "spex",
    version,
    about = "AI-first specification-driven development framework cli"
)]
struct Cli {
    #[command(subcommand)]
    command: Commands,
}

#[derive(Subcommand)]
enum Commands {
    #[command(about = "Initialize a spex project")]
    Init,
    #[command(about = "Update spex to the latest version (skills, rules, docs, etc.)")]
    Update,
    #[command(about = "Run spex and rule checks")]
    Check(CheckArgs),
    #[command(about = "Report coverage")]
    Coverage(CoverageArgs),
    #[command(about = "Validate JSON or YAML files against a JSON Schema")]
    CheckSchema(CheckSchemaArgs),
    #[command(about = "Print project configuration")]
    Info(InfoArgs),
    #[command(about = "Query JSON or YAML with a jq filter")]
    Jq(JqArgs),
    #[command(about = "Print the project rules")]
    Rules(RulesArgs),
    #[command(about = "Print the project specs")]
    Specs(SpecsArgs),
}

const TOOL_FAILURE_EXIT_CODE: u8 = 2;

fn main() -> ExitCode {
    run(Cli::parse().command).unwrap_or_else(|error| {
        eprintln!("{}", failure_report(&error));
        ExitCode::from(TOOL_FAILURE_EXIT_CODE)
    })
}

fn run(command: Commands) -> Result<ExitCode> {
    match command {
        Commands::Init => commands::init::run(),
        Commands::Update => commands::update::run(),
        Commands::Check(args) => commands::check::run(args),
        Commands::CheckSchema(args) => commands::check_schema::run(args),
        Commands::Coverage(args) => commands::coverage::run(args),
        Commands::Info(args) => commands::info::run(args),
        Commands::Jq(args) => commands::jq::run(args),
        Commands::Rules(args) => commands::rules::run(args),
        Commands::Specs(args) => commands::specs::run(args),
    }
}