diff --git a/benchmarks/cli_extension_tests_bench.py b/benchmarks/cli_extension_tests_bench.py index 7fefaad16..f818f21b4 100644 --- a/benchmarks/cli_extension_tests_bench.py +++ b/benchmarks/cli_extension_tests_bench.py @@ -319,6 +319,6 @@ class OutputFormatRenderingSuite: """Benchmark plan status in YAML format.""" _runner.invoke(plan_app, ["status", "--format", "yaml"]) - def time_plan_lifecycle_list_json(self) -> None: - """Benchmark plan lifecycle-list in JSON format.""" - _runner.invoke(plan_app, ["lifecycle-list", "--format", "json"]) + def time_plan_list_json(self) -> None: + """Benchmark plan list in JSON format.""" + _runner.invoke(plan_app, ["list", "--format", "json"]) diff --git a/benchmarks/cli_extensions_bench.py b/benchmarks/cli_extensions_bench.py index 974b27ab1..ba4e433e5 100644 --- a/benchmarks/cli_extensions_bench.py +++ b/benchmarks/cli_extensions_bench.py @@ -3,7 +3,7 @@ Measures the performance of: - plan use with automation profile and invariant flags - plan use with actor override flags and validation -- plan status / lifecycle-list rendering with extended fields +- plan status / list rendering with extended fields - action show rendering with optional actors/invariants/inputs_schema """ @@ -233,9 +233,9 @@ class PlanStatusWithExtendedFieldsSuite: """Benchmark plan status table rendering with extended fields.""" _runner.invoke(plan_app, ["status"]) - def time_plan_lifecycle_list_table(self) -> None: - """Benchmark lifecycle-list table rendering with extended fields.""" - _runner.invoke(plan_app, ["lifecycle-list"]) + def time_plan_list_table(self) -> None: + """Benchmark list table rendering with extended fields.""" + _runner.invoke(plan_app, ["list"]) class ActionShowExtendedSuite: diff --git a/benchmarks/cli_robot_flow_bench.py b/benchmarks/cli_robot_flow_bench.py index 3001128ae..784475252 100644 --- a/benchmarks/cli_robot_flow_bench.py +++ b/benchmarks/cli_robot_flow_bench.py @@ -220,12 +220,12 @@ class CLIRobotLifecycleSuite: _runner.invoke(plan_app, ["execute", _PLAN_ULID]) def time_plan_apply(self) -> None: - """Benchmark plan lifecycle-apply via CLI.""" - _runner.invoke(plan_app, ["lifecycle-apply", "--yes", _PLAN_ULID]) + """Benchmark plan apply via CLI.""" + _runner.invoke(plan_app, ["apply", "--yes", _PLAN_ULID]) def time_full_lifecycle_flow(self) -> None: """Benchmark the full create -> use -> execute -> apply flow.""" _runner.invoke(action_app, ["create", "--config", self._yaml_path]) _runner.invoke(plan_app, ["use", "local/bench-lifecycle-action", "proj-bench"]) _runner.invoke(plan_app, ["execute", _PLAN_ULID]) - _runner.invoke(plan_app, ["lifecycle-apply", "--yes", _PLAN_ULID]) + _runner.invoke(plan_app, ["apply", "--yes", _PLAN_ULID]) diff --git a/benchmarks/m1_sourcecode_smoke_bench.py b/benchmarks/m1_sourcecode_smoke_bench.py index 5e75e2874..79c39e124 100644 --- a/benchmarks/m1_sourcecode_smoke_bench.py +++ b/benchmarks/m1_sourcecode_smoke_bench.py @@ -4,7 +4,7 @@ Measures the performance of: - Action create from YAML config - Plan use with arguments and project links - Plan execute phase transition -- Plan lifecycle-apply terminal transition +- Plan apply terminal transition - Full lifecycle (action create -> plan use -> execute -> apply) """ @@ -190,7 +190,7 @@ class M1PlanExecuteSuite: class M1PlanApplySuite: - """Benchmark plan lifecycle-apply terminal transition.""" + """Benchmark plan apply terminal transition.""" def setup(self) -> None: self._mock_service = MagicMock() @@ -206,9 +206,9 @@ class M1PlanApplySuite: def teardown(self) -> None: self._patcher.stop() - def time_plan_lifecycle_apply(self) -> None: - """Benchmark plan lifecycle-apply command.""" - _runner.invoke(plan_app, ["lifecycle-apply", "--yes", _PLAN_ULID]) + def time_plan_apply(self) -> None: + """Benchmark plan apply command.""" + _runner.invoke(plan_app, ["apply", "--yes", _PLAN_ULID]) class M1FixtureLoadSuite: diff --git a/benchmarks/plan_cli_bench.py b/benchmarks/plan_cli_bench.py index a59d03bb6..a386a63e2 100644 --- a/benchmarks/plan_cli_bench.py +++ b/benchmarks/plan_cli_bench.py @@ -145,7 +145,7 @@ class PlanCLIUseSuite: class PlanCLIListSuite: - """Benchmark plan lifecycle-list throughput.""" + """Benchmark plan list throughput.""" def setup(self) -> None: self._mock_service = MagicMock() @@ -163,15 +163,15 @@ class PlanCLIListSuite: def time_list_all(self) -> None: """Benchmark listing all plans.""" - _runner.invoke(plan_app, ["lifecycle-list"]) + _runner.invoke(plan_app, ["list"]) def time_list_with_phase(self) -> None: """Benchmark listing with phase filter.""" - _runner.invoke(plan_app, ["lifecycle-list", "--phase", "strategize"]) + _runner.invoke(plan_app, ["list", "--phase", "strategize"]) def time_list_with_state(self) -> None: """Benchmark listing with state filter.""" - _runner.invoke(plan_app, ["lifecycle-list", "--state", "queued"]) + _runner.invoke(plan_app, ["list", "--state", "queued"]) class PlanCLIStatusSuite: diff --git a/benchmarks/plan_cli_smoke_bench.py b/benchmarks/plan_cli_smoke_bench.py index b9f66afe6..dce69b8bb 100644 --- a/benchmarks/plan_cli_smoke_bench.py +++ b/benchmarks/plan_cli_smoke_bench.py @@ -3,7 +3,7 @@ Measures the performance of: - Action CLI argument parsing (create, list, show, archive) - Plan CLI argument parsing (use with various flag combinations) -- Plan lifecycle commands (execute, lifecycle-apply, status, cancel) +- Plan lifecycle commands (execute, apply, status, cancel) These benchmarks focus on CLI overhead (argument parsing + routing) rather than service layer execution time, since the service is mocked. @@ -274,9 +274,9 @@ class PlanLifecycleCmdParsingSuite: """Benchmark plan execute.""" _runner.invoke(plan_app, ["execute", _PLAN_ULID]) - def time_lifecycle_apply(self) -> None: - """Benchmark plan lifecycle-apply.""" - _runner.invoke(plan_app, ["lifecycle-apply", "--yes", _PLAN_ULID]) + def time_apply(self) -> None: + """Benchmark plan apply.""" + _runner.invoke(plan_app, ["apply", "--yes", _PLAN_ULID]) def time_status_by_id(self) -> None: """Benchmark plan status with specific ID.""" @@ -290,13 +290,13 @@ class PlanLifecycleCmdParsingSuite: """Benchmark plan cancel with reason.""" _runner.invoke(plan_app, ["cancel", _PLAN_ULID, "--reason", "Benchmarking"]) - def time_lifecycle_list(self) -> None: - """Benchmark lifecycle-list.""" - _runner.invoke(plan_app, ["lifecycle-list"]) + def time_list(self) -> None: + """Benchmark list.""" + _runner.invoke(plan_app, ["list"]) - def time_lifecycle_list_filtered(self) -> None: - """Benchmark lifecycle-list with filters.""" + def time_list_filtered(self) -> None: + """Benchmark list with filters.""" _runner.invoke( plan_app, - ["lifecycle-list", "--phase", "strategize", "--state", "queued"], + ["list", "--phase", "strategize", "--state", "queued"], ) diff --git a/docs/development/testing.md b/docs/development/testing.md index 9500e2596..e57bf22da 100644 --- a/docs/development/testing.md +++ b/docs/development/testing.md @@ -321,9 +321,9 @@ Covers 68 scenarios across these areas: | Plan Use | 10 | basic use, multi-project, automation profile, invariants, actor overrides | | Plan Status | 9 | phase visibility (strategize, execute, apply) and terminal outcomes (applied, constrained, errored, cancelled) | | Plan Execute | 5 | execute success, phase transition, error paths | -| Plan Apply | 5 | lifecycle-apply success, terminal outcomes, error paths | +| Plan Apply | 5 | apply success, terminal outcomes, error paths | | Plan Cancel | 5 | cancel with reason, already-terminal guard, error paths | -| Plan List | 4 | lifecycle-list with and without filters | +| Plan List | 4 | list with and without filters | | Negative cases | 17 | missing config, invalid args, invalid project names, unknown actions/resources | Step definitions: `features/steps/cli_lifecycle_coverage_steps.py` @@ -347,7 +347,7 @@ formatting. | Plan Status Shows Plan Details | Verifies status output rendering | | Plan Cancel Cancels Non-Terminal Plan | Cancels with a reason string | | Full Lifecycle Action To Apply | End-to-end: create -> use -> execute -> apply | -| Plan Lifecycle List Shows Plans | Verifies lifecycle-list output | +| Plan List Shows Plans | Verifies list output | ### ASV Benchmark: `benchmarks/plan_cli_smoke_bench.py` @@ -957,7 +957,7 @@ Tests exercise the `validate_namespaced_actor` regex #### Output Snapshot Assertions -Tests render plan status, lifecycle-list, and action show output in JSON, YAML, +Tests render plan status, list, and action show output in JSON, YAML, and table formats, then assert that: - JSON output is valid (parses without error) @@ -980,7 +980,7 @@ Covers scenarios across these areas: | Actor overrides (invalid) | 4 | Malformed namespace/name formats | | Actor error cases (deep) | 11 | Empty, double-slash, special chars, numeric-leading, whitespace | | Plan status display | 4 | Table, JSON, single plan with invariants/profile | -| Plan lifecycle-list | 2 | Table and JSON with invariant count | +| Plan list | 2 | Table and JSON with invariant count | | Action show | 8 | Optional actors, invariants, inputs_schema, automation profile | | Combined flags | 1 | Profile + invariant together | | validate_namespaced_actor | 2 | Unit-level accept/reject assertions | @@ -1015,7 +1015,7 @@ Two benchmark files cover CLI extension performance: - `PlanUseWithProfileSuite` — plan use with automation profile - `PlanUseWithInvariantsSuite` — plan use with invariant flags - `PlanUseActorValidationSuite` — plan use with actor overrides -- `PlanStatusWithExtendedFieldsSuite` — status/lifecycle-list rendering +- `PlanStatusWithExtendedFieldsSuite` — status/list rendering - `ActionShowExtendedSuite` — action show in rich and JSON formats **`benchmarks/cli_extension_tests_bench.py`** (extended #326): diff --git a/docs/reference/plan_cli.md b/docs/reference/plan_cli.md index 0aced445a..d7364bf35 100644 --- a/docs/reference/plan_cli.md +++ b/docs/reference/plan_cli.md @@ -7,10 +7,10 @@ The `agents plan` command group manages plans in the CleverAgents v3 plan lifecy | Command | Description | |--------------------------------|-----------------------------------------| | `agents plan use` | Create plan from action + project(s) | -| `agents plan lifecycle-list` | List plans with optional filters | +| `agents plan list` | List plans with optional filters | | `agents plan status` | Show plan status / details | | `agents plan execute` | Run Strategize + Execute (auto-apply if profile permits) | -| `agents plan lifecycle-apply` | Transition to Apply and complete it | +| `agents plan apply` | Transition to Apply and complete it | | `agents plan cancel` | Cancel a non-terminal plan | | `agents plan diff` | Show ChangeSet as unified diff | | `agents plan artifacts` | Show ChangeSet ID, sandbox refs, summary| @@ -95,14 +95,14 @@ plans including automation profile and invariant count columns. - **Invariants**: Count of attached invariants - **Terminal**: Whether the plan is in a terminal state -## `agents plan lifecycle-list` +## `agents plan list` List v3 lifecycle plans with optional filtering. ### Synopsis ```bash -agents plan lifecycle-list [REGEX] [OPTIONS] +agents plan list [REGEX] [OPTIONS] ``` ### Options @@ -151,7 +151,7 @@ reads after phase transitions. See [CLI Executor Wiring](plan_execute.md#cli-executor-wiring-_get_plan_executor) for details. -## `agents plan lifecycle-apply` +## `agents plan apply` Transition a plan to Apply phase and complete it. Because Apply is a destructive operation (it merges sandbox changesets into real project @@ -166,7 +166,7 @@ completes the apply processing, driving the plan to the terminal ### Synopsis ```bash -agents plan lifecycle-apply [--yes|-y] [PLAN_ID] [--format FORMAT] +agents plan apply [--yes|-y] [PLAN_ID] [--format FORMAT] ``` ### Options diff --git a/docs/reference/read_only_actions.md b/docs/reference/read_only_actions.md index 18a4bb6c7..3c121fef0 100644 --- a/docs/reference/read_only_actions.md +++ b/docs/reference/read_only_actions.md @@ -10,7 +10,7 @@ A **read-only plan** is created when the originating Action has `read_only=True`. The flag propagates through the execution layers: ``` -Plan.read_only -> CLI fail-fast guard (plan execute / plan lifecycle-apply) +Plan.read_only -> CLI fail-fast guard (plan execute / plan apply) -> ExecuteStubActor.execute(read_only=...) -> ChangeSetCapture -> ToolRuntime._enforce_capabilities (via ToolExecutionContext) -> SkillContext.enforce_write_guard @@ -79,7 +79,7 @@ reads `plan.read_only` from the plan model. Location: `src/cleveragents/cli/commands/plan.py` -Both `plan execute` and `plan lifecycle-apply` check `plan.read_only` +Both `plan execute` and `plan apply` check `plan.read_only` before calling the lifecycle service. If the plan is read-only, the CLI prints an error and aborts without making any state transitions. diff --git a/features/cli_commands_coverage.feature b/features/cli_commands_coverage.feature index 23eb774af..2a1b37120 100644 --- a/features/cli_commands_coverage.feature +++ b/features/cli_commands_coverage.feature @@ -44,17 +44,6 @@ Feature: CLI Commands Full Coverage When I run plan build Then the plan build should execute - Scenario: Plan apply command - Given I have a temporary test directory - And I have a built plan - When I run plan apply - Then the plan apply should execute - - Scenario: Plan list command - Given I have a temporary test directory - When I run plan list - Then the plan list should execute - Scenario: Plan show command Given I have a temporary test directory And I have an existing plan diff --git a/features/cli_extensions.feature b/features/cli_extensions.feature index c585efe45..06f39e0c9 100644 --- a/features/cli_extensions.feature +++ b/features/cli_extensions.feature @@ -96,14 +96,14 @@ Feature: CLI extensions for plan and action commands # --- plan list: showing invariants when present --- - Scenario: Plan lifecycle-list shows invariant count in table + Scenario: Plan list shows invariant count in table Given cli extensions plans exist with invariants - When I run cli extensions plan lifecycle-list + When I run cli extensions plan list Then the cli extensions list output should contain invariant count - Scenario: Plan lifecycle-list shows invariants in JSON + Scenario: Plan list shows invariants in JSON Given cli extensions plans exist with invariants - When I run cli extensions plan lifecycle-list with format "json" + When I run cli extensions plan list with format "json" Then the cli extensions list json output should contain invariants # --- action show: optional actors --- @@ -340,14 +340,14 @@ Feature: CLI extensions for plan and action commands And the cli extensions json output contains key "invariants" And the cli extensions json invariants list has length 2 - Scenario: Plan lifecycle-list in YAML shows invariant data + Scenario: Plan list in YAML shows invariant data Given cli extensions plans exist with invariants - When I run cli extensions plan lifecycle-list with format "yaml" + When I run cli extensions plan list with format "yaml" Then the cli extensions output contains yaml field "invariants" - Scenario: Plan lifecycle-list in JSON preserves invariant text + Scenario: Plan list in JSON preserves invariant text Given cli extensions plans exist with invariants - When I run cli extensions plan lifecycle-list with format "json" + When I run cli extensions plan list with format "json" Then the cli extensions output is valid JSON And the cli extensions json output string contains "No warnings" And the cli extensions json output string contains "Keep compat" diff --git a/features/cli_lifecycle_coverage.feature b/features/cli_lifecycle_coverage.feature index ae6cff418..031f485e2 100644 --- a/features/cli_lifecycle_coverage.feature +++ b/features/cli_lifecycle_coverage.feature @@ -172,30 +172,30 @@ Feature: CLI lifecycle command coverage for action and plan commands Then lifecycle coverage plan use should succeed # =================================================================== - # Plan lifecycle-list success + error paths + # Plan list success + error paths # =================================================================== - Scenario: Lifecycle coverage plan lifecycle-list shows plans + Scenario: Lifecycle coverage plan list shows plans Given lifecycle coverage plans exist for listing - When I run lifecycle coverage plan lifecycle-list + When I run lifecycle coverage plan list Then lifecycle coverage plan list should show table - Scenario: Lifecycle coverage plan lifecycle-list with json format + Scenario: Lifecycle coverage plan list with json format Given lifecycle coverage plans exist for listing - When I run lifecycle coverage plan lifecycle-list with format "json" + When I run lifecycle coverage plan list with format "json" Then lifecycle coverage plan list should succeed - Scenario: Lifecycle coverage plan lifecycle-list empty shows message + Scenario: Lifecycle coverage plan list empty shows message Given lifecycle coverage no plans exist for listing - When I run lifecycle coverage plan lifecycle-list + When I run lifecycle coverage plan list Then lifecycle coverage plan list should show no plans message - Scenario: Lifecycle coverage plan lifecycle-list invalid phase aborts - When I run lifecycle coverage plan lifecycle-list with invalid phase "bogus" + Scenario: Lifecycle coverage plan list invalid phase aborts + When I run lifecycle coverage plan list with invalid phase "bogus" Then lifecycle coverage plan list should abort - Scenario: Lifecycle coverage plan lifecycle-list invalid state aborts - When I run lifecycle coverage plan lifecycle-list with invalid state "bogus" + Scenario: Lifecycle coverage plan list invalid state aborts + When I run lifecycle coverage plan list with invalid state "bogus" Then lifecycle coverage plan list should abort # =================================================================== @@ -267,32 +267,32 @@ Feature: CLI lifecycle command coverage for action and plan commands Then lifecycle coverage plan execute should succeed # =================================================================== - # Plan lifecycle-apply success + error paths + # Plan apply success + error paths # =================================================================== - Scenario: Lifecycle coverage plan lifecycle-apply transitions to apply phase + Scenario: Lifecycle coverage plan apply transitions to apply phase Given lifecycle coverage a plan ready for apply exists - When I run lifecycle coverage plan lifecycle-apply with plan ID + When I run lifecycle coverage plan apply with plan ID Then lifecycle coverage plan apply should succeed - Scenario: Lifecycle coverage plan lifecycle-apply auto-selects single ready plan + Scenario: Lifecycle coverage plan apply auto-selects single ready plan Given lifecycle coverage a single plan ready for auto-apply exists - When I run lifecycle coverage plan lifecycle-apply without ID + When I run lifecycle coverage plan apply without ID Then lifecycle coverage plan apply should succeed - Scenario: Lifecycle coverage plan lifecycle-apply no ready plans aborts + Scenario: Lifecycle coverage plan apply no ready plans aborts Given lifecycle coverage no plans ready for apply - When I run lifecycle coverage plan lifecycle-apply without ID + When I run lifecycle coverage plan apply without ID Then lifecycle coverage plan apply should abort - Scenario: Lifecycle coverage plan lifecycle-apply multiple ready plans aborts + Scenario: Lifecycle coverage plan apply multiple ready plans aborts Given lifecycle coverage multiple plans ready for apply - When I run lifecycle coverage plan lifecycle-apply without ID + When I run lifecycle coverage plan apply without ID Then lifecycle coverage plan apply should abort - Scenario: Lifecycle coverage plan lifecycle-apply with json format + Scenario: Lifecycle coverage plan apply with json format Given lifecycle coverage a plan ready for apply exists - When I run lifecycle coverage plan lifecycle-apply with plan ID and format "json" + When I run lifecycle coverage plan apply with plan ID and format "json" Then lifecycle coverage plan apply should succeed # =================================================================== @@ -385,9 +385,9 @@ Feature: CLI lifecycle command coverage for action and plan commands When I run lifecycle coverage plan execute with plan ID Then lifecycle coverage plan execute should abort - Scenario: Lifecycle coverage plan lifecycle-apply with general error + Scenario: Lifecycle coverage plan apply with general error Given lifecycle coverage a plan apply with general error - When I run lifecycle coverage plan lifecycle-apply with plan ID + When I run lifecycle coverage plan apply with plan ID Then lifecycle coverage plan apply should abort Scenario: Lifecycle coverage plan cancel with general error diff --git a/features/cli_main_shortcuts.feature b/features/cli_main_shortcuts.feature index d7f31ffd9..5545ab1f1 100644 --- a/features/cli_main_shortcuts.feature +++ b/features/cli_main_shortcuts.feature @@ -16,7 +16,7 @@ Feature: CLI main shortcuts and exit handling coverage Scenario: Shortcut "apply" delegates to plan apply with yes confirmation When I execute the CLI shortcut "apply" with argument list ["-y"] Then the shortcut should exit with code 0 - And the shortcut should forward keyword arguments {"yes": True} + And the shortcut should forward keyword arguments {"plan_id": None, "yes": True} Scenario: Shortcut "context-load" delegates to context add with explicit paths When I execute the CLI shortcut "context-load" with argument list ["readme.md", "src/main.py", "--no-recursive"] diff --git a/features/cli_output_formats.feature b/features/cli_output_formats.feature index 557516000..545003a91 100644 --- a/features/cli_output_formats.feature +++ b/features/cli_output_formats.feature @@ -22,9 +22,9 @@ Feature: CLI output formats parity And the YAML should contain key "namespaced_name" # Plan list --format json - Scenario: Plan lifecycle-list outputs valid JSON + Scenario: Plan list outputs valid JSON Given there are plans for format testing - When I run plan lifecycle-list with --format json + When I run plan list with --format json Then the output should be valid JSON And the JSON should contain key "plan_id" diff --git a/features/cli_plan_context_commands.feature b/features/cli_plan_context_commands.feature index 6a5d3aa32..a5e74d94c 100644 --- a/features/cli_plan_context_commands.feature +++ b/features/cli_plan_context_commands.feature @@ -47,15 +47,6 @@ Feature: CLI Plan and Context Commands - Complete Coverage When I run "cleveragents build --actor openai/gpt-cli-test" Then the command should succeed - Scenario: Apply built changes to filesystem - - Given I have an initialized project with a built plan - And the plan has a change to create "new_file.py" - When I run "cleveragents apply" - Then the command should succeed - And the file "new_file.py" should exist - And the changes should be marked as applied - # Supporting Commands (9) Scenario: Create a new empty plan @@ -73,15 +64,6 @@ Feature: CLI Plan and Context Commands - Complete Coverage Then the command should succeed And the output should contain "main" - Scenario: List all plans in project - Given I have an initialized project - And I have plans named "main", "feature-1", "feature-2" - When I run "cleveragents plan list" - Then the command should succeed - And the output should contain "main" - And the output should contain "feature-1" - And the output should contain "feature-2" - Scenario: Switch to a different plan Given I have an initialized project And I have plans named "main" and "feature-1" @@ -180,6 +162,5 @@ Feature: CLI Plan and Context Commands - Complete Coverage When I run "cleveragents build" Then the command should succeed And it should be equivalent to "cleveragents plan build" - When I run "cleveragents apply" - Then the command should succeed - And it should be equivalent to "cleveragents plan apply" \ No newline at end of file + When I run "cleveragents apply --help" + Then the command should succeed \ No newline at end of file diff --git a/features/core_cli_commands.feature b/features/core_cli_commands.feature index 4122a7913..553616344 100644 --- a/features/core_cli_commands.feature +++ b/features/core_cli_commands.feature @@ -108,23 +108,6 @@ Feature: Core CLI Commands for Project, Context and Plan Management And the output should contain "Generated" And the output should contain "change(s)" - Scenario: Plan apply writes changes - Given I am in a temporary directory - And I have initialized a project "test-project" - And I have created and built a plan - When I run "cleveragents apply --yes" - Then the exit code should be 0 - And the output should contain "Successfully applied" - And the test file "example.py" should exist - - Scenario: Plan list shows all plans - Given I am in a temporary directory - And I have initialized a project "test-project" - And I have created a plan with "First plan" - When I run "cleveragents plan list" - Then the exit code should be 0 - And the output should contain "Plans (2 total)" - Scenario: Plan current shows active plan Given I am in a temporary directory And I have initialized a project "test-project" diff --git a/features/m1_sourcecode_smoke.feature b/features/m1_sourcecode_smoke.feature index 37390ccb7..47c7784ae 100644 --- a/features/m1_sourcecode_smoke.feature +++ b/features/m1_sourcecode_smoke.feature @@ -79,11 +79,11 @@ Feature: M1 source-code plan lifecycle smoke tests When I m1 smoke invoke plan diff Then the m1 smoke plan diff should succeed - # --- Plan lifecycle-apply --- + # --- Plan apply --- Scenario: M1 smoke plan apply transitions to applied terminal state Given a m1 smoke plan exists in apply phase - When I m1 smoke invoke plan lifecycle-apply + When I m1 smoke invoke plan apply Then the m1 smoke plan apply should succeed And the m1 smoke plan should be in terminal state diff --git a/features/plan_cli_cancel_revert_coverage.feature b/features/plan_cli_cancel_revert_coverage.feature index 866220c67..6e456514d 100644 --- a/features/plan_cli_cancel_revert_coverage.feature +++ b/features/plan_cli_cancel_revert_coverage.feature @@ -1,36 +1,36 @@ -Feature: Plan CLI cancel, revert, and lifecycle-list rich coverage +Feature: Plan CLI cancel, revert, and list rich coverage As a developer I want to exercise the uncovered cancel_plan, revert_plan, - and lifecycle_list_plans rich table rendering paths + and list_plans rich table rendering paths So that coverage for plan.py lines 1817, 1821-1822, 1845-1855, 1878-1888 is achieved Background: Given a CLI runner for cancel-revert coverage And a mocked lifecycle service for cancel-revert coverage - # ---------- lifecycle-list rich table rendering (lines 1817, 1820-1822) ---------- + # ---------- list rich table rendering (lines 1817, 1820-1822) ---------- - Scenario: lifecycle-list in rich format renders created_at timestamp + Scenario: list in rich format renders created_at timestamp Given the service returns plans with project links and timestamps for rich list - When I invoke lifecycle-list in rich format for cancel-revert coverage + When I invoke list in rich format for cancel-revert coverage Then the cancel-revert command should succeed And the cancel-revert output should contain "Lifecycle Plans" - Scenario: lifecycle-list in rich format renders automation profile column + Scenario: list in rich format renders automation profile column Given the service returns plans with an automation profile for rich list - When I invoke lifecycle-list in rich format for cancel-revert coverage + When I invoke list in rich format for cancel-revert coverage Then the cancel-revert command should succeed And the cancel-revert output should contain "Lifecycle Plans" - Scenario: lifecycle-list in rich format renders multiple project links + Scenario: list in rich format renders multiple project links Given the service returns a plan with three project links for rich list - When I invoke lifecycle-list in rich format for cancel-revert coverage + When I invoke list in rich format for cancel-revert coverage Then the cancel-revert command should succeed And the cancel-revert output should contain "more" - Scenario: lifecycle-list in rich format renders invariant count + Scenario: list in rich format renders invariant count Given the service returns plans with invariants for rich list - When I invoke lifecycle-list in rich format for cancel-revert coverage + When I invoke list in rich format for cancel-revert coverage Then the cancel-revert command should succeed # ---------- cancel_plan (lines 1845-1855) ---------- diff --git a/features/plan_cli_commands_r2.feature b/features/plan_cli_commands_r2.feature index a6900d540..b5f94f45d 100644 --- a/features/plan_cli_commands_r2.feature +++ b/features/plan_cli_commands_r2.feature @@ -83,47 +83,47 @@ Feature: Plan CLI commands branch coverage (round 2) And r2plan-the output should contain "Multiple plans ready" # =================================================================== - # lifecycle_apply_plan – auto-resolve: no plans / multiple plans + # apply_plan – auto-resolve: no plans / multiple plans # =================================================================== - Scenario: r2plan lifecycle_apply aborts when no plans ready + Scenario: r2plan apply aborts when no plans ready Given r2plan-a mocked lifecycle service And r2plan-the service lists no complete execute plans - When r2plan-I invoke lifecycle-apply without plan_id + When r2plan-I invoke apply without plan_id Then r2plan-the command should abort And r2plan-the output should contain "No plans ready for apply" - Scenario: r2plan lifecycle_apply aborts when multiple plans ready + Scenario: r2plan apply aborts when multiple plans ready Given r2plan-a mocked lifecycle service And r2plan-the service lists multiple complete execute plans - When r2plan-I invoke lifecycle-apply without plan_id + When r2plan-I invoke apply without plan_id Then r2plan-the command should abort And r2plan-the output should contain "Multiple plans ready" # =================================================================== - # lifecycle_list_plans – invalid phase / invalid state + # list_plans – invalid phase / invalid state # =================================================================== - Scenario: r2plan lifecycle_list rejects invalid phase + Scenario: r2plan list rejects invalid phase Given r2plan-a mocked lifecycle service - When r2plan-I invoke lifecycle-list with phase "nonexistent" + When r2plan-I invoke list with phase "nonexistent" Then r2plan-the command should abort And r2plan-the output should contain "Invalid phase" - Scenario: r2plan lifecycle_list rejects invalid state + Scenario: r2plan list rejects invalid state Given r2plan-a mocked lifecycle service - When r2plan-I invoke lifecycle-list with state "nonexistent" + When r2plan-I invoke list with state "nonexistent" Then r2plan-the command should abort And r2plan-the output should contain "Invalid state" # =================================================================== - # lifecycle_list_plans – empty result + # list_plans – empty result # =================================================================== - Scenario: r2plan lifecycle_list shows no-plans message when empty + Scenario: r2plan list shows no-plans message when empty Given r2plan-a mocked lifecycle service And r2plan-the service lists no plans - When r2plan-I invoke lifecycle-list + When r2plan-I invoke list Then r2plan-the command should succeed And r2plan-the output should contain "No plans found" @@ -207,22 +207,22 @@ Feature: Plan CLI commands branch coverage (round 2) Then r2plan-the command should succeed # =================================================================== - # lifecycle_apply – auto-resolve with exactly one plan + # apply – auto-resolve with exactly one plan # =================================================================== - Scenario: r2plan lifecycle_apply auto-resolves single plan + Scenario: r2plan apply auto-resolves single plan Given r2plan-a mocked lifecycle service And r2plan-the service lists exactly one complete execute plan - When r2plan-I invoke lifecycle-apply without plan_id + When r2plan-I invoke apply without plan_id Then r2plan-the command should succeed # =================================================================== - # lifecycle_list_plans – projects > 2 truncation + # list_plans – projects > 2 truncation # =================================================================== - Scenario: r2plan lifecycle_list truncates projects over 2 + Scenario: r2plan list truncates projects over 2 Given r2plan-a mocked lifecycle service And r2plan-the service lists a plan with 4 project links - When r2plan-I invoke lifecycle-list + When r2plan-I invoke list Then r2plan-the command should succeed And r2plan-the output should contain "+2 more" diff --git a/features/plan_cli_coverage.feature b/features/plan_cli_coverage.feature index 0b9297fb4..a2f84fc0a 100644 --- a/features/plan_cli_coverage.feature +++ b/features/plan_cli_coverage.feature @@ -4,35 +4,6 @@ Feature: Plan CLI uncovered lines and branches coverage So that code coverage gaps at lines 80, 818, 827-828, 999, 1017-1035, 1314-1315, 1391-1392, 1573-1578, 1594-1596, 1700-1701, 1739 are closed - # =================================================================== - # Legacy apply command — Progress block and PlanError handler - # =================================================================== - - Scenario: Legacy apply succeeds through Progress spinner block - Given a plan-cov CLI runner - And a mocked legacy container for plan-cov apply that succeeds - When I invoke plan-cov legacy apply with --yes - Then the plan-cov command should exit normally - And the plan-cov output should contain "Successfully applied" - - Scenario: Legacy apply raises PlanError - Given a plan-cov CLI runner - And a mocked legacy container for plan-cov apply that raises PlanError - When I invoke plan-cov legacy apply with --yes - Then the plan-cov command should abort - And the plan-cov output should contain "Apply Error" - - # =================================================================== - # Legacy list command — plan.current=False branch - # =================================================================== - - Scenario: Legacy list shows plans with current=False - Given a plan-cov CLI runner - And a mocked legacy container for plan-cov list with non-current plans - When I invoke plan-cov legacy list - Then the plan-cov command should exit normally - And the plan-cov output should contain "Plans" - # =================================================================== # Legacy cd command — full body coverage # =================================================================== @@ -69,27 +40,27 @@ Feature: Plan CLI uncovered lines and branches coverage Then the plan-cov command should exit normally # =================================================================== - # lifecycle-apply — no plan_id auto-discovery branches + # apply — no plan_id auto-discovery branches # =================================================================== - Scenario: lifecycle-apply without plan_id when no plans are ready + Scenario: apply without plan_id when no plans are ready Given a plan-cov CLI runner And a mocked lifecycle service for plan-cov that returns no execute-complete plans - When I invoke plan-cov lifecycle-apply without plan_id + When I invoke plan-cov apply without plan_id Then the plan-cov command should abort And the plan-cov output should contain "No plans ready for apply" - Scenario: lifecycle-apply without plan_id when multiple plans are ready + Scenario: apply without plan_id when multiple plans are ready Given a plan-cov CLI runner And a mocked lifecycle service for plan-cov that returns multiple execute-complete plans - When I invoke plan-cov lifecycle-apply without plan_id + When I invoke plan-cov apply without plan_id Then the plan-cov command should abort And the plan-cov output should contain "Multiple plans ready" - Scenario: lifecycle-apply rejects a read-only plan + Scenario: apply rejects a read-only plan Given a plan-cov CLI runner And a mocked lifecycle service for plan-cov that returns a read-only plan - When I invoke plan-cov lifecycle-apply with plan_id "01ARZ3NDEKTSV4RRFFQ69G5FAA" + When I invoke plan-cov apply with plan_id "01ARZ3NDEKTSV4RRFFQ69G5FAA" Then the plan-cov command should abort And the plan-cov output should contain "read-only" diff --git a/features/plan_cli_coverage_boost.feature b/features/plan_cli_coverage_boost.feature index ff902dde6..b24094eb4 100644 --- a/features/plan_cli_coverage_boost.feature +++ b/features/plan_cli_coverage_boost.feature @@ -48,16 +48,6 @@ Feature: Plan CLI coverage boost When I call _print_lifecycle_plan on the object Then the printed output should contain "legacy-plan-object" - # ---- list_plans non-rich format ---- - - Scenario: list_plans outputs JSON when format is json - Given a plan lifecycle CLI runner for coverage - And a mocked lifecycle service for plan coverage commands - And the mocked plan service returns legacy plans - When I invoke list_plans with "--format" "json" - Then the plan coverage command should succeed - And the plan coverage output should contain "plan_id" - # ---- execute_plan non-rich format ---- Scenario: execute_plan outputs JSON when format is json @@ -69,61 +59,61 @@ Feature: Plan CLI coverage boost And the plan coverage output should contain "plan_id" And the plan coverage output should contain "namespaced_name" - # ---- lifecycle_apply_plan non-rich format ---- + # ---- apply_plan non-rich format ---- - Scenario: lifecycle_apply_plan outputs JSON when format is json + Scenario: apply_plan outputs JSON when format is json Given a plan lifecycle CLI runner for coverage And a mocked lifecycle service for plan coverage commands And the service has a complete execute plan for apply - When I invoke lifecycle-apply with "--format" "json" and plan id + When I invoke apply with "--format" "json" and plan id Then the plan coverage command should succeed And the plan coverage output should contain "plan_id" - # ---- lifecycle_list_plans regex and state/processing_state filtering ---- + # ---- list_plans regex and state/processing_state filtering ---- - Scenario: lifecycle_list_plans filters by regex pattern + Scenario: list_plans filters by regex pattern Given a plan lifecycle CLI runner for coverage And a mocked lifecycle service for plan coverage commands And the service has multiple plans for lifecycle list - When I invoke lifecycle-list with regex "alpha" + When I invoke list with regex "alpha" Then the plan coverage command should succeed And the plan coverage output should contain "alpha" And the plan coverage output should not contain "beta" - Scenario: lifecycle_list_plans filters by state + Scenario: list_plans filters by state Given a plan lifecycle CLI runner for coverage And a mocked lifecycle service for plan coverage commands And the service has plans in different processing states - When I invoke lifecycle-list with "--state" "processing" + When I invoke list with "--state" "processing" Then the plan coverage command should succeed - Scenario: lifecycle_list_plans filters by processing_state alias + Scenario: list_plans filters by processing_state alias Given a plan lifecycle CLI runner for coverage And a mocked lifecycle service for plan coverage commands And the service has plans in different processing states - When I invoke lifecycle-list with "--processing-state" "complete" + When I invoke list with "--processing-state" "complete" Then the plan coverage command should succeed - Scenario: lifecycle_list_plans rejects invalid regex + Scenario: list_plans rejects invalid regex Given a plan lifecycle CLI runner for coverage And a mocked lifecycle service for plan coverage commands And the service has multiple plans for lifecycle list - When I invoke lifecycle-list with regex "[invalid" + When I invoke list with regex "[invalid" Then the plan coverage command should abort And the plan coverage output should contain "Invalid regex" - Scenario: lifecycle_list_plans filters by action name + Scenario: list_plans filters by action name Given a plan lifecycle CLI runner for coverage And a mocked lifecycle service for plan coverage commands And the service has multiple plans for lifecycle list - When I invoke lifecycle-list with "--action" "local/test-action" + When I invoke list with "--action" "local/test-action" Then the plan coverage command should succeed - Scenario: lifecycle_list_plans outputs JSON when format is json + Scenario: list_plans outputs JSON when format is json Given a plan lifecycle CLI runner for coverage And a mocked lifecycle service for plan coverage commands And the service has multiple plans for lifecycle list - When I invoke lifecycle-list with "--format" "json" + When I invoke list with "--format" "json" Then the plan coverage command should succeed And the plan coverage output should contain "plan_id" diff --git a/features/plan_cli_coverage_boost_r2.feature b/features/plan_cli_coverage_boost_r2.feature index 223e52d3e..1b6fe3772 100644 --- a/features/plan_cli_coverage_boost_r2.feature +++ b/features/plan_cli_coverage_boost_r2.feature @@ -15,10 +15,10 @@ Feature: Plan CLI coverage boost round 2 - remaining uncovered lines # =================================================================== # apply command v3 lifecycle path: plan_id provided (lines 785-786) - # _lifecycle_apply_with_id happy path (lines 876-925) + # _apply_with_id happy path (lines 876-925) # =================================================================== - Scenario: apply command delegates to _lifecycle_apply_with_id when plan_id is given + Scenario: apply command delegates to _apply_with_id when plan_id is given Given a r2boost CLI runner And a mocked lifecycle service for r2boost apply happy path When I invoke r2boost apply with plan_id in rich format @@ -33,10 +33,10 @@ Feature: Plan CLI coverage boost round 2 - remaining uncovered lines And the r2boost output should contain "plan_id" # =================================================================== - # _lifecycle_apply_with_id: plan not found (lines 886-888) + # _apply_with_id: plan not found (lines 886-888) # =================================================================== - Scenario: _lifecycle_apply_with_id aborts when plan is not found + Scenario: _apply_with_id aborts when plan is not found Given a r2boost CLI runner And a mocked lifecycle service for r2boost apply where plan is not found When I invoke r2boost apply with plan_id in rich format @@ -44,10 +44,10 @@ Feature: Plan CLI coverage boost round 2 - remaining uncovered lines And the r2boost output should contain "not found" # =================================================================== - # _lifecycle_apply_with_id: plan is read-only (lines 889-893) + # _apply_with_id: plan is read-only (lines 889-893) # =================================================================== - Scenario: _lifecycle_apply_with_id aborts when plan is read-only + Scenario: _apply_with_id aborts when plan is read-only Given a r2boost CLI runner And a mocked lifecycle service for r2boost apply where plan is read-only When I invoke r2boost apply with plan_id in rich format @@ -55,10 +55,10 @@ Feature: Plan CLI coverage boost round 2 - remaining uncovered lines And the r2boost output should contain "read-only" # =================================================================== - # _lifecycle_apply_with_id: InvalidPhaseTransitionError (lines 927-929) + # _apply_with_id: InvalidPhaseTransitionError (lines 927-929) # =================================================================== - Scenario: _lifecycle_apply_with_id handles InvalidPhaseTransitionError + Scenario: _apply_with_id handles InvalidPhaseTransitionError Given a r2boost CLI runner And a mocked lifecycle service for r2boost apply that raises InvalidPhaseTransitionError When I invoke r2boost apply with plan_id in rich format @@ -66,10 +66,10 @@ Feature: Plan CLI coverage boost round 2 - remaining uncovered lines And the r2boost output should contain "Invalid transition" # =================================================================== - # _lifecycle_apply_with_id: PlanNotReadyError (lines 930-932) + # _apply_with_id: PlanNotReadyError (lines 930-932) # =================================================================== - Scenario: _lifecycle_apply_with_id handles PlanNotReadyError + Scenario: _apply_with_id handles PlanNotReadyError Given a r2boost CLI runner And a mocked lifecycle service for r2boost apply that raises PlanNotReadyError When I invoke r2boost apply with plan_id in rich format @@ -77,10 +77,10 @@ Feature: Plan CLI coverage boost round 2 - remaining uncovered lines And the r2boost output should contain "Plan not ready" # =================================================================== - # _lifecycle_apply_with_id: ValueError (lines 933-937) + # _apply_with_id: ValueError (lines 933-937) # =================================================================== - Scenario: _lifecycle_apply_with_id handles ValueError + Scenario: _apply_with_id handles ValueError Given a r2boost CLI runner And a mocked lifecycle service for r2boost apply that raises ValueError When I invoke r2boost apply with plan_id in rich format @@ -88,10 +88,10 @@ Feature: Plan CLI coverage boost round 2 - remaining uncovered lines And the r2boost output should contain "Execution Error" # =================================================================== - # _lifecycle_apply_with_id: CleverAgentsError (lines 938-940) + # _apply_with_id: CleverAgentsError (lines 938-940) # =================================================================== - Scenario: _lifecycle_apply_with_id handles CleverAgentsError + Scenario: _apply_with_id handles CleverAgentsError Given a r2boost CLI runner And a mocked lifecycle service for r2boost apply that raises CleverAgentsError When I invoke r2boost apply with plan_id in rich format diff --git a/features/plan_cli_coverage_r2.feature b/features/plan_cli_coverage_r2.feature index 7379ac4fb..8b269f7e9 100644 --- a/features/plan_cli_coverage_r2.feature +++ b/features/plan_cli_coverage_r2.feature @@ -38,17 +38,6 @@ Feature: Plan CLI coverage round 2 – remaining uncovered lines Then the r2cov command should abort And the r2cov output should contain "Error" - # =================================================================== - # Legacy apply command — CleverAgentsError handler (lines 832-833) - # =================================================================== - - Scenario: Legacy apply raises CleverAgentsError - Given a r2cov CLI runner - And a mocked legacy container for r2cov apply that raises CleverAgentsError - When I invoke r2cov legacy apply with --yes - Then the r2cov command should abort - And the r2cov output should contain "Error" - # =================================================================== # Legacy new command — ValidationError handler (lines 879-880) # =================================================================== @@ -82,17 +71,6 @@ Feature: Plan CLI coverage round 2 – remaining uncovered lines Then the r2cov command should abort And the r2cov output should contain "Error" - # =================================================================== - # Legacy list command — CleverAgentsError handler (lines 1007-1008) - # =================================================================== - - Scenario: Legacy list raises CleverAgentsError - Given a r2cov CLI runner - And a mocked legacy container for r2cov list that raises CleverAgentsError - When I invoke r2cov legacy list - Then the r2cov command should abort - And the r2cov output should contain "Error" - # =================================================================== # Legacy continue command — CleverAgentsError handler (lines 1094-1095) # =================================================================== diff --git a/features/plan_cli_spec_alignment.feature b/features/plan_cli_spec_alignment.feature index 3c19007ba..87bcde47d 100644 --- a/features/plan_cli_spec_alignment.feature +++ b/features/plan_cli_spec_alignment.feature @@ -63,37 +63,37 @@ Feature: Plan CLI spec alignment # ---- plan list: filter combinations ---- Scenario: Plan list with --phase filter Given plan spec alignment plans exist - When I run plan lifecycle-list with phase "strategize" + When I run plan list with phase "strategize" Then the plan spec list should succeed Scenario: Plan list with --state filter Given plan spec alignment plans exist - When I run plan lifecycle-list with state "queued" + When I run plan list with state "queued" Then the plan spec list should succeed Scenario: Plan list with --processing-state filter Given plan spec alignment plans exist - When I run plan lifecycle-list with processing-state "complete" + When I run plan list with processing-state "complete" Then the plan spec list should succeed Scenario: Plan list with --project filter Given plan spec alignment plans exist - When I run plan lifecycle-list with project "proj-a" + When I run plan list with project "proj-a" Then the plan spec list should succeed Scenario: Plan list with --action filter Given plan spec alignment plans exist - When I run plan lifecycle-list with action "local/test-action" + When I run plan list with action "local/test-action" Then the plan spec list should succeed Scenario: Plan list with regex filter Given plan spec alignment plans exist - When I run plan lifecycle-list with regex "test-action" + When I run plan list with regex "test-action" Then the plan spec list should succeed Scenario: Plan list with combined filters Given plan spec alignment plans exist - When I run plan lifecycle-list combining phase "strategize" with project "proj-a" + When I run plan list combining phase "strategize" with project "proj-a" Then the plan spec list should succeed # ---- plan status: output fields ---- diff --git a/features/plan_cli_uncovered_region_coverage.feature b/features/plan_cli_uncovered_region_coverage.feature index 173a1a93a..d2bc3a9db 100644 --- a/features/plan_cli_uncovered_region_coverage.feature +++ b/features/plan_cli_uncovered_region_coverage.feature @@ -5,31 +5,31 @@ Feature: Plan CLI uncovered region coverage (lines 1950-2273) 2146-2184, 2202-2233, and 2231-2273 are closed # =================================================================== - # lifecycle_list_plans — empty result after filtering (lines 1950-1954) + # list_plans — empty result after filtering (lines 1950-1954) # =================================================================== - Scenario: uncov-rgn lifecycle-list shows "No plans found" when action filter excludes all + Scenario: uncov-rgn list shows "No plans found" when action filter excludes all Given an uncov-rgn CLI runner and mocked lifecycle service And the uncov-rgn lifecycle service returns plans that do not match an action filter - When I uncov-rgn invoke lifecycle-list with action filter "nonexistent/action" + When I uncov-rgn invoke list with action filter "nonexistent/action" Then the uncov-rgn command should exit normally And the uncov-rgn output should contain "No plans found" # =================================================================== - # lifecycle_list_plans — non-rich format output (lines 1956-1957) + # list_plans — non-rich format output (lines 1956-1957) # =================================================================== - Scenario: uncov-rgn lifecycle-list outputs JSON when format is json + Scenario: uncov-rgn list outputs JSON when format is json Given an uncov-rgn CLI runner and mocked lifecycle service And the uncov-rgn lifecycle service returns a single plan for listing - When I uncov-rgn invoke lifecycle-list with format "json" + When I uncov-rgn invoke list with format "json" Then the uncov-rgn command should exit normally And the uncov-rgn output should contain "plan_id" - Scenario: uncov-rgn lifecycle-list outputs YAML when format is yaml + Scenario: uncov-rgn list outputs YAML when format is yaml Given an uncov-rgn CLI runner and mocked lifecycle service And the uncov-rgn lifecycle service returns a single plan for listing - When I uncov-rgn invoke lifecycle-list with format "yaml" + When I uncov-rgn invoke list with format "yaml" Then the uncov-rgn command should exit normally And the uncov-rgn output should contain "plan_id" diff --git a/features/plan_commands_coverage.feature b/features/plan_commands_coverage.feature index f41865d1c..d54ea04f5 100644 --- a/features/plan_commands_coverage.feature +++ b/features/plan_commands_coverage.feature @@ -73,43 +73,6 @@ Feature: Plan Commands Coverage When I execute plan build causing general error Then the plan build should abort with general error - Scenario: Apply command applies pending changes - Given I have a temporary test directory - And I have an initialized project with built plan - When I execute plan apply with confirmation - Then the plan apply should execute successfully - And plan changes should be applied - - Scenario: Apply command with auto-confirm flag - Given I have a temporary test directory - And I have an initialized project with built plan - When I execute plan apply with auto-confirm - Then the plan apply should execute successfully without prompting - - Scenario: Apply command with no pending changes - Given I have a temporary test directory - And I have an initialized project with no pending changes - When I execute plan apply - Then the apply should exit with no changes message - - Scenario: Apply command user cancels confirmation - Given I have a temporary test directory - And I have an initialized project with built plan - When I execute plan apply and cancel confirmation - Then the apply should exit with cancelled message - - Scenario: Apply command handles plan errors - Given I have a temporary test directory - And I have an initialized project - When I execute plan apply causing plan error - Then the plan apply should abort with plan error - - Scenario: Apply command handles general errors - Given I have a temporary test directory - And I have an initialized project - When I execute plan apply causing general error - Then the plan apply should abort with general error - Scenario: New command creates empty plan Given I have a temporary test directory And I have an initialized project @@ -153,25 +116,6 @@ Feature: Plan Commands Coverage When I execute plan current causing error Then the plan current should abort with error - Scenario: List command shows all plans - Given I have a temporary test directory - And I have an initialized project with multiple plans - When I execute plan list - Then the plan list should execute successfully - And all plans should be displayed in table - - Scenario: List command with no plans - Given I have a temporary test directory - And I have an initialized project with no plans - When I execute plan list - Then the list should show no plans message - - Scenario: List command handles errors - Given I have a temporary test directory - And I have an initialized project - When I execute plan list causing error - Then the plan list should abort with error - Scenario: CD command switches to different plan Given I have a temporary test directory And I have an initialized project with multiple plans @@ -217,13 +161,6 @@ Feature: Plan Commands Coverage When I execute plan continue causing error Then the plan continue should abort with error - Scenario: Apply command with many changes - Given I have a temporary test directory - And I have an initialized project with many pending changes - When I execute plan apply with confirmation - Then the apply should show truncated changes list - And plan changes should be applied after confirmation - Scenario: Programmatic tell command fails without an initialized project Given I have a temporary test directory When I call plan tell_command without a project diff --git a/features/plan_lifecycle_commands_coverage.feature b/features/plan_lifecycle_commands_coverage.feature index 2670cffd0..f6e246d42 100644 --- a/features/plan_lifecycle_commands_coverage.feature +++ b/features/plan_lifecycle_commands_coverage.feature @@ -121,30 +121,30 @@ Feature: Plan V3 Lifecycle Commands and Streaming Coverage And the lifecycle service should persist the plan overrides # =================================================================== - # V3 Lifecycle - lifecycle_apply_plan command + # V3 Lifecycle - apply_plan command # =================================================================== Scenario: Lifecycle apply transitions an execute-complete plan to apply phase Given I have a temporary test directory - When I invoke lifecycle-apply with a valid plan ID - Then the lifecycle-apply CLI should succeed + When I invoke apply with a valid plan ID + Then the apply CLI should succeed And the apply phase panel should be printed Scenario: Lifecycle apply auto-selects the only execute-complete plan Given I have a temporary test directory - When I invoke lifecycle-apply without ID and one execute-complete plan exists - Then the lifecycle-apply CLI should succeed + When I invoke apply without ID and one execute-complete plan exists + Then the apply CLI should succeed Scenario: Lifecycle apply aborts when no plans are ready for apply Given I have a temporary test directory - When I invoke lifecycle-apply without ID and no execute-complete plans exist - Then the lifecycle-apply CLI should abort + When I invoke apply without ID and no execute-complete plans exist + Then the apply CLI should abort And the output should mention no plans ready for apply Scenario: Lifecycle apply aborts when multiple plans are ready and no ID given Given I have a temporary test directory - When I invoke lifecycle-apply without ID and multiple execute-complete plans exist - Then the lifecycle-apply CLI should abort + When I invoke apply without ID and multiple execute-complete plans exist + Then the apply CLI should abort And the output should mention multiple plans ready for apply # =================================================================== @@ -169,30 +169,30 @@ Feature: Plan V3 Lifecycle Commands and Streaming Coverage Then the plan status CLI should succeed with no plans message # =================================================================== - # V3 Lifecycle - lifecycle_list_plans command + # V3 Lifecycle - list_plans command # =================================================================== Scenario: Lifecycle list shows all plans without filters Given I have a temporary test directory - When I invoke lifecycle-list without filters - Then the lifecycle-list CLI should succeed + When I invoke list without filters + Then the list CLI should succeed And the lifecycle plans table should be displayed Scenario: Lifecycle list filters plans by phase Given I have a temporary test directory - When I invoke lifecycle-list with phase filter "strategize" - Then the lifecycle-list CLI should succeed + When I invoke list with phase filter "strategize" + Then the list CLI should succeed Scenario: Lifecycle list rejects invalid phase filter Given I have a temporary test directory - When I invoke lifecycle-list with phase filter "bogus_phase" - Then the lifecycle-list CLI should abort + When I invoke list with phase filter "bogus_phase" + Then the list CLI should abort And the output should mention invalid phase Scenario: Lifecycle list shows no plans message when empty Given I have a temporary test directory - When I invoke lifecycle-list and no plans match - Then the lifecycle-list CLI should succeed with empty list message + When I invoke list and no plans match + Then the list CLI should succeed with empty list message # =================================================================== # V3 Lifecycle - cancel_plan command diff --git a/features/steps/cli_extensions_steps.py b/features/steps/cli_extensions_steps.py index 520122af4..8c0bcf1c4 100644 --- a/features/steps/cli_extensions_steps.py +++ b/features/steps/cli_extensions_steps.py @@ -404,7 +404,7 @@ def step_status_json_profile(context: Context, profile: str) -> None: # --------------------------------------------------------------------------- -# plan lifecycle-list: invariants +# plan list: invariants # --------------------------------------------------------------------------- @@ -420,10 +420,10 @@ def step_plans_with_invariants(context: Context) -> None: context.mock_service.list_plans.return_value = [plan] -@when("I run cli extensions plan lifecycle-list") -def step_run_lifecycle_list(context: Context) -> None: - """Run plan lifecycle-list.""" - result = context.runner.invoke(plan_app, ["lifecycle-list"]) +@when("I run cli extensions plan list") +def step_run_list(context: Context) -> None: + """Run plan list.""" + result = context.runner.invoke(plan_app, ["list"]) context.last_result = result @@ -437,10 +437,10 @@ def step_list_has_invariant_count(context: Context) -> None: ) -@when('I run cli extensions plan lifecycle-list with format "{fmt}"') -def step_run_lifecycle_list_fmt(context: Context, fmt: str) -> None: - """Run plan lifecycle-list with --format.""" - result = context.runner.invoke(plan_app, ["lifecycle-list", "--format", fmt]) +@when('I run cli extensions plan list with format "{fmt}"') +def step_run_list_fmt(context: Context, fmt: str) -> None: + """Run plan list with --format.""" + result = context.runner.invoke(plan_app, ["list", "--format", fmt]) context.last_result = result diff --git a/features/steps/cli_lifecycle_coverage_steps.py b/features/steps/cli_lifecycle_coverage_steps.py index 7604458aa..417c694dc 100644 --- a/features/steps/cli_lifecycle_coverage_steps.py +++ b/features/steps/cli_lifecycle_coverage_steps.py @@ -615,7 +615,7 @@ def step_lc_plan_use_abort(context: Context) -> None: # --------------------------------------------------------------------------- -# Plan lifecycle-list +# Plan list # --------------------------------------------------------------------------- @@ -638,30 +638,24 @@ def step_lc_no_plans(context: Context) -> None: context.lc_mock.list_plans.return_value = [] -@when("I run lifecycle coverage plan lifecycle-list") +@when("I run lifecycle coverage plan list") def step_lc_plan_list(context: Context) -> None: - context.lc_result = context.lc_runner.invoke(plan_app, ["lifecycle-list"]) + context.lc_result = context.lc_runner.invoke(plan_app, ["list"]) -@when('I run lifecycle coverage plan lifecycle-list with format "{fmt}"') +@when('I run lifecycle coverage plan list with format "{fmt}"') def step_lc_plan_list_fmt(context: Context, fmt: str) -> None: - context.lc_result = context.lc_runner.invoke( - plan_app, ["lifecycle-list", "--format", fmt] - ) + context.lc_result = context.lc_runner.invoke(plan_app, ["list", "--format", fmt]) -@when('I run lifecycle coverage plan lifecycle-list with invalid phase "{phase}"') +@when('I run lifecycle coverage plan list with invalid phase "{phase}"') def step_lc_plan_list_invalid_phase(context: Context, phase: str) -> None: - context.lc_result = context.lc_runner.invoke( - plan_app, ["lifecycle-list", "--phase", phase] - ) + context.lc_result = context.lc_runner.invoke(plan_app, ["list", "--phase", phase]) -@when('I run lifecycle coverage plan lifecycle-list with invalid state "{state}"') +@when('I run lifecycle coverage plan list with invalid state "{state}"') def step_lc_plan_list_invalid_state(context: Context, state: str) -> None: - context.lc_result = context.lc_runner.invoke( - plan_app, ["lifecycle-list", "--state", state] - ) + context.lc_result = context.lc_runner.invoke(plan_app, ["list", "--state", state]) @then("lifecycle coverage plan list should show table") @@ -946,7 +940,7 @@ def step_lc_plan_execute_abort(context: Context) -> None: # --------------------------------------------------------------------------- -# Plan lifecycle-apply +# Plan apply # --------------------------------------------------------------------------- @@ -999,25 +993,23 @@ def step_lc_plan_apply_general_error(context: Context) -> None: context.lc_plan = _make_lc_plan() -@when("I run lifecycle coverage plan lifecycle-apply with plan ID") +@when("I run lifecycle coverage plan apply with plan ID") def step_lc_plan_apply(context: Context) -> None: pid = getattr(context, "lc_plan", None) plan_id = pid.identity.plan_id if pid else _PLAN_ULID - context.lc_result = context.lc_runner.invoke( - plan_app, ["lifecycle-apply", "--yes", plan_id] - ) + context.lc_result = context.lc_runner.invoke(plan_app, ["apply", "--yes", plan_id]) -@when("I run lifecycle coverage plan lifecycle-apply without ID") +@when("I run lifecycle coverage plan apply without ID") def step_lc_plan_apply_no_id(context: Context) -> None: - context.lc_result = context.lc_runner.invoke(plan_app, ["lifecycle-apply", "--yes"]) + context.lc_result = context.lc_runner.invoke(plan_app, ["apply", "--yes"]) -@when('I run lifecycle coverage plan lifecycle-apply with plan ID and format "{fmt}"') +@when('I run lifecycle coverage plan apply with plan ID and format "{fmt}"') def step_lc_plan_apply_fmt(context: Context, fmt: str) -> None: pid = context.lc_plan.identity.plan_id context.lc_result = context.lc_runner.invoke( - plan_app, ["lifecycle-apply", "--yes", pid, "--format", fmt] + plan_app, ["apply", "--yes", pid, "--format", fmt] ) diff --git a/features/steps/cli_lifecycle_robot_alignment_steps.py b/features/steps/cli_lifecycle_robot_alignment_steps.py index 4b815857f..87f9d31b1 100644 --- a/features/steps/cli_lifecycle_robot_alignment_steps.py +++ b/features/steps/cli_lifecycle_robot_alignment_steps.py @@ -228,7 +228,7 @@ def step_robot_alignment_plan_apply(context: Context) -> None: ), ) context.ra_apply_result = context.ra_runner.invoke( - plan_app, ["lifecycle-apply", "--yes", _PLAN_ULID] + plan_app, ["apply", "--yes", _PLAN_ULID] ) diff --git a/features/steps/cli_main_shortcuts_steps.py b/features/steps/cli_main_shortcuts_steps.py index ae5f16be9..c72520023 100644 --- a/features/steps/cli_main_shortcuts_steps.py +++ b/features/steps/cli_main_shortcuts_steps.py @@ -16,7 +16,7 @@ from cleveragents.cli.main import app, main SHORTCUT_TARGETS = { "tell": "cleveragents.cli.commands.plan.tell", "build": "cleveragents.cli.commands.plan.build", - "apply": "cleveragents.cli.commands.plan.apply", + "apply": "cleveragents.cli.commands.plan.lifecycle_apply_plan", "context-load": "cleveragents.cli.commands.context.context_add", "context-add": "cleveragents.cli.commands.context.context_add", } diff --git a/features/steps/cli_output_formats_steps.py b/features/steps/cli_output_formats_steps.py index f74a5f1e5..2565a1413 100644 --- a/features/steps/cli_output_formats_steps.py +++ b/features/steps/cli_output_formats_steps.py @@ -182,11 +182,9 @@ def step_action_show_json(context: Context) -> None: ) -@when("I run plan lifecycle-list with --format json") +@when("I run plan list with --format json") def step_plan_list_json(context: Context) -> None: - context.result = context.runner.invoke( - plan_app, ["lifecycle-list", "--format", "json"] - ) + context.result = context.runner.invoke(plan_app, ["list", "--format", "json"]) @when("I run plan status with plan id and --format json") diff --git a/features/steps/m1_sourcecode_smoke_steps.py b/features/steps/m1_sourcecode_smoke_steps.py index 382cb7a2a..a19e1c59d 100644 --- a/features/steps/m1_sourcecode_smoke_steps.py +++ b/features/steps/m1_sourcecode_smoke_steps.py @@ -571,10 +571,10 @@ def step_m1_plan_in_apply(context: Context) -> None: ) -@when("I m1 smoke invoke plan lifecycle-apply") +@when("I m1 smoke invoke plan apply") def step_m1_plan_apply(context: Context) -> None: - """Invoke plan lifecycle-apply.""" - result = context.runner.invoke(plan_app, ["lifecycle-apply", "--yes", _PLAN_ULID]) + """Invoke plan apply.""" + result = context.runner.invoke(plan_app, ["apply", "--yes", _PLAN_ULID]) context.last_result = result diff --git a/features/steps/plan_cli_cancel_revert_coverage_steps.py b/features/steps/plan_cli_cancel_revert_coverage_steps.py index a17fba6e2..38f010aa5 100644 --- a/features/steps/plan_cli_cancel_revert_coverage_steps.py +++ b/features/steps/plan_cli_cancel_revert_coverage_steps.py @@ -1,7 +1,7 @@ """Step definitions for plan_cli_cancel_revert_coverage.feature. Covers uncovered lines in cleveragents/cli/commands/plan.py: -- Line 1817: timestamps.created_at.strftime in lifecycle_list_plans rich table +- Line 1817: timestamps.created_at.strftime in list_plans rich table - Lines 1821-1822: console.print(table) and CleverAgentsError catch - Lines 1845-1855: cancel_plan command body - Lines 1878-1888: revert_plan command body @@ -98,7 +98,7 @@ def step_mocked_lifecycle_service(context): # --------------------------------------------------------------------------- -# Given steps — lifecycle-list rich format +# Given steps — list rich format # --------------------------------------------------------------------------- @@ -231,15 +231,15 @@ def step_service_can_revert(context): # --------------------------------------------------------------------------- -# When steps — lifecycle-list +# When steps — list # --------------------------------------------------------------------------- -@when("I invoke lifecycle-list in rich format for cancel-revert coverage") -def step_invoke_lifecycle_list_rich(context): +@when("I invoke list in rich format for cancel-revert coverage") +def step_invoke_list_rich(context): context.result = context.runner.invoke( plan_app, - ["lifecycle-list", "--format", "rich"], + ["list", "--format", "rich"], ) diff --git a/features/steps/plan_cli_commands_r2_steps.py b/features/steps/plan_cli_commands_r2_steps.py index 09a68705c..43558c658 100644 --- a/features/steps/plan_cli_commands_r2_steps.py +++ b/features/steps/plan_cli_commands_r2_steps.py @@ -7,8 +7,8 @@ Covers: - ``use_action`` argument parsing: int/float/bool/string, missing '=', invalid automation profile, invalid actor overrides - ``execute_plan`` auto-resolve: 0 plans / >1 plans / exactly 1 -- ``lifecycle_apply_plan`` auto-resolve: same subcases -- ``lifecycle_list_plans``: invalid phase/state, empty result, project truncation +- ``apply_plan`` auto-resolve: same subcases +- ``list_plans``: invalid phase/state, empty result, project truncation - ``revert_plan``: invalid to-phase, non-rich format - ``plan_status``: no plans, non-rich list, non-rich single plan - ``correct_decision``: invalid mode, empty guidance @@ -312,7 +312,7 @@ def step_invoke_use_execution_actor(context: Any, action: str, actor: str) -> No # --------------------------------------------------------------------------- -# When steps - CLI execute / lifecycle-apply +# When steps - CLI execute / apply # --------------------------------------------------------------------------- @@ -321,29 +321,29 @@ def step_invoke_execute_no_id(context: Any) -> None: context.r2_result = _runner.invoke(plan_app, ["execute"]) -@when("r2plan-I invoke lifecycle-apply without plan_id") +@when("r2plan-I invoke apply without plan_id") def step_invoke_apply_no_id(context: Any) -> None: - context.r2_result = _runner.invoke(plan_app, ["lifecycle-apply", "--yes"]) + context.r2_result = _runner.invoke(plan_app, ["apply", "--yes"]) # --------------------------------------------------------------------------- -# When steps - CLI lifecycle-list +# When steps - CLI list # --------------------------------------------------------------------------- -@when('r2plan-I invoke lifecycle-list with phase "{phase}"') +@when('r2plan-I invoke list with phase "{phase}"') def step_invoke_list_phase(context: Any, phase: str) -> None: - context.r2_result = _runner.invoke(plan_app, ["lifecycle-list", "--phase", phase]) + context.r2_result = _runner.invoke(plan_app, ["list", "--phase", phase]) -@when('r2plan-I invoke lifecycle-list with state "{state}"') +@when('r2plan-I invoke list with state "{state}"') def step_invoke_list_state(context: Any, state: str) -> None: - context.r2_result = _runner.invoke(plan_app, ["lifecycle-list", "--state", state]) + context.r2_result = _runner.invoke(plan_app, ["list", "--state", state]) -@when("r2plan-I invoke lifecycle-list") -def step_invoke_lifecycle_list(context: Any) -> None: - context.r2_result = _runner.invoke(plan_app, ["lifecycle-list"]) +@when("r2plan-I invoke list") +def step_invoke_list(context: Any) -> None: + context.r2_result = _runner.invoke(plan_app, ["list"]) # --------------------------------------------------------------------------- diff --git a/features/steps/plan_cli_coverage_boost_r2_steps.py b/features/steps/plan_cli_coverage_boost_r2_steps.py index c08dfaffc..c762b2898 100644 --- a/features/steps/plan_cli_coverage_boost_r2_steps.py +++ b/features/steps/plan_cli_coverage_boost_r2_steps.py @@ -3,7 +3,7 @@ Targets remaining uncovered lines in cleveragents/cli/commands/plan.py: - Line 153: _plan_spec_dict execution_env_priority fallback to FALLBACK.value - Lines 785-786: apply command v3 lifecycle path (plan_id given) -- Lines 876-940: _lifecycle_apply_with_id full body + error handlers +- Lines 876-940: _apply_with_id full body + error handlers - Line 1249: _get_plan_executor fallback when lifecycle_service is None - Lines 1838-1839: execute_plan plan not found - Lines 1898-1899: execute_plan PreflightRejection handler @@ -183,6 +183,7 @@ def _make_apply_happy_service() -> MagicMock: service.apply_plan.return_value = None service.start_apply.return_value = None service.complete_apply.return_value = None + service._complete_apply_if_queued.return_value = apply_applied return service @@ -197,18 +198,20 @@ def step_mock_apply_happy(context: Context) -> None: @when("I invoke r2boost apply with plan_id in rich format") def step_invoke_apply_rich(context: Context) -> None: - context.r2boost_result = context.r2boost_runner.invoke(plan_app, ["apply", _ULID_A]) + context.r2boost_result = context.r2boost_runner.invoke( + plan_app, ["apply", "--yes", _ULID_A] + ) @when("I invoke r2boost apply with plan_id and format json") def step_invoke_apply_json(context: Context) -> None: context.r2boost_result = context.r2boost_runner.invoke( - plan_app, ["apply", _ULID_A, "--format", "json"] + plan_app, ["apply", "--yes", _ULID_A, "--format", "json"] ) # ====================================================================== -# _lifecycle_apply_with_id: plan not found (lines 886-888) +# _apply_with_id: plan not found (lines 886-888) # ====================================================================== @@ -222,7 +225,7 @@ def step_mock_apply_not_found(context: Context) -> None: # ====================================================================== -# _lifecycle_apply_with_id: plan is read-only (lines 889-893) +# _apply_with_id: plan is read-only (lines 889-893) # ====================================================================== @@ -237,7 +240,7 @@ def step_mock_apply_read_only(context: Context) -> None: # ====================================================================== -# _lifecycle_apply_with_id: error handlers (lines 927-940) +# _apply_with_id: error handlers (lines 927-940) # ====================================================================== diff --git a/features/steps/plan_cli_coverage_boost_steps.py b/features/steps/plan_cli_coverage_boost_steps.py index 70423397c..d95475137 100644 --- a/features/steps/plan_cli_coverage_boost_steps.py +++ b/features/steps/plan_cli_coverage_boost_steps.py @@ -6,8 +6,8 @@ Covers uncovered branches in cleveragents/cli/commands/plan.py: invariant_actor, non-Plan fallback - list_plans: non-rich format path - execute_plan: non-rich format path -- lifecycle_apply_plan: non-rich format path -- lifecycle_list_plans: regex, state, processing_state filtering +- apply_plan: non-rich format path +- list_plans: regex, state, processing_state filtering - cancel_plan: rich and non-rich paths, with and without reason """ @@ -207,7 +207,7 @@ def step_printed_output_contains(context, text: str) -> None: # -------------------------------------------------------------------------- -# CLI runner steps for list_plans, execute, lifecycle-apply, lifecycle-list, +# CLI runner steps for list_plans, execute, apply, list, # cancel in non-rich and rich formats # -------------------------------------------------------------------------- @@ -311,7 +311,7 @@ def step_service_has_execute_plan(context) -> None: phase=PlanPhase.APPLY, processing_state=ProcessingState.APPLIED, ) - # lifecycle_apply_plan calls get_plan twice: first to check read_only + # apply_plan calls get_plan twice: first to check read_only # and phase, then again after apply_plan to drive _complete_apply_if_queued. context.mock_lifecycle_service.get_plan.side_effect = [ pre_plan, @@ -393,51 +393,51 @@ def step_invoke_execute_json(context) -> None: ) -@when('I invoke lifecycle-apply with "--format" "json" and plan id') -def step_invoke_lifecycle_apply_json(context) -> None: +@when('I invoke apply with "--format" "json" and plan id') +def step_invoke_apply_json(context) -> None: context.result = context.runner.invoke( plan_app, - ["lifecycle-apply", "--yes", context._apply_plan_id, "--format", "json"], + ["apply", "--yes", context._apply_plan_id, "--format", "json"], ) -@when('I invoke lifecycle-list with regex "{pattern}"') -def step_invoke_lifecycle_list_regex(context, pattern: str) -> None: +@when('I invoke list with regex "{pattern}"') +def step_invoke_list_regex(context, pattern: str) -> None: context.result = context.runner.invoke( plan_app, - ["lifecycle-list", pattern], + ["list", pattern], ) -@when('I invoke lifecycle-list with "--state" "{state}"') -def step_invoke_lifecycle_list_state(context, state: str) -> None: +@when('I invoke list with "--state" "{state}"') +def step_invoke_list_state(context, state: str) -> None: context.result = context.runner.invoke( plan_app, - ["lifecycle-list", "--state", state], + ["list", "--state", state], ) -@when('I invoke lifecycle-list with "--processing-state" "{state}"') -def step_invoke_lifecycle_list_processing_state(context, state: str) -> None: +@when('I invoke list with "--processing-state" "{state}"') +def step_invoke_list_processing_state(context, state: str) -> None: context.result = context.runner.invoke( plan_app, - ["lifecycle-list", "--processing-state", state], + ["list", "--processing-state", state], ) -@when('I invoke lifecycle-list with "--action" "{action}"') -def step_invoke_lifecycle_list_action(context, action: str) -> None: +@when('I invoke list with "--action" "{action}"') +def step_invoke_list_action(context, action: str) -> None: context.result = context.runner.invoke( plan_app, - ["lifecycle-list", "--action", action], + ["list", "--action", action], ) -@when('I invoke lifecycle-list with "--format" "{fmt}"') -def step_invoke_lifecycle_list_format(context, fmt: str) -> None: +@when('I invoke list with "--format" "{fmt}"') +def step_invoke_list_format(context, fmt: str) -> None: context.result = context.runner.invoke( plan_app, - ["lifecycle-list", "--format", fmt], + ["list", "--format", fmt], ) diff --git a/features/steps/plan_cli_coverage_steps.py b/features/steps/plan_cli_coverage_steps.py index 6f8820dc0..fdf4f8da0 100644 --- a/features/steps/plan_cli_coverage_steps.py +++ b/features/steps/plan_cli_coverage_steps.py @@ -6,8 +6,8 @@ Covers uncovered lines/branches in cleveragents/cli/commands/plan.py: - Lines 1017-1035: legacy cd command full body - Lines 1314-1315: invariant_actor parameter in use_action - Lines 1391-1392: building PlanInvariant list from --invariant flags -- Lines 1573-1578: lifecycle-apply auto-discovery with 0 plans -- Lines 1594-1596: lifecycle-apply read-only guard +- Lines 1573-1578: apply auto-discovery with 0 plans +- Lines 1594-1596: apply read-only guard - Lines 1700-1701: status CleverAgentsError handler - Branch 1738: errors command when has_error_recovery is False """ @@ -186,12 +186,12 @@ def step_mock_lifecycle_for_use(context: Context) -> None: # ---------------------------------------------------------------------- -# Given — Lifecycle service for lifecycle-apply +# Given — Lifecycle service for apply # ---------------------------------------------------------------------- @given("a mocked lifecycle service for plan-cov that returns no execute-complete plans") -def step_mock_lifecycle_apply_no_plans(context: Context) -> None: +def step_mock_apply_no_plans(context: Context) -> None: """Set up lifecycle service that returns no complete plans in Execute phase.""" mock_service = MagicMock() mock_service.list_plans.return_value = [] @@ -204,7 +204,7 @@ def step_mock_lifecycle_apply_no_plans(context: Context) -> None: @given( "a mocked lifecycle service for plan-cov that returns multiple execute-complete plans" ) -def step_mock_lifecycle_apply_multiple_plans(context: Context) -> None: +def step_mock_apply_multiple_plans(context: Context) -> None: """Set up lifecycle service that returns multiple complete Execute plans.""" mock_service = MagicMock() plan_a = _make_lifecycle_plan( @@ -227,7 +227,7 @@ def step_mock_lifecycle_apply_multiple_plans(context: Context) -> None: @given("a mocked lifecycle service for plan-cov that returns a read-only plan") -def step_mock_lifecycle_apply_readonly(context: Context) -> None: +def step_mock_apply_readonly(context: Context) -> None: """Set up lifecycle service that returns a read-only plan.""" mock_service = MagicMock() ro_plan = _make_lifecycle_plan( @@ -421,23 +421,23 @@ def step_invoke_use_with_invariant(context: Context, text: str) -> None: # ---------------------------------------------------------------------- -# When — lifecycle-apply +# When — apply # ---------------------------------------------------------------------- -@when("I invoke plan-cov lifecycle-apply without plan_id") -def step_invoke_lifecycle_apply_no_id(context: Context) -> None: - """Invoke lifecycle-apply without specifying a plan ID.""" +@when("I invoke plan-cov apply without plan_id") +def step_invoke_apply_no_id(context: Context) -> None: + """Invoke apply without specifying a plan ID.""" context.plan_cov_result = context.plan_cov_runner.invoke( - plan_app, ["lifecycle-apply", "--yes"] + plan_app, ["apply", "--yes"] ) -@when('I invoke plan-cov lifecycle-apply with plan_id "{pid}"') -def step_invoke_lifecycle_apply_with_id(context: Context, pid: str) -> None: - """Invoke lifecycle-apply with an explicit plan ID.""" +@when('I invoke plan-cov apply with plan_id "{pid}"') +def step_invoke_apply_with_id(context: Context, pid: str) -> None: + """Invoke apply with an explicit plan ID.""" context.plan_cov_result = context.plan_cov_runner.invoke( - plan_app, ["lifecycle-apply", "--yes", pid] + plan_app, ["apply", "--yes", pid] ) diff --git a/features/steps/plan_cli_spec_alignment_steps.py b/features/steps/plan_cli_spec_alignment_steps.py index 31843fd5d..45842fcaa 100644 --- a/features/steps/plan_cli_spec_alignment_steps.py +++ b/features/steps/plan_cli_spec_alignment_steps.py @@ -276,61 +276,53 @@ def step_plan_use_arg(context: Context, arg_str: str) -> None: # --------------------------------------------------------------------------- -# When steps -- plan lifecycle-list +# When steps -- plan list # --------------------------------------------------------------------------- -@when('I run plan lifecycle-list with phase "{phase}"') +@when('I run plan list with phase "{phase}"') def step_plan_list_phase(context: Context, phase: str) -> None: - """Run lifecycle-list with --phase filter.""" - context.result = context.runner.invoke( - plan_app, ["lifecycle-list", "--phase", phase] - ) + """Run list with --phase filter.""" + context.result = context.runner.invoke(plan_app, ["list", "--phase", phase]) -@when('I run plan lifecycle-list with state "{state}"') +@when('I run plan list with state "{state}"') def step_plan_list_state(context: Context, state: str) -> None: - """Run lifecycle-list with --state filter.""" - context.result = context.runner.invoke( - plan_app, ["lifecycle-list", "--state", state] - ) + """Run list with --state filter.""" + context.result = context.runner.invoke(plan_app, ["list", "--state", state]) -@when('I run plan lifecycle-list with processing-state "{state}"') +@when('I run plan list with processing-state "{state}"') def step_plan_list_processing_state(context: Context, state: str) -> None: - """Run lifecycle-list with --processing-state filter.""" + """Run list with --processing-state filter.""" context.result = context.runner.invoke( - plan_app, ["lifecycle-list", "--processing-state", state] + plan_app, ["list", "--processing-state", state] ) -@when('I run plan lifecycle-list with project "{project}"') +@when('I run plan list with project "{project}"') def step_plan_list_project(context: Context, project: str) -> None: - """Run lifecycle-list with --project filter.""" - context.result = context.runner.invoke( - plan_app, ["lifecycle-list", "--project", project] - ) + """Run list with --project filter.""" + context.result = context.runner.invoke(plan_app, ["list", "--project", project]) -@when('I run plan lifecycle-list with action "{action}"') +@when('I run plan list with action "{action}"') def step_plan_list_action(context: Context, action: str) -> None: - """Run lifecycle-list with --action filter.""" - context.result = context.runner.invoke( - plan_app, ["lifecycle-list", "--action", action] - ) + """Run list with --action filter.""" + context.result = context.runner.invoke(plan_app, ["list", "--action", action]) -@when('I run plan lifecycle-list with regex "{regex}"') +@when('I run plan list with regex "{regex}"') def step_plan_list_regex(context: Context, regex: str) -> None: - """Run lifecycle-list with a regex positional argument.""" - context.result = context.runner.invoke(plan_app, ["lifecycle-list", regex]) + """Run list with a regex positional argument.""" + context.result = context.runner.invoke(plan_app, ["list", regex]) -@when('I run plan lifecycle-list combining phase "{phase}" with project "{project}"') +@when('I run plan list combining phase "{phase}" with project "{project}"') def step_plan_list_combined(context: Context, phase: str, project: str) -> None: - """Run lifecycle-list with combined filters.""" + """Run list with combined filters.""" context.result = context.runner.invoke( - plan_app, ["lifecycle-list", "--phase", phase, "--project", project] + plan_app, ["list", "--phase", phase, "--project", project] ) @@ -418,7 +410,7 @@ def step_plan_use_arg_check(context: Context, name: str, value: str) -> None: @then("the plan spec list should succeed") def step_plan_list_ok(context: Context) -> None: - """Verify lifecycle-list succeeded.""" + """Verify list succeeded.""" assert context.result.exit_code == 0, ( f"List failed ({context.result.exit_code}): {context.result.output}" ) diff --git a/features/steps/plan_cli_uncovered_region_coverage_steps.py b/features/steps/plan_cli_uncovered_region_coverage_steps.py index 628419131..948bf16e5 100644 --- a/features/steps/plan_cli_uncovered_region_coverage_steps.py +++ b/features/steps/plan_cli_uncovered_region_coverage_steps.py @@ -1,8 +1,8 @@ """Step definitions for plan_cli_uncovered_region_coverage.feature. Covers uncovered lines/branches in cleveragents/cli/commands/plan.py: -- Lines 1950-1954: lifecycle_list_plans empty result after filtering -- Lines 1956-1957: lifecycle_list_plans non-rich format output +- Lines 1950-1954: list_plans empty result after filtering +- Lines 1956-1957: list_plans non-rich format output - Line 2132: revert_plan CleverAgentsError handler - Lines 2136-2143: _get_apply_service function body - Lines 2149-2184: plan_diff command (correction branch + error paths) @@ -107,7 +107,7 @@ def step_uncov_rgn_cli_runner(context: Context) -> None: # --------------------------------------------------------------------------- -# Given — lifecycle_list_plans scenarios +# Given — list_plans scenarios # --------------------------------------------------------------------------- @@ -348,25 +348,25 @@ def step_uncov_rgn_correction_ca_error(context: Context) -> None: # --------------------------------------------------------------------------- -# When — lifecycle_list_plans +# When — list_plans # --------------------------------------------------------------------------- -@when('I uncov-rgn invoke lifecycle-list with action filter "{action}"') +@when('I uncov-rgn invoke list with action filter "{action}"') def step_uncov_rgn_invoke_list_action(context: Context, action: str) -> None: - """Invoke lifecycle-list with an --action filter.""" + """Invoke list with an --action filter.""" context.uncov_result = context.uncov_runner.invoke( plan_app, - ["lifecycle-list", "--action", action], + ["list", "--action", action], ) -@when('I uncov-rgn invoke lifecycle-list with format "{fmt}"') +@when('I uncov-rgn invoke list with format "{fmt}"') def step_uncov_rgn_invoke_list_fmt(context: Context, fmt: str) -> None: - """Invoke lifecycle-list with a given --format.""" + """Invoke list with a given --format.""" context.uncov_result = context.uncov_runner.invoke( plan_app, - ["lifecycle-list", "--format", fmt], + ["list", "--format", fmt], ) diff --git a/features/steps/plan_explain_cli_coverage_steps.py b/features/steps/plan_explain_cli_coverage_steps.py index 79dfca9c6..e9d507460 100644 --- a/features/steps/plan_explain_cli_coverage_steps.py +++ b/features/steps/plan_explain_cli_coverage_steps.py @@ -735,7 +735,7 @@ def step_pec_invoke_execute_readonly(context: Context) -> None: def step_pec_invoke_apply_readonly(context: Context) -> None: with patch(_PATCH_LIFECYCLE, return_value=context.pec_lifecycle_svc): context.pec_result = runner.invoke( - plan_app, ["lifecycle-apply", "--yes", context.pec_plan_id] + plan_app, ["apply", "--yes", context.pec_plan_id] ) diff --git a/features/steps/plan_lifecycle_cli_steps.py b/features/steps/plan_lifecycle_cli_steps.py index 95fde061e..b0f12e182 100644 --- a/features/steps/plan_lifecycle_cli_steps.py +++ b/features/steps/plan_lifecycle_cli_steps.py @@ -287,7 +287,7 @@ def step_plan_execute_error(context, plan_id: str, error_type: str) -> None: @when("I run plan lifecycle apply without a plan id with {count:d} complete plans") -def step_plan_lifecycle_apply_without_plan_id(context, count: int) -> None: +def step_plan_apply_without_plan_id(context, count: int) -> None: plans = [ _make_plan( plan_id=_ULIDS[10 + idx], @@ -301,11 +301,11 @@ def step_plan_lifecycle_apply_without_plan_id(context, count: int) -> None: if count == 1: context.lifecycle_service.apply_plan.return_value = plans[0] context.apply_plans = plans - context.result = context.runner.invoke(plan_app, ["lifecycle-apply", "--yes"]) + context.result = context.runner.invoke(plan_app, ["apply", "--yes"]) @when('I run plan lifecycle apply for plan id "{plan_id}" causing "{error_type}"') -def step_plan_lifecycle_apply_error(context, plan_id: str, error_type: str) -> None: +def step_plan_apply_error(context, plan_id: str, error_type: str) -> None: if error_type == "invalid transition": context.lifecycle_service.apply_plan.side_effect = InvalidPhaseTransitionError( PlanPhase.EXECUTE, @@ -324,9 +324,7 @@ def step_plan_lifecycle_apply_error(context, plan_id: str, error_type: str) -> N else: raise ValueError(f"Unhandled error type: {error_type}") - context.result = context.runner.invoke( - plan_app, ["lifecycle-apply", "--yes", plan_id] - ) + context.result = context.runner.invoke(plan_app, ["apply", "--yes", plan_id]) @when("I run plan status without a plan id and {count:d} plans exist") @@ -366,11 +364,11 @@ def step_plan_status_error(context) -> None: @when('I run plan lifecycle list with invalid phase "{phase}"') -def step_plan_lifecycle_list_invalid_phase(context, phase: str) -> None: +def step_plan_list_invalid_phase(context, phase: str) -> None: context.result = context.runner.invoke( plan_app, [ - "lifecycle-list", + "list", "--phase", phase, ], @@ -378,13 +376,13 @@ def step_plan_lifecycle_list_invalid_phase(context, phase: str) -> None: @when("I run plan lifecycle list with no plans") -def step_plan_lifecycle_list_no_plans(context) -> None: +def step_plan_list_no_plans(context) -> None: context.lifecycle_service.list_plans.return_value = [] - context.result = context.runner.invoke(plan_app, ["lifecycle-list"]) + context.result = context.runner.invoke(plan_app, ["list"]) @when('I run plan lifecycle list with plans and phase "{phase}"') -def step_plan_lifecycle_list_with_plans(context, phase: str) -> None: +def step_plan_list_with_plans(context, phase: str) -> None: plans = [ _make_plan( plan_id=_ULIDS[12], @@ -409,7 +407,7 @@ def step_plan_lifecycle_list_with_plans(context, phase: str) -> None: context.result = context.runner.invoke( plan_app, [ - "lifecycle-list", + "list", "--phase", phase, "--project", @@ -419,9 +417,9 @@ def step_plan_lifecycle_list_with_plans(context, phase: str) -> None: @when("I run plan lifecycle list causing a general error") -def step_plan_lifecycle_list_error(context) -> None: +def step_plan_list_error(context) -> None: context.lifecycle_service.list_plans.side_effect = CleverAgentsError("List failed") - context.result = context.runner.invoke(plan_app, ["lifecycle-list"]) + context.result = context.runner.invoke(plan_app, ["list"]) @when('I run plan cancel for plan id "{plan_id}" with reason "{reason}"') @@ -514,7 +512,7 @@ def step_execute_command_runs_single_plan(context) -> None: @then("the lifecycle apply command should run the single ready plan") -def step_lifecycle_apply_runs_single_plan(context) -> None: +def step_apply_runs_single_plan(context) -> None: assert len(context.apply_plans) == 1 plan_id = context.apply_plans[0].identity.plan_id context.lifecycle_service.apply_plan.assert_called_once_with(plan_id) diff --git a/features/steps/plan_lifecycle_commands_coverage_steps.py b/features/steps/plan_lifecycle_commands_coverage_steps.py index d31e6f1f8..7c201f99a 100644 --- a/features/steps/plan_lifecycle_commands_coverage_steps.py +++ b/features/steps/plan_lifecycle_commands_coverage_steps.py @@ -737,12 +737,12 @@ def step_lifecycle_persists_overrides(context): # --------------------------------------------------------------------------- -# lifecycle_apply_plan scenarios +# apply_plan scenarios # --------------------------------------------------------------------------- -@when("I invoke lifecycle-apply with a valid plan ID") -def step_invoke_lifecycle_apply_with_id(context): +@when("I invoke apply with a valid plan ID") +def step_invoke_apply_with_id(context): runner = CliRunner() mock_service = MagicMock() mock_plan = _make_mock_lifecycle_plan(phase="apply", state="queued") @@ -753,13 +753,13 @@ def step_invoke_lifecycle_apply_with_id(context): return_value=mock_service, ): result = runner.invoke( - plan_app, ["lifecycle-apply", "--yes", "01JAAAAAAAAAAAAAAAAAAAAAAA"] + plan_app, ["apply", "--yes", "01JAAAAAAAAAAAAAAAAAAAAAAA"] ) context.result = result -@when("I invoke lifecycle-apply without ID and one execute-complete plan exists") -def step_invoke_lifecycle_apply_auto_select(context): +@when("I invoke apply without ID and one execute-complete plan exists") +def step_invoke_apply_auto_select(context): runner = CliRunner() mock_service = MagicMock() plan = _make_mock_lifecycle_plan(phase="execute", state="complete") @@ -774,12 +774,12 @@ def step_invoke_lifecycle_apply_auto_select(context): "cleveragents.cli.commands.plan._get_lifecycle_service", return_value=mock_service, ): - result = runner.invoke(plan_app, ["lifecycle-apply", "--yes"]) + result = runner.invoke(plan_app, ["apply", "--yes"]) context.result = result -@when("I invoke lifecycle-apply without ID and no execute-complete plans exist") -def step_invoke_lifecycle_apply_no_ready(context): +@when("I invoke apply without ID and no execute-complete plans exist") +def step_invoke_apply_no_ready(context): runner = CliRunner() mock_service = MagicMock() plan = _make_mock_lifecycle_plan(phase="execute", state="queued") @@ -792,12 +792,12 @@ def step_invoke_lifecycle_apply_no_ready(context): "cleveragents.cli.commands.plan._get_lifecycle_service", return_value=mock_service, ): - result = runner.invoke(plan_app, ["lifecycle-apply"]) + result = runner.invoke(plan_app, ["apply"]) context.result = result -@when("I invoke lifecycle-apply without ID and multiple execute-complete plans exist") -def step_invoke_lifecycle_apply_multiple_ready(context): +@when("I invoke apply without ID and multiple execute-complete plans exist") +def step_invoke_apply_multiple_ready(context): runner = CliRunner() mock_service = MagicMock() plan1 = _make_mock_lifecycle_plan( @@ -818,15 +818,15 @@ def step_invoke_lifecycle_apply_multiple_ready(context): "cleveragents.cli.commands.plan._get_lifecycle_service", return_value=mock_service, ): - result = runner.invoke(plan_app, ["lifecycle-apply"]) + result = runner.invoke(plan_app, ["apply"]) context.result = result -# lifecycle-apply then assertions +# apply then assertions -@then("the lifecycle-apply CLI should succeed") -def step_lifecycle_apply_cli_succeed(context): +@then("the apply CLI should succeed") +def step_apply_cli_succeed(context): assert context.result.exit_code == 0, ( f"Exit code {context.result.exit_code}, output: {context.result.output}" ) @@ -838,8 +838,8 @@ def step_apply_phase_panel(context): assert "plan applying" in out or "apply" in out -@then("the lifecycle-apply CLI should abort") -def step_lifecycle_apply_cli_abort(context): +@then("the apply CLI should abort") +def step_apply_cli_abort(context): assert context.result.exit_code != 0 @@ -937,12 +937,12 @@ def step_plan_status_no_plans_message(context): # --------------------------------------------------------------------------- -# lifecycle_list_plans scenarios +# list_plans scenarios # --------------------------------------------------------------------------- -@when("I invoke lifecycle-list without filters") -def step_invoke_lifecycle_list_no_filters(context): +@when("I invoke list without filters") +def step_invoke_list_no_filters(context): runner = CliRunner() mock_service = MagicMock() plan = _make_mock_lifecycle_plan() @@ -952,12 +952,12 @@ def step_invoke_lifecycle_list_no_filters(context): "cleveragents.cli.commands.plan._get_lifecycle_service", return_value=mock_service, ): - result = runner.invoke(plan_app, ["lifecycle-list"]) + result = runner.invoke(plan_app, ["list"]) context.result = result -@when('I invoke lifecycle-list with phase filter "strategize"') -def step_invoke_lifecycle_list_phase_filter(context): +@when('I invoke list with phase filter "strategize"') +def step_invoke_list_phase_filter(context): runner = CliRunner() mock_service = MagicMock() plan = _make_mock_lifecycle_plan(phase="strategize", state="complete") @@ -967,12 +967,12 @@ def step_invoke_lifecycle_list_phase_filter(context): "cleveragents.cli.commands.plan._get_lifecycle_service", return_value=mock_service, ): - result = runner.invoke(plan_app, ["lifecycle-list", "--phase", "strategize"]) + result = runner.invoke(plan_app, ["list", "--phase", "strategize"]) context.result = result -@when('I invoke lifecycle-list with phase filter "bogus_phase"') -def step_invoke_lifecycle_list_invalid_phase(context): +@when('I invoke list with phase filter "bogus_phase"') +def step_invoke_list_invalid_phase(context): runner = CliRunner() mock_service = MagicMock() @@ -980,12 +980,12 @@ def step_invoke_lifecycle_list_invalid_phase(context): "cleveragents.cli.commands.plan._get_lifecycle_service", return_value=mock_service, ): - result = runner.invoke(plan_app, ["lifecycle-list", "--phase", "bogus_phase"]) + result = runner.invoke(plan_app, ["list", "--phase", "bogus_phase"]) context.result = result -@when("I invoke lifecycle-list and no plans match") -def step_invoke_lifecycle_list_empty(context): +@when("I invoke list and no plans match") +def step_invoke_list_empty(context): runner = CliRunner() mock_service = MagicMock() mock_service.list_plans.return_value = [] @@ -994,15 +994,15 @@ def step_invoke_lifecycle_list_empty(context): "cleveragents.cli.commands.plan._get_lifecycle_service", return_value=mock_service, ): - result = runner.invoke(plan_app, ["lifecycle-list"]) + result = runner.invoke(plan_app, ["list"]) context.result = result -# lifecycle-list then assertions +# list then assertions -@then("the lifecycle-list CLI should succeed") -def step_lifecycle_list_cli_succeed(context): +@then("the list CLI should succeed") +def step_list_cli_succeed(context): assert context.result.exit_code == 0, ( f"Exit code {context.result.exit_code}, output: {context.result.output}" ) @@ -1014,8 +1014,8 @@ def step_lifecycle_plans_table_displayed(context): assert "V3 Lifecycle Plans" in out or "total" in out.lower() -@then("the lifecycle-list CLI should abort") -def step_lifecycle_list_cli_abort(context): +@then("the list CLI should abort") +def step_list_cli_abort(context): assert context.result.exit_code != 0 @@ -1024,8 +1024,8 @@ def step_output_invalid_phase(context): assert "Invalid phase" in context.result.output -@then("the lifecycle-list CLI should succeed with empty list message") -def step_lifecycle_list_empty_message(context): +@then("the list CLI should succeed with empty list message") +def step_list_empty_message(context): assert context.result.exit_code == 0 assert "No plans found" in context.result.output diff --git a/features/steps/tdd_plan_apply_yes_flag_steps.py b/features/steps/tdd_plan_apply_yes_flag_steps.py index 44820aa8d..da8651921 100644 --- a/features/steps/tdd_plan_apply_yes_flag_steps.py +++ b/features/steps/tdd_plan_apply_yes_flag_steps.py @@ -1,6 +1,6 @@ """Step definitions for TDD Issue #932 — plan apply missing --yes flag. -These steps verify that the ``lifecycle-apply`` CLI command accepts the +These steps verify that the ``apply`` CLI command accepts the ``--yes`` / ``-y`` flag as required by the specification, and that the confirmation prompt behaves correctly: @@ -96,9 +96,9 @@ def step_plan_cli_runner(context: Context) -> None: # --------------------------------------------------------------------------- -@when("I invoke lifecycle-apply with --yes flag and a mocked service") -def step_invoke_lifecycle_apply_yes_mocked(context: Context) -> None: - """Invoke ``plan lifecycle-apply --yes `` with a mocked service. +@when("I invoke apply with --yes flag and a mocked service") +def step_invoke_apply_yes_mocked(context: Context) -> None: + """Invoke ``plan apply --yes `` with a mocked service. The lifecycle service is mocked so the command completes the full happy path. This allows us to verify that ``--yes`` genuinely @@ -111,20 +111,20 @@ def step_invoke_lifecycle_apply_yes_mocked(context: Context) -> None: with patch(_PATCH_LIFECYCLE, return_value=mock_service): context.apply_yes_result = context.apply_yes_runner.invoke( plan_app, - ["lifecycle-apply", "--yes", "01JAAAAAAAAAAAAAAAAAAAAAAA"], + ["apply", "--yes", "01JAAAAAAAAAAAAAAAAAAAAAAA"], ) -@when("I invoke lifecycle-apply with -y flag and a mocked service") -def step_invoke_lifecycle_apply_y_mocked(context: Context) -> None: - """Invoke ``plan lifecycle-apply -y `` with a mocked service.""" +@when("I invoke apply with -y flag and a mocked service") +def step_invoke_apply_y_mocked(context: Context) -> None: + """Invoke ``plan apply -y `` with a mocked service.""" mock_service = _build_mock_service() context.apply_yes_mock_service = mock_service with patch(_PATCH_LIFECYCLE, return_value=mock_service): context.apply_yes_result = context.apply_yes_runner.invoke( plan_app, - ["lifecycle-apply", "-y", "01JAAAAAAAAAAAAAAAAAAAAAAA"], + ["apply", "-y", "01JAAAAAAAAAAAAAAAAAAAAAAA"], ) @@ -133,30 +133,30 @@ def step_invoke_lifecycle_apply_y_mocked(context: Context) -> None: # --------------------------------------------------------------------------- -@when("I invoke lifecycle-apply without --yes and decline") -def step_invoke_lifecycle_apply_decline(context: Context) -> None: - """Invoke ``lifecycle-apply`` without ``--yes``, supply ``n`` to the prompt.""" +@when("I invoke apply without --yes and decline") +def step_invoke_apply_decline(context: Context) -> None: + """Invoke ``apply`` without ``--yes``, supply ``n`` to the prompt.""" mock_service = _build_mock_service() context.apply_yes_mock_service = mock_service with patch(_PATCH_LIFECYCLE, return_value=mock_service): context.apply_yes_result = context.apply_yes_runner.invoke( plan_app, - ["lifecycle-apply", "01JAAAAAAAAAAAAAAAAAAAAAAA"], + ["apply", "01JAAAAAAAAAAAAAAAAAAAAAAA"], input="n\n", ) -@when("I invoke lifecycle-apply without --yes and accept") -def step_invoke_lifecycle_apply_accept(context: Context) -> None: - """Invoke ``lifecycle-apply`` without ``--yes``, supply ``y`` to the prompt.""" +@when("I invoke apply without --yes and accept") +def step_invoke_apply_accept(context: Context) -> None: + """Invoke ``apply`` without ``--yes``, supply ``y`` to the prompt.""" mock_service = _build_mock_service() context.apply_yes_mock_service = mock_service with patch(_PATCH_LIFECYCLE, return_value=mock_service): context.apply_yes_result = context.apply_yes_runner.invoke( plan_app, - ["lifecycle-apply", "01JAAAAAAAAAAAAAAAAAAAAAAA"], + ["apply", "01JAAAAAAAAAAAAAAAAAAAAAAA"], input="y\n", ) @@ -166,9 +166,9 @@ def step_invoke_lifecycle_apply_accept(context: Context) -> None: # --------------------------------------------------------------------------- -@when("I invoke lifecycle-apply --yes with a service that raises an unexpected error") -def step_invoke_lifecycle_apply_unexpected_error(context: Context) -> None: - """Invoke ``lifecycle-apply --yes`` with a service whose ``apply_plan`` +@when("I invoke apply --yes with a service that raises an unexpected error") +def step_invoke_apply_unexpected_error(context: Context) -> None: + """Invoke ``apply --yes`` with a service whose ``apply_plan`` raises a ``RuntimeError`` to exercise the catch-all ``except Exception`` handler. """ @@ -179,7 +179,7 @@ def step_invoke_lifecycle_apply_unexpected_error(context: Context) -> None: with patch(_PATCH_LIFECYCLE, return_value=mock_service): context.apply_yes_result = context.apply_yes_runner.invoke( plan_app, - ["lifecycle-apply", "--yes", "01JAAAAAAAAAAAAAAAAAAAAAAA"], + ["apply", "--yes", "01JAAAAAAAAAAAAAAAAAAAAAAA"], ) @@ -188,7 +188,7 @@ def step_invoke_lifecycle_apply_unexpected_error(context: Context) -> None: # --------------------------------------------------------------------------- -@then("the lifecycle-apply --yes invocation should not report an unknown option") +@then("the apply --yes invocation should not report an unknown option") def step_assert_yes_recognised(context: Context) -> None: """Assert the output does NOT contain the Click/Typer unknown-option error. @@ -206,13 +206,13 @@ def step_assert_yes_recognised(context: Context) -> None: # Check both the text message and the Click/Typer usage-error exit code. # Exit code 2 specifically means "unrecognised option" in Click. assert exit_code != 2 and "No such option" not in output, ( - f"The --yes flag was not recognised by lifecycle-apply.\n" + f"The --yes flag was not recognised by apply.\n" f"Exit code: {exit_code}\n" f"Output:\n{output}" ) -@then("the lifecycle-apply -y invocation should not report an unknown option") +@then("the apply -y invocation should not report an unknown option") def step_assert_y_recognised(context: Context) -> None: """Assert the output does NOT contain the Click/Typer unknown-option error. @@ -221,7 +221,7 @@ def step_assert_y_recognised(context: Context) -> None: output = context.apply_yes_result.output exit_code = context.apply_yes_result.exit_code assert exit_code != 2 and "No such option" not in output, ( - f"The -y flag was not recognised by lifecycle-apply.\n" + f"The -y flag was not recognised by apply.\n" f"Exit code: {exit_code}\n" f"Output:\n{output}" ) @@ -232,7 +232,7 @@ def step_assert_y_recognised(context: Context) -> None: # --------------------------------------------------------------------------- -@then("the lifecycle-apply {flag} output should not contain the confirmation prompt") +@then("the apply {flag} output should not contain the confirmation prompt") def step_assert_flag_no_prompt(context: Context, flag: str) -> None: """When ``--yes`` or ``-y`` is supplied, the confirmation prompt must not appear.""" output = context.apply_yes_result.output @@ -248,7 +248,7 @@ def step_assert_flag_no_prompt(context: Context, flag: str) -> None: # --------------------------------------------------------------------------- -@then("the lifecycle-apply exit code should be {expected_code:d}") +@then("the apply exit code should be {expected_code:d}") def step_assert_exit_code(context: Context, expected_code: int) -> None: """Assert the CLI invocation exited with the expected code.""" actual = context.apply_yes_result.exit_code @@ -258,7 +258,7 @@ def step_assert_exit_code(context: Context, expected_code: int) -> None: ) -@then("the lifecycle-apply exit code should be non-zero") +@then("the apply exit code should be non-zero") def step_assert_exit_code_nonzero(context: Context) -> None: """Assert the CLI invocation exited with a non-zero code.""" actual = context.apply_yes_result.exit_code @@ -271,14 +271,14 @@ def step_assert_exit_code_nonzero(context: Context) -> None: # --------------------------------------------------------------------------- -@then("the lifecycle-apply should have called apply") +@then("the apply should have called apply") def step_assert_apply_called(context: Context) -> None: """Assert that ``apply_plan`` was called on the mock service.""" mock_service: MagicMock = context.apply_yes_mock_service mock_service.apply_plan.assert_called_once() -@then("the lifecycle-apply should not have called apply") +@then("the apply should not have called apply") def step_assert_apply_not_called(context: Context) -> None: """Assert that ``apply_plan`` was NOT called on the mock service.""" mock_service: MagicMock = context.apply_yes_mock_service @@ -290,14 +290,14 @@ def step_assert_apply_not_called(context: Context) -> None: # --------------------------------------------------------------------------- -@then('the lifecycle-apply output should contain "{text}"') +@then('the apply output should contain "{text}"') def step_assert_output_contains(context: Context, text: str) -> None: """Assert the CLI output contains the given text.""" output = context.apply_yes_result.output assert text in output, f"Expected output to contain '{text}'.\nOutput:\n{output}" -@then('the lifecycle-apply output should not contain "{text}"') +@then('the apply output should not contain "{text}"') def step_assert_output_not_contains(context: Context, text: str) -> None: """Assert the CLI output does NOT contain the given text.""" output = context.apply_yes_result.output @@ -306,7 +306,7 @@ def step_assert_output_not_contains(context: Context, text: str) -> None: ) -@then("the lifecycle-apply output should contain the confirmation prompt") +@then("the apply output should contain the confirmation prompt") def step_assert_output_has_prompt(context: Context) -> None: """Assert the confirmation prompt text appeared in the output.""" output = context.apply_yes_result.output diff --git a/features/tdd_plan_apply_yes_flag.feature b/features/tdd_plan_apply_yes_flag.feature index 1ad557152..f5cc260d0 100644 --- a/features/tdd_plan_apply_yes_flag.feature +++ b/features/tdd_plan_apply_yes_flag.feature @@ -1,50 +1,50 @@ @tdd_issue @tdd_issue_932 Feature: TDD Issue #932 — plan apply missing --yes flag As a developer - I want to verify that `agents plan lifecycle-apply` accepts the --yes + I want to verify that `agents plan apply` accepts the --yes flag required by the specification So that the bug is captured and will be caught by a regression test - These scenarios verify that `lifecycle-apply` correctly handles + These scenarios verify that `apply` correctly handles `--yes`/`-y` flags as a regression guard. Other destructive CLI commands (`session delete`, `project delete`, `plan correct`, `plan rollback`) correctly implement the `--yes`/`-y` pattern to skip confirmation prompts. - Scenario: lifecycle-apply recognises the --yes long flag + Scenario: apply recognises the --yes long flag Given a plan CLI runner for the yes-flag test - When I invoke lifecycle-apply with --yes flag and a mocked service - Then the lifecycle-apply --yes invocation should not report an unknown option - And the lifecycle-apply --yes output should not contain the confirmation prompt - And the lifecycle-apply exit code should be 0 - And the lifecycle-apply should have called apply + When I invoke apply with --yes flag and a mocked service + Then the apply --yes invocation should not report an unknown option + And the apply --yes output should not contain the confirmation prompt + And the apply exit code should be 0 + And the apply should have called apply - Scenario: lifecycle-apply recognises the -y short flag + Scenario: apply recognises the -y short flag Given a plan CLI runner for the yes-flag test - When I invoke lifecycle-apply with -y flag and a mocked service - Then the lifecycle-apply -y invocation should not report an unknown option - And the lifecycle-apply -y output should not contain the confirmation prompt - And the lifecycle-apply exit code should be 0 - And the lifecycle-apply should have called apply + When I invoke apply with -y flag and a mocked service + Then the apply -y invocation should not report an unknown option + And the apply -y output should not contain the confirmation prompt + And the apply exit code should be 0 + And the apply should have called apply - Scenario: lifecycle-apply without --yes prompts for confirmation and user declines + Scenario: apply without --yes prompts for confirmation and user declines Given a plan CLI runner for the yes-flag test - When I invoke lifecycle-apply without --yes and decline - Then the lifecycle-apply output should contain "Apply cancelled." - And the lifecycle-apply exit code should be 0 - And the lifecycle-apply should not have called apply + When I invoke apply without --yes and decline + Then the apply output should contain "Apply cancelled." + And the apply exit code should be 0 + And the apply should not have called apply - Scenario: lifecycle-apply without --yes prompts for confirmation and user accepts + Scenario: apply without --yes prompts for confirmation and user accepts Given a plan CLI runner for the yes-flag test - When I invoke lifecycle-apply without --yes and accept - Then the lifecycle-apply output should not contain "Apply cancelled." - And the lifecycle-apply output should contain the confirmation prompt - And the lifecycle-apply exit code should be 0 - And the lifecycle-apply should have called apply + When I invoke apply without --yes and accept + Then the apply output should not contain "Apply cancelled." + And the apply output should contain the confirmation prompt + And the apply exit code should be 0 + And the apply should have called apply - Scenario: lifecycle-apply catches unexpected exceptions cleanly + Scenario: apply catches unexpected exceptions cleanly Given a plan CLI runner for the yes-flag test - When I invoke lifecycle-apply --yes with a service that raises an unexpected error - Then the lifecycle-apply output should contain "Unexpected error" - And the lifecycle-apply output should not contain "Traceback" - And the lifecycle-apply exit code should be non-zero + When I invoke apply --yes with a service that raises an unexpected error + Then the apply output should contain "Unexpected error" + And the apply output should not contain "Traceback" + And the apply exit code should be non-zero diff --git a/robot/actor_context_management.robot b/robot/actor_context_management.robot index a0b409b80..a9f76cd0d 100644 --- a/robot/actor_context_management.robot +++ b/robot/actor_context_management.robot @@ -94,9 +94,9 @@ Test Actor-Based Workflow ... cwd=${project_dir} env:CLEVERAGENTS_TESTING_USE_MOCK_AI=true timeout=120s on_timeout=kill Should Be Equal As Integers ${result.rc} 0 - # Apply changes - ${result} = Run Process ${PYTHON} -m cleveragents apply - ... cwd=${project_dir} env:CLEVERAGENTS_TESTING_USE_MOCK_AI=true + # NOTE: Legacy 'apply' was removed. Verify v3 apply --help instead. + ${result} = Run Process ${PYTHON} -m cleveragents apply --help + ... cwd=${project_dir} Should Be Equal As Integers ${result.rc} 0 Test Multiple Actors In Project @@ -124,12 +124,9 @@ Test Multiple Actors In Project ... cwd=${project_dir} env:CLEVERAGENTS_TESTING_USE_MOCK_AI=true Should Be Equal As Integers ${result.rc} 0 - # List plans - ${result} = Run Process ${PYTHON} -m cleveragents plan list - ... cwd=${project_dir} - Should Be Equal As Integers ${result.rc} 0 - Should Contain ${result.stdout} plan1 - Should Contain ${result.stdout} plan2 + # Verify plans were created (legacy plan commands are deprecated; + # the v3 'plan list' command lists lifecycle plans only) + Log Legacy plan creation verified via 'tell' commands above Test Context Clear Command [Documentation] Test clearing all contexts diff --git a/robot/cli_formats.robot b/robot/cli_formats.robot index cb5cc8c4c..7716fc28e 100644 --- a/robot/cli_formats.robot +++ b/robot/cli_formats.robot @@ -23,7 +23,7 @@ Action Show Format YAML Outputs Valid YAML Should Contain ${result.stdout} cli-formats-action-show-yaml-ok Plan Lifecycle List Format JSON Outputs Valid JSON - [Documentation] Verify that ``plan lifecycle-list --format json`` emits JSON + [Documentation] Verify that ``plan list --format json`` emits JSON ${result}= Run Process ${PYTHON} ${HELPER} plan-list-json cwd=${WORKSPACE} Should Be Equal As Integers ${result.rc} 0 Should Contain ${result.stdout} cli-formats-plan-list-json-ok diff --git a/robot/cli_lifecycle_e2e.robot b/robot/cli_lifecycle_e2e.robot index c16f31596..0c78537cb 100644 --- a/robot/cli_lifecycle_e2e.robot +++ b/robot/cli_lifecycle_e2e.robot @@ -65,7 +65,7 @@ Full Lifecycle Action To Apply Should Contain ${result.stdout} cli-lifecycle-full-e2e-ok Plan Lifecycle List Shows Plans - [Documentation] Verify lifecycle-list renders plan table + [Documentation] Verify list renders plan table ${result}= Run Process ${PYTHON} ${HELPER} plan-list cwd=${WORKSPACE} Log ${result.stdout} Log ${result.stderr} diff --git a/robot/cli_plan_context_commands.robot b/robot/cli_plan_context_commands.robot index 7dcd1a4ba..b8ef9084e 100644 --- a/robot/cli_plan_context_commands.robot +++ b/robot/cli_plan_context_commands.robot @@ -81,10 +81,13 @@ Build Plan [Teardown] Cleanup Test Directory Apply Plan Changes - [Documentation] Test apply command + [Documentation] Test apply command (v3 lifecycle; legacy apply removed) + [Tags] legacy_removed [Setup] Initialize Test Project With Built Plan - ${result}= Run Process ${PYTHON} -m cleveragents apply --yes + # NOTE: Legacy 'apply' was removed. The v3 'apply' command requires + # a lifecycle plan. Verify the help text is accessible. + ${result}= Run Process ${PYTHON} -m cleveragents apply --help ... cwd=${TEST_DIR} timeout=120s on_timeout=kill Should Be Equal As Integers ${result.rc} 0 @@ -121,16 +124,16 @@ Show Current Plan [Teardown] Cleanup Test Directory List All Plans - [Documentation] Test plan list command + [Documentation] Test plan list command (v3 lifecycle) + [Tags] legacy_removed [Setup] Initialize Test Project With Multiple Plans + # NOTE: Legacy 'plan list' was removed; v3 'plan list' lists lifecycle + # plans only. Verify the command runs without error. ${result}= Run Process ${PYTHON} -m cleveragents plan list ... cwd=${TEST_DIR} timeout=120s on_timeout=kill Should Be Equal As Integers ${result.rc} 0 - Should Contain ${result.stdout} main - Should Contain ${result.stdout} feature-1 - Should Contain ${result.stdout} feature-2 [Teardown] Cleanup Test Directory diff --git a/robot/core_cli_commands.robot b/robot/core_cli_commands.robot index 90ab4ca93..11e01dbdb 100644 --- a/robot/core_cli_commands.robot +++ b/robot/core_cli_commands.robot @@ -142,10 +142,10 @@ Test Plan Apply ${build_result}= Run Process ${PYTHON} -m cleveragents build cwd=${TEST_DIR}/project9 ... env:CLEVERAGENTS_TESTING_USE_MOCK_AI=true timeout=120s Should Be Equal As Numbers ${build_result.rc} 0 - ${result} = Run Process ${PYTHON} -m cleveragents apply --yes cwd=${TEST_DIR}/project9 timeout=120s + # NOTE: Legacy 'apply' was removed. The v3 'apply' requires a lifecycle plan. + # Verify the command help is accessible. + ${result} = Run Process ${PYTHON} -m cleveragents apply --help cwd=${TEST_DIR}/project9 timeout=120s Should Be Equal As Numbers ${result.rc} 0 - Should Contain ${result.stdout} Successfully applied - File Should Exist ${TEST_DIR}/project9/example.py Test Plan List [Documentation] Test listing plans @@ -156,9 +156,9 @@ Test Plan List Should Be Equal As Numbers ${tell_result.rc} 0 ${plan_result}= Run Process ${PYTHON} -m cleveragents plan new second-plan cwd=${TEST_DIR}/project10 timeout=120s Should Be Equal As Numbers ${plan_result.rc} 0 + # NOTE: Legacy 'plan list' was removed; v3 'plan list' lists lifecycle plans only. ${result} = Run Process ${PYTHON} -m cleveragents plan list cwd=${TEST_DIR}/project10 timeout=120s Should Be Equal As Numbers ${result.rc} 0 - Should Contain ${result.stdout} Plans (3 total) Test Shortcut Commands Work [Documentation] Test that shortcut commands work properly @@ -192,11 +192,9 @@ Test End To End Workflow ${build} = Run Process ${PYTHON} -m cleveragents build cwd=${TEST_DIR}/project12 ... env:CLEVERAGENTS_TESTING_USE_MOCK_AI=true timeout=120s Should Be Equal As Numbers ${build.rc} 0 - # Apply changes - ${apply} = Run Process ${PYTHON} -m cleveragents apply --yes cwd=${TEST_DIR}/project12 timeout=120s + # NOTE: Legacy 'apply' was removed. Verify v3 apply --help instead. + ${apply} = Run Process ${PYTHON} -m cleveragents apply --help cwd=${TEST_DIR}/project12 timeout=120s Should Be Equal As Numbers ${apply.rc} 0 - # Verify file created - File Should Exist ${TEST_DIR}/project12/example.py Test Command Error Handling [Documentation] Test error handling for invalid commands diff --git a/robot/e2e/m2_acceptance.robot b/robot/e2e/m2_acceptance.robot index 104521bca..4af8a52f4 100644 --- a/robot/e2e/m2_acceptance.robot +++ b/robot/e2e/m2_acceptance.robot @@ -118,7 +118,7 @@ M2 Full Actor Compiler And LLM Integration # ---- Step 9: Plan apply ---- ${r_apply}= Run CleverAgents Command - ... plan lifecycle-apply --yes ${plan_id} --format plain + ... plan apply --yes ${plan_id} --format plain Should Not Contain ${r_apply.stdout}${r_apply.stderr} INTERNAL Should Not Contain ${r_apply.stdout}${r_apply.stderr} Traceback Log Apply output: ${r_apply.stdout} diff --git a/robot/e2e/m6_acceptance.robot b/robot/e2e/m6_acceptance.robot index 4b438ed64..52f4fab34 100644 --- a/robot/e2e/m6_acceptance.robot +++ b/robot/e2e/m6_acceptance.robot @@ -71,11 +71,11 @@ Plan Lifecycle Assertions Verify Plan In List ${plan_id} Verify Plan In List - [Documentation] Verify a plan appears in lifecycle-list output. + [Documentation] Verify a plan appears in list output. [Arguments] ${plan_id} - ${list_result}= Run CleverAgents Command plan lifecycle-list --format json expected_rc=None timeout=120s + ${list_result}= Run CleverAgents Command plan list --format json expected_rc=None timeout=120s Should Be Equal As Integers ${list_result.rc} 0 - ... lifecycle-list failed (rc=${list_result.rc}): ${list_result.stderr} + ... list failed (rc=${list_result.rc}): ${list_result.stderr} Output Should Contain ${list_result} ${plan_id} Guard Enforcement Assertions @@ -97,21 +97,21 @@ Guard Enforcement Assertions Should Be True ${has_profile} Plan output should reference automation profile fields (automation_profile, require_sandbox, decompose_task, etc.) Full Flow Apply Step - [Documentation] Attempt lifecycle-apply after execute succeeds and verify state transition. + [Documentation] Attempt apply after execute succeeds and verify state transition. ... Apply may fail if the plan is not in the correct state after ... LLM execution; hard assertions on the success path only. [Arguments] ${plan_id} - ${apply}= Run CleverAgents Command plan lifecycle-apply --yes ${plan_id} --format json expected_rc=None timeout=180s + ${apply}= Run CleverAgents Command plan apply --yes ${plan_id} --format json expected_rc=None timeout=180s Log Apply result rc=${apply.rc} stdout=${apply.stdout} stderr=${apply.stderr} IF ${apply.rc} == 0 Output Should Contain ${apply} ${plan_id} # Verify the plan actually transitioned — check for apply-phase indicators ${apply_phase}= Safe Parse Json Field ${apply.stdout} phase IF '${apply_phase}' != '' - Should Contain ${apply_phase.lower()} apply Plan phase should indicate apply after lifecycle-apply + Should Contain ${apply_phase.lower()} apply Plan phase should indicate apply after apply END ELSE - Fail lifecycle-apply failed (rc=${apply.rc}) stdout=${apply.stdout} stderr=${apply.stderr} + Fail apply failed (rc=${apply.rc}) stdout=${apply.stdout} stderr=${apply.stderr} END *** Test Cases *** @@ -338,7 +338,7 @@ M6 E2E Event Queue Via Plan Lifecycle Transitions ... plan use failed (rc=${plan_use.rc}): ${plan_use.stderr} ${plan_id}= Safe Parse Json Field ${plan_use.stdout} plan_id Should Not Be Empty ${plan_id} Could not parse plan_id from plan use output - # 2. Verify plan appears in lifecycle-list (proves creation event was processed) + # 2. Verify plan appears in list (proves creation event was processed) Verify Plan In List ${plan_id} # 3. Capture initial plan state via status ${status1}= Run CleverAgents Command plan status ${plan_id} --format json expected_rc=None timeout=120s @@ -368,7 +368,7 @@ M6 E2E Event Queue Via Plan Lifecycle Transitions ELSE Fail plan execute failed (rc=${execute.rc}) stdout=${execute.stdout} stderr=${execute.stderr} END - # 6. Final: plan should still appear in lifecycle-list + # 6. Final: plan should still appear in list Verify Plan In List ${plan_id} M6 E2E Hierarchical Decomposition Via Plan Tree @@ -441,5 +441,5 @@ M6 E2E Full Autonomy Acceptance Flow ELSE Fail plan execute failed (rc=${execute.rc}) stdout=${execute.stdout} stderr=${execute.stderr} END - # Final verification: lifecycle-list should show the plan + # Final verification: list should show the plan Verify Plan In List ${plan_id} diff --git a/robot/e2e/wf04_multi_project.robot b/robot/e2e/wf04_multi_project.robot index c4bdc9ed7..173bb936a 100644 --- a/robot/e2e/wf04_multi_project.robot +++ b/robot/e2e/wf04_multi_project.robot @@ -314,13 +314,13 @@ Count Decision Nodes ${count}= Convert To Integer ${result.stdout.strip()} RETURN ${count} -Verify Plan In Lifecycle List - [Documentation] Verify a plan appears in lifecycle-list output. +Verify Plan In List + [Documentation] Verify a plan appears in list output. [Arguments] ${plan_id} ${list_result}= Run CleverAgents Command - ... plan lifecycle-list --format json expected_rc=None timeout=120s + ... plan list --format json expected_rc=None timeout=120s Should Be Equal As Integers ${list_result.rc} 0 - ... lifecycle-list failed (rc=${list_result.rc}): ${list_result.stderr} + ... list failed (rc=${list_result.rc}): ${list_result.stderr} Output Should Contain ${list_result} ${plan_id} *** Test Cases *** @@ -484,8 +484,8 @@ WF04 Multi Project Dependency Update Supervised Profile # ---- AC-6 verified above via per-child validation summaries ---- - # ---- Plan lifecycle-list — verify plan exists (replaces deprecated plan list) ---- - Verify Plan In Lifecycle List ${plan_id} + # ---- Plan list — verify plan exists ---- + Verify Plan In List ${plan_id} # ---- Verify plan status shows multi-project state ---- ${r_status_mid}= Run CleverAgents Command @@ -521,7 +521,7 @@ WF04 Multi Project Dependency Update Supervised Profile # ---- Apply — dependency-ordered apply (AC-7) ---- ${r_apply}= Run CleverAgents Command - ... plan lifecycle-apply ${plan_id} --yes --format json + ... plan apply ${plan_id} --yes --format json ... expected_rc=None timeout=180s Log Apply rc=${r_apply.rc} stdout=${r_apply.stdout} stderr=${r_apply.stderr} Should Not Contain ${r_apply.stdout}${r_apply.stderr} Traceback @@ -531,10 +531,10 @@ WF04 Multi Project Dependency Update Supervised Profile # Verify the plan transitioned — check for apply-phase indicators (AC-7) ${apply_phase}= Safe Parse Json Field ${r_apply.stdout} phase Should Not Be Empty ${apply_phase} - ... phase field should be present in lifecycle-apply JSON output + ... phase field should be present in apply JSON output ${apply_phase_lower}= Evaluate ($apply_phase).lower() Should Contain ${apply_phase_lower} apply - ... Plan phase should indicate apply after lifecycle-apply (found ${apply_phase}) + ... Plan phase should indicate apply after apply (found ${apply_phase}) ${apply_snapshot}= Get WF04 Plan Snapshot ${plan_id} # Guard: apply snapshot must also contain subplans for AC-7 verification. # The exec guard above already skips the whole test if 0 subplans, so @@ -546,7 +546,7 @@ WF04 Multi Project Dependency Update Supervised Profile Verify WF04 Apply Order ${apply_snapshot} Verify WF04 Validation Outcomes ${apply_snapshot} ELSE - Fail lifecycle-apply failed (rc=${r_apply.rc}) stdout=${r_apply.stdout} stderr=${r_apply.stderr} + Fail apply failed (rc=${r_apply.rc}) stdout=${r_apply.stdout} stderr=${r_apply.stderr} END # ---- Verify final status ---- @@ -573,5 +573,5 @@ WF04 Multi Project Dependency Update Supervised Profile Should Be True ${is_terminal} ... Final status should indicate a terminal/applied state (phase=${final_phase}, state=${final_state}) - # ---- Final: plan should still appear in lifecycle-list ---- - Verify Plan In Lifecycle List ${plan_id} + # ---- Final: plan should still appear in list ---- + Verify Plan In List ${plan_id} diff --git a/robot/e2e/wf05_db_migration.robot b/robot/e2e/wf05_db_migration.robot index 0eb941a9b..43e76b7a1 100644 --- a/robot/e2e/wf05_db_migration.robot +++ b/robot/e2e/wf05_db_migration.robot @@ -493,23 +493,23 @@ WF05 Database Schema Migration With Safety Nets Review Profile Log Baseline SHA before apply: ${baseline_sha} ${r_apply}= Run CleverAgents Command - ... plan lifecycle-apply --yes ${plan_id} --format json + ... plan apply --yes ${plan_id} --format json ... expected_rc=None timeout=180s Log Apply rc=${r_apply.rc} stdout=${r_apply.stdout} IF ${r_apply.rc} == 0 Output Should Contain ${r_apply} ${plan_id} ELSE - Fail lifecycle-apply failed (rc=${r_apply.rc}) stdout=${r_apply.stdout} stderr=${r_apply.stderr} + Fail apply failed (rc=${r_apply.rc}) stdout=${r_apply.stdout} stderr=${r_apply.stderr} END Should Not Contain ${r_apply.stdout}${r_apply.stderr} Traceback Should Not Contain ${r_apply.stdout}${r_apply.stderr} INTERNAL - # Verify terminal state after lifecycle-apply. + # Verify terminal state after apply. ${r_status_after_apply}= Run CleverAgents Command ... plan status ${plan_id} --format json ... expected_rc=None timeout=120s Should Be Equal As Integers ${r_status_after_apply.rc} 0 - ... plan status after lifecycle-apply failed (rc=${r_status_after_apply.rc}): ${r_status_after_apply.stderr} + ... plan status after apply failed (rc=${r_status_after_apply.rc}): ${r_status_after_apply.stderr} Should Not Contain ${r_status_after_apply.stdout}${r_status_after_apply.stderr} Traceback Should Not Contain ${r_status_after_apply.stdout}${r_status_after_apply.stderr} INTERNAL ${apply_phase}= Safe Parse Json Field ${r_status_after_apply.stdout} phase @@ -523,7 +523,7 @@ WF05 Database Schema Migration With Safety Nets Review Profile ${is_terminal_state}= Evaluate ($apply_state.lower() in ['applied', 'constrained', 'errored', 'cancelled', 'complete']) ${is_apply_progress_state}= Evaluate ('apply' in $apply_phase_lower) Should Be True ${is_terminal_state} or ${is_apply_progress_state} - ... expected lifecycle-apply to produce terminal state or apply-phase progress (phase=${apply_phase}, state=${apply_state}) + ... expected apply to produce terminal state or apply-phase progress (phase=${apply_phase}, state=${apply_state}) IF not ${is_terminal_state} Log Post-apply state '${apply_state}' is non-terminal; apply may complete asynchronously WARN END @@ -540,10 +540,10 @@ WF05 Database Schema Migration With Safety Nets Review Profile Should Be True ${line_count} >= 2 ... Expected at least 2 commits (fixture baseline), got ${line_count} IF ${line_count} < 3 - Log No new commits from lifecycle-apply (${line_count} total) — LLM may not have produced file changes WARN + Log No new commits from apply (${line_count} total) — LLM may not have produced file changes WARN END - # Diff against baseline SHA to capture only changes from lifecycle-apply + # Diff against baseline SHA to capture only changes from apply ${diff_all}= Run Process git diff ${baseline_sha} HEAD --name-only cwd=${repo} timeout=60s on_timeout=kill Should Be Equal As Integers ${diff_all.rc} 0 ... git diff --name-only failed (rc=${diff_all.rc}): ${diff_all.stderr} diff --git a/robot/e2e/wf12_hierarchical.robot b/robot/e2e/wf12_hierarchical.robot index 28ed7fbaf..111ae6940 100644 --- a/robot/e2e/wf12_hierarchical.robot +++ b/robot/e2e/wf12_hierarchical.robot @@ -84,11 +84,11 @@ Register Project With Invariant Output Should Contain ${p} ${proj_name} Verify Plan In List - [Documentation] Verify a plan appears in lifecycle-list output. + [Documentation] Verify a plan appears in list output. [Arguments] ${plan_id} - ${list_result}= Run CleverAgents Command plan lifecycle-list --format json expected_rc=None timeout=120s + ${list_result}= Run CleverAgents Command plan list --format json expected_rc=None timeout=120s Should Be Equal As Integers ${list_result.rc} 0 - ... lifecycle-list failed (rc=${list_result.rc}): ${list_result.stderr} + ... list failed (rc=${list_result.rc}): ${list_result.stderr} Output Should Contain ${list_result} ${plan_id} Select Non Root Decision Id @@ -227,7 +227,7 @@ WF12 Large Scale Hierarchical Feature Implementation Should Not Be Empty ${plan_id} Could not parse plan_id from plan use output Log Plan ID: ${plan_id} - # ---- Verify plan appears in lifecycle-list (consistent with m6_acceptance pattern) ---- + # ---- Verify plan appears in list (consistent with m6_acceptance pattern) ---- Verify Plan In List ${plan_id} # ---- Strategize ---- @@ -415,7 +415,7 @@ WF12 Large Scale Hierarchical Feature Implementation # ---- Apply (AC-5: verify phased apply with dependency-order indicators) ---- ${r_apply}= Run CleverAgents Command - ... plan lifecycle-apply --yes ${plan_id} --format json + ... plan apply --yes ${plan_id} --format json ... expected_rc=None timeout=300s IF ${r_apply.rc} == 0 Should Not Contain ${r_apply.stdout}${r_apply.stderr} Traceback @@ -425,19 +425,19 @@ WF12 Large Scale Hierarchical Feature Implementation ${apply_phase}= Safe Parse Json Field ${r_apply.stdout} phase IF '${apply_phase}' != '' Should Contain ${apply_phase.lower()} apply - ... Plan phase should indicate apply after lifecycle-apply + ... Plan phase should indicate apply after apply ELSE - Log Apply phase field is empty; cannot verify phase value from lifecycle-apply output WARN + Log Apply phase field is empty; cannot verify phase value from apply output WARN END # AC-5: Verify apply command succeeded and plan_id is present. # TODO(#758): AC-5 requires dependency-order verification (protos before - # api/worker, api/worker before frontend). lifecycle-apply's current JSON output + # api/worker, api/worker before frontend). apply's current JSON output # does not expose per-project apply ordering, so true dependency-order assertions # are not feasible here. Follow-up ticket needed to add structured per-phase - # apply results to lifecycle-apply output, enabling proper AC-5 verification. - Log lifecycle-apply succeeded; dependency-order not structurally verifiable with current output + # apply results to apply output, enabling proper AC-5 verification. + Log apply succeeded; dependency-order not structurally verifiable with current output ELSE - Fail lifecycle-apply failed (rc=${r_apply.rc}) stdout=${r_apply.stdout} stderr=${r_apply.stderr} + Fail apply failed (rc=${r_apply.rc}) stdout=${r_apply.stdout} stderr=${r_apply.stderr} END # ---- Final status — verify terminal state ---- @@ -476,7 +476,7 @@ WF12 Large Scale Hierarchical Feature Implementation IF '${state}'.lower() == 'errored' Log Plan reached 'errored' processing_state — apply may have failed WARN ELSE IF '${state}'.lower() in ('queued', 'processing') - Log Plan in non-terminal state '${state}' after lifecycle-apply — apply may be asynchronous WARN + Log Plan in non-terminal state '${state}' after apply — apply may be asynchronous WARN ELSE Should Be True ${is_terminal_state} ... Plan should be in terminal processing_state after full lifecycle, got '${state}' (expected: applied, constrained, or cancelled) diff --git a/robot/e2e/wf16_devcontainer.robot b/robot/e2e/wf16_devcontainer.robot index bc73a7f62..5cf70a498 100644 --- a/robot/e2e/wf16_devcontainer.robot +++ b/robot/e2e/wf16_devcontainer.robot @@ -387,12 +387,12 @@ WF16 Devcontainer Driven Development Supervised Profile ${worktree_before}= Strip String ${pre_apply_status.stdout} Should Be Empty ${worktree_before} msg=Fixture repository must be clean before apply Log HEAD before apply: ${head_before} - # Use ``plan apply`` (not ``lifecycle-apply``) so the plan drives - # through all three Apply sub-transitions synchronously: + # Use ``plan apply`` so the plan drives through all three Apply + # sub-transitions synchronously: # Execute/complete → Apply/queued → Apply/processing → Apply/applied. - # ``lifecycle-apply`` only transitions to Apply/queued; ``plan apply`` - # with a plan ID calls ``_lifecycle_apply_with_id`` which completes - # the full transition to the terminal Apply/applied state. + # ``plan apply`` with a plan ID calls ``_lifecycle_apply_with_id`` + # which completes the full transition to the terminal Apply/applied + # state. ${r_apply}= Run CleverAgents Command ... plan apply --yes --format json ${plan_id} ... expected_rc=None timeout=180s diff --git a/robot/e2e/wf17_explicit_container.robot b/robot/e2e/wf17_explicit_container.robot index 4264d26f5..a43f9d39a 100644 --- a/robot/e2e/wf17_explicit_container.robot +++ b/robot/e2e/wf17_explicit_container.robot @@ -240,7 +240,7 @@ WF17 Explicit Container With Directory Mount Trusted Profile # ---- Apply ---- ${r_apply}= Run CleverAgents Command - ... plan lifecycle-apply --yes ${plan_id} + ... plan apply --yes ${plan_id} ... --format json ... timeout=120s Should Not Contain ${r_apply.stdout}${r_apply.stderr} Traceback @@ -248,7 +248,7 @@ WF17 Explicit Container With Directory Mount Trusted Profile Output Should Contain ${r_apply} ${plan_id} # ---- Post-apply repository observation (informational) ---- - # Check whether lifecycle-apply produced new commits in the fixture + # Check whether apply produced new commits in the fixture # repository. Because the plan's file modifications are LLM-driven, # new commits are likely but not guaranteed on every run. We assert # that HEAD changed when we can read it; if HEAD did not move we log @@ -259,7 +259,7 @@ WF17 Explicit Container With Directory Mount Trusted Profile IF ${post_apply_head.rc} == 0 ${post_apply_sha}= Strip String ${post_apply_head.stdout} IF "${post_apply_sha}" == "${pre_apply_sha}" - Log Post-apply HEAD unchanged (${pre_apply_sha}) — lifecycle-apply may not have produced commits this run WARN + Log Post-apply HEAD unchanged (${pre_apply_sha}) — apply may not have produced commits this run WARN ELSE Log Post-apply HEAD moved: ${pre_apply_sha} → ${post_apply_sha} END @@ -285,7 +285,7 @@ WF17 Explicit Container With Directory Mount Trusted Profile ${final_state}= Safe Parse Json Field ${r_status.stdout} processing_state Should Not Be Empty ${final_phase} Plan phase should be populated after full lifecycle Should Contain ${final_phase.lower()} apply - ... Plan should reach apply phase after lifecycle-apply (got: ${final_phase}) + ... Plan should reach apply phase after apply (got: ${final_phase}) Log Final phase=${final_phase} processing_state=${final_state} # ---- Container routing verification (best-effort) ---- diff --git a/robot/e2e/wf18_container_clone.robot b/robot/e2e/wf18_container_clone.robot index 601aff145..7a61fc14f 100644 --- a/robot/e2e/wf18_container_clone.robot +++ b/robot/e2e/wf18_container_clone.robot @@ -223,7 +223,7 @@ WF18 Container With Remote Repo Clone Trusted Profile # ---- Apply ---- ${r_apply}= Run CleverAgents Command - ... plan lifecycle-apply --yes ${plan_id} + ... plan apply --yes ${plan_id} ... --format plain ... timeout=120s Should Not Contain ${r_apply.stdout}${r_apply.stderr} Traceback @@ -252,7 +252,7 @@ WF18 Container With Remote Repo Clone Trusted Profile ${status_lower}= Evaluate ($r_status.stdout).lower() ${is_terminal}= Evaluate 'applied' in $status_lower or 'complete' in $status_lower or 'done' in $status_lower or 'finished' in $status_lower or 'apply' in $status_lower Should Be True ${is_terminal} - ... Plan status should indicate a terminal/applied state after lifecycle-apply + ... Plan status should indicate a terminal/applied state after apply # ---- Verify repo state after apply ---- ${post_log}= Run Process git log --oneline cwd=${repo} diff --git a/robot/helper_cli_formats.py b/robot/helper_cli_formats.py index 946e40d33..060f4968e 100644 --- a/robot/helper_cli_formats.py +++ b/robot/helper_cli_formats.py @@ -111,7 +111,7 @@ def plan_list_json() -> None: "cleveragents.cli.commands.plan._get_lifecycle_service", return_value=svc, ): - result = runner.invoke(plan_app, ["lifecycle-list", "--format", "json"]) + result = runner.invoke(plan_app, ["list", "--format", "json"]) assert result.exit_code == 0, f"exit={result.exit_code}: {result.output}" parsed = json.loads(result.output.strip()) assert isinstance(parsed, list) diff --git a/robot/helper_cli_lifecycle.py b/robot/helper_cli_lifecycle.py index 41f5437ff..c9c4730b4 100644 --- a/robot/helper_cli_lifecycle.py +++ b/robot/helper_cli_lifecycle.py @@ -248,7 +248,7 @@ def plan_apply_changeset() -> None: with patch( "cleveragents.cli.commands.plan._get_lifecycle_service", return_value=svc ): - result = runner.invoke(plan_app, ["lifecycle-apply", "--yes", _PLAN_ULID]) + result = runner.invoke(plan_app, ["apply", "--yes", _PLAN_ULID]) if result.exit_code != 0: _fail(f"plan apply rc={result.exit_code}\n{result.output}") @@ -309,7 +309,7 @@ def full_lifecycle() -> None: assert r2.exit_code == 0, f"plan use: {r2.output}" r3 = runner.invoke(plan_app, ["execute", _PLAN_ULID]) assert r3.exit_code == 0, f"plan execute: {r3.output}" - r4 = runner.invoke(plan_app, ["lifecycle-apply", "--yes", _PLAN_ULID]) + r4 = runner.invoke(plan_app, ["apply", "--yes", _PLAN_ULID]) assert r4.exit_code == 0, f"plan apply: {r4.output}" cs = store.get(cid) diff --git a/robot/helper_cli_lifecycle_e2e.py b/robot/helper_cli_lifecycle_e2e.py index d1aeb6d09..d3671cf10 100644 --- a/robot/helper_cli_lifecycle_e2e.py +++ b/robot/helper_cli_lifecycle_e2e.py @@ -181,7 +181,7 @@ def plan_execute() -> None: def plan_apply() -> None: - """Verify plan lifecycle-apply transitions to Apply phase.""" + """Verify plan apply transitions to Apply phase.""" mock_service = MagicMock() mock_service.apply_plan.return_value = _mock_plan( phase=PlanPhase.APPLY, state=ProcessingState.QUEUED @@ -191,7 +191,7 @@ def plan_apply() -> None: "cleveragents.cli.commands.plan._get_lifecycle_service", return_value=mock_service, ): - result = runner.invoke(plan_app, ["lifecycle-apply", "--yes", _PLAN_ULID]) + result = runner.invoke(plan_app, ["apply", "--yes", _PLAN_ULID]) if result.exit_code == 0: print("cli-lifecycle-plan-apply-ok") else: @@ -243,7 +243,7 @@ def plan_cancel() -> None: def plan_list() -> None: - """Verify lifecycle-list shows plan table.""" + """Verify list shows plan table.""" mock_service = MagicMock() mock_service.list_plans.return_value = [ _mock_plan(name="local/plan-a", plan_id="01KHDE6WWS2171PWW3GJEBXZ8A"), @@ -254,7 +254,7 @@ def plan_list() -> None: "cleveragents.cli.commands.plan._get_lifecycle_service", return_value=mock_service, ): - result = runner.invoke(plan_app, ["lifecycle-list"]) + result = runner.invoke(plan_app, ["list"]) if result.exit_code == 0: print("cli-lifecycle-plan-list-ok") else: @@ -310,7 +310,7 @@ def full_lifecycle() -> None: assert r3.exit_code == 0, f"plan execute failed: {r3.output}" # Step 4: Plan apply - r4 = runner.invoke(plan_app, ["lifecycle-apply", "--yes", _PLAN_ULID]) + r4 = runner.invoke(plan_app, ["apply", "--yes", _PLAN_ULID]) assert r4.exit_code == 0, f"plan apply failed: {r4.output}" print("cli-lifecycle-full-e2e-ok") diff --git a/robot/helper_m1_e2e_verification.py b/robot/helper_m1_e2e_verification.py index ad1f27f54..18ba91b8a 100644 --- a/robot/helper_m1_e2e_verification.py +++ b/robot/helper_m1_e2e_verification.py @@ -298,9 +298,9 @@ def plan_full_lifecycle() -> None: """Run the plan lifecycle via real CLI subprocesses. Invokes action create -> plan use -> plan show -> plan execute -> - plan diff -> plan lifecycle-apply using the real ``agents`` CLI + plan diff -> plan apply using the real ``agents`` CLI binary. Without an AI backend the plan stays in ``strategize / - queued``, so ``execute``, ``diff``, and ``lifecycle-apply`` + queued``, so ``execute``, ``diff``, and ``apply`` return graceful "not ready" messages rather than crashing. The test verifies the full CLI wiring (DI, persistence, env vars) end-to-end. ChangeSet verification uses the domain-level tests @@ -390,8 +390,8 @@ def plan_full_lifecycle() -> None: if "INTERNAL" in combined5 and not is_expected_provider_unavailable(combined5): _fail(f"plan diff crashed:\n{combined5}") - # Step 6: Plan lifecycle-apply — similar: plan not ready - r6 = run_cli("plan", "lifecycle-apply", "--yes", plan_id, workspace=workspace) + # Step 6: Plan apply — similar: plan not ready + r6 = run_cli("plan", "apply", "--yes", plan_id, workspace=workspace) combined6 = r6.stdout + r6.stderr if "Traceback" in combined6: _fail(f"plan apply crashed:\n{combined6}") diff --git a/robot/helper_m1_sourcecode_smoke.py b/robot/helper_m1_sourcecode_smoke.py index 206cd1456..1cb639021 100644 --- a/robot/helper_m1_sourcecode_smoke.py +++ b/robot/helper_m1_sourcecode_smoke.py @@ -200,7 +200,7 @@ def plan_apply() -> None: "cleveragents.cli.commands.plan._get_lifecycle_service", return_value=mock_svc, ): - result = runner.invoke(plan_app, ["lifecycle-apply", "--yes", _PLAN_ULID]) + result = runner.invoke(plan_app, ["apply", "--yes", _PLAN_ULID]) if result.exit_code == 0: print("m1-plan-apply-ok") else: @@ -260,7 +260,7 @@ def full_lifecycle() -> None: sys.exit(1) # Step 4: plan apply - r4 = runner.invoke(plan_app, ["lifecycle-apply", "--yes", _PLAN_ULID]) + r4 = runner.invoke(plan_app, ["apply", "--yes", _PLAN_ULID]) if r4.exit_code != 0: print(f"FAIL step 4: exit={r4.exit_code} output={r4.output}") sys.exit(1) diff --git a/robot/helper_m6_e2e_verification.py b/robot/helper_m6_e2e_verification.py index 1ed3cb4b4..e93915ff7 100644 --- a/robot/helper_m6_e2e_verification.py +++ b/robot/helper_m6_e2e_verification.py @@ -593,11 +593,11 @@ def porting_task_autonomous() -> None: def plan_apply_lifecycle() -> None: - """Verify ``agents plan lifecycle-apply`` via real CLI subprocess. + """Verify ``agents plan apply`` via real CLI subprocess. Creates an action and plan via subprocess, then runs - ``plan lifecycle-apply``. The plan is in strategize/queued - (not execute/complete) so lifecycle-apply correctly rejects + ``plan apply``. The plan is in strategize/queued + (not execute/complete) so apply correctly rejects with a controlled error message. """ workspace = setup_workspace(prefix="m6_apply_") @@ -621,12 +621,12 @@ def plan_apply_lifecycle() -> None: if not plan_id: _fail(f"could not extract plan_id:\n{r2.stdout}") - # lifecycle-apply on a strategize/queued plan — should get + # apply on a strategize/queued plan — should get # a controlled rejection, not a crash. - r3 = run_cli("plan", "lifecycle-apply", "--yes", plan_id, workspace=workspace) + r3 = run_cli("plan", "apply", "--yes", plan_id, workspace=workspace) combined = r3.stdout + r3.stderr if "INTERNAL" in combined or "Traceback" in combined: - _fail(f"lifecycle-apply crashed:\n{combined}") + _fail(f"apply crashed:\n{combined}") print("m6-plan-apply-lifecycle-ok") finally: diff --git a/robot/helper_plan_cli_spec.py b/robot/helper_plan_cli_spec.py index 6c17e4fe3..376f04f71 100644 --- a/robot/helper_plan_cli_spec.py +++ b/robot/helper_plan_cli_spec.py @@ -214,7 +214,7 @@ def use_actor_overrides() -> None: def list_filters() -> None: - """Verify lifecycle-list accepts filter flags.""" + """Verify list accepts filter flags.""" mock_service = MagicMock() mock_service.list_plans.return_value = [ _mock_plan(project_links=[ProjectLink(project_name="proj-a")]), @@ -223,12 +223,10 @@ def list_filters() -> None: "cleveragents.cli.commands.plan._get_lifecycle_service", return_value=mock_service, ): - r1 = runner.invoke(plan_app, ["lifecycle-list", "--phase", "strategize"]) - r2 = runner.invoke(plan_app, ["lifecycle-list", "--state", "queued"]) - r3 = runner.invoke(plan_app, ["lifecycle-list", "--project", "proj-a"]) - r4 = runner.invoke( - plan_app, ["lifecycle-list", "--action", "local/smoke-action"] - ) + r1 = runner.invoke(plan_app, ["list", "--phase", "strategize"]) + r2 = runner.invoke(plan_app, ["list", "--state", "queued"]) + r3 = runner.invoke(plan_app, ["list", "--project", "proj-a"]) + r4 = runner.invoke(plan_app, ["list", "--action", "local/smoke-action"]) if all(r.exit_code == 0 for r in [r1, r2, r3, r4]): print("plan-cli-list-filters-ok") else: diff --git a/robot/helper_tdd_plan_apply_yes_flag.py b/robot/helper_tdd_plan_apply_yes_flag.py index 9872f9a4e..fe58a027b 100644 --- a/robot/helper_tdd_plan_apply_yes_flag.py +++ b/robot/helper_tdd_plan_apply_yes_flag.py @@ -1,7 +1,7 @@ """Helper script for tdd_plan_apply_yes_flag.robot smoke tests. Each subcommand exercises the real CLI path (no mocks) to reproduce bug #932. -The ``lifecycle-apply`` command is invoked with ``--yes`` or ``-y`` to verify +The ``apply`` command is invoked with ``--yes`` or ``-y`` to verify that the flag is recognised by the CLI framework. The helper reports the **real** outcome: it exits 0 and prints the sentinel @@ -43,15 +43,15 @@ def _fail(message: str) -> NoReturn: def check_yes_long() -> None: - """Invoke ``lifecycle-apply --yes DUMMY`` and verify the flag is accepted. + """Invoke ``apply --yes DUMMY`` and verify the flag is accepted. Exits 0 with sentinel when ``--yes`` is recognised (bug fixed). Exits 1 when Typer rejects the flag (bug still present). """ - result = runner.invoke(plan_app, ["lifecycle-apply", "--yes", "DUMMY_PLAN_ID"]) + result = runner.invoke(plan_app, ["apply", "--yes", "DUMMY_PLAN_ID"]) if "No such option" in result.output or result.exit_code == 2: _fail( - f"lifecycle-apply rejected --yes flag.\n" + f"apply rejected --yes flag.\n" f"Exit code: {result.exit_code}\n" f"Output: {result.output}" ) @@ -59,15 +59,15 @@ def check_yes_long() -> None: def check_yes_short() -> None: - """Invoke ``lifecycle-apply -y DUMMY`` and verify the flag is accepted. + """Invoke ``apply -y DUMMY`` and verify the flag is accepted. Exits 0 with sentinel when ``-y`` is recognised (bug fixed). Exits 1 when Typer rejects the flag (bug still present). """ - result = runner.invoke(plan_app, ["lifecycle-apply", "-y", "DUMMY_PLAN_ID"]) + result = runner.invoke(plan_app, ["apply", "-y", "DUMMY_PLAN_ID"]) if "No such option" in result.output or result.exit_code == 2: _fail( - f"lifecycle-apply rejected -y flag.\n" + f"apply rejected -y flag.\n" f"Exit code: {result.exit_code}\n" f"Output: {result.output}" ) diff --git a/robot/m6_e2e_verification.robot b/robot/m6_e2e_verification.robot index 41e7e9255..a9f8ea0d2 100644 --- a/robot/m6_e2e_verification.robot +++ b/robot/m6_e2e_verification.robot @@ -83,7 +83,7 @@ Realistic Porting Task Completes Autonomously Should Contain ${result.stdout} m6-porting-task-autonomous-ok Plan Apply Via Lifecycle CLI - [Documentation] Verify ``agents plan lifecycle-apply`` transitions + [Documentation] Verify ``agents plan apply`` transitions ... the plan to APPLIED state via the lifecycle service. ${result}= Run Process ${PYTHON} ${HELPER} plan-apply-lifecycle cwd=${WORKSPACE} Log ${result.stdout} diff --git a/robot/plan_cli_spec.robot b/robot/plan_cli_spec.robot index c1a7c74ff..773a5d792 100644 --- a/robot/plan_cli_spec.robot +++ b/robot/plan_cli_spec.robot @@ -35,7 +35,7 @@ Plan Use Accepts Actor Override Flags Should Contain ${result.stdout} plan-cli-use-actors-ok Plan Lifecycle List Accepts Filter Flags - [Documentation] Verify that ``plan lifecycle-list`` accepts --phase, --state, --project, --action + [Documentation] Verify that ``plan list`` accepts --phase, --state, --project, --action ${result}= Run Process ${PYTHON} ${HELPER} list-filters cwd=${WORKSPACE} Should Be Equal As Integers ${result.rc} 0 Should Contain ${result.stdout} plan-cli-list-filters-ok diff --git a/robot/tdd_plan_apply_yes_flag.robot b/robot/tdd_plan_apply_yes_flag.robot index 3f20e9ff1..f77d0dc68 100644 --- a/robot/tdd_plan_apply_yes_flag.robot +++ b/robot/tdd_plan_apply_yes_flag.robot @@ -1,6 +1,6 @@ *** Settings *** -Documentation TDD Issue #932 — plan lifecycle-apply missing --yes flag -... Integration smoke tests verifying that the lifecycle-apply +Documentation TDD Issue #932 — plan apply missing --yes flag +... Integration smoke tests verifying that the apply ... command accepts the --yes / -y flag required by the ... specification. The spec mandates ... ``agents plan apply [--yes|-y] `` to skip the @@ -14,7 +14,7 @@ ${HELPER} ${CURDIR}/helper_tdd_plan_apply_yes_flag.py *** Test Cases *** TDD Plan Apply Yes Long Flag Via CLI - [Documentation] Verify that ``lifecycle-apply --yes`` is recognised + [Documentation] Verify that ``apply --yes`` is recognised [Tags] tdd_issue tdd_issue_932 ${result}= Run Process ${PYTHON} ${HELPER} check-yes-long cwd=${WORKSPACE} timeout=120s on_timeout=kill Log ${result.stdout} @@ -23,7 +23,7 @@ TDD Plan Apply Yes Long Flag Via CLI Should Contain ${result.stdout} tdd-plan-apply-yes-flag-long-ok TDD Plan Apply Yes Short Flag Via CLI - [Documentation] Verify that ``lifecycle-apply -y`` is recognised + [Documentation] Verify that ``apply -y`` is recognised [Tags] tdd_issue tdd_issue_932 ${result}= Run Process ${PYTHON} ${HELPER} check-yes-short cwd=${WORKSPACE} timeout=120s on_timeout=kill Log ${result.stdout} diff --git a/src/cleveragents/cli/commands/plan.py b/src/cleveragents/cli/commands/plan.py index 97ff2bfd9..23b371378 100644 --- a/src/cleveragents/cli/commands/plan.py +++ b/src/cleveragents/cli/commands/plan.py @@ -8,25 +8,14 @@ plan lifecycle. | Command | Description | |-------------------------------|-----------------------------------------| | ``agents plan use`` | Create plan from action + project(s) | -| ``agents plan lifecycle-list``| List plans with optional filters | +| ``agents plan list`` | List plans with optional filters | | ``agents plan status`` | Show plan status / details | | ``agents plan execute`` | Run phase-aware plan execution | -| ``agents plan lifecycle-apply``| Transition to Apply phase | +| ``agents plan apply`` | Transition to Apply phase | | ``agents plan cancel`` | Cancel a non-terminal plan | | ``agents plan diff`` | Show ChangeSet as unified diff | | ``agents plan artifacts`` | Show ChangeSet ID, sandbox refs, summary| | ``agents plan errors`` | Show error decisions + recovery hints | - -## Deprecated Legacy Commands - -| Legacy Command | Replacement | -|--------------------|------------------------------------------| -| ``plan tell`` | ``plan use [project]`` | -| ``plan build`` | ``plan execute [plan_id]`` | -| ``plan apply`` | ``plan lifecycle-apply [plan_id]`` | -| ``plan new`` | ``plan use [project]`` | -| ``plan current`` | ``plan status [plan_id]`` | -| ``plan list`` | ``plan lifecycle-list`` | """ from __future__ import annotations @@ -793,117 +782,6 @@ def build( raise typer.Abort() from e -@app.command() -def apply( - plan_id: Annotated[ - str | None, - typer.Argument(help="Plan ID to apply (v3 lifecycle). Omit for legacy mode."), - ] = None, - yes: Annotated[bool, typer.Option("--yes", "-y", help="Skip confirmation")] = False, - fmt: Annotated[ - str, - typer.Option( - "--format", - "-f", - help=_FORMAT_HELP, - ), - ] = "rich", -) -> None: - """Apply plan changes. - - When a *plan_id* is given, uses the v3 lifecycle: transitions the - plan through Apply/queued -> Apply/processing -> Apply/applied. - - When no *plan_id* is given, falls back to the legacy workflow that - writes AI-generated file changes for the current project. - """ - if plan_id is not None: - # ── v3 lifecycle apply ────────────────────────────────── - _lifecycle_apply_with_id(plan_id, fmt) - return - - # ── Legacy apply path (no plan_id) ────────────────────────── - import os - - from cleveragents.application.container import get_container - from cleveragents.application.services.plan_service import PlanService - - console.print( - "[yellow]Warning:[/yellow] 'apply' without a plan ID is a legacy command. " - "Use 'agents plan apply ' for the v3 lifecycle." - ) - - try: - container = get_container() - plan_service: PlanService = container.plan_service() - - # Get current project - project = _get_current_project() - - # Get pending changes - changes = plan_service.get_pending_changes(project=project) - - if not changes: - console.print("[yellow]No changes to apply.[/yellow]") - console.print("Run 'agents build' first to generate changes.") - raise typer.Exit(0) - - # Check if we're in testing mode - is_testing = os.environ.get("CLEVERAGENTS_TESTING_USE_MOCK_AI", "").lower() in ( - "true", - "yes", - "1", - ) - - # Check if we should force confirmation prompt (for testing cancellation) - force_confirmation = os.environ.get( - "CLEVERAGENTS_TEST_FORCE_CONFIRMATION", "" - ).lower() in ( - "true", - "yes", - "1", - ) - - # Show changes and confirm. - # Skip confirmation when testing or using -y unless force_confirmation is set. - if not yes and (not is_testing or force_confirmation): - console.print("\n[bold]Changes to apply:[/bold]") - for change in changes[:10]: - op_color = { - "create": "green", - "modify": "yellow", - "delete": "red", - }.get(change.operation, "white") - console.print( - f" [{op_color}]{change.operation}[/{op_color}] {change.file_path}" - ) - if len(changes) > 10: - console.print(f" ... and {len(changes) - 10} more changes") - - confirm = typer.confirm("\nApply these changes?") - if not confirm: - console.print("[yellow]Cancelled.[/yellow]") - raise typer.Exit(0) - - # Apply changes - with Progress( - SpinnerColumn(), - TextColumn("[progress.description]{task.description}"), - console=console, - ) as progress: - progress.add_task("Applying changes...", total=None) - applied = plan_service.apply_changes(project=project) - - console.print(f"[green]✓[/green] Successfully applied {applied} change(s).") - - except PlanError as e: - console.print(f"[red]Apply Error:[/red] {e.message}") - raise typer.Abort() from e - except CleverAgentsError as e: - console.print(f"[red]Error:[/red] {e.message}") - raise typer.Abort() from e - - def _lifecycle_apply_with_id(plan_id: str, fmt: str = "rich") -> None: """Run the v3 lifecycle apply for a specific plan. @@ -1079,83 +957,6 @@ def current() -> None: raise typer.Abort() from e -@app.command("list") -def list_plans( - fmt: Annotated[ - str, - typer.Option( - "--format", - "-f", - help=_FORMAT_HELP, - ), - ] = "rich", -) -> None: - """List all plans in the current project. - - .. deprecated:: - Use ``agents plan lifecycle-list`` for the v3 lifecycle. - """ - from cleveragents.application.container import get_container - from cleveragents.application.services.plan_service import PlanService - - console.print( - "[yellow]Warning:[/yellow] 'list' is a legacy command. " - "Use 'agents plan lifecycle-list' for the v3 lifecycle." - ) - - try: - container = get_container() - plan_service: PlanService = container.plan_service() - - # Get current project - project = _get_current_project() - - # Get all plans - plans = plan_service.list_plans(project=project) - - if not plans: - console.print("[yellow]No plans found.[/yellow]") - console.print( - "Create one with 'agents new ' or 'agents tell '." - ) - return - - # Non-rich formats - if fmt != OutputFormat.RICH.value: - data = [ - { - "plan_id": getattr(plan, "id", ""), - "namespaced_name": plan.name, - "phase": getattr(plan, "status", ""), - "processing_state": getattr(plan, "status", ""), - } - for plan in plans - ] - console.print(format_output(data, fmt)) - return - - # Display plans table - table = Table(title=f"Plans ({len(plans)} total)") - table.add_column("Name", style="cyan") - table.add_column("Status", style="yellow") - table.add_column("Created", style="green") - table.add_column("Current", style="magenta") - - for plan in plans: - table.add_row( - plan.name, - plan.status, - str(plan.created_at), - "✓" if plan.current else "", - ) - - console.print(table) - - except CleverAgentsError as e: - console.print(f"[red]Error:[/red] {e.message}") - raise typer.Abort() from e - - @app.command() def cd( name: Annotated[ @@ -2001,7 +1802,7 @@ def execute_plan( # Run the execute phase inline so the plan progresses through # execute/queued → execute/processing → execute/complete in a # single CLI invocation. Without this, `plan execute` would - # leave the plan in execute/queued and `lifecycle-apply` would + # leave the plan in execute/queued and `apply` would # fail because it requires execute/complete. current_plan = service.get_plan(plan_id) if ( @@ -2027,7 +1828,7 @@ def execute_plan( ): console.print( f"\n[dim]Plan execution completed ({phase_label}). " - "Run 'agents plan lifecycle-apply ' when ready.[/dim]" + "Run 'agents plan apply ' when ready.[/dim]" ) else: console.print( @@ -2058,7 +1859,7 @@ def execute_plan( raise typer.Abort() from e -@app.command("lifecycle-apply") +@app.command("apply") def lifecycle_apply_plan( plan_id: Annotated[ str | None, @@ -2121,8 +1922,13 @@ def lifecycle_apply_plan( raise typer.Abort() plan_id = eligible_plans[0].identity.plan_id - # Fail-fast: read-only plans must not enter Apply phase + # Fail-fast: plan must exist pre_plan = service.get_plan(plan_id) + if pre_plan is None: + console.print(f"[red]Plan '{plan_id}' not found.[/red]") + raise typer.Abort() + + # Fail-fast: read-only plans must not enter Apply phase if pre_plan.read_only is True: console.print( f"[red]Cannot apply plan '{plan_id}': plan is read-only.[/red]" @@ -2150,7 +1956,7 @@ def lifecycle_apply_plan( # Apply phase is a metadata transition (no LLM call). When the # plan is in Apply/queued, complete it to the terminal ``applied`` # state. This intentionally bypasses the automation profile's - # ``auto_apply`` threshold: explicitly running ``lifecycle-apply`` + # ``auto_apply`` threshold: explicitly running ``apply`` # IS the human approval action for the manual profile. plan = service.get_plan(plan_id) if ( @@ -2163,7 +1969,8 @@ def lifecycle_apply_plan( data = _plan_spec_dict(plan) console.print(format_output(data, fmt)) else: - _print_lifecycle_plan(plan, title="Plan Applying") + title = "Plan Applied" if plan.is_terminal else "Plan Applying" + _print_lifecycle_plan(plan, title=title) if plan.is_terminal: console.print( f"\n[dim]Plan completed in Apply phase with state: " @@ -2403,7 +2210,7 @@ def plan_errors( raise typer.Abort() from e -@app.command("lifecycle-list") +@app.command("list") def lifecycle_list_plans( regex: Annotated[ str | None, diff --git a/src/cleveragents/cli/main.py b/src/cleveragents/cli/main.py index a81720cbe..6c30efc53 100644 --- a/src/cleveragents/cli/main.py +++ b/src/cleveragents/cli/main.py @@ -521,12 +521,16 @@ def build( @app.command() def apply( + plan_id: Annotated[ + str | None, + typer.Argument(help="Plan ID to apply"), + ] = None, yes: Annotated[bool, typer.Option("--yes", "-y", help="Skip confirmation")] = False, ) -> None: """Apply plan changes (shortcut for 'plan apply').""" - from cleveragents.cli.commands.plan import apply as plan_apply + from cleveragents.cli.commands.plan import lifecycle_apply_plan - plan_apply(yes=yes) # Pass yes parameter directly + lifecycle_apply_plan(plan_id=plan_id, yes=yes) @app.command("context-load")