ff25bb5db197e1b8a048154cc9d34dc098ebd434
lrnassar
  Mon Mar 16 09:19:20 2026 -0700
Feedback from AI CR.

diff --git src/utils/redmineCli src/utils/redmineCli
index a1e25d90336..986f4d5ff5a 100755
--- src/utils/redmineCli
+++ src/utils/redmineCli
@@ -208,31 +208,31 @@
                 lines.append(f"  - Assignee changed: {old} -> {new}")
             elif name == "done_ratio":
                 lines.append(f"  - Progress: {old}% -> {new}%")
             else:
                 lines.append(f"  - {name}: {old} -> {new}")
         elif prop == "attachment":
             lines.append(f"  - Attached: {new}")
     return "\n".join(lines)
 
 
 # ---------------------------------------------------------------------------
 # Subcommand: show
 # ---------------------------------------------------------------------------
 
 def cmd_show(args):
-    """Display a single ticket in Markdown (equivalent to redmineDump)."""
+    """Display a single ticket in Markdown."""
     data = api_get(args.base_url,
                    f"/issues/{args.ticket_id}.json?include=journals,attachments",
                    args.api_key)
     issue = data["issue"]
 
     attachments = {a["id"]: a for a in issue.get("attachments", [])}
     attach_by_name = {a["filename"]: a for a in issue.get("attachments", [])}
 
     img_dir = None
     if args.images:
         img_dir = tempfile.mkdtemp(prefix=f"redmine_{args.ticket_id}_")
         print(f"<!-- Images downloaded to: {img_dir} -->", file=sys.stderr)
 
     def resolve_images(text):
         if not text:
@@ -322,84 +322,81 @@
     if img_dir:
         for a in issue["attachments"]:
             if a.get("content_type", "").startswith("image/"):
                 local = os.path.join(img_dir, a["filename"])
                 if not os.path.exists(local):
                     download_file(a["content_url"], local, args.api_key)
                     print(f"  Downloaded: {local}", file=sys.stderr)
 
     print("\n".join(out))
 
 
 def download_file(url, dest_path, api_key):
     """Download a file with API key auth."""
     req = urllib.request.Request(url)
     req.add_header("X-Redmine-API-Key", api_key)
-    with urllib.request.urlopen(req) as resp:
+    with urllib.request.urlopen(req, timeout=30) as resp:
         with open(dest_path, "wb") as f:
             f.write(resp.read())
 
 
 # ---------------------------------------------------------------------------
 # Subcommand: list
 # ---------------------------------------------------------------------------
 
 def cmd_list(args):
     """List/search tickets with filters."""
     params = {
         "project_id": args.project,
         "limit": str(args.limit),
         "offset": str(args.offset),
         "sort": args.sort,
     }
 
     if args.status:
         params["status_id"] = args.status
 
     if args.assigned_to:
         if args.assigned_to.lower() == "me":
             params["assigned_to_id"] = "me"
         else:
             params["assigned_to_id"] = str(resolve_user(args.assigned_to))
 
     if args.tracker:
-        if args.tracker.isdigit():
-            params["tracker_id"] = args.tracker
-        else:
         params["tracker_id"] = args.tracker
 
     if args.search:
         params["subject"] = f"~{args.search}"
 
     query = urllib.parse.urlencode(params)
     data = api_get(args.base_url, f"/issues.json?{query}", args.api_key)
 
     issues = data.get("issues", [])
     total = data.get("total_count", 0)
 
     if not issues:
         print("No issues found.")
         return
 
     out = []
     out.append("| # | Status | Assignee | Subject |")
     out.append("|---|--------|----------|---------|")
     for iss in issues:
         tid = iss["id"]
         status = iss["status"]["name"]
         assignee = iss.get("assigned_to", {}).get("name", "—")
-        subject = iss["subject"][:60]
+        subject = iss["subject"][:60].replace("|", "\\|")
         out.append(f"| {tid} | {status} | {assignee} | {subject} |")
     out.append("")
     start = args.offset + 1
     end = args.offset + len(issues)
     out.append(f"{total} issues total (showing {start}-{end})")
 
     print("\n".join(out))
 
 
 # ---------------------------------------------------------------------------
 # Subcommand: create
 # ---------------------------------------------------------------------------
 
 def cmd_create(args):
     """Create a new Redmine ticket."""