Sync: Complete project state with all MEGA SPRINT V1-V3 features and Codex stubs

This commit is contained in:
renato97
2026-04-08 17:58:47 -03:00
parent c9d3528900
commit 6d080d43b3
372 changed files with 189715 additions and 8590 deletions

View File

@@ -0,0 +1,714 @@
param(
[string]$TaskDirectory = "",
[string]$RunLabel = "autopilot",
[string]$Implementer = "",
[string[]]$Reviewers = @(),
[switch]$UseCodexMaster = $true,
[switch]$AutoFix = $true,
[switch]$DryRun
)
. (Join-Path $PSScriptRoot "Common.ps1")
$ralphRoot = Get-RalphRoot
$repoRoot = Get-RepoRoot
$roots = Get-RalphTaskRoots
$automationConfig = Get-RalphAutomationConfig
if ([string]::IsNullOrWhiteSpace($TaskDirectory)) {
$TaskDirectory = Join-Path $ralphRoot "tasks\current"
}
if ([string]::IsNullOrWhiteSpace($Implementer)) {
$Implementer = Get-DefaultImplementer
}
if ($Reviewers.Count -eq 0) {
$Reviewers = Get-DefaultReviewers
}
$taskPack = Read-TaskPack -TaskDirectory $TaskDirectory
$submissionPath = Join-Path $TaskDirectory "submission.json"
$submissionMetadata = $null
if (Test-Path $submissionPath) {
try {
$submissionMetadata = Read-JsonFile -Path $submissionPath
}
catch {
$submissionMetadata = $null
}
}
$runId = New-RunId -Label $RunLabel
$runDir = Join-Path $ralphRoot ("runs\" + $runId)
$worktreePath = Join-Path $ralphRoot ("worktrees\" + $runId + "-" + $Implementer)
Ensure-Directory -Path $runDir
Ensure-Directory -Path (Join-Path $runDir "prompts")
Ensure-Directory -Path (Join-Path $runDir "outputs")
Ensure-Directory -Path (Join-Path $runDir "reviews")
Copy-Item -Path $taskPack.Files.Task -Destination (Join-Path $runDir "TASK.md") -Force
Copy-Item -Path $taskPack.Files.Acceptance -Destination (Join-Path $runDir "ACCEPTANCE.md") -Force
Copy-Item -Path $taskPack.Files.Context -Destination (Join-Path $runDir "CONTEXT.md") -Force
$script:runState = [ordered]@{
run_id = $runId
status = "initializing"
stage = "initializing"
started_at = (Get-Date).ToString("o")
finished_at = $null
task_directory = $TaskDirectory
run_dir = $runDir
worktree = $worktreePath
implementer = [ordered]@{
name = $Implementer
status = "pending"
started_at = $null
finished_at = $null
output_file = ""
}
reviewers = @()
codex_master = [ordered]@{
enabled = [bool]$UseCodexMaster
status = $(if ($UseCodexMaster) { "pending" } else { "disabled" })
started_at = $null
finished_at = $null
output_file = ""
verdict = ""
acceptance_passed = $false
}
fix_pass = [ordered]@{
enabled = [bool]$AutoFix
status = $(if ($AutoFix) { "pending" } else { "disabled" })
started_at = $null
finished_at = $null
output_file = ""
}
latest_message = "Run initialized"
errors = @()
}
foreach ($reviewer in $Reviewers) {
$script:runState.reviewers += [ordered]@{
name = $reviewer
status = "pending"
started_at = $null
finished_at = $null
output_file = ""
}
}
function Get-FollowupGeneration {
if ($null -eq $submissionMetadata) {
return 0
}
if ($submissionMetadata.PSObject.Properties.Name -contains "followup_generation") {
try {
return [int]$submissionMetadata.followup_generation
}
catch {
return 0
}
}
return 0
}
function Save-RunState {
Set-RalphCurrentRunState -State $script:runState
}
function Set-RunPhase {
param(
[Parameter(Mandatory = $true)][string]$Stage,
[Parameter(Mandatory = $true)][string]$Status,
[Parameter(Mandatory = $true)][string]$Message
)
$script:runState.stage = $Stage
$script:runState.status = $Status
$script:runState.latest_message = $Message
Save-RunState
Add-RalphEvent -RunId $script:runState.run_id -Stage $Stage -Status $Status -Message $Message
}
function Set-ActorState {
param(
[Parameter(Mandatory = $true)][ValidateSet("implementer", "reviewer", "codex_master", "fix_pass")][string]$ActorType,
[Parameter(Mandatory = $true)][string]$Status,
[Parameter(Mandatory = $true)][string]$Message,
[string]$ActorName = "",
[string]$OutputFile = ""
)
$timestamp = (Get-Date).ToString("o")
$target = $null
$actorLabel = $ActorName
switch ($ActorType) {
"implementer" {
$target = $script:runState.implementer
$actorLabel = $script:runState.implementer.name
}
"reviewer" {
$target = $script:runState.reviewers | Where-Object { $_.name -eq $ActorName } | Select-Object -First 1
$actorLabel = $ActorName
}
"codex_master" {
$target = $script:runState.codex_master
$actorLabel = "codex_master"
}
"fix_pass" {
$target = $script:runState.fix_pass
$actorLabel = $script:runState.implementer.name
}
}
if ($null -ne $target) {
$target.status = $Status
if ($Status -eq "running" -and -not $target.started_at) {
$target.started_at = $timestamp
}
if ($Status -in @("completed", "failed", "skipped")) {
$target.finished_at = $timestamp
}
if ($OutputFile) {
$target.output_file = $OutputFile
}
}
$script:runState.latest_message = $Message
Save-RunState
Add-RalphEvent -RunId $script:runState.run_id -Stage $ActorType -Status $Status -Actor $actorLabel -Message $Message -Data @{
output_file = $OutputFile
}
}
function Invoke-CodexReviewPass {
param(
[Parameter(Mandatory = $true)][string]$StageName,
[Parameter(Mandatory = $true)][string]$PromptFileName,
[Parameter(Mandatory = $true)][string]$OutputFileName,
[Parameter(Mandatory = $true)][string]$RunningMessage,
[Parameter(Mandatory = $true)][string]$CompletedMessage,
[string[]]$ExtraSections = @()
)
$promptPath = Join-Path $runDir ("prompts\" + $PromptFileName)
$outputPath = Join-Path $runDir ("reviews\" + $OutputFileName)
New-PromptDocument `
-TemplatePath (Join-Path $ralphRoot "templates\CODEX_REVIEW_PROMPT.md") `
-TaskPack $taskPack `
-OutputPath $promptPath `
-ExtraSections $ExtraSections
Set-RunPhase -Stage $StageName -Status "running" -Message $RunningMessage
Set-ActorState -ActorType "codex_master" -Status "running" -Message $RunningMessage -OutputFile $outputPath
$verdict = & (Join-Path $PSScriptRoot "Invoke-CodexMaster.ps1") `
-PromptFile $promptPath `
-OutputFile $outputPath `
-WorkingDirectory $worktreePath
$script:runState.codex_master.verdict = [string]$verdict.verdict
$script:runState.codex_master.acceptance_passed = [bool]$verdict.acceptance_passed
Set-ActorState -ActorType "codex_master" -Status "completed" -Message ($CompletedMessage + " (verdict: " + $verdict.verdict + ")") -OutputFile $outputPath
Set-RunPhase -Stage $StageName -Status "completed" -Message ($CompletedMessage + " (verdict: " + $verdict.verdict + ")")
Save-RunState
return $verdict
}
function Invoke-AutoFollowupTask {
param(
[Parameter(Mandatory = $true)][string]$OutcomeStatus,
[Parameter(Mandatory = $true)][string]$OutcomeSummary
)
if ($null -eq $automationConfig) {
return $null
}
if (-not ($automationConfig.PSObject.Properties.Name -contains "auto_followup")) {
return $null
}
$autoFollowup = $automationConfig.auto_followup
$enabled = $false
try { $enabled = [bool]$autoFollowup.enabled } catch { $enabled = $false }
if (-not $enabled) {
return $null
}
if (-not $UseCodexMaster) {
return $null
}
$trigger = $false
if ($OutcomeStatus -eq "failed") {
try { $trigger = [bool]$autoFollowup.trigger_on_failure } catch { $trigger = $false }
}
elseif ($OutcomeStatus -eq "completed") {
try { $trigger = [bool]$autoFollowup.trigger_on_success } catch { $trigger = $false }
}
if (-not $trigger) {
return $null
}
$maxDepth = 0
try { $maxDepth = [int]$autoFollowup.max_chain_depth } catch { $maxDepth = 0 }
$currentDepth = Get-FollowupGeneration
if ($maxDepth -gt 0 -and $currentDepth -ge $maxDepth) {
return $null
}
$targetRelative = "docs\autopilot"
if ($autoFollowup.PSObject.Properties.Name -contains "target_directory" -and -not [string]::IsNullOrWhiteSpace([string]$autoFollowup.target_directory)) {
$targetRelative = [string]$autoFollowup.target_directory
}
$targetDirectory = Join-Path $repoRoot $targetRelative
Ensure-Directory -Path $targetDirectory
$prefix = "AUTOFOLLOWUP"
if ($autoFollowup.PSObject.Properties.Name -contains "title_prefix" -and -not [string]::IsNullOrWhiteSpace([string]$autoFollowup.title_prefix)) {
$prefix = [string]$autoFollowup.title_prefix
}
$nextPromptOutput = Join-Path $runDir "NEXT_TASK.md"
$extraSections = @(
"## PREVIOUS OUTCOME SUMMARY`n$OutcomeSummary",
"## RUN SUMMARY FILE`n$(Join-Path $runDir 'SUMMARY.md')",
"## RUN OUTPUTS DIRECTORY`n$(Join-Path $runDir 'outputs')",
"## RUN REVIEWS DIRECTORY`n$(Join-Path $runDir 'reviews')"
)
$null = & (Join-Path $PSScriptRoot "Invoke-CodexNextTask.ps1") `
-TaskDirectory $TaskDirectory `
-RunDirectory $runDir `
-OutputFile $nextPromptOutput `
-RunStatus $OutcomeStatus `
-WorkingDirectory $worktreePath `
-ExtraSections $extraSections
$dateLabel = Get-Date -Format "yyyyMMdd-HHmmss"
$fileName = "{0}-{1}.md" -f $dateLabel, (Convert-ToRalphSlug -Text ($prefix + "-" + $taskPack.Task.Substring(0, [Math]::Min($taskPack.Task.Length, 32))))
$finalMdPath = Join-Path $targetDirectory $fileName
Copy-Item -Path $nextPromptOutput -Destination $finalMdPath -Force
$taskInfo = New-RalphTaskPackFromMarkdown `
-MarkdownPath $finalMdPath `
-AdditionalMetadata @{
auto_generated = $true
parent_run_id = $runId
parent_task_directory = $TaskDirectory
followup_generation = ($currentDepth + 1)
source_run_status = $OutcomeStatus
}
Add-RalphEvent -RunId $runId -Stage "auto_followup" -Status "queued" -Actor "codex_master" -Message ("Auto-followup task queued: " + $taskInfo.title) -Data @{
task_directory = $taskInfo.task_directory
source_markdown = $finalMdPath
}
Send-TelegramNotification `
-EventName "task_queued" `
-Title "Auto-followup queued" `
-Message ($taskInfo.title + "`n" + $taskInfo.task_directory) `
-RunId $runId `
-Stage "auto_followup" `
-Status "queued" | Out-Null
return [ordered]@{
title = $taskInfo.title
task_directory = $taskInfo.task_directory
source_markdown = $finalMdPath
followup_generation = ($currentDepth + 1)
}
}
Save-RunState
Add-RalphEvent -RunId $runId -Stage "initializing" -Status "started" -Message "Ralph run initialized" -Data @{
implementer = $Implementer
reviewers = $Reviewers
worktree = $worktreePath
}
Send-TelegramNotification `
-EventName "run_started" `
-Title "Run started" `
-Message ("Implementer: " + $Implementer + "`nReviewers: " + ($Reviewers -join ", ")) `
-RunId $runId `
-Stage "initializing" `
-Status "started" | Out-Null
$gitStatus = & git -C $repoRoot status --short
Write-Utf8File -Path (Join-Path $runDir "repo_status_before.txt") -Content (($gitStatus -join "`n") + "`n")
$gitStat = & git -C $repoRoot diff --stat
Write-Utf8File -Path (Join-Path $runDir "repo_diff_stat_before.txt") -Content (($gitStat -join "`n") + "`n")
$implementerPrompt = Join-Path $runDir "prompts\implementer.md"
New-PromptDocument `
-TemplatePath (Join-Path $ralphRoot "templates\IMPLEMENTER_PROMPT.md") `
-TaskPack $taskPack `
-OutputPath $implementerPrompt `
-ExtraSections @(
"## WORKTREE`nEdit only inside this worktree:`n`n$worktreePath",
"## REQUIRED RUN OUTPUT`nWrite a file named CHANGES.md in this run directory:`n`n$runDir"
)
$summaryLines = @(
"# Ralph Run",
"",
"- Run ID: $runId",
"- Implementer: $Implementer",
"- Reviewers: $(($Reviewers -join ', '))",
"- Worktree: $worktreePath",
"- Codex master review: $(if ($UseCodexMaster) { 'enabled' } else { 'disabled' })",
"- Auto fix pass: $(if ($AutoFix) { 'enabled' } else { 'disabled' })",
"- Dry run: $(if ($DryRun) { 'yes' } else { 'no' })"
)
if ($DryRun) {
Set-RunPhase -Stage "dry_run" -Status "completed" -Message "Dry run prepared successfully"
$script:runState.finished_at = (Get-Date).ToString("o")
Save-RunState
Write-Utf8File -Path (Join-Path $runDir "SUMMARY.md") -Content (($summaryLines -join "`n") + "`n")
Get-Content -Raw -Path (Join-Path $runDir "SUMMARY.md")
return
}
Set-RunPhase -Stage "worktree" -Status "running" -Message "Creating isolated worktree"
& git -C $repoRoot worktree add --detach $worktreePath HEAD | Out-Null
Set-RunPhase -Stage "worktree" -Status "completed" -Message "Worktree ready"
$reviewOutputs = @()
$codexFinalVerdict = $null
$autoFollowupResult = $null
$script:heartbeatJob = $null
$script:heartbeatSignalPath = ""
$codexReviewSections = @(
"## IMPLEMENTER WORKTREE`n$worktreePath",
"## IMPLEMENTER DIFF FILE`n$(Join-Path $runDir 'implementer.patch')",
"## IMPLEMENTER STATUS FILE`n$(Join-Path $runDir 'implementer_status.txt')"
)
function Start-HeartbeatMonitor {
param(
[Parameter(Mandatory = $true)][string]$Stage,
[Parameter(Mandatory = $true)][string]$Title,
[Parameter(Mandatory = $true)][string]$Message,
[int]$IntervalSeconds = 300
)
Stop-HeartbeatMonitor
$signalPath = Join-Path $runDir ("heartbeat-" + $Stage + ".lock")
Write-Utf8File -Path $signalPath -Content ((Get-Date).ToString("o"))
$commonPath = Join-Path $PSScriptRoot "Common.ps1"
$script:heartbeatSignalPath = $signalPath
$script:heartbeatJob = Start-Job -ArgumentList $commonPath, $signalPath, $Stage, $Title, $Message, $runId, $IntervalSeconds -ScriptBlock {
param($CommonPath, $SignalPath, $StageName, $TitleText, $MessageText, $RunIdValue, $IntervalValue)
. $CommonPath
while (Test-Path $SignalPath) {
Start-Sleep -Seconds $IntervalValue
if (-not (Test-Path $SignalPath)) {
break
}
Send-TelegramNotification `
-EventName "run_heartbeat" `
-Title $TitleText `
-Message $MessageText `
-RunId $RunIdValue `
-Stage $StageName `
-Status "running" | Out-Null
}
}
}
function Stop-HeartbeatMonitor {
if (-not [string]::IsNullOrWhiteSpace($script:heartbeatSignalPath) -and (Test-Path $script:heartbeatSignalPath)) {
Remove-Item -LiteralPath $script:heartbeatSignalPath -Force -ErrorAction SilentlyContinue
}
$script:heartbeatSignalPath = ""
if ($null -ne $script:heartbeatJob) {
Wait-Job -Job $script:heartbeatJob -Timeout 1 | Out-Null
if ($script:heartbeatJob.State -eq "Running") {
Stop-Job -Job $script:heartbeatJob -Force | Out-Null
}
Remove-Job -Job $script:heartbeatJob -Force -ErrorAction SilentlyContinue
$script:heartbeatJob = $null
}
}
try {
$implementerOutput = Join-Path $runDir "outputs\implementer.json"
Set-RunPhase -Stage "implementer" -Status "running" -Message ("Implementer " + $Implementer + " started")
Set-ActorState -ActorType "implementer" -Status "running" -Message ("Implementer " + $Implementer + " received task pack") -OutputFile $implementerOutput
Start-HeartbeatMonitor -Stage "implementer" -Title "Run heartbeat" -Message ("Implementer running: " + $Implementer)
& (Join-Path $PSScriptRoot "Invoke-ClaudeProvider.ps1") `
-ProviderName $Implementer `
-PromptFile $implementerPrompt `
-OutputFile $implementerOutput `
-WorkingDirectory $worktreePath `
-AddDirectories @($runDir, $repoRoot)
Stop-HeartbeatMonitor
Set-ActorState -ActorType "implementer" -Status "completed" -Message ("Implementer " + $Implementer + " finished first pass") -OutputFile $implementerOutput
Send-TelegramNotification `
-EventName "implementer_completed" `
-Title "Implementer finished" `
-Message ("Implementer: " + $Implementer) `
-RunId $runId `
-Stage "implementer" `
-Status "completed" | Out-Null
$worktreeStatus = & git -C $worktreePath status --short
Write-Utf8File -Path (Join-Path $runDir "implementer_status.txt") -Content (($worktreeStatus -join "`n") + "`n")
$worktreeDiff = & git -C $worktreePath diff --no-ext-diff
Write-Utf8File -Path (Join-Path $runDir "implementer.patch") -Content (($worktreeDiff -join "`n") + "`n")
foreach ($reviewer in $Reviewers) {
if ($reviewer -eq $Reviewers[0]) {
Send-TelegramNotification `
-EventName "reviewers_started" `
-Title "Reviewers started" `
-Message (($Reviewers -join ", ")) `
-RunId $runId `
-Stage "review" `
-Status "running" | Out-Null
}
$promptPath = Join-Path $runDir ("prompts\review-" + $reviewer + ".md")
New-PromptDocument `
-TemplatePath (Join-Path $ralphRoot "templates\REVIEWER_PROMPT.md") `
-TaskPack $taskPack `
-OutputPath $promptPath `
-ExtraSections @(
"## IMPLEMENTER WORKTREE`n$worktreePath",
"## IMPLEMENTER DIFF FILE`n$(Join-Path $runDir 'implementer.patch')",
"## IMPLEMENTER STATUS FILE`n$(Join-Path $runDir 'implementer_status.txt')"
)
$reviewOutput = Join-Path $runDir ("reviews\" + $reviewer + ".json")
Set-RunPhase -Stage "review" -Status "running" -Message ("Reviewer " + $reviewer + " started")
Set-ActorState -ActorType "reviewer" -ActorName $reviewer -Status "running" -Message ("Reviewer " + $reviewer + " analyzing diff") -OutputFile $reviewOutput
& (Join-Path $PSScriptRoot "Invoke-ClaudeProvider.ps1") `
-ProviderName $reviewer `
-PromptFile $promptPath `
-OutputFile $reviewOutput `
-WorkingDirectory $worktreePath `
-AddDirectories @($runDir, $repoRoot)
Set-ActorState -ActorType "reviewer" -ActorName $reviewer -Status "completed" -Message ("Reviewer " + $reviewer + " completed review") -OutputFile $reviewOutput
$reviewOutputs += $reviewOutput
}
Set-RunPhase -Stage "review" -Status "completed" -Message "All provider reviews completed"
$codexReviewSections += "## REVIEW FILES`n$($reviewOutputs -join "`n")"
if ($UseCodexMaster -and $AutoFix) {
$null = Invoke-CodexReviewPass `
-StageName "codex_review_pre_fix" `
-PromptFileName "codex_master_review_pre_fix.md" `
-OutputFileName "codex_master_pre_fix.json" `
-RunningMessage "Codex master pre-fix review started" `
-CompletedMessage "Codex master pre-fix review completed" `
-ExtraSections $codexReviewSections
}
if ($AutoFix) {
$fixPrompt = Join-Path $runDir "prompts\fix_pass.md"
$fixExtraSections = @(
"## FIX PASS`nRead the reviewer outputs and fix the highest-signal issues only.",
"## REVIEW FILES`n$($reviewOutputs -join "`n")"
)
if ($UseCodexMaster) {
$fixExtraSections += "## CODEX REVIEW FILE`n$(Join-Path $runDir 'reviews\codex_master_pre_fix.json')"
}
else {
$fixExtraSections += "## CODEX REVIEW FILE`nCodex review disabled for this run."
}
$fixExtraSections += "## REQUIRED RUN OUTPUT`nUpdate CHANGES.md in this run directory after the fix pass:`n`n$runDir"
New-PromptDocument `
-TemplatePath (Join-Path $ralphRoot "templates\IMPLEMENTER_PROMPT.md") `
-TaskPack $taskPack `
-OutputPath $fixPrompt `
-ExtraSections $fixExtraSections
Set-RunPhase -Stage "fix_pass" -Status "running" -Message ("Fix pass started with " + $Implementer)
Set-ActorState -ActorType "fix_pass" -Status "running" -Message ("Implementer " + $Implementer + " applying review fixes") -OutputFile (Join-Path $runDir "outputs\fix_pass.json")
Send-TelegramNotification `
-EventName "fix_pass_started" `
-Title "Fix pass started" `
-Message ("Implementer: " + $Implementer) `
-RunId $runId `
-Stage "fix_pass" `
-Status "running" | Out-Null
Start-HeartbeatMonitor -Stage "fix_pass" -Title "Run heartbeat" -Message ("Fix pass running: " + $Implementer)
& (Join-Path $PSScriptRoot "Invoke-ClaudeProvider.ps1") `
-ProviderName $Implementer `
-PromptFile $fixPrompt `
-OutputFile (Join-Path $runDir "outputs\fix_pass.json") `
-WorkingDirectory $worktreePath `
-AddDirectories @($runDir, $repoRoot)
Stop-HeartbeatMonitor
Set-ActorState -ActorType "fix_pass" -Status "completed" -Message ("Implementer " + $Implementer + " finished fix pass") -OutputFile (Join-Path $runDir "outputs\fix_pass.json")
Set-RunPhase -Stage "fix_pass" -Status "completed" -Message "Fix pass completed"
$finalDiff = & git -C $worktreePath diff --no-ext-diff
Write-Utf8File -Path (Join-Path $runDir "final.patch") -Content (($finalDiff -join "`n") + "`n")
}
$finalStatus = & git -C $worktreePath status --short
Write-Utf8File -Path (Join-Path $runDir "final_status.txt") -Content (($finalStatus -join "`n") + "`n")
if ($UseCodexMaster) {
$finalDiffPath = Join-Path $runDir "final.patch"
if (-not (Test-Path $finalDiffPath)) {
$finalDiffPath = Join-Path $runDir "implementer.patch"
}
$codexFinalSections = @(
"## IMPLEMENTER WORKTREE`n$worktreePath",
"## FINAL DIFF FILE`n$finalDiffPath",
"## FINAL STATUS FILE`n$(Join-Path $runDir 'final_status.txt')",
"## REVIEW FILES`n$($reviewOutputs -join "`n")"
)
if ($AutoFix) {
$codexFinalSections += "## FIX PASS OUTPUT`n$(Join-Path $runDir 'outputs\\fix_pass.json')"
$codexFinalSections += "## PRE-FIX CODEX REVIEW`n$(Join-Path $runDir 'reviews\\codex_master_pre_fix.json')"
}
$codexFinalVerdict = Invoke-CodexReviewPass `
-StageName "codex_review_final" `
-PromptFileName "codex_master_review_final.md" `
-OutputFileName "codex_master_final.json" `
-RunningMessage "Codex master final review started" `
-CompletedMessage "Codex master final review completed" `
-ExtraSections $codexFinalSections
if (([string]$codexFinalVerdict.verdict) -ne "pass" -or -not [bool]$codexFinalVerdict.acceptance_passed) {
Send-TelegramNotification `
-EventName "codex_failed" `
-Title "Codex gate rejected run" `
-Message ([string]$codexFinalVerdict.summary) `
-RunId $runId `
-Stage "codex_review_final" `
-Status "failed" | Out-Null
throw ("Codex master rejected the run with verdict '{0}': {1}" -f $codexFinalVerdict.verdict, $codexFinalVerdict.summary)
}
}
$summaryLines += @(
"",
"## Outputs",
"",
"- Run directory: $runDir",
"- Worktree: $worktreePath",
"- Implementer output: $(Join-Path $runDir 'outputs\implementer.json')",
"- Final status: $(Join-Path $runDir 'final_status.txt')",
"- Codex final verdict: $(if ($UseCodexMaster -and $null -ne $codexFinalVerdict) { [string]$codexFinalVerdict.verdict } else { 'not-run' })"
)
try {
$autoFollowupResult = Invoke-AutoFollowupTask -OutcomeStatus "completed" -OutcomeSummary "Run completed successfully"
}
catch {
$script:runState.errors += ("Auto-followup generation error: " + $_.Exception.Message)
Save-RunState
Add-RalphEvent -RunId $runId -Stage "auto_followup" -Status "failed" -Actor "codex_master" -Message $_.Exception.Message
}
if ($null -ne $autoFollowupResult) {
$summaryLines += @(
"",
"## Auto Followup",
"",
"- Title: $($autoFollowupResult.title)",
"- Task directory: $($autoFollowupResult.task_directory)",
"- Source markdown: $($autoFollowupResult.source_markdown)"
)
}
Write-Utf8File -Path (Join-Path $runDir "SUMMARY.md") -Content (($summaryLines -join "`n") + "`n")
$script:runState.status = "completed"
$script:runState.stage = "completed"
$script:runState.finished_at = (Get-Date).ToString("o")
$script:runState.latest_message = "Run completed successfully"
Save-RunState
Add-RalphEvent -RunId $runId -Stage "completed" -Status "completed" -Message "Ralph run completed successfully" -Data @{
run_dir = $runDir
worktree = $worktreePath
}
Send-TelegramNotification `
-EventName "run_completed" `
-Title "Run completed" `
-Message ("Implementer: " + $Implementer + "`nCodex verdict: " + $(if ($UseCodexMaster -and $null -ne $codexFinalVerdict) { [string]$codexFinalVerdict.verdict } else { "not-run" })) `
-RunId $runId `
-Stage "completed" `
-Status "completed" | Out-Null
Get-Content -Raw -Path (Join-Path $runDir "SUMMARY.md")
}
catch {
Stop-HeartbeatMonitor
$failureMessage = $_.Exception.Message
if ($UseCodexMaster -and $null -eq $codexFinalVerdict) {
try {
$failureSections = @(
"## FAILURE CONTEXT`nThe autopilot run failed before final acceptance.",
"## FAILURE MESSAGE`n$failureMessage",
"## IMPLEMENTER WORKTREE`n$worktreePath",
"## IMPLEMENTER DIFF FILE`n$(Join-Path $runDir 'implementer.patch')",
"## IMPLEMENTER STATUS FILE`n$(Join-Path $runDir 'implementer_status.txt')",
"## REVIEW FILES`n$($reviewOutputs -join "`n")"
)
$null = Invoke-CodexReviewPass `
-StageName "codex_review_failure" `
-PromptFileName "codex_master_review_failure.md" `
-OutputFileName "codex_master_failure.json" `
-RunningMessage "Codex master failure review started" `
-CompletedMessage "Codex master failure review completed" `
-ExtraSections $failureSections
}
catch {
$script:runState.errors += ("Codex failure review error: " + $_.Exception.Message)
Add-RalphEvent -RunId $runId -Stage "codex_review_failure" -Status "failed" -Actor "codex_master" -Message $_.Exception.Message
}
}
$script:runState.status = "failed"
$script:runState.stage = "failed"
$script:runState.finished_at = (Get-Date).ToString("o")
$script:runState.latest_message = $failureMessage
$script:runState.errors += $failureMessage
Save-RunState
Add-RalphEvent -RunId $runId -Stage "failed" -Status "failed" -Message $failureMessage
Send-TelegramNotification `
-EventName "run_failed" `
-Title "Run failed" `
-Message $failureMessage `
-RunId $runId `
-Stage "failed" `
-Status "failed" | Out-Null
try {
$autoFollowupResult = Invoke-AutoFollowupTask -OutcomeStatus "failed" -OutcomeSummary $failureMessage
}
catch {
$script:runState.errors += ("Auto-followup generation error: " + $_.Exception.Message)
Save-RunState
Add-RalphEvent -RunId $runId -Stage "auto_followup" -Status "failed" -Actor "codex_master" -Message $_.Exception.Message
}
$summaryLines += @(
"",
"## Failure",
"",
$failureMessage
)
if ($null -ne $autoFollowupResult) {
$summaryLines += @(
"",
"## Auto Followup",
"",
"- Title: $($autoFollowupResult.title)",
"- Task directory: $($autoFollowupResult.task_directory)",
"- Source markdown: $($autoFollowupResult.source_markdown)"
)
}
Write-Utf8File -Path (Join-Path $runDir "SUMMARY.md") -Content (($summaryLines -join "`n") + "`n")
throw
}