From 0bf200142508d6680ad08702c3da4af8054ddd06 Mon Sep 17 00:00:00 2001 From: Rushil Patel Date: Thu, 21 Aug 2025 11:48:01 -0700 Subject: [PATCH 1/2] fix: update path resolution --- .../cli/commands/claude/config/mcp_setup.py | 20 +++++++--- src/codegen/cli/commands/claude/main.py | 29 ++++++++++---- src/codegen/cli/commands/claude/utils.py | 39 +++++++++++++++++++ 3 files changed, 76 insertions(+), 12 deletions(-) create mode 100644 src/codegen/cli/commands/claude/utils.py diff --git a/src/codegen/cli/commands/claude/config/mcp_setup.py b/src/codegen/cli/commands/claude/config/mcp_setup.py index 852046fca..f3cd8be03 100644 --- a/src/codegen/cli/commands/claude/config/mcp_setup.py +++ b/src/codegen/cli/commands/claude/config/mcp_setup.py @@ -1,9 +1,9 @@ - import subprocess from codegen.cli.api.endpoints import MCP_SERVER_ENDPOINT -from codegen.cli.commands.claude.quiet_console import console from codegen.cli.auth.token_manager import get_current_token +from codegen.cli.commands.claude.quiet_console import console +from codegen.cli.commands.claude.utils import resolve_claude_path def add_codegen_mcp_server(): @@ -14,9 +14,14 @@ def add_codegen_mcp_server(): console.print("⚠️ No authentication token found. Please run 'codegen login' first.", style="yellow") return + claude_path = resolve_claude_path() + if not claude_path: + console.print("⚠️ 'claude' CLI not found to add MCP server", style="yellow") + return + add_result = subprocess.run( [ - "claude", + claude_path, "mcp", "add", "--transport", @@ -45,13 +50,18 @@ def add_codegen_mcp_server(): def cleanup_codegen_mcp_server(): try: + claude_path = resolve_claude_path() + if not claude_path: + # Silently skip if claude is not found during cleanup + return + subprocess.run( [ - "claude", + claude_path, "mcp", "remove", "codegen-tools", ], ) except Exception as e: - console.print(f"⚠️ Error removing MCP server: {e}", style="yellow") \ No newline at end of file + console.print(f"⚠️ Error removing MCP server: {e}", style="yellow") diff --git a/src/codegen/cli/commands/claude/main.py b/src/codegen/cli/commands/claude/main.py index 5f7d457d4..afe69e504 100644 --- a/src/codegen/cli/commands/claude/main.py +++ b/src/codegen/cli/commands/claude/main.py @@ -16,13 +16,14 @@ from codegen.cli.auth.token_manager import get_current_token from codegen.cli.commands.claude.claude_log_watcher import ClaudeLogWatcherManager from codegen.cli.commands.claude.claude_session_api import ( - update_claude_session_status, - generate_session_id, create_claude_session, + generate_session_id, + update_claude_session_status, ) from codegen.cli.commands.claude.config.mcp_setup import add_codegen_mcp_server, cleanup_codegen_mcp_server -from codegen.cli.commands.claude.hooks import cleanup_claude_hook, ensure_claude_hook, get_codegen_url, SESSION_FILE +from codegen.cli.commands.claude.hooks import SESSION_FILE, cleanup_claude_hook, ensure_claude_hook, get_codegen_url from codegen.cli.commands.claude.quiet_console import console +from codegen.cli.commands.claude.utils import resolve_claude_path from codegen.cli.rich.spinners import create_spinner from codegen.cli.utils.org import resolve_org_id @@ -125,10 +126,24 @@ def _run_claude_interactive(resolved_org_id: int, no_mcp: bool | None) -> None: # Initialize log watcher manager log_watcher_manager = ClaudeLogWatcherManager() - # Test if Claude Code is accessible first - console.print("🔍 Testing Claude Code accessibility...", style="blue") + # Resolve Claude CLI path and test accessibility + claude_path = resolve_claude_path() + if not claude_path: + console.print("❌ Claude Code CLI not found.", style="red") + console.print( + "💡 If you migrated a local install, ensure `~/.claude/local/claude` exists, or add it to PATH.", + style="dim", + ) + console.print( + "💡 Otherwise install globally via npm (e.g., `npm i -g claude`) or run `claude /migrate`.", + style="dim", + ) + update_claude_session_status(session_id, "ERROR", resolved_org_id) + raise typer.Exit(1) + + console.print(f"🔍 Using Claude CLI at: {claude_path}", style="blue") try: - test_result = subprocess.run(["claude", "--version"], capture_output=True, text=True, timeout=10) + test_result = subprocess.run([claude_path, "--version"], capture_output=True, text=True, timeout=10) if test_result.returncode == 0: console.print(f"✅ Claude Code found: {test_result.stdout.strip()}", style="green") else: @@ -153,7 +168,7 @@ def _run_claude_interactive(resolved_org_id: int, no_mcp: bool | None) -> None: url = get_codegen_url(session_id) console.print(f"\n🔵 Codegen URL: {url}\n", style="bold blue") - process = subprocess.Popen(["claude", "--session-id", session_id]) + process = subprocess.Popen([claude_path, "--session-id", session_id]) # Start log watcher for the session console.print("📋 Starting log watcher...", style="blue") diff --git a/src/codegen/cli/commands/claude/utils.py b/src/codegen/cli/commands/claude/utils.py new file mode 100644 index 000000000..dda7ae4c8 --- /dev/null +++ b/src/codegen/cli/commands/claude/utils.py @@ -0,0 +1,39 @@ +"""Utility functions for Claude CLI integration.""" + +import os +from shutil import which + + +def resolve_claude_path() -> str | None: + """Resolve the path to the Claude Code CLI. + + Tries PATH first, then common local install locations created by `claude /migrate`. + + Returns: + Path to the claude executable if found, None otherwise. + """ + # 1) Check system PATH first + path_from_path = which("claude") + if path_from_path: + return path_from_path + + # 2) Check common local install locations + home = os.path.expanduser("~") + candidates = [ + # Local install created by `claude /migrate` + os.path.join(home, ".claude", "local", "claude"), + os.path.join(home, ".claude", "local", "node_modules", ".bin", "claude"), + # Common global install locations + "/usr/local/bin/claude", + "/opt/homebrew/bin/claude", # Homebrew on Apple Silicon + ] + + for candidate in candidates: + try: + if os.path.isfile(candidate) and os.access(candidate, os.X_OK): + return candidate + except Exception: + # Best-effort checks only; ignore filesystem errors + pass + + return None \ No newline at end of file From bc1142b18b692c726a3e9f07970fba71bed09ba8 Mon Sep 17 00:00:00 2001 From: Rushil Patel Date: Thu, 21 Aug 2025 11:52:27 -0700 Subject: [PATCH 2/2] nit: newline --- src/codegen/cli/commands/claude/utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/codegen/cli/commands/claude/utils.py b/src/codegen/cli/commands/claude/utils.py index dda7ae4c8..b8fb06049 100644 --- a/src/codegen/cli/commands/claude/utils.py +++ b/src/codegen/cli/commands/claude/utils.py @@ -8,7 +8,7 @@ def resolve_claude_path() -> str | None: """Resolve the path to the Claude Code CLI. Tries PATH first, then common local install locations created by `claude /migrate`. - + Returns: Path to the claude executable if found, None otherwise. """ @@ -36,4 +36,4 @@ def resolve_claude_path() -> str | None: # Best-effort checks only; ignore filesystem errors pass - return None \ No newline at end of file + return None