|
|
|
|
|
|
|
|
import subprocess |
|
|
import sys |
|
|
import platform |
|
|
import os |
|
|
import json |
|
|
|
|
|
IS_WINDOWS = platform.system() == "Windows" |
|
|
PROGRESS_FILE = ".setup_progress" |
|
|
|
|
|
|
|
|
|
|
|
class Colors: |
|
|
HEADER = "\033[95m" |
|
|
BLUE = "\033[94m" |
|
|
CYAN = "\033[96m" |
|
|
GREEN = "\033[92m" |
|
|
YELLOW = "\033[93m" |
|
|
RED = "\033[91m" |
|
|
ENDC = "\033[0m" |
|
|
BOLD = "\033[1m" |
|
|
UNDERLINE = "\033[4m" |
|
|
|
|
|
|
|
|
def load_progress(): |
|
|
"""Loads the last saved step and data from setup.""" |
|
|
if os.path.exists(PROGRESS_FILE): |
|
|
with open(PROGRESS_FILE, "r") as f: |
|
|
try: |
|
|
return json.load(f) |
|
|
except (json.JSONDecodeError, KeyError): |
|
|
return {"step": 0, "data": {}} |
|
|
return {"step": 0, "data": {}} |
|
|
|
|
|
|
|
|
def get_setup_method(): |
|
|
"""Gets the setup method chosen during setup.""" |
|
|
progress = load_progress() |
|
|
return progress.get("data", {}).get("setup_method") |
|
|
|
|
|
|
|
|
def check_docker_compose_up(): |
|
|
result = subprocess.run( |
|
|
["docker", "compose", "ps", "-q"], |
|
|
capture_output=True, |
|
|
text=True, |
|
|
shell=IS_WINDOWS, |
|
|
) |
|
|
return len(result.stdout.strip()) > 0 |
|
|
|
|
|
|
|
|
def print_manual_instructions(): |
|
|
"""Prints instructions for manually starting Suna services.""" |
|
|
print(f"\n{Colors.BLUE}{Colors.BOLD}π Manual Startup Instructions{Colors.ENDC}\n") |
|
|
|
|
|
print("To start Suna, you need to run these commands in separate terminals:\n") |
|
|
|
|
|
print(f"{Colors.BOLD}1. Start Infrastructure (in project root):{Colors.ENDC}") |
|
|
print(f"{Colors.CYAN} docker compose up redis rabbitmq -d{Colors.ENDC}\n") |
|
|
|
|
|
print(f"{Colors.BOLD}2. Start Frontend (in a new terminal):{Colors.ENDC}") |
|
|
print(f"{Colors.CYAN} cd frontend && npm run dev{Colors.ENDC}\n") |
|
|
|
|
|
print(f"{Colors.BOLD}3. Start Backend (in a new terminal):{Colors.ENDC}") |
|
|
print(f"{Colors.CYAN} cd backend && uv run api.py{Colors.ENDC}\n") |
|
|
|
|
|
print(f"{Colors.BOLD}4. Start Background Worker (in a new terminal):{Colors.ENDC}") |
|
|
print( |
|
|
f"{Colors.CYAN} cd backend && uv run dramatiq run_agent_background{Colors.ENDC}\n" |
|
|
) |
|
|
|
|
|
print("Once all services are running, access Suna at: http://localhost:3000\n") |
|
|
|
|
|
print( |
|
|
f"{Colors.YELLOW}π‘ Tip:{Colors.ENDC} You can use '{Colors.CYAN}./start.py{Colors.ENDC}' to start/stop the infrastructure services." |
|
|
) |
|
|
|
|
|
|
|
|
def main(): |
|
|
setup_method = get_setup_method() |
|
|
|
|
|
if "--help" in sys.argv: |
|
|
print("Usage: ./start.py [OPTION]") |
|
|
print("Manage Suna services based on your setup method") |
|
|
print("\nOptions:") |
|
|
print(" -f\tForce start containers without confirmation") |
|
|
print(" --help\tShow this help message") |
|
|
return |
|
|
|
|
|
|
|
|
if not setup_method: |
|
|
print( |
|
|
f"{Colors.YELLOW}β οΈ Setup method not detected. Run './setup.py' first or using Docker Compose as default.{Colors.ENDC}" |
|
|
) |
|
|
setup_method = "docker" |
|
|
|
|
|
if setup_method == "manual": |
|
|
|
|
|
|
|
|
print(f"{Colors.BLUE}{Colors.BOLD}Manual Setup Detected{Colors.ENDC}") |
|
|
print("Managing infrastructure services (Redis, RabbitMQ)...\n") |
|
|
|
|
|
force = "-f" in sys.argv |
|
|
if force: |
|
|
print("Force awakened. Skipping confirmation.") |
|
|
|
|
|
is_infra_up = subprocess.run( |
|
|
["docker", "compose", "ps", "-q", "redis", "rabbitmq"], |
|
|
capture_output=True, |
|
|
text=True, |
|
|
shell=IS_WINDOWS, |
|
|
) |
|
|
is_up = len(is_infra_up.stdout.strip()) > 0 |
|
|
|
|
|
if is_up: |
|
|
action = "stop" |
|
|
msg = "π Stop infrastructure services? [y/N] " |
|
|
else: |
|
|
action = "start" |
|
|
msg = "β‘ Start infrastructure services? [Y/n] " |
|
|
|
|
|
if not force: |
|
|
response = input(msg).strip().lower() |
|
|
if action == "stop": |
|
|
if response != "y": |
|
|
print("Aborting.") |
|
|
return |
|
|
else: |
|
|
if response == "n": |
|
|
print("Aborting.") |
|
|
return |
|
|
|
|
|
if action == "stop": |
|
|
subprocess.run(["docker", "compose", "down"], shell=IS_WINDOWS) |
|
|
print(f"\n{Colors.GREEN}β
Infrastructure services stopped.{Colors.ENDC}") |
|
|
else: |
|
|
subprocess.run( |
|
|
["docker", "compose", "up", "redis", "rabbitmq", "-d"], shell=IS_WINDOWS |
|
|
) |
|
|
print(f"\n{Colors.GREEN}β
Infrastructure services started.{Colors.ENDC}") |
|
|
print_manual_instructions() |
|
|
|
|
|
else: |
|
|
print(f"{Colors.BLUE}{Colors.BOLD}Docker Setup Detected{Colors.ENDC}") |
|
|
print("Managing all Suna services with Docker Compose...\n") |
|
|
|
|
|
force = "-f" in sys.argv |
|
|
if force: |
|
|
print("Force awakened. Skipping confirmation.") |
|
|
|
|
|
is_up = check_docker_compose_up() |
|
|
|
|
|
if is_up: |
|
|
action = "stop" |
|
|
msg = "π Stop all Suna services? [y/N] " |
|
|
else: |
|
|
action = "start" |
|
|
msg = "β‘ Start all Suna services? [Y/n] " |
|
|
|
|
|
if not force: |
|
|
response = input(msg).strip().lower() |
|
|
if action == "stop": |
|
|
if response != "y": |
|
|
print("Aborting.") |
|
|
return |
|
|
else: |
|
|
if response == "n": |
|
|
print("Aborting.") |
|
|
return |
|
|
|
|
|
if action == "stop": |
|
|
subprocess.run(["docker", "compose", "down"], shell=IS_WINDOWS) |
|
|
print(f"\n{Colors.GREEN}β
All Suna services stopped.{Colors.ENDC}") |
|
|
else: |
|
|
subprocess.run(["docker", "compose", "up", "-d"], shell=IS_WINDOWS) |
|
|
print(f"\n{Colors.GREEN}β
All Suna services started.{Colors.ENDC}") |
|
|
print(f"{Colors.CYAN}π Access Suna at: http://localhost:3000{Colors.ENDC}") |
|
|
|
|
|
|
|
|
if __name__ == "__main__": |
|
|
main() |
|
|
|