two-step agent spawn: request_init_config + request_spawn

This commit is contained in:
damocles 2026-05-20 14:32:54 +02:00 committed by Mara
parent 42437f9c6a
commit 80dd5bb69e
7 changed files with 165 additions and 14 deletions

View file

@ -57,6 +57,18 @@ pub async fn approve(coord: Arc<Coordinator>, id: i64) -> Result<()> {
}
finish_approval(&coord, &approval, result, terminal_tag)
}
ApprovalKind::InitConfig => {
// Seed the proposed config repo. Runs synchronously — it's just
// a few git operations with no nixos-container involvement.
let result: Result<()> = async {
lifecycle::setup_proposed(&proposed_dir, &approval.agent).await?;
lifecycle::ensure_claude_dir(&claude_dir)?;
lifecycle::ensure_state_dir(&notes_dir)?;
Ok(())
}
.await;
finish_approval(&coord, &approval, result, None)
}
ApprovalKind::Spawn => {
// Run the spawn in the background so the approve POST returns
// immediately. The dashboard reads `transient` to render a spinner.
@ -144,6 +156,7 @@ fn finish_approval(
let approval_kind = match approval.kind {
ApprovalKind::Spawn => "spawn",
ApprovalKind::ApplyCommit => "apply_commit",
ApprovalKind::InitConfig => "init_config",
};
let sha_short = approval
.fetched_sha
@ -159,12 +172,19 @@ fn finish_approval(
note.clone(),
approval.description.clone(),
);
// For spawn/rebuild approvals, also surface the underlying action so
// the manager knows whether the container actually came up. The
// ApprovalResolved event already carries the same `ok` signal but
// For spawn/rebuild/init_config approvals, also surface the underlying
// action so the manager knows whether the lifecycle step succeeded.
// The ApprovalResolved event already carries the same `ok` signal but
// separating it lets the manager react to the lifecycle change
// without having to special-case approvals.
match approval.kind {
ApprovalKind::InitConfig => {
if ok {
coord.notify_manager(&HelperEvent::ConfigReady {
agent: approval.agent.clone(),
});
}
}
ApprovalKind::Spawn => coord.notify_manager(&HelperEvent::Spawned {
agent: approval.agent.clone(),
ok,
@ -439,6 +459,7 @@ pub async fn deny(coord: &Coordinator, id: i64, note: Option<&str>) -> Result<()
let approval_kind = match a.kind {
ApprovalKind::Spawn => "spawn",
ApprovalKind::ApplyCommit => "apply_commit",
ApprovalKind::InitConfig => "init_config",
};
let sha_short = sha.as_deref().map(|s| s[..s.len().min(12)].to_owned());
let description = a.description.clone();