@echo off setlocal set "AI_RESTART_ROOT=%~dp0" powershell -NoProfile -ExecutionPolicy Bypass -Command "$p='%~f0'; $s=Get-Content -LiteralPath $p -Raw; $m=':ps1'; $i=$s.LastIndexOf($m); if ($i -lt 0) { throw 'PowerShell payload marker not found.' }; Invoke-Expression $s.Substring($i + $m.Length)" set "EXIT_CODE=%ERRORLEVEL%" if "%~1"=="--no-pause" exit /b %EXIT_CODE% echo. if not "%EXIT_CODE%"=="0" echo [servers] Failed with exit code %EXIT_CODE%. pause exit /b %EXIT_CODE% :ps1 $ErrorActionPreference = "Stop" $root = (Resolve-Path -LiteralPath $env:AI_RESTART_ROOT).Path $logDir = Join-Path $root ".server-logs" New-Item -ItemType Directory -Force -Path $logDir | Out-Null $ports = @(8000, 8001, 8002, 8003, 5173, 5174) function Write-Step { param([string] $Message) Write-Host "[servers] $Message" } function Get-CommandPath { param([string[]] $Candidates) foreach ($candidate in $Candidates) { if ([string]::IsNullOrWhiteSpace($candidate)) { continue } if (Test-Path -LiteralPath $candidate) { return (Resolve-Path -LiteralPath $candidate).Path } $cmd = Get-Command $candidate -ErrorAction SilentlyContinue if ($cmd) { return $cmd.Source } } return $null } function Read-DotEnv { param([string] $Path) $result = @{} if (-not (Test-Path -LiteralPath $Path)) { return $result } foreach ($line in Get-Content -LiteralPath $Path) { if ($line -match "^\s*$" -or $line -match "^\s*#") { continue } if ($line -match "^\s*([^#=\s]+)\s*=\s*(.*)\s*$") { $key = $matches[1] $value = $matches[2].Trim() if ( ($value.StartsWith('"') -and $value.EndsWith('"')) -or ($value.StartsWith("'") -and $value.EndsWith("'")) ) { $value = $value.Substring(1, $value.Length - 2) } $result[$key] = $value } } return $result } function Stop-ExistingServers { Write-Step "Stopping existing project servers." $currentPid = $PID $rootPattern = [regex]::Escape($root) $commandPattern = "uvicorn|ont_platform\.api|phase[0-9]_app|vite|npm(\.cmd)?\s+run\s+(dev|preview|start)" $matched = Get-CimInstance Win32_Process | Where-Object { if (-not $_.CommandLine) { return $false } if ($_.ProcessId -eq $currentPid) { return $false } $cmd = $_.CommandLine return ($cmd -match $commandPattern) -and ( $cmd -match $rootPattern -or $cmd -match "ontology_platform|ont_platform" ) } foreach ($proc in $matched) { Write-Step ("Killing process {0} ({1})" -f $proc.ProcessId, $proc.Name) Stop-Process -Id $proc.ProcessId -Force -ErrorAction SilentlyContinue } $listeners = Get-NetTCPConnection -State Listen -ErrorAction SilentlyContinue | Where-Object { $ports -contains $_.LocalPort } | Select-Object -ExpandProperty OwningProcess -Unique foreach ($pidToStop in $listeners) { if ($pidToStop -and $pidToStop -ne $currentPid) { Write-Step ("Killing listener on configured dev port, pid {0}" -f $pidToStop) Stop-Process -Id $pidToStop -Force -ErrorAction SilentlyContinue } } Start-Sleep -Milliseconds 800 } function Invoke-LoggedCommand { param( [string] $FilePath, [string[]] $Arguments, [string] $WorkingDirectory, [string] $LogName ) $logPath = Join-Path $logDir $LogName $stderrPath = Join-Path $logDir ($LogName -replace "\.log$", ".stderr.log") Write-Step ("Running {0} {1}" -f (Split-Path -Leaf $FilePath), ($Arguments -join " ")) Remove-Item -LiteralPath $logPath, $stderrPath -Force -ErrorAction SilentlyContinue $proc = Start-Process ` -FilePath $FilePath ` -ArgumentList $Arguments ` -WorkingDirectory $WorkingDirectory ` -RedirectStandardOutput $logPath ` -RedirectStandardError $stderrPath ` -WindowStyle Hidden ` -Wait ` -PassThru $exitCode = $proc.ExitCode if ($exitCode -ne 0) { throw "Command failed with exit code $exitCode. See $logPath and $stderrPath" } } function Start-LoggedServer { param( [string] $Name, [int] $Port, [string] $FilePath, [string[]] $Arguments, [string] $WorkingDirectory, [hashtable] $Environment = @{} ) $stdout = Join-Path $logDir "$Name-stdout.log" $stderr = Join-Path $logDir "$Name-stderr.log" Remove-Item -LiteralPath $stdout, $stderr -Force -ErrorAction SilentlyContinue $previous = @{} foreach ($key in $Environment.Keys) { $previous[$key] = [Environment]::GetEnvironmentVariable($key, "Process") [Environment]::SetEnvironmentVariable($key, [string] $Environment[$key], "Process") } try { $proc = Start-Process ` -FilePath $FilePath ` -ArgumentList $Arguments ` -WorkingDirectory $WorkingDirectory ` -RedirectStandardOutput $stdout ` -RedirectStandardError $stderr ` -WindowStyle Hidden ` -PassThru } finally { foreach ($key in $Environment.Keys) { [Environment]::SetEnvironmentVariable($key, $previous[$key], "Process") } } Write-Step ("Started {0}: pid {1}" -f $Name, $proc.Id) return [pscustomobject]@{ Name = $Name Port = $Port Pid = $proc.Id Stdout = $stdout Stderr = $stderr } } function Wait-Port { param( [int] $Port, [int] $Seconds = 20 ) $deadline = (Get-Date).AddSeconds($Seconds) while ((Get-Date) -lt $deadline) { try { $client = [System.Net.Sockets.TcpClient]::new() $async = $client.BeginConnect("127.0.0.1", $Port, $null, $null) if ($async.AsyncWaitHandle.WaitOne(500)) { $client.EndConnect($async) $client.Close() return $true } $client.Close() } catch { Start-Sleep -Milliseconds 500 } } return $false } function Start-Neo4jIfAvailable { $composeFile = Join-Path $root "docker-compose.neo4j.yml" if (-not (Test-Path -LiteralPath $composeFile)) { return } $docker = Get-CommandPath @("docker") if (-not $docker) { Write-Step "Docker was not found; skipping Neo4j compose service." return } try { Invoke-LoggedCommand -FilePath $docker -Arguments @("compose", "-f", $composeFile, "down") -WorkingDirectory $root -LogName "neo4j-down.log" Invoke-LoggedCommand -FilePath $docker -Arguments @("compose", "-f", $composeFile, "up", "-d") -WorkingDirectory $root -LogName "neo4j-up.log" Write-Step "Neo4j compose service requested." } catch { Write-Step "Neo4j compose restart skipped/failed. See .server-logs\\neo4j-*.log" } } Stop-ExistingServers Start-Neo4jIfAvailable $npm = Get-CommandPath @("npm.cmd", "npm") $frontendDir = Join-Path $root "ontology_platform\web\frontend" $frontendReady = $false if ((Test-Path -LiteralPath (Join-Path $frontendDir "package.json")) -and $npm) { if (-not (Test-Path -LiteralPath (Join-Path $frontendDir "node_modules"))) { Invoke-LoggedCommand -FilePath $npm -Arguments @("ci") -WorkingDirectory $frontendDir -LogName "frontend-npm-ci.log" } Invoke-LoggedCommand -FilePath $npm -Arguments @("run", "build") -WorkingDirectory $frontendDir -LogName "frontend-build.log" $frontendReady = $true } elseif (Test-Path -LiteralPath (Join-Path $frontendDir "package.json")) { Write-Step "npm was not found; skipping frontend rebuild." } $servers = @() $ontologyRoot = Join-Path $root "ontology_platform" $ontologyPython = Get-CommandPath @( (Join-Path $ontologyRoot ".venv\Scripts\python.exe"), (Join-Path $root ".venv\Scripts\python.exe"), "C:\Users\lasta\AppData\Local\Python\bin\python.exe", "C:\Users\lasta\.cache\codex-runtimes\codex-primary-runtime\dependencies\python\python.exe", "python" ) if ((Test-Path -LiteralPath (Join-Path $ontologyRoot "ont_platform\api\main.py")) -and $ontologyPython) { $ontologyEnv = Read-DotEnv -Path (Join-Path $ontologyRoot ".env") $ontologyEnv["PHASE"] = "6" $ontologyEnv["HOST"] = "127.0.0.1" $ontologyEnv["PORT"] = "8001" $servers += Start-LoggedServer ` -Name "ontology-platform-8001" ` -Port 8001 ` -FilePath $ontologyPython ` -Arguments @("-m", "uvicorn", "ont_platform.api.main:app", "--host", "127.0.0.1", "--port", "8001") ` -WorkingDirectory $ontologyRoot ` -Environment $ontologyEnv } else { Write-Step "ontology_platform server entrypoint or Python was not found; skipped." } if ($frontendReady) { $servers += Start-LoggedServer ` -Name "ontology-frontend-8000" ` -Port 8000 ` -FilePath $npm ` -Arguments @("run", "dev", "--", "--host", "127.0.0.1", "--port", "8000") ` -WorkingDirectory $frontendDir } $pidFile = Join-Path $logDir "server-pids.txt" $servers | ForEach-Object { "{0} pid={1} stdout={2} stderr={3}" -f $_.Name, $_.Pid, $_.Stdout, $_.Stderr } | Set-Content -LiteralPath $pidFile -Encoding UTF8 $missingPorts = @() foreach ($port in ($servers | Select-Object -ExpandProperty Port -Unique)) { if (Wait-Port -Port $port -Seconds 25) { Write-Step ("Port {0} is listening." -f $port) } else { Write-Step ("Port {0} did not open. Check logs in {1}" -f $port, $logDir) $missingPorts += $port } } if ($missingPorts.Count -gt 0) { throw "Some servers did not start: ports $($missingPorts -join ', ')" } Write-Host "" Write-Step "Done." Write-Host " Ontology UI: http://127.0.0.1:8000/static/" Write-Host " Ontology API: http://127.0.0.1:8001/docs" Write-Host " Logs: $logDir"