diff --git a/server/main.py b/server/main.py index f48e9f2..5efd4af 100644 --- a/server/main.py +++ b/server/main.py @@ -120,9 +120,11 @@ async def setup_status(): # Check for Claude CLI claude_cli = shutil.which("claude") is not None - # Check for credentials file - credentials_path = Path.home() / ".claude" / ".credentials.json" - credentials = credentials_path.exists() + # Check for Claude CLI configuration directory + # Note: Claude CLI no longer stores credentials in ~/.claude/.credentials.json + # The existence of ~/.claude indicates the CLI has been configured + claude_dir = Path.home() / ".claude" + credentials = claude_dir.exists() and claude_dir.is_dir() # Check for Node.js and npm node = shutil.which("node") is not None diff --git a/server/services/process_manager.py b/server/services/process_manager.py index d2b4f0b..31352fc 100644 --- a/server/services/process_manager.py +++ b/server/services/process_manager.py @@ -36,6 +36,47 @@ SENSITIVE_PATTERNS = [ r'aws[_-]?secret[=:][^\s]+', ] +# Patterns that indicate Claude CLI authentication errors +AUTH_ERROR_PATTERNS = [ + r"not\s+logged\s+in", + r"not\s+authenticated", + r"authentication\s+(failed|required|error)", + r"login\s+required", + r"please\s+(run\s+)?['\"]?claude\s+login", + r"unauthorized", + r"invalid\s+(token|credential|api.?key)", + r"expired\s+(token|session|credential)", + r"could\s+not\s+authenticate", + r"sign\s+in\s+(to|required)", +] + + +def is_auth_error(text: str) -> bool: + """Check if text contains Claude CLI authentication error messages.""" + if not text: + return False + text_lower = text.lower() + for pattern in AUTH_ERROR_PATTERNS: + if re.search(pattern, text_lower): + return True + return False + + +AUTH_ERROR_HELP = """ +================================================================================ + AUTHENTICATION ERROR DETECTED +================================================================================ + +Claude CLI requires authentication to work. + +To fix this, run: + claude login + +This will open a browser window to sign in. +After logging in, try starting the agent again. +================================================================================ +""" + def sanitize_output(line: str) -> str: """Remove sensitive information from output lines.""" @@ -185,6 +226,9 @@ class AgentProcessManager: if not self.process or not self.process.stdout: return + auth_error_detected = False + output_buffer = [] # Buffer recent lines for auth error detection + try: loop = asyncio.get_running_loop() while True: @@ -198,6 +242,18 @@ class AgentProcessManager: decoded = line.decode("utf-8", errors="replace").rstrip() sanitized = sanitize_output(decoded) + # Buffer recent output for auth error detection + output_buffer.append(decoded) + if len(output_buffer) > 20: + output_buffer.pop(0) + + # Check for auth errors + if not auth_error_detected and is_auth_error(decoded): + auth_error_detected = True + # Broadcast auth error help message + for help_line in AUTH_ERROR_HELP.strip().split('\n'): + await self._broadcast_output(help_line) + await self._broadcast_output(sanitized) except asyncio.CancelledError: @@ -209,6 +265,12 @@ class AgentProcessManager: if self.process and self.process.poll() is not None: exit_code = self.process.returncode if exit_code != 0 and self.status == "running": + # Check buffered output for auth errors if we haven't detected one yet + if not auth_error_detected: + combined_output = '\n'.join(output_buffer) + if is_auth_error(combined_output): + for help_line in AUTH_ERROR_HELP.strip().split('\n'): + await self._broadcast_output(help_line) self.status = "crashed" elif self.status == "running": self.status = "stopped" diff --git a/start_ui.sh b/start_ui.sh index 644db74..895c4dd 100644 --- a/start_ui.sh +++ b/start_ui.sh @@ -9,6 +9,27 @@ echo " AutoCoder UI" echo "====================================" echo "" +# Check if Claude CLI is installed +if ! command -v claude &> /dev/null; then + echo "[!] Claude CLI not found" + echo "" + echo " The agent requires Claude CLI to work." + echo " Install it from: https://claude.ai/download" + echo "" + echo " After installing, run: claude login" + echo "" +else + echo "[OK] Claude CLI found" + # Note: Claude CLI no longer stores credentials in ~/.claude/.credentials.json + # We can't reliably check auth status without making an API call + if [ -d "$HOME/.claude" ]; then + echo " (If you're not logged in, run: claude login)" + else + echo "[!] Claude CLI not configured - run 'claude login' first" + fi +fi +echo "" + # Check if Python is available if ! command -v python3 &> /dev/null; then if ! command -v python &> /dev/null; then