Files
cleveragents-core/features/project_cli.feature
HAL9000 207d65e87e fix(cli): add Invariants and Validations panels to project show rich output
The `agents project show` command now displays Invariants and Validations
panels in its rich output, completing the specification for project display.

Domain model updates:
- Added `invariants: list[str]` and `invariant_actor: str | None` fields to
  NamespacedProject domain model with backward-compatible defaults
- Updated NamespacedProjectModel.to_domain() to parse invariants from JSON
- Fixed from_domain() to preserve actual invariants/invariant_actor data

CLI output enhancements:
- Extracted project show logic into dedicated project_show.py module
- Invariants panel: displays count and list of project-level invariants
  or '(none)' when no invariants are defined
- Validations panel: displays validation attachments for linked resources
- Invariant Actor field displayed when configured

Refactoring:
- Split oversized project.py (654 lines) into modular files under 500 lines:
  * project_show.py - show command and display helpers
  * project_legacy.py - legacy file-filter sub-app preserved
  * project_resource_commands.py - resource link/unlink/delete commands

Database roundtrip fix:
- from_domain() now properly serializes actual invariants_json (was hardcoded
  to empty list) and invariant_actor (was hardcoded to None)

BDD/Behave coverage added:
- Scenario: Create a project with invariants
- Scenario: Project spec dict contains invariants and validations keys
- Scenario: Show project with no invariants displays none
- Scenario: Show project with invariants displays invariant list
- Scenario: Show project with invariant_actor displays actor

ISSUES CLOSED: #9333
2026-06-03 12:16:20 -04:00

213 lines
9.8 KiB
Gherkin

