Skip to main content

opencode_ralph_loop_cli/
lib.rs

1pub mod cli;
2pub mod commands;
3pub mod config;
4pub mod error;
5pub mod fs_atomic;
6pub mod hash;
7pub mod manifest;
8pub mod output;
9pub mod templates;
10
11use clap::Parser;
12
13use crate::cli::{Cli, Commands};
14use crate::error::CliError;
15
16const JSON_OUTPUT_SCHEMA: &str = r#"{
17  "$schema": "https://json-schema.org/draft-07/schema#",
18  "title": "opencode-ralph-loop-cli output",
19  "description": "JSON/NDJSON output schema for opencode-ralph-loop-cli v1",
20  "type": "object",
21  "required": ["status", "command", "files", "summary", "cli_version", "schema_version", "duration_ms", "plugin_version"],
22  "properties": {
23    "status":         { "type": "string", "description": "ok | drift | error:<msg>" },
24    "command":        { "type": "string" },
25    "cli_version":    { "type": "string" },
26    "schema_version": { "type": "integer" },
27    "plugin_version": { "type": "string" },
28    "duration_ms":    { "type": "integer" },
29    "files": {
30      "type": "array",
31      "items": {
32        "type": "object",
33        "required": ["path", "action", "sha256", "size_bytes"],
34        "properties": {
35          "path":            { "type": "string" },
36          "action":          { "type": "string", "enum": ["created","updated","skipped","modified","missing","removed"] },
37          "sha256":          { "type": "string" },
38          "expected_sha256": { "type": ["string", "null"] },
39          "size_bytes":      { "type": "integer" }
40        }
41      }
42    },
43    "summary": {
44      "type": "object",
45      "properties": {
46        "created":  { "type": "integer" },
47        "updated":  { "type": "integer" },
48        "skipped":  { "type": "integer" },
49        "modified": { "type": "integer" },
50        "missing":  { "type": "integer" },
51        "removed":  { "type": "integer" }
52      }
53    }
54  }
55}"#;
56
57pub fn run() -> i32 {
58    init_tracing();
59
60    // SIGINT → exit code 130 (per PRD)
61    ctrlc::set_handler(|| {
62        std::process::exit(130);
63    })
64    .ok();
65
66    let cli = Cli::parse();
67
68    // --json-schema: print JSON output schema and exit
69    if cli.json_schema {
70        println!("{}", JSON_OUTPUT_SCHEMA);
71        return 0;
72    }
73
74    // Load XDG config (silently falls back to defaults)
75    let _config = crate::config::Config::load(cli.config.as_ref());
76
77    let result = dispatch(cli);
78
79    match result {
80        Ok(()) => 0,
81        Err(e) => {
82            eprintln!("ERROR: {e}");
83            e.exit_code()
84        }
85    }
86}
87
88fn dispatch(cli: Cli) -> Result<(), CliError> {
89    match cli.command {
90        Commands::Init(args) => commands::init::run(&args, &cli.output),
91        Commands::Check(args) => commands::check::run(&args, &cli.output),
92        Commands::Uninstall(args) => commands::uninstall::run(&args, &cli.output),
93        Commands::List => commands::list::run(&cli.output),
94        Commands::Doctor => {
95            let path = std::env::current_dir().map_err(|e| CliError::io("current directory", e))?;
96            commands::doctor::run(&path, &cli.output)
97        }
98        Commands::Completions { shell } => {
99            commands::completions::run(shell);
100            Ok(())
101        }
102    }
103}
104
105fn init_tracing() {
106    use tracing_subscriber::{EnvFilter, fmt};
107    fmt()
108        .with_env_filter(EnvFilter::from_default_env())
109        .with_writer(std::io::stderr)
110        .init();
111}