fix(cli): render spec-required Filters, Summary panels and Elapsed column in agents plan list rich output (#1522)
CI / build (push) Successful in 18s
CI / lint (push) Failing after 18s
CI / helm (push) Successful in 22s
CI / typecheck (push) Failing after 44s
CI / coverage (push) Has been skipped
CI / benchmark-regression (push) Has been skipped
CI / security (push) Failing after 49s
CI / unit_tests (push) Failing after 2m1s
CI / docker (push) Has been skipped
CI / quality (push) Successful in 3m54s
CI / e2e_tests (push) Has been cancelled
CI / integration_tests (push) Has been cancelled
CI / benchmark-publish (push) Has been cancelled
CI / status-check (push) Has been cancelled

Implements issue #1522. The agents plan list command now displays spec-compliant rich output with proper table columns, Filters panel, Summary panel, and success message.

Co-authored-by: Jeffrey Phillips Freeman <the@jeffreyfreeman.me>
Co-committed-by: Jeffrey Phillips Freeman <the@jeffreyfreeman.me>
This commit was merged in pull request #1565.
This commit is contained in:
2026-04-02 21:39:20 +00:00
committed by Forgejo
parent e069a2edde
commit 1a07a891ca
+76 -22
View File
@@ -25,6 +25,7 @@ import re
import time
import warnings
from contextlib import suppress
from datetime import datetime
from pathlib import Path
from typing import TYPE_CHECKING, Annotated, Any
@@ -2343,43 +2344,96 @@ def lifecycle_list_plans(
console.print(format_output(data, fmt))
return
# Display plans table
table = Table(title=f"V3 Lifecycle Plans ({len(plans)} total)")
# Display plans table with spec-required columns
table = Table(title="Plans")
table.add_column("ID", style="cyan")
table.add_column("Name", style="white")
table.add_column("Action", style="blue")
table.add_column("Phase", style="yellow")
table.add_column("State", style="magenta")
table.add_column("Profile", style="blue")
table.add_column("Invariants", style="dim")
table.add_column("Projects", style="green")
table.add_column("Created", style="dim")
table.add_column("Action", style="blue")
table.add_column("Project", style="green")
table.add_column("Elapsed", style="dim")
for plan in plans:
# Get first project or "(none)"
link_names = [link.project_name for link in plan.project_links]
projects = ", ".join(link_names[:2])
if len(link_names) > 2:
projects += f" +{len(link_names) - 2} more"
project_display = link_names[0] if link_names else "(none)"
profile = (
plan.automation_profile.profile_name if plan.automation_profile else ""
)
inv_count = str(len(plan.invariants)) if plan.invariants else ""
# Calculate elapsed time
created = plan.timestamps.created_at
now = datetime.now(created.tzinfo) if created.tzinfo else datetime.now()
elapsed = now - created
hours = int(elapsed.total_seconds() // 3600)
minutes = int((elapsed.total_seconds() % 3600) // 60)
seconds = int(elapsed.total_seconds() % 60)
elapsed_str = f"{hours:02d}:{minutes:02d}:{seconds:02d}"
table.add_row(
plan.identity.plan_id[:8] + "...",
str(plan.namespaced_name),
plan.action_name,
plan.identity.plan_id[:8],
plan.phase.value,
plan.state.value if plan.state else "",
profile,
inv_count,
projects or "(none)",
plan.timestamps.created_at.strftime("%Y-%m-%d %H:%M"),
plan.action_name,
project_display,
elapsed_str,
)
console.print(table)
# Display Filters panel (only if any filter is active)
active_filters = []
if phase_filter:
active_filters.append(f"[yellow]Phase:[/yellow] {phase_filter}")
else:
active_filters.append("[yellow]Phase:[/yellow] (any)")
if state_filter:
active_filters.append(f"[yellow]State:[/yellow] {state_filter.value}")
else:
active_filters.append("[yellow]State:[/yellow] (any)")
if project_id:
active_filters.append(f"[yellow]Project:[/yellow] {project_id}")
else:
active_filters.append("[yellow]Project:[/yellow] (any)")
if action_filter:
active_filters.append(f"[yellow]Action:[/yellow] {action_filter}")
else:
active_filters.append("[yellow]Action:[/yellow] (any)")
# Only show Filters panel if at least one filter is active
if phase_filter or state_filter or project_id or action_filter:
filters_text = "\n".join(active_filters)
filters_panel = Panel(filters_text, title="Filters", border_style="dim")
console.print(filters_panel)
# Display Summary panel
total_plans = len(plans)
processing_count = sum(
1 for p in plans if p.processing_state.value == "processing"
)
completed_count = sum(
1 for p in plans if p.processing_state.value == "complete"
)
errored_count = sum(
1 for p in plans if p.processing_state.value == "errored"
)
summary_text = (
f"[yellow bold]Total:[/yellow bold] {total_plans}\n"
f"[blue bold]Processing:[/blue bold] {processing_count}\n"
f"[green bold]Completed:[/green bold] {completed_count}\n"
f"[red bold]Errored:[/red bold] {errored_count}"
)
summary_panel = Panel(summary_text, title="Summary", border_style="dim")
console.print(summary_panel)
# Print success message
plan_word = "plan" if total_plans == 1 else "plans"
console.print(
f"[green bold]✓ OK[/green bold] {total_plans} {plan_word} listed"
)
except CleverAgentsError as e:
console.print(f"[red]Error:[/red] {e.message}")
raise typer.Abort() from e