code-baseline 1.6.0

Enforce architectural decisions AI coding tools keep ignoring
Documentation
pub mod format;
pub mod toml_config;

use clap::{Parser, Subcommand, ValueEnum};
use std::path::PathBuf;

#[derive(Parser)]
#[command(name = "baseline", about = "Enforce architectural decisions AI coding tools keep ignoring")]
pub struct Cli {
    #[command(subcommand)]
    pub command: Commands,
}

#[derive(Subcommand)]
pub enum Commands {
    /// Scan files for rule violations
    Scan {
        /// Paths to scan (files or directories)
        #[arg(required_unless_present = "stdin")]
        paths: Vec<PathBuf>,

        /// Path to baseline.toml config file
        #[arg(short, long, default_value = "baseline.toml")]
        config: PathBuf,

        /// Output format
        #[arg(short, long, value_enum, default_value_t = OutputFormat::Pretty)]
        format: OutputFormat,

        /// Read file content from stdin instead of disk
        #[arg(long)]
        stdin: bool,

        /// Filename to use for glob matching when using --stdin
        #[arg(long, requires = "stdin")]
        filename: Option<String>,

        /// Only scan files changed relative to a base branch (requires git)
        #[arg(long, conflicts_with = "stdin")]
        changed_only: bool,

        /// Base ref for --changed-only (default: auto-detect from CI env or "main")
        #[arg(long, requires = "changed_only")]
        base: Option<String>,

        /// Apply fixes automatically
        #[arg(long)]
        fix: bool,

        /// Preview fixes without applying (requires --fix)
        #[arg(long, requires = "fix")]
        dry_run: bool,
    },

    /// Count current occurrences of ratchet patterns and write a baseline JSON file
    Baseline {
        /// Paths to scan (files or directories)
        #[arg(required = true)]
        paths: Vec<PathBuf>,

        /// Path to baseline.toml config file
        #[arg(short, long, default_value = "baseline.toml")]
        config: PathBuf,

        /// Output file path for the baseline JSON
        #[arg(short, long, default_value = ".baseline-snapshot.json")]
        output: PathBuf,
    },

    /// Run as an MCP (Model Context Protocol) server over stdio
    Mcp {
        /// Path to baseline.toml config file
        #[arg(short, long, default_value = "baseline.toml")]
        config: PathBuf,
    },

    /// Generate a starter baseline.toml for your project
    Init {
        /// Output file path for the generated config
        #[arg(short, long, default_value = "baseline.toml")]
        output: PathBuf,

        /// Overwrite existing config file
        #[arg(long)]
        force: bool,
    },

    /// Manage ratchet rules (add, tighten, import from baseline)
    Ratchet {
        #[command(subcommand)]
        command: RatchetCommands,
    },
}

#[derive(Subcommand)]
pub enum RatchetCommands {
    /// Add a new ratchet rule, auto-counting current occurrences
    Add {
        /// Pattern to match (literal string or regex with --regex)
        pattern: String,

        /// Rule ID (default: slugified pattern)
        #[arg(long)]
        id: Option<String>,

        /// File glob filter
        #[arg(long, default_value = "**/*")]
        glob: String,

        /// Treat pattern as regex
        #[arg(long)]
        regex: bool,

        /// Custom message
        #[arg(long)]
        message: Option<String>,

        /// Path to baseline.toml config file
        #[arg(short, long, default_value = "baseline.toml")]
        config: PathBuf,

        /// Paths to scan (files or directories)
        #[arg(default_value = ".")]
        paths: Vec<PathBuf>,
    },

    /// Re-count and lower max_count for an existing ratchet rule
    Down {
        /// Rule ID of the ratchet rule to tighten
        rule_id: String,

        /// Path to baseline.toml config file
        #[arg(short, long, default_value = "baseline.toml")]
        config: PathBuf,

        /// Paths to scan (files or directories)
        #[arg(default_value = ".")]
        paths: Vec<PathBuf>,
    },

    /// Create ratchet rules from a baseline JSON file
    From {
        /// Path to the baseline JSON file (output of `baseline snapshot`)
        baseline: PathBuf,

        /// Path to baseline.toml config file
        #[arg(short, long, default_value = "baseline.toml")]
        config: PathBuf,
    },
}

#[derive(Clone, ValueEnum)]
pub enum OutputFormat {
    Pretty,
    Json,
    Compact,
    Github,
    Sarif,
    Markdown,
}