Commit Graph

759 Commits

Author SHA1 Message Date
freemo 891cbdcc66 fix(lint): resolve import ordering and type annotation lint errors
Fix ruff I001 (unsorted imports) and UP043 (unnecessary default type
arguments) in lsp_server_stub_steps.py introduced by the structlog
capture fix.
2026-04-04 23:48:02 +00:00
freemo 68f9871f33 fix(test): resolve structlog cache interference in LSP and retry test suites
structlog's cache_logger_on_first_use=True causes module-level loggers
to permanently cache their processor chain on first use. Tests using
capture_logs() reconfigure processors, but cached loggers never pick up
the new configuration — resulting in empty capture lists.

Fixed by adding custom capture context managers that:
1. Temporarily disable logger caching
2. Replace the module-level logger with a fresh uncached instance
3. Restore original logger and config on exit

Fixes 11 LSP server stub scenarios and 2 retry policy wiring scenarios.
2026-04-04 23:08:32 +00:00
freemo eaf15dd17c fix(ci): restore all CI quality gates to passing on master
Apply remaining fixes not covered by the 4278ba91 commit:

1. src/cleveragents/cli/main.py:
   info and diagnostics commands now call configure_structlog(WARNING)
   before build_info_data()/build_diagnostics_data() when non-rich format
   is requested. This prevents debug-level structlog messages from
   corrupting --format json/yaml output in integration tests.

2. robot/helper_config_cli.py:
   Call configure_structlog(WARNING) before importing cleveragents CLI
   commands so plugin_manager debug messages don't pollute CliRunner
   captured output (fixes Config List JSON Format test).

