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
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:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user