You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
161 lines
6.8 KiB
161 lines
6.8 KiB
<#
|
|
.SYNOPSIS
|
|
Reconstruct the state of lights-out runs for Companion polling and Morning Review.
|
|
.DESCRIPTION
|
|
Reads the durable registry at ~\.scout\lights-out\runs.json and, for each run, re-derives
|
|
live facts from git and gnhf's own artifacts. Safe to call from a brand-new Scout session
|
|
that has no memory of the conversation that launched the run.
|
|
.EXAMPLE
|
|
.\check-run.ps1 -Latest
|
|
.EXAMPLE
|
|
.\check-run.ps1 -Since 1 -Json
|
|
#>
|
|
[CmdletBinding()]
|
|
param(
|
|
[string]$Id,
|
|
[switch]$Latest,
|
|
[switch]$Active,
|
|
[int]$Since = 0,
|
|
[int]$NotesTail = 40,
|
|
[switch]$Json
|
|
)
|
|
|
|
Set-StrictMode -Version Latest
|
|
$ErrorActionPreference = 'Stop'
|
|
|
|
. (Join-Path $PSScriptRoot 'lib.ps1')
|
|
|
|
$runs = @(Read-LightsOutRuns)
|
|
if ($runs.Count -eq 0) {
|
|
if ($Json) { '[]' } else { Write-Host 'No lights-out runs have ever been registered.' }
|
|
return
|
|
}
|
|
|
|
$runs = $runs | Sort-Object { [datetime]::Parse($_.startedAt) } -Descending
|
|
|
|
if ($Id) { $runs = @($runs | Where-Object { $_.id -eq $Id }) }
|
|
if ($Active) { $runs = @($runs | Where-Object { $_.status -in @('running', 'launching', 'finalizing') }) }
|
|
if ($Since -gt 0) {
|
|
$cutoff = (Get-Date).AddDays(-$Since)
|
|
$runs = @($runs | Where-Object { [datetime]::Parse($_.startedAt) -ge $cutoff })
|
|
}
|
|
if ($Latest) { $runs = @($runs | Select-Object -First 1) }
|
|
|
|
$results = foreach ($run in $runs) {
|
|
$alive = $false
|
|
if ($run.PSObject.Properties['workerPid'] -and $run.workerPid) {
|
|
$alive = Test-LightsOutProcessAlive -ProcessId ([int]$run.workerPid) -StartedAtIso $run.startedAt
|
|
}
|
|
|
|
$runDir = $null
|
|
if (Test-Path -LiteralPath $run.repoPath) {
|
|
$runDir = Resolve-LightsOutRunDir -RepoPath $run.repoPath -RunId $run.id
|
|
}
|
|
|
|
$endState = $null
|
|
if ($runDir) {
|
|
$esPath = Join-Path $runDir 'end-state.json'
|
|
if (Test-Path -LiteralPath $esPath) {
|
|
try { $endState = Get-Content -LiteralPath $esPath -Raw | ConvertFrom-Json } catch { }
|
|
}
|
|
}
|
|
|
|
$commits = @()
|
|
$diffStat = ''
|
|
$branchExists = $false
|
|
if ((Test-Path -LiteralPath $run.repoPath) -and $run.baseCommit) {
|
|
$branchExists = [bool](git -C $run.repoPath rev-parse --verify --quiet $run.branch 2>$null)
|
|
$ref = if ($branchExists) { $run.branch } else { 'HEAD' }
|
|
$commits = @(git -C $run.repoPath --no-pager log --oneline "$($run.baseCommit)..$ref" 2>$null)
|
|
$diffStat = (git -C $run.repoPath --no-pager diff --shortstat "$($run.baseCommit)..$ref" 2>$null) -join ' '
|
|
}
|
|
|
|
$notesTailText = $null
|
|
if ($runDir) {
|
|
$np = Join-Path $runDir 'notes.md'
|
|
if (Test-Path -LiteralPath $np) {
|
|
$notesTailText = (Get-Content -LiteralPath $np -Tail $NotesTail -ErrorAction SilentlyContinue) -join "`n"
|
|
}
|
|
}
|
|
|
|
$elapsed = $null
|
|
try {
|
|
$end = if ($run.PSObject.Properties['endedAt'] -and $run.endedAt) { [datetime]::Parse($run.endedAt) } else { Get-Date }
|
|
$elapsed = '{0:h\hm\m}' -f ($end - [datetime]::Parse($run.startedAt))
|
|
}
|
|
catch { }
|
|
|
|
$vaultNote = $null
|
|
if ($run.PSObject.Properties['vaultNote'] -and $run.vaultNote) { $vaultNote = $run.vaultNote }
|
|
else {
|
|
$guess = Join-Path (Get-LightsOutVaultFolder -Run $run) 'summary.md'
|
|
if (Test-Path -LiteralPath $guess) { $vaultNote = $guess }
|
|
}
|
|
|
|
# A run the registry thinks is live, whose worker process is gone, died without finalizing
|
|
# (reboot, forced kill, power loss). Say so rather than reporting it as still working.
|
|
$effectiveStatus = $run.status
|
|
if ($run.status -in @('running', 'launching', 'finalizing') -and -not $alive) {
|
|
$effectiveStatus = 'orphaned'
|
|
}
|
|
|
|
[pscustomobject]@{
|
|
id = $run.id
|
|
status = $effectiveStatus
|
|
recordedStatus = $run.status
|
|
workerAlive = $alive
|
|
workerPid = if ($run.PSObject.Properties['workerPid']) { $run.workerPid } else { $null }
|
|
mode = $run.mode
|
|
agent = $run.agent
|
|
repoPath = $run.repoPath
|
|
branch = $run.branch
|
|
branchExists = $branchExists
|
|
startedAt = $run.startedAt
|
|
endedAt = if ($run.PSObject.Properties['endedAt']) { $run.endedAt } else { $null }
|
|
elapsed = $elapsed
|
|
gnhfExitCode = if ($run.PSObject.Properties['gnhfExitCode']) { $run.gnhfExitCode } else { $null }
|
|
commitCount = $commits.Count
|
|
commits = $commits
|
|
diffStat = $diffStat
|
|
stopWhen = if ($run.PSObject.Properties['stopWhen']) { $run.stopWhen } else { $null }
|
|
endState = $endState
|
|
verifyCommand = if ($run.PSObject.Properties['verifyCommand']) { $run.verifyCommand } else { $null }
|
|
verifyExitCodeBefore = if ($run.PSObject.Properties['verifyExitCodeBefore']) { $run.verifyExitCodeBefore } else { $null }
|
|
verifyExitCodeAfter = if ($run.PSObject.Properties['verifyExitCodeAfter']) { $run.verifyExitCodeAfter } else { $null }
|
|
runDir = $runDir
|
|
gnhfKind = if ($run.PSObject.Properties['gnhfKind']) { $run.gnhfKind } else { $null }
|
|
gnhfVersion = if ($run.PSObject.Properties['gnhfVersion']) { $run.gnhfVersion } else { $null }
|
|
vaultNote = $vaultNote
|
|
notesTail = $notesTailText
|
|
prompt = $run.prompt
|
|
}
|
|
}
|
|
|
|
if ($Json) {
|
|
$arr = @($results)
|
|
# NOTE: do not name this $json -- PowerShell variables are case-insensitive, so it would
|
|
# assign a string to the [switch]$Json parameter and throw at the call site.
|
|
$jsonText = $arr | ConvertTo-Json -Depth 10
|
|
if ($arr.Count -eq 1) { "[$jsonText]" } else { $jsonText }
|
|
return
|
|
}
|
|
|
|
foreach ($r in $results) {
|
|
Write-Host ''
|
|
Write-Host "=== $($r.id) ===" -ForegroundColor Cyan
|
|
Write-Host " status : $($r.status)$(if ($r.status -eq 'orphaned') { ' <- worker died without finalizing' })"
|
|
Write-Host " repo/branch : $($r.repoPath) [$($r.branch)$(if (-not $r.branchExists) { ' MISSING' })]"
|
|
Write-Host " agent/mode : $($r.agent) / $($r.mode)"
|
|
Write-Host " started : $($r.startedAt) elapsed: $($r.elapsed)"
|
|
Write-Host " commits : $($r.commitCount) $($r.diffStat)"
|
|
if ($r.stopWhen) { Write-Host " stop-when : $($r.stopWhen)" }
|
|
if ($r.endState) { Write-Host " end-state : $($r.endState.status) (iterations=$($r.endState.iterations))" }
|
|
if ($r.verifyCommand) { Write-Host " verify : '$($r.verifyCommand)' before=$($r.verifyExitCodeBefore) after=$($r.verifyExitCodeAfter)" }
|
|
if ($r.vaultNote) { Write-Host " vault note : $($r.vaultNote)" }
|
|
if ($r.runDir) { Write-Host " run dir : $($r.runDir)" }
|
|
if ($r.notesTail) {
|
|
Write-Host " --- notes tail ---"
|
|
$r.notesTail -split "`n" | ForEach-Object { Write-Host " $_" }
|
|
}
|
|
}
|
|
Write-Host ''
|
|
|