From c8132cd14649df5fb88fd4ae186154f788e7ceb8 Mon Sep 17 00:00:00 2001 From: leeyuhoon Date: Wed, 22 Jul 2026 19:26:18 +0900 Subject: [PATCH] kanban: add explicit `delete` verb for archived tasks Adds `hermes kanban delete ` as a first-class subcommand that permanently deletes already-archived tasks via delete_archived_task, with CLI test coverage. Co-Authored-By: Claude Fable 5 --- hermes_cli/kanban.py | 24 +++++++++++++++++++ .../test_kanban_core_functionality.py | 18 ++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/hermes_cli/kanban.py b/hermes_cli/kanban.py index 0937fc40f2e76..c146322d62211 100644 --- a/hermes_cli/kanban.py +++ b/hermes_cli/kanban.py @@ -649,6 +649,16 @@ def build_parser(parent_subparsers: argparse._SubParsersAction) -> argparse.Argu help="Permanently delete already-archived task ids from the board", ) + p_delete = sub.add_parser( + "delete", + help="Permanently delete already-archived tasks", + ) + p_delete.add_argument( + "task_ids", + nargs="+", + help="Already-archived task ids to permanently delete", + ) + # --- tail --- p_tail = sub.add_parser("tail", help="Follow a task's event stream") p_tail.add_argument("task_id") @@ -1007,6 +1017,7 @@ def kanban_command(args: argparse.Namespace) -> int: "unblock": _cmd_unblock, "promote": _cmd_promote, "archive": _cmd_archive, + "delete": _cmd_delete, "tail": _cmd_tail, "dispatch": _cmd_dispatch, "daemon": _cmd_daemon, @@ -2267,6 +2278,19 @@ def _cmd_archive(args: argparse.Namespace) -> int: return 0 if not failed else 1 +def _cmd_delete(args: argparse.Namespace) -> int: + """Permanently delete archived tasks via the explicit CLI verb.""" + failed: list[str] = [] + with kb.connect_closing() as conn: + for tid in args.task_ids: + if not kb.delete_archived_task(conn, tid): + failed.append(tid) + print(f"cannot delete {tid} (must already be archived)", file=sys.stderr) + else: + print(f"Deleted {tid}") + return 0 if not failed else 1 + + def _cmd_tail(args: argparse.Namespace) -> int: last_id = 0 print(f"Tailing events for {args.task_id}. Ctrl-C to stop.") diff --git a/tests/hermes_cli/test_kanban_core_functionality.py b/tests/hermes_cli/test_kanban_core_functionality.py index 0e898999c1d24..8bf41c1878803 100644 --- a/tests/hermes_cli/test_kanban_core_functionality.py +++ b/tests/hermes_cli/test_kanban_core_functionality.py @@ -788,6 +788,24 @@ def test_cli_archive_rm_deletes_archived_tasks(kanban_home): conn.close() +def test_cli_delete_removes_archived_task(kanban_home): + conn = kb.connect() + try: + tid = kb.create_task(conn, title="gone") + assert kb.archive_task(conn, tid) + finally: + conn.close() + + out = run_slash(f"delete {tid}") + + assert f"Deleted {tid}" in out + conn = kb.connect() + try: + assert kb.get_task(conn, tid) is None + finally: + conn.close() + + def test_cli_archive_rm_rejects_live_tasks(kanban_home): conn = kb.connect() try: