$r,'executed'=>true,'intent'=>'wave114']); exit; } function wv_sh($cmd, $t=15){ return trim(shell_exec("timeout $t bash -c " . escapeshellarg($cmd) . " 2>&1")); } // ===== SNAPSHOT HETZNER ARCHIVER (Opus 12-AVR) ===== if (preg_match('/snapshot.*hetzner|hetzner.*snap|snap.*archiv|archiv.*snap|snap.*status|snap.*progress/i', $q)) { $log = @file_get_contents('/tmp/wevia-snapshot-archiver.log') ?: 'NO LOG'; $ps = wv_sh('ps aux | grep "wevia-snap-archiver\|archive-remaining" | grep -v grep'); $hz = wv_sh('python3 /opt/weval-l99/wevia-snap-archiver.py list 2>&1'); $gh = wv_sh("curl -s 'https://api.github.com/repos/Yacineutt/weval-archive/releases?per_page=10' -H 'Authorization: token REDACTED_CURRENT_PAT' | python3 -c \"import sys,json;[print(f\\\" {r.get('tag_name','?'):20s} assets:{len(r.get('assets',[]))}\\\") for r in json.load(sys.stdin) if 'snap' in r.get('tag_name','').lower()]\""); $r = "SNAPSHOT ARCHIVER STATUS:\n"; $r .= "Process: " . ($ps ? "RUNNING\n$ps" : "NOT RUNNING") . "\n\n"; $r .= "Hetzner Snapshots:\n$hz\n\n"; $r .= "GitHub Releases:\n" . ($gh ?: "none") . "\n\n"; $r .= "Log (last 15 lines):\n" . implode("\n", array_slice(explode("\n", trim($log)), -15)); wv_out($r); } // ===== RECONCILE WAVE 114 ===== if (preg_match('/reconcil|wave.?11[34]|bilan.?complet|etat.?global/i', $q)) { $nr = @json_decode(@file_get_contents('/var/www/html/api/nonreg-latest.json'), true) ?: []; $bench = @json_decode(@file_get_contents('/var/www/html/api/ai-benchmark-cache.json'), true) ?: []; $sot = @json_decode(@file_get_contents('/var/www/html/api/source-of-truth.json'), true) ?: []; $ais = $bench['all_ais'] ?? []; $wired = count(array_filter($ais, fn($a)=>!empty($a['wired']))); $total = count($ais); $gitH = wv_sh("cd /var/www/html && git log --oneline -1"); $gitB = wv_sh("cd /opt/wevia-brain 2>/dev/null && git log --oneline -1"); $dock = (int)wv_sh("docker ps -q | wc -l"); $pap = wv_sh("curl -sk -o /dev/null -w '%{http_code}' https://paperclip.weval-consulting.com"); $mir = wv_sh("curl -sk -o /dev/null -w '%{http_code}' https://mirofish.weval-consulting.com"); $dir = @json_decode(wv_sh("curl -sk https://weval-consulting.com/api/wevia-director.php?status"), true) ?: []; $dirU = $dir['uptime'] ?? '?'; $wvSend = wv_sh("curl -sk -o /dev/null -w '%{http_code}' https://wevads.weval-consulting.com/deliverads/send-pipeline.php"); $r = "WAVE 114 RECONCILIATION\n"; $r .= "NonReg: {$nr['pass']}/{$nr['total']} (fail=".count($nr['failures'] ?? []).")\n"; $r .= "AIs: $wired/$total wired (non-wired = refs payantes)\n"; $r .= "Docker: $dock containers | Paperclip=$pap | MiroFish=$mir\n"; $r .= "WV-Send S95: HTTP $wvSend ".($wvSend=='500'?'❌ FAIL':'✅')."\n"; $r .= "Director: uptime $dirU\n"; $r .= "Git html HEAD: ".substr($gitH,0,60)."\n"; if ($gitB) $r .= "Git brain HEAD: ".substr($gitB,0,60)."\n"; $r .= "---\nGAPS restants:\n"; if ($wvSend == '500') $r .= "- WV-Send S95 500 (send-pipeline.php)\n"; if (!file_exists('/var/www/html/agents-archi.html')) $r .= "- agents-archi.html manquant\n"; else { $ah = file_get_contents('/var/www/html/agents-archi.html'); $oc = substr_count($ah, '{'); $cc = substr_count($ah, '}'); if ($oc != $cc) $r .= "- agents-archi.html brace imbalance: $oc ouvertes / $cc fermees\n"; } wv_out($r); } // ===== SCAN GAPS ===== if (preg_match('/scan.?gap|gap.?scan|detecte.?lacune|lacune/i', $q)) { $gaps = []; // 1. WV-Send $c = wv_sh("curl -sk -o /dev/null -w '%{http_code}' https://wevads.weval-consulting.com/deliverads/send-pipeline.php"); if ($c == '500') $gaps[] = "WV-Send S95 returns 500 (send-pipeline.php)"; // 2. agents-archi brace if (file_exists('/var/www/html/agents-archi.html')) { $t = file_get_contents('/var/www/html/agents-archi.html'); $o = substr_count($t, '{'); $c = substr_count($t, '}'); if ($o != $c) $gaps[] = "agents-archi.html braces $o/$c (imbalance)"; } // 3. Paperclip/MiroFish $p = wv_sh("curl -sk -o /dev/null -w '%{http_code}' https://paperclip.weval-consulting.com"); $m = wv_sh("curl -sk -o /dev/null -w '%{http_code}' https://mirofish.weval-consulting.com"); if ($p != '200') $gaps[] = "Paperclip HTTP $p"; if ($m != '200') $gaps[] = "MiroFish HTTP $m"; // 4. NonReg fails $nr = @json_decode(@file_get_contents('/var/www/html/api/nonreg-latest.json'), true) ?: []; if (!empty($nr['failures'])) foreach($nr['failures'] as $f) $gaps[] = "NonReg fail: ".(is_array($f) ? ($f['n'].' '.$f['d']) : $f); // 5. GitHub PAT $pat = @file_get_contents('/etc/weval/secrets.env'); if ($pat && preg_match('/GITHUB_PAT.*ghp_/', $pat)) $gaps[] = "GitHub PAT: verifier expiration manuellement"; $r = "SCAN GAPS (".count($gaps)." lacunes):\n"; foreach($gaps as $i => $g) $r .= ($i+1).". $g\n"; if (!$gaps) $r .= "Aucune lacune detectee."; wv_out($r); } // ===== FIX WV-SEND ===== if (preg_match('/fix.?wv.?send|diagnose.?wv.?send|wv.?send.?500/i', $q)) { $url = 'https://wevads.weval-consulting.com/deliverads/send-pipeline.php'; $verbose = wv_sh("curl -sk -i '$url' 2>&1 | head -30"); $log = wv_sh("ssh -p 49222 -o StrictHostKeyChecking=no -o ConnectTimeout=5 -i /root/.ssh/wevads_key root@10.1.0.3 'tail -30 /var/log/nginx/wevads.error.log 2>/dev/null | grep -i \"send-pipeline\\|deliverads\" | tail -5' 2>&1", 20); $file = wv_sh("ssh -p 49222 -o StrictHostKeyChecking=no -o ConnectTimeout=5 -i /root/.ssh/wevads_key root@10.1.0.3 'ls -la /var/www/wevads/deliverads/send-pipeline.php 2>&1; php -l /var/www/wevads/deliverads/send-pipeline.php 2>&1' 2>&1", 20); $r = "FIX WV-SEND diagnosis:\n"; $r .= "=== HTTP ===\n".substr($verbose, 0, 500)."\n"; $r .= "=== FILE+LINT ===\n".substr($file, 0, 500)."\n"; $r .= "=== NGINX LOG ===\n".substr($log, 0, 500)."\n"; wv_out($r); } // ===== L99 BETON ===== if (preg_match('/l99.?beton|beton.?orchestra|l99.?12.?couche/i', $q)) { $exists = file_exists('/opt/weval-l99/l99-beton.sh'); if (!$exists) wv_out("l99-beton.sh non trouve"); // Run in background shell_exec("nohup bash /opt/weval-l99/l99-beton.sh > /tmp/l99-beton.out 2>&1 &"); sleep(2); $pid = wv_sh("pgrep -f l99-beton.sh | head -1"); wv_out("L99 BETON launched (pid=$pid). 12 couches en cours. Check: /opt/weval-l99/beton/l99-beton-latest.json"); } // ===== AGENTS-ARCHI BRACE CHECK ===== if (preg_match('/agents.?archi|archi.?3d|brace.?check|code.?analyze/i', $q)) { $f = '/var/www/html/agents-archi.html'; if (!file_exists($f)) wv_out("agents-archi.html not found"); $t = file_get_contents($f); $lines = explode("\n", $t); // find