diff --git a/start.py b/start.py index 0236122..455bc97 100644 --- a/start.py +++ b/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.")