param( [string]$Instruction = "", [string]$Mode = "", [switch]$ControlledApply, [switch]$RunNow, [string]$Source = "agent99-submit-request", [string]$RequestedBy = "", [string]$ExternalId = "", [string]$ReplyChatId = "", [string]$AgentRoot = "C:\Wooo\Agent99" ) $ErrorActionPreference = "Stop" if (-not $Instruction) { $Instruction = Read-Host "Agent99 request" } if (-not $Instruction) { throw "Instruction is required." } $allowedModes = @("Status", "Recover", "StartVMs", "PublicSmoke", "HarborRepair", "AwoooRepair", "Perf", "LoadShed", "SelfCheck", "BackupCheck") function Test-AgentContainsChar { param( [string]$Text, [int[]]$Codes ) foreach ($code in $Codes) { if ($Text.IndexOf([string][char]$code) -ge 0) { return $true } } return $false } function Resolve-AgentRequestMode { param( [string]$Text, [string]$ExplicitMode ) if ($ExplicitMode) { if ($ExplicitMode -notin $allowedModes) { throw "Mode is not allowlisted: $ExplicitMode" } return $ExplicitMode } $lower = $Text.ToLowerInvariant() $mentionsPublic = ($lower -match "public|smoke|website|site|route|url|http|502" -or (Test-AgentContainsChar $Text @(0x7DB2, 0x7AD9))) $wantsRecovery = ($lower -match "recover|reboot|restore|restart|startup|repair|fix|502" -or (Test-AgentContainsChar $Text @(0x6062, 0x5FA9, 0x91CD, 0x555F, 0x4FEE))) if ($mentionsPublic -and $wantsRecovery) { return "Recover" } if ($mentionsPublic) { return "PublicSmoke" } if ($wantsRecovery) { return "Recover" } if ($lower -match "vm|vmware|startvm|start vm|start vms" -or (Test-AgentContainsChar $Text @(0x865B, 0x64EC, 0x4E3B, 0x6A5F))) { return "StartVMs" } if ($lower -match "cpu|load|memory|ram|disk|perf|performance|pressure" -or (Test-AgentContainsChar $Text @(0x6548, 0x80FD, 0x78C1, 0x789F, 0x8CA0, 0x8F09))) { return "Perf" } if ($lower -match "backup|snapshot|restore drill|cron" -or (Test-AgentContainsChar $Text @(0x5099, 0x4EFD))) { return "BackupCheck" } if ($lower -match "self|agent|health|selfcheck" -or (Test-AgentContainsChar $Text @(0x81EA, 0x6AA2, 0x5065, 0x5EB7))) { return "SelfCheck" } if ($lower -match "harbor|registry") { return "HarborRepair" } if ($lower -match "awoooi|k3s|pod|pods") { return "AwoooRepair" } return "Status" } $modeName = Resolve-AgentRequestMode $Instruction $Mode $queueDir = Join-Path $AgentRoot "queue" $requestDir = Join-Path $AgentRoot "requests" $evidenceDir = Join-Path $AgentRoot "evidence" New-Item -ItemType Directory -Force -Path $queueDir, $requestDir, $evidenceDir | Out-Null $id = "request-" + (Get-Date -Format "yyyyMMdd-HHmmss") + "-" + ([guid]::NewGuid().ToString("N").Substring(0, 8)) $request = [pscustomobject]@{ id = $id instruction = $Instruction resolvedMode = $modeName controlledApply = [bool]$ControlledApply requestedBy = if ($RequestedBy) { $RequestedBy } else { $env:USERNAME } source = $Source externalId = $ExternalId createdAt = (Get-Date -Format o) } $requestPath = Join-Path $requestDir "$id.json" $queuePath = Join-Path $queueDir "$id.json" $request | ConvertTo-Json -Depth 8 | Set-Content -Path $requestPath -Encoding UTF8 [pscustomobject]@{ id = $id mode = $modeName controlledApply = [bool]$ControlledApply requestedBy = if ($RequestedBy) { $RequestedBy } else { $env:USERNAME } source = $Source externalId = $ExternalId reason = "operator_instruction" instruction = $Instruction requestPath = $requestPath replyChatId = $ReplyChatId createdAt = (Get-Date -Format o) } | ConvertTo-Json -Depth 8 | Set-Content -Path $queuePath -Encoding UTF8 $result = [pscustomobject]@{ ok = $true id = $id instruction = $Instruction resolvedMode = $modeName controlledApply = [bool]$ControlledApply requestPath = $requestPath queuePath = $queuePath runNow = [bool]$RunNow controlExitCode = $null } if ($RunNow) { $launcher = Join-Path $AgentRoot "agent99-run.ps1" $process = Start-Process -FilePath "powershell.exe" -ArgumentList @("-NoProfile", "-ExecutionPolicy", "Bypass", "-File", $launcher, "-Mode", "ControlTick") -Wait -PassThru -WindowStyle Hidden $process.Refresh() $result.controlExitCode = $process.ExitCode } $submitEvidence = Join-Path $evidenceDir "agent99-submit-$id.json" $result | ConvertTo-Json -Depth 8 | Set-Content -Path $submitEvidence -Encoding UTF8 $result | ConvertTo-Json -Depth 8