Skip to content
Closed
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
64 changes: 64 additions & 0 deletions hermes_cli/kanban.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,11 @@ def _run_state_kwargs(args: argparse.Namespace) -> Optional[dict[str, str]]:
return {"state_type": st, "state_name": sn}


def _infer_subscribe_from_env() -> Optional[dict[str, str]]:
"""Delegate to the canonical env-var resolution in ``kanban_db``."""
return kb._resolve_subscribe_from_env()


def _parse_workspace_flag(value: str) -> tuple[str, Optional[str]]:
"""Parse ``--workspace`` into ``(kind, path|None)``.

Expand Down Expand Up @@ -341,6 +346,14 @@ def build_parser(parent_subparsers: argparse._SubParsersAction) -> argparse.Argu
"two retries. Omit to use the dispatcher's "
"kanban.failure_limit config "
f"(default {kb.DEFAULT_FAILURE_LIMIT}).")
p_create.add_argument("--subscribe-platform", default=None,
help="Auto-subscribe task notifications for this platform")
p_create.add_argument("--subscribe-chat-id", default=None,
help="Chat ID for the notification subscription")
p_create.add_argument("--subscribe-thread-id", default=None,
help="Optional thread/topic ID for the notification subscription")
p_create.add_argument("--subscribe-user-id", default=None,
help="Optional user ID for the notification subscription")
p_create.add_argument("--initial-status",
choices=sorted(kb.VALID_INITIAL_STATUSES),
default="running",
Expand Down Expand Up @@ -550,6 +563,13 @@ def build_parser(parent_subparsers: argparse._SubParsersAction) -> argparse.Argu
p_unblock = sub.add_parser("unblock", help="Return one or more blocked/scheduled tasks to ready")
p_unblock.add_argument("task_ids", nargs="+")

p_rerun = sub.add_parser("rerun", help="Reset a completed/blocked task for another attempt")
p_rerun.add_argument("task_id")
p_rerun.add_argument("--reason", default=None,
help="Optional reason recorded on the rerun event")
p_rerun.add_argument("--reassign-to", dest="new_assignee", default=None,
help="Optional assignee profile to use for the rerun")

p_archive = sub.add_parser("archive", help="Archive one or more tasks")
p_archive.add_argument("task_ids", nargs="*",
help="Task ids to archive (default mode)")
Expand Down Expand Up @@ -899,6 +919,7 @@ def _restore_board_env() -> None:
"block": _cmd_block,
"schedule": _cmd_schedule,
"unblock": _cmd_unblock,
"rerun": _cmd_rerun,
"archive": _cmd_archive,
"tail": _cmd_tail,
"dispatch": _cmd_dispatch,
Expand Down Expand Up @@ -1286,6 +1307,28 @@ def _cmd_create(args: argparse.Namespace) -> int:
file=sys.stderr,
)
return 2
subscribe = None
sub_platform = (getattr(args, "subscribe_platform", None) or "").strip()
sub_chat_id = (getattr(args, "subscribe_chat_id", None) or "").strip()
sub_thread_id = (getattr(args, "subscribe_thread_id", None) or "").strip()
sub_user_id = (getattr(args, "subscribe_user_id", None) or "").strip()
if any((sub_platform, sub_chat_id, sub_thread_id, sub_user_id)):
if not sub_platform or not sub_chat_id:
print(
"kanban: --subscribe-platform and --subscribe-chat-id must be passed together",
file=sys.stderr,
)
return 2
subscribe = {
"platform": sub_platform,
"chat_id": sub_chat_id,
}
if sub_thread_id:
subscribe["thread_id"] = sub_thread_id
if sub_user_id:
subscribe["user_id"] = sub_user_id
if subscribe is None:
subscribe = _infer_subscribe_from_env()
with kb.connect() as conn:
task_id = kb.create_task(
conn,
Expand All @@ -1304,6 +1347,7 @@ def _cmd_create(args: argparse.Namespace) -> int:
max_runtime_seconds=max_runtime,
skills=getattr(args, "skills", None) or None,
max_retries=max_retries,
subscribe=subscribe,
initial_status=getattr(args, "initial_status", "running"),
)
task = kb.get_task(conn, task_id)
Expand Down Expand Up @@ -1955,6 +1999,26 @@ def _cmd_unblock(args: argparse.Namespace) -> int:
return 0 if not failed else 1


def _cmd_rerun(args: argparse.Namespace) -> int:
with kb.connect() as conn:
ok = kb.rerun_task(
conn,
args.task_id,
reason=getattr(args, "reason", None),
new_assignee=getattr(args, "new_assignee", None),
)
if not ok:
print(
f"cannot rerun {args.task_id} (not completed/blocked/archived?)",
file=sys.stderr,
)
return 1
task = kb.get_task(conn, args.task_id)
status = task.status if task else "?"
print(f"Rerun {args.task_id} ({status})")
return 0


def _cmd_archive(args: argparse.Namespace) -> int:
ids = list(args.task_ids or [])
purge_ids = list(getattr(args, "purge_ids", None) or [])
Expand Down
Loading
Loading