Feature: plan apply --format json returns spec-required JSON envelope As a programmatic consumer of the CleverAgents CLI I want ``agents plan apply --format json`` to return a spec-compliant JSON envelope So that tooling and scripts can reliably parse the apply output Background: Given a plan CLI runner for the apply JSON envelope test # ── Envelope field presence ────────────────────────────────────────────── Scenario: apply JSON output includes all required top-level envelope fields When I invoke plan apply with --format json and a mocked service Then the apply JSON envelope should contain field "command" And the apply JSON envelope should contain field "status" And the apply JSON envelope should contain field "exit_code" And the apply JSON envelope should contain field "data" And the apply JSON envelope should contain field "timing" And the apply JSON envelope should contain field "messages" Scenario: apply JSON envelope command field is "plan apply" When I invoke plan apply with --format json and a mocked service Then the apply JSON envelope command should be "plan apply" Scenario: apply JSON envelope status field is "ok" When I invoke plan apply with --format json and a mocked service Then the apply JSON envelope status should be "ok" Scenario: apply JSON envelope exit_code field is 0 When I invoke plan apply with --format json and a mocked service Then the apply JSON envelope exit_code should be 0 Scenario: apply JSON envelope messages is a non-empty list When I invoke plan apply with --format json and a mocked service Then the apply JSON envelope messages should be a non-empty list # ── Data field structure ───────────────────────────────────────────────── Scenario: apply JSON envelope data field contains required sub-fields When I invoke plan apply with --format json and a mocked service Then the apply JSON data should contain field "artifacts" And the apply JSON data should contain field "changes" And the apply JSON data should contain field "project" And the apply JSON data should contain field "applied_at" And the apply JSON data should contain field "validation" And the apply JSON data should contain field "sandbox_cleanup" And the apply JSON data should contain field "lifecycle" Scenario: apply JSON data validation field contains test lint and type_check When I invoke plan apply with --format json and a mocked service Then the apply JSON data validation should contain field "tests" And the apply JSON data validation should contain field "lint" And the apply JSON data validation should contain field "type_check" Scenario: apply JSON data lifecycle field contains required sub-fields When I invoke plan apply with --format json and a mocked service Then the apply JSON data lifecycle should contain field "phase" And the apply JSON data lifecycle should contain field "state" And the apply JSON data lifecycle should contain field "total_duration" And the apply JSON data lifecycle should contain field "total_cost" And the apply JSON data lifecycle should contain field "decisions_made" And the apply JSON data lifecycle should contain field "child_plans" Scenario: apply JSON data sandbox_cleanup field contains worktree branch checkpoint When I invoke plan apply with --format json and a mocked service Then the apply JSON data sandbox_cleanup should contain field "worktree" And the apply JSON data sandbox_cleanup should contain field "branch" And the apply JSON data sandbox_cleanup should contain field "checkpoint" # ── sandbox_cleanup derives from actual plan state ─────────────────────── Scenario: sandbox_cleanup shows removed state for terminal apply plan When I invoke plan apply with --format json and a terminal apply plan Then the apply JSON data sandbox_cleanup worktree should be "removed" And the apply JSON data sandbox_cleanup branch should be "merged to main" And the apply JSON data sandbox_cleanup checkpoint should be "archived" Scenario: sandbox_cleanup shows active state for non-terminal plan When I invoke plan apply with --format json and a non-terminal plan Then the apply JSON data sandbox_cleanup worktree should be "active" And the apply JSON data sandbox_cleanup branch should be "open" And the apply JSON data sandbox_cleanup checkpoint should be "pending" # ── Command isolation ──────────────────────────────────────────────────── Scenario: plan status --format json does not emit plan apply command field When I invoke plan status with --format json and a mocked service Then the plan status JSON output should not have command "plan apply" Scenario: plan cancel --format json does not emit plan apply command field When I invoke plan cancel with --format json and a mocked service Then the plan cancel JSON output should not have command "plan apply" # ── Legacy plan fallback ───────────────────────────────────────────────── Scenario: apply JSON envelope handles legacy plan object gracefully When I invoke the apply output dict with a legacy plan object Then the legacy apply JSON envelope command should be "plan apply" And the legacy apply JSON envelope data should contain field "plan" # ── total_cost from cost_metadata ──────────────────────────────────────── Scenario: apply JSON data lifecycle total_cost reflects plan cost_metadata When I invoke plan apply with --format json and a plan with cost metadata Then the apply JSON data lifecycle total_cost should start with "$"