feat(kanban): add scheduled status for delayed follow-ups

Salvages #24533 by @roycepersonalassistant. Adds a first-class
'scheduled' Kanban status for time-delay follow-ups that aren't
waiting on human input.

- hermes kanban schedule <task_id> [reason] CLI command
- Dashboard/API transitions to/from Scheduled
- unblock_task() now releases both 'blocked' AND 'scheduled' tasks
  (re-checking parent dependencies before moving to ready/todo)
- i18n + docs updates

Resolved conflicts: kept HEAD's failure-counter reset on unblock
alongside the PR's scheduled state, kept HEAD's 'running' direct-set
rejection, combined both bulk-status branches. Dropped the dist/
bundle changes (months-stale; would need rebuild from source).
This commit is contained in:
roycepersonalassistant 2026-05-18 21:38:57 -07:00 committed by Teknium
parent b5c1fe78aa
commit e3823657d6
8 changed files with 149 additions and 14 deletions

View file

@ -321,6 +321,28 @@ def test_patch_block_then_unblock(client):
assert r.json()["task"]["status"] == "ready"
def test_patch_schedule_then_unblock(client):
t = client.post("/api/plugins/kanban/tasks", json={"title": "x"}).json()["task"]
r = client.patch(
f"/api/plugins/kanban/tasks/{t['id']}",
json={"status": "scheduled", "block_reason": "run tomorrow"},
)
assert r.status_code == 200
assert r.json()["task"]["status"] == "scheduled"
columns = client.get("/api/plugins/kanban/board").json()["columns"]
assert "scheduled" in [c["name"] for c in columns]
scheduled = next(c for c in columns if c["name"] == "scheduled")
assert any(x["id"] == t["id"] for x in scheduled["tasks"])
r = client.patch(
f"/api/plugins/kanban/tasks/{t['id']}",
json={"status": "ready"},
)
assert r.status_code == 200
assert r.json()["task"]["status"] == "ready"
def test_patch_drag_drop_move_todo_to_ready(client):
"""Direct status write: the drag-drop path for statuses without a
dedicated verb (e.g. manually promoting todo -> ready).