From a5c2836b0796e44cc1ed738320faa1a5dba890a3 Mon Sep 17 00:00:00 2001 From: ACR27 <1626914+ACR27@users.noreply.github.com> Date: Mon, 18 May 2026 20:25:23 -0700 Subject: [PATCH] feat(kanban): allow trimmed task comments SS-1647 live SHIP validation: real code + tests for kanban comment --max-len. --- hermes_cli/kanban.py | 9 +++++++++ tests/hermes_cli/test_kanban_cli.py | 14 ++++++++++++-- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/hermes_cli/kanban.py b/hermes_cli/kanban.py index 38202e461ed..a85636cf8b9 100644 --- a/hermes_cli/kanban.py +++ b/hermes_cli/kanban.py @@ -403,6 +403,8 @@ def build_parser(parent_subparsers: argparse._SubParsersAction) -> argparse.Argu p_comment.add_argument("text", nargs="+", help="Comment body") p_comment.add_argument("--author", default=None, help="Author name (default: $HERMES_PROFILE or 'user')") + p_comment.add_argument("--max-len", type=int, default=None, + help="Trim the stored comment body to this many characters") p_complete = sub.add_parser("complete", help="Mark one or more tasks done") p_complete.add_argument("task_ids", nargs="+", @@ -1616,6 +1618,13 @@ def _cmd_claim(args: argparse.Namespace) -> int: def _cmd_comment(args: argparse.Namespace) -> int: body = " ".join(args.text).strip() + if args.max_len is not None: + if args.max_len < 1: + print("kanban: --max-len must be positive", file=sys.stderr) + return 2 + if len(body) > args.max_len: + suffix = f"\n\n[trimmed to {args.max_len} chars by --max-len]" + body = body[: max(0, args.max_len - len(suffix))].rstrip() + suffix author = args.author or _profile_author() with kb.connect() as conn: kb.add_comment(conn, args.task_id, author, body) diff --git a/tests/hermes_cli/test_kanban_cli.py b/tests/hermes_cli/test_kanban_cli.py index 9187acd2774..ae0fdb768cd 100644 --- a/tests/hermes_cli/test_kanban_cli.py +++ b/tests/hermes_cli/test_kanban_cli.py @@ -96,9 +96,19 @@ def test_run_slash_show_includes_comments(kanban_home): out = kc.run_slash("create 'x'") import re tid = re.search(r"(t_[a-f0-9]+)", out).group(1) - kc.run_slash(f"comment {tid} 'source is paywalled'") + kc.run_slash(f"comment {tid} 'remember to include performance section'") show = kc.run_slash(f"show {tid}") - assert "source is paywalled" in show + assert "performance section" in show + + +def test_run_slash_comment_max_len_trims_long_body(kanban_home): + out = kc.run_slash("create 'x'") + import re + tid = re.search(r"(t_[a-f0-9]+)", out).group(1) + kc.run_slash(f"comment {tid} '{'x' * 30}' --max-len 20") + show = kc.run_slash(f"show {tid}") + assert "trimmed to 20 chars by --max-len" in show + assert "x" * 30 not in show def test_run_slash_block_unblock_cycle(kanban_home):