use anyhow::{Result, anyhow};
use crate::{agent, commands::run as run_cmd, config, debuglog};
use super::args::{ParallelSubcommand, RunCommand, RunLoopArgs, RunOneArgs};
pub fn handle_run(cmd: RunCommand, force: bool) -> Result<()> {
let profile = selected_profile(&cmd);
let resolved = config::resolve_from_cwd_with_profile(profile)?;
match cmd {
RunCommand::Resume(args) => {
maybe_enable_debug(args.debug, &resolved)?;
let overrides = agent::resolve_run_agent_overrides(&args.agent)?;
run_cmd::run_loop(
&resolved,
run_cmd::RunLoopOptions {
max_tasks: 0,
agent_overrides: overrides,
force: args.force || force,
auto_resume: true,
starting_completed: 0,
non_interactive: args.non_interactive,
parallel_workers: None,
wait_when_blocked: false,
wait_poll_ms: 1000,
wait_timeout_seconds: 0,
notify_when_unblocked: false,
wait_when_empty: false,
empty_poll_ms: 30_000,
run_event_handler: None,
},
)
}
RunCommand::One(args) => handle_run_one(args, force, &resolved),
RunCommand::Loop(args) => handle_run_loop(args, force, &resolved),
RunCommand::Parallel(args) => match args.command {
ParallelSubcommand::Status(status_args) => {
run_cmd::parallel_status(&resolved, status_args.json)
}
ParallelSubcommand::Retry(retry_args) => {
run_cmd::parallel_retry(&resolved, &retry_args.task)
}
},
}
}
fn selected_profile(cmd: &RunCommand) -> Option<&str> {
match cmd {
RunCommand::Resume(args) => args.agent.profile.as_deref(),
RunCommand::One(args) => args.agent.profile.as_deref(),
RunCommand::Loop(args) => args.agent.profile.as_deref(),
RunCommand::Parallel(_) => None,
}
}
fn maybe_enable_debug(debug: bool, resolved: &config::Resolved) -> Result<()> {
if debug {
debuglog::enable(&resolved.repo_root)?;
}
Ok(())
}
fn handle_run_one(args: RunOneArgs, force: bool, resolved: &config::Resolved) -> Result<()> {
maybe_enable_debug(args.debug, resolved)?;
let overrides = agent::resolve_run_agent_overrides(&args.agent)?;
if args.dry_run {
if args.parallel_worker {
return Err(anyhow!("--dry-run cannot be used with --parallel-worker"));
}
return run_cmd::dry_run_one(resolved, &overrides, args.id.as_deref());
}
if args.parallel_worker {
return handle_parallel_worker_run_one(args, force, resolved, overrides);
}
let resume_options = run_cmd::RunOneResumeOptions::detect(args.resume, args.non_interactive);
if let Some(task_id) = args.id.as_deref() {
run_cmd::run_one_with_id(
resolved,
&overrides,
force,
task_id,
resume_options,
None,
None,
None,
)?;
} else {
run_cmd::run_one(resolved, &overrides, force, resume_options)?;
}
Ok(())
}
fn handle_parallel_worker_run_one(
args: RunOneArgs,
force: bool,
resolved: &config::Resolved,
overrides: crate::agent::AgentOverrides,
) -> Result<()> {
let task_id = args
.id
.as_deref()
.ok_or_else(|| anyhow!("--parallel-worker requires --id <TASK_ID>"))?;
let target_branch = args
.parallel_target_branch
.as_deref()
.ok_or_else(|| anyhow!("--parallel-worker requires --parallel-target-branch"))?;
let mut worker_resolved = resolved.clone();
worker_resolved.queue_path = args
.coordinator_queue_path
.clone()
.ok_or_else(|| anyhow!("--parallel-worker requires --coordinator-queue-path"))?;
worker_resolved.done_path = args
.coordinator_done_path
.clone()
.ok_or_else(|| anyhow!("--parallel-worker requires --coordinator-done-path"))?;
log::debug!(
"parallel worker using queue/done paths: queue={}, done={}, target_branch={}",
worker_resolved.queue_path.display(),
worker_resolved.done_path.display(),
target_branch
);
run_cmd::run_one_parallel_worker(&worker_resolved, &overrides, force, task_id, target_branch)?;
Ok(())
}
fn handle_run_loop(args: RunLoopArgs, force: bool, resolved: &config::Resolved) -> Result<()> {
maybe_enable_debug(args.debug, resolved)?;
let overrides = agent::resolve_run_agent_overrides(&args.agent)?;
if args.dry_run {
return run_cmd::dry_run_loop(resolved, &overrides);
}
run_cmd::run_loop(
resolved,
run_cmd::RunLoopOptions {
max_tasks: args.max_tasks,
agent_overrides: overrides,
force,
auto_resume: args.resume,
starting_completed: 0,
non_interactive: args.non_interactive,
parallel_workers: args.parallel,
wait_when_blocked: args.wait_when_blocked,
wait_poll_ms: args.wait_poll_ms,
wait_timeout_seconds: args.wait_timeout_seconds,
notify_when_unblocked: args.notify_when_unblocked,
wait_when_empty: args.wait_when_empty,
empty_poll_ms: args.empty_poll_ms,
run_event_handler: None,
},
)
}