Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 26 additions & 1 deletion hermes_cli/kanban.py
Original file line number Diff line number Diff line change
Expand Up @@ -559,6 +559,16 @@ def build_parser(parent_subparsers: argparse._SubParsersAction) -> argparse.Argu
p_block.add_argument("reason", nargs="*", help="Reason (also appended as a comment)")
p_block.add_argument("--ids", nargs="+", default=None,
help="Additional task ids to block with the same reason (bulk mode)")
p_block.add_argument(
"--kind", default=None, choices=sorted(kb.VALID_BLOCK_KINDS),
help=(
"Typed block reason. 'dependency' waits in todo (auto-promoted "
"when parents finish, no human); 'needs_input'/'capability' go to "
"blocked for a human; 'transient' marks a maybe-flaky failure. "
"Repeated same-kind re-blocks after unblock route the task to "
"triage to break unblock loops. Omit for a generic block."
),
)

p_schedule = sub.add_parser("schedule", help="Park one or more tasks in Scheduled (waiting on time, not human input)")
p_schedule.add_argument("task_id")
Expand Down Expand Up @@ -1928,6 +1938,7 @@ def _cmd_edit(args: argparse.Namespace) -> int:

def _cmd_block(args: argparse.Namespace) -> int:
reason = " ".join(args.reason).strip() if args.reason else None
kind = getattr(args, "kind", None)
author = _profile_author()
ids = [args.task_id] + list(getattr(args, "ids", None) or [])
failed: list[str] = []
Expand All @@ -1939,12 +1950,26 @@ def _cmd_block(args: argparse.Namespace) -> int:
conn,
tid,
reason=reason,
kind=kind,
expected_run_id=_worker_run_id_for(tid),
):
failed.append(tid)
print(f"cannot block {tid}", file=sys.stderr)
else:
print(f"Blocked {tid}" + (f": {reason}" if reason else ""))
# Report where the task actually landed — dependency blocks go
# to todo, and a tripped unblock-loop breaker routes to triage.
landed = kb.get_task(conn, tid)
where = landed.status if landed else "blocked"
suffix = f": {reason}" if reason else ""
if where == "todo":
print(f"{tid} → todo (dependency wait){suffix}")
elif where == "triage":
print(
f"{tid} → triage (unblock loop detected — needs a "
f"human decision){suffix}"
)
else:
print(f"Blocked {tid}{suffix}")
return 0 if not failed else 1


Expand Down
Loading
Loading