From 8b7866bd0bcdaab9ba62b5de2bb668b33b17e726 Mon Sep 17 00:00:00 2001 From: Aditya Chhabra Date: Fri, 13 Mar 2026 02:59:53 +0530 Subject: [PATCH] fix: use container-wired PlanLifecycleService for persistence in CLI commands Both action.py and plan.py CLI commands were creating PlanLifecycleService with only settings (no UnitOfWork), causing in-memory-only storage that lost data between CLI invocations. Now uses container.plan_lifecycle_service() which injects a real UnitOfWork for database persistence. Also fixed list_actions() to query the persistence layer instead of only reading from the in-memory cache, which was always empty on fresh service instances. --- .../services/plan_lifecycle_service.py | 25 ++++++++++++++++++- src/cleveragents/cli/commands/action.py | 5 +--- src/cleveragents/cli/commands/plan.py | 6 +---- 3 files changed, 26 insertions(+), 10 deletions(-) diff --git a/src/cleveragents/application/services/plan_lifecycle_service.py b/src/cleveragents/application/services/plan_lifecycle_service.py index 619b8184..0151db52 100644 --- a/src/cleveragents/application/services/plan_lifecycle_service.py +++ b/src/cleveragents/application/services/plan_lifecycle_service.py @@ -553,7 +553,30 @@ class PlanLifecycleService: Returns: List of matching Actions """ - actions = list(self._actions.values()) + # Start with in-memory actions + seen_names: set[str] = set() + actions: list[Action] = [] + + for action in self._actions.values(): + seen_names.add(str(action.namespaced_name)) + actions.append(action) + + # Merge from persistence layer + if self._persisted and self.unit_of_work is not None: + try: + with self.unit_of_work.transaction() as ctx: + persisted = ctx.actions.list_available(namespace=namespace) + for action in persisted: + name_str = str(action.namespaced_name) + if name_str not in seen_names: + seen_names.add(name_str) + actions.append(action) + self._actions[name_str] = action + except Exception: + self._logger.warning( + "list_actions_persistence_fallback", + exc_info=True, + ) if namespace: actions = [a for a in actions if a.namespaced_name.namespace == namespace] diff --git a/src/cleveragents/cli/commands/action.py b/src/cleveragents/cli/commands/action.py index 00380d13..212d12ad 100644 --- a/src/cleveragents/cli/commands/action.py +++ b/src/cleveragents/cli/commands/action.py @@ -84,10 +84,7 @@ _FORMAT_HELP = "Output format: json, yaml, plain, table, or rich (default: rich) def _get_lifecycle_service() -> PlanLifecycleService: """Get the PlanLifecycleService from the container.""" container = get_container() - settings = container.settings() - # For now, we create the service directly since it's not yet in the container - # This will be updated when we add proper DI support - return PlanLifecycleService(settings=settings) + return container.plan_lifecycle_service() def _action_spec_dict(action: Action) -> dict[str, object]: diff --git a/src/cleveragents/cli/commands/plan.py b/src/cleveragents/cli/commands/plan.py index f06d8780..63ba8477 100644 --- a/src/cleveragents/cli/commands/plan.py +++ b/src/cleveragents/cli/commands/plan.py @@ -1106,13 +1106,9 @@ def continue_plan( def _get_lifecycle_service(): """Get the PlanLifecycleService from the container.""" from cleveragents.application.container import get_container - from cleveragents.application.services.plan_lifecycle_service import ( - PlanLifecycleService, - ) container = get_container() - settings = container.settings() - return PlanLifecycleService(settings=settings) + return container.plan_lifecycle_service() def _print_lifecycle_plan(plan: Any, title: str = "Plan") -> None: