diff --git a/apps/backend/cli/utils.py b/apps/backend/cli/utils.py index 25b92ca2..b9969020 100644 --- a/apps/backend/cli/utils.py +++ b/apps/backend/cli/utils.py @@ -15,7 +15,46 @@ if str(_PARENT_DIR) not in sys.path: sys.path.insert(0, str(_PARENT_DIR)) from core.auth import get_auth_token, get_auth_token_source -from dotenv import load_dotenv + + +def import_dotenv(): + """ + Import and return load_dotenv with helpful error message if not installed. + + This centralized function ensures consistent error messaging across all + runner scripts when python-dotenv is not available. + + Returns: + The load_dotenv function + + Raises: + SystemExit: If dotenv cannot be imported, with helpful installation instructions. + """ + try: + from dotenv import load_dotenv as _load_dotenv + + return _load_dotenv + except ImportError: + sys.exit( + "Error: Required Python package 'python-dotenv' is not installed.\n" + "\n" + "This usually means you're not using the virtual environment.\n" + "\n" + "To fix this:\n" + "1. From the 'apps/backend/' directory, activate the venv:\n" + " source .venv/bin/activate # Linux/macOS\n" + " .venv\\Scripts\\activate # Windows\n" + "\n" + "2. Or install dependencies directly:\n" + " pip install python-dotenv\n" + " pip install -r requirements.txt\n" + "\n" + f"Current Python: {sys.executable}\n" + ) + + +# Load .env with helpful error if dependencies not installed +load_dotenv = import_dotenv() from graphiti_config import get_graphiti_status from linear_integration import LinearManager from linear_updater import is_linear_enabled diff --git a/apps/backend/runners/github/runner.py b/apps/backend/runners/github/runner.py index 669030e4..b3934cdc 100644 --- a/apps/backend/runners/github/runner.py +++ b/apps/backend/runners/github/runner.py @@ -56,8 +56,10 @@ if sys.platform == "win32": # Add backend to path sys.path.insert(0, str(Path(__file__).parent.parent.parent)) -# Load .env file -from dotenv import load_dotenv +# Load .env file with centralized error handling +from cli.utils import import_dotenv + +load_dotenv = import_dotenv() env_file = Path(__file__).parent.parent.parent / ".env" if env_file.exists(): diff --git a/apps/backend/runners/gitlab/runner.py b/apps/backend/runners/gitlab/runner.py index c2a0be32..d4f61827 100644 --- a/apps/backend/runners/gitlab/runner.py +++ b/apps/backend/runners/gitlab/runner.py @@ -26,8 +26,10 @@ from pathlib import Path # Add backend to path sys.path.insert(0, str(Path(__file__).parent.parent.parent)) -# Load .env file -from dotenv import load_dotenv +# Load .env file with centralized error handling +from cli.utils import import_dotenv + +load_dotenv = import_dotenv() env_file = Path(__file__).parent.parent.parent / ".env" if env_file.exists(): diff --git a/apps/backend/runners/ideation_runner.py b/apps/backend/runners/ideation_runner.py index 4e74f683..9b914456 100644 --- a/apps/backend/runners/ideation_runner.py +++ b/apps/backend/runners/ideation_runner.py @@ -26,8 +26,10 @@ from pathlib import Path # Add auto-claude to path sys.path.insert(0, str(Path(__file__).parent.parent)) -# Load .env file from auto-claude/ directory -from dotenv import load_dotenv +# Load .env file with centralized error handling +from cli.utils import import_dotenv + +load_dotenv = import_dotenv() env_file = Path(__file__).parent.parent / ".env" if env_file.exists(): diff --git a/apps/backend/runners/insights_runner.py b/apps/backend/runners/insights_runner.py index 22c2d9ad..bd4bf362 100644 --- a/apps/backend/runners/insights_runner.py +++ b/apps/backend/runners/insights_runner.py @@ -15,8 +15,10 @@ from pathlib import Path # Add auto-claude to path sys.path.insert(0, str(Path(__file__).parent.parent)) -# Load .env file from auto-claude/ directory -from dotenv import load_dotenv +# Load .env file with centralized error handling +from cli.utils import import_dotenv + +load_dotenv = import_dotenv() env_file = Path(__file__).parent.parent / ".env" if env_file.exists(): diff --git a/apps/backend/runners/roadmap_runner.py b/apps/backend/runners/roadmap_runner.py index 4a31c025..06625add 100644 --- a/apps/backend/runners/roadmap_runner.py +++ b/apps/backend/runners/roadmap_runner.py @@ -20,8 +20,10 @@ from pathlib import Path # Add auto-claude to path sys.path.insert(0, str(Path(__file__).parent.parent)) -# Load .env file from auto-claude/ directory -from dotenv import load_dotenv +# Load .env file with centralized error handling +from cli.utils import import_dotenv + +load_dotenv = import_dotenv() env_file = Path(__file__).parent.parent / ".env" if env_file.exists(): diff --git a/apps/backend/runners/spec_runner.py b/apps/backend/runners/spec_runner.py index 0bda6db1..4c5a4bba 100644 --- a/apps/backend/runners/spec_runner.py +++ b/apps/backend/runners/spec_runner.py @@ -26,11 +26,11 @@ The AI considers: - Risk factors and edge cases Usage: - python auto-claude/spec_runner.py --task "Add user authentication" - python auto-claude/spec_runner.py --interactive - python auto-claude/spec_runner.py --continue 001-feature - python auto-claude/spec_runner.py --task "Fix button color" --complexity simple - python auto-claude/spec_runner.py --task "Simple fix" --no-ai-assessment + python runners/spec_runner.py --task "Add user authentication" + python runners/spec_runner.py --interactive + python runners/spec_runner.py --continue 001-feature + python runners/spec_runner.py --task "Fix button color" --complexity simple + python runners/spec_runner.py --task "Simple fix" --no-ai-assessment """ import sys @@ -81,8 +81,10 @@ if sys.platform == "win32": # Add auto-claude to path (parent of runners/) sys.path.insert(0, str(Path(__file__).parent.parent)) -# Load .env file -from dotenv import load_dotenv +# Load .env file with centralized error handling +from cli.utils import import_dotenv + +load_dotenv = import_dotenv() env_file = Path(__file__).parent.parent / ".env" dev_env_file = Path(__file__).parent.parent.parent / "dev" / "auto-claude" / ".env" diff --git a/guides/CLI-USAGE.md b/guides/CLI-USAGE.md index c0c50785..dd41f507 100644 --- a/guides/CLI-USAGE.md +++ b/guides/CLI-USAGE.md @@ -74,16 +74,16 @@ All commands below should be run from the `apps/backend/` directory: source .venv/bin/activate # Create a spec interactively -python spec_runner.py --interactive +python runners/spec_runner.py --interactive # Or with a task description -python spec_runner.py --task "Add user authentication with OAuth" +python runners/spec_runner.py --task "Add user authentication with OAuth" # Force a specific complexity level -python spec_runner.py --task "Fix button color" --complexity simple +python runners/spec_runner.py --task "Fix button color" --complexity simple # Continue an interrupted spec -python spec_runner.py --continue 001-feature +python runners/spec_runner.py --continue 001-feature ``` ### Complexity Tiers