Compare commits

...

2 Commits

Author SHA1 Message Date
controller-ci-rerun 9b2feb14ec chore: re-trigger CI [controller]
CI / load-versions (pull_request) Successful in 7s
CI / push-validation (pull_request) Successful in 8s
CI / helm (pull_request) Successful in 17s
CI / lint (pull_request) Successful in 18s
CI / quality (pull_request) Successful in 18s
CI / build (pull_request) Successful in 35s
CI / security (pull_request) Successful in 1m12s
CI / typecheck (pull_request) Successful in 3m47s
CI / unit_tests (pull_request) Failing after 4m25s
CI / coverage (pull_request) Has been skipped
CI / docker (pull_request) Has been skipped
CI / integration_tests (pull_request) Failing after 8m19s
CI / status-check (pull_request) Failing after 3s
2026-06-19 03:01:49 -04:00
HAL9000 0f5c54cc79 fix(cli): add Capability panel, Config path, and Created timestamp to validation add output (#1422)
The agents validation add command's rich output now includes:
- Config: field showing path to YAML config file
- Created: field with timestamp (%Y-%m-%d %H:%M format)
- Capability panel (Read-Only enforced, Checkpointable enforced, Timeout)
- OK Validation registered footer message

Also fixes Rich Console writing to stderr instead of stdout, breaking BDD
test output capture. Console now explicitly uses sys.stdout.

Co-authored-by: HAL 9000 <hal9000@cleverthis.com>

ISSUES CLOSED: #1422
2026-06-19 03:00:56 -04:00
3 changed files with 252 additions and 4 deletions
@@ -0,0 +1,134 @@
"""Step definitions for validation add output format feature (issue #1422).
Tests that ``agents validation add`` rich output includes:
- Config: field (path to config file)
- Created: field (timestamp)
- Capability panel (Read-Only, Checkpointable, Timeout)
- OK Validation registered footer message
"""
from __future__ import annotations
import os
import tempfile
from typing import Any
from unittest.mock import MagicMock, patch
from behave import given, then, when
from behave.runner import Context
from typer.testing import CliRunner
from cleveragents.cli.commands.validation import app as validation_app
_VALIDATION_YAML = """\
name: local/run-tests
description: Run unit tests with coverage
source: custom
mode: required
code: |
def run(inputs):
return {"passed": True}
"""
_runner = CliRunner()
def _make_mock_validation(
name: str = "local/run-tests",
) -> dict[str, Any]:
"""Create a mock validation dict as returned by the service layer."""
return {
"name": name,
"description": "Run unit tests with coverage",
"source": "custom",
"tool_type": "validation",
"mode": "required",
"timeout": 300,
}
def _patch_val_svc(context: Context) -> Any:
return patch(
"cleveragents.cli.commands.validation._get_tool_registry_service",
return_value=context.val_output_mock_service,
)
# ---------------------------------------------------------------------------
# Background
# ---------------------------------------------------------------------------
@given("a validation add output format test runner with mocks")
def step_val_output_format_runner(context: Context) -> None:
context.val_output_runner = _runner
context.val_output_result = None
context.val_output_yaml_path = None
context.val_output_mock_service = MagicMock()
context.val_output_mock_service.register_tool.return_value = _make_mock_validation()
context.val_output_mock_service.update_tool.return_value = _make_mock_validation()
context.val_output_mock_service.get_tool.return_value = None
# ---------------------------------------------------------------------------
# Given steps
# ---------------------------------------------------------------------------
@given("a validation add output format YAML config at a known path")
def step_val_output_yaml_config(context: Context) -> None:
fd, path = tempfile.mkstemp(suffix=".yaml")
with os.fdopen(fd, "w") as fh:
fh.write(_VALIDATION_YAML)
context.val_output_yaml_path = path
@given("the validation add output format validation already exists")
def step_val_output_already_exists(context: Context) -> None:
context.val_output_mock_service.get_tool.return_value = _make_mock_validation()
context.val_output_mock_service.update_tool.return_value = _make_mock_validation()
# ---------------------------------------------------------------------------
# When steps
# ---------------------------------------------------------------------------
@when("I invoke validation add output format with rich output")
def step_val_output_invoke_rich(context: Context) -> None:
with _patch_val_svc(context):
context.val_output_result = _runner.invoke(
validation_app,
["add", "--config", context.val_output_yaml_path],
)
@when("I invoke validation add output format with --update flag")
def step_val_output_invoke_update(context: Context) -> None:
with _patch_val_svc(context):
context.val_output_result = _runner.invoke(
validation_app,
["add", "--config", context.val_output_yaml_path, "--update"],
)
# ---------------------------------------------------------------------------
# Then assertions
# ---------------------------------------------------------------------------
@then("the validation add output format result should succeed")
def step_val_output_result_success(context: Context) -> None:
assert context.val_output_result is not None
assert context.val_output_result.exit_code == 0, (
f"Expected exit 0, got {context.val_output_result.exit_code}. "
f"Output: {context.val_output_result.output}"
)
@then('the validation add output format output should contain "{text}"')
def step_val_output_contains(context: Context, text: str) -> None:
assert context.val_output_result is not None
assert text in context.val_output_result.output, (
f"Expected '{text}' in output. Got: {context.val_output_result.output}"
)
@@ -0,0 +1,66 @@
@tdd_issue @tdd_issue_1422
Feature: Bug #1422 — validation add output missing Capability panel, Config path, and Created timestamp
As a user of the CleverAgents CLI
I want the ``agents validation add`` command to display the Config path,
Created timestamp, Capability panel, and footer message in its rich output
So that the output matches the specification at docs/specification.md lines 9319-9360
Background:
Given a validation add output format test runner with mocks
Scenario: validation add rich output includes Config path
Given a validation add output format YAML config at a known path
When I invoke validation add output format with rich output
Then the validation add output format result should succeed
And the validation add output format output should contain "Config:"
Scenario: validation add rich output includes Created timestamp
Given a validation add output format YAML config at a known path
When I invoke validation add output format with rich output
Then the validation add output format result should succeed
And the validation add output format output should contain "Created:"
Scenario: validation add rich output includes Capability panel
Given a validation add output format YAML config at a known path
When I invoke validation add output format with rich output
Then the validation add output format result should succeed
And the validation add output format output should contain "Capability"
Scenario: validation add rich output includes Read-Only enforced field
Given a validation add output format YAML config at a known path
When I invoke validation add output format with rich output
Then the validation add output format result should succeed
And the validation add output format output should contain "Read-Only:"
Scenario: validation add rich output includes Checkpointable enforced field
Given a validation add output format YAML config at a known path
When I invoke validation add output format with rich output
Then the validation add output format result should succeed
And the validation add output format output should contain "Checkpointable:"
Scenario: validation add rich output includes Timeout field
Given a validation add output format YAML config at a known path
When I invoke validation add output format with rich output
Then the validation add output format result should succeed
And the validation add output format output should contain "Timeout:"
Scenario: validation add rich output includes OK footer message
Given a validation add output format YAML config at a known path
When I invoke validation add output format with rich output
Then the validation add output format result should succeed
And the validation add output format output should contain "OK Validation registered"
Scenario: validation add rich output includes Validation Registered panel title
Given a validation add output format YAML config at a known path
When I invoke validation add output format with rich output
Then the validation add output format result should succeed
And the validation add output format output should contain "Validation Registered"
Scenario: validation add with --update flag also shows Config and Capability panel
Given a validation add output format YAML config at a known path
And the validation add output format validation already exists
When I invoke validation add output format with --update flag
Then the validation add output format result should succeed
And the validation add output format output should contain "Config:"
And the validation add output format output should contain "Capability"
And the validation add output format output should contain "OK Validation registered"
+52 -4
View File
@@ -48,6 +48,8 @@ Based on implementation_plan.md -- Task C1.tool.cli.
from __future__ import annotations
import sys
from datetime import datetime
from pathlib import Path
from typing import Annotated, Any
@@ -68,7 +70,9 @@ from cleveragents.domain.models.core.tool import Validation, ValidationMode
# Create sub-app for validation commands
app = typer.Typer(help="Manage validations (pass/fail tools) and resource attachments.")
console = Console()
# Use stdout so Typer/CliRunner captures output in result.output (BDD tests
# assert on result.output; Rich defaults to stderr which would break those).
console = Console(file=sys.stdout)
# Reusable --format option description
_FORMAT_HELP = "Output format: json, yaml, plain, table, or rich (default: rich)"
@@ -136,8 +140,18 @@ def _print_validation(
tool: Any,
title: str = "Validation",
fmt: str = OutputFormat.RICH.value,
config_path: str | None = None,
created_at: datetime | None = None,
) -> None:
"""Print validation details in the requested format."""
"""Print validation details in the requested format.
Args:
tool: The validation tool object to print
title: Panel title (e.g., "Validation Registered")
fmt: Output format (rich, json, yaml, etc.)
config_path: Path to the config file (optional)
created_at: Timestamp of creation (optional)
"""
data = _validation_spec_dict(tool)
if fmt != OutputFormat.RICH.value:
console.print(format_output(data, fmt))
@@ -155,6 +169,15 @@ def _print_validation(
f"[bold]Mode:[/bold] {mode}"
)
# Add Config field if provided
if config_path:
details += f"\n[bold]Config:[/bold] {config_path}"
# Add Created field if provided
if created_at:
created_str = created_at.strftime("%Y-%m-%d %H:%M")
details += f"\n[bold]Created:[/bold] {created_str}"
wraps = data.get("wraps")
if wraps:
details += f"\n[bold]Wraps:[/bold] {wraps}"
@@ -162,8 +185,21 @@ def _print_validation(
if transform:
details += f"\n[bold]Transform:[/bold] {transform}"
# Print main panel
console.print(Panel(details, title=title, expand=False))
# Add Capability panel
timeout = getattr(tool, "timeout", 300)
capability_details = (
f"[bold]Read-Only:[/bold] true (enforced)\n"
f"[bold]Checkpointable:[/bold] false (enforced)\n"
f"[bold]Timeout:[/bold] {timeout}s"
)
console.print(Panel(capability_details, title="Capability", expand=False))
# Add footer message
console.print("[green]✓ OK Validation registered[/green]")
@app.command("add")
def add(
@@ -239,11 +275,23 @@ def add(
existing = service.get_tool(validation.name)
if existing is not None:
registered = service.update_tool(validation)
_print_validation(registered, title="Validation Updated", fmt=fmt)
_print_validation(
registered,
title="Validation Updated",
fmt=fmt,
config_path=str(config),
created_at=datetime.now(),
)
return
registered = service.register_tool(validation)
_print_validation(registered, title="Validation Registered", fmt=fmt)
_print_validation(
registered,
title="Validation Registered",
fmt=fmt,
config_path=str(config),
created_at=datetime.now(),
)
except FileNotFoundError as exc:
console.print(f"[red]Config file error:[/red] {exc}")