use super::clock::{Clock, IdGen};
use super::subagent::{SpawnRequest, spawn_subagent_branch};
use super::{Error, SOULS_DIR};
use crate::prompt::inbox::{self, Launcher};
use crate::template::GitRunner;
use crate::workspace;
use std::path::{Path, PathBuf};
pub struct ChildDispatchRequest<'a> {
pub repo: &'a Path,
pub parent_branch: &'a str,
pub parent_worktree: &'a Path,
pub role: &'a str,
pub goal: &'a str,
pub fork_point: Option<&'a str>,
}
pub fn run(
req: &ChildDispatchRequest<'_>,
git: &dyn GitRunner,
clock: &dyn Clock,
id_gen: &dyn IdGen,
launcher: &dyn Launcher,
) -> Result<String, Error> {
let sub_id = format!("{}-{}", clock.now_compact(), id_gen.short());
let sub_branch = format!("{}-{sub_id}", req.parent_branch);
let sub_worktree = workspace::agent_worktree(req.repo, &sub_branch);
let commit =
workspace::governing_config(req.repo, req.parent_branch, git).map_err(|source| {
Error::Git {
op: "governing config",
source,
}
})?;
let soul_rel = format!("{SOULS_DIR}/{}.md", req.role);
let soul = workspace::show_control(req.repo, &commit, &soul_rel, git).map_err(|source| {
Error::ControlRead {
path: PathBuf::from(format!("{commit}:{soul_rel}")),
source,
}
})?;
let commit_subject = format!("dispatch: {} [{sub_branch}]", req.role);
spawn_subagent_branch(
&SpawnRequest {
parent_worktree: req.parent_worktree,
parent_branch: req.parent_branch,
sub_branch: &sub_branch,
sub_worktree: &sub_worktree,
fork_point: req.fork_point,
goal_text: req.goal,
soul_text: Some(&soul),
commit_subject: &commit_subject,
},
git,
)?;
inbox::deposit(req.repo, &sub_branch, req.parent_branch, req.goal, clock)?;
inbox::probe_and_launch(req.repo, &sub_branch, launcher).map_err(|source| {
Error::ExecutorLock {
path: inbox::inbox_dir(req.repo, &sub_branch),
source,
}
})?;
Ok(sub_branch)
}
#[cfg(test)]
mod tests;