From 955cf0111051514ef0bb84e2dc8726ba32b335ef Mon Sep 17 00:00:00 2001 From: Zhi Date: Sun, 22 Feb 2026 04:22:19 +0000 Subject: [PATCH] feat: CLI add search/transition/stats commands --- cli.py | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/cli.py b/cli.py index 4613ca8..b226160 100755 --- a/cli.py +++ b/cli.py @@ -110,6 +110,41 @@ def cmd_health(args): print(f"Status: {result['status']}") + +def cmd_search(args): + params = [f"q={args.query}"] + if args.project: + params.append(f"project_id={args.project}") + qs = "&".join(params) + issues = _request("GET", f"/search/issues?{qs}") + if not issues: + print(" No results found.") + return + for i in issues: + status_icon = {"open": "\U0001f7e2", "in_progress": "\U0001f535", "resolved": "\u2705", "closed": "\u26ab", "blocked": "\U0001f534"}.get(i["status"], "\u2753") + type_icon = {"resolution": "\u2696\ufe0f", "task": "\U0001f4cb", "story": "\U0001f4d6", "test": "\U0001f9ea"}.get(i["issue_type"], "\U0001f4cc") + print(f" {status_icon} {type_icon} #{i['id']} [{i['priority']}] {i['title']}") + + +def cmd_transition(args): + result = _request("POST", f"/issues/{args.issue_id}/transition?new_status={args.status}") + print(f"Issue #{result['id']} transitioned to: {result['status']}") + + +def cmd_stats(args): + params = f"?project_id={args.project}" if args.project else "" + stats = _request("GET", f"/dashboard/stats{params}") + print(f"Total: {stats['total']}") + print("By status:") + for s, c in stats["by_status"].items(): + if c > 0: + print(f" {s}: {c}") + print("By type:") + for t, c in stats["by_type"].items(): + if c > 0: + print(f" {t}: {c}") + + def main(): parser = argparse.ArgumentParser(description="HarborForge CLI") sub = parser.add_subparsers(dest="command") @@ -151,6 +186,21 @@ def main(): # health sub.add_parser("health", help="Health check") + + # search + p_search = sub.add_parser("search", help="Search issues") + p_search.add_argument("query") + p_search.add_argument("--project", "-p", type=int) + + # transition + p_trans = sub.add_parser("transition", help="Transition issue status") + p_trans.add_argument("issue_id", type=int) + p_trans.add_argument("status", choices=["open", "in_progress", "resolved", "closed", "blocked"]) + + # stats + p_stats = sub.add_parser("stats", help="Dashboard stats") + p_stats.add_argument("--project", "-p", type=int) + args = parser.parse_args() if not args.command: parser.print_help() @@ -164,6 +214,9 @@ def main(): "users": cmd_users, "version": cmd_version, "health": cmd_health, + "search": cmd_search, + "transition": cmd_transition, + "stats": cmd_stats, } cmds[args.command](args)