feat: Add authentication error handling to start.py

Add detection and helpful messaging for Claude CLI authentication errors
in the Python launcher, complementing the shell script improvements.

Changes:
- Add is_auth_error() helper with regex patterns for common auth errors
- Add print_auth_error_help() for consistent, actionable error messages
- Update run_spec_creation() to capture stderr and detect auth failures
- Update run_agent() to capture stderr and detect auth failures
- Both functions now provide helpful "run claude login" guidance

Error patterns detected:
- "not logged in" / "not authenticated"
- "authentication failed/required/error"
- "login required"
- "please run claude login"
- "unauthorized"
- "invalid token/credential/api key"
- "expired token/session/credential"

This aligns the Python UX with the shell script's non-blocking warning
approach while adding proactive error detection.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
mantarayDigital
2026-01-08 07:30:41 +02:00
parent 81dbc4bc16
commit 780cfd343f

View File

@@ -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.")