feat: add State Hub bulk status skill

This commit is contained in:
2026-06-07 20:11:07 +02:00
parent 8f17bc1f50
commit 55e36bdf2d
9 changed files with 496 additions and 5 deletions

View File

@@ -31,6 +31,7 @@ endpoint they wrap:
| `create_workstream(...)` | `POST /workstreams/` |
| `create_task(...)` | `POST /tasks/` |
| `update_task_status(...)` | `PATCH /tasks/{task_id}` |
| `bulk_update_task_statuses(...)` | `POST /tasks/bulk-status-sync` |
| `record_decision(...)` | `POST /decisions/` |
| `add_progress_event(...)` | `POST /progress/` |
@@ -93,6 +94,7 @@ entity while recording the missing progress event.
| `create_workstream(topic_id, title, ...)` | `slug?`; `owner?`; `description?`; `due_date?` | Creates workstream under a topic. Use `get_state_summary()` to find topic IDs. |
| `create_task(workstream_id, title, ...)` | `priority`: low/medium/high/critical; `assignee?`; `due_date?` | Creates task under a workstream. |
| `update_task_status(task_id, status, ...)` | `status`: wait/todo/progress/done/cancel; `blocking_reason?` describes wait conditions | Legacy aliases `blocked`, `in_progress`, `cancelled`, and `canceled` are accepted during migration. |
| `bulk_update_task_statuses(updates, author?, session_id?)` | `updates`: list of `{task_id, status, blocking_reason?}` | Updates many task statuses in one REST call and emits one `task_status_changed` progress event per task. Prefer this at session checkpoints instead of many single-task calls. |
| `update_workstream_status(workstream_id, status)` | `status`: proposed/ready/active/blocked/backlog/finished/archived | Thin shortcut — use `update_workstream` for full field control. |
| `update_workstream(workstream_id, ...)` | `title?`; `description?`; `owner?`; `due_date?`; `repo_goal_id?`; `status?` | Patch any subset of workstream fields. Pass empty string for `repo_goal_id` to clear the link. |

View File

@@ -633,6 +633,34 @@ def update_task_status(
return _json_result(task)
@mcp.tool()
def bulk_update_task_statuses(
updates: list[dict[str, Any]],
author: str | None = "custodian",
session_id: str | None = None,
) -> str:
"""Update many task statuses in one call and emit one progress_event per task.
Args:
updates: list of {task_id, status, blocking_reason?}; status values are
wait | todo | progress | done | cancel
author: optional progress event author (defaults to custodian)
session_id: optional agent session identifier for progress events
"""
result = _post("/tasks/bulk-status-sync", {
"updates": updates,
"author": author,
"session_id": session_id,
})
if error := _response_error(
"bulk_update_task_statuses",
result,
("updated", "progress_event_ids"),
):
return _json_result(error)
return _json_result(result)
@mcp.tool()
def flag_for_human(task_id: str, note: str) -> str:
"""Flag a task as requiring human intervention.