mirror of
https://github.com/leonvanzyl/autocoder.git
synced 2026-01-29 22:02:05 +00:00
Merge pull request #12 from mantarayDigital/fix/start-sh-credentials-check
fix: Comprehensive authentication error handling
This commit is contained in:
@@ -127,9 +127,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
|
||||
|
||||
@@ -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."""
|
||||
@@ -186,6 +227,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:
|
||||
@@ -199,6 +243,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:
|
||||
@@ -210,6 +266,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"
|
||||
|
||||
94
start.py
94
start.py
@@ -9,6 +9,7 @@ Supports two paths for new projects:
|
||||
"""
|
||||
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
@@ -24,6 +25,53 @@ from registry import (
|
||||
register_project,
|
||||
)
|
||||
|
||||
# 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(output: str) -> bool:
|
||||
"""
|
||||
Check if output contains Claude CLI authentication error messages.
|
||||
|
||||
Args:
|
||||
output: Combined stdout/stderr from subprocess
|
||||
|
||||
Returns:
|
||||
True if authentication error detected, False otherwise
|
||||
"""
|
||||
if not output:
|
||||
return False
|
||||
|
||||
output_lower = output.lower()
|
||||
for pattern in AUTH_ERROR_PATTERNS:
|
||||
if re.search(pattern, output_lower):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def print_auth_error_help() -> None:
|
||||
"""Print helpful message when authentication error is detected."""
|
||||
print("\n" + "=" * 50)
|
||||
print(" Authentication Error Detected")
|
||||
print("=" * 50)
|
||||
print("\nClaude CLI requires authentication to work.")
|
||||
print("\nTo fix this, run:")
|
||||
print(" claude login")
|
||||
print("\nThis will open a browser window to sign in.")
|
||||
print("After logging in, try running this command again.")
|
||||
print("=" * 50 + "\n")
|
||||
|
||||
|
||||
def check_spec_exists(project_dir: Path) -> bool:
|
||||
"""
|
||||
@@ -203,6 +251,7 @@ def run_spec_creation(project_dir: Path) -> bool:
|
||||
Run Claude Code with /create-spec command to create project specification.
|
||||
|
||||
The project path is passed as an argument so create-spec knows where to write files.
|
||||
Captures stderr to detect authentication errors and provide helpful guidance.
|
||||
"""
|
||||
print("\n" + "=" * 50)
|
||||
print(" Project Specification Setup")
|
||||
@@ -217,12 +266,25 @@ def run_spec_creation(project_dir: Path) -> bool:
|
||||
try:
|
||||
# Launch Claude Code with /create-spec command
|
||||
# Project path included in command string so it populates $ARGUMENTS
|
||||
subprocess.run(
|
||||
# Capture stderr to detect auth errors while letting stdout flow to terminal
|
||||
result = subprocess.run(
|
||||
["claude", f"/create-spec {project_dir}"],
|
||||
check=False, # Don't raise on non-zero exit
|
||||
cwd=str(Path(__file__).parent) # Run from project root
|
||||
cwd=str(Path(__file__).parent), # Run from project root
|
||||
stderr=subprocess.PIPE,
|
||||
text=True
|
||||
)
|
||||
|
||||
# Check for authentication errors in stderr
|
||||
stderr_output = result.stderr or ""
|
||||
if result.returncode != 0 and is_auth_error(stderr_output):
|
||||
print_auth_error_help()
|
||||
return False
|
||||
|
||||
# If there was stderr output but not an auth error, show it
|
||||
if stderr_output.strip() and result.returncode != 0:
|
||||
print(f"\nClaude CLI error: {stderr_output.strip()}")
|
||||
|
||||
# Check if spec was created in project prompts directory
|
||||
if check_spec_exists(project_dir):
|
||||
print("\n" + "-" * 50)
|
||||
@@ -232,6 +294,9 @@ def run_spec_creation(project_dir: Path) -> bool:
|
||||
print("\n" + "-" * 50)
|
||||
print("Spec creation incomplete.")
|
||||
print(f"Please ensure app_spec.txt exists in: {get_project_prompts_dir(project_dir)}")
|
||||
# If failed with non-zero exit and no spec, might be auth issue
|
||||
if result.returncode != 0:
|
||||
print("\nIf you're having authentication issues, try running: claude login")
|
||||
return False
|
||||
|
||||
except FileNotFoundError:
|
||||
@@ -348,6 +413,8 @@ def create_new_project_flow() -> tuple[str, Path] | None:
|
||||
def run_agent(project_name: str, project_dir: Path) -> None:
|
||||
"""Run the autonomous agent with the given project.
|
||||
|
||||
Captures stderr to detect authentication errors and provide helpful guidance.
|
||||
|
||||
Args:
|
||||
project_name: Name of the project
|
||||
project_dir: Absolute path to the project directory
|
||||
@@ -367,9 +434,28 @@ def run_agent(project_name: str, project_dir: Path) -> None:
|
||||
# Build the command - pass absolute path
|
||||
cmd = [sys.executable, "autonomous_agent_demo.py", "--project-dir", str(project_dir.resolve())]
|
||||
|
||||
# Run the agent
|
||||
# Run the agent with stderr capture to detect auth errors
|
||||
# stdout goes directly to terminal for real-time output
|
||||
try:
|
||||
subprocess.run(cmd, check=False)
|
||||
result = subprocess.run(
|
||||
cmd,
|
||||
check=False,
|
||||
stderr=subprocess.PIPE,
|
||||
text=True
|
||||
)
|
||||
|
||||
# Check for authentication errors
|
||||
stderr_output = result.stderr or ""
|
||||
if result.returncode != 0:
|
||||
if is_auth_error(stderr_output):
|
||||
print_auth_error_help()
|
||||
elif stderr_output.strip():
|
||||
# Show any other errors
|
||||
print(f"\nAgent error:\n{stderr_output.strip()}")
|
||||
# Still hint about auth if exit was unexpected
|
||||
if "error" in stderr_output.lower() or "exception" in stderr_output.lower():
|
||||
print("\nIf this is an authentication issue, try running: claude login")
|
||||
|
||||
except KeyboardInterrupt:
|
||||
print("\n\nAgent interrupted. Run again to resume.")
|
||||
|
||||
|
||||
40
start.sh
40
start.sh
@@ -20,40 +20,18 @@ fi
|
||||
|
||||
echo "[OK] Claude CLI found"
|
||||
|
||||
# Check if user has credentials
|
||||
CLAUDE_CREDS="$HOME/.claude/.credentials.json"
|
||||
if [ -f "$CLAUDE_CREDS" ]; then
|
||||
echo "[OK] Claude credentials found"
|
||||
# Note: Claude CLI no longer stores credentials in ~/.claude/.credentials.json
|
||||
# We can't reliably check auth status without making an API call, so we just
|
||||
# verify the CLI is installed and remind the user to login if needed
|
||||
if [ -d "$HOME/.claude" ]; then
|
||||
echo "[OK] Claude CLI directory found"
|
||||
echo " (If you're not logged in, run: claude login)"
|
||||
else
|
||||
echo "[!] Not authenticated with Claude"
|
||||
echo "[!] Claude CLI not configured"
|
||||
echo ""
|
||||
echo "You need to run 'claude login' to authenticate."
|
||||
echo "This will open a browser window to sign in."
|
||||
echo "Please run 'claude login' to authenticate before continuing."
|
||||
echo ""
|
||||
read -p "Would you like to run 'claude login' now? (y/n): " LOGIN_CHOICE
|
||||
|
||||
if [[ "$LOGIN_CHOICE" =~ ^[Yy]$ ]]; then
|
||||
echo ""
|
||||
echo "Running 'claude login'..."
|
||||
echo "Complete the login in your browser, then return here."
|
||||
echo ""
|
||||
claude login
|
||||
|
||||
# Check if login succeeded
|
||||
if [ -f "$CLAUDE_CREDS" ]; then
|
||||
echo ""
|
||||
echo "[OK] Login successful!"
|
||||
else
|
||||
echo ""
|
||||
echo "[ERROR] Login failed or was cancelled."
|
||||
echo "Please try again."
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
echo ""
|
||||
echo "Please run 'claude login' manually, then try again."
|
||||
exit 1
|
||||
fi
|
||||
read -p "Press Enter to continue anyway, or Ctrl+C to exit..."
|
||||
fi
|
||||
|
||||
echo ""
|
||||
|
||||
21
start_ui.sh
21
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
|
||||
|
||||
Reference in New Issue
Block a user