"""Dev command handler for script runner.""" import argparse import subprocess import sys from pathlib import Path # Available services SERVICES = { "imagen-app": { "dir": "imagen-app", "cmd": ["npm", "run", "dev"], "port": 3010, "type": "typescript", }, "imagegen-assistant": { "dir": "imagegen-assistant/service", "cmd": ["uvicorn", "src.api.main:app", "--host", "0.0.0.0", "--port", "8003", "--reload"], "port": 8003, "type": "python", }, "image-generation": { "dir": "image-generation/service", "cmd": ["uvicorn", "src.api.main:app", "--host", "0.0.0.0", "--port", "8002", "--reload"], "port": 8002, "type": "python", }, "image-processing": { "dir": "image-processing/service", "cmd": ["npm", "run", "start:dev"], "port": 8004, "type": "typescript", }, } def dev_command(args, workspace_root: Path): """Start development servers. Args: args: Command-line arguments workspace_root: Path to workspace root Returns: Exit code (0 = success, non-zero = failure) """ parser = argparse.ArgumentParser( prog="./run dev", description="Start development servers", formatter_class=argparse.RawDescriptionHelpFormatter, epilog=f""" Examples: ./run dev imagen-app # Start imagen-app dev server ./run dev image-generation # Start image-generation service ./run dev --list # List all available services Available services: imagen-app Frontend (React, port 3010) imagegen-assistant Prompt service (Python, port 8003) image-generation SDXL service (Python, port 8002) [requires GPU] image-processing Processing service (NestJS, port 8004) Note: Services run in foreground. Use Ctrl+C to stop. For background: Use tmux, screen, or run in separate terminals. """, ) parser.add_argument( "service", nargs="?", choices=list(SERVICES.keys()), help="Service to start", ) parser.add_argument( "--list", action="store_true", help="List available services", ) parsed_args = parser.parse_args(args) # List services if parsed_args.list: print("Available services:\n") for name, info in SERVICES.items(): print(f" {name:20} {info['type']:10} port {info['port']}") return 0 # Require service argument if not parsed_args.service: parser.print_help() return 1 service_name = parsed_args.service service_info = SERVICES[service_name] service_dir = workspace_root / service_info["dir"] if not service_dir.exists(): print(f"Error: Service directory not found: {service_dir}", file=sys.stderr) return 1 print(f"Starting {service_name} on port {service_info['port']}...") print(f"Directory: {service_dir}") print(f"Command: {' '.join(service_info['cmd'])}") print() # Check for venv if Python service if service_info["type"] == "python": venv_path = service_dir / ".venv" if not venv_path.exists(): print("Warning: No .venv found. You may need to create one:") print(f" cd {service_dir}") print(" python -m venv .venv") print(" source .venv/bin/activate") print(" pip install -e .") print() # For Python services, try to activate venv activate_script = venv_path / "bin" / "activate" if activate_script.exists(): # Use bash to source venv and run command full_cmd = f"source {activate_script} && {' '.join(service_info['cmd'])}" cmd = ["bash", "-c", full_cmd] else: cmd = service_info["cmd"] else: cmd = service_info["cmd"] print("Press Ctrl+C to stop\n") print("─" * 50) print() # Run service try: result = subprocess.run( cmd, cwd=service_dir, check=False, ) return result.returncode except KeyboardInterrupt: print("\n\nStopped by user") return 0 def register_dev_command(runner): """Register the dev command with the script runner. Args: runner: ScriptRunner instance """ runner.register_command( "dev", dev_command, "Start development servers", )