129 lines
4.4 KiB
Python
129 lines
4.4 KiB
Python
import os
|
|
import shutil
|
|
import subprocess
|
|
from pathlib import Path
|
|
from typing import List
|
|
|
|
import psutil
|
|
import typer
|
|
import uvicorn
|
|
from dotenv import load_dotenv, set_key
|
|
from mcp.server.fastmcp import FastMCP
|
|
from rich.panel import Panel
|
|
from rich.prompt import Confirm
|
|
|
|
from skyvern.utils import detect_os
|
|
|
|
from .console import console
|
|
|
|
run_app = typer.Typer()
|
|
|
|
mcp = FastMCP("Skyvern")
|
|
|
|
|
|
def get_pids_on_port(port: int) -> List[int]:
|
|
"""Return a list of PIDs listening on the given port."""
|
|
pids = []
|
|
try:
|
|
for conn in psutil.net_connections(kind="inet"):
|
|
if conn.laddr and conn.laddr.port == port and conn.pid:
|
|
pids.append(conn.pid)
|
|
except Exception:
|
|
pass
|
|
return list(set(pids))
|
|
|
|
|
|
def kill_pids(pids: List[int]) -> None:
|
|
"""Kill the given list of PIDs in a cross-platform way."""
|
|
host_system = detect_os()
|
|
for pid in pids:
|
|
try:
|
|
if host_system in {"windows", "wsl"}:
|
|
subprocess.run(f"taskkill /PID {pid} /F", shell=True, check=False)
|
|
else:
|
|
os.kill(pid, 9)
|
|
except Exception:
|
|
console.print(f"[red]Failed to kill process {pid}[/red]")
|
|
|
|
|
|
@run_app.command(name="server")
|
|
def run_server() -> None:
|
|
"""Run the Skyvern API server."""
|
|
load_dotenv()
|
|
load_dotenv(".env")
|
|
from skyvern.config import settings
|
|
|
|
port = settings.PORT
|
|
console.print(Panel(f"[bold green]Starting Skyvern API Server on port {port}...", border_style="green"))
|
|
uvicorn.run(
|
|
"skyvern.forge.api_app:app",
|
|
host="0.0.0.0",
|
|
port=port,
|
|
log_level="info",
|
|
)
|
|
|
|
|
|
@run_app.command(name="ui")
|
|
def run_ui() -> None:
|
|
"""Run the Skyvern UI server."""
|
|
console.print(Panel("[bold blue]Starting Skyvern UI Server...[/bold blue]", border_style="blue"))
|
|
try:
|
|
with console.status("[bold green]Checking for existing process on port 8080...") as status:
|
|
pids = get_pids_on_port(8080)
|
|
if pids:
|
|
status.stop()
|
|
response = Confirm.ask("Process already running on port 8080. [yellow]Kill it?[/yellow]")
|
|
if response:
|
|
kill_pids(pids)
|
|
console.print("✅ [green]Process killed.[/green]")
|
|
else:
|
|
console.print("[yellow]UI server not started. Process already running on port 8080.[/yellow]")
|
|
return
|
|
status.stop()
|
|
except Exception as e: # pragma: no cover - CLI safeguards
|
|
console.print(f"[red]Error checking for process: {e}[/red]")
|
|
|
|
current_dir = Path(__file__).parent.parent.parent
|
|
frontend_dir = current_dir / "skyvern-frontend"
|
|
if not frontend_dir.exists():
|
|
console.print(
|
|
f"[bold red]ERROR: Skyvern Frontend directory not found at [path]{frontend_dir}[/path]. Are you in the right repo?[/bold red]"
|
|
)
|
|
return
|
|
|
|
if not (frontend_dir / ".env").exists():
|
|
console.print("[bold blue]Setting up frontend .env file...[/bold blue]")
|
|
shutil.copy(frontend_dir / ".env.example", frontend_dir / ".env")
|
|
main_env_path = current_dir / ".env"
|
|
if main_env_path.exists():
|
|
load_dotenv(main_env_path)
|
|
skyvern_api_key = os.getenv("SKYVERN_API_KEY")
|
|
if skyvern_api_key:
|
|
frontend_env_path = frontend_dir / ".env"
|
|
set_key(str(frontend_env_path), "VITE_SKYVERN_API_KEY", skyvern_api_key)
|
|
else:
|
|
console.print("[red]ERROR: SKYVERN_API_KEY not found in .env file[/red]")
|
|
else:
|
|
console.print("[red]ERROR: .env file not found[/red]")
|
|
|
|
console.print("✅ [green]Successfully set up frontend .env file[/green]")
|
|
|
|
os.chdir(frontend_dir)
|
|
|
|
try:
|
|
console.print("📦 [bold blue]Running npm install...[/bold blue]")
|
|
subprocess.run("npm install --silent", shell=True, check=True)
|
|
console.print("✅ [green]npm install complete.[/green]")
|
|
console.print("🚀 [bold blue]Starting npm UI server...[/bold blue]")
|
|
subprocess.run("npm run start", shell=True, check=True)
|
|
except subprocess.CalledProcessError as e:
|
|
console.print(f"[bold red]Error running UI server: {e}[/bold red]")
|
|
return
|
|
|
|
|
|
@run_app.command(name="mcp")
|
|
def run_mcp() -> None:
|
|
"""Run the MCP server."""
|
|
console.print(Panel("[bold green]Starting MCP Server...[/bold green]", border_style="green"))
|
|
mcp.run(transport="stdio")
|