scheduled prompts: edit existing schedule (closes #474)

This commit is contained in:
damocles 2026-05-26 15:04:05 +02:00
commit 9fee1a1e56
6 changed files with 428 additions and 0 deletions

View file

@ -350,6 +350,21 @@ async fn dispatch(req: &ManagerRequest, coord: &Arc<Coordinator>) -> ManagerResp
ManagerRequest::CancelSchedule { id, targets } => {
handle_cancel_schedule(coord, hive_sh4re::MANAGER_AGENT, *id, targets.as_deref())
}
ManagerRequest::EditSchedule {
id,
body,
description,
interval_seconds,
next_fire_at_unix,
} => handle_edit_schedule(
coord,
hive_sh4re::MANAGER_AGENT,
*id,
body.clone(),
description.clone(),
*interval_seconds,
*next_fire_at_unix,
),
ManagerRequest::ListSchedules => match coord.scheduled_prompts.list() {
Ok(schedules) => ManagerResponse::Schedules {
schedules: schedules.into_iter().map(schedule_to_wire).collect(),
@ -863,6 +878,59 @@ async fn handle_fire_schedule_now(
}
}
/// Authorize + dispatch a `EditSchedule` patch (#474). Same
/// ownership rules as `CancelSchedule` — the manager can edit
/// schedules it owns + any owned by an agent in its subtree.
/// Forwards the partial payload to
/// `ScheduledPrompts::update` which enforces the cancelled-row
/// + zero-interval validation. Returns `Ok` on a clean update;
/// `Err` with the underlying message on any auth / validation
/// failure so the dashboard can surface it verbatim.
#[allow(clippy::too_many_arguments)]
fn handle_edit_schedule(
coord: &Arc<Coordinator>,
requester: &str,
schedule_id: i64,
body: Option<String>,
description: Option<Option<String>>,
interval_seconds: Option<Option<u64>>,
next_fire_at_unix: Option<i64>,
) -> ManagerResponse {
let schedule = match coord.scheduled_prompts.get(schedule_id) {
Ok(Some(s)) => s,
Ok(None) => {
return ManagerResponse::Err {
message: format!("schedule {schedule_id} not found"),
}
}
Err(e) => {
return ManagerResponse::Err {
message: format!("read schedule {schedule_id}: {e:#}"),
}
}
};
if !cancel_authorized(requester, &schedule.owner) {
return ManagerResponse::Err {
message: format!(
"not authorized: {requester} cannot edit schedule owned by {owner}",
owner = schedule.owner
),
};
}
let patch = crate::scheduled_prompts::UpdateSchedule {
body,
description,
interval_seconds,
next_fire_at_unix,
};
match coord.scheduled_prompts.update(schedule_id, patch) {
Ok(()) => ManagerResponse::Ok,
Err(e) => ManagerResponse::Err {
message: format!("edit schedule {schedule_id}: {e:#}"),
},
}
}
/// Permission check for `CancelSchedule` on the manager surface.
/// `requester` (always `hm1nd` here) can cancel its own schedules.
/// Sub-agent ownership is delegated to topology — see