2025-05-20 19:43:33 -04:00
import asyncio
import subprocess
import uuid
import typer
from rich . padding import Padding
from rich . panel import Panel
from rich . progress import Progress , SpinnerColumn , TextColumn
from rich . prompt import Confirm , Prompt
2025-11-19 17:25:33 -07:00
from skyvern . forge . forge_app_initializer import start_forge_app
2025-05-20 19:43:33 -04:00
from skyvern . utils import migrate_db
2025-10-12 10:36:24 -07:00
from skyvern . utils . env_paths import resolve_backend_env_path
2025-05-20 19:43:33 -04:00
from . browser import setup_browser_config
from . console import console
from . database import setup_postgresql
from . llm_setup import setup_llm_providers , update_or_add_env_var
from . mcp import setup_local_organization , setup_mcp
2025-12-04 21:14:48 -07:00
def init_env (
2025-05-20 19:43:33 -04:00
no_postgres : bool = typer . Option ( False , " --no-postgres " , help = " Skip starting PostgreSQL container " ) ,
2026-01-30 11:38:34 -07:00
database_string : str = typer . Option (
" " ,
" --database-string " ,
help = " Custom database connection string (e.g., postgresql+psycopg://user:password@host:port/dbname). When provided, skips Docker PostgreSQL setup. " ,
) ,
2025-12-04 21:14:48 -07:00
) - > bool :
2025-05-20 19:43:33 -04:00
""" Interactive initialization command for Skyvern. """
console . print (
Panel (
" [bold green]Welcome to Skyvern CLI Initialization![/bold green] " ,
border_style = " green " ,
expand = False ,
)
)
console . print ( " [italic]This wizard will help you set up Skyvern.[/italic] " )
2025-12-14 16:10:43 -07:00
infra_choice = Prompt . ask (
" Would you like to run Skyvern [bold blue]local[/bold blue]ly or in the [bold purple]cloud[/bold purple]? " ,
2025-05-20 19:43:33 -04:00
choices = [ " local " , " cloud " ] ,
)
2025-12-14 16:10:43 -07:00
run_local = infra_choice == " local "
2025-05-20 19:43:33 -04:00
if run_local :
2026-01-30 11:38:34 -07:00
if database_string :
console . print ( " 🔗 [bold blue]Using custom database connection...[/bold blue] " )
update_or_add_env_var ( " DATABASE_STRING " , database_string )
console . print ( " ✅ [green]Database connection string set in .env file.[/green] " )
else :
setup_postgresql ( no_postgres )
2025-05-20 19:43:33 -04:00
console . print ( " 📊 [bold blue]Running database migrations...[/bold blue] " )
migrate_db ( )
console . print ( " ✅ [green]Database migration complete.[/green] " )
console . print ( " 🔑 [bold blue]Generating local organization API key...[/bold blue] " )
2025-11-19 17:25:33 -07:00
start_forge_app ( )
2025-05-20 19:43:33 -04:00
api_key = asyncio . run ( setup_local_organization ( ) )
if api_key :
console . print ( " ✅ [green]Local organization API key generated.[/green] " )
else :
console . print ( " [red]Failed to generate local organization API key. Please check server logs.[/red] " )
2025-10-12 10:36:24 -07:00
backend_env_path = resolve_backend_env_path ( )
if backend_env_path . exists ( ) :
2025-11-20 05:16:16 +02:00
console . print ( f " 💡 [ { backend_env_path } ] file already exists. " , style = " yellow " , markup = False )
2025-05-20 19:43:33 -04:00
redo_llm_setup = Confirm . ask (
" Do you want to go through [bold yellow]LLM provider setup again[/bold yellow]? " ,
default = False ,
)
if not redo_llm_setup :
console . print ( " [green]Skipping LLM setup.[/green] " )
else :
console . print ( " \n [bold blue]Initializing .env file for LLM providers...[/bold blue] " )
setup_llm_providers ( )
else :
console . print ( " \n [bold blue]Initializing .env file...[/bold blue] " )
setup_llm_providers ( )
console . print ( " \n [bold blue]Configuring browser settings...[/bold blue] " )
browser_type , browser_location , remote_debugging_url = setup_browser_config ( )
update_or_add_env_var ( " BROWSER_TYPE " , browser_type )
if browser_location :
update_or_add_env_var ( " CHROME_EXECUTABLE_PATH " , browser_location )
if remote_debugging_url :
update_or_add_env_var ( " BROWSER_REMOTE_DEBUGGING_URL " , remote_debugging_url )
console . print ( " ✅ [green]Browser configuration complete.[/green] " )
console . print ( " 🌐 [bold blue]Setting Skyvern Base URL to: http://localhost:8000[/bold blue] " )
update_or_add_env_var ( " SKYVERN_BASE_URL " , " http://localhost:8000 " )
2025-05-26 18:50:11 -07:00
2025-05-27 02:18:23 +03:00
console . print ( " \n [bold yellow]To run Skyvern you can either:[/bold yellow] " )
console . print ( " • [green]skyvern run server[/green] (reuses the DB we just created) " )
2025-05-26 18:50:11 -07:00
console . print (
" • [cyan]docker compose up -d[/cyan] (starts a new Postgres inside Compose; you may stop the first container with: [magenta]docker rm -f postgresql-container[/magenta]) "
)
console . print (
" \n [italic]Only one Postgres container can run on the host ' s port 5432 at a time. If you switch to Docker Compose, remove the original with:[/italic] [magenta]docker rm -f postgresql-container[/magenta] "
)
2025-05-20 19:43:33 -04:00
else :
console . print ( Panel ( " [bold purple]Cloud Deployment Setup[/bold purple] " , border_style = " purple " ) )
base_url = Prompt . ask ( " Enter Skyvern base URL " , default = " https://api.skyvern.com " , show_default = True )
if not base_url :
base_url = " https://api.skyvern.com "
console . print ( " \n [bold]To get your API key:[/bold] " )
console . print ( " 1. Create an account at [link]https://app.skyvern.com[/link] " )
console . print ( " 2. Go to [bold cyan]Settings[/bold cyan] " )
console . print ( " 3. [bold green]Copy your API key[/bold green] " )
api_key = Prompt . ask ( " Enter your Skyvern API key " , password = True )
if not api_key :
console . print ( " [red]API key is required.[/red] " )
api_key = Prompt . ask ( " Please re-enter your Skyvern API key " , password = True )
if not api_key :
console . print ( " [bold red]Error: API key cannot be empty. Aborting initialization.[/bold red] " )
2025-12-04 21:14:48 -07:00
return False
2025-05-20 19:43:33 -04:00
update_or_add_env_var ( " SKYVERN_BASE_URL " , base_url )
analytics_id_input = Prompt . ask ( " Please enter your email for analytics (press enter to skip) " , default = " " )
analytics_id = analytics_id_input if analytics_id_input else str ( uuid . uuid4 ( ) )
update_or_add_env_var ( " ANALYTICS_ID " , analytics_id )
update_or_add_env_var ( " SKYVERN_API_KEY " , api_key )
2025-10-12 10:36:24 -07:00
console . print ( f " ✅ [green] { resolve_backend_env_path ( ) } file has been initialized.[/green] " )
2025-05-20 19:43:33 -04:00
if Confirm . ask ( " \n Would you like to [bold yellow]configure the MCP server[/bold yellow]? " , default = True ) :
setup_mcp ( )
if not run_local :
console . print (
" \n 🎉 [bold green]MCP configuration is complete! Your AI applications are now ready to use Skyvern Cloud.[/bold green] "
)
if run_local :
console . print ( " \n ⬇️ [bold blue]Installing Chromium browser...[/bold blue] " )
with Progress (
SpinnerColumn ( ) , TextColumn ( " [progress.description] {task.description} " ) , transient = True , console = console
) as progress :
progress . add_task ( " [bold blue]Downloading Chromium, this may take a moment... " , total = None )
subprocess . run ( [ " playwright " , " install " , " chromium " ] , check = True )
console . print ( " ✅ [green]Chromium installation complete.[/green] " )
console . print ( " \n 🎉 [bold green]Skyvern setup complete![/bold green] " )
console . print ( " [bold]To start using Skyvern, run:[/bold] " )
console . print ( Padding ( " skyvern run server " , ( 1 , 4 ) , style = " reverse green " ) )
2025-05-20 20:45:15 -04:00
2025-12-04 21:14:48 -07:00
return run_local
2025-05-20 20:45:15 -04:00
def init_browser ( ) - > None :
""" Initialize only the browser configuration and install Chromium. """
console . print ( " \n [bold blue]Configuring browser settings...[/bold blue] " )
browser_type , browser_location , remote_debugging_url = setup_browser_config ( )
update_or_add_env_var ( " BROWSER_TYPE " , browser_type )
if browser_location :
update_or_add_env_var ( " CHROME_EXECUTABLE_PATH " , browser_location )
if remote_debugging_url :
update_or_add_env_var ( " BROWSER_REMOTE_DEBUGGING_URL " , remote_debugging_url )
console . print ( " ✅ [green]Browser configuration complete.[/green] " )
console . print ( " \n ⬇️ [bold blue]Installing Chromium browser...[/bold blue] " )
with Progress (
SpinnerColumn ( ) , TextColumn ( " [progress.description] {task.description} " ) , transient = True , console = console
) as progress :
progress . add_task ( " [bold blue]Downloading Chromium, this may take a moment... " , total = None )
subprocess . run ( [ " playwright " , " install " , " chromium " ] , check = True )
console . print ( " ✅ [green]Chromium installation complete.[/green] " )