From ea25627051bef868dbd2a1b0bece88eb28ea21a5 Mon Sep 17 00:00:00 2001 From: HAL9000 Date: Thu, 30 Apr 2026 03:41:52 +0000 Subject: [PATCH] feat(cli): wire up ACMS context sub-app to main CLI entry point MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ACMS context CLI commands ('context show' / 'context clear') were fully implemented in 'acms_context.py' with comprehensive tests, mocks, benchmarks, and documentation — but the module was never imported or registered in 'cli/main.py'. This commit wires up the 'acms_context.app' Typer sub-app so that 'agents acms context show' and 'agents acms context clear' are actually accessible from the CLI. Changes: - Import acms_context in _register_subcommands() - Register acms_context.app as the 'acms' sub-app on the main Typer app - Add 'acms' to valid_cmds list in main() for fast-path validation - Add 'acms context' entry to _print_basic_help() output - Minor formatting cleanup applied by ruff ISSUES CLOSED: #9586 Refs: #9675 --- features/steps/acms_context_cli_steps.py | 7 ++--- robot/helper_acms_context_cli.py | 8 ++---- src/cleveragents/cli/commands/acms_context.py | 27 ++++++------------- src/cleveragents/cli/main.py | 10 +++++++ 4 files changed, 22 insertions(+), 30 deletions(-) diff --git a/features/steps/acms_context_cli_steps.py b/features/steps/acms_context_cli_steps.py index acfe6b61f..27de8ada2 100644 --- a/features/steps/acms_context_cli_steps.py +++ b/features/steps/acms_context_cli_steps.py @@ -220,9 +220,7 @@ def step_run_context_clear_path(context: Any, pattern: str) -> None: from cleveragents.cli.commands.acms_context import acms_context_clear all_entries: list[TieredFragment] = context.entries_to_remove - filtered = [ - f for f in all_entries if fnmatch.fnmatch(f.resource_id, pattern) - ] + filtered = [f for f in all_entries if fnmatch.fnmatch(f.resource_id, pattern)] mock_service = make_mock_tier_service(fragments=all_entries) mock_container = make_mock_container(mock_service) @@ -344,8 +342,7 @@ def step_run_context_clear_help(context: Any) -> None: from cleveragents.cli.commands.acms_context import acms_context_clear context.command_output = ( - acms_context_clear.__doc__ - or "Remove stale context entries from the ACMS index" + acms_context_clear.__doc__ or "Remove stale context entries from the ACMS index" ) context.command_exit_code = 0 diff --git a/robot/helper_acms_context_cli.py b/robot/helper_acms_context_cli.py index 8b94512df..923121d01 100644 --- a/robot/helper_acms_context_cli.py +++ b/robot/helper_acms_context_cli.py @@ -152,9 +152,7 @@ def _cmd_context_show_empty() -> int: print(f"acms-fail: context show empty exited with code {exit_code}") return 1 if "No context found for view: empty_view" not in output: - print( - f"acms-fail: expected 'No context found for view' in output\n{output}" - ) + print(f"acms-fail: expected 'No context found for view' in output\n{output}") return 1 print("acms-context-show-empty-ok") return 0 @@ -238,9 +236,7 @@ def _cmd_context_clear_no_match() -> int: print(f"acms-fail: context clear no-match exited with code {exit_code}") return 1 if "No context entries match the specified filters" not in output: - print( - f"acms-fail: expected 'No context entries match' in output\n{output}" - ) + print(f"acms-fail: expected 'No context entries match' in output\n{output}") return 1 print("acms-context-clear-no-match-ok") return 0 diff --git a/src/cleveragents/cli/commands/acms_context.py b/src/cleveragents/cli/commands/acms_context.py index 65c3c1c07..c458dee19 100644 --- a/src/cleveragents/cli/commands/acms_context.py +++ b/src/cleveragents/cli/commands/acms_context.py @@ -23,9 +23,7 @@ if TYPE_CHECKING: pass # Create sub-app for ACMS context commands -app = typer.Typer( - help="ACMS context management commands (agents acms context)" -) +app = typer.Typer(help="ACMS context management commands (agents acms context)") def _format_budget_utilization( @@ -82,9 +80,7 @@ def acms_context_show( fragments = tier_service.get_scoped_view([view.strip()]) if not fragments: - console.print( - f"[yellow]No context found for view: {view}[/yellow]" - ) + console.print(f"[yellow]No context found for view: {view}[/yellow]") return # Display assembled context @@ -98,9 +94,7 @@ def acms_context_show( total_tokens = 0 for fragment in fragments: - resource_id, tier_label, token_str, project = ( - _format_fragment_row(fragment) - ) + resource_id, tier_label, token_str, project = _format_fragment_row(fragment) total_tokens += fragment.token_count table.add_row(resource_id, tier_label, token_str, project) @@ -200,9 +194,7 @@ def acms_context_clear( console.print(table) if len(entries_to_remove) > 10: - console.print( - f" ... and {len(entries_to_remove) - 10} more entries" - ) + console.print(f" ... and {len(entries_to_remove) - 10} more entries") # Confirm if needed if not yes: @@ -215,9 +207,7 @@ def acms_context_clear( # Remove entries by evicting from their respective tiers removed_count = _remove_fragments(tier_service, entries_to_remove) - console.print( - f"\n[green]✓[/green] Removed {removed_count} context entries." - ) + console.print(f"\n[green]✓[/green] Removed {removed_count} context entries.") except CleverAgentsError as e: console = _get_console() @@ -249,13 +239,12 @@ def _filter_fragments( result = fragments if path: - result = [ - f for f in result if fnmatch.fnmatch(f.resource_id, path) - ] + result = [f for f in result if fnmatch.fnmatch(f.resource_id, path)] if tag: result = [ - f for f in result + f + for f in result if f.metadata.get("tag") == tag or f.metadata.get("tags") == tag ] diff --git a/src/cleveragents/cli/main.py b/src/cleveragents/cli/main.py index f92202a9c..19d0e6588 100644 --- a/src/cleveragents/cli/main.py +++ b/src/cleveragents/cli/main.py @@ -80,6 +80,7 @@ def _register_subcommands() -> None: try: from cleveragents.cli.commands import ( + acms_context, action, actor, audit, @@ -113,6 +114,13 @@ def _register_subcommands() -> None: app.add_typer(project.app, name="project", help="Project management") + # Register acms context as a sub-app (canonical: agents acms context) + app.add_typer( + acms_context.app, + name="acms", + help="ACMS (Advanced Context Management System) operations.", + ) + # Register context as a sub-app of actor (canonical: agents actor context) actor.app.add_typer( context.app, @@ -260,6 +268,7 @@ def _print_basic_help() -> None: typer.echo("\nCommon commands:") typer.echo(" project Project management") typer.echo(" actor context Actor context management") + typer.echo(" acms context ACMS context management (show, clear)") typer.echo(" plan Plan operations (actor required)") typer.echo(" actor Actor management and defaults") typer.echo(" init Initialize a project") @@ -765,6 +774,7 @@ def main(args: list[str] | None = None) -> int: "diagnostics", "init", "project", + "acms", "context", "plan", "actor",