phase 8 step 2: approval-gated spawn + dashboard spinner
This commit is contained in:
parent
a42fdb3a5c
commit
c59fa8541c
10 changed files with 382 additions and 90 deletions
|
|
@ -3,37 +3,85 @@
|
|||
//! `&Coordinator` and the request parameters; callers stitch the response
|
||||
//! shape they want (HTTP redirect vs JSON).
|
||||
|
||||
use anyhow::{Result, bail};
|
||||
use hive_sh4re::{ApprovalStatus, HelperEvent, MANAGER_AGENT, Message, SYSTEM_SENDER};
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::coordinator::Coordinator;
|
||||
use anyhow::{Result, bail};
|
||||
use hive_sh4re::{ApprovalKind, ApprovalStatus, HelperEvent, MANAGER_AGENT, Message, SYSTEM_SENDER};
|
||||
|
||||
use crate::coordinator::{Coordinator, TransientKind};
|
||||
use crate::lifecycle::{self, MANAGER_NAME};
|
||||
|
||||
/// Approve a pending request: read the agent.nix at the approval's commit from
|
||||
/// the proposed repo, copy into the applied repo, commit there, and rebuild
|
||||
/// the agent container. On failure marks the approval failed (with the error
|
||||
/// note) and returns the error. Either way, an `ApprovalResolved` helper event
|
||||
/// is pushed into the manager's inbox.
|
||||
pub async fn approve(coord: &Coordinator, id: i64) -> Result<()> {
|
||||
/// Approve a pending request and run the underlying action. Dispatches on the
|
||||
/// approval kind:
|
||||
/// - `ApplyCommit`: read agent.nix at the approval's commit from the proposed
|
||||
/// repo, copy into the applied repo, commit there, rebuild the container.
|
||||
/// Synchronous — returns once the rebuild completes.
|
||||
/// - `Spawn`: create + start a brand-new sub-agent container. Runs in a
|
||||
/// background task so the operator's approve click returns immediately;
|
||||
/// the dashboard surfaces a transient `Spawning` state until the container
|
||||
/// is up. On failure, the approval is marked failed.
|
||||
///
|
||||
/// In all cases an `ApprovalResolved` helper event lands in the manager's
|
||||
/// inbox when the work resolves.
|
||||
pub async fn approve(coord: Arc<Coordinator>, id: i64) -> Result<()> {
|
||||
let approval = coord.approvals.mark_approved(id)?;
|
||||
tracing::info!(%approval.id, %approval.agent, %approval.commit_ref, "approval: applying + rebuilding");
|
||||
tracing::info!(
|
||||
%approval.id,
|
||||
%approval.agent,
|
||||
kind = ?approval.kind,
|
||||
%approval.commit_ref,
|
||||
"approval: running action",
|
||||
);
|
||||
|
||||
let agent_dir = coord.register_agent(&approval.agent)?;
|
||||
let proposed_dir = Coordinator::agent_proposed_dir(&approval.agent);
|
||||
let applied_dir = Coordinator::agent_applied_dir(&approval.agent);
|
||||
let claude_dir = Coordinator::agent_claude_dir(&approval.agent);
|
||||
let result: Result<()> = async {
|
||||
lifecycle::apply_commit(&applied_dir, &proposed_dir, &approval.commit_ref).await?;
|
||||
lifecycle::rebuild(
|
||||
&approval.agent,
|
||||
&coord.hyperhive_flake,
|
||||
&agent_dir,
|
||||
&applied_dir,
|
||||
&claude_dir,
|
||||
)
|
||||
.await
|
||||
|
||||
match approval.kind {
|
||||
ApprovalKind::ApplyCommit => {
|
||||
let result = async {
|
||||
lifecycle::apply_commit(&applied_dir, &proposed_dir, &approval.commit_ref).await?;
|
||||
lifecycle::rebuild(
|
||||
&approval.agent,
|
||||
&coord.hyperhive_flake,
|
||||
&agent_dir,
|
||||
&applied_dir,
|
||||
&claude_dir,
|
||||
)
|
||||
.await
|
||||
}
|
||||
.await;
|
||||
finish_approval(&coord, &approval, result)
|
||||
}
|
||||
ApprovalKind::Spawn => {
|
||||
// Run the spawn in the background so the approve POST returns
|
||||
// immediately. The dashboard reads `transient` to render a spinner.
|
||||
coord.set_transient(&approval.agent, TransientKind::Spawning);
|
||||
let coord_bg = coord.clone();
|
||||
let approval_bg = approval.clone();
|
||||
tokio::spawn(async move {
|
||||
let agent_bg = approval_bg.agent.clone();
|
||||
let result = lifecycle::spawn(
|
||||
&approval_bg.agent,
|
||||
&coord_bg.hyperhive_flake,
|
||||
&agent_dir,
|
||||
&proposed_dir,
|
||||
&applied_dir,
|
||||
&claude_dir,
|
||||
)
|
||||
.await;
|
||||
coord_bg.clear_transient(&agent_bg);
|
||||
if let Err(e) = finish_approval(&coord_bg, &approval_bg, result) {
|
||||
tracing::warn!(agent = %agent_bg, error = ?e, "spawn approval failed");
|
||||
}
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
.await;
|
||||
}
|
||||
|
||||
fn finish_approval(coord: &Coordinator, approval: &hive_sh4re::Approval, result: Result<()>) -> Result<()> {
|
||||
match result {
|
||||
Ok(()) => {
|
||||
notify_manager(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue