147 lines
4.4 KiB
PowerShell
147 lines
4.4 KiB
PowerShell
[CmdletBinding()]
|
|
param(
|
|
[ValidateRange(15, 10080)]
|
|
[int]$MinAgeMinutes = 120,
|
|
|
|
[switch]$Apply
|
|
)
|
|
|
|
$ErrorActionPreference = 'Stop'
|
|
throw 'Docker development copy: runtime control is disabled until container isolation is ready. See DOCKER_MIGRATION.md.'
|
|
$now = Get-Date
|
|
$agentVitePattern = 'AgentUI_2\.01.*frontend-next.*vite\\bin\\vite\.js'
|
|
$npxVitePattern = 'npx-cli\.js.*\bvite\b'
|
|
$agentEsbuildPattern = 'AgentUI_2\.01.*frontend-next.*@esbuild'
|
|
|
|
function Get-VitePort {
|
|
param([string]$CommandLine)
|
|
|
|
if ($CommandLine -match '--port\s+(\d+)') {
|
|
return $matches[1]
|
|
}
|
|
return $null
|
|
}
|
|
|
|
$processes = @(Get-CimInstance Win32_Process)
|
|
$agentNodes = @(
|
|
$processes | Where-Object {
|
|
$_.Name -eq 'node.exe' -and [string]$_.CommandLine -match $agentVitePattern
|
|
}
|
|
)
|
|
$ports = @{}
|
|
foreach ($process in $agentNodes) {
|
|
$port = Get-VitePort ([string]$process.CommandLine)
|
|
if ($port) {
|
|
$ports[$port] = $true
|
|
}
|
|
}
|
|
$npxNodes = @(
|
|
$processes | Where-Object {
|
|
if ($_.Name -ne 'node.exe' -or [string]$_.CommandLine -notmatch $npxVitePattern) {
|
|
return $false
|
|
}
|
|
$port = Get-VitePort ([string]$_.CommandLine)
|
|
return $port -and $ports.ContainsKey($port)
|
|
}
|
|
)
|
|
|
|
$connectedPids = @{}
|
|
try {
|
|
Get-NetTCPConnection -State Established -ErrorAction Stop | ForEach-Object {
|
|
$connectedPids[[int]$_.OwningProcess] = $true
|
|
}
|
|
} catch {
|
|
throw "Refusing cleanup because established TCP connections could not be inspected: $($_.Exception.Message)"
|
|
}
|
|
|
|
$protectedPorts = @{}
|
|
$newestAgent = $agentNodes | Sort-Object CreationDate -Descending | Select-Object -First 1
|
|
if ($newestAgent) {
|
|
$newestPort = Get-VitePort ([string]$newestAgent.CommandLine)
|
|
if ($newestPort) {
|
|
$protectedPorts[$newestPort] = 'newest AgentUI Vite instance'
|
|
}
|
|
}
|
|
foreach ($process in @($agentNodes + $npxNodes)) {
|
|
$port = Get-VitePort ([string]$process.CommandLine)
|
|
if (-not $port) {
|
|
continue
|
|
}
|
|
$created = [datetime]$process.CreationDate
|
|
$ageMinutes = ($now - $created).TotalMinutes
|
|
if ($ageMinutes -lt $MinAgeMinutes) {
|
|
$protectedPorts[$port] = "younger than $MinAgeMinutes minutes"
|
|
}
|
|
if ($connectedPids.ContainsKey([int]$process.ProcessId)) {
|
|
$protectedPorts[$port] = 'has an established TCP connection'
|
|
}
|
|
}
|
|
|
|
$targetAgentNodes = @(
|
|
$agentNodes | Where-Object {
|
|
$port = Get-VitePort ([string]$_.CommandLine)
|
|
$port -and -not $protectedPorts.ContainsKey($port)
|
|
}
|
|
)
|
|
$targetPorts = @{}
|
|
$targetAgentPids = @{}
|
|
foreach ($process in $targetAgentNodes) {
|
|
$targetPorts[(Get-VitePort ([string]$process.CommandLine))] = $true
|
|
$targetAgentPids[[int]$process.ProcessId] = $true
|
|
}
|
|
$targetNpxNodes = @(
|
|
$npxNodes | Where-Object {
|
|
$port = Get-VitePort ([string]$_.CommandLine)
|
|
$port -and $targetPorts.ContainsKey($port)
|
|
}
|
|
)
|
|
$targetEsbuild = @(
|
|
$processes | Where-Object {
|
|
$_.Name -eq 'esbuild.exe' -and
|
|
[string]$_.ExecutablePath -match $agentEsbuildPattern -and
|
|
$targetAgentPids.ContainsKey([int]$_.ParentProcessId)
|
|
}
|
|
)
|
|
$targetIds = @(
|
|
@($targetEsbuild + $targetAgentNodes + $targetNpxNodes).ProcessId |
|
|
Where-Object { $null -ne $_ -and [int]$_ -gt 0 } |
|
|
ForEach-Object { [int]$_ } |
|
|
Sort-Object -Unique
|
|
)
|
|
|
|
Write-Output "AgentUI Vite instances: $($agentNodes.Count)"
|
|
Write-Output "Protected ports: $($protectedPorts.Count)"
|
|
Write-Output "Stale ports: $($targetPorts.Count)"
|
|
Write-Output "Target processes: $($targetIds.Count)"
|
|
|
|
if (-not $Apply) {
|
|
Write-Output 'Dry run only. Re-run with -Apply to terminate the exact stale process set.'
|
|
exit 0
|
|
}
|
|
|
|
if ($targetIds.Count -eq 0) {
|
|
Write-Output 'No stale AgentUI Vite processes require cleanup.'
|
|
exit 0
|
|
}
|
|
|
|
Stop-Process -Id $targetIds -Force -ErrorAction SilentlyContinue
|
|
Start-Sleep -Seconds 5
|
|
|
|
$remaining = @(
|
|
Get-CimInstance Win32_Process | Where-Object {
|
|
$targetIds -contains [int]$_.ProcessId -and (
|
|
($_.Name -eq 'node.exe' -and (
|
|
[string]$_.CommandLine -match $agentVitePattern -or
|
|
[string]$_.CommandLine -match $npxVitePattern
|
|
)) -or
|
|
($_.Name -eq 'esbuild.exe' -and [string]$_.ExecutablePath -match $agentEsbuildPattern)
|
|
)
|
|
}
|
|
)
|
|
if ($remaining.Count -gt 0) {
|
|
Write-Error "Cleanup left $($remaining.Count) exact target process(es) running."
|
|
exit 1
|
|
}
|
|
|
|
Write-Output "Terminated $($targetIds.Count) stale AgentUI Vite process(es)."
|