use super::{ChildDispatchRequest, Error};
use crate::prompt::compactor::{COMPACTOR_ROLE, compactor_goal};
use crate::prompt::inbox::{AdvanceLauncher, Launcher};
use crate::prompt::role;
use crate::prompt::{NanoIdGen, SystemClock, child_dispatch};
use crate::template::RealGit;
use crate::workspace;
use std::path::Path;
const ROLE_COMPACTOR: &str = COMPACTOR_ROLE;
#[derive(Debug)]
pub enum DispatchCliError {
Layout(workspace::LayoutError),
UnknownParent(workspace::UnknownAgent),
InvalidRole(role::validate::Invalid),
GoalRequired(String),
GoalForbidden(&'static str),
Inner(Error),
}
impl std::fmt::Display for DispatchCliError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Layout(e) => write!(f, "{e}"),
Self::UnknownParent(e) => write!(f, "{e}"),
Self::InvalidRole(inv) => write!(f, "{inv}"),
Self::GoalRequired(r) => write!(f, "--goal is required for role {r:?}"),
Self::GoalForbidden(r) => write!(f, "--goal is not accepted for role {r:?}"),
Self::Inner(e) => write!(f, "{e}"),
}
}
}
impl From<Error> for DispatchCliError {
fn from(value: Error) -> Self {
Self::Inner(value)
}
}
pub fn run(
role: &str,
repo: &Path,
branch: &str,
goal: Option<&str>,
driver_target: &Path,
) -> Result<(), DispatchCliError> {
let launcher = AdvanceLauncher::with_exe(driver_target.to_path_buf());
run_with(role, repo, branch, goal, &launcher)
}
fn run_with(
role: &str,
repo: &Path,
parent_branch: &str,
goal: Option<&str>,
launcher: &dyn Launcher,
) -> Result<(), DispatchCliError> {
workspace::require(repo).map_err(DispatchCliError::Layout)?;
workspace::require_agent(
repo,
parent_branch,
"a child forks off an existing parent (ARCH §2.5)",
&RealGit::new(),
)
.map_err(DispatchCliError::UnknownParent)?;
role::validate::validate(repo, parent_branch, role, &RealGit::new())
.map_err(DispatchCliError::InvalidRole)?;
let goal_text = if role == ROLE_COMPACTOR {
if goal.is_some() {
return Err(DispatchCliError::GoalForbidden(ROLE_COMPACTOR));
}
compactor_goal(parent_branch)
} else {
goal.ok_or_else(|| DispatchCliError::GoalRequired(role.to_owned()))?
.to_owned()
};
dispatch_child(repo, parent_branch, role, &goal_text, launcher)
}
fn dispatch_child(
repo: &Path,
parent_branch: &str,
role: &str,
goal: &str,
launcher: &dyn Launcher,
) -> Result<(), DispatchCliError> {
let parent_worktree = crate::workspace::agent_worktree(repo, parent_branch);
let req = ChildDispatchRequest {
repo,
parent_branch,
parent_worktree: &parent_worktree,
role,
goal,
fork_point: None,
};
let child = child_dispatch::run(&req, &RealGit::new(), &SystemClock, &NanoIdGen, launcher)?;
println!("{child}");
Ok(())
}
#[cfg(test)]
mod tests;