param( [string]$AgentRoot = "C:\Wooo\Agent99", [switch]$InstallScheduledTasks ) $ErrorActionPreference = "Stop" $SourceRoot = Split-Path -Parent $MyInvocation.MyCommand.Path $BinDir = Join-Path $AgentRoot "bin" $ConfigDir = Join-Path $AgentRoot "config" $EvidenceDir = Join-Path $AgentRoot "evidence" $LogDir = Join-Path $AgentRoot "logs" $QueueDir = Join-Path $AgentRoot "queue" $RequestDir = Join-Path $AgentRoot "requests" $AlertDir = Join-Path $AgentRoot "alerts" $PlaybookDir = Join-Path $AgentRoot "playbooks" $DashboardDir = Join-Path $AgentRoot "dashboard" foreach ($dir in @($AgentRoot, $BinDir, $ConfigDir, $EvidenceDir, $LogDir, $QueueDir, $RequestDir, $AlertDir, $PlaybookDir, $DashboardDir)) { New-Item -ItemType Directory -Force -Path $dir | Out-Null } function Copy-AgentFile { param([string]$Name) $src = Join-Path $SourceRoot $Name $dst = Join-Path $BinDir $Name if (Test-Path $src) { $srcFull = [System.IO.Path]::GetFullPath($src) $dstFull = [System.IO.Path]::GetFullPath($dst) if ($srcFull -ne $dstFull) { Copy-Item -Force $src $dst } } } Copy-AgentFile "agent99-control-plane.ps1" Copy-AgentFile "agent99-register-tasks.ps1" Copy-AgentFile "agent99-submit-request.ps1" Copy-AgentFile "agent99-telegram-inbox.ps1" Copy-AgentFile "agent99-sre-alert-inbox.ps1" Copy-AgentFile "agent99-sre-alert-relay.ps1" Copy-AgentFile "host-reboot-scorecard.ps1" $exampleConfig = Join-Path $SourceRoot "agent99.config.example.json" $configPath = Join-Path $ConfigDir "agent99.config.json" if (-not (Test-Path $configPath)) { if (Test-Path $exampleConfig) { Copy-Item $exampleConfig $configPath } else { @" { "agentName": "Agent99", "agentRoot": "$($AgentRoot.Replace('\', '\\'))", "sshUser": "wooo", "sshUsers": {}, "vmrunPath": "", "hosts": ["192.168.0.110", "192.168.0.112", "192.168.0.120", "192.168.0.121", "192.168.0.188"], "vms": [], "publicUrls": ["awoooi.wooo.work", "stock.wooo.work", "2026fifa.wooo.work", "gitea.wooo.work", "harbor.wooo.work"], "sreAlertRelay": { "enabled": true, "prefix": "http://+:8787/agent99/sre-alert/", "tokenEnv": "AGENT99_SRE_RELAY_TOKEN", "allowedRemotePrefixes": ["127.", "::1", "192.168.0."] }, "telegram": { "enabled": true, "botTokenEnv": "AGENT99_TELEGRAM_BOT_TOKEN", "chatIdEnv": "AGENT99_TELEGRAM_CHAT_ID", "botTokenEnvAliases": ["AWOOOI_TG_BOT_TOKEN", "OPENCLAW_TG_BOT_TOKEN", "TELEGRAM_BOT_TOKEN", "TELEGRAM_TOKEN", "TG_BOT_TOKEN", "AIDER_WATCH_TELEGRAM_TOKEN"], "chatIdEnvAliases": ["TELEGRAM_CHAT_ID", "TELEGRAM_ALERT_CHAT_ID", "TELEGRAM_P0_CHAT_ID", "TELEGRAM_SECURITY_CHAT_ID", "OPENCLAW_TG_CHAT_ID", "TG_CHAT_ID", "AIDER_WATCH_TELEGRAM_CHAT_ID"], "relay": { "enabled": true, "host": "192.168.0.110", "container": "stockplatform-v2-api-1" }, "alertAllOperations": false, "alertInfoEvents": false, "alertOperatorCommands": true, "alertSreCommandResults": true, "dedupeMinutes": 30 }, "selfHealth": { "scheduledTasks": [ "Wooo-Agent99-Startup-Recovery", "Wooo-Agent99-Heartbeat", "Wooo-Agent99-Performance-Guard", "Wooo-Agent99-Control-Loop", "Wooo-Agent99-Telegram-Inbox", "Wooo-Agent99-SRE-Alert-Inbox", "Wooo-Agent99-SRE-Alert-Relay", "Wooo-Agent99-Self-Health", "Wooo-Agent99-Backup-Health" ] }, "performance": { "enabled": true, "intervalMinutes": 1, "loadPerCoreWarning": 0.9, "loadPerCoreCritical": 1.5, "memoryAvailablePercentCritical": 10, "diskUsedPercentWarning": 90, "diskUsedPercentCritical": 95, "captureTopCpuOnWarning": true, "topCpuTimeoutSeconds": 10, "loadShedding": { "enabled": true, "actions": [] } }, "backupHealth": { "host": "192.168.0.110", "targets": [], "fileChecks": [], "cronPatterns": [] } } "@ | Set-Content -Encoding UTF8 $configPath } } $launcher = Join-Path $AgentRoot "agent99-run.ps1" @" param( [ValidateSet("Status", "Recover", "StartVMs", "PublicSmoke", "HarborRepair", "AwoooRepair", "Perf", "LoadShed", "SelfCheck", "BackupCheck", "ProviderFreshness", "SecurityTriage", "ControlTick")] [string]`$Mode = "Status", [switch]`$ControlledApply, [switch]`$SuppressAlerts, [string]`$SuppressReason = "" ) & "$BinDir\agent99-control-plane.ps1" -Mode `$Mode -ControlledApply:`$ControlledApply -SuppressAlerts:`$SuppressAlerts -SuppressReason `$SuppressReason -ConfigPath "$configPath" -EvidenceDir "$EvidenceDir" "@ | Set-Content -Encoding UTF8 $launcher $submitCmd = Join-Path $AgentRoot "agent99-submit-request.cmd" @" @echo off powershell.exe -NoProfile -ExecutionPolicy Bypass -File "$BinDir\agent99-submit-request.ps1" -RunNow pause "@ | Set-Content -Encoding ASCII $submitCmd function Find-Vmrun { $candidates = @( "C:\Program Files (x86)\VMware\VMware Workstation\vmrun.exe", "C:\Program Files\VMware\VMware Workstation\vmrun.exe" ) foreach ($candidate in $candidates) { if (Test-Path $candidate) { return $candidate } } return "" } $vmrun = Find-Vmrun if ($vmrun) { $config = Get-Content $configPath -Raw | ConvertFrom-Json $config.vmrunPath = $vmrun $config | ConvertTo-Json -Depth 8 | Set-Content -Encoding UTF8 $configPath } if ($InstallScheduledTasks) { & (Join-Path $BinDir "agent99-register-tasks.ps1") -AgentRoot $AgentRoot } Write-Host "Agent99 bootstrap complete" Write-Host "AgentRoot: $AgentRoot" Write-Host "Config: $configPath" Write-Host "Evidence: $EvidenceDir" if ($vmrun) { Write-Host "vmrun: $vmrun" } else { Write-Host "vmrun: not detected; update agent99.config.json" }