mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-06-04 07:31:58 +00:00
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:
parent
b5c1fe78aa
commit
e3823657d6
8 changed files with 149 additions and 14 deletions
|
|
@ -236,6 +236,34 @@ def test_claim_fails_on_non_ready(kanban_home):
|
|||
assert kb.claim_task(conn, t) is None
|
||||
|
||||
|
||||
def test_schedule_task_parks_time_delay_without_dispatching(kanban_home):
|
||||
with kb.connect() as conn:
|
||||
t = kb.create_task(conn, title="delayed recheck", assignee="ops")
|
||||
assert kb.schedule_task(conn, t, reason="run next week") is True
|
||||
task = kb.get_task(conn, t)
|
||||
assert task.status == "scheduled"
|
||||
assert kb.claim_task(conn, t) is None
|
||||
|
||||
events = kb.list_events(conn, t)
|
||||
assert any(e.kind == "scheduled" and e.payload == {"reason": "run next week"} for e in events)
|
||||
|
||||
|
||||
def test_unblock_scheduled_rechecks_parent_gate(kanban_home):
|
||||
with kb.connect() as conn:
|
||||
parent = kb.create_task(conn, title="parent")
|
||||
child = kb.create_task(conn, title="child", parents=[parent])
|
||||
assert kb.get_task(conn, child).status == "todo"
|
||||
assert kb.schedule_task(conn, child, reason="wait until tomorrow") is True
|
||||
|
||||
assert kb.unblock_task(conn, child) is True
|
||||
assert kb.get_task(conn, child).status == "todo"
|
||||
|
||||
kb.complete_task(conn, parent)
|
||||
assert kb.schedule_task(conn, child, reason="second timer") is True
|
||||
assert kb.unblock_task(conn, child) is True
|
||||
assert kb.get_task(conn, child).status == "ready"
|
||||
|
||||
|
||||
def test_stale_claim_reclaimed(kanban_home, monkeypatch):
|
||||
import signal
|
||||
import hermes_cli.kanban_db as _kb
|
||||
|
|
|
|||
|
|
@ -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).
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue