66 lines
3.4 KiB
PowerShell
66 lines
3.4 KiB
PowerShell
# Process ownership is determined by checkout paths, never by a port or name alone.
|
|
function Get-ArtemisUpgradeProcesses {
|
|
param([string]$ProjectRoot, [object[]]$Processes, [int[]]$ProtectedIds = @())
|
|
$root = [IO.Path]::GetFullPath($ProjectRoot).TrimEnd('\') + '\'
|
|
$venv = $root + '.venv\'
|
|
$selected = @{}
|
|
foreach ($process in $Processes) {
|
|
if ($ProtectedIds -contains [int]$process.ProcessId) { continue }
|
|
$executable = [string]$process.ExecutablePath
|
|
$command = [string]$process.CommandLine
|
|
$python = $process.Name -match '^(python(w)?|artemis(-admin)?)\.exe$'
|
|
$inVenv = $executable.StartsWith($venv, [StringComparison]::OrdinalIgnoreCase)
|
|
$explicitRoot = $command.Replace('/', '\').IndexOf($root, [StringComparison]::OrdinalIgnoreCase) -ge 0
|
|
$entrypoint = $command -match '(?i)(?:-m\s+(?:artemis(?:\s|\.|$)|apps\.admin_console(?:\.|\s)|mcp_server(?:\.|\s|$))|[\\/]artemis(?:\.exe|[\\/]__main__\.py)|[\\/]mcp_server[\\/])'
|
|
if (($python -and $inVenv) -or ($explicitRoot -and $entrypoint -and ($python -or $process.Name -eq 'uv.exe'))) {
|
|
$selected[[int]$process.ProcessId] = $process
|
|
}
|
|
}
|
|
do {
|
|
$added = $false
|
|
foreach ($process in $Processes) {
|
|
$id = [int]$process.ProcessId
|
|
if ($selected.ContainsKey($id) -or $ProtectedIds -contains $id) { continue }
|
|
# Shared device services and desktop applications can outlive a task.
|
|
if ($process.Name -match '^(adb|codex|chrome|msedge|firefox|emulator|MuMu.*|Nemu.*|Nox.*|MEmu.*|LdVBox.*|HD-Player)\.exe$') { continue }
|
|
if ($selected.ContainsKey([int]$process.ParentProcessId)) {
|
|
$selected[$id] = $process
|
|
$added = $true
|
|
}
|
|
}
|
|
} while ($added)
|
|
return @($selected.Values)
|
|
}
|
|
|
|
function Stop-ArtemisUpgradeProcesses {
|
|
param([string]$ProjectRoot)
|
|
$snapshot = @(Get-CimInstance Win32_Process -ErrorAction Stop)
|
|
$protected = @($PID)
|
|
$parentId = $PID
|
|
do {
|
|
$parent = $snapshot | Where-Object { [int]$_.ProcessId -eq $parentId } | Select-Object -First 1
|
|
$parentId = if ($parent) { [int]$parent.ParentProcessId } else { 0 }
|
|
if ($parentId -and $protected -notcontains $parentId) { $protected += $parentId } else { break }
|
|
} while ($true)
|
|
$deadline = [DateTime]::UtcNow.AddSeconds(10)
|
|
do {
|
|
$targets = @(Get-ArtemisUpgradeProcesses -ProjectRoot $ProjectRoot -Processes $snapshot -ProtectedIds $protected)
|
|
if (-not $targets.Count) { return }
|
|
foreach ($target in $targets) {
|
|
$id = [int]$target.ProcessId
|
|
$current = Get-CimInstance Win32_Process -Filter "ProcessId = $id" -ErrorAction Stop
|
|
if (-not $current -or $current.CreationDate -ne $target.CreationDate) { continue }
|
|
Write-Host "[STOP] ARTEMIS PID $id ($($target.Name))"
|
|
try { Stop-Process -Id $id -Force -ErrorAction Stop }
|
|
catch {
|
|
if (Get-CimInstance Win32_Process -Filter "ProcessId = $id" -ErrorAction Stop) { throw }
|
|
}
|
|
}
|
|
Start-Sleep -Milliseconds 200
|
|
$snapshot = @(Get-CimInstance Win32_Process -ErrorAction Stop)
|
|
} while ([DateTime]::UtcNow -lt $deadline)
|
|
if (@(Get-ArtemisUpgradeProcesses -ProjectRoot $ProjectRoot -Processes $snapshot -ProtectedIds $protected).Count) {
|
|
throw 'ARTEMIS processes are still running. Source/dependency updates were not started.'
|
|
}
|
|
}
|