From 8edb113632371e95bb320e2fd005f55409ea2acf Mon Sep 17 00:00:00 2001 From: HAL9000 Date: Sat, 9 May 2026 23:08:47 +0000 Subject: [PATCH] fix(cli): resolve persistence bug, lint issues, and import placement (#8675 / #8623) --- src/cleveragents/cli/commands/project.py | 19 ++--- .../cli/commands/project_switch.py | 77 ++++++------------- 2 files changed, 29 insertions(+), 67 deletions(-) diff --git a/src/cleveragents/cli/commands/project.py b/src/cleveragents/cli/commands/project.py index 335af4259..e18612a9d 100644 --- a/src/cleveragents/cli/commands/project.py +++ b/src/cleveragents/cli/commands/project.py @@ -40,6 +40,11 @@ from cleveragents.core.exceptions import ( ValidationError, ) +from cleveragents.cli.commands.project_switch import switch_project + + +_FORMAT_HELP = "Output format: json, yaml, plain, or rich (default: rich)" + # Create sub-app for project commands app = typer.Typer(help="Project management commands") file_filter_app = typer.Typer( @@ -48,8 +53,7 @@ file_filter_app = typer.Typer( console = _get_console() err_console = _get_err_console() -# Reusable --format option description -_FORMAT_HELP = "Output format: json, yaml, plain, table, or rich (default: rich)" + # --------------------------------------------------------------------------- @@ -994,17 +998,6 @@ def delete( ) - - -# --------------------------------------------------------------------------- -# Switch subcommand — delegates to standalone project_switch module -# --------------------------------------------------------------------------- - -from cleveragents.cli.commands.project_switch import ( - switch_project, -) - - @app.command(name="switch") def switch( name: Annotated[ diff --git a/src/cleveragents/cli/commands/project_switch.py b/src/cleveragents/cli/commands/project_switch.py index efdfefcb6..2614e9d16 100644 --- a/src/cleveragents/cli/commands/project_switch.py +++ b/src/cleveragents/cli/commands/project_switch.py @@ -12,6 +12,8 @@ Commands: from __future__ import annotations +from pathlib import Path + from typing import Any import typer @@ -58,8 +60,16 @@ def switch_project( err_console.print(f"[red]Project not found:[/red] {name}") raise typer.Exit(1) from exc - # Persist active-project selection to user config - _persist_active_project(container, name) + # Persist active-project selection via the project's .cleveragents dir + proj_path = getattr(proj, 'path', None) or getattr(proj, 'local_path', None) + if proj_path is not None: + _persist_active_project(Path(proj_path), name) + else: + # Fallback: write to cwd project marker + try: + _persist_active_project(Path.cwd(), name) + except Exception: + pass data = svc.project_to_dict(proj) @@ -72,63 +82,22 @@ def switch_project( console.print(format_output(data, output_format)) -def _persist_active_project(container: Any, namespaced_name: str) -> None: - """Persist the active project name to ``~/.cleveragents/config.toml``. - - Reads an existing config (if present), updates the - ``active_project`` key, and writes back. If no config file - exists yet, one is created with the default directory structure. +def _persist_active_project(project_dir: Path, namespaced_name: str) -> None: + """Persist the project name to {project_dir}/.cleveragents/project.name. Args: - container: The application DI container. + project_dir: The resolved path of the project directory to use as context. namespaced_name: The project's namespaced name to persist. """ - from pathlib import Path - - # Resolve the base data directory (same location ProjectService uses) + # Write project name inside the project's .cleveragents dir + clever_dir = project_dir / ".cleveragents" try: - settings = getattr(container, "settings", None) - if settings is not None: - base_dir = getattr(settings, "data_path", Path.home() / ".cleveragents") - else: - base_dir = Path.home() / ".cleveragents" - except Exception: - base_dir = Path.home() / ".cleveragents" - - config_file = base_dir / "config.toml" - - # Ensure directory exists - try: - config_file.parent.mkdir(parents=True, exist_ok=True) - except Exception: - # Silently fail on write if home dir is not writable + clever_dir.mkdir(parents=True, exist_ok=True) + except OSError: return - # Read existing config if present (simple key-value TOML) - current_lines: list[str] = [] + name_file = clever_dir / "project.name" try: - if config_file.exists(): - raw_config = config_file.read_text() - current_lines = raw_config.strip().splitlines(keepends=True) if raw_config.strip() else [] - except Exception: - pass - - # Update or append active_project key - _found_active = False - new_lines: list[str] = [] - for line in current_lines: - stripped = line.strip() - if stripped.startswith("active_project"): - new_lines.append(f'active_project = "{namespaced_name}"\n') - _found_active = True - else: - new_lines.append(line) - - if not _found_active: - new_lines.append("\n" + f'active_project = "{namespaced_name}"\n') - - try: - config_file.write_text("".join(new_lines), encoding="utf-8") - except Exception: - # Silently fail on write if not writable - pass + name_file.write_text(namespaced_name, encoding="utf-8") + except OSError: + pass # Silently fail on write