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,292 @@
param(
[int]$PollSeconds = 15,
[string]$Implementer = "",
[string[]]$Reviewers = @(),
[switch]$DisableCodexMaster,
[switch]$DisableAutoFix,
[switch]$DryRun,
[switch]$Once,
[int]$MaxTasks = 0,
[string]$InboxDirectory = ""
)
. (Join-Path $PSScriptRoot "Common.ps1")
$roots = Get-RalphTaskRoots
foreach ($path in $roots.Values) {
Ensure-Directory -Path $path
}
if ([string]::IsNullOrWhiteSpace($InboxDirectory)) {
$InboxDirectory = $roots.Inbox
}
Ensure-Directory -Path $InboxDirectory
$lockFile = Get-RalphStateFile -Name "inbox_daemon.lock.json"
$daemonStateFile = Get-RalphStateFile -Name "inbox_daemon_state.json"
$script:daemonRunId = "daemon-" + (Get-Date -Format "yyyyMMdd-HHmmss")
$script:processedCount = 0
function Save-DaemonState {
param(
[string]$Status,
[string]$Message,
[hashtable]$Extra = @{}
)
$state = [ordered]@{
pid = $PID
status = $Status
message = $Message
updated_at = (Get-Date).ToString("o")
poll_seconds = $PollSeconds
dry_run = [bool]$DryRun
inbox_directory = $InboxDirectory
processed_count = $script:processedCount
}
foreach ($key in $Extra.Keys) {
$state[$key] = $Extra[$key]
}
Write-JsonFile -Path $daemonStateFile -Object $state
}
function Acquire-DaemonLock {
if (Test-Path $lockFile) {
try {
$existing = Read-JsonFile -Path $lockFile
$existingPid = 0
try { $existingPid = [int]$existing.pid } catch { $existingPid = 0 }
if ($existingPid -gt 0) {
$proc = Get-Process -Id $existingPid -ErrorAction SilentlyContinue
if ($null -ne $proc) {
throw "Ralph inbox daemon already running with PID $existingPid."
}
}
}
catch {
# stale or malformed lock; overwrite it
}
}
Write-JsonFile -Path $lockFile -Object ([ordered]@{
pid = $PID
started_at = (Get-Date).ToString("o")
inbox_directory = $InboxDirectory
})
}
function Release-DaemonLock {
if (Test-Path $lockFile) {
Remove-Item -LiteralPath $lockFile -Force -ErrorAction SilentlyContinue
}
}
function Get-NextInboxItem {
$directories = @(Get-ChildItem -LiteralPath $InboxDirectory -Directory -ErrorAction SilentlyContinue | Sort-Object LastWriteTime, Name)
foreach ($dir in $directories) {
if (Test-Path (Join-Path $dir.FullName "TASK.md")) {
return [ordered]@{
kind = "taskpack"
path = $dir.FullName
name = $dir.Name
}
}
}
$files = @(Get-ChildItem -LiteralPath $InboxDirectory -File -Filter *.md -ErrorAction SilentlyContinue | Sort-Object LastWriteTime, Name)
foreach ($file in $files) {
return [ordered]@{
kind = "markdown"
path = $file.FullName
name = $file.Name
}
}
return $null
}
function Move-InboxItemToProcessing {
param([hashtable]$Item)
$id = "{0}-{1}" -f (Get-Date -Format "yyyyMMdd-HHmmss"), (Convert-ToRalphSlug -Text ([System.IO.Path]::GetFileNameWithoutExtension($Item.name)))
$targetDir = Join-Path $roots.Processing $id
Ensure-Directory -Path $targetDir
if ($Item.kind -eq "taskpack") {
$targetParent = Split-Path -Parent $targetDir
if (-not (Test-Path $targetParent)) {
Ensure-Directory -Path $targetParent
}
Remove-Item -LiteralPath $targetDir -Recurse -Force -ErrorAction SilentlyContinue
Move-Item -LiteralPath $Item.path -Destination $targetDir
return [ordered]@{
id = $id
task_directory = $targetDir
title = $Item.name
source = $Item.path
}
}
$taskInfo = New-RalphTaskPackFromMarkdown -MarkdownPath $Item.path -TaskId $id -TargetDirectory $targetDir
Remove-Item -LiteralPath $Item.path -Force
return [ordered]@{
id = $taskInfo.id
task_directory = $taskInfo.task_directory
title = $taskInfo.title
source = $Item.path
}
}
function Finalize-ProcessedItem {
param(
[hashtable]$Processed,
[string]$DestinationRoot,
[string]$State,
[string]$RunId = "",
[string]$Summary = ""
)
Ensure-Directory -Path $DestinationRoot
$destination = Join-Path $DestinationRoot ([System.IO.Path]::GetFileName($Processed.task_directory))
if (Test-Path $destination) {
Remove-Item -LiteralPath $destination -Recurse -Force -ErrorAction SilentlyContinue
}
Move-Item -LiteralPath $Processed.task_directory -Destination $destination
$submissionFile = Join-Path $destination "submission.json"
$submission = [ordered]@{
id = $Processed.id
title = $Processed.title
state = $State
finished_at = (Get-Date).ToString("o")
source = $Processed.source
run_id = $RunId
summary = $Summary
}
Write-JsonFile -Path $submissionFile -Object $submission
return $destination
}
Acquire-DaemonLock
Save-DaemonState -Status "running" -Message "Inbox daemon started"
Add-RalphEvent -RunId $script:daemonRunId -Stage "daemon" -Status "running" -Actor "daemon" -Message "Ralph inbox daemon started" -Data @{
inbox_directory = $InboxDirectory
}
Send-TelegramNotification `
-EventName "daemon_started" `
-Title "Ralph daemon started" `
-Message ("Inbox: " + $InboxDirectory) `
-RunId $script:daemonRunId `
-Stage "daemon" `
-Status "running" | Out-Null
try {
while ($true) {
$item = Get-NextInboxItem
if ($null -eq $item) {
if ($Once) {
Save-DaemonState -Status "idle" -Message "No tasks in inbox; exiting because -Once was used"
break
}
Save-DaemonState -Status "idle" -Message "Waiting for inbox tasks"
Start-Sleep -Seconds $PollSeconds
continue
}
$processed = Move-InboxItemToProcessing -Item $item
$script:processedCount += 1
Save-DaemonState -Status "running" -Message ("Processing task " + $processed.id) -Extra @{
current_task = $processed.id
current_task_directory = $processed.task_directory
}
Add-RalphEvent -RunId $script:daemonRunId -Stage "queue" -Status "started" -Actor "daemon" -Message ("Dequeued task " + $processed.id) -Data @{
task_directory = $processed.task_directory
}
Send-TelegramNotification `
-EventName "task_processing" `
-Title "Task processing" `
-Message ($processed.title + "`n" + $processed.task_directory) `
-RunId $processed.id `
-Stage "queue" `
-Status "started" | Out-Null
$runId = ""
$summary = ""
try {
$args = @(
"-ExecutionPolicy", "Bypass",
"-File", (Join-Path $PSScriptRoot "Start-RalphAutopilot.ps1"),
"-TaskDirectory", $processed.task_directory,
"-RunLabel", "queue"
)
if ($DryRun) {
$args += "-DryRun"
}
if (-not [string]::IsNullOrWhiteSpace($Implementer)) {
$args += @("-Implementer", $Implementer)
}
foreach ($reviewer in $Reviewers) {
$args += @("-Reviewers", $reviewer)
}
if ($DisableCodexMaster) {
$args += "-UseCodexMaster:$false"
}
if ($DisableAutoFix) {
$args += "-AutoFix:$false"
}
& powershell.exe @args
if ($LASTEXITCODE -ne 0) {
throw "Start-RalphAutopilot.ps1 failed with exit code $LASTEXITCODE"
}
$currentRunState = Read-JsonFile -Path (Get-RalphStateFile -Name "current_run.json")
$runId = [string]$currentRunState.run_id
$summary = [string]$currentRunState.latest_message
$finalPath = Finalize-ProcessedItem -Processed $processed -DestinationRoot $roots.Completed -State "completed" -RunId $runId -Summary $summary
Add-RalphEvent -RunId $script:daemonRunId -Stage "queue" -Status "completed" -Actor "daemon" -Message ("Completed task " + $processed.id) -Data @{
task_directory = $finalPath
run_id = $runId
}
Send-TelegramNotification `
-EventName "task_completed" `
-Title "Task completed" `
-Message ($processed.title + "`n" + $summary) `
-RunId $runId `
-Stage "queue" `
-Status "completed" | Out-Null
}
catch {
$summary = $_.Exception.Message
$failedPath = Finalize-ProcessedItem -Processed $processed -DestinationRoot $roots.Failed -State "failed" -RunId $runId -Summary $summary
Add-RalphEvent -RunId $script:daemonRunId -Stage "queue" -Status "failed" -Actor "daemon" -Message ("Failed task " + $processed.id + ": " + $summary) -Data @{
task_directory = $failedPath
run_id = $runId
}
Send-TelegramNotification `
-EventName "task_failed" `
-Title "Task failed" `
-Message ($processed.title + "`n" + $summary) `
-RunId $runId `
-Stage "queue" `
-Status "failed" | Out-Null
}
if ($MaxTasks -gt 0 -and $script:processedCount -ge $MaxTasks) {
Save-DaemonState -Status "completed" -Message "MaxTasks limit reached"
break
}
}
}
finally {
Save-DaemonState -Status "stopped" -Message "Inbox daemon stopped"
Add-RalphEvent -RunId $script:daemonRunId -Stage "daemon" -Status "stopped" -Actor "daemon" -Message "Ralph inbox daemon stopped"
Send-TelegramNotification `
-EventName "daemon_stopped" `
-Title "Ralph daemon stopped" `
-Message "Inbox daemon stopped" `
-RunId $script:daemonRunId `
-Stage "daemon" `
-Status "stopped" | Out-Null
Release-DaemonLock
}