3. features/steps/aimodelscredentials_steps.py:
   ModelProviderOption config checks now use getattr fallback so they
   work both when context.model_config is set (via explicit 'I examine
   the ModelProviderOption model_config' step) and when context.model_instance
   is set (via 'I create a ModelProviderOption with only priority set to N').

4. features/steps/plan_namespaced_name_tdd_steps.py:
   @when steps now set context.error and context.lsp_error in addition to
   context.exception so the existing @then steps from service_steps.py
   and lsp_registry_steps.py match and validate correctly.

No quality gates suppressed. All changes are to test and source files.

ISSUES CLOSED: #2597
2026-04-04 20:38:16 +00:00
freemo 7db698b602 fix(ci): fix parallel Behave test isolation and undefined step errors
- Rewrite TUI session export/import step definitions to use constructor-
  based dependency injection (container_factory) instead of
  unittest.mock.patch context managers that fail across fork() boundaries
  in the parallel test runner.
- Add container_factory parameter to TuiCommandRouter dataclass so tests
  can inject a mock container that survives multiprocessing.fork().
- Add use_step_matcher('re') to a2a_jsonrpc_wire_format_steps.py so
  regex-based step patterns are matched correctly (fixes 30 errored
  scenarios with 56 undefined steps).
- Add plural 'rows' variant to database_handler_crud_steps.py row-count
  step matcher (fixes 1 errored scenario).

ISSUES CLOSED: #2597
2026-04-04 20:38:16 +00:00
freemo 02250473ad fix(ci): restore all CI quality gates to passing on master
Fix all failing CI quality gates (lint, unit_tests, format) without
suppressing any quality enforcement.

Root causes and fixes:

1. Format: features/steps/plan_namespaced_name_tdd_steps.py had trailing
   whitespace; fixed by running ruff format.

2. Unit tests - A2A JSON-RPC 2.0 migration (commit 9c6d6915) renamed
   A2aRequest fields (operation→method, request_id→id, a2a_version→jsonrpc)
   and A2aResponse fields (status+data→result, request_id→id) but did not
   update all step files and feature files:
   - a2a_jsonrpc_wire_format_steps.py: added use_step_matcher('re') and
     reset to 'parse' at end to prevent parallel test interference
   - a2a_facade_wiring_steps.py: updated operation= to method=, .status/.data
     to .result
   - a2a_facade_steps.py: updated request_id→id, a2a_version→jsonrpc,
     A2aResponse(request_id=..., status=...) to new API
   - m6_facade_steps.py: updated all old API usage
   - devcontainer_cleanup_steps.py: updated A2aRequest(operation=...)
   - plan_prompt_command_steps.py: updated A2aRequest(operation=...)
   - wf03_plan_prompt_confidence_steps.py: updated A2aRequest(operation=...)
   - consolidated_misc.feature: updated old A2aRequest/A2aResponse scenarios

3. Unit tests - Session CLI output changed (commit 0d5d9cf0 and others):
   - 'Session Created' → 'Session created' (lowercase)
   - 'Session Details' → 'Session Summary'
   - 'Sessions (N total)' → 'Sessions'
   - session list JSON: top-level 'total' → nested 'summary.total'
   - Fixed in: session_cli.feature, session_cli_coverage_boost.feature,
     session_cli_uncovered_branches.feature, session_list_error.feature,
     tdd_session_create_persist_steps.py

4. Unit tests - Plan list output changed (commit 1a07a891):
   - 'V3 Lifecycle Plans' → 'Plans'
   - 'Lifecycle Plans' → 'Plans'
   - Name column removed (restored in source)
   - Invariants column removed (restored in source)
   - Project truncation removed (restored in source)
   - Fixed in: plan_cli_cancel_revert_coverage.feature,
     plan_lifecycle_cli_coverage.feature, plan_cli_coverage_boost_steps.py,
     plan.py (source code restored)

5. Unit tests - Plan apply command now requires ULID (commit 300a5d6d):
   - plan_cli_coverage_r3.feature: updated 'PLAN-001' to valid ULID
   - plan_cli_coverage_r3_steps.py: added --yes flag, added new step for
     no-eligible-plans path

6. Unit tests - Various source code bugs:
   - ThoughtBlock: converted from @dataclass to Pydantic BaseModel
     (architecture test requires all dataclasses to use Pydantic)
   - session.py: added DatabaseError handling to export, import, tell commands
   - database.py: fixed rollback_to() to reuse checkpoint connection for writes
   - database.py: added _get_checkpoint_conn() helper
   - check-tls-cert.py: fixed SSLCertVerificationError.reason AttributeError

7. Unit tests - Test step bugs:
   - error_recovery_coverage_boost_steps.py: fixed invalid ULID _PLAN_ID
   - session_service_coverage_steps.py: fixed 'sha256:' prefix bug in checksum
   - database_models_new_coverage_steps.py: added 'name' field to session mock
   - async_audit_recording_steps.py: fixed Settings(audit_async=False) via env var
   - coverage_threshold_config_steps.py: added --coverage-min pattern support
   - m5_acms_smoke_steps.py: updated usage hint text
   - actor_cli_yaml_steps.py: updated 'Removed actor' → 'Actor removed'
   - aimodelscredentials_steps.py: set context.imported_class in import step
   - domain_base_model.feature: added missing 'When I examine model_config' step
   - tui_first_run_steps.py: fixed module reload to restore cleveragents.tui.*
     modules after test (prevented patch interference in subsequent tests)
   - tui_first_run_steps.py: added set_search('') step for empty string
   - resource_handler_base_coverage_r3_steps.py: use _MinimalHandler instead
     of DatabaseResourceHandler for NotImplementedError tests
   - resource_handler_crud.feature: updated to test new DatabaseHandler behavior
   - resource_handler_sandbox.feature: updated to test new DatabaseHandler behavior
   - tdd_json_decode_crash_persistence.feature: fixed @tdd_bug → @tdd_issue tags

8. Parallel test interference:
   - All step files using use_step_matcher('re') now reset to 'parse' at end
     to prevent global matcher state leaking to subsequent step files
2026-04-04 20:38:16 +00:00
freemo 6e94e1d321 fix(persistence): close session in AutomationProfileRepository auto_commit finally block
Add missing `finally: if self._auto_commit: session.close()` blocks to all four public session-creating methods in AutomationProfileRepository: get_by_name(), list_all(), upsert(), and delete(). Closes #987
2026-04-04 19:58:54 +00:00
freemo 4db53ae830 Merge pull request 'fix(cli): add --namespace/-n option to agents plan list command' (#2616) from fix/plan-list-namespace-option into master 2026-04-03 21:40:46 +00:00
freemo 52730b0846 fix(cli): add --namespace/-n option to agents plan list command
Add the missing --namespace/-n option to lifecycle_list_plans() in
plan.py, mirroring the existing implementation in list_actions() in
action.py. The service layer already supported namespace filtering;
only the CLI layer was missing the option.

Changes:
- Add namespace parameter to lifecycle_list_plans() with --namespace/-n
  option flags and 'Filter plans by namespace' help text
- Pass namespace through to service.list_plans(namespace=namespace, ...)
- Update TUI Filters panel to display 'Namespace: <value>' when provided
- Add usage examples to command docstring
- Add 4 Behave unit test scenarios covering --namespace/-n option
- Add 2 Robot Framework integration tests verifying namespace filtering

ISSUES CLOSED: #2165
2026-04-03 20:50:17 +00:00
freemo b96138b88e fix(mcp): extract error message from content[0].text per MCP 1.4.0 protocol
MCPToolAdapter.invoke() was reading error messages from result.get('error',
'unknown error'), but the MCP 1.4.0 protocol returns errors in the content
field as a list of content items with type and text keys. This caused every
error from a real MCP 1.4.0-compliant server to be silently replaced with
the string 'unknown error'.

Changes:
- src/cleveragents/mcp/adapter.py: extract error_text from content[0].text
  with safe guards (isinstance check, length check) and fallback to
  'unknown error' when content is absent or empty
- features/mocks/mock_mcp_transport.py: return MCP 1.4.0-compliant error
  responses using content list format instead of the non-standard error key
- features/tdd_mcp_error_content_key.feature: Behave scenario verifying
  correct error extraction from MCP 1.4.0 content arrays (written as TDD
  issue-capture, @tdd_expected_fail removed after fix applied)
- features/steps/tdd_mcp_error_content_key_steps.py: step definitions for
  the new scenario including _MCP14ErrorTransport mock subclass

All 51 MCP adapter scenarios pass. Typecheck: 0 errors. Lint: clean.

ISSUES CLOSED: #2158
2026-04-03 19:03:15 +00:00
Luis Mendes 9e93ea5fc6 fix(persistence): close session in AutomationProfileRepository auto_commit finally block
Add missing `finally: if self._auto_commit: session.close()` blocks to
all four public session-creating methods in `AutomationProfileRepository`:
`get_by_name()`, `list_all()`, `upsert()`, and `delete()`.  Without
these blocks, sessions were never closed when the repository operated in
auto_commit mode, causing a slow session leak that could exhaust the
connection pool over time.

The fix mirrors the pattern already used by `SessionRepository`, which
correctly closes its session in a `finally` block for every public method.

Removed the `@tdd_expected_fail` tag from the TDD test
(`tdd_automation_profile_session_leak.feature`) so the six scenarios
now run as normal regression tests (four original plus two new scenarios
for `get_by_name` and `list_all`).

ISSUES CLOSED: #987
2026-04-03 19:00:22 +00:00
freemo 33c1e4cd1a test(plan): add TDD issue-capture test for NamespacedName digit-start validation bug
This TDD test captures the buggy behavior where `NamespacedName.validate_namespace()`
and `validate_name()` accept names starting with digits, violating the spec requirement
that namespace and name components must start with a letter (consistent with
`_BARE_NAME_RE` in project.py).

Three failing scenarios demonstrate the bug:
1. parse() accepting namespace starting with digit ("123abc/my-action")
2. constructor accepting name starting with digit (local/"123-action")
3. constructor accepting namespace starting with digit ("999org"/valid-name)

Tagged with @tdd_expected_fail per Bug Fix Workflow.

Implements #2145
Blocks #2147
2026-04-03 13:38:33 -04:00
freemo 0be3f85c56 feat(tui): implement Permission Question Widget
Implement inline permission question widget for quick allow/reject
decisions within the conversation stream with file diff context.

ISSUES CLOSED: #997
2026-04-03 05:56:27 +00:00
brent.edwards df41f64f21 test: add TDD bug-capture test for #989 — JSON decode crash in persistence
Add a new Behave TDD regression scenario that persists corrupt automation-profile JSON and verifies repository reads do not leak raw JSONDecodeError. The scenario is tagged with @tdd_bug, @tdd_bug_989, and @tdd_expected_fail so it currently inverts the intentional assertion failure and will require tag removal when bug #989 is fixed.\n\nAlso stabilize an unrelated integration fixture in robot/resource_dag.robot by sharing a single SQLAlchemy session in inline scripts; this removes nondeterministic visibility of flushed resource-type rows and keeps required nox integration quality gates deterministic for this branch.\n\nISSUES CLOSED: #1094
2026-04-03 03:58:45 +00:00
freemo 977cacc299 Merge pull request 'refactor(domain): extract shared model_config into a base Pydantic model' (#2014) from fix/domain-pydantic-base-model-config into master 2026-04-03 03:29:26 +00:00
freemo 650b1038b6 refactor(domain): extract shared model_config into a base Pydantic model
Introduce DomainBaseModel in src/cleveragents/domain/models/base.py that
defines the single shared model_config (str_strip_whitespace, validate_assignment,
arbitrary_types_allowed=False, populate_by_name, use_enum_values) previously
duplicated verbatim across five domain model files.

Update 14 classes across five files to inherit from DomainBaseModel instead
of pydantic.BaseModel directly, removing all inline model_config duplication:
- aimodelscredentials/ai_models_credentials.py (ModelProviderOption)
- aimodelserrors/ai_models_errors.py (ModelError, FallbackResult)
- aimodelsproviders/ai_models_providers.py (ModelProviderExtraAuthVars,
  ModelProviderConfigSchema)
- auth/auth.py (AuthHeader, TrialPlansExceededError, TrialMessagesExceededError,
  BillingError, ApiError, ClientAccount, ClientAuth)
- planconfig/plan_config.py (PlanConfig, ConfigSetting)

Pure structural refactor — no behavioral changes. Models with different
configurations (acms, aimodels_custom, etc.) are left untouched.

Add BDD feature (22 scenarios) and Robot integration tests (8 test cases)
verifying inheritance, config correctness, and no-duplication invariants.

ISSUES CLOSED: #1941
2026-04-03 02:01:45 +00:00
freemo 8f24887ecf Merge pull request 'fix(cli): disallow mixing legacy and v3 plan workflows' (#1577) from fix/prevent-legacy-v3-mixing into master 2026-04-03 01:24:06 +00:00
freemo 50a5e9672b feat(tui): implement shell danger detection patterns
Implement dangerous shell pattern detection with configurable pattern registry, danger level classification, and user warning system.

Closes #1003

ISSUES CLOSED: #1003
2026-04-03 01:15:23 +00:00
freemo 70e2ce4386 Merge pull request 'fix(infra): resolve TLS handshake failure on git.dev.cleveragents.com' (#1865) from fix/infra-tls-handshake-failure-git-dev into master 2026-04-03 01:13:31 +00:00
freemo b6ea4cd1e6 Merge pull request 'fix(cli): add missing Type field, Config, Capabilities, and Tools panels to actor add rich output' (#1969) from fix/actor-add-rich-output-missing-panels into master 2026-04-03 01:12:34 +00:00
freemo b7574a4fdd Merge pull request 'fix(a2a): rename A2aRequest/A2aResponse fields to comply with JSON-RPC 2.0 wire format' (#1990) from fix-1501-a2a-jsonrpc-wire-format into master 2026-04-03 01:12:34 +00:00
freemo a126a1c5bb Merge pull request 'fix(tests): resolve flakiness in test_example_flaky_test' (#1810) from fix/test-infra-flaky-test-example into master 2026-04-03 01:09:32 +00:00
freemo 9c6d69153e fix(a2a): rename A2aRequest/A2aResponse fields to comply with JSON-RPC 2.0 wire format
Rewrites the A2aRequest and A2aResponse Pydantic models to use the field
names mandated by the JSON-RPC 2.0 specification, fixing a fundamental
protocol compliance issue that prevented external A2A-compliant clients
from communicating with the server.

Changes:
- A2aRequest: a2a_version→jsonrpc (fixed '2.0'), request_id→id,
  operation→method; auth field removed (not in JSON-RPC 2.0)
- A2aResponse: a2a_version→jsonrpc, request_id→id, status+data→result
  (success path), timing_ms removed; added _result_xor_error validator
  enforcing mutual exclusion of result and error fields
- A2aLocalFacade.dispatch(): updated to use request.method, request.id,
  result=data, error=A2aErrorDetail(...)
- A2aHttpTransport.send(): updated to use request.method
- CLI call sites (session.py, plan.py): updated A2aRequest(method=...)
  and response.result / response.error field access
- All existing A2A Behave step files updated to new field names
- New 35-scenario Behave feature (a2a_jsonrpc_wire_format.feature)
  covering serialisation, deserialisation, validation, and facade dispatch
- New 7-test Robot Framework suite (a2a_jsonrpc_wire_format.robot)
  for end-to-end wire format verification

ISSUES CLOSED: #1501
2026-04-03 00:29:46 +00:00
freemo d430d671a0 fix(cli): add missing Type field, Config, Capabilities, and Tools panels to actor add rich output
Extended `_print_actor()` to render the full spec-required output for
`agents actor add`: the Actor Added panel now includes a Type field, and
three additional panels (Config, Capabilities, Tools) plus a success
status line are rendered when `show_add_panels=True`.

- Add `Type:` field to the Actor Added panel (from `config_blob["type"]`)
- Implement Config panel: Path, Hash, Options count, Nodes count, Edges count
- Implement Capabilities panel: bulleted list (rendered only when non-empty)
- Implement Tools panel: Rich table with Tool, Read-Only, Safe columns
  (rendered only when non-empty; string tool entries default to yes/yes)
- Add `✓ OK Actor added` success status line after all panels
- Pass `config_path` and `show_add_panels=True` from `add()` command
- Add Behave BDD scenarios covering each new panel and the success line
- Add Robot Framework integration test verifying the full rich output

ISSUES CLOSED: #1499
2026-04-03 00:23:58 +00:00
freemo 300a5d6ddc fix(cli): disallow mixing legacy and v3 plan workflows
Add ULID format validation to all v3 plan commands to prevent users from
accidentally mixing legacy ('agents tell') and v3 ('agents plan use')
workflows. The two systems use separate storage backends and cannot be
mixed; this change detects the mismatch early and provides actionable
error messages.

Changes:
- Add _validate_plan_ulid() with proper Crockford Base32 regex
  (^[0-9A-HJKMNP-TV-Z]{26}$, re.IGNORECASE) that correctly rejects
  invalid characters (I, L, O, U), hyphens, and wrong-length strings
- Add _PLAN_ULID_RE compiled regex and _ULID_VALIDATION_ERROR_MSG constant
  with actionable guidance explaining the legacy/v3 incompatibility
- Apply ULID validation to all v3 commands: execute_plan,
  _lifecycle_apply_with_id, lifecycle_apply_plan, plan_status,
  plan_errors, cancel_plan (only on user-provided IDs, not auto-discovered)
- Update _LEGACY_DEPRECATION_MSG and tell/build command warnings to
  explicitly state that the two workflows are INCOMPATIBLE and cannot be mixed
- Add comprehensive BDD tests in features/plan_ulid_validation.feature
  with step definitions using Typer CLI runner (not subprocess)
- Update CONTRIBUTING.md with 'Workflow Choice: Legacy vs. v3 Plan
  Lifecycle' section documenting the incompatibility and migration path

ISSUES CLOSED: #1560
2026-04-03 00:01:48 +00:00
freemo 8c81f13758 fix(infra): resolve TLS handshake failure on git.dev.cleveragents.com
The TLS handshake failure on git.dev.cleveragents.com was caused by the
hostname being absent from the certificate's Subject Alternative Names
(SANs), or by SNI virtual-host misconfiguration on the server side.

This commit delivers the repository-side remediation:

- scripts/check-tls-cert.py: New TLS certificate health-check script.
  Connects to a hostname, verifies the certificate's SANs include the
  target hostname, checks expiry, and reports errors/warnings.  Accepts
  an injectable SSLContext for unit testing without real network access.
  Supports wildcard SAN matching and configurable expiry warning threshold.

- docs/development/ops-runbook.md: New ops runbook documenting the full
  certificate renewal procedure (Let's Encrypt/certbot and manual CA),
  SNI misconfiguration diagnosis steps, expiry monitoring with cron, and
  recommended alert thresholds (30/14/7/0 days).

- features/tls_certificate_check.feature: 14 Behave scenarios tagged
  @tdd_issue @tdd_issue_1543 covering: missing SAN detection, valid SAN
  acceptance, expired certificate detection, expiry warning threshold,
  TLS handshake errors, connection timeouts, connection refused, wildcard
  SAN matching, and _hostname_matches_san unit tests.

- features/steps/tls_certificate_check_steps.py: Step definitions for
  the above feature, using unittest.mock to inject SSL contexts and
  socket connections so no real network calls are made.

- mkdocs.yml: Added Ops Runbook to the Development section navigation.

The actual server-side certificate renewal (adding git.dev.cleveragents.com
as a SAN and reloading the web server) must be performed by the server
administrator following the procedure in docs/development/ops-runbook.md.

Closes #1543

ISSUES CLOSED: #1543
2026-04-02 23:59:37 +00:00
freemo 8843872ce0 fix(tests): resolve flakiness in test_example_flaky_test
Add deterministic BDD feature and step definitions to resolve the
flaky-test detection alert for test_example_flaky_test (issue #1542).

Root cause: the async-job heartbeat step previously relied on a fixed
time.sleep(0.01) that was insufficient on fast CI runners. When two
consecutive datetime.now(UTC) calls returned the same microsecond value
the 'heartbeat updated' assertion failed intermittently.

The busy-wait guard (already present in async_execution_steps.py) is
the correct fix. This commit adds a dedicated feature that:

- Validates the heartbeat timestamp strictly advances after the
  busy-wait (the primary test_example_flaky_test scenario)
- Covers rejection of heartbeat recording for queued and completed jobs
- Adds a bounded heartbeat step that asserts the busy-wait terminates
  within a wall-clock budget, preventing infinite hangs on broken clocks

ISSUES CLOSED: #1542
2026-04-02 23:53:13 +00:00
freemo 288ff276b3 fix(a2a): reformat SseEventFormatter output to JSON-RPC 2.0 notification structure
- Add _EVENT_TYPE_TO_METHOD class-level mapping (ClassVar[dict[str, str]]) to
  convert A2A event types to JSON-RPC 2.0 method names:
  TaskStatusUpdateEvent → task/statusUpdate
  TaskArtifactUpdateEvent → task/artifactUpdate
- Refactor SseEventFormatter.format() to produce JSON-RPC 2.0 notification
  envelope: {"jsonrpc": "2.0", "method": "...", "params": {...}}
- Move event data fields into params object; include taskId (from plan_id)
  in params when plan_id is present, per spec §Streaming Architecture
- Remove non-spec fields (event_id, event_type, timestamp, plan_id) from
  the data payload; these remain in SSE envelope headers (event: and id:)
- Update BDD feature to verify JSON-RPC 2.0 structure for both event types,
  events with/without plan_id, custom data in params, and exclusion of
  non-spec fields
- Fix pre-existing type errors in step definitions: replace try/except
  ImportError pattern with direct imports and use behave.runner.Context
  for proper static typing (0 pyright errors)

ISSUES CLOSED: #1502
2026-04-02 23:53:13 +00:00
freemo 09be821a38 fix(cli): make version command show actual git commit (#1520)
Implements issue #1520. The version command now displays the actual git commit SHA to help identify which version of the code is running.

Co-authored-by: Jeffrey Phillips Freeman <the@jeffreyfreeman.me>
Co-committed-by: Jeffrey Phillips Freeman <the@jeffreyfreeman.me>
2026-04-02 21:30:05 +00:00
freemo 5c49b2134b feat(tui): implement shell danger detection patterns
Implement dangerous shell pattern detection with configurable pattern
registry, danger level classification, and user warning system.

- Domain: ShellDangerLevel enum (LOW, MEDIUM, HIGH, CRITICAL)
- Domain: DangerousPattern value object with regex matching
- Domain: DangerousCommandWarning value object
- Domain: DangerousPatternDetector with configurable pattern registry
- Application: ShellSafetyService with warn_callback and block_level
- Default patterns: rm -rf, fork bomb, dd if=, mkfs, chmod 777,
  sudo rm, wget/curl piped to sh/bash, git push --force
- BDD tests covering all pattern categories, safe commands,
  registry management, and service behavior

ISSUES CLOSED: #1003
2026-04-02 20:48:33 +00:00
freemo b96154d612 fix(session): session export checksum stored with sha256 prefix per spec #1450 (#1481)
Co-authored-by: Jeffrey Phillips Freeman <the@jeffreyfreeman.me>
Co-committed-by: Jeffrey Phillips Freeman <the@jeffreyfreeman.me>
2026-04-02 19:29:50 +00:00
freemo 48cff5cfe0 refactor(cli): rename plan lifecycle-list and lifecycle-apply to match specification
Renames `plan lifecycle-list` to `plan list` and `plan lifecycle-apply` to `plan apply` to align with the specification's canonical command names. Removes legacy V2 plan commands that occupied those names.

- Renamed CLI command registrations from lifecycle-list/lifecycle-apply to list/apply
- Removed legacy V2 apply and list commands (~200 lines)
- Updated apply shortcut in main.py to delegate to v3 lifecycle
- Added defensive null check for plan existence in apply command
- Updated 63+ test, doc, and benchmark files for consistency

Closes #881

Co-authored-by: Jeffrey Phillips Freeman <the@jeffreyfreeman.me>
Co-committed-by: Jeffrey Phillips Freeman <the@jeffreyfreeman.me>
2026-04-02 19:09:04 +00:00
freemo d0ef563175 feat(mcp): implement lazy start/auto-stop and sandbox path rewriting for MCP tools
Add lifecycle management and sandbox support for MCP tools:

- McpClient: lazy start, configurable idle timeout with auto-stop, health monitoring with automatic restart
- McpRegistry: namespace-isolated tracking of multiple MCP servers
- SandboxPathRewriter: bi-directional file path rewriting between host and sandbox workspaces
- MCPCapabilityMetadata: structured exposure of full MCP server capabilities
- 26 BDD scenarios covering lifecycle, sandbox rewriting, and edge cases

ISSUES CLOSED: #938
2026-04-02 18:18:40 +00:00
freemo 2a266929fd Merge pull request 'bug(cli): automation_profile._get_service() bypasses DI container' (#1181) from bugfix/m4-automation-profile-di-bypass into master 2026-04-02 17:54:14 +00:00
freemo 7e4301066c Merge pull request 'refactor(cli): move context commands to actor context subgroup' (#1194) from feature/m4-actor-context-hierarchy into master 2026-04-02 17:53:42 +00:00
freemo bcf54d08c9 Merge pull request 'feat(plugin): register spec-defined extension points in PluginManager' (#1217) from feature/plugin-extension-points into master 2026-04-02 17:40:18 +00:00
freemo 085f71a69d feat(ci): add Helm chart lint and template validation to CI
Add kubeconform manifest validation to the existing helm CI job.
The helm job already had helm lint and helm template steps (added in
#1085). This commit completes the optional acceptance criterion from
#1089 by adding kubeconform v0.7.0 to validate rendered manifests
against the Kubernetes 1.29.0 schema in strict mode.

Closes #1089
2026-04-02 17:40:00 +00:00
freemo 6c94ad9552 Merge pull request 'fix: add --required/--informational flags to validation add CLI' (#1222) from bugfix/m5-validation-required-flag into master 2026-04-02 17:39:19 +00:00
freemo f035e2efbd Merge pull request 'feat(tui): implement first-run experience with actor selection overlay' (#1391) from feature/m8-tui-first-run into master 2026-04-02 17:33:44 +00:00
freemo d0515ff1ac feat(tui): implement session export/import (JSON + Markdown)
Add Markdown export format for sessions alongside the existing JSON export.
Implement TUI slash command routing for /session:export and /session:import.

- Add Session.as_export_markdown() domain method producing a human-readable
  Markdown transcript (lossy, not importable — for sharing/documentation)
- Extend CLI 'agents session export' with --format flag (json|md)
- Extend TuiCommandRouter._session_command() to handle 'export' and 'import'
  subcommands, delegating to the session service via the DI container
- Add 16 Behave scenarios covering domain model, CLI, and TUI command paths

Closes #1004
2026-04-02 17:30:37 +00:00
freemo 2e24483947 feat(tui): implement session export/import (JSON + Markdown)
Add Markdown export format for sessions alongside the existing JSON export.
Implement TUI slash command routing for /session:export and /session:import.

- Add Session.as_export_markdown() domain method producing a human-readable
  Markdown transcript (lossy, not importable — for sharing/documentation)
- Extend CLI 'agents session export' with --format flag (json|md)
- Extend TuiCommandRouter._session_command() to handle 'export' and 'import'
  subcommands, delegating to the session service via the DI container
- Add 16 Behave scenarios covering domain model, CLI, and TUI command paths

Closes #1004
2026-04-02 17:16:59 +00:00
freemo 2863b5d1e1 feat(tui): implement first-run experience with actor selection overlay
Implements the first-run experience for the TUI as specified in the
specification's 'First-Run Experience' section (§ TUI Architecture).

On first launch (no personas configured), a centered ActorSelectionOverlay
widget is displayed guiding the user to select an actor. The overlay
supports keyboard navigation (j/k), fuzzy search (/), and confirmation
(enter). Selecting an actor creates a default persona and dismisses the
overlay.

Changes:
- Add src/cleveragents/tui/first_run.py: is_first_run() detection helper
  and create_default_persona_for_actor() setup helper
- Add src/cleveragents/tui/widgets/actor_selection_overlay.py:
  ActorSelectionOverlay widget with show/hide/navigate/search/confirm API
  and render_actor_selection() pure rendering function
- Update src/cleveragents/tui/app.py: integrate first-run check in
  on_mount(), yield ActorSelectionOverlay in compose(), add
  _complete_first_run() method
- Update src/cleveragents/tui/widgets/__init__.py: export
  ActorSelectionOverlay
- Add features/tui_first_run.feature + features/steps/tui_first_run_steps.py:
  comprehensive Behave BDD tests covering all public API paths

ISSUES CLOSED: #1007
2026-04-02 17:12:54 +00:00
freemo 0787f42e2f feat(acms): operationalize UKO runtime with provenance and temporal versioning
Operationalizes the Universal Knowledge Ontology (UKO) runtime per issue #891, implementing provenance tracking, temporal versioning, ACMS context strategy integration, four-layer ontology population, implicit relationship inference, and graph persistence.

New services:
- UKOQueryInterface: typed interface for ACMS context strategies to query UKO classification data
- UKOInferenceEngine: semantic analysis producing implicit triples with confidence 0.7
- UKOGraphPersistence: serialises/restores UKO graph state via JSON or in-memory backends

Modified: uko_indexer_internals.py index_graph() now runs inference and populates uko:layer triples for all four ontology layers.

47 BDD scenarios covering all acceptance criteria.

Closes #891

Co-authored-by: Jeffrey Phillips Freeman <the@jeffreyfreeman.me>
Co-committed-by: Jeffrey Phillips Freeman <the@jeffreyfreeman.me>
2026-04-02 17:09:15 +00:00
freemo ee980ee117 feat(resource): implement DevcontainerHandler missing protocol methods (#1286)
Implements the four missing protocol methods on DevcontainerHandler required by Epic #825 (ResourceHandler Protocol Completion):

- delete(): uses 'devcontainer exec rm -rf' to delete files/dirs inside the container; returns DeleteResult(success=False) for missing/stopped containers rather than raising.
- list_children(): uses 'devcontainer exec ls -1' to enumerate workspace entries; returns an empty list on container failure.
- diff(): compares content hashes between the devcontainer workspace and another filesystem location; uses EMPTY_CONTENT_HASH sentinel to treat both-absent as no-change.
- create_sandbox(): delegates to BaseResourceHandler.create_sandbox with lazy activation (same DETECTED/STOPPED/FAILED guard as resolve()).

All methods raise ValueError for resources with no location.

Adds 18 Behave BDD scenarios covering success paths, failure/stopped-container paths, empty-path edge cases, and ValueError guards.

ISSUES CLOSED: #1242

Co-authored-by: Jeffrey Phillips Freeman <the@jeffreyfreeman.me>
Co-committed-by: Jeffrey Phillips Freeman <the@jeffreyfreeman.me>
2026-04-02 17:08:52 +00:00
freemo c2097ee2ed feat(events): enrich PLAN_APPLIED event with changeset statistics from PlanApplyService
Enriches the PLAN_APPLIED domain event with SEC7 audit-logging statistics per docs/specification.md §Audit Logging (issue #716).

Changes:
- PlanLifecycleService.complete_apply() now accepts optional keyword arguments: files_changed, lines_added, lines_removed, resources_modified, apply_duration_seconds (all default to 0). These are included in the PLAN_APPLIED event details dict alongside the existing action_name, phase, and project_names fields.
- PlanApplyService.apply_with_validation_gate() computes changeset statistics from SpecChangeSet.summary() and measures apply duration, then passes all statistics to complete_apply().
- New BDD feature features/plan_applied_event_enrichment.feature with 13 scenarios.

Closes #716

Co-authored-by: Jeffrey Phillips Freeman <the@jeffreyfreeman.me>
Co-committed-by: Jeffrey Phillips Freeman <the@jeffreyfreeman.me>
2026-04-02 17:08:38 +00:00
freemo 4a18a15ca5 feat(tui): implement PermissionsScreen with diff view
Implement PermissionsScreen with diff view for tool permission requests.
- 3 diff display modes (unified, side-by-side, context)
- Allow/reject keyboard bindings
- Permission decision persistence
- 62 BDD scenarios covering all components

ISSUES CLOSED: #996

Co-authored-by: Jeffrey Phillips Freeman <the@jeffreyfreeman.me>
Co-committed-by: Jeffrey Phillips Freeman <the@jeffreyfreeman.me>
2026-04-02 17:08:13 +00:00
freemo ec52acffb7 feat(resource): implement DatabaseResourceHandler CRUD and checkpoint methods
Implements all missing CRUD and checkpoint methods on DatabaseResourceHandler per issue #1241 (Epic #825 ResourceHandler Protocol Completion):

- read(): SQLite queries sqlite_master for schema; remote returns connection-info
- write(): SQLite executes SQL statements; remote returns not-supported result
- delete(): SQLite executes DROP TABLE IF EXISTS; remote returns not-supported
- list_children(): SQLite lists tables/views from sqlite_master; remote returns []
- diff(): compares schemas via content_hash on both sides
- create_checkpoint(): SQLite creates SAVEPOINT on open connection; remote uses content-hash fallback
- rollback_to(): SQLite executes ROLLBACK TO SAVEPOINT; remote returns not-supported

All methods handle errors gracefully (no unhandled exceptions). Adds comprehensive Behave BDD tests covering all methods for both SQLite and remote database types.

ISSUES CLOSED: #1241

Co-authored-by: Jeffrey Phillips Freeman <the@jeffreyfreeman.me>
Co-committed-by: Jeffrey Phillips Freeman <the@jeffreyfreeman.me>
2026-04-02 17:08:05 +00:00
freemo 0989f58dc8 feat(estimation): wire actor.default.estimation config fallback and Strategize-to-Estimate lifecycle hook (#1310)
Co-authored-by: Jeffrey Phillips Freeman <the@jeffreyfreeman.me>
Co-committed-by: Jeffrey Phillips Freeman <the@jeffreyfreeman.me>
2026-04-02 17:07:48 +00:00
freemo cfc9e04a90 feat(tui): implement actor thought block rendering
Implement ThoughtBlock domain model with configurable max_lines (default 10), expanded state, and helper methods for rendering truncated/full content. Implement ThoughtBlockWidget TUI widget with muted styling, collapsed/expanded state, and expand/collapse toggle. Add 23 Behave BDD scenarios covering domain model and widget behaviour.

Closes #1001

ISSUES CLOSED: #1001

Co-authored-by: Jeffrey Phillips Freeman <the@jeffreyfreeman.me>
Co-committed-by: Jeffrey Phillips Freeman <the@jeffreyfreeman.me>
2026-04-02 17:07:47 +00:00
freemo 65aa7a7842 feat(events): enrich PLAN_CANCELLED event with progress and resource cleanup context (#1301)
Enriches the PLAN_CANCELLED domain event emitted by PlanLifecycleService.cancel_plan() with additional context fields to improve audit trail quality (SEC7 Audit Logging).

Progress context fields: cancelled_phase, cancelled_processing_state, last_completed_step, subplan_count
Resource cleanup context fields: sandbox_refs, changeset_id, resources_pending_cleanup

Existing fields (reason, project_names) preserved for backward compatibility.
15 BDD scenarios added covering all new fields, accuracy, and backward compatibility.

Closes #717

Co-authored-by: Jeffrey Phillips Freeman <the@jeffreyfreeman.me>
Co-committed-by: Jeffrey Phillips Freeman <the@jeffreyfreeman.me>
2026-04-02 17:07:41 +00:00
freemo 1d36449a98 fix(cli): remove extra --mode flag from validation attach
Remove the --mode/-m CLI flag from the validation attach command to align
with the specification, which defines validation mode as an inherent
property of the validation definition set at registration time via
validation add, not as a per-attachment override.

The service layer (ToolRegistryService.attach_validation) no longer
accepts mode as a parameter; instead it reads the mode from the
validation's registered definition. The ToolRegistryRepository
_to_legacy_domain now exposes the mode field so the service can access it.

All tests that passed --mode to the CLI or service have been updated or
removed. The invalid-mode validation scenarios were removed since the
mode is no longer caller-supplied. Coverage remains at 98.7%.

ISSUES CLOSED: #913

Co-authored-by: Jeffrey Phillips Freeman <jeffrey.freeman@cleverthis.com>
Co-committed-by: Jeffrey Phillips Freeman <jeffrey.freeman@cleverthis.com>
2026-04-02 17:07:26 +00:00