chore: initial commit of ai site platform
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
173
scripts/Stop-Stack.ps1
Normal file
173
scripts/Stop-Stack.ps1
Normal file
@@ -0,0 +1,173 @@
|
||||
# Unified stack teardown: Docker containers (if any) + ALL native leftovers.
|
||||
# Used by stop.ps1 / restart.ps1 / start.ps1 / start-host.ps1.
|
||||
# Console messages are ASCII-only to avoid GBK mojibake.
|
||||
param(
|
||||
[switch]$Quiet
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "SilentlyContinue"
|
||||
$Root = Split-Path -Parent $PSScriptRoot
|
||||
if (-not (Test-Path (Join-Path $Root "start.ps1"))) {
|
||||
# allow calling from repo root as -File scripts\Stop-Stack.ps1
|
||||
if (Test-Path (Join-Path $PSScriptRoot "..\start.ps1")) {
|
||||
$Root = Resolve-Path (Join-Path $PSScriptRoot "..")
|
||||
}
|
||||
}
|
||||
Set-Location -LiteralPath $Root
|
||||
$LogDir = Join-Path $Root ".runtime\logs"
|
||||
|
||||
function Write-Info([string]$msg) {
|
||||
if (-not $Quiet) { Write-Host $msg }
|
||||
}
|
||||
|
||||
function Kill-Tree([int]$ProcessId) {
|
||||
if ($ProcessId -le 0) { return }
|
||||
# Skip self / critical system
|
||||
if ($ProcessId -eq $PID) { return }
|
||||
& taskkill.exe /F /T /PID $ProcessId 2>$null | Out-Null
|
||||
Stop-Process -Id $ProcessId -Force -ErrorAction SilentlyContinue
|
||||
}
|
||||
|
||||
function Kill-Port([int]$Port) {
|
||||
$pids = @()
|
||||
Get-NetTCPConnection -LocalPort $Port -State Listen -ErrorAction SilentlyContinue | ForEach-Object {
|
||||
$pids += [int]$_.OwningProcess
|
||||
}
|
||||
$net = & netstat.exe -ano 2>$null
|
||||
foreach ($line in $net) {
|
||||
if ($line -notmatch [regex]::Escape(":${Port}")) { continue }
|
||||
if ($line -notmatch "LISTENING") { continue }
|
||||
$parts = ($line -split "\s+") | Where-Object { $_ }
|
||||
$procId = 0
|
||||
if ([int]::TryParse($parts[-1], [ref]$procId) -and $procId -gt 0) {
|
||||
$pids += $procId
|
||||
}
|
||||
}
|
||||
foreach ($procId in ($pids | Select-Object -Unique)) {
|
||||
try {
|
||||
$proc = Get-Process -Id $procId -ErrorAction Stop
|
||||
} catch {
|
||||
continue
|
||||
}
|
||||
Write-Info (" free port {0} (pid={1} {2})" -f $Port, $procId, $proc.ProcessName)
|
||||
Kill-Tree $procId
|
||||
}
|
||||
}
|
||||
|
||||
function Kill-ByCommand([string]$ProcessName, [string]$Pattern) {
|
||||
Get-CimInstance Win32_Process -Filter ("Name='{0}'" -f $ProcessName) -ErrorAction SilentlyContinue | Where-Object {
|
||||
$_.CommandLine -and ($_.CommandLine -match $Pattern)
|
||||
} | ForEach-Object {
|
||||
Write-Info (" kill {0} pid={1}" -f $ProcessName, $_.ProcessId)
|
||||
Kill-Tree ([int]$_.ProcessId)
|
||||
}
|
||||
}
|
||||
|
||||
# ----- 1) Docker first (do NOT return; native may still be running) -----
|
||||
$dockerOk = $false
|
||||
try {
|
||||
$null = & docker info 2>&1
|
||||
if ($LASTEXITCODE -eq 0) { $dockerOk = $true }
|
||||
} catch { }
|
||||
|
||||
if ($dockerOk) {
|
||||
Write-Info "==> docker compose down --remove-orphans"
|
||||
& docker compose down --remove-orphans 2>$null
|
||||
# also stop any leftover named containers from older compose projects
|
||||
$names = @("ai-web-1", "ai-ai-1", "ai-gateway-1", "ai-platform-1", "ai-postgres-1")
|
||||
foreach ($n in $names) {
|
||||
& docker rm -f $n 2>$null | Out-Null
|
||||
}
|
||||
}
|
||||
|
||||
# ----- 2) Watchdog first (otherwise it revives ai) -----
|
||||
Write-Info "==> stopping native processes..."
|
||||
$watchPidFile = Join-Path $LogDir "watchdog.pid"
|
||||
if (Test-Path $watchPidFile) {
|
||||
$wid = Get-Content $watchPidFile -ErrorAction SilentlyContinue
|
||||
if ($wid) {
|
||||
Write-Info (" kill watchdog pid={0}" -f $wid)
|
||||
Kill-Tree ([int]$wid)
|
||||
}
|
||||
Remove-Item $watchPidFile -Force -ErrorAction SilentlyContinue
|
||||
}
|
||||
Kill-ByCommand "powershell.exe" "watch-services\.ps1"
|
||||
Kill-ByCommand "pwsh.exe" "watch-services\.ps1"
|
||||
Kill-ByCommand "powershell.exe" "start-host\.ps1"
|
||||
Kill-ByCommand "powershell.exe" "Restart-AiOnly|restart_ai_only|hard_restart"
|
||||
|
||||
# ----- 3) Pid files -----
|
||||
foreach ($name in @("ai-service.pid", "platform.pid", "gateway.pid", "web.pid", "watchdog.pid")) {
|
||||
$pf = Join-Path $LogDir $name
|
||||
if (Test-Path $pf) {
|
||||
$pidText = Get-Content $pf -ErrorAction SilentlyContinue
|
||||
if ($pidText) {
|
||||
Write-Info (" kill {0} -> {1}" -f $name, $pidText)
|
||||
Kill-Tree ([int]$pidText)
|
||||
}
|
||||
Remove-Item $pf -Force -ErrorAction SilentlyContinue
|
||||
}
|
||||
}
|
||||
|
||||
# ----- 4) By process name / cmdline -----
|
||||
Get-Process -Name "platform", "gateway" -ErrorAction SilentlyContinue | ForEach-Object {
|
||||
Write-Info (" kill {0} pid={1}" -f $_.ProcessName, $_.Id)
|
||||
Kill-Tree ([int]$_.Id)
|
||||
}
|
||||
|
||||
# uvicorn reloader = parent + workers
|
||||
Kill-ByCommand "python.exe" "uvicorn"
|
||||
Kill-ByCommand "python.exe" "app:app"
|
||||
Kill-ByCommand "python.exe" "shot_worker\.py"
|
||||
Kill-ByCommand "python.exe" "fidelity_loop|FIDELITY_SHOT"
|
||||
Kill-ByCommand "python.exe" "ai-service"
|
||||
|
||||
# vite / node tooling for this repo
|
||||
Kill-ByCommand "node.exe" "vite"
|
||||
Kill-ByCommand "node.exe" "esbuild"
|
||||
Kill-ByCommand "cmd.exe" "npm.*vite|vite\.js"
|
||||
|
||||
# Playwright Chromium leftovers from fidelity shots
|
||||
Kill-ByCommand "chrome.exe" "ms-playwright|playwright"
|
||||
Kill-ByCommand "chromium.exe" "ms-playwright|playwright"
|
||||
Get-CimInstance Win32_Process -ErrorAction SilentlyContinue | Where-Object {
|
||||
$_.Name -match '^(chrome|chromium)\.exe$' -and $_.CommandLine -match 'ms-playwright|playwright_chromium'
|
||||
} | ForEach-Object {
|
||||
Write-Info (" kill playwright browser pid={0}" -f $_.ProcessId)
|
||||
Kill-Tree ([int]$_.ProcessId)
|
||||
}
|
||||
|
||||
# ----- 5) Ports (authoritative) -----
|
||||
foreach ($port in 8888, 8001, 8180, 5173) {
|
||||
Kill-Port $port
|
||||
}
|
||||
|
||||
Start-Sleep -Seconds 2
|
||||
|
||||
# second pass for stubborn reloaders
|
||||
Kill-ByCommand "python.exe" "uvicorn|app:app|shot_worker"
|
||||
Kill-ByCommand "node.exe" "vite"
|
||||
foreach ($port in 8888, 8001, 8180, 5173) {
|
||||
Kill-Port $port
|
||||
}
|
||||
Start-Sleep -Seconds 1
|
||||
|
||||
# ----- 6) Verify (only live processes count) -----
|
||||
$still = @()
|
||||
foreach ($port in 8888, 8001, 8180, 5173) {
|
||||
Get-NetTCPConnection -LocalPort $port -State Listen -ErrorAction SilentlyContinue | ForEach-Object {
|
||||
$proc = Get-Process -Id $_.OwningProcess -ErrorAction SilentlyContinue
|
||||
if ($proc) {
|
||||
$still += (":{0} pid={1} {2}" -f $port, $_.OwningProcess, $proc.ProcessName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($still.Count -gt 0) {
|
||||
Write-Host "WARN still listening after stop:" -ForegroundColor Yellow
|
||||
$still | ForEach-Object { Write-Host (" {0}" -f $_) }
|
||||
exit 1
|
||||
}
|
||||
|
||||
Write-Info "OK stopped (docker + native; ports 8888/8001/8180/5173 free)"
|
||||
exit 0
|
||||
Reference in New Issue
Block a user