Skip to main content

opencode_ralph_loop_cli/
cli.rs

1use std::path::PathBuf;
2
3use clap::{Parser, Subcommand, ValueEnum};
4use clap_complete::Shell;
5
6#[derive(Parser)]
7#[command(
8    name = "opencode-ralph-loop-cli",
9    version,
10    about = "Scaffolder CLI for OpenCode Ralph Loop plugin",
11    long_about = None,
12)]
13pub struct Cli {
14    #[command(subcommand)]
15    pub command: Commands,
16
17    /// Increases log verbosity in stderr
18    #[arg(long, global = true)]
19    pub verbose: bool,
20
21    /// Suppresses non-essential output
22    #[arg(long, global = true)]
23    pub quiet: bool,
24
25    /// Disables ANSI colors
26    #[arg(long = "no-color", global = true, env = "NO_COLOR")]
27    pub no_color: bool,
28
29    /// Output format
30    #[arg(
31        long,
32        global = true,
33        value_name = "FORMAT",
34        default_value = "text",
35        env = "OPENCODE_RALPH_LOOP_CLI_OUTPUT"
36    )]
37    pub output: OutputFormat,
38
39    /// Alternative configuration file
40    #[arg(
41        long,
42        global = true,
43        value_name = "FILE",
44        env = "OPENCODE_RALPH_LOOP_CLI_CONFIG"
45    )]
46    pub config: Option<std::path::PathBuf>,
47
48    /// Prints the JSON output schema and exits
49    #[arg(long = "json-schema", global = true)]
50    pub json_schema: bool,
51}
52
53#[derive(Subcommand)]
54pub enum Commands {
55    /// Generates the complete .opencode/ structure
56    Init(InitArgs),
57    /// Validates existing structure against embedded templates
58    Check(CheckArgs),
59    /// Removes files tracked via manifest
60    Uninstall(UninstallArgs),
61    /// Lists embedded templates with hashes
62    List,
63    /// Runs environment diagnostics
64    Doctor,
65    /// Generates shell completion scripts
66    Completions {
67        /// Target shell
68        shell: Shell,
69    },
70}
71
72#[derive(clap::Args, Debug)]
73pub struct InitArgs {
74    /// Target directory where .opencode/ will be created
75    #[arg(long, default_value = ".")]
76    pub path: PathBuf,
77
78    /// Overwrites existing files
79    #[arg(long, env = "OPENCODE_RALPH_LOOP_CLI_FORCE")]
80    pub force: bool,
81
82    /// Simulates generation without writing to disk
83    #[arg(long = "dry-run")]
84    pub dry_run: bool,
85
86    /// Overrides the @opencode-ai/plugin version
87    #[arg(
88        long = "plugin-version",
89        env = "OPENCODE_RALPH_LOOP_CLI_PLUGIN_VERSION"
90    )]
91    pub plugin_version: Option<String>,
92
93    /// Suppresses package.json generation
94    #[arg(long = "no-package-json")]
95    pub no_package_json: bool,
96
97    /// Suppresses .gitignore generation
98    #[arg(long = "no-gitignore")]
99    pub no_gitignore: bool,
100
101    /// Suppresses .manifest.json generation
102    #[arg(long = "no-manifest")]
103    pub no_manifest: bool,
104
105    /// Prints the install command at the end (default: disabled)
106    #[arg(long = "install-hint")]
107    pub install_hint: bool,
108}
109
110#[derive(clap::Args, Debug)]
111pub struct CheckArgs {
112    /// Directory to audit
113    #[arg(long, default_value = ".")]
114    pub path: PathBuf,
115
116    /// Fails on first drift detected
117    #[arg(long)]
118    pub strict: bool,
119
120    /// Forces exit zero regardless of drift
121    #[arg(long = "exit-zero")]
122    pub exit_zero: bool,
123}
124
125#[derive(clap::Args, Debug)]
126pub struct UninstallArgs {
127    /// Target directory
128    #[arg(long, default_value = ".")]
129    pub path: PathBuf,
130
131    /// Simulates removal without deleting files
132    #[arg(long = "dry-run")]
133    pub dry_run: bool,
134
135    /// Ignores missing manifest
136    #[arg(long, env = "OPENCODE_RALPH_LOOP_CLI_FORCE")]
137    pub force: bool,
138
139    /// Preserves ralph-loop.local.md
140    #[arg(long = "keep-state")]
141    pub keep_state: bool,
142
143    /// Preserves node_modules if present
144    #[arg(long = "keep-node-modules")]
145    pub keep_node_modules: bool,
146}
147
148#[derive(ValueEnum, Clone, Default, Debug, PartialEq)]
149pub enum OutputFormat {
150    #[default]
151    Text,
152    Json,
153    Ndjson,
154    Quiet,
155}