Sync: Complete project state with all MEGA SPRINT V1-V3 features and Codex stubs
This commit is contained in:
714
ralph/scripts/Start-RalphAutopilot.ps1
Normal file
714
ralph/scripts/Start-RalphAutopilot.ps1
Normal 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
|
||||
}
|
||||
Reference in New Issue
Block a user