| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110 |
- param(
- [switch]$ForceKillPorts
- )
- $ErrorActionPreference = "Stop"
- Set-StrictMode -Version Latest
- $RepoRoot = (Resolve-Path (Join-Path $PSScriptRoot "..")).Path
- $RuntimeDir = Join-Path $RepoRoot ".runtime"
- $ManagedNames = @("api", "web")
- $KnownPorts = @(3000, 3001, 3002)
- function Write-Step([string]$Message) {
- Write-Host "==> $Message" -ForegroundColor Cyan
- }
- function Write-WarnLine([string]$Message) {
- Write-Host "WARN: $Message" -ForegroundColor Yellow
- }
- function Get-PidFilePath([string]$Name) {
- return Join-Path $RuntimeDir "$Name.pid"
- }
- function Test-ProcessRunning([int]$ProcessId) {
- try {
- $null = Get-Process -Id $ProcessId -ErrorAction Stop
- return $true
- } catch {
- return $false
- }
- }
- function Get-ProcessCommandLine([int]$ProcessId) {
- try {
- $process = Get-CimInstance Win32_Process -Filter "ProcessId = $ProcessId"
- if ($null -eq $process -or $null -eq $process.CommandLine) {
- return ""
- }
- return [string]$process.CommandLine
- } catch {
- return ""
- }
- }
- function Test-SentAIProcess([int]$ProcessId) {
- $commandLine = Get-ProcessCommandLine $ProcessId
- if (-not $commandLine) {
- return $false
- }
- return $commandLine -like "*SentAI*" -or
- $commandLine -like "*@sentai*" -or
- $commandLine -like "*npm.cmd run dev:api*" -or
- $commandLine -like "*npm.cmd run dev:web*"
- }
- function Stop-ProcessTree([int]$ProcessId) {
- & taskkill /PID $ProcessId /T /F | Out-Null
- }
- function Get-ListenerOwners([int]$Port) {
- try {
- return @(Get-NetTCPConnection -LocalPort $Port -State Listen -ErrorAction Stop |
- Select-Object -ExpandProperty OwningProcess -Unique)
- } catch {
- return @()
- }
- }
- foreach ($name in $ManagedNames) {
- $pidFile = Get-PidFilePath $name
- if (-not (Test-Path $pidFile)) {
- continue
- }
- $raw = (Get-Content $pidFile -ErrorAction SilentlyContinue | Select-Object -First 1)
- $managedPid = 0
- if ([int]::TryParse($raw, [ref]$managedPid) -and (Test-ProcessRunning $managedPid)) {
- Write-Step "Stopping managed $name process $managedPid."
- Stop-ProcessTree $managedPid
- }
- Remove-Item $pidFile -ErrorAction SilentlyContinue
- }
- foreach ($port in $KnownPorts) {
- [array]$owners = @(Get-ListenerOwners $port)
- foreach ($owner in $owners) {
- if ($ForceKillPorts -or (Test-SentAIProcess $owner)) {
- Write-WarnLine "Stopping remaining process $owner on port $port."
- Stop-ProcessTree $owner
- continue
- }
- Write-WarnLine "Port $port is still used by non-SentAI process $owner. Leaving it untouched."
- }
- }
- Start-Sleep -Seconds 2
- Write-Host ""
- foreach ($port in $KnownPorts) {
- [array]$owners = @(Get-ListenerOwners $port)
- if ($owners.Count -eq 0) {
- Write-Host "Port $port closed." -ForegroundColor Green
- } else {
- Write-Host "Port $port still in use by $($owners -join ', ')." -ForegroundColor Yellow
- }
- }
|