diff --git a/features/session_list_error.feature b/features/session_list_error.feature index ff7451260..921731af2 100644 --- a/features/session_list_error.feature +++ b/features/session_list_error.feature @@ -71,6 +71,7 @@ Feature: Session list command handles missing database gracefully Then the session-list-error command should exit successfully And the session-list-error output should be valid JSON containing "sessions" And the session-list-error output should not contain "AttributeError" + And the session-list-error JSON summary should represent an empty result @tdd_issue @tdd_issue_554 # @tdd_issue @tdd_issue_4270 @tdd_expected_fail @skip diff --git a/features/steps/session_list_error_steps.py b/features/steps/session_list_error_steps.py index 402f805ed..ef7f8b0dd 100644 --- a/features/steps/session_list_error_steps.py +++ b/features/steps/session_list_error_steps.py @@ -251,6 +251,50 @@ def step_output_json_key(context: Context, key: str) -> None: ) +@then("the session-list-error JSON summary should represent an empty result") +def step_json_empty_summary(context: Context) -> None: + result = context.sle_result + assert result is not None, "No command was invoked" + try: + parsed = json.loads(result.output) + except json.JSONDecodeError as exc: + raise AssertionError(f"Output is not valid JSON:\n{result.output}") from exc + + data = _unwrap_envelope(parsed) + assert isinstance(data, dict), f"Expected JSON object, got {type(data)}: {data}" + + sessions = data.get("sessions") + assert isinstance(sessions, list), ( + f"Expected 'sessions' to be a list, got {type(sessions)}: {sessions}" + ) + assert not sessions, f"Expected no sessions but found: {sessions}" + + assert "total" not in data, ( + "Top-level 'total' key should not be present; expected value nested in 'summary'." + ) + + summary = data.get("summary") + assert isinstance(summary, dict), ( + f"Expected 'summary' to be a dict, got {type(summary)}: {summary}" + ) + + expected_keys = {"total", "most_recent", "oldest", "total_messages", "storage"} + missing_keys = expected_keys - set(summary) + assert not missing_keys, f"Missing summary keys: {sorted(missing_keys)}" + + assert summary["total"] == 0, f"Expected summary total 0, got {summary['total']}" + assert summary["total_messages"] == 0, ( + f"Expected total_messages 0, got {summary['total_messages']}" + ) + assert summary["most_recent"] is None, ( + f"Expected most_recent None, got {summary['most_recent']}" + ) + assert summary["oldest"] is None, f"Expected oldest None, got {summary['oldest']}" + assert summary["storage"] == "0 KB", ( + f"Expected storage '0 KB', got {summary['storage']}" + ) + + @then('the session-list-error output should be valid YAML containing "{key}"') def step_output_yaml_key(context: Context, key: str) -> None: result = context.sle_result diff --git a/src/cleveragents/cli/commands/session.py b/src/cleveragents/cli/commands/session.py index 25229f840..888955f7f 100644 --- a/src/cleveragents/cli/commands/session.py +++ b/src/cleveragents/cli/commands/session.py @@ -292,7 +292,7 @@ def list_sessions( # For machine-readable formats, always emit a structured empty list # so that callers parsing JSON/YAML receive valid output. if fmt not in (OutputFormat.RICH.value, OutputFormat.COLOR.value): - typer.echo(format_output({"sessions": [], "total": 0}, fmt)) + typer.echo(format_output(_session_list_dict([]), fmt)) return console.print("[yellow]No sessions found.[/yellow]") console.print("Create one with 'agents session create'")