# ZCLAW Full Stack Start Script # Starts: PostgreSQL (Docker) -> SaaS Backend -> Admin Web -> ChromeDriver (optional) -> Tauri Desktop # # NOTE: ZCLAW now uses internal Kernel (zclaw-kernel) for all operations. # No external ZCLAW runtime is required. param( [switch]$NoBrowser, [switch]$Dev, [switch]$Help, [switch]$Stop, [switch]$DesktopOnly, [switch]$NoSaas ) $ErrorActionPreference = "Continue" $ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path # Colors function info { param($msg) Write-Host "[INFO] $msg" -ForegroundColor Cyan } function ok { param($msg) Write-Host "[OK] $msg" -ForegroundColor Green } function warn { param($msg) Write-Host "[WARN] $msg" -ForegroundColor Yellow } function err { param($msg) Write-Host "[ERROR] $msg" -ForegroundColor Red } if ($Help) { Write-Host @" ZCLAW Full Stack Start Script ============================== Usage: .\start-all.ps1 [options] Options: -DesktopOnly Start desktop only (skip ChromeDriver + SaaS + PostgreSQL) -NoBrowser Skip ChromeDriver startup -NoSaas Skip PostgreSQL + SaaS backend + Admin dashboard startup -Dev Development mode (hot reload) -Stop Stop all services -Help Show this help Note: ZCLAW uses an internal Rust-based Kernel for all operations. No external runtime is required. Quick Commands: pnpm start # Start all services pnpm start:dev # Start in dev mode pnpm start:desktop # Start desktop only (no browser, no SaaS) "@ exit 0 } # Stop all services if ($Stop) { info "Stopping all ZCLAW services..." # Stop ChromeDriver Get-Process -Name "chromedriver" -ErrorAction SilentlyContinue | Stop-Process -Force ok "ChromeDriver stopped" # Stop SaaS backend (kill process tree) Get-Process -Name "zclaw-saas" -ErrorAction SilentlyContinue | ForEach-Object { & taskkill /T /F /PID $_.Id 2>$null ok "Stopped SaaS backend process tree (PID: $($_.Id))" } $port8080 = netstat -ano | Select-String ":8080.*LISTENING" if ($port8080) { $pid8080 = ($port8080 -split '\s+')[-1] if ($pid8080 -match '^\d+$') { & taskkill /T /F /PID $pid8080 2>$null ok "Stopped SaaS backend on port 8080 (PID: $pid8080)" } } # Stop any process on port 4200 (legacy, may still be in use) $port4200 = netstat -ano | Select-String ":4200.*LISTENING" if ($port4200) { $pid4200 = ($port4200 -split '\s+')[-1] if ($pid4200 -match '^\d+$') { & taskkill /T /F /PID $pid4200 2>$null ok "Stopped process on port 4200 (PID: $pid4200)" } } # Stop Admin dev server (kill process tree to ensure node.exe children die) $port3000 = netstat -ano | Select-String ":3000.*LISTENING" if ($port3000) { $pid3000 = ($port3000 -split '\s+')[-1] if ($pid3000 -match '^\d+$') { & taskkill /T /F /PID $pid3000 2>$null ok "Stopped Admin dev server on port 3000 (PID: $pid3000)" } } # Stop Tauri/ZClaw Get-Process -Name "ZClaw" -ErrorAction SilentlyContinue | Stop-Process -Force Get-Process -Name "desktop" -ErrorAction SilentlyContinue | Stop-Process -Force ok "ZCLAW Desktop stopped" # Kill any process on port 1420 (Vite dev server) $port1420 = netstat -ano | Select-String ":1420.*LISTENING" if ($port1420) { $pid1420 = ($port1420 -split '\s+')[-1] if ($pid1420 -match '^\d+$') { & taskkill /T /F /PID $pid1420 2>$null ok "Killed process on port 1420 (PID: $pid1420)" } } ok "All services stopped" exit 0 } Write-Host "" Write-Host "===============================================" -ForegroundColor Magenta Write-Host " ZCLAW - AI Agent Desktop Client" -ForegroundColor Magenta Write-Host "===============================================" -ForegroundColor Magenta Write-Host "" # Track processes for cleanup $Jobs = @() function Cleanup { info "Cleaning up..." # Kill tracked process trees (parent + all children) foreach ($job in $Jobs) { if ($job -and !$job.HasExited) { info "Stopping $($job.ProcessName) (PID: $($job.Id)) and child processes" try { # taskkill /T kills the entire process tree, not just the parent & taskkill /T /F /PID $job.Id 2>$null if (!$job.HasExited) { $job.Kill() } } catch { try { $job.Kill() } catch {} } } } # Fallback: kill processes by known ports foreach ($port in @(8080, 3000)) { $listening = netstat -ano | Select-String ":${port}.*LISTENING" if ($listening) { $pid = ($listening -split '\s+')[-1] if ($pid -match '^\d+$') { info "Killing orphan process on port $port (PID: $pid)" & taskkill /T /F /PID $pid 2>$null } } } } trap { Cleanup; break } Register-EngineEvent -SourceIdentifier PowerShell.Exiting -Action { Cleanup } | Out-Null # Skip SaaS and ChromeDriver if DesktopOnly if ($DesktopOnly) { $NoBrowser = $true $NoSaas = $true } # 1. PostgreSQL (Windows native) — required for SaaS backend if (-not $NoSaas) { info "Checking PostgreSQL..." $port5432 = netstat -ano | Select-String ":5432.*LISTENING" if ($port5432) { ok "PostgreSQL is running on port 5432" } else { # Try to start the Windows PostgreSQL service $pgService = Get-Service -Name "postgresql*" -ErrorAction SilentlyContinue | Select-Object -First 1 if ($pgService) { if ($pgService.Status -ne "Running") { info "Starting PostgreSQL service: $($pgService.Name)..." Start-Service -Name $pgService.Name -ErrorAction SilentlyContinue Start-Sleep -Seconds 2 ok "PostgreSQL service started" } else { ok "PostgreSQL service is running" } } else { warn "PostgreSQL not found on port 5432 and no Windows service detected." warn "SaaS backend requires PostgreSQL. Please start it manually." $NoSaas = $true } } } else { info "Skipping PostgreSQL" } Write-Host "" # 2. SaaS Backend (for cloud features: account, relay, config sync) if (-not $NoSaas) { info "Checking SaaS backend..." # Check if port 8080 is already in use $port8080 = netstat -ano | Select-String ":8080.*LISTENING" if ($port8080) { $pid8080 = ($port8080 -split '\s+')[-1] if ($pid8080 -match '^\d+$') { ok "SaaS backend already running on port 8080 (PID: $pid8080)" } } else { # Check if zclaw-saas binary exists $saasBin = "$ScriptDir\target\debug\zclaw-saas.exe" $saasBinRelease = "$ScriptDir\target\release\zclaw-saas.exe" $saasExe = if (Test-Path $saasBinRelease) { $saasBinRelease } elseif (Test-Path $saasBin) { $saasBin } else { $null } if ($saasExe) { ok "SaaS backend binary found: $saasExe" info "Starting SaaS backend on port 8080..." if ($Dev) { $env:ZCLAW_SAAS_DEV = "true" } $proc = Start-Process -FilePath $saasExe -PassThru -WindowStyle Minimized $Jobs += $proc Start-Sleep -Seconds 3 if ($proc.HasExited) { err "SaaS backend exited unexpectedly. Run manually: cd $ScriptDir && ZCLAW_SAAS_DEV=true cargo run -p zclaw-saas" } else { ok "SaaS backend started (PID: $($proc.Id))" } } else { warn "SaaS backend binary not found. Building..." info "Run: cargo build -p zclaw-saas" warn "SaaS cloud features will be unavailable until built." } } } else { info "Skipping SaaS backend" } Write-Host "" # 3. Admin Web (Next.js management dashboard on port 3000) if (-not $NoSaas) { info "Checking Admin dashboard..." $port3000 = netstat -ano | Select-String ":3000.*LISTENING" if ($port3000) { $pid3000 = ($port3000 -split '\s+')[-1] if ($pid3000 -match '^\d+$') { ok "Admin dashboard already running on port 3000 (PID: $pid3000)" } } else { if (Test-Path "$ScriptDir\admin\package.json") { info "Starting Admin dashboard on port 3000..." Set-Location "$ScriptDir\admin" if ($Dev) { $proc = Start-Process -FilePath "cmd.exe" -ArgumentList "/c cd /d `"$ScriptDir\admin`" && pnpm dev" -PassThru -WindowStyle Minimized } else { $proc = Start-Process -FilePath "cmd.exe" -ArgumentList "/c cd /d `"$ScriptDir\admin`" && pnpm dev" -PassThru -WindowStyle Minimized } $Jobs += $proc Set-Location $ScriptDir Start-Sleep -Seconds 5 $port3000Check = netstat -ano | Select-String ":3000.*LISTENING" if ($port3000Check) { ok "Admin dashboard started on port 3000 (PID: $($proc.Id))" } else { warn "Admin dashboard may still be starting. Check http://localhost:3000" } } else { warn "Admin directory not found. Skipping." } } } else { info "Skipping Admin dashboard" } Write-Host "" # 4. ChromeDriver (optional - for Browser Hand automation) if (-not $NoBrowser) { info "Checking ChromeDriver..." $existing = Get-Process -Name "chromedriver" -ErrorAction SilentlyContinue if ($existing) { ok "ChromeDriver already running (PID: $($existing.Id))" } else { $chromedriver = Get-Command chromedriver -ErrorAction SilentlyContinue if ($chromedriver) { ok "ChromeDriver found: $($chromedriver.Source)" info "Starting ChromeDriver on port 4444..." $proc = Start-Process -FilePath "chromedriver" -ArgumentList "--port=4444" -PassThru -WindowStyle Hidden $Jobs += $proc Start-Sleep -Milliseconds 500 if ($proc.HasExited) { warn "ChromeDriver exited. Check if port 4444 is in use." } else { ok "ChromeDriver started (PID: $($proc.Id))" } } else { warn "ChromeDriver not found. Browser automation disabled." info "Download: https://chromedriver.chromium.org/downloads" } } } else { info "Skipping ChromeDriver" } Write-Host "" # 5. Start Tauri Desktop info "Starting ZCLAW Desktop..." Set-Location "$ScriptDir/desktop" # Check if port 1420 is in use $port1420 = netstat -ano | Select-String ":1420.*LISTENING" if ($port1420) { $pid1420 = ($port1420 -split '\s+')[-1] if ($pid1420 -match '^\d+$') { warn "Port 1420 is in use by PID $pid1420. Killing..." Stop-Process -Id $pid1420 -Force -ErrorAction SilentlyContinue Start-Sleep -Seconds 1 } } if ($Dev) { info "Development mode enabled" pnpm tauri dev } else { $exe = "src-tauri\target\release\ZClaw.exe" if (Test-Path $exe) { info "Starting built application..." Start-Process $exe ok "ZCLAW Desktop started" } else { info "Built app not found, using dev mode..." pnpm tauri dev } } if ($Dev) { Write-Host "" info "Press Ctrl+C to stop all services..." try { while ($true) { Start-Sleep -Seconds 1 } } finally { Cleanup } }