1use std::path::PathBuf;
14
15use clap::{Args, Subcommand};
16
17use super::help::{
18 PARALLEL_AFTER_LONG_HELP, PARALLEL_RETRY_AFTER_LONG_HELP, PARALLEL_STATUS_AFTER_LONG_HELP,
19 RESUME_AFTER_LONG_HELP, RUN_AFTER_LONG_HELP, RUN_LOOP_AFTER_LONG_HELP, RUN_ONE_AFTER_LONG_HELP,
20};
21
22#[derive(Args)]
23#[command(
24 about = "Run Ralph supervisor (executes queued tasks via codex/opencode/gemini/claude/cursor/kimi/pi)",
25 after_long_help = RUN_AFTER_LONG_HELP
26)]
27pub struct RunArgs {
28 #[command(subcommand)]
29 pub command: RunCommand,
30}
31
32#[derive(Subcommand)]
33pub enum RunCommand {
34 #[command(about = "Resume an interrupted session from where it left off", after_long_help = RESUME_AFTER_LONG_HELP)]
35 Resume(ResumeArgs),
36 #[command(about = "Run exactly one task (the first todo in the configured queue file)", after_long_help = RUN_ONE_AFTER_LONG_HELP)]
37 One(RunOneArgs),
38 #[command(about = "Run tasks repeatedly until no todo remain (or --max-tasks is reached)", after_long_help = RUN_LOOP_AFTER_LONG_HELP)]
39 Loop(RunLoopArgs),
40 #[command(
41 about = "Experimental: manage parallel mode operations",
42 after_long_help = PARALLEL_AFTER_LONG_HELP,
43 hide = true
44 )]
45 Parallel(ParallelArgs),
46}
47
48#[derive(Args)]
49pub struct ResumeArgs {
50 #[arg(long)]
51 pub force: bool,
52 #[arg(long)]
53 pub debug: bool,
54 #[arg(long)]
55 pub non_interactive: bool,
56 #[command(flatten)]
57 pub agent: crate::agent::RunAgentArgs,
58}
59
60#[derive(Args)]
61pub struct RunOneArgs {
62 #[arg(long)]
63 pub debug: bool,
64 #[arg(long)]
65 pub resume: bool,
66 #[arg(long, value_name = "TASK_ID")]
67 pub id: Option<String>,
68 #[arg(long)]
69 pub non_interactive: bool,
70 #[arg(long, conflicts_with = "parallel_worker")]
71 pub dry_run: bool,
72 #[arg(
73 long,
74 hide = true,
75 conflicts_with = "resume",
76 requires_all = ["id", "coordinator_queue_path", "coordinator_done_path", "parallel_target_branch"]
77 )]
78 pub parallel_worker: bool,
79 #[arg(
80 long,
81 hide = true,
82 value_name = "PATH",
83 requires_all = ["parallel_worker", "coordinator_done_path"]
84 )]
85 pub coordinator_queue_path: Option<PathBuf>,
86 #[arg(
87 long,
88 hide = true,
89 value_name = "PATH",
90 requires_all = ["parallel_worker", "coordinator_queue_path"]
91 )]
92 pub coordinator_done_path: Option<PathBuf>,
93 #[arg(
94 long,
95 hide = true,
96 value_name = "BRANCH",
97 requires_all = ["parallel_worker", "coordinator_queue_path", "coordinator_done_path"]
98 )]
99 pub parallel_target_branch: Option<String>,
100 #[command(flatten)]
101 pub agent: crate::agent::RunAgentArgs,
102}
103
104#[derive(Args)]
105pub struct RunLoopArgs {
106 #[arg(long, default_value_t = 0)]
107 pub max_tasks: u32,
108 #[arg(long)]
109 pub debug: bool,
110 #[arg(long)]
111 pub resume: bool,
112 #[arg(long)]
113 pub non_interactive: bool,
114 #[arg(long, conflicts_with = "parallel")]
115 pub dry_run: bool,
116 #[arg(
117 long,
118 value_parser = clap::value_parser!(u8).range(2..),
119 num_args = 0..=1,
120 default_missing_value = "2",
121 value_name = "N",
122 )]
123 pub parallel: Option<u8>,
124 #[arg(long, conflicts_with = "parallel")]
125 pub wait_when_blocked: bool,
126 #[arg(
127 long,
128 default_value_t = 1000,
129 value_parser = clap::value_parser!(u64).range(50..),
130 value_name = "MS"
131 )]
132 pub wait_poll_ms: u64,
133 #[arg(long, default_value_t = 0, value_name = "SECONDS")]
134 pub wait_timeout_seconds: u64,
135 #[arg(long)]
136 pub notify_when_unblocked: bool,
137 #[arg(long, alias = "continuous", conflicts_with = "parallel")]
138 pub wait_when_empty: bool,
139 #[arg(
140 long,
141 default_value_t = 30_000,
142 value_parser = clap::value_parser!(u64).range(50..),
143 value_name = "MS"
144 )]
145 pub empty_poll_ms: u64,
146 #[command(flatten)]
147 pub agent: crate::agent::RunAgentArgs,
148}
149
150#[derive(Args)]
151pub struct ParallelArgs {
152 #[command(subcommand)]
153 pub command: ParallelSubcommand,
154}
155
156#[derive(Subcommand)]
157pub enum ParallelSubcommand {
158 #[command(about = "Show status of parallel workers", after_long_help = PARALLEL_STATUS_AFTER_LONG_HELP)]
159 Status(ParallelStatusArgs),
160 #[command(about = "Retry a blocked or failed parallel worker", after_long_help = PARALLEL_RETRY_AFTER_LONG_HELP)]
161 Retry(ParallelRetryArgs),
162}
163
164#[derive(Args)]
165pub struct ParallelStatusArgs {
166 #[arg(long)]
167 pub json: bool,
168}
169
170#[derive(Args)]
171pub struct ParallelRetryArgs {
172 #[arg(long, value_name = "TASK_ID", required = true)]
173 pub task: String,
174}