Feature: Project CLI commands (B0.cli.projects)
As a CleverAgents user
I want to manage projects via CLI commands
So that I can create, list, show, link, unlink, and delete projects
Background:
Given a project CLI in-memory database is initialized
# ── Create ────────────────────────────────────────────────────
Scenario: Create a project with bare name defaults to local namespace
When I run project create with name "my-app"
Then the project "local/my-app" should exist
And the project namespace should be "local"
Scenario: Create a project with explicit namespace
When I run project create with name "team/my-app"
Then the project "team/my-app" should exist
And the project namespace should be "team"
Scenario: Create a project with description
When I run project create named "my-app" described as "My test project"
Then the project "local/my-app" should exist
And the project description should be "My test project"
Scenario: Create a project with invalid name fails
When I run project create with invalid name "123bad"
Then the create command should fail with exit code 1
Scenario: Create a duplicate project fails
Given a project "local/dup-test" already exists
When I run project create with name "dup-test"
Then the create command should fail with exit code 1
Scenario: Create a project with reserved namespace fails
When I run project create with invalid name "system/bad"
Then the create command should fail with exit code 1
Scenario: Create a project with invariants
When I run project create named "inv-proj" with invariants "do not modify tests" plus "keep API stable"
Then the project "local/inv-proj" should exist
# ── List ─────────────────────────────────────────────────────
Scenario: List projects shows created projects
Given a project "local/proj-a" already exists
And a project "local/proj-b" already exists
When I list projects
Then the project list should contain "local/proj-a"
And the project list should contain "local/proj-b"
Scenario: List projects with namespace filter
Given a project "local/proj-x" already exists
And a project "team/proj-y" already exists
When I list projects with namespace "team"
Then the project list should contain "team/proj-y"
And the project list should not contain "local/proj-x"
Scenario: List projects with regex filter
Given a project "local/api-service" already exists
And a project "local/web-app" already exists
When I list projects with regex "api"
Then the project list should contain "local/api-service"
And the project list should not contain "local/web-app"
Scenario: List projects with invalid regex fails
When I list projects with invalid regex "[invalid"
Then the list command should fail with exit code 1
Scenario: List projects when empty shows message
When I list projects
Then the project CLI output should contain "No projects found"
# ── Show ─────────────────────────────────────────────────────
Scenario: Show project displays details
Given a project "local/show-test" already exists with description "A test project"
When I show project "local/show-test"
Then the show output should contain "local/show-test"
And the show output should contain "A test project"
Scenario: Show nonexistent project fails
When I show project "local/nonexistent"
Then the show command should fail with exit code 1
Scenario: Show project with linked resources
Given a project "local/linked-proj" already exists
And a resource is linked to project "local/linked-proj"
When I show project "local/linked-proj"
Then the show output should contain "linked_resources"
# ── Link Resource ────────────────────────────────────────────
Scenario: Link resource to project
Given a project "local/link-test" already exists
And a registered resource "my-resource" exists
When I link resource "my-resource" to project "local/link-test"
Then the link should succeed
Scenario: Link resource read-only to project
Given a project "local/ro-test" already exists
And a registered resource "ro-resource" exists
When I link resource "ro-resource" to project "local/ro-test" with read-only
Then the link should succeed
Scenario: Link resource to nonexistent project fails
When I attempt to link to nonexistent project "local/no-such-project"
Then the link command should fail with exit code 1
Scenario: Link nonexistent resource to project fails
Given a project "local/link-fail" already exists
When I link nonexistent resource "no-such-resource" to project "local/link-fail"
Then the link command should fail with exit code 1
# ── Unlink Resource ──────────────────────────────────────────
Scenario: Unlink resource from project
Given a project "local/unlink-test" already exists
And a resource is linked to project "local/unlink-test"
When I unlink the resource from project "local/unlink-test" with yes
Then the unlink should succeed
Scenario: Unlink nonexistent resource from project fails
Given a project "local/unlink-fail" already exists
When I unlink nonexistent resource from project "local/unlink-fail" with yes
Then the unlink command should fail with exit code 1
# ── Delete ───────────────────────────────────────────────────
Scenario: Delete project with confirmation
Given a project "local/del-test" already exists
When I delete project "local/del-test" with yes
Then the project "local/del-test" should not exist
Scenario: Delete nonexistent project fails
When I delete project "local/never-existed" with yes
Then the delete command should fail with exit code 1
Scenario: Delete project with linked resources without force fails
Given a project "local/del-linked" already exists
And a resource is linked to project "local/del-linked"
When I delete project "local/del-linked" with yes but no force
Then the delete command should fail with exit code 1
Scenario: Delete project with linked resources with force
Given a project "local/del-force" already exists
And a resource is linked to project "local/del-force"
When I delete project "local/del-force" with yes and force
Then the project "local/del-force" should not exist
# ── Format output ────────────────────────────────────────────
Scenario: List projects with JSON format
Given a project "local/json-test" already exists
When I list projects with format "json"
Then the project CLI output should contain "namespaced_name"
Scenario: Show project with YAML format
Given a project "local/yaml-test" already exists
When I show project details for "local/yaml-test" as "yaml"
Then the project CLI output should contain "namespaced_name"
Scenario: Show project with plain format
Given a project "local/plain-test" already exists
When I show project details for "local/plain-test" as "plain"
Then the project CLI output should contain "namespaced_name"
Scenario: Create project with JSON format
When I run project create named "fmt-proj" formatted as "json"
Then the project CLI output should contain "namespaced_name"
# ── Project spec dict helper ─────────────────────────────────
Scenario: Project spec dict contains expected keys
Given a project "local/spec-dict" already exists
When I generate the project spec dict for "local/spec-dict"
Then the spec dict should have key "namespaced_name"
And the spec dict should have key "namespace"
And the spec dict should have key "name"
And the spec dict should have key "description"
And the spec dict should have key "linked_resources"
And the spec dict should have key "created_at"
And the spec dict should have key "updated_at"
Scenario: Project spec dict contains invariants and validations keys
Given a project "local/spec-inv" already exists
When I generate the project spec dict for "local/spec-inv"
Then the spec dict should have key "invariants"
And the spec dict should have key "invariant_actor"
And the spec dict should have key "validations"
# ── Invariants and Validations panels ───────────────────────
Scenario: Show project with no invariants displays none
Given a project "local/no-inv-proj" already exists
When I show project "local/no-inv-proj"
Then the show output should contain "invariants"
Scenario: Show project displays validations count
Given a project "local/val-proj" already exists
When I show project "local/val-proj"
Then the show output should contain "validations"
Scenario: Show project with invariants displays invariant list
Given a project "local/inv-show-proj" already exists with invariants
When I show project "local/inv-show-proj"
Then the show output should contain "invariants"
Scenario: Show project with invariant_actor displays actor
Given a project "local/actor-proj" already exists with invariant actor
When I show project "local/actor-proj"
Then the show output should contain "invariant_actor"