Skip to main content

ralph/cli/
helpers.rs

1//! Shared helpers for the top-level CLI surface.
2//!
3//! Responsibilities:
4//! - Emit top-level helper commands such as `help-all` and `cli-spec`.
5//! - Centralize small queue/list helper utilities reused by subcommands.
6//! - Keep stdout handling consistent for machine-readable CLI helpers.
7//!
8//! Not handled here:
9//! - Clap argument definitions.
10//! - Subcommand business logic beyond small shared helpers.
11//! - Parse-regression tests.
12//!
13//! Invariants/assumptions:
14//! - `cli-spec` remains machine-readable and broken-pipe tolerant.
15//! - Shared queue/list helpers preserve existing read-only semantics.
16
17use anyhow::Result;
18use std::io::{self, Write};
19
20use crate::contracts::QueueFile;
21
22use super::args::{CliSpecArgs, CliSpecFormatArg};
23
24pub fn handle_cli_spec(args: CliSpecArgs) -> Result<()> {
25    match args.format {
26        CliSpecFormatArg::Json => {
27            let json = crate::commands::cli_spec::emit_cli_spec_json_pretty()?;
28            let mut stdout = io::stdout().lock();
29            if let Err(err) = writeln!(stdout, "{json}") {
30                if err.kind() == io::ErrorKind::BrokenPipe {
31                    return Ok(());
32                }
33                return Err(err.into());
34            }
35            Ok(())
36        }
37    }
38}
39
40pub fn handle_help_all() {
41    println!(
42        "Core:\n  init\n  app\n  queue\n  task\n  scan\n  run\n  config\n  version\n\nAdvanced:\n  prompt\n  doctor\n  context\n  prd\n  completions\n  migrate\n  cleanup\n  watch\n  webhook\n  productivity\n  plugin\n  runner\n  tutorial\n  undo\n  machine\n  cli-spec\n\nExperimental:\n  run loop --parallel\n  run parallel status\n  run parallel retry"
43    );
44}
45
46pub(crate) fn load_and_validate_queues_read_only(
47    resolved: &crate::config::Resolved,
48    include_done: bool,
49) -> Result<(QueueFile, Option<QueueFile>)> {
50    crate::queue::load_and_validate_queues(resolved, include_done)
51}
52
53pub(crate) fn resolve_list_limit(limit: u32, all: bool) -> Option<usize> {
54    if all || limit == 0 {
55        None
56    } else {
57        Some(limit as usize)
58    }
59}