Skip to main content

plan_issue_cli/
cli.rs

1use clap::{Parser, ValueEnum};
2
3use crate::ValidationError;
4use crate::commands::Command;
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)]
7pub enum OutputFormat {
8    Text,
9    Json,
10}
11
12#[derive(Debug, Clone, Parser)]
13#[command(
14    version,
15    about = "Rust implementation of the plan-issue orchestration workflow.",
16    after_help = "Usage paths:\n  - plan-issue: live GitHub-backed orchestration\n  - plan-issue-local: local-first rehearsal and dry-run flow\n\nUnsupported in plan-issue-local:\n  - Any --issue path that requires live GitHub reads/writes (for example: status-plan/ready-plan with --issue, close-plan with --issue-only, cleanup-worktrees).\n\nUse instead:\n  - plan-issue <command> ...        (live GitHub path)\n  - --body-file + --dry-run flows   (local rehearsal path where supported)\n\nBoth binaries share the same typed command contract.",
17    disable_help_subcommand = true
18)]
19pub struct Cli {
20    /// Pass-through repository target for GitHub operations.
21    #[arg(long, global = true, value_name = "owner/repo")]
22    pub repo: Option<String>,
23
24    /// Print write actions without mutating GitHub state.
25    #[arg(long, global = true)]
26    pub dry_run: bool,
27
28    /// Bypass markdown payload guard for GitHub body/comment writes.
29    #[arg(short = 'f', long, global = true)]
30    pub force: bool,
31
32    /// Output machine-readable JSON (alias for --format json).
33    #[arg(long, global = true)]
34    pub json: bool,
35
36    /// Output format.
37    #[arg(long, global = true, value_enum)]
38    pub format: Option<OutputFormat>,
39
40    #[command(subcommand)]
41    pub command: Command,
42}
43
44impl Cli {
45    pub fn resolve_output_format(&self) -> Result<OutputFormat, ValidationError> {
46        if self.json && matches!(self.format, Some(OutputFormat::Text)) {
47            return Err(ValidationError::new(
48                "invalid-output-mode",
49                "--json cannot be combined with --format text",
50            ));
51        }
52
53        if self.json || matches!(self.format, Some(OutputFormat::Json)) {
54            return Ok(OutputFormat::Json);
55        }
56
57        Ok(OutputFormat::Text)
58    }
59
60    pub fn validate(&self) -> Result<(), ValidationError> {
61        self.command.validate(self.dry_run)
62    }
63}