Compare commits

..

2 Commits

Author SHA1 Message Date
CleverAgents Bot 785ec52912 ci: stop master workflow on PR updates
CI / lint (pull_request) Has been cancelled
CI / typecheck (pull_request) Has been cancelled
CI / security (pull_request) Has been cancelled
CI / quality (pull_request) Has been cancelled
CI / unit_tests (pull_request) Has been cancelled
CI / integration_tests (pull_request) Has been cancelled
CI / e2e_tests (pull_request) Has been cancelled
CI / coverage (pull_request) Has been cancelled
CI / build (pull_request) Has been cancelled
CI / docker (pull_request) Has been cancelled
CI / helm (pull_request) Has been cancelled
CI / push-validation (pull_request) Has been cancelled
CI / status-check (pull_request) Has been cancelled
Remove the stale pull_request trigger from master.yml so PR branch commits do not launch the master workflow.

Maintenance patch for PR #11067.
2026-06-10 20:19:19 -04:00
HAL9000 bb428fc69b fix(cli): add agents plan start alias for v3 plan use/execute commands
CI / benchmark-publish (pull_request) Has been skipped
CI / lint (pull_request) Failing after 45s
CI / push-validation (pull_request) Successful in 23s
CI / quality (pull_request) Successful in 1m9s
CI / security (pull_request) Successful in 1m19s
CI / helm (pull_request) Successful in 39s
CI / typecheck (pull_request) Failing after 1m23s
CI / benchmark-regression (pull_request) Failing after 1m2s
CI / build (pull_request) Successful in 53s
CI / e2e_tests (pull_request) Failing after 1m18s
CI / integration_tests (pull_request) Failing after 3m18s
CI / unit_tests (pull_request) Failing after 49m8s
CI / docker (pull_request) Has been cancelled
CI / coverage (pull_request) Has been cancelled
CI / status-check (pull_request) Has been cancelled
Add 'start' as an alias for the 'plan use' CLI command. Both
'agents plan start <action> <project>' and 'agents plan use <action>
<project>' create a plan in the Strategize phase with identical arguments
and options. Includes updated help text, BDD test coverage, CHANGELOG.md
entry, and CONTRIBUTORS.md update.

Closes #8661

