diff --git a/db/connectors/ticket b/db/connectors/ticket index bf0b2ef46..c70852b01 100755 --- a/db/connectors/ticket +++ b/db/connectors/ticket @@ -141,28 +141,72 @@ def cmd_list(conn, args): out({"ok": True, "count": len(rows), "rows": rows}) -def cmd_show(conn, ticket_id): - rows = query(conn, """SELECT t.*, p.title as parent_title - FROM tickets t LEFT JOIN tickets p ON t.parent_id = p.id - WHERE t.id = ?""", (ticket_id,)) - if not rows: - out({"ok": False, "error": f"Ticket #{ticket_id} not found"}) - return - ticket = rows[0] - # Get children - children = query(conn, "SELECT id, title, status, priority FROM tickets WHERE parent_id = ? ORDER BY id", (ticket_id,)) - # Get dependencies (what blocks this) - blockers = query(conn, """SELECT t.id, t.title, t.status FROM ticket_deps d - JOIN tickets t ON d.blocker_id = t.id - WHERE d.blocked_id = ?""", (ticket_id,)) - # Get dependents (what this blocks) - blocks = query(conn, """SELECT t.id, t.title, t.status FROM ticket_deps d - JOIN tickets t ON d.blocked_id = t.id - WHERE d.blocker_id = ?""", (ticket_id,)) - ticket["children"] = children - ticket["blocked_by"] = blockers - ticket["blocks"] = blocks - out({"ok": True, "ticket": ticket}) +def cmd_show(conn, ids, brief=False): + tickets = [] + for ticket_id in ids: + rows = query(conn, """SELECT t.*, p.title as parent_title + FROM tickets t LEFT JOIN tickets p ON t.parent_id = p.id + WHERE t.id = ?""", (ticket_id,)) + if not rows: + tickets.append({"id": ticket_id, "error": f"Ticket #{ticket_id} not found"}) + continue + ticket = rows[0] + # Get children + children = query(conn, "SELECT id, title, status, priority FROM tickets WHERE parent_id = ? ORDER BY id", (ticket_id,)) + # Get dependencies (what blocks this) + blockers = query(conn, """SELECT t.id, t.title, t.status FROM ticket_deps d + JOIN tickets t ON d.blocker_id = t.id + WHERE d.blocked_id = ?""", (ticket_id,)) + # Get dependents (what this blocks) + blocks = query(conn, """SELECT t.id, t.title, t.status FROM ticket_deps d + JOIN tickets t ON d.blocked_id = t.id + WHERE d.blocker_id = ?""", (ticket_id,)) + ticket["children"] = children + ticket["blocked_by"] = blockers + ticket["blocks"] = blocks + tickets.append(ticket) + if brief: + _print_brief(tickets) + elif len(tickets) == 1: + out({"ok": True, "ticket": tickets[0]}) + else: + out({"ok": True, "count": len(tickets), "tickets": tickets}) + + +def _print_brief(tickets): + for i, t in enumerate(tickets): + if "error" in t: + print(f"#{t['id']}: NOT FOUND") + continue + # Header line + print(f"#{t['id']}: {t['title']}") + # Metadata line + parts = [f"{t['type']}", f"P:{t['priority']}", f"S:{t['status']}"] + if t.get("assigned_to"): + parts.append(f"@{t['assigned_to']}") + if t.get("parent_id"): + parts.append(f"Epic:#{t['parent_id']} ({t.get('parent_title', '?')})") + if t.get("sprint_id"): + parts.append(f"Sprint:{t['sprint_id']}") + if t.get("decision_ref"): + parts.append(f"Ref:{t['decision_ref']}") + print(f" {' | '.join(parts)}") + # Description + desc = t.get("description") or "" + if desc: + # Truncate long descriptions + if len(desc) > 200: + desc = desc[:197] + "..." + print(f" {desc}") + # Dependencies + if t.get("blocked_by"): + blockers = ", ".join(f"#{b['id']} ({b['status']})" for b in t["blocked_by"]) + print(f" Blocked by: {blockers}") + if t.get("blocks"): + blocks = ", ".join(f"#{b['id']}" for b in t["blocks"]) + print(f" Blocks: {blocks}") + if i < len(tickets) - 1: + print() def cmd_done(conn, ids): @@ -286,7 +330,7 @@ HELP = """ticket — project ticket CLI Usage: ticket list [--status S] [--priority P] [--epic N] [--sprint N] [--assigned A] - ticket show Full ticket detail with deps and children + ticket show [--brief] [...] Full ticket detail (--brief for summary) ticket done [ ...] Mark tickets as done ticket status Change ticket status ticket assign Assign ticket to agent/branch @@ -320,10 +364,12 @@ def main(): if cmd == "list": cmd_list(conn, args) elif cmd == "show": - if not args: - out({"ok": False, "error": "Usage: ticket show "}) + brief = "--brief" in args + id_args = [a for a in args if a != "--brief"] + if not id_args: + out({"ok": False, "error": "Usage: ticket show [--brief] [ ...]"}) else: - cmd_show(conn, int(args[0])) + cmd_show(conn, [int(a) for a in id_args], brief=brief) elif cmd == "done": if not args: out({"ok": False, "error": "Usage: ticket done [ ...]"})