opencode-ralph-loop-cli 0.1.0

Scaffolder CLI for OpenCode Ralph Loop plugin — one command setup
Documentation
use std::path::PathBuf;

use clap::{Parser, Subcommand, ValueEnum};
use clap_complete::Shell;

#[derive(Parser)]
#[command(
    name = "opencode-ralph-loop-cli",
    version,
    about = "Scaffolder CLI for OpenCode Ralph Loop plugin",
    long_about = None,
)]
pub struct Cli {
    #[command(subcommand)]
    pub command: Commands,

    /// Increases log verbosity in stderr
    #[arg(long, global = true)]
    pub verbose: bool,

    /// Suppresses non-essential output
    #[arg(long, global = true)]
    pub quiet: bool,

    /// Disables ANSI colors
    #[arg(long = "no-color", global = true, env = "NO_COLOR")]
    pub no_color: bool,

    /// Output format
    #[arg(
        long,
        global = true,
        value_name = "FORMAT",
        default_value = "text",
        env = "OPENCODE_RALPH_LOOP_CLI_OUTPUT"
    )]
    pub output: OutputFormat,

    /// Alternative configuration file
    #[arg(
        long,
        global = true,
        value_name = "FILE",
        env = "OPENCODE_RALPH_LOOP_CLI_CONFIG"
    )]
    pub config: Option<std::path::PathBuf>,

    /// Prints the JSON output schema and exits
    #[arg(long = "json-schema", global = true)]
    pub json_schema: bool,
}

#[derive(Subcommand)]
pub enum Commands {
    /// Generates the complete .opencode/ structure
    Init(InitArgs),
    /// Validates existing structure against embedded templates
    Check(CheckArgs),
    /// Removes files tracked via manifest
    Uninstall(UninstallArgs),
    /// Lists embedded templates with hashes
    List,
    /// Runs environment diagnostics
    Doctor,
    /// Generates shell completion scripts
    Completions {
        /// Target shell
        shell: Shell,
    },
}

#[derive(clap::Args, Debug)]
pub struct InitArgs {
    /// Target directory where .opencode/ will be created
    #[arg(long, default_value = ".")]
    pub path: PathBuf,

    /// Overwrites existing files
    #[arg(long, env = "OPENCODE_RALPH_LOOP_CLI_FORCE")]
    pub force: bool,

    /// Simulates generation without writing to disk
    #[arg(long = "dry-run")]
    pub dry_run: bool,

    /// Overrides the @opencode-ai/plugin version
    #[arg(
        long = "plugin-version",
        env = "OPENCODE_RALPH_LOOP_CLI_PLUGIN_VERSION"
    )]
    pub plugin_version: Option<String>,

    /// Suppresses package.json generation
    #[arg(long = "no-package-json")]
    pub no_package_json: bool,

    /// Suppresses .gitignore generation
    #[arg(long = "no-gitignore")]
    pub no_gitignore: bool,

    /// Suppresses .manifest.json generation
    #[arg(long = "no-manifest")]
    pub no_manifest: bool,

    /// Prints the install command at the end (default: disabled)
    #[arg(long = "install-hint")]
    pub install_hint: bool,
}

#[derive(clap::Args, Debug)]
pub struct CheckArgs {
    /// Directory to audit
    #[arg(long, default_value = ".")]
    pub path: PathBuf,

    /// Fails on first drift detected
    #[arg(long)]
    pub strict: bool,

    /// Forces exit zero regardless of drift
    #[arg(long = "exit-zero")]
    pub exit_zero: bool,
}

#[derive(clap::Args, Debug)]
pub struct UninstallArgs {
    /// Target directory
    #[arg(long, default_value = ".")]
    pub path: PathBuf,

    /// Simulates removal without deleting files
    #[arg(long = "dry-run")]
    pub dry_run: bool,

    /// Ignores missing manifest
    #[arg(long, env = "OPENCODE_RALPH_LOOP_CLI_FORCE")]
    pub force: bool,

    /// Preserves ralph-loop.local.md
    #[arg(long = "keep-state")]
    pub keep_state: bool,

    /// Preserves node_modules if present
    #[arg(long = "keep-node-modules")]
    pub keep_node_modules: bool,
}

#[derive(ValueEnum, Clone, Default, Debug, PartialEq)]
pub enum OutputFormat {
    #[default]
    Text,
    Json,
    Ndjson,
    Quiet,
}