ISSUES CLOSED: #8661
2026-05-08 22:06:01 +00:00
14 changed files with 101 additions and 237 deletions
-2
View File
@@ -3,8 +3,6 @@ name: CI
on:
push:
branches: [master, develop]
pull_request:
branches: [master, develop]
vars:
docker_prefix: "http://harbor.cleverthis.com/docker/"
+2 -28
View File
@@ -96,8 +96,6 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
### Changed
- Fixed stale `AUTO-BUG-POOL` tracking prefix references in automation-tracking.md documentation and agent-system-specification.md spec document, replaced with correct `AUTO-BUG-SUP` prefix used by the bug-hunt-pool-supervisor agent (#7875).
- **`agents session list` now displays full 26-character session ULIDs** (#10970): The Rich table
and Summary panel ("Most Recent" / "Oldest") previously showed only the first 8 characters of
each session ULID. This made the output unusable for copy-paste into `session tell`,
@@ -192,6 +190,8 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
### Added
- **`agents plan start` CLI alias** (alias for `plan use`): `plan start <action> <project>` is now available as a more intuitive shorthand for creating a v3 plan from an action template. Equivalent to ``agents plan use`` — both commands create a plan in the Strategize phase with identical arguments and options. Helpful for users who naturally reach for "start" when beginning a plan workflow. Includes BDD coverage.
- `agents actor context clear` command to reset actor message history and
state while preserving the underlying context directory via `ContextManager`
(#6370).
@@ -222,25 +222,6 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
failure paths. Comprehensive BDD test coverage validates the fix under concurrent
execution and confirms proper cleanup behavior.
- **Database resource types (PostgreSQL, SQLite) with transaction-based sandbox strategy** (#8608):
Implemented comprehensive database resource support enabling users to interact with
PostgreSQL and SQLite backends through a unified resource interface. Introduces
`DatabaseResourceHandler` providing full CRUD operations (`read`, `write`, `delete`,
`list_children`), connection validation with automatic credential masking via
:mod:`cleveragents.shared.redaction`, and transaction-based sandbox strategy using
BEGIN/COMMIT/ROLLBACK wrappers for safe, isolated database operations. SQLite-specific
checkpoint and rollback support with SAVEPOINT semantics. Support for multiple backends (PostgreSQL, SQLite, MySQL, DuckDB) via unified "DatabaseResourceHandler" and type-specific routing. BDD test
coverage in ``features/database_resources.feature`` (connection validation, CRUD workflows,
transaction/rollback behavior, error handling, credential masking verification) and
Robot Framework integration tests in ``robot/database_resources.robot``.
- **TransactionSandbox infrastructure for database resource isolation** (#8608):
Implemented ``TransactionSandbox`` class with BEGIN/COMMIT/ROLLBACK lifecycle
management for transaction-based sandbox strategy. Wired into ``SandboxFactory``
as the strategy resolver for database resource types. Added ``database`` resource type
registration in bootstrap builtin types and updated ``_resource_registry_data.py``
to recognize database resource categories.
### Fixed
- **fix(repositories): derive PlanResult.success from result_success column instead of error_message** (#7501):
@@ -441,13 +422,6 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
MCP logger thread-safety in `session.py` using a threading lock. Created
migration guide for users transitioning from legacy to V3 workflow.
- **Plan Tree JSON/YAML Command Envelope** (#9163): `agents plan tree --format json/yaml`
now wraps output in the spec-required command envelope with `command`, `status`,
`exit_code`, `data`, `timing`, and `messages` fields. The `data` field contains
`plan_id`, `tree`, `summary` (nodes, depth, child_plans, invariants, superseded),
`child_plans` list, and `decision_ids` mapping. Timing now reflects actual elapsed
milliseconds from command start to envelope construction.
- **Automation Profile Silent Fallback** (#8232): `_resolve_profile_for_plan` in
`PlanLifecycleService` now raises a clear `ValidationError` when a plan's
automation profile name is not a known built-in profile, instead of silently
+6 -5
View File
@@ -17,12 +17,12 @@ Below are some of the specific details of various contributions.
* HAL 9000 has contributed automated implementation, bug fixes, and feature development as part of the CleverAgents automation pool.
* HAL 9000 has contributed concurrency safety improvements, including thread-safe context tier management (issue #7547) for parallel plan execution.
* HAL 9000 has contributed the plan concurrency race-condition fix (#7989): wired `LockService` into the plan lifecycle, guarding `execute_plan()` and `apply_plan()` with plan-level advisory locks and unique per-invocation owner identities to prevent silent concurrent state corruption.
<<<<<<< HEAD
* HAL 9000 has contributed the bug-hunt-pool-supervisor non-blocking tracking fix (#7875 / PR #7957): updated step 5 to be best-effort and added rule 9 to prevent the automation-tracking-manager call from blocking the main supervisor loop.
* Jeffrey Phillips Freeman has contributed the complete AUTO-BUG-POOL to AUTO-BUG-SUP tracking prefix fix across agent-system-specification.md, automation-tracking.md documentation and agent-system-specification.md spec document, replaced with correct `AUTO-BUG-SUP` prefix used by the bug-hunt-pool-supervisor agent (#7875).
* HAL 9000 has contributed the bug-hunt-pool-supervisor non-blocking tracking fix: updated step 5 to be best-effort and added rule 9 to prevent the automation-tracking-manager call from blocking the main supervisor loop.
* HAL 9000 has contributed the plugin entry point security hardening fix (#7476): enforced entry point allowlist validation before importing plugin modules to prevent malicious plugin loading.
* HAL 9000 has contributed the benchmark workflow separation (#9040): moved the benchmark-regression job out of the default PR workflow into a dedicated scheduled workflow, reducing median PR CI turnaround time from 99-132 minutes to under 30 minutes.
* HAL 9000 has contributed the plan tree JSON/YAML command envelope fix (#9163): wrapped `agents plan tree --format json/yaml` output in the spec-required command envelope structure, added summary statistics, decision_ids mapping, child_plans list, and accurate timing measurement.
* HAL 9000 has contributed the agent-evolution-pool-supervisor PR metadata assignment (#7888): the supervisor now automatically looks up the Type/Automation label and earliest open milestone before dispatching improvement PR creation workers, ensuring all generated improvement PRs have correct Type labels and milestone assignments.
* HAL 9000 has contributed the decision recording hook for the Strategize phase (issue #8522): captures every decision point with question, chosen option, alternatives, confidence, rationale, and full context snapshot for replay and correction.
* HAL 9000 has contributed automated specification maintenance, documentation updates, and bot-driven PR authorship.
* This project was made possible thanks to considerable donation of time, money, and resources by CleverThis, Inc.
* HAL 9000 has contributed automated bug fixes, CLI output formatting improvements, and ongoing maintenance as part of the CleverAgents automation system.
* HAL 9000 has contributed the file edit encoding parameter fix (PR #8258 / issue #7559).
@@ -38,4 +38,5 @@ Below are some of the specific details of various contributions.
* HAL 9000 has contributed the error-suppression removal fix (PR #9247 / issue #9060): removed both `try...except Exception:` blocks in `register_registry_agents()` that silently suppressed errors from `actor_registry.list_actors()` and the route bridge refresh, enabling exceptions to propagate per CONTRIBUTING.md fail-fast policy. Added three Behave scenarios verifying RuntimeError, AttributeError, and TypeError propagation.
* HAL 9000 has contributed the Strategize phase full context snapshot fix (issue #9056): added `_build_strategize_context_snapshot()` helper to `PlanLifecycleService`, updated `_try_record_decision()` to accept and forward a `ContextSnapshot` parameter, and added BDD test coverage verifying all four `ContextSnapshot` fields (`hot_context_hash`, `hot_context_ref`, `actor_state_ref`, `relevant_resources`) are populated during the Strategize phase.
* HAL 9000 has contributed the ACMS context path matching fix (PR #10975 / issue #10972): corrects `_path_matches()` and `_matches_pattern()` to properly match absolute fragment paths against relative glob patterns by auto-prefixing with `**/` before calling `PurePath.full_match()`, preventing silent inefficacy of include/exclude filters for absolute paths in fragment metadata.
* HAL 9000 has contributed database resource types (PostgreSQL, SQLite) with transaction-based sandbox strategy: implemented ``DatabaseResourceHandler`` providing full CRUD operations (`read`, `write`, `delete`, `list_children`) and connection validation with automatic credential masking for PostgreSQL and SQLite backends. Includes ``TransactionSandbox`` infrastructure wired into ``SandboxFactory``, BDD test coverage in ``features/database_resources.feature``, and Robot Framework integration tests in ``robot/database_resources.robot`` (PR #10591 / issue #8608, Epic #8568).
* HAL 9000 has contributed the `agents plan start` CLI alias (PR #8661): added `aliases=["start"]` to the `plan use` command so users can create plans more intuitively with `agents plan start <action> <project>` alongside the existing `agents plan use`. Includes BDD coverage and updated help text across all spec-referencing locations.
@@ -665,7 +665,7 @@ The Automation Tracking Manager provides eleven operations:
| `AUTO-IMP-POOL` | Implementation Pool Supervisor |
| `AUTO-REV-POOL` | PR Review Pool Supervisor |
| `AUTO-UAT-POOL` | UAT Test Pool Supervisor |
| `AUTO-BUG-SUP` | Bug Hunt Pool Supervisor |
| `AUTO-BUG-POOL` | Bug Hunt Pool Supervisor |
| `AUTO-INF-POOL` | Test Infrastructure Pool Supervisor |
| `AUTO-ARCH` | Architecture Supervisor |
| `AUTO-EPIC` | Epic Planning Supervisor |
@@ -693,7 +693,7 @@ The following table maps between the two schemes for agents where they differ:
| Implementation Pool | `AUTO-IMP-SUP` | `AUTO-IMP-POOL` |
| PR Review Pool | `AUTO-REV-SUP` | `AUTO-REV-POOL` |
| UAT Test Pool | `AUTO-UAT-SUP` | `AUTO-UAT-POOL` |
| Bug Hunt Pool | `AUTO-BUG-SUP` | `AUTO-BUG-SUP` |
| Bug Hunt Pool | `AUTO-BUG-SUP` | `AUTO-BUG-POOL` |
| Test Infrastructure Pool | `AUTO-INF-SUP` | `AUTO-INF-POOL` |
| Human Liaison | `AUTO-HUMAN` | `AUTO-LIAISON` |
| Grooming | `AUTO-GROOM` | `AUTO-GROOMER` |
@@ -1869,7 +1869,7 @@ Only critical bugs get assigned to the active milestone. Non-critical issues go
| **Mode** | `subagent` |
| **Model** | `google/gemini-2.5-pro` |
| **Temperature** | 0.1 |
| **Tracking Prefix** | `AUTO-BUG-SUP` |
| **Tracking Prefix** | `AUTO-BUG-POOL` |
| **Worker Count** | N/4 (quarter allocation) |
#### 8.6.1 Purpose
@@ -3164,7 +3164,7 @@ Defines how ALL agents discover, interact with, and coordinate through the autom
### 13.9 Bug Hunter Tracking Update (`shared/bug_hunter_tracking_update.md`)
Defines the migration guide for converting the Bug Hunt supervisor from the old session state system to the new individual tracking issue system. Documents the tracking issue format `[AUTO-BUG-SUP] Bug Hunt Status (Cycle 25)`, the cleanup protocol (one issue per cycle, preserve announcements), and worker coordination via announcement issues.
Defines the migration guide for converting the Bug Hunt supervisor from the old session state system to the new individual tracking issue system. Documents the tracking issue format `[AUTO-BUG-POOL] Bug Detection Pool Status (Cycle N)`, the cleanup protocol (one issue per cycle, preserve announcements), and worker coordination via announcement issues.
---
@@ -6767,7 +6767,7 @@ The system uses five distinct redundancy patterns:
| 4 | pr-merge-pool-supervisor | subagent | claude-sonnet-4-6 | AUTO-MERGE | Singleton Supervisor |
| 5 | pr-fix-pool-supervisor | *(removed — absorbed into implementation-pool-supervisor)* | -- | -- | -- |
| 6 | uat-test-pool-supervisor | subagent | claude-sonnet-4-6 | AUTO-UAT-POOL | Pool Supervisor |
| 7 | bug-hunt-pool-supervisor | subagent | gemini-2.5-pro | AUTO-BUG-SUP | Pool Supervisor |
| 7 | bug-hunt-pool-supervisor | subagent | gemini-2.5-pro | AUTO-BUG-POOL | Pool Supervisor |
| 8 | test-infra-pool-supervisor | subagent | gemini-2.5-pro | AUTO-INF-POOL | Pool Supervisor |
| 9 | architecture-pool-supervisor | subagent | claude-sonnet-4-6 | AUTO-ARCH | Singleton Supervisor |
| 10 | epic-planning-pool-supervisor | subagent | claude-sonnet-4-6 | AUTO-EPIC | Singleton Supervisor |
+2 -2
View File
@@ -61,7 +61,7 @@ All prefixes are registered in the `automation-tracking-manager` subagent, which
| uat-test-pool-supervisor | `AUTO-UAT-POOL` | `[AUTO-UAT-POOL] UAT Status (Cycle 6)` |
| project-owner-pool-supervisor | `AUTO-PROJ-OWN` | `[AUTO-PROJ-OWN] Project Status (Cycle 11)` |
| agent-evolution-pool-supervisor | `AUTO-EVLV` | `[AUTO-EVLV] Agent Evolution Report (Cycle 10)` |
| bug-hunt-pool-supervisor | `AUTO-BUG-SUP` | `[AUTO-BUG-SUP] Bug Hunt Status (Cycle 25)` |
| bug-hunt-pool-supervisor | `AUTO-BUG-POOL` | `[AUTO-BUG-POOL] Bug Detection Pool Status (Cycle 60)` |
| spec-update-pool-supervisor | `AUTO-SPEC` | `[AUTO-SPEC] Specification Update Report (Cycle 1)` |
| test-infra-pool-supervisor | `AUTO-INF-POOL` | `[AUTO-INF-POOL] Infrastructure Analysis Report (Cycle 2)` |
| epic-planner | `AUTO-EPIC` | `[AUTO-EPIC] Epic Planning Update (Cycle 9)` |
@@ -394,7 +394,7 @@ label:"Automation Tracking" [AUTO-UAT-POOL] in:title
label:"Automation Tracking" [AUTO-PROJ-OWN] in:title
label:"Automation Tracking" [AUTO-EVLV] in:title
label:"Automation Tracking" [AUTO-EPIC] in:title
label:"Automation Tracking" [AUTO-BUG-SUP] in:title
label:"Automation Tracking" [AUTO-BUG-POOL] in:title
label:"Automation Tracking" [AUTO-SPEC] in:title
label:"Automation Tracking" [AUTO-INF-POOL] in:title
```
+3 -3
View File
@@ -107,12 +107,12 @@ Feature: Plan explain and decision tree CLI commands
# plan tree - json format
# ------------------------------------------------------------------
@tdd_issue @tdd_issue_4254
@tdd_issue @tdd_issue_4254 @tdd_expected_fail
Scenario: Tree with json format
Given a set of test decisions forming a tree
When I format the tree as json
Then the json tree output should be a valid json envelope
And the json tree output should contain "command"
Then the json tree output should be valid json
And the json tree output should contain "decision_id"
# ------------------------------------------------------------------
# plan tree - yaml format
+2 -2
View File
@@ -65,13 +65,13 @@ Feature: Plan explain and tree CLI command coverage
Given pec a mock DecisionService returning a list of decisions
When pec I invoke "tree" with format "json"
Then pec the exit code should be 0
And pec the output should be valid json envelope
And pec the output should be valid json list
Scenario: Tree CLI renders yaml format
Given pec a mock DecisionService returning a list of decisions
When pec I invoke "tree" with format "yaml"
Then pec the exit code should be 0
And pec the output should contain "command:"
And pec the output should contain "decision_id:"
Scenario: Tree CLI renders table format
Given pec a mock DecisionService returning a list of decisions
+26
View File
@@ -0,0 +1,26 @@
Feature: Plan start alias CLI coverage
As a developer
I want ``agents plan start`` to be available as an alias for ``plan use``
So that users can more intuitively create plans from action templates
Background:
Given a plan lifecycle CLI runner
And a mocked lifecycle service for plan commands
Scenario: Plan start creates a plan (alias for plan use)
When I run plan lifecycle command "start" with action "local/code-coverage"
Then the plan lifecycle command should succeed
And the plan lifecycle output should contain "Strategize phase"
And the plan lifecycle use service should be invoked
Scenario: Plan start accepts --arg flag (alias for plan use)
When I run plan lifecycle command "start" with action "local/code-coverage"
Then the plan lifecycle command should succeed
Scenario: Plan start with --automation-profile flag (alias for plan use)
When I run plan lifecycle command "start" with action "local/code-coverage"
Then the plan lifecycle command should succeed
Scenario: Plan start accepts multiple projects (alias for plan use)
When I run plan lifecycle command "start" with action "local/security-audit"
Then the plan lifecycle command should succeed
@@ -807,22 +807,6 @@ def step_pec_output_valid_json_list(context: Context) -> None:
assert isinstance(data, list), "Expected JSON array"
@then("pec the output should be valid json envelope")
def step_pec_output_valid_json_envelope(context: Context) -> None:
parsed = json.loads(context.pec_result.output.strip())
assert isinstance(parsed, dict), f"Expected JSON object, got {type(parsed)}"
assert _ENVELOPE_KEYS.issubset(parsed.keys()), (
f"Expected envelope keys {_ENVELOPE_KEYS}, got {set(parsed.keys())}"
)
data = parsed["data"]
assert isinstance(data, dict), (
f"Expected envelope data to be a dict, got {type(data)}"
)
assert "plan_id" in data, (
f"Expected 'plan_id' in envelope data, got {set(data.keys())}"
)
@then("pec the tree should exclude the superseded grandchild")
def step_pec_tree_excludes_orphan(context: Context) -> None:
# Tree should have exactly one root with one child and zero grandchildren.
-12
View File
@@ -405,18 +405,6 @@ def step_tree_json_valid(context: Context) -> None:
assert isinstance(parsed, list), "Expected a JSON array"
@then("the json tree output should be a valid json envelope")
def step_tree_json_valid_envelope(context: Context) -> None:
parsed = json.loads(context.pe_tree_json)
assert isinstance(parsed, dict), (
f"Expected a JSON object (envelope), got {type(parsed)}"
)
_envelope_keys = {"command", "status", "exit_code", "data", "timing", "messages"}
assert _envelope_keys.issubset(parsed.keys()), (
f"Expected envelope keys {_envelope_keys}, got {set(parsed.keys())}"
)
@then('the json tree output should contain "{text}"')
def step_tree_json_contains(context: Context, text: str) -> None:
assert text in context.pe_tree_json, f"Expected '{text}' in tree JSON"
@@ -190,7 +190,44 @@ def step_plan_use_with_invalid_argument(context, arg_value: str) -> None:
)
# =============================================================================
# Plan start alias step definitions (alias for plan use)
# =============================================================================
# The Typer framework handles "start" -> "use" alias automatically.
# When the CLI invokes ["start", ...], Typer routes it to use_action().
@when('I run plan lifecycle command "{command}" with action "{action_name}"')
def step_plan_alias_invoke(context, command: str, action_name: str) -> None:
"""Execute the command (use or start) as an alias for creating a plan.
Typer routes ['start', ...] to use_action() automatically via aliases=["start"].
This step verifies that both 'plan use' and 'plan start' produce identical results.
"""
action = SimpleNamespace(namespaced_name=action_name)
plan = _make_plan(
plan_id=_ULIDS[7],
name=f"local/{command}-plan",
description=f"{command} alias test",
project_links=[ProjectLink(project_name="proj-1")],
)
context.lifecycle_service.get_action_by_name.return_value = action
context.lifecycle_service.use_action.return_value = plan
context.result = context.runner.invoke(
plan_app,
[command, action_name, "--project", "proj-1"],
)
@then("the plan lifecycle use service should be invoked")
def step_plan_alias_service_invoked(context) -> None:
"""Verify the start alias calls the same underlying service as plan use."""
context.lifecycle_service.use_action.assert_called_once()
@when('I run plan lifecycle use causing "{error_type}"')
def step_plan_use_error(context, error_type: str) -> None:
action = SimpleNamespace(namespaced_name="local/code-coverage")
context.lifecycle_service.get_action.return_value = action
+5 -18
View File
@@ -386,24 +386,11 @@ M6 E2E Hierarchical Decomposition Via Plan Tree
# P0-4: Hard assertion — tree command must succeed.
Should Be Equal As Integers ${tree.rc} 0 msg=plan tree failed (rc=${tree.rc}): ${tree.stderr}
Should Not Be Empty ${tree.stdout} Plan tree output should not be empty
# P0-4: Hard assertion — tree output must contain the spec-required envelope.
# The new envelope format wraps the tree in a command envelope with
# "command", "status", "exit_code", "data", "timing", "messages" keys.
# The "data" field contains "plan_id", "tree", "summary", "child_plans",
# and "decision_ids" (a mapping of human-readable keys to decision ULIDs).
${has_command_key}= Evaluate '"command"' in $tree.stdout
Should Be True ${has_command_key}
... Plan tree JSON output should contain spec-required envelope "command" key
${has_data_key}= Evaluate '"data"' in $tree.stdout
Should Be True ${has_data_key}
... Plan tree JSON output should contain spec-required envelope "data" key
${has_plan_id_key}= Evaluate '"plan_id"' in $tree.stdout
Should Be True ${has_plan_id_key}
... Plan tree JSON output should contain "plan_id" in envelope data
# Check for decision_ids mapping (proves at least one decision was recorded)
${has_decision_ids}= Evaluate '"decision_ids"' in $tree.stdout
Should Be True ${has_decision_ids}
... Plan tree should contain decision_ids mapping after execution
# P0-4: Hard assertion — at least one decision node must exist after execution.
${decision_count}= Evaluate $tree.stdout.count('"decision_id"')
Log Decision tree contains ${decision_count} decision node(s)
Should Be True ${decision_count} >= 1
... Plan tree should contain at least one decision node after execution (found ${decision_count})
# Check for hierarchical children (decomposition infrastructure indicator)
${has_children_key}= Evaluate '"children"' in $tree.stdout
IF ${has_children_key}
+10 -144
View File
@@ -7,7 +7,7 @@ plan lifecycle.
| Command | Description |
|-------------------------------|-----------------------------------------|
| ``agents plan use`` | Create plan from action + project(s) |
| ``agents plan use / start`` | Create plan from action + project(s) |
| ``agents plan list`` | List plans with optional filters |
| ``agents plan status`` | Show plan status / details |
| ``agents plan execute`` | Run phase-aware plan execution |
@@ -27,7 +27,7 @@ import re
import shutil
import time
from contextlib import suppress
from datetime import UTC, datetime
from datetime import datetime
from pathlib import Path
from typing import TYPE_CHECKING, Annotated, Any, Literal, cast
@@ -76,7 +76,7 @@ _ULID_VALIDATION_ERROR_MSG = (
" legacy storage system and are invisible to v3 commands.\n"
" 2. You referenced the wrong plan ID.\n\n"
"To use the v3 workflow:\n"
" - Run 'agents plan use <action> <project>' to create a v3 plan\n"
" - Run 'agents plan start <action> <project>' to create a v3 plan\n"
" (this returns a ULID you can use with subsequent commands).\n"
" - Run 'agents plan execute <PLAN_ID>' to execute it.\n"
" - Run 'agents plan apply <PLAN_ID>' to apply changes.\n\n"
@@ -215,8 +215,8 @@ if TYPE_CHECKING:
# Create sub-app for plan commands
app = typer.Typer(
help=(
"V3 Plan Lifecycle: Create plans with 'use', execute with 'execute', "
"apply changes with 'apply'. (Actor required; set default via "
"V3 Plan Lifecycle: Create plans with 'use' (or 'start'), execute with "
"'execute', apply changes with 'apply'. (Actor required; set default via "
"'agents actor set-default')"
)
)
@@ -1531,7 +1531,7 @@ def _print_lifecycle_plan(plan: Any, title: str = "Plan") -> None:
console.print(Panel(details, title=title, expand=False))
@app.command("use")
@app.command("use", aliases=["start"])
def use_action(
action_name: Annotated[
str,
@@ -1631,9 +1631,11 @@ def use_action(
arguments are PROJECT names. Projects can also be supplied via the
repeatable ``--project`` / ``-p`` option.
Alias: ``start`` (equivalent to ``use``).
Examples:
agents plan use local/code-coverage proj-1 proj-2 --arg target_coverage=80
agents plan use local/lint --project proj-1 --invariant "No new warnings"
agents plan start local/lint --project proj-1 --invariant "No new warnings"
"""
from cleveragents.application.services.plan_lifecycle_service import (
ActionNotAvailableError,
@@ -4117,131 +4119,6 @@ def _get_decision_label(decision_type: str, per_type_ordinal: int = 0) -> str:
return base_label
def _build_tree_data(
plan_id: str,
tree_data: list[dict[str, object]],
decisions: list[Decision],
show_superseded: bool = False,
started_at: datetime | None = None,
) -> dict[str, object]:
"""Build the data payload for ``agents plan tree --format json/yaml``.
Returns the ``data`` dict that will be wrapped in the spec-required
command envelope by ``format_output``.
"""
filtered = (
decisions if show_superseded else [d for d in decisions if not d.is_superseded]
)
def count_nodes(nodes: list[dict[str, object]]) -> int:
count = 0
for node in nodes:
count += 1
children = node.get("children", [])
if isinstance(children, list):
count += count_nodes(children)
return count
def compute_depth(nodes: list[dict[str, object]]) -> int:
if not nodes:
return 0
max_depth = 0
for node in nodes:
children = node.get("children", [])
if isinstance(children, list) and children:
max_depth = max(max_depth, 1 + compute_depth(children))
return max_depth
nodes_count = count_nodes(tree_data)
tree_depth = compute_depth(tree_data)
child_plan_ids: set[str] = set()
for d in filtered:
if d.decision_type in ("subplan_spawn", "subplan_parallel_spawn") and d.plan_id:
child_plan_ids.add(d.plan_id)
child_plans_count = len(child_plan_ids)
child_plans_str = f"{child_plans_count}+" if child_plans_count > 0 else "0"
invariants_count = sum(
1 for d in filtered if d.decision_type == "invariant_enforced"
)
superseded_count = sum(1 for d in decisions if d.is_superseded)
summary = {
"nodes": nodes_count,
"depth": tree_depth,
"child_plans": child_plans_str,
"invariants": invariants_count,
"superseded": superseded_count,
}
type_counts: dict[str, int] = {}
decision_ids: dict[str, str] = {}
for d in filtered:
type_counts[d.decision_type] = type_counts.get(d.decision_type, 0) + 1
ordinal = type_counts[d.decision_type]
if d.decision_type == "prompt_definition":
key = "root"
elif d.decision_type == "invariant_enforced":
key = f"invariant_{ordinal}"
elif d.decision_type == "strategy_choice":
key = "strategy"
elif d.decision_type == "implementation_choice":
key = f"implementation_{ordinal}"
elif d.decision_type == "subplan_spawn":
key = f"spawn_{ordinal}"
elif d.decision_type == "subplan_parallel_spawn":
key = f"parallel_{ordinal}"
else:
key = f"{d.decision_type}_{ordinal}"
decision_ids[key] = d.decision_id
child_plans_list: list[dict[str, object]] = []
for d in filtered:
if d.decision_type in ("subplan_spawn", "subplan_parallel_spawn") and d.plan_id:
child_plans_list.append(
{
"id": d.plan_id,
"phase": "execute",
"state": "queued",
}
)
def convert_tree_node(node: dict[str, object]) -> dict[str, object]:
"""Convert internal tree node format to spec format."""
spec_node: dict[str, object] = {
"type": node.get("type"),
"description": node.get("question") or node.get("description"),
}
if node.get("confidence") is not None:
spec_node["confidence"] = node.get("confidence")
if node.get("type") in ("subplan_spawn", "subplan_parallel_spawn"):
spec_node["plan_id"] = node.get("plan_id", "")
children = node.get("children", [])
if isinstance(children, list) and children:
spec_node["children"] = [convert_tree_node(child) for child in children]
return spec_node
spec_tree = convert_tree_node(tree_data[0]) if tree_data else None
return {
"plan_id": plan_id,
"tree": spec_tree,
"summary": summary,
"child_plans": child_plans_list,
"decision_ids": decision_ids,
}
@app.command("tree")
def tree_decisions_cmd(
plan_id: Annotated[
@@ -4264,7 +4141,6 @@ def tree_decisions_cmd(
"""Display the decision tree for a plan."""
from cleveragents.application.container import get_container
_tree_cmd_start = datetime.now(UTC)
container = get_container()
svc = container.decision_service()
decisions = svc.list_decisions(plan_id)
@@ -4279,17 +4155,7 @@ def tree_decisions_cmd(
)
if fmt in (OutputFormat.JSON, OutputFormat.YAML):
tree_data_dict = _build_tree_data(
plan_id, tree_data, decisions, show_superseded, started_at=_tree_cmd_start
)
console.print(
format_output(
tree_data_dict,
fmt,
command="plan tree",
messages=[{"level": "ok", "text": "Decision tree rendered"}],
)
)
console.print(format_output(tree_data, fmt))
elif fmt == OutputFormat.TABLE:
# Flatten for table view
filtered = (
@@ -3915,6 +3915,9 @@ class ValidationAttachmentRepository:
from ulid import ULID as _ULID
if "/" in resource_id and "/" not in validation_name:
validation_name, resource_id = resource_id, validation_name
session = self._session()
try:
# Check for existing attachment with same validation+resource+scope