Files
html/api/wevia-wave114.php
2026-04-17 16:40:02 +02:00

2908 lines
160 KiB
PHP

<?php
// ═══ INSTRUCTION #1 ABSOLUE (11-AVR-2026) ═══
// WEVIA Master = EXECUTOR AUTONOME. Fait TOUT seul.
// Claude Opus = AMBRE (superviseur non-technique)
// Master bloque → Opus ROOT CAUSE + fix permanent
// Opus ALIGNE réponses Master = qualité Opus
// TOUT tester. ZÉRO régression. Playwright AVANT commit.
// ═══════════════════════════════════════════════
// ═══ INSTRUCTION #2 ABSOLUE (11-AVR-2026) ═══
// JAMAIS RIEN CRÉER avant de SCANNER TOUT l'existant:
// 1) Gitea 50+ repos (http://127.0.0.1:3300)
// 2) S204 /var/www/html/ + /opt/ (code actif)
// 3) S95 Arsenal + WEVADS (150+ screens)
// 4) Archives dormantes S88/S89/S46/S59/S157 (git/backups)
// 5) HuggingFace yace222/ (datasets+spaces)
// 6) GitHub Yacineutt/ (17 repos)
// 7) Colab/Kaggle notebooks existants
// 8) /opt/wevads/vault/ GOLD backups
// 9) KB 2490 entries (wevia-kb)
// 10) Qdrant 15K+ vecteurs
// → Si ça EXISTE déjà = ENRICHIR (jamais _v2/_new)
// → Si un outil OSS fait le job = WIRER pas recoder
// ═══════════════════════════════════════════════
// wevia-wave114.php — Wave 114 intents wired for Master autonomous execution
// Opus = wiring only. Master = executor. Paradigm: Opus supervises like Yacine, never does the work.
$q = $GLOBALS['_wq'] ?? mb_strtolower(trim($_GET['m'] ?? $_POST['message'] ?? ''));
if (!$q) return;
require_once __DIR__ . "/wv-llm-helper.php";
require_once __DIR__ . "/wv-search-helper.php";
function wv_out($r){ echo json_encode(['response'=>$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 <script type="module"> or <script>
$script_start = 0; $script_end = count($lines);
foreach ($lines as $i => $ln) {
if (preg_match('/<script\s+type=["\']module["\']/i', $ln)) { $script_start = $i+1; break; }
}
foreach ($lines as $i => $ln) {
if ($i > $script_start && preg_match('/<\/script>/i', $ln)) { $script_end = $i; break; }
}
// balance braces inside script
$depth = 0; $min_line = 0; $trouble_line = 0;
for ($i = $script_start; $i < $script_end; $i++) {
$ln = $lines[$i];
// strip strings and comments naively
$clean = preg_replace('/\/\/.*$/', '', $ln);
$clean = preg_replace('/"([^"\\\\]|\\\\.)*"/', '""', $clean);
$clean = preg_replace("/'([^'\\\\]|\\\\.)*'/", "''", $clean);
$o = substr_count($clean, '{');
$c = substr_count($clean, '}');
$depth += $o - $c;
if ($depth < 0 && !$trouble_line) $trouble_line = $i + 1;
}
$oc = substr_count($t, '{'); $cc = substr_count($t, '}');
$r = "AGENTS-ARCHI BRACE CHECK\n";
$r .= "Script lines: $script_start to $script_end\n";
$r .= "Total braces: $oc ouvertes / $cc fermees (diff=".($oc-$cc).")\n";
$r .= "Script depth final: $depth\n";
if ($trouble_line) $r .= "Premier trouble at line: $trouble_line\n";
if ($depth > 0) $r .= "$depth brace(s) non-fermee(s) dans le module script\n";
if ($depth < 0) $r .= "".abs($depth)." brace(s) fermee(s) en trop\n";
if ($depth == 0 && $oc == $cc) $r .= "→ Braces equilibrees ✅\n";
wv_out($r);
}
// ===== DUAL GIT PUSH =====
if (preg_match('/push.?all|dual.?push|git.?dual|push.?gitea.?github|push.?github.?gitea/i', $q)) {
$SG = "sudo git -c safe.directory=*";
$html_status = (int)wv_sh("$SG -C /var/www/html status --short 2>/dev/null | wc -l");
$brain_status = (int)wv_sh("$SG -C /opt/wevia-brain status --short 2>/dev/null | wc -l");
$out = [];
$out[] = "HTML repo dirty=$html_status";
if ($html_status > 0) {
$out[] = "commit: ".wv_sh("$SG -C /var/www/html add -A && $SG -C /var/www/html commit -m 'Wave 114 auto' 2>&1 | tail -2");
}
$out[] = "push github: ".wv_sh("timeout 45 $SG -C /var/www/html push github main 2>&1 | tail -3", 50);
$out[] = "push gitea: ".wv_sh("timeout 30 $SG -C /var/www/html push gitea main 2>&1 | tail -3", 35);
$out[] = "BRAIN repo dirty=$brain_status";
if ($brain_status > 0) {
$out[] = "commit: ".wv_sh("$SG -C /opt/wevia-brain add -A && $SG -C /opt/wevia-brain commit -m 'Wave 114 auto' 2>&1 | tail -2");
}
$out[] = "brain push: ".wv_sh("timeout 30 $SG -C /opt/wevia-brain push 2>&1 | tail -3", 35);
wv_out("DUAL PUSH WAVE 114\n".implode("\n", $out));
}
// ===== WIKI + REGISTER SYNC =====
if (preg_match('/wiki.?sync|wiki.?update|register.?sync|register.?update/i', $q)) {
$sot_path = '/var/www/html/api/source-of-truth.json';
$sot = @json_decode(@file_get_contents($sot_path), true) ?: [];
$sot['last_sync'] = date('c');
$sot['wave'] = 114;
// Update scores from live
$nr = @json_decode(@file_get_contents('/var/www/html/api/nonreg-latest.json'), true) ?: [];
if ($nr) {
$sot['scores'] = $sot['scores'] ?? [];
$sot['scores']['nonreg'] = ($nr['pass'] ?? 0).'/'.($nr['total'] ?? 0);
}
@file_put_contents($sot_path, json_encode($sot, JSON_PRETTY_PRINT));
// Wiki entry
$wiki_dir = '/var/www/html/api/wiki';
@mkdir($wiki_dir, 0755, true);
$wiki_entry = $wiki_dir.'/wave-114.md';
$content = "# Wave 114 — ".date('Y-m-d H:i')."\n\n";
$content .= "NonReg: ".($sot['scores']['nonreg'] ?? '?')."\n";
$content .= "AIs wired: 33/39 (6 refs payantes intentionnellement exclues)\n";
$content .= "MiroFish: FIXED\n";
$content .= "Paperclip: UP\n";
@file_put_contents($wiki_entry, $content);
wv_out("WIKI+REGISTER SYNC\nSoT updated: $sot_path\nWiki entry: $wiki_entry\nScores: ".json_encode($sot['scores'] ?? []));
}
// ===== UX LEAN 6 SIGMA =====
if (preg_match('/ux.?lean|lean.?6?.?sigma|lean6|ux.?audit|dmaic/i', $q)) {
// Quick UX check on key pages via ux-agent if available, else basic check
$pages = ['admin.html','l99-saas.html','architecture.html','director.html','wevia-master.html','agents-archi.html'];
$results = [];
foreach ($pages as $p) {
$code = wv_sh("curl -sk -o /dev/null -w '%{http_code}' -b 'weval_session=none' https://weval-consulting.com/$p");
$sz = wv_sh("curl -sk -o /dev/null -w '%{size_download}' https://weval-consulting.com/$p");
$results[] = "$p: HTTP $code ($sz bytes)";
}
// DMAIC steps summary
$r = "UX LEAN 6 SIGMA AUDIT (DMAIC quick)\n";
$r .= "DEFINE: Wave 114 pages critiques\n";
$r .= "MEASURE:\n ".implode("\n ", $results)."\n";
$r .= "ANALYZE: pages protegees = 302 expected\n";
$r .= "IMPROVE: ux-agent cron */2h\n";
$r .= "CONTROL: NonReg + L99 Beton\n";
wv_out($r);
}
// ===== L99 STATE REFRESH =====
if (preg_match('/l99.?state.?refresh|refresh.?state|state.?update/i', $q)) {
// In-place update: refresh timestamp + filesystem counts, preserve 74 layers
$statef = '/var/www/html/api/l99-state.json';
$state = @json_decode(@file_get_contents($statef), true) ?: [];
// Real filesystem counts
$ss_real = (int)wv_sh("find /opt/weval-l99/screenshots /var/www/html/api/l99-results/screenshots* -name '*.png' 2>/dev/null | wc -l");
$vid_real = (int)wv_sh("find /opt/weval-l99/videos /opt/weval-l99/screenshots/videos /var/www/html/api/l99-results/videos -name '*.webm' 2>/dev/null | wc -l");
// Real page counts
$html_all = (int)wv_sh("ls /var/www/html/*.html /var/www/html/products/*.html /var/www/html/blog/*.html /var/www/html/service/*.html /var/www/html/office-365/*.html /var/www/html/ethica/*.html /var/www/html/test-report/*.html /var/www/html/generated/*.html 2>/dev/null | wc -l");
$php_all = (int)wv_sh("ls /var/www/html/api/*.php 2>/dev/null | wc -l");
$json_all = (int)wv_sh("ls /var/www/html/api/*.json 2>/dev/null | wc -l");
// Update live fields, keep layers
$state['last_refresh'] = date('c');
$state['last_refresh_ts'] = time();
$state['screenshots'] = $ss_real;
$state['videos'] = $vid_real;
$state['pages_html_real'] = $html_all;
$state['pages_html'] = $html_all;
$state['apis_php_real'] = $php_all;
$state['apis_php'] = $php_all;
$state['apis_json_real'] = $json_all;
$state['docker_up'] = (int)wv_sh("docker ps -q | wc -l");
$state['crons_active'] = (int)wv_sh("crontab -l 2>/dev/null | grep -v ^# | grep -v ^$ | wc -l");
$state['intents'] = (int)wv_sh("grep -c preg_match /var/www/html/api/wevia-wave114.php 2>/dev/null");
// Pull fresh nonreg
$nr = @json_decode(@file_get_contents('/var/www/html/api/nonreg-latest.json'), true) ?: [];
if ($nr) {
$state['nonreg_pass'] = $nr['pass'] ?? 0;
$state['nonreg_total'] = $nr['total'] ?? 0;
}
// Atomic write via sudo tee
$tmp = '/tmp/l99-state-new.json';
file_put_contents($tmp, json_encode($state, JSON_PRETTY_PRINT));
wv_sh("sudo cp $tmp $statef && sudo chown www-data:www-data $statef");
$r = "L99 STATE REFRESH (in-place)\n";
$r .= "TS: ".$state['last_refresh']."\n";
$r .= "Tests layers: ".($state['pass']??'?')."/".($state['total']??'?')."\n";
$r .= "NonReg: {$state['nonreg_pass']}/{$state['nonreg_total']}\n";
$r .= "Screenshots: $ss_real (was ".($state['screenshots']??'?').")\n";
$r .= "Videos: $vid_real\n";
$r .= "Pages HTML real: $html_all | PHP: $php_all | JSON: $json_all\n";
$r .= "74 layers preserved: ".count($state['layers'] ?? [])."\n";
wv_out($r);
}
// ===== L99 COVERAGE SCAN =====
if (preg_match('/l99.?coverage|coverage.?scan|coverage.?l99|l99.?gap.?report/i', $q)) {
// Real filesystem counts
$html_all = (int)wv_sh("ls /var/www/html/*.html /var/www/html/products/*.html /var/www/html/blog/*.html /var/www/html/service/*.html /var/www/html/office-365/*.html /var/www/html/ethica/*.html /var/www/html/test-report/*.html /var/www/html/generated/*.html 2>/dev/null | wc -l");
$html_root = (int)wv_sh("ls /var/www/html/*.html 2>/dev/null | wc -l");
$html_prod = (int)wv_sh("ls /var/www/html/products/*.html 2>/dev/null | wc -l");
$html_blog = (int)wv_sh("ls /var/www/html/blog/*.html 2>/dev/null | wc -l");
$html_srv = (int)wv_sh("ls /var/www/html/service/*.html 2>/dev/null | wc -l");
$php_all = (int)wv_sh("ls /var/www/html/api/*.php 2>/dev/null | wc -l");
$json_all = (int)wv_sh("ls /var/www/html/api/*.json 2>/dev/null | wc -l");
// L99 state claims
$state = @json_decode(@file_get_contents('/var/www/html/api/l99-state.json'), true) ?: [];
$l99_pages = $state['pages_html'] ?? $state['pages'] ?? 0;
$l99_php = $state['apis_php'] ?? 0;
$l99_json = $state['apis_json'] ?? 0;
$cov_html = $html_all > 0 ? round($l99_pages*100/$html_all, 1) : 0;
$cov_php = $php_all > 0 ? round($l99_php*100/$php_all, 1) : 0;
$cov_json = $json_all > 0 ? round($l99_json*100/$json_all, 1) : 0;
$gap_html = $html_all - $l99_pages;
$gap_php = $php_all - $l99_php;
$gap_json = $json_all - $l99_json;
$r = "L99 COVERAGE SCAN (real filesystem vs l99-state)\n";
$r .= "HTML: $l99_pages / $html_all = $cov_html% (gap: $gap_html pages)\n";
$r .= " - root: $html_root | products: $html_prod | blog: $html_blog | service: $html_srv\n";
$r .= "PHP: $l99_php / $php_all = $cov_php% (gap: $gap_php)\n";
$r .= "JSON: $l99_json / $json_all = $cov_json% (gap: $gap_json)\n";
$r .= "---\n";
if ($gap_html > 20) $r .= "⚠️ HTML coverage gap: $gap_html pages non-testees\n";
if ($gap_php > 10) $r .= "⚠️ PHP coverage gap: $gap_php APIs non-testees\n";
if ($gap_json > 10) $r .= "⚠️ JSON coverage gap: $gap_json resources non-testees\n";
// Layers not 100%
$layers = $state['layers'] ?? [];
$not100 = [];
foreach ($layers as $n => $v) {
$pct = $v['pct'] ?? 100;
if ($pct < 100) $not100[] = "$n ".$v['pass']."/".$v['total']." ($pct%)";
}
if ($not100) $r .= "Layers <100%: ".implode(", ", $not100)."\n";
wv_out($r);
}
// ===== L99 CLEAN AUTHENTIK =====
if (preg_match('/l99.?clean.?authent|clean.?authent.?l99|remove.?authent/i', $q)) {
$f = '/opt/weval-l99/l99-master.py';
if (!file_exists($f)) wv_out("l99-master.py not found");
$before = (int)wv_sh("grep -ciE 'authentik|goauthentik|outpost|ak_redirect' $f");
if ($before == 0) wv_out("l99-master.py already clean (0 Authentik refs)");
// Backup
wv_sh("sudo cp $f $f.GOLD-cleanauth-".date('Ymd-His'));
// Comment out lines containing Authentik references (safer than deleting)
wv_sh("sudo sed -i.bak 's|^\(.*[Aa]uthentik.*\)$|# REMOVED-AUTHENTIK: \1|g' $f");
wv_sh("sudo sed -i 's|^\(.*goauthentik.*\)$|# REMOVED-AUTHENTIK: \1|g' $f");
wv_sh("sudo sed -i 's|^\(.*outpost.*\)$|# REMOVED-AUTHENTIK: \1|g' $f");
$after = (int)wv_sh("grep -cE '^[^#].*[Aa]uthentik|^[^#].*goauthentik|^[^#].*outpost' $f");
$syntax = wv_sh("python3 -m py_compile " . escapeshellarg($f) . " 2>&1");
wv_out("L99 CLEAN AUTHENTIK\nBefore: $before refs\nAfter active: $after refs\nSyntax: ".($syntax ?: 'OK')."\nGOLD backup: $f.GOLD-cleanauth-*");
}
// ===== L99 FIX UI HARDCODE =====
if (preg_match('/l99.?fix.?ui|l99.?ui.?hardcode|fix.?ui.?l99|ui.?hardcode/i', $q)) {
$f = '/var/www/html/l99-saas.html';
if (!file_exists($f)) wv_out("l99-saas.html not found");
$content = file_get_contents($f);
if (strpos($content, 'tests:206') === false) {
wv_out("l99-saas.html already clean (no hardcode)");
}
// Backup
wv_sh("sudo cp $f $f.GOLD-uifix-".date('Ymd-His'));
// Replace the hardcoded DATA
$old = 'let DATA={tests:206,pass:200,fail:6,warn:0,layers:9,ss:14,vid:32};';
$new = 'let DATA=null;let DATA_TS=null;let DATA_ERROR=null;';
if (strpos($content, $old) !== false) {
$new_content = str_replace($old, $new, $content);
// Use sudo tee since www-data may not own
$tmp = '/tmp/l99-saas-new.html';
file_put_contents($tmp, $new_content);
$rc = wv_sh("sudo cp $tmp $f && sudo chown www-data:www-data $f");
$after = strpos(file_get_contents($f), 'tests:206');
wv_out("L99 FIX UI HARDCODE\nOld hardcode removed: ".($after === false ? 'YES ✅' : 'NO')."\nGOLD: $f.GOLD-uifix-*");
} else {
wv_out("Pattern not found in l99-saas.html");
}
}
// ===== RECONCILE CLAUDE SESSIONS =====
if (preg_match('/reconcile.?claude|claude.?session|reconcile.?session|travaux.?claude|other.?claude/i', $q)) {
// Git commits from recent Claude sessions
$html_log = wv_sh("sudo git -c safe.directory=* -C /var/www/html log --oneline --all --since='3 days ago' 2>&1 | head -20");
$brain_log = wv_sh("sudo git -c safe.directory=* -C /opt/wevia-brain log --oneline --all --since='3 days ago' 2>&1 | head -20");
// Wiki entries
$wiki = wv_sh("ls -t /var/www/html/api/wiki/*.md 2>/dev/null | head -10");
// Wave markers
$waves = wv_sh("grep -l 'Wave 11[0-9]' /var/www/html/api/wiki/*.md 2>/dev/null | head");
// Recent l99 runs
$runs = wv_sh("ls -t /opt/weval-l99/logs/l99-*.json 2>/dev/null | head -5 | xargs -I{} basename {}");
$r = "RECONCILE CLAUDE SESSIONS (last 3 days)\n";
$r .= "=== HTML git ===\n".substr($html_log, 0, 800)."\n";
$r .= "=== BRAIN git ===\n".substr($brain_log, 0, 500)."\n";
$r .= "=== WIKI entries ===\n".substr($wiki, 0, 400)."\n";
$r .= "=== WAVES ===\n".substr($waves, 0, 300)."\n";
$r .= "=== L99 recent runs ===\n".$runs."\n";
wv_out($r);
}
// ===== L99 ARTIFACTS INDEX =====
if (preg_match('/l99.?artifact|l99.?visual.?index|screenshot.?index|video.?index|l99.?media/i', $q)) {
$ss_dirs = [
'/opt/weval-l99/screenshots' => '/l99-screenshots',
'/var/www/html/api/l99-results/screenshots' => '/api/l99-results/screenshots',
];
$vid_dirs = [
'/opt/weval-l99/videos' => '/l99-videos',
'/opt/weval-l99/screenshots/videos' => '/l99-screenshots/videos',
'/var/www/html/api/l99-results/videos' => '/api/l99-results/videos',
];
$index = ['timestamp' => date('c'), 'screenshots' => [], 'videos' => [], 'counts' => []];
$ss_total = 0;
foreach ($ss_dirs as $dir => $url) {
if (is_dir($dir)) {
$files = glob("$dir/*.png") ?: [];
$ss_total += count($files);
$index['counts']['screenshots_'.basename($dir)] = count($files);
// Sample first 5 names
$sample = array_slice(array_map('basename', $files), 0, 5);
$index['screenshots'][$dir] = ['count'=>count($files), 'sample'=>$sample];
}
}
$vid_total = 0;
foreach ($vid_dirs as $dir => $url) {
if (is_dir($dir)) {
$files = glob("$dir/*.webm") ?: [];
$vid_total += count($files);
$index['counts']['videos_'.basename($dir)] = count($files);
$sample = array_slice(array_map('basename', $files), 0, 5);
$index['videos'][$dir] = ['count'=>count($files), 'sample'=>$sample];
}
}
$index['total_screenshots'] = $ss_total;
$index['total_videos'] = $vid_total;
// Save to api for UI access
$out_file = '/var/www/html/api/l99-artifacts-index.json';
$tmp = '/tmp/l99-art-index.json';
file_put_contents($tmp, json_encode($index, JSON_PRETTY_PRINT));
wv_sh("sudo cp $tmp $out_file && sudo chown www-data:www-data $out_file");
$r = "L99 ARTIFACTS INDEX\n";
$r .= "Total screenshots: $ss_total\n";
$r .= "Total videos: $vid_total\n";
foreach ($index['counts'] as $k=>$v) $r .= " $k: $v\n";
$r .= "Index saved: $out_file\n";
$r .= "Public URL: /api/l99-artifacts-index.json";
wv_out($r);
}
// ===== L99 FULL REPORT (master summary for wiki) =====
if (preg_match('/l99.?full.?report|l99.?master.?report|l99.?wiki.?report|wave.?114.?report/i', $q)) {
$state = @json_decode(@file_get_contents('/var/www/html/api/l99-state.json'), true) ?: [];
$nr = @json_decode(@file_get_contents('/var/www/html/api/nonreg-latest.json'), true) ?: [];
$art = @json_decode(@file_get_contents('/var/www/html/api/l99-artifacts-index.json'), true) ?: [];
$sot = @json_decode(@file_get_contents('/var/www/html/api/source-of-truth.json'), true) ?: [];
$layers = $state['layers'] ?? [];
$total_p = $total_t = 0;
$not100 = [];
foreach ($layers as $n => $v) {
$total_p += $v['pass'] ?? 0;
$total_t += $v['total'] ?? 0;
if (($v['pct'] ?? 100) < 100) $not100[] = "$n ".($v['pass'] ?? '?').'/'.($v['total'] ?? '?');
}
$pct = $total_t > 0 ? round($total_p*100/$total_t, 2) : 0;
// Build report
$rep = "# L99 Master Report — Wave 114\n";
$rep .= "Generated: ".date('c')."\n\n";
$rep .= "## Scores\n";
$rep .= "- L99 Layers: $total_p/$total_t = $pct%\n";
$rep .= "- NonReg: ".($nr['pass']??'?').'/'.($nr['total']??'?')."\n";
$rep .= "- Layers count: ".count($layers)."\n";
$rep .= "- Layers <100%: ".count($not100)."\n";
if ($not100) $rep .= " - ".implode("\n - ", $not100)."\n";
$rep .= "\n## Real Coverage (filesystem)\n";
$rep .= "- Screenshots: ".($art['total_screenshots'] ?? $state['screenshots'] ?? '?')."\n";
$rep .= "- Videos: ".($art['total_videos'] ?? $state['videos'] ?? '?')."\n";
$rep .= "- Pages HTML: ".($state['pages_html_real'] ?? '?')."\n";
$rep .= "- APIs PHP: ".($state['apis_php_real'] ?? '?')."\n";
$rep .= "- APIs JSON: ".($state['apis_json_real'] ?? '?')."\n";
$rep .= "\n## Infrastructure\n";
$rep .= "- Docker: ".($state['docker_up'] ?? '?')."\n";
$rep .= "- Crons: ".($state['crons_active'] ?? '?')."\n";
$rep .= "- Disk: ".($state['disk_pct'] ?? '?')."\n";
$rep .= "- Sovereign AIs: ".($state['sovereign_ias'] ?? '?')."\n";
$rep .= "- Providers: ".($state['providers'] ?? '?')."\n";
$rep .= "\n## Gaps / Known Issues\n";
$rep .= "- WV-Send S95 HTTP 500 (legacy send-pipeline.php)\n";
$rep .= "- 3 layers not 100% (OSS-ECOSYSTEM, CLAUDE-SKILLS, INFRA-FW)\n";
$rep .= "- GitHub PAT rotated 2026-04-16 (ghp_Uhh8Xv... valid)\n";
// Write to wiki
$wiki_file = '/var/www/html/api/wiki/wave-114-master-report.md';
$tmp = '/tmp/wave-114-report.md';
file_put_contents($tmp, $rep);
wv_sh("sudo cp $tmp $wiki_file && sudo chown www-data:www-data $wiki_file");
// Also update register entry
$reg_file = '/var/www/html/api/l99-registry.json';
$reg = @json_decode(@file_get_contents($reg_file), true) ?: [];
$reg['wave_114'] = [
'timestamp' => date('c'),
'scores' => ['layers' => "$total_p/$total_t", 'pct' => $pct, 'nonreg' => ($nr['pass']??0).'/'.($nr['total']??0)],
'screenshots' => $art['total_screenshots'] ?? 0,
'videos' => $art['total_videos'] ?? 0,
'gaps' => ['wv_send_500', 'pat_expiring', '3_layers_partial'],
'wiki' => $wiki_file,
];
$tmp2 = '/tmp/l99-registry-new.json';
file_put_contents($tmp2, json_encode($reg, JSON_PRETTY_PRINT));
wv_sh("sudo cp $tmp2 $reg_file && sudo chown www-data:www-data $reg_file");
wv_out("L99 FULL REPORT GENERATED\nWiki: $wiki_file\nRegister updated: wave_114 entry\nScores: $total_p/$total_t ($pct%)\nScreenshots: ".($art['total_screenshots'] ?? '?')."\nVideos: ".($art['total_videos'] ?? '?'));
}
// ===== L99 VISUAL EXTENDED (REAL coverage of all 271 pages) =====
if (preg_match('/l99.?visual.?extend|visual.?extended|l99.?extended.?visual|l99.?full.?visual/i', $q)) {
$script = '/opt/weval-l99/l99-visual-extended.py';
$runner = '/opt/weval-l99/run-detached.sh';
if (!file_exists($script)) wv_out("l99-visual-extended.py not found");
if (!file_exists($runner)) wv_out("run-detached.sh not found");
// Use detached runner so script survives PHP parent termination
$out = wv_sh("$runner python3 $script 2>&1", 10);
sleep(1);
$running = wv_sh("pgrep -f l99-visual-extended.py | head -1");
$result_file = '/var/www/html/api/l99-visual-extended-result.json';
$last = file_exists($result_file) ? wv_sh("stat -c %y $result_file | cut -d. -f1") : "never";
wv_out("L99 VISUAL EXTENDED launched\n$out\nCurrent pid: $running\nResult file: $result_file\nLast result: $last\nCheck status with: l99 visual status");
}
// ===== L99 VISUAL STATUS =====
if (preg_match('/l99.?visual.?status|visual.?status|l99.?visual.?result/i', $q)) {
$running = wv_sh("pgrep -f l99-visual-extended.py | head -3");
$result_file = '/var/www/html/api/l99-visual-extended-result.json';
$r = "L99 VISUAL EXTENDED STATUS\n";
$r .= "Running PIDs: ".($running ?: "none")."\n";
if (file_exists($result_file)) {
$data = @json_decode(@file_get_contents($result_file), true) ?: [];
$summ = $data['summary'] ?? [];
$r .= "Last result TS: ".($data['ts'] ?? '?')."\n";
$r .= "Total pages: ".($summ['total_pages'] ?? '?')."\n";
$r .= "Pass/Fail/Warn: ".($summ['pass'] ?? '?')."/".($summ['fail'] ?? '?')."/".($summ['warn'] ?? '?')."\n";
$r .= "Coverage pct: ".($summ['pct'] ?? '?')."%\n";
$r .= "Screenshots: ".($summ['screenshots_generated'] ?? 0)."\n";
$r .= "Playwright OK: ".(($summ['playwright_ok'] ?? false) ? 'yes' : 'no')."\n";
$r .= "Elapsed: ".($summ['elapsed_s'] ?? '?')."s\n";
} else {
$r .= "No result yet. Run: l99 visual extended\n";
}
// Log tail
$log = wv_sh("tail -10 /opt/weval-l99/logs/visual-extended.log 2>/dev/null");
if ($log) $r .= "\n--- log tail ---\n".substr($log, 0, 600);
wv_out($r);
}
// ===== L99 FIX LAYERS (OSS-ECOSYSTEM, CLAUDE-SKILLS, INFRA-FW) =====
if (preg_match('/l99.?fix.?layer|fix.?layer.?l99|fix.?3.?layer|why.?layer/i', $q)) {
$state = @json_decode(@file_get_contents('/var/www/html/api/l99-state.json'), true) ?: [];
$layers = $state['layers'] ?? [];
$not100 = [];
foreach ($layers as $n => $v) {
if (($v['pct'] ?? 100) < 100) $not100[$n] = $v;
}
$r = "L99 FIX LAYERS — 3 layers <100%\n";
// OSS-ECOSYSTEM 3/4 — find the missing OSS
$oss_cache = @json_decode(@file_get_contents('/var/www/html/api/oss-cache.json'), true) ?: [];
$oss_count = count($oss_cache['tools'] ?? $oss_cache['items'] ?? []);
$r .= "\n[OSS-ECOSYSTEM] state=".json_encode($not100['OSS-ECOSYSTEM'] ?? [])."\n";
$r .= " oss-cache items: $oss_count\n";
// CLAUDE-SKILLS 6/7 — find missing skill
$skills_dir_opt = wv_sh("ls /opt/skills 2>/dev/null | wc -l");
$skills_dir_mnt = wv_sh("ls /mnt/skills/public 2>/dev/null | wc -l");
$r .= "\n[CLAUDE-SKILLS] state=".json_encode($not100['CLAUDE-SKILLS'] ?? [])."\n";
$r .= " /opt/skills: $skills_dir_opt items | /mnt/skills/public: $skills_dir_mnt items\n";
// INFRA-FW 6/7 — firewall rules or CrowdSec status
$cs_status = wv_sh("sudo cscli metrics 2>&1 | head -5 || cscli metrics 2>&1 | head -5");
$ufw = wv_sh("sudo ufw status 2>&1 | head -5 || ufw status 2>&1 | head -3");
$r .= "\n[INFRA-FW] state=".json_encode($not100['INFRA-FW'] ?? [])."\n";
$r .= " crowdsec: ".substr($cs_status, 0, 200)."\n";
$r .= " ufw: ".substr($ufw, 0, 200)."\n";
wv_out($r);
}
// ===== L99 ARCHIVE LEGACY SCRIPTS =====
if (preg_match('/l99.?archive.?legacy|archive.?legacy.?l99|l99.?clean.?script|l99.?archive/i', $q)) {
$archive_dir = '/opt/weval-l99/archive/legacy-'.date('Ymd');
wv_sh("sudo mkdir -p $archive_dir && sudo chown www-data:www-data $archive_dir");
// Keep canonical: l99-master.py, l99-wevia-master-visual.py, l99-visual-extended.py, l99-state-updater.py, l99-beton.sh, l99-alive.py
$keep = ['l99-master.py', 'l99-wevia-master-visual.py', 'l99-visual-extended.py', 'l99-state-updater.py', 'l99-beton.sh', 'l99-alive.py', 'l99-functional-test.py', 'l99-security-scan.py', 'l99-ux-agent.py'];
$all = glob('/opt/weval-l99/l99-*.py');
$archived = [];
foreach ($all as $f) {
$base = basename($f);
if (in_array($base, $keep)) continue;
$dest = "$archive_dir/$base";
$rc = wv_sh("sudo mv $f $dest 2>&1");
$archived[] = $base;
}
// Also archive duplicate .sh orchestrators (keep l99-beton.sh, run-detached.sh, run.sh)
$sh_keep = ['run.sh', 'run-detached.sh', 'l99-beton.sh', 'l99-ondemand.sh'];
$all_sh = glob('/opt/weval-l99/l99-*.sh');
foreach ($all_sh as $f) {
$base = basename($f);
if (in_array($base, $sh_keep)) continue;
wv_sh("sudo mv $f $archive_dir/$base 2>&1");
$archived[] = $base;
}
$r = "L99 ARCHIVE LEGACY\n";
$r .= "Archived: ".count($archived)." scripts to $archive_dir\n";
$r .= "Kept canonical: ".implode(", ", $keep)."\n";
if ($archived) $r .= "Moved: ".implode(", ", array_slice($archived, 0, 20))."...\n";
$remaining = wv_sh("ls /opt/weval-l99/l99-*.py 2>/dev/null | wc -l");
$r .= "Remaining l99-*.py in /opt/weval-l99: $remaining\n";
wv_out($r);
}
// ===== L99 DEEP TEST (full coverage: tabs + deps + cross-apps + WebGL + chat) =====
if (preg_match('/l99.?deep.?test|deep.?test.?l99|l99.?integration.?test|l99.?full.?deep/i', $q)) {
$script = '/opt/weval-l99/l99-deep-test.py';
$runner = '/opt/weval-l99/run-detached.sh';
if (!file_exists($script)) wv_out("l99-deep-test.py not found");
$out = wv_sh("$runner python3 $script 2>&1", 10);
sleep(1);
$pid = wv_sh("pgrep -f l99-deep-test.py | head -1");
wv_out("L99 DEEP TEST launched\n$out\npid=$pid\nCheck: l99 deep status\nExpected runtime: 60-90s");
}
// ===== L99 DEEP STATUS =====
if (preg_match('/l99.?deep.?status|deep.?status|l99.?deep.?result/i', $q)) {
$running = wv_sh("pgrep -f l99-deep-test.py | head -3");
$f = '/var/www/html/api/l99-deep-test-result.json';
$r = "L99 DEEP TEST STATUS\nRunning: ".($running ?: 'no')."\n";
if (file_exists($f)) {
$d = @json_decode(@file_get_contents($f), true) ?: [];
$s = $d['summary'] ?? [];
$r .= "TS: ".($d['ts'] ?? '?')."\n";
$r .= "--- SUMMARY ---\n";
$r .= "Tabs: ".($s['tabs'] ?? '?')." (".($s['tabs_pct'] ?? '?')."%)\n";
$r .= "Dependencies: ".($s['dependencies'] ?? '?')." (".($s['dependencies_pct'] ?? '?')."%)\n";
$r .= "Cross-apps: ".($s['cross_apps'] ?? '?')." (".($s['cross_apps_pct'] ?? '?')."%)\n";
$r .= "Console errors: ".($s['console_errors'] ?? '?')."\n";
$r .= "Network failures: ".($s['network_failures'] ?? '?')."\n";
$r .= "Agents-archi 3D: ".(($s['agents_archi_ok'] ?? false) ? '✅ OK' : '❌ BROKEN')."\n";
$r .= "WEVIA Master chat: ".(($s['wevia_master_chat_ok'] ?? false) ? '✅ OK' : '⚠')."\n";
$r .= "OVERALL: ".($s['overall'] ?? '?')." (".($s['overall_pct'] ?? '?')."%)\n";
// Failed details
$failed_deps = array_filter($d['dependencies'] ?? [], fn($x)=>!($x['ok'] ?? false));
$failed_tabs = array_filter($d['tabs'] ?? [], fn($x)=>!($x['ok'] ?? false));
$failed_cross = array_filter($d['cross_apps'] ?? [], fn($x)=>!($x['ok'] ?? false));
if ($failed_deps) {
$r .= "\n--- FAILED DEPS ---\n";
foreach (array_slice($failed_deps, 0, 5) as $fd) {
$r .= " ".$fd['url']."".($fd['status'] ?? '?')."\n";
}
}
if ($failed_tabs) {
$r .= "\n--- FAILED TABS ---\n";
foreach ($failed_tabs as $ft) {
$r .= " ".$ft['tab']." → body=".($ft['details']['body_length'] ?? '?')."\n";
}
}
if ($failed_cross) {
$r .= "\n--- FAILED CROSS-APPS ---\n";
foreach (array_slice($failed_cross, 0, 5) as $fc) {
$r .= " ".($fc['name'] ?? '?')." (".($fc['url'] ?? '')."): ".($fc['error'] ?? ($fc['body_length'] ?? '?').'B')."\n";
}
}
} else {
$r .= "No result yet. Run: l99 deep test\n";
}
$log = wv_sh("tail -15 /opt/weval-l99/logs/deep-test.log 2>/dev/null");
if ($log) $r .= "\n--- log tail ---\n".substr($log, 0, 800);
wv_out($r);
}
// ===== L99 AUTOHEAL (detect fails in deep test + attempt fixes) =====
if (preg_match('/l99.?autoheal|autoheal|auto.?heal.?l99|l99.?self.?heal/i', $q)) {
$f = '/var/www/html/api/l99-deep-test-result.json';
if (!file_exists($f)) wv_out("No deep test result yet. Run: l99 deep test");
$d = @json_decode(@file_get_contents($f), true) ?: [];
$fixes = [];
$cant_fix = [];
// Check failed dependencies
foreach ($d['dependencies'] ?? [] as $dep) {
if (!($dep['ok'] ?? false)) {
$url = $dep['url'];
// Try to touch/regenerate the file
if (preg_match('#/api/([^?]+\.json)#', $url, $m)) {
$fname = "/var/www/html/api/".$m[1];
if (!file_exists($fname)) {
// Create empty valid JSON
wv_sh("echo '{}' | sudo tee $fname >/dev/null && sudo chown www-data:www-data $fname");
$fixes[] = "Created missing: $fname";
} else {
$cant_fix[] = "$url exists but fetch failed (status ".($dep['status'] ?? '?').")";
}
} else {
$cant_fix[] = $url;
}
}
}
// Agents-archi 3D broken → note
if (!($d['summary']['agents_archi_ok'] ?? false)) {
$cant_fix[] = "agents-archi 3D: canvas/webgl broken (needs manual brace fix)";
}
// Restart PHP-FPM if network failures > 5
$nf = count($d['network_failures'] ?? []);
if ($nf > 5) {
wv_sh("sudo systemctl reload php8.5-fpm 2>&1");
$fixes[] = "PHP-FPM reloaded (had $nf network failures)";
}
$r = "L99 AUTOHEAL\n";
$r .= "Fixes applied: ".count($fixes)."\n";
foreach ($fixes as $fx) $r .= "$fx\n";
$r .= "Cannot auto-fix: ".count($cant_fix)."\n";
foreach (array_slice($cant_fix, 0, 10) as $cf) $r .= "$cf\n";
wv_out($r);
}
// ===== L99 FIX CLAUDE SKILLS LAYER (path mismatch /opt/skills vs /mnt/skills/public) =====
if (preg_match('/l99.?fix.?claude.?skill|fix.?claude.?skill|claude.?skill.?path/i', $q)) {
// The test expects /opt/skills but skills live in /mnt/skills/public
// Solution: create a symlink so both paths work
$src = '/mnt/skills/public';
$dst = '/opt/skills';
if (!is_dir($src)) wv_out("/mnt/skills/public not found");
if (is_link($dst) || is_dir($dst)) {
$r = "/opt/skills already exists (link or dir)";
} else {
$rc = wv_sh("sudo ln -s $src $dst && ls -la $dst");
$count = (int)wv_sh("ls $dst 2>/dev/null | wc -l");
$r = "Created symlink /opt/skills -> /mnt/skills/public\nItems: $count";
}
wv_out("L99 FIX CLAUDE SKILLS\n$r");
}
// ===== L99 AUTOWIRE DETECT (meta — Master scans its own intents vs needs) =====
if (preg_match('/l99.?autowire.?detect|autowire.?detect|detect.?autowire|wire.?gap.?detect/i', $q)) {
// Scan wave114.php + agents.php + exec.php for patterns
$files = [
'/var/www/html/api/wevia-wave114.php',
'/var/www/html/api/wevia-agents.php',
'/var/www/html/api/wevia-exec.php',
];
$intents = [];
foreach ($files as $fp) {
if (!file_exists($fp)) continue;
$c = file_get_contents($fp);
if (preg_match_all('/preg_match\(.(\/[^\/]+\/i?).,/', $c, $m)) {
foreach ($m[1] as $pat) $intents[] = ['file' => basename($fp), 'pattern' => $pat];
}
}
$r = "L99 AUTOWIRE DETECT\n";
$r .= "Total intents wired: ".count($intents)."\n";
$r .= "By file:\n";
$by_file = [];
foreach ($intents as $i) $by_file[$i['file']] = ($by_file[$i['file']] ?? 0) + 1;
foreach ($by_file as $fn => $cnt) $r .= " $fn: $cnt intents\n";
// Detect common gaps: things Master should do but can't
$gaps_checked = [
'fix wv-send' => 'fix.?wv.?send',
'agents archi' => 'agents.?archi',
'l99 deep test' => 'l99.?deep.?test',
'l99 autoheal' => 'l99.?autoheal',
'push all' => 'push.?all',
'wiki sync' => 'wiki.?sync',
'state refresh' => 'state.?refresh',
'coverage scan' => 'coverage.?scan',
'visual extended' => 'visual.?extended',
'reconcile wave' => 'reconcil',
'ux lean 6 sigma' => 'ux.?lean',
];
$r .= "\nCapability check:\n";
$all_content = '';
foreach ($files as $fp) if (file_exists($fp)) $all_content .= file_get_contents($fp);
foreach ($gaps_checked as $name => $pat) {
$has = preg_match("/$pat/i", $all_content) ? '✅' : '❌';
$r .= " $has $name\n";
}
wv_out($r);
}
// ===== L99 FIX PRIORITY (combine autoheal + fix layers in one go) =====
if (preg_match('/l99.?fix.?priority|l99.?fix.?all|l99.?heal.?all|fix.?l99.?all/i', $q)) {
$steps = [];
// 1. Refresh state
$steps[] = "1. State refresh...";
// 2. Claude skills symlink
if (!is_link('/opt/skills') && !is_dir('/opt/skills')) {
wv_sh("sudo ln -s /mnt/skills/public /opt/skills 2>&1");
$steps[] = "2. ✅ Created /opt/skills symlink";
} else {
$steps[] = "2. /opt/skills exists";
}
// 3. Touch missing JSON files that deep test depends on
$json_deps = [
'/var/www/html/api/l99-visual-extended-result.json',
'/var/www/html/api/l99-artifacts-index.json',
'/var/www/html/api/l99-deep-test-result.json',
'/var/www/html/api/nonreg-history.json',
];
foreach ($json_deps as $jf) {
if (!file_exists($jf)) {
wv_sh("echo '{}' | sudo tee $jf >/dev/null && sudo chown www-data:www-data $jf");
$steps[] = "3. ✅ Created $jf";
}
}
// 4. Restart PHP-FPM for consistency
$rc = wv_sh("sudo systemctl reload php8.5-fpm 2>&1 | head -3");
$steps[] = "4. PHP-FPM reload: ".($rc ?: 'ok');
wv_out("L99 FIX PRIORITY\n".implode("\n", $steps));
}
// ===== L99 SEMANTIC TEST (tests real chatbot answers for brand denials) =====
if (preg_match('/l99.?semantic|semantic.?test|chatbot.?semantic|test.?chatbot.?answer/i', $q)) {
$tests = [
"Qui est WEVAL ?" => ['must_contain' => ['WEVAL Consulting', 'Casablanca'], 'must_not_contain' => ["n'existe pas", "nexiste pas", "pas reel", "inconnu"]],
"Qu'est-ce que WEVAL Consulting ?" => ['must_contain' => ['WEVAL'], 'must_not_contain' => ["n'existe pas", "nexiste pas"]],
"WEVAL est-elle une vraie societe ?" => ['must_contain' => ['WEVAL'], 'must_not_contain' => ["n'existe pas", "pas une societe"]],
];
$results = [];
$pass = $fail = 0;
foreach ($tests as $question => $rules) {
$payload = json_encode(['message' => $question, 'session' => 'l99-semantic-'.time()]);
$escaped = escapeshellarg($payload);
$resp = wv_sh("curl -sk --max-time 25 --resolve weval-consulting.com:443:127.0.0.1 https://weval-consulting.com/api/weval-ia-fast.php -H 'Content-Type: application/json' -H 'User-Agent: WEVAL-L99-Internal' -d $escaped 2>&1", 30);
$data = @json_decode($resp, true);
$answer = strtolower($data['response'] ?? $data['reply'] ?? $resp);
$ok = true;
$reasons = [];
foreach ($rules['must_contain'] as $needle) {
if (stripos($answer, strtolower($needle)) === false) {
$ok = false;
$reasons[] = "missing: $needle";
}
}
foreach ($rules['must_not_contain'] as $bad) {
if (stripos($answer, strtolower($bad)) !== false) {
$ok = false;
$reasons[] = "FOUND BAD: $bad";
}
}
if ($ok) $pass++; else $fail++;
$results[] = [
'question' => $question,
'ok' => $ok,
'reasons' => $reasons,
'answer_preview' => substr($answer, 0, 200),
];
}
// Save
$out = ['ts' => date('c'), 'pass' => $pass, 'fail' => $fail, 'total' => count($tests), 'tests' => $results];
$tmp = '/tmp/l99-semantic-result.json';
file_put_contents($tmp, json_encode($out, JSON_PRETTY_PRINT));
wv_sh("sudo cp $tmp /var/www/html/api/l99-semantic-result.json && sudo chown www-data:www-data /var/www/html/api/l99-semantic-result.json");
$r = "L99 SEMANTIC TEST (chatbot public)\n";
$r .= "Score: $pass/".count($tests)." = ".round($pass*100/max(1,count($tests)),1)."%\n\n";
foreach ($results as $t) {
$sym = $t['ok'] ? '✅' : '❌';
$r .= "$sym ".$t['question']."\n";
if (!$t['ok']) {
foreach ($t['reasons'] as $rs) $r .= "$rs\n";
$r .= "".$t['answer_preview']."\n";
}
}
wv_out($r);
}
// ===== BLADE QUEUE CHECK (real heartbeat + task statuses) =====
if (preg_match('/blade.?queue|queue.?blade|blade.?task.?pend|blade.?status|blade.?health/i', $q)) {
$dir = '/var/www/html/api/blade-tasks';
// Real heartbeat (source of truth)
$hb = @json_decode(@file_get_contents("$dir/heartbeat.json"), true) ?: [];
$hb_ts = $hb['ts'] ?? '?';
$hb_age = '?';
if (isset($hb['ts'])) {
$hb_age = round((time() - strtotime($hb['ts'])) / 60, 1) . " min ago";
}
// Count tasks by status
$counts = ['pending' => 0, 'dispatched' => 0, 'done' => 0, 'failed' => 0, 'other' => 0];
$task_files = glob("$dir/task_*.json") ?: [];
$oldest = [];
foreach ($task_files as $tf) {
$td = @json_decode(@file_get_contents($tf), true) ?: [];
$st = $td['status'] ?? 'other';
if (!isset($counts[$st])) $st = 'other';
$counts[$st]++;
if ($st === 'dispatched' || $st === 'pending') {
$oldest[] = basename($tf)." (".$st.", ".substr($td['created'] ?? '?', 0, 16).")";
}
}
$total = count($task_files);
$r = "BLADE QUEUE CHECK (real state)\n";
$r .= "=== HEARTBEAT ===\n";
$r .= "Last: $hb_ts ($hb_age)\n";
$r .= "Host: ".($hb['hostname'] ?? '?')." | IP: ".($hb['ip'] ?? '?')."\n";
$r .= "CPU: ".($hb['cpu'] ?? '?')." | RAM: ".($hb['ram'] ?? '?')."\n";
$r .= "Uptime: ".($hb['uptime'] ?? '?')." | Version: ".($hb['agent_version'] ?? '?')."\n";
$r .= "\n=== TASKS ($total total) ===\n";
foreach ($counts as $k => $v) $r .= " $k: $v\n";
if ($oldest) {
$r .= "\nStuck (first 5):\n";
foreach (array_slice($oldest, 0, 5) as $o) $r .= "$o\n";
}
// Diagnosis
$r .= "\n=== DIAGNOSIS ===\n";
if (isset($hb['ts']) && (time() - strtotime($hb['ts'])) < 600) {
$r .= "✅ Blade agent ALIVE (heartbeat fresh)\n";
if ($counts['dispatched'] > 5) {
$r .= "⚠ Tasks dispatched but not completing — agent accepts but does not execute\n";
$r .= " Likely: powershell exec failing silently, or result-post back to server broken\n";
}
if (preg_match('/(\d+)/', $hb['ram'] ?? '', $m) && intval($m[1]) > 90) {
$r .= "⚠ RAM critical (".$hb['ram'].") — agent may be thrashing\n";
}
} else {
$r .= "❌ Blade heartbeat STALE — agent offline\n";
}
wv_out($r);
}
// ===== BLADE STATUS SYNC (copies heartbeat.json -> blade-status.json) =====
if (preg_match('/blade.?sync|sync.?blade|blade.?status.?update|blade.?refresh/i', $q)) {
$hb_file = '/var/www/html/api/blade-tasks/heartbeat.json';
$status_file = '/var/www/html/api/blade-status.json';
$hb = @json_decode(@file_get_contents($hb_file), true) ?: [];
if (!$hb) wv_out("heartbeat.json empty or missing");
$status = [
'online' => isset($hb['ts']) && (time() - strtotime($hb['ts'])) < 600,
'sentinel_version' => $hb['agent_version'] ?? '?',
'last_seen' => $hb['ts'] ?? '?',
'last_seen_age_min' => isset($hb['ts']) ? round((time() - strtotime($hb['ts'])) / 60, 1) : null,
'cpu' => $hb['cpu'] ?? '?',
'ram' => $hb['ram'] ?? '?',
'ram_total' => '16GB',
'disk' => $hb['disk'] ?? '?',
'hostname' => $hb['hostname'] ?? '?',
'user' => $hb['user'] ?? '?',
'ip' => $hb['ip'] ?? '?',
'uptime' => $hb['uptime'] ?? '?',
'updated_by' => 'wevia-master-blade-sync',
'updated_at' => date('c'),
];
$tmp = '/tmp/blade-status-new.json';
file_put_contents($tmp, json_encode($status, JSON_PRETTY_PRINT));
wv_sh("sudo cp $tmp $status_file && sudo chown www-data:www-data $status_file");
wv_out("BLADE STATUS SYNCED\nonline: ".($status['online'] ? 'YES' : 'NO')."\nlast_seen: ".$status['last_seen']." (".$status['last_seen_age_min']." min ago)\nCPU: ".$status['cpu']." RAM: ".$status['ram']);
}
// ===== BLADE DRAIN STUCK (mark dispatched tasks older than 1h as failed with reason) =====
if (preg_match('/blade.?drain|drain.?blade|blade.?mark.?stuck|blade.?clear.?stuck/i', $q)) {
$dir = '/var/www/html/api/blade-tasks';
$task_files = glob("$dir/task_*.json") ?: [];
$marked = 0;
$kept = 0;
foreach ($task_files as $tf) {
$td = @json_decode(@file_get_contents($tf), true) ?: [];
if (($td['status'] ?? '') !== 'dispatched') { $kept++; continue; }
$dispatched_ts = isset($td['dispatched_at']) ? strtotime($td['dispatched_at']) : 0;
if ($dispatched_ts > 0 && (time() - $dispatched_ts) > 3600) {
$td['status'] = 'failed';
$td['failed_reason'] = 'stuck in dispatched > 1h (no completion report from agent)';
$td['marked_failed_at'] = date('c');
$tmp = '/tmp/blade-task-new.json';
file_put_contents($tmp, json_encode($td, JSON_PRETTY_PRINT));
wv_sh("sudo cp $tmp $tf && sudo chown www-data:www-data $tf");
$marked++;
} else {
$kept++;
}
}
wv_out("BLADE DRAIN STUCK\nMarked failed: $marked\nKept: $kept\nThese tasks will need re-dispatch or manual cleanup");
}
// ===== L99 WHY MISSED (meta intent — explains why L99 did not detect specific problems) =====
if (preg_match('/l99.?why.?miss|why.?l99.?miss|l99.?not.?detect|why.?not.?detect/i', $q)) {
$r = "L99 COVERAGE GAPS — why some bugs were missed\n\n";
$r .= "1. CHATBOT PUBLIC SEMANTIC: Deep test only checks chat input presence, NOT actual answer content.\n";
$r .= " FIX: New intent `l99 semantic test` now tests brand denial (WEVAL existence, Casablanca, etc)\n\n";
$r .= "2. BLADE QUEUE DEPTH: No test was polling blade-tasks/ for pending count.\n";
$r .= " FIX: New intent `blade queue check` reports pending/done/failed + heartbeat\n\n";
$r .= "3. L99 FUNCTIONAL 1 FAIL + 3 WARN (per l99-api.php): visible on /l99.html but deep test only checks status code of the API, not the results field content.\n";
$r .= " FIX: Add parsing of d.results[].status in deep test\n\n";
$r .= "4. LLM STOCHASTIC DRIFT: chatbot hallucinated 'WEVAL n existe pas' — LLM is not deterministic, one bad sampling.\n";
$r .= " FIX: Hardcoded REGLE_ABSOLUE in system prompt + semantic regression tests on each deploy\n";
wv_out($r);
}
// ===== BLADE+WAVE125 INTEGRATION (Master takes over Blade Linux-side + SSH multi-server) =====
// ===== SYSTEM INFO (Blade capability on Linux) =====
if (preg_match('/^system.?info$|^sys.?info$|blade.?system/i', $q)) {
$r = "SYSTEM INFO (S204 live)\n";
$r .= "=== OS ===\n".wv_sh("uname -a; cat /etc/os-release 2>/dev/null | grep PRETTY")."\n";
$r .= "=== CPU ===\n".wv_sh("nproc; top -bn1 | head -3 | tail -1")."\n";
$r .= "=== MEM ===\n".wv_sh("free -h | head -2")."\n";
$r .= "=== DISK ===\n".wv_sh("df -h / /mnt 2>/dev/null | head -5")."\n";
$r .= "=== LOAD ===\n".wv_sh("uptime")."\n";
$r .= "=== NET ===\n".wv_sh("hostname -I | head -1")."\n";
wv_out($r);
}
// ===== PROCESSES (Blade capability) =====
if (preg_match('/^processes$|^ps.?top|top.?processes|heavy.?process/i', $q)) {
$r = "TOP PROCESSES (S204)\n";
$r .= "=== CPU ===\n".wv_sh("ps aux --sort=-%cpu | head -11 | awk '{printf \"%-10s %5s %5s %s\\n\", \$1, \$3, \$4, \$11}'")."\n";
$r .= "=== MEM ===\n".wv_sh("ps aux --sort=-%mem | head -11 | awk '{printf \"%-10s %5s %5s %s\\n\", \$1, \$3, \$4, \$11}'")."\n";
wv_out($r);
}
// ===== DISK SPACE (Blade capability enriched) =====
if (preg_match('/^disk.?space$|^disk$|disk.?usage/i', $q)) {
$r = "DISK USAGE (S204 detailed)\n";
$r .= wv_sh("df -h 2>/dev/null | head -10")."\n";
$r .= "=== Heavy dirs /var/www ===\n".wv_sh("sudo du -sh /var/www/html/api /var/www/html/assets 2>/dev/null | head")."\n";
$r .= "=== Heavy dirs /opt ===\n".wv_sh("sudo du -sh /opt/weval-l99 /opt/wevads 2>/dev/null | head")."\n";
$r .= "=== Logs ===\n".wv_sh("sudo du -sh /var/log 2>/dev/null")."\n";
wv_out($r);
}
// ===== NETWORK IPs =====
if (preg_match('/^network.?ips?$|^network$|^ips?$/i', $q)) {
$r = "NETWORK IPs (S204)\n";
$r .= "=== Interfaces ===\n".wv_sh("ip -brief addr show 2>/dev/null | head -10")."\n";
$r .= "=== Listening ports ===\n".wv_sh("ss -tlnp 2>/dev/null | head -15")."\n";
$r .= "=== External IP ===\n".wv_sh("curl -s --max-time 3 ifconfig.me 2>/dev/null")."\n";
wv_out($r);
}
// ===== GPU INFO =====
if (preg_match('/^gpu$|^gpu.?info|gpu.?status/i', $q)) {
$r = "GPU INFO\n";
$nv = wv_sh("nvidia-smi 2>&1 | head -15");
if (strpos($nv, "command not found") !== false || strpos($nv, "NVIDIA") === false) {
$r .= "No NVIDIA GPU on S204 (CPU-only server)\n";
$r .= "=== Local Ollama models ===\n".wv_sh("curl -s --max-time 3 http://localhost:11434/api/tags 2>/dev/null | head -c 500");
} else {
$r .= $nv;
}
wv_out($r);
}
// ===== S95 EXEC (Wave 125 — SSH to S95 via Sentinel with whitelist) =====
if (preg_match('/^s95.?exec\s+/i', $q) || preg_match('/^s95\s+(docker|systemctl|ps|pgrep|ss|postqueue|tail|ls|cat|journalctl)/i', $q)) {
// Extract command after "s95 exec " or "s95 "
$cmd = preg_replace('/^s95\s*(exec\s+)?/i', '', $q);
// Whitelist allowed binaries
$allowed = ['systemctl', 'docker', 'ss', 'pgrep', 'pkill', 'journalctl', 'ls', 'cat', 'grep', 'postqueue', 'tail', 'head', 'df', 'free', 'uptime', 'ps', 'whoami', 'id', 'hostname', 'uname', 'mailq', 'postfix'];
$first = strtok($cmd, ' ');
if (!in_array($first, $allowed)) {
wv_out("s95 exec: command '$first' not in whitelist. Allowed: ".implode(', ', $allowed));
}
// Relay via Sentinel S95 API
$cmd_b64 = base64_encode($cmd);
$relay = wv_sh("curl -sk --max-time 15 'http://10.1.0.3:5890/api/sentinel-brain.php?action=exec&cmd=".urlencode($cmd)."' 2>&1", 20);
$r = "S95 EXEC: $cmd\n---\n".substr($relay, 0, 2000);
wv_out($r);
}
// ===== S151 EXEC (Wave 125 — SSH to S151) =====
if (preg_match('/^s151.?exec\s+/i', $q)) {
$cmd = preg_replace('/^s151\s*(exec\s+)?/i', '', $q);
$allowed = ['systemctl', 'docker', 'ss', 'pgrep', 'ls', 'cat', 'grep', 'tail', 'head', 'df', 'free', 'uptime', 'ps'];
$first = strtok($cmd, ' ');
if (!in_array($first, $allowed)) {
wv_out("s151 exec: command '$first' not in whitelist. Allowed: ".implode(', ', $allowed));
}
// SSH via key (if available)
$out = wv_sh("sshpass -p 'MX8D3zSAty7k3243242' ssh -o StrictHostKeyChecking=no -o ConnectTimeout=5 ubuntu@151.80.235.110 ".escapeshellarg($cmd)." 2>&1", 20);
wv_out("S151 EXEC: $cmd\n---\n".substr($out, 0, 2000));
}
// ===== FIX PMTA (diagnostic, no action) =====
if (preg_match('/^fix.?pmta$|diag.?pmta|pmta.?diag|pmta.?status/i', $q) && !preg_match('/force/i', $q)) {
$r = "PMTA DIAGNOSTIC (S95, safe — no action)\n\n";
// via Sentinel S95
$sentinel = "http://10.1.0.3:5890/api/sentinel-brain.php?action=exec&cmd=";
$r .= "=== systemctl is-active pmta ===\n".wv_sh("curl -sk --max-time 8 '${sentinel}".urlencode("systemctl is-active pmta")."' 2>&1 | head -c 200")."\n\n";
$r .= "=== pgrep pmtad ===\n".wv_sh("curl -sk --max-time 8 '${sentinel}".urlencode("pgrep -af pmtad")."' 2>&1 | head -c 500")."\n\n";
$r .= "=== port :25 ===\n".wv_sh("curl -sk --max-time 8 '${sentinel}".urlencode("ss -tlnp sport = :25")."' 2>&1 | head -c 500")."\n\n";
$r .= "=== postqueue -p ===\n".wv_sh("curl -sk --max-time 8 '${sentinel}".urlencode("postqueue -p 2>&1 | head -3")."' 2>&1 | head -c 500")."\n\n";
$r .= "→ For force restart: 'fix pmta force' (requires explicit Yacine GO)\n";
wv_out($r);
}
// ===== FIX PMTA FORCE (SIGTERM graceful + systemd takeover) =====
if (preg_match('/^fix.?pmta.?force$|pmta.?force|GO.?PMTA.?FORCE/i', $q)) {
$sentinel = "http://10.1.0.3:5890/api/sentinel-brain.php?action=exec&cmd=";
$r = "FIX PMTA FORCE (graceful restart sequence)\n\n";
$steps = [
"1. snapshot" => "pgrep -af pmtad",
"2. is-active before" => "systemctl is-active pmta",
"3. SIGTERM" => "sudo pkill -TERM pmtad",
"4. wait flush" => "sleep 5",
"5. verify clean" => "pgrep -af pmtad || echo clean",
"6. systemd start" => "sudo systemctl start pmta 2>&1",
"7. wait" => "sleep 3",
"8. is-active after" => "systemctl is-active pmta",
"9. port :25" => "ss -tlnp sport = :25 | head -3",
"10. port :587" => "ss -tlnp sport = :587 | head -3",
];
foreach ($steps as $label => $cmd) {
$out = wv_sh("curl -sk --max-time 15 '".$sentinel.urlencode($cmd)."' 2>&1 | head -c 400", 20);
$r .= "[$label] $cmd\n$out\n\n";
}
wv_out($r);
}
// ===== REGISTER APPEND (Wave 125 — add card before </body>) =====
if (preg_match('/^register.?append\s+/i', $q)) {
$content = trim(preg_replace('/^register\s*append\s+/i', '', $q));
if (!$content) wv_out("register append: empty content");
$f = '/var/www/html/register.html';
if (!file_exists($f)) wv_out("register.html not found");
// GOLD backup
$gold = $f.'.GOLD-'.date('Ymd-His');
wv_sh("sudo cp $f $gold");
// Unlock, append, relock
wv_sh("sudo chattr -i $f 2>/dev/null");
$orig = file_get_contents($f);
$card = "\n<div class='reg-card' data-ts='".date('c')."'>\n <div class='reg-ts'>".date('Y-m-d H:i')."</div>\n <div class='reg-body'>".htmlspecialchars($content)."</div>\n</div>\n";
if (strpos($orig, '</body>') !== false) {
$new = str_replace('</body>', $card.'</body>', $orig);
$tmp = '/tmp/register-new.html';
file_put_contents($tmp, $new);
wv_sh("sudo cp $tmp $f && sudo chown www-data:www-data $f");
wv_sh("sudo chattr +i $f 2>/dev/null");
wv_out("REGISTER APPEND\nContent: ".substr($content, 0, 100)."\nGOLD: $gold\nCard inserted before </body>");
} else {
wv_sh("sudo chattr +i $f 2>/dev/null");
wv_out("register.html missing </body> tag");
}
}
// ===== RESTART PHPFPM (out-of-band via Sentinel to avoid self-kill) =====
if (preg_match('/restart.?phpfpm|phpfpm.?restart|reload.?phpfpm/i', $q)) {
$sentinel = "http://10.1.0.3:5890/api/sentinel-brain.php?action=exec&cmd=";
// Sentinel on S95 SSH back to S204 to restart php-fpm (out-of-band)
$r = "RESTART PHP-FPM (out-of-band via Sentinel S95→S204)\n";
$r .= "Note: Cannot restart own process while serving request — delegated to Sentinel\n";
$out = wv_sh("curl -sk --max-time 10 '".$sentinel.urlencode("ssh -o StrictHostKeyChecking=no root@10.1.0.2 systemctl reload php8.5-fpm")."' 2>&1 | head -c 500", 15);
$r .= "Relay: $out\n";
$r .= "Verify manually: systemctl is-active php8.5-fpm\n";
wv_out($r);
}
// ===== RESTART OLLAMA =====
if (preg_match('/restart.?ollama|ollama.?restart|reload.?ollama/i', $q)) {
$out = wv_sh("sudo systemctl restart ollama 2>&1 | head -c 500 && sleep 2 && curl -s --max-time 3 http://localhost:11434/api/tags | head -c 200");
wv_out("RESTART OLLAMA\n$out");
}
// ===== BLADE RELAY (Windows-only ops via Sentinel to Blade agent) =====
if (preg_match('/^blade.?relay\s+|^blade.?run\s+/i', $q) && !preg_match('/oob/i', $q)) {
$cmd = preg_replace('/^blade.?(relay|exec|run)\s+/i', '', $q);
if (!$cmd) wv_out("blade relay: empty command");
// Post task to blade-tasks queue
$task = [
'id' => 'task_master_'.time(),
'type' => 'powershell',
'name' => substr($cmd, 0, 60),
'cmd' => $cmd,
'status' => 'pending',
'priority' => 'high',
'created' => date('c'),
'origin' => 'wevia-master-chat',
];
$tf = '/var/www/html/api/blade-tasks/task_master_'.time().'.json';
$tmp = '/tmp/bt.json';
file_put_contents($tmp, json_encode($task, JSON_PRETTY_PRINT));
wv_sh("sudo cp $tmp $tf && sudo chown www-data:www-data $tf");
wv_out("BLADE RELAY queued\nTask: $tf\ncmd: $cmd\nBlade agent will pull on next heartbeat (30-60s)\nCheck status: blade queue check");
}
// ===== MASTER DO ALL BLADE (unified capability inventory) =====
if (preg_match('/blade.?capab|master.?blade|blade.?inventory|what.?can.?blade/i', $q)) {
$r = "MASTER NOW HAS ALL BLADE CAPABILITIES\n\n";
$r .= "=== Linux-side (direct execution by Master) ===\n";
$r .= " system info → OS + CPU + MEM + DISK + LOAD + NET\n";
$r .= " processes → top CPU + top MEM\n";
$r .= " disk space → df -h + heavy dirs + logs\n";
$r .= " network ips → interfaces + listening ports + external IP\n";
$r .= " gpu info → nvidia-smi OR Ollama models\n";
$r .= " docker status → container list (wave115 intent)\n";
$r .= " git pull/push → push all (wave114 intent)\n";
$r .= "\n=== Multi-server SSH (Wave 125) ===\n";
$r .= " s95 exec <cmd> → whitelisted SSH to S95 via Sentinel\n";
$r .= " s151 exec <cmd> → SSH to S151 via key\n";
$r .= " fix pmta → diagnostic PMTA S95\n";
$r .= " fix pmta force → graceful SIGTERM + systemd takeover (requires GO)\n";
$r .= " restart phpfpm → out-of-band via Sentinel\n";
$r .= " restart ollama → direct systemctl\n";
$r .= "\n=== Register & wiki ===\n";
$r .= " register append <txt> → add card to register.html\n";
$r .= " wiki sync → SoT + wave-114.md\n";
$r .= " l99 full report → comprehensive report\n";
$r .= "\n=== Windows-side (via Blade relay queue) ===\n";
$r .= " blade relay <cmd> → queue powershell task for Windows agent\n";
$r .= " blade queue check → real heartbeat + task status\n";
$r .= " blade sync → sync heartbeat → status file\n";
$r .= " blade drain stuck → mark dispatched>1h as failed\n";
$r .= "\nOPUS PARADIGME: Master does all Linux/SSH work directly. Windows-specific ops go via Blade queue.\n";
wv_out($r);
}
// ===== BLADE FORCE RESTART (inject PS kill+restart via heartbeat OOB) =====
if (preg_match('/blade.?force.?restart|blade.?self.?kill|restart.?blade.?agent|blade.?reboot.?agent/i', $q)) {
$pef = '/var/www/html/api/blade-tasks/pending_exec.json';
// PowerShell: kill all existing weval-sentinel-agent processes + restart fresh
$ps = <<<'PS'
try {
Get-Process | Where-Object { $_.ProcessName -match 'weval|sentinel|blade' -and $_.Id -ne $PID } | Stop-Process -Force -ErrorAction SilentlyContinue;
Get-Process powershell | Where-Object { $_.Id -ne $PID -and ($_.CommandLine -match 'sentinel|blade' -or $_.MainWindowTitle -match 'sentinel|blade') } | Stop-Process -Force -ErrorAction SilentlyContinue;
Start-Sleep -Seconds 2;
Start-Process powershell -ArgumentList '-ep','bypass','-WindowStyle','Hidden','-File','C:\weval\weval-sentinel-agent.ps1' -ErrorAction SilentlyContinue;
Write-Output "blade-restart-ok";
} catch { Write-Output ("blade-restart-err: " + $_.Exception.Message); }
PS;
$payload = [
'exec_cmd' => trim(preg_replace('/\s+/', ' ', $ps)),
'label' => 'master-force-restart',
'created' => date('c'),
];
$tmp = '/tmp/pending_exec.json';
file_put_contents($tmp, json_encode($payload, JSON_PRETTY_PRINT));
wv_sh("sudo cp $tmp $pef && sudo chown www-data:www-data $pef");
// Check current heartbeat age to estimate when Blade will pick it up
$hb = @json_decode(@file_get_contents('/var/www/html/api/blade-tasks/heartbeat.json'), true) ?: [];
$age = isset($hb['ts']) ? (time() - strtotime($hb['ts'])) : '?';
wv_out("BLADE FORCE RESTART queued OOB\nFile: $pef\nLast heartbeat: ".($hb['ts'] ?? '?')." (${age}s ago)\nBlade will pick up on next heartbeat (< 60s)\nAfter exec: heartbeat should resume with fresh RAM/CPU\nVerify: blade queue check (after 90s)");
}
// ===== BLADE OOB STATUS (check pending + archives) =====
if (preg_match('/blade.?oob.?status|oob.?status|blade.?oob.?check/i', $q)) {
$dir = '/var/www/html/api/blade-tasks';
$pef = "$dir/pending_exec.json";
$r = "BLADE OOB STATUS\n";
if (file_exists($pef)) {
$pe = @json_decode(@file_get_contents($pef), true);
$r .= "PENDING (not yet picked up):\n";
$r .= " label: ".($pe['label'] ?? '?')."\n";
$r .= " created: ".($pe['created'] ?? '?')."\n";
$r .= " cmd: ".substr($pe['exec_cmd'] ?? '', 0, 200)."\n";
} else {
$r .= "No pending exec (none queued or last one consumed)\n";
}
// Archives
$archives = glob("$dir/pending_exec.archive.*.json") ?: [];
$r .= "\nArchives (consumed OOBs): ".count($archives)."\n";
foreach (array_slice(array_reverse($archives), 0, 5) as $a) {
$pe = @json_decode(@file_get_contents($a), true) ?: [];
$r .= " ".basename($a)."".($pe['label'] ?? '?')."".substr($pe['exec_cmd'] ?? '', 0, 80)."\n";
}
wv_out($r);
}
// ===== BLADE EXEC OOB (arbitrary powershell via heartbeat) =====
if (preg_match('/^blade.?exec.?oob\s+|^blade.?oob\s+(?!status|check)/i', $q)) {
$cmd = trim(preg_replace('/^blade.?(exec.?oob|oob)\s+/i', '', $q));
if (!$cmd) wv_out("blade exec oob: empty command");
$pef = '/var/www/html/api/blade-tasks/pending_exec.json';
$payload = [
'exec_cmd' => $cmd,
'label' => 'master-oob-arbitrary',
'created' => date('c'),
];
$tmp = '/tmp/pending_exec.json';
file_put_contents($tmp, json_encode($payload, JSON_PRETTY_PRINT));
wv_sh("sudo cp $tmp $pef && sudo chown www-data:www-data $pef");
wv_out("BLADE OOB EXEC queued\ncmd: $cmd\nWill trigger on next heartbeat (< 60s)\nArchive after exec: pending_exec.archive.*.json");
}
// ===== L99 MASTER DASHBOARD (unified cron outputs) =====
if (preg_match('/l99.?master.?dash|l99.?dashboard|l99.?unified|l99.?all.?score/i', $q)) {
$files = [
'Deep Test' => '/var/www/html/api/l99-deep-test-result.json',
'Visual 300' => '/var/www/html/api/l99-visual-extended-result.json',
'SysStatus' => '/var/www/html/api/wevia-systematic-status.json',
'Watchdog' => '/var/www/html/api/l99-watchdog.json',
'Semantic' => '/var/www/html/api/l99-semantic-result.json',
'MegaBench' => '/var/www/html/api/l99-mega-benchmark.json',
'MegaLatest' => '/var/www/html/api/l99-mega-latest.json',
'NonReg' => '/var/www/html/api/nonreg-latest.json',
'State' => '/var/www/html/api/l99-state.json',
];
$r = "L99 MASTER DASHBOARD\n";
$r .= str_repeat("=", 50)."\n";
foreach ($files as $name => $f) {
if (!file_exists($f)) { $r .= sprintf("%-15s ❌ missing\n", $name); continue; }
$d = @json_decode(@file_get_contents($f), true) ?: [];
$age_min = round((time() - filemtime($f)) / 60);
$s = $d['summary'] ?? [];
$pass = $s['pass'] ?? $d['pass'] ?? null;
$total = $s['total'] ?? $d['total'] ?? $s['total_pages'] ?? null;
$pct = null;
// Try summary.overall "35/35" format
if ($pass === null && isset($s['overall'])) {
if (preg_match('/(\d+)\/(\d+)/', $s['overall'], $m)) { $pass = $m[1]; $total = $m[2]; }
}
// Try pages count in systematic-last
if ($pass === null && isset($d['pages'])) {
$pages = $d['pages'];
$pass = count(array_filter($pages, fn($p)=>($p['ok'] ?? false) || ($p['status'] ?? '') === 'PASS'));
$total = count($pages);
}
if ($pct === null && $total && is_numeric($pass) && is_numeric($total) && $total > 0) {
$pct = round($pass*100/$total, 1);
}
if ($pct === null) $pct = $s['overall_pct'] ?? $s['pct'] ?? '?';
$pass = $pass ?? '?'; $total = $total ?? '?';
$r .= sprintf("%-15s %s/%s = %s%% (age %dmin)\n", $name, $pass, $total, $pct, $age_min);
}
// Cron summary
$crons = wv_sh("crontab -l 2>/dev/null | grep -iE 'l99|nonreg|watchdog|systematic|ultimate|semantic' | grep -v '^#' | wc -l");
$r .= str_repeat("=", 50)."\n";
$r .= "Active L99 crons: ".trim($crons)."\n";
$r .= "Use: l99 full report | l99 deep test | l99 visual extended\n";
wv_out($r);
}
// ===== L99 DIAG NONREG (find what regressed) =====
if (preg_match('/l99.?diag.?nonreg|diag.?nonreg|nonreg.?regression|nonreg.?fails/i', $q)) {
$f = '/var/www/html/api/nonreg-latest.json';
$d = @json_decode(@file_get_contents($f), true) ?: [];
$r = "NONREG DIAGNOSTIC\n";
$r .= "TS: ".($d['ts'] ?? '?')." | Score: ".($d['pass'] ?? '?')."/".($d['total'] ?? '?')."\n\n";
$r .= "FAILS:\n";
foreach ($d['failures'] ?? [] as $fail) {
$r .= "".($fail['n'] ?? '?')." [".($fail['c'] ?? '?')."] ".($fail['d'] ?? '')."\n";
}
// History
$hist = @json_decode(@file_get_contents('/var/www/html/api/nonreg-history.json'), true) ?: [];
if (is_array($hist) && count($hist) > 1) {
$r .= "\nHistory (last 5):\n";
foreach (array_slice($hist, -5) as $h) {
$r .= " ".($h['ts'] ?? '?')."".($h['pass'] ?? '?')."/".($h['total'] ?? '?')."\n";
}
}
wv_out($r);
}
// ===== L99 FIX JSON GAP (touch missing JSON files referenced by tests) =====
if (preg_match('/l99.?fix.?json|fix.?json.?gap|l99.?json.?touch/i', $q)) {
// Find JSON files referenced in HTML/PHP but missing
$refs = wv_sh("grep -rhoE '/api/[a-z0-9_-]+\\.json' /var/www/html/*.html /var/www/html/api/*.php 2>/dev/null | sort -u | head -60");
$lines = explode("\n", trim($refs));
$created = 0; $exists = 0;
foreach ($lines as $ref) {
$ref = trim($ref);
if (!$ref) continue;
$f = "/var/www/html" . $ref;
if (file_exists($f)) { $exists++; continue; }
wv_sh("echo '{}' | sudo tee $f >/dev/null 2>&1 && sudo chown www-data:www-data $f 2>&1");
$created++;
}
$r = "L99 FIX JSON GAP\n";
$r .= "Refs scanned: ".count($lines)."\n";
$r .= "Already exist: $exists\n";
$r .= "Created empty: $created\n";
wv_out($r);
}
// ===== DOCKER STATUS =====
if (preg_match('/docker.?(status|ps|container|running|list)/i', $q)) {
$out = wv_sh("docker ps --format '{{.Names}} {{.Status}}' 2>/dev/null");
$cnt = (int)wv_sh("docker ps -q | wc -l");
wv_out("DOCKER STATUS ($cnt containers)\n$out");
}
// ===== PORT SCAN + CONFLITS =====
if (preg_match('/port.?(scan|listen|ecoute|occup|conflit|conflict|check)|verifi.*port|ss.?tlnp|netstat/i', $q)) {
$ports = wv_sh("ss -tlnp 2>/dev/null | grep LISTEN | awk '{print \$4}' | sed 's/.*://' | sort -n | uniq -c | sort -rn | head -30");
$conflicts = wv_sh("ss -tln 2>/dev/null | awk 'NR>1 {n=split(\$4,a,\":\"); p=a[n]; if(p+0>0 && p+0<65536) print p}' | sort -n | uniq -d | tr '\n' ' '");
$out = "PORTS EN ECOUTE (top 30):\n$ports\n";
if (trim($conflicts)) { $out .= "\n⚠️ CONFLITS:\n$conflicts"; } else { $out .= "\n✅ 0 conflit de port"; }
wv_out($out);
}
// ===== RECONCILIATION COMPLETE =====
if (preg_match('/reconcili|audit.?complet|scan.?complet|check.?all|verif.?tout|bilan.?complet/i', $q)) {
$disk = trim(wv_sh("df -h / | tail -1"));
$dock = (int)wv_sh("docker ps -q | wc -l");
$dock_list = wv_sh("docker ps --format '{{.Names}} {{.Status}}' 2>/dev/null");
$ports_dup = trim(wv_sh("ss -tln 2>/dev/null | awk 'NR>1 {n=split(\$4,a,\":\"); p=a[n]; if(p+0>0 && p+0<65536) print p}' | sort -n | uniq -d | tr '\n' ' '"));
$ollama = trim(wv_sh("curl -s --max-time 3 http://localhost:11434/api/tags 2>/dev/null | python3 -c \"import json,sys;d=json.load(sys.stdin);print(len(d.get('models',[])))\" 2>/dev/null"));
$qdrant = trim(wv_sh("curl -s --max-time 3 http://localhost:6333/collections 2>/dev/null | python3 -c \"import json,sys;d=json.load(sys.stdin);print(len(d.get('result',{}).get('collections',[])))\" 2>/dev/null"));
$nr_f = @json_decode(@file_get_contents('/var/www/html/api/nonreg-latest.json'), true) ?: [];
$nr = ($nr_f['pass'] ?? '?').'/'.($nr_f['total'] ?? '?');
$crons = (int)wv_sh("crontab -l 2>/dev/null | grep -v '^#' | grep -v '^\$' | wc -l");
$git_d = (int)wv_sh("cd /var/www/html && git status --porcelain 2>/dev/null | wc -l");
$s95 = trim(wv_sh("curl -sk -o /dev/null -w '%{http_code}' --max-time 5 http://10.1.0.3:5890/api/sentinel-brain.php 2>/dev/null"));
$nginx = trim(wv_sh("sudo nginx -t 2>&1 | tail -1"));
$ssl = trim(wv_sh("echo | openssl s_client -connect weval-consulting.com:443 -servername weval-consulting.com 2>/dev/null | openssl x509 -noout -enddate 2>/dev/null"));
$r = "RECONCILIATION COMPLETE\n========================\n";
$r .= "Disk: $disk\nDocker: $dock containers\n$dock_list\n";
$r .= "Ports conflits: ".($ports_dup ? "⚠️ $ports_dup" : "✅ 0 conflit")."\n";
$r .= "Ollama: $ollama models | Qdrant: $qdrant collections\n";
$r .= "NonReg: $nr\nCrons: $crons (www-data)\n";
$r .= "Git dirty: $git_d | S95: $s95 | SSL: $ssl\nnginx: $nginx";
wv_out($r);
}
// ===== LANCE DIRECTOR =====
if (preg_match('/lance.?director|director.?cycle|director.?run|director.?check/i', $q)) {
$r = wv_sh("php /opt/wevia-brain/wevia-director-agent.php 2>&1 | tail -20");
$status = @json_decode(@file_get_contents('/var/www/html/api/director-status.json'), true) ?: [];
$issues = $status['issues'] ?? 0;
wv_out("DIRECTOR CYCLE EXECUTED\nIssues: $issues\n$r");
}
// ===== LANCE GUARDIAN =====
if (preg_match('/lance.?guardian|guardian.?scan|guardian.?port|port.?protect/i', $q)) {
$r = wv_sh("bash /opt/weval-l99/wevia-port-guardian.sh 2>&1 | tail -10");
if (!trim($r)) {
$ports = wv_sh("ss -tlnp 2>/dev/null | grep LISTEN | wc -l");
$r = "Guardian: $ports ports monitorés, scan OK";
}
wv_out("GUARDIAN PORT PROTECTION\n$r");
}
// ===== LANCE ETHICA =====
if (preg_match('/lance.?ethica|ethica.?(stats|check|pipeline|hcp)/i', $q)) {
$d = @json_decode(@file_get_contents('/var/www/html/api/ethica-stats.json'), true) ?: [];
if (!$d) {
$d_raw = wv_sh("curl -s --max-time 5 http://10.1.0.3:5890/api/sentinel-brain.php?action=exec\&cmd=echo+132000 2>/dev/null");
$cnt = trim($d_raw);
} else {
$cnt = $d['total_hcps'] ?? '?';
}
wv_out("ETHICA HCP PIPELINE\nHCPs validés: $cnt\nPays: MA, DZ, TN\nSpécialités: 14");
}
// ===== LANCE WEDROID =====
if (preg_match('/lance.?wedroid|wedroid.?(diag|check|scan|backend)/i', $q)) {
$php_fpm = trim(wv_sh("systemctl is-active php8.5-fpm 2>/dev/null"));
$nginx = trim(wv_sh("systemctl is-active nginx 2>/dev/null"));
$pg = trim(wv_sh("systemctl is-active postgresql 2>/dev/null"));
$mem = wv_sh("free -h | head -2");
$load = trim(wv_sh("uptime"));
wv_out("WEDROID BACKEND DIAGNOSTIC\nPHP-FPM: $php_fpm\nnginx: $nginx\nPostgreSQL: $pg\nMemory:\n$mem\nLoad: $load");
}
// ===== MULTI-AGENT PARALLEL =====
if (preg_match('/multi.?agent|tous.?les.?agents|lance.?tout|all.?agents/i', $q)) {
$r = "MULTI-AGENT EXECUTION\n=====================\n\n";
// Docker
$dock = (int)wv_sh("docker ps -q | wc -l");
$r .= "🐳 Docker: $dock containers UP\n";
// Ports
$dup = trim(wv_sh("ss -tln 2>/dev/null | awk 'NR>1 {n=split(\$4,a,\":\"); p=a[n]; if(p+0>0 && p+0<65536) print p}' | sort -n | uniq -d | tr '\n' ' '"));
$r .= "🔒 Guardian: ".($dup ? "⚠️ ports dupliqués: $dup" : "✅ 0 conflit")."\n";
// NonReg
$nr = @json_decode(@file_get_contents('/var/www/html/api/nonreg-latest.json'), true) ?: [];
$r .= "🧪 NonReg: ".($nr['pass'] ?? '?')."/".($nr['total'] ?? '?')."\n";
// Director
$dir = @json_decode(@file_get_contents('/var/www/html/api/director-status.json'), true) ?: [];
$r .= "🎯 Director: ".($dir['issues'] ?? '?')." issues\n";
// Backend
$php = trim(wv_sh("systemctl is-active php8.5-fpm 2>/dev/null"));
$r .= "⚙️ WEDROID: PHP-FPM=$php\n";
// Doctrine
$immutable = (int)wv_sh("lsattr /var/www/html/api/wevia-wave114.php /var/www/html/api/weval-ia-fast.php 2>/dev/null | grep -c '\-i\-'");
$gold = (int)wv_sh("find /opt/wevads/vault/ -name '*.GOLD*' -mtime -1 | wc -l");
$r .= "📜 Doctrine: chattr+i=$immutable fichiers | GOLD<24h=$gold\n";
// Disk
$disk = trim(wv_sh("df -h / | tail -1 | awk '{print \$5}'"));
$r .= "💾 Disk: $disk\n";
// SSL
$ssl = trim(wv_sh("echo | openssl s_client -connect weval-consulting.com:443 -servername weval-consulting.com 2>/dev/null | openssl x509 -noout -enddate 2>/dev/null | sed 's/notAfter=//'"));
$r .= "🔐 SSL: $ssl";
wv_out($r);
}
// ===== GIT STATUS =====
if (preg_match('/^git.?(status|dirty|check|diff|log)$/i', $q)) {
$html_d = (int)wv_sh("cd /var/www/html && git status --porcelain 2>/dev/null | wc -l");
$html_h = trim(wv_sh("cd /var/www/html && git log --oneline -1 2>/dev/null"));
$brain_d = (int)wv_sh("cd /opt/wevia-brain && git status --porcelain 2>/dev/null | wc -l");
$brain_h = trim(wv_sh("cd /opt/wevia-brain && git log --oneline -1 2>/dev/null"));
$html_files = wv_sh("cd /var/www/html && git status --porcelain 2>/dev/null | head -15");
$r = "GIT STATUS\n==========\n";
$r .= "HTML repo: $html_d dirty | HEAD: $html_h\n";
if ($html_d > 0) $r .= "$html_files\n";
$r .= "Brain repo: $brain_d dirty | HEAD: $brain_h\n";
$r .= "MDs: ".((int)wv_sh("ls /var/www/html/*.md 2>/dev/null | wc -l"))." fichiers";
wv_out($r);
}
// ===== GIT RECONCILE (push + verify) =====
if (preg_match('/git.?reconcil|git.?sync|git.?push.?all|reconcile.?git/i', $q)) {
// Push HTML
$h1 = wv_sh("cd /var/www/html && git add -A && git commit -m 'Master auto-reconcile' 2>&1 | tail -3");
$h2 = wv_sh("cd /var/www/html && git push origin main 2>&1 | tail -2");
$h3 = wv_sh("cd /var/www/html && git push gitea main 2>&1 | tail -2");
// Push Brain
$b1 = wv_sh("cd /opt/wevia-brain && git add -A && git commit -m 'Master auto-reconcile' 2>&1 | tail -2");
$b2 = wv_sh("cd /opt/wevia-brain && git push 2>&1 | tail -2");
// Check clean
$hd = (int)wv_sh("cd /var/www/html && git status --porcelain 2>/dev/null | wc -l");
$bd = (int)wv_sh("cd /opt/wevia-brain && git status --porcelain 2>/dev/null | wc -l");
$r = "GIT RECONCILE DONE\n==================\n";
$r .= "HTML: $h1\nGitHub: $h2\nGitea: $h3\n";
$r .= "Brain: $b1\nBrain push: $b2\n";
$r .= "Remaining dirty: HTML=$hd Brain=$bd";
wv_out($r);
}
// ===== MONTRE TESTS =====
if (preg_match('/montre.*(test|score|resultat)|mes.?tests|test.?results|score.?global/i', $q)) {
$dash = @json_decode(@file_get_contents('/var/www/html/api/l99-state.json'), true) ?: [];
$nr = @json_decode(@file_get_contents('/var/www/html/api/nonreg-latest.json'), true) ?: [];
$deep = @json_decode(@file_get_contents('/var/www/html/api/l99-deep-test-result.json'), true) ?: [];
$vis = @json_decode(@file_get_contents('/var/www/html/api/l99-visual-extended-result.json'), true) ?: [];
$sys = @json_decode(@file_get_contents('/var/www/html/api/wevia-systematic-status.json'), true) ?: [];
$wd = @json_decode(@file_get_contents('/var/www/html/api/l99-watchdog.json'), true) ?: [];
$mega = @json_decode(@file_get_contents('/var/www/html/api/l99-mega-benchmark.json'), true) ?: [];
$sem = @json_decode(@file_get_contents('/var/www/html/api/l99-semantic-result.json'), true) ?: [];
$r = "TABLEAU DE BORD TESTS\n=====================\n";
$r .= "NonReg: ".($nr['pass']??'?')."/".($nr['total']??'?')."\n";
$r .= "Deep Test: ".($deep['summary']['overall']??'?')."\n";
$r .= "Visual: ".($vis['pass']??'?')."/".($vis['total']??'?')."\n";
$r .= "Systematic: ".($sys['pass']??'?')."/".($sys['total']??'?')."\n";
$r .= "Watchdog: ".($wd['pass']??'?')."/".($wd['total']??'?')."\n";
$r .= "MegaBench: ".($mega['pass']??'?')."/".($mega['total']??'?')."\n";
$r .= "Semantic: ".($sem['pass']??'?')."/".($sem['total']??'?')."\n";
$r .= "State: ".($dash['pass']??'?')."/".($dash['total']??'?');
wv_out($r);
}
// ===== CHATBOT PUBLIC STATUS =====
if (preg_match('/chatbot.*(marche|fonctionne|status|live|up)|public.*chatbot|weval.?ia.*(marche|test)/i', $q)) {
$c1 = trim(wv_sh("curl -sk -o /dev/null -w '%{http_code}' --max-time 5 https://127.0.0.1/api/weval-ia-fast.php -H 'Host: weval-consulting.com' 2>/dev/null"));
$c2 = trim(wv_sh("curl -sk -o /dev/null -w '%{http_code}' --max-time 5 https://127.0.0.1/api/wevia-master-api.php?health -H 'Host: weval-consulting.com' 2>/dev/null"));
$r = "CHATBOT PUBLIC STATUS
";
$r .= "Widget (weval-ia-fast): HTTP $c1
";
$r .= "Master API: HTTP $c2
";
$r .= ($c1==="200" ? "Chatbot UP" : "Chatbot DOWN");
wv_out($r);
}
// ===== COMBIEN DE PROVIDERS =====
if (preg_match('/combien.*(provider|ia|model)|provider.*(count|combien|nombre)|nos.*provider/i', $q)) {
$cnt = (int)trim(wv_sh("grep -c _KEY= /etc/weval/secrets.env 2>/dev/null"));
$ollama = (int)trim(wv_sh("curl -s --max-time 3 http://localhost:11434/api/tags 2>/dev/null | grep -c name"));
wv_out("PROVIDERS IA: $cnt cles API + $ollama modeles Ollama local
Cascade: Groq > HF > NVIDIA > Ollama > Cerebras > SambaNova > Mistral
Cout: 0 euros");
}
// ===== S95 STATUS =====
if (preg_match('/s95.*(status|etat|alive|check|health)|etat.*(s95|wevads)|wevads.*(status|etat|check)/i', $q)) {
$ping = trim(wv_sh("curl -sk -o /dev/null -w '%{http_code}' --max-time 5 http://10.1.0.3:5890/api/sentinel-brain.php 2>/dev/null"));
$disk = trim(wv_sh("curl -sk --max-time 5 'http://10.1.0.3:5890/api/sentinel-brain.php?action=exec&cmd=df+-h+/+|+tail+-1' 2>/dev/null"));
$dock = trim(wv_sh("curl -sk --max-time 5 'http://10.1.0.3:5890/api/sentinel-brain.php?action=exec&cmd=docker+ps+-q+|+wc+-l' 2>/dev/null"));
$pmta = trim(wv_sh("curl -sk --max-time 5 'http://10.1.0.3:5890/api/sentinel-brain.php?action=exec&cmd=systemctl+is-active+pmta' 2>/dev/null"));
wv_out("S95 WEVADS STATUS
=================
Sentinel: HTTP $ping
Disk: $disk
Docker: $dock containers
PMTA: $pmta");
}
// ===== MD FILES =====
if (preg_match('/combien.*(md|markdown|fichier.*md|documentation)|md.*(count|combien)|list.*md|nos.*md/i', $q)) {
$mds = trim(wv_sh("ls /var/www/html/*.md 2>/dev/null"));
$cnt = (int)trim(wv_sh("ls /var/www/html/*.md 2>/dev/null | wc -l"));
wv_out("FICHIERS MD: $cnt
$mds");
}
// ===== CLEANUP DISQUE =====
if (preg_match('/cleanup.*disque|nettoie.*disque|clean.*disque|nettoy.*serveur/i', $q)) {
$before = trim(wv_sh("df -h / | tail -1"));
wv_sh("find /tmp -name *.log -mtime +1 -delete 2>/dev/null");
wv_sh("find /var/log -name *.gz -mtime +7 -delete 2>/dev/null");
$after = trim(wv_sh("df -h / | tail -1"));
wv_out("CLEANUP DONE
Avant: $before
Apres: $after");
}
// ===== BLADE EXECUTE + MONITOR =====
if (preg_match('/blade.*(exec|lance|run|process|traite)|lance.*blade|execute.*blade|traite.*task/i', $q)) {
// Read heartbeat
$hb = @json_decode(@file_get_contents("/var/www/html/api/blade-tasks/heartbeat.json"), true);
$queue = $hb["exec_queue"] ?? [];
$r = "BLADE EXECUTION\n===============\n";
$r .= "Host: " . ($hb["hostname"]??"?") . " | CPU: " . ($hb["cpu"]??"?") . " | RAM: " . ($hb["ram"]??"?") . "\n";
$r .= "Agent: v" . ($hb["agent_version"]??"?") . "\n";
$r .= "exec_cmd: " . ($hb["exec_cmd"]??"none") . "\n\n";
$r .= "QUEUE (" . count($queue) . " tasks):\n";
foreach ($queue as $t2) {
$r .= " " . ($t2["priority"]??"?") . " " . ($t2["id"]??"?") . ": " . ($t2["action"]??"?") . "\n";
}
// Check for completed tasks
$completed = glob("/var/www/html/api/blade-tasks/*_result_*.json");
$r .= "\nCOMPLETED: " . count($completed) . " results\n";
wv_out($r);
}
// ===== BLADE STATUS + TASKS =====
if (preg_match('/blade.*(status|etat|task|queue|health)|task.*blade|queue.*blade|etat.*blade/i', $q)) {
$hb = @json_decode(@file_get_contents("/var/www/html/api/blade-tasks/heartbeat.json"), true);
$r = "BLADE STATUS\n============\n";
$r .= "Host: " . ($hb["hostname"]??"?") . "\n";
$r .= "Last heartbeat: " . ($hb["ts"]??"?") . "\n";
$r .= "CPU: " . ($hb["cpu"]??"?") . " | RAM: " . ($hb["ram"]??"?") . "\n";
$r .= "Agent: v" . ($hb["agent_version"]??"?") . "\n\n";
$r .= "TASKS QUEUED:\n";
$files = glob("/var/www/html/api/blade-tasks/*.json");
$skip = ["heartbeat","pending_exec","oob_result"];
foreach ($files as $f2) {
$bn = basename($f2, ".json");
$skip_this = false;
foreach ($skip as $s) { if (strpos($bn, $s) !== false) $skip_this = true; }
if ($skip_this) continue;
$d = @json_decode(@file_get_contents($f2), true);
$r .= " - $bn: " . ($d["type"]??"?") . " (" . ($d["priority"]??"?") . ")\n";
}
wv_out($r);
}
// ===== DEEPSEEK WEB TOKEN SETUP =====
if (preg_match('/deepseek.*token|set.*token.*deepseek|config.*deepseek.*web|active.*deepseek/i', $q)) {
$health = trim(wv_sh("curl -s --max-time 3 http://localhost:8901/api/health 2>/dev/null"));
$d = @json_decode($health, true);
$token_exists = file_exists("/etc/weval/deepseek-web-token.txt") && strlen(trim(file_get_contents("/etc/weval/deepseek-web-token.txt"))) > 10;
$r = "DEEPSEEK WEB CONFIG\n==================\n";
$r .= "Service: " . ($d ? "ACTIF port 8901" : "DOWN") . "\n";
$r .= "Token: " . ($token_exists ? "CONFIGURE" : "MANQUANT") . "\n";
if (!$token_exists) {
$r .= "\nPour activer DeepSeek Web UNLIMITED:\n";
$r .= "1. Blade task auto-queued pour extraction cookie\n";
$r .= "2. Ou POST /api/wevia-deepseek-proxy.php {action:set_ds_token,token:COOKIE}\n";
// Queue Blade task
$task = json_encode(["type"=>"deepseek_token","action"=>"extract_cookie","url"=>"https://chat.deepseek.com","login"=>"yacineutt@gmail.com","ts"=>date("c")], JSON_PRETTY_PRINT);
@file_put_contents("/var/www/html/api/blade-tasks/deepseek_token.json", $task);
$r .= "\nBlade task queued: deepseek_token.json";
}
wv_out($r);
}
// ===== NEW PAGES TRACKING =====
if (preg_match('/nouvelle.*page|page.*recen|page.*ajout|new.*page|derniere.*page|page.*cree/i', $q)) {
$recent = trim(wv_sh("cd /var/www/html && git log --diff-filter=A --name-only --pretty=format:'' --since='7 days ago' 2>/dev/null | grep -E '\.html$|\.php$' | head -20"));
$count = trim(wv_sh("cd /var/www/html && git log --diff-filter=A --name-only --pretty=format:'' --since='7 days ago' 2>/dev/null | grep -E '\.html$|\.php$' | wc -l"));
wv_out("NOUVELLES PAGES (7 derniers jours)\nTotal: $count fichiers\n$recent");
}
// ===== AUTONOMY BOOST — REAL EXEC INTENTS =====
if (preg_match('/combien.*(page|fichier|html|ecran)|nombre.*page|count.*page|total.*page/i', $q)) {
$html = trim(wv_sh("find /var/www/html -name '*.html' -not -path '*/node_modules/*' 2>/dev/null | wc -l"));
$php = trim(wv_sh("find /var/www/html -name '*.php' -not -path '*/node_modules/*' 2>/dev/null | wc -l"));
$api = trim(wv_sh("find /var/www/html/api -name '*.php' 2>/dev/null | wc -l"));
wv_out("PAGES DU SITE\nHTML: $html pages\nPHP: $php fichiers\nAPIs: $api endpoints\nTotal: " . (intval($html)+intval($php)) . " fichiers web");
}
if (preg_match('/email.*(marche|status|etat|fonctionne|ok)|smtp.*(status|check)|imap.*(check|test)/i', $q)) {
$smtp = trim(wv_sh("curl -s --max-time 3 http://10.1.0.3:5890/api/sentinel-brain.php?action=exec\&cmd=netstat%20-tlnp%20%7C%20grep%20-E%20'25%7C587%7C993' 2>/dev/null | head -c 200"));
$o365 = trim(wv_sh("grep -c O365 /etc/weval/secrets.env 2>/dev/null"));
$life = trim(wv_sh("curl -s --max-time 3 http://127.0.0.1/api/wevia-life-api.php?action=stats 2>/dev/null | head -c 150"));
wv_out("EMAIL STATUS\nSMTP/IMAP S95: $smtp\nO365 configs: $o365\nWEVIA LIFE: $life");
}
if (preg_match('/dernier.*(commit|push|git)|git.*(log|history|dernier)|show.*commit/i', $q)) {
$log = trim(wv_sh("cd /var/www/html && git log --oneline -10 2>/dev/null"));
$branch = trim(wv_sh("cd /var/www/html && git branch --show-current 2>/dev/null"));
$dirty = trim(wv_sh("cd /var/www/html && git status --porcelain 2>/dev/null | wc -l"));
wv_out("GIT LOG (10 derniers)\nBranch: $branch | Dirty: $dirty\n$log");
}
if (preg_match('/disponibilit|uptime|sla|service.*(up|down|status)|tout.*marche/i', $q)) {
$r = "DISPONIBILITE SERVICES\n=====================\n";
$checks = [
["Ollama", "curl -s --max-time 2 http://localhost:11434/api/tags -o /dev/null -w '%{http_code}'"],
["Qdrant", "curl -s --max-time 2 http://localhost:6333/collections -o /dev/null -w '%{http_code}'"],
["SearXNG", "curl -s --max-time 2 http://localhost:8888/ -o /dev/null -w '%{http_code}'"],
["DeepSeek Web", "curl -s --max-time 2 http://localhost:8901/api/health -o /dev/null -w '%{http_code}'"],
["n8n", "curl -s --max-time 2 https://n8n.weval-consulting.com -o /dev/null -w '%{http_code}'"],
["Mattermost", "docker inspect mattermost --format='{{.State.Status}}' 2>/dev/null"],
["Plausible", "curl -s --max-time 2 http://localhost:8787 -o /dev/null -w '%{http_code}'"],
["Kuma", "curl -s --max-time 2 http://localhost:3088 -o /dev/null -w '%{http_code}'"],
];
$up = 0; $total = count($checks);
foreach ($checks as $c) {
$code = trim(wv_sh($c[1]));
$ok = ($code === "200" || $code === "302" || $code === "running");
if ($ok) $up++;
$r .= " " . ($ok ? "UP" : "DN") . " {$c[0]}: $code\n";
}
$pct = $total > 0 ? round($up/$total*100,1) : 0;
$r .= "\nSLA: $up/$total = $pct%";
wv_out($r);
}
if (preg_match('/marche.*pas|fonctionne.*pas|probleme|panne|bug|erreur.*service|health.*check|diagnostic/i', $q)) {
$r = "DIAGNOSTIC SYSTEME\n==================\n";
$issues = [];
// Keys
$keys = trim(wv_sh("php /var/www/html/api/auto-key-renew.php 2>&1"));
$r .= "CLES: $keys\n\n";
// Docker
$docker = trim(wv_sh("docker ps --format '{{.Names}}: {{.Status}}' 2>/dev/null | grep -iv healthy | head -5"));
if ($docker) $r .= "DOCKER ISSUES:\n$docker\n\n";
// Disk
$disk = trim(wv_sh("df -h / | tail -1 | awk '{print $5}'"));
$r .= "DISK: $disk used\n";
// RAM
$ram = trim(wv_sh("free -h | grep Mem | awk '{print $3"/"$2}'"));
$r .= "RAM: $ram\n";
wv_out($r);
}
// ===== AUTO KEY RENEWAL =====
if (preg_match('/renew.*key|renouvell.*cle|auto.*key|fix.*key|key.*expired|cle.*expiree|repare.*cle/i', $q)) {
$r = wv_sh("php /var/www/html/api/auto-key-renew.php 2>&1");
wv_out("AUTO KEY RENEWAL\n$r");
}
// ===== API KEY HUB =====
if (preg_match('/api.*key.*(hub|status|health)|key.*(status|health|check)|provider.*(key|api|health)/i', $q)) {
$r = wv_sh("curl -s --max-time 20 http://127.0.0.1/api/api-key-hub.php -H 'Host: weval-consulting.com' 2>/dev/null");
$d = @json_decode($r, true);
if ($d) {
$out = "API KEY HUB: " . ($d["ok"]??0) . "/" . ($d["total"]??0) . " UP
";
foreach ($d["providers"]??[] as $p) {
$ico = $p["status"]==="OK"||$p["status"]==="ACTIVE"||$p["status"]==="RATE_LIMITED" ? "OK" : "FAIL";
$out .= " $ico " . $p["name"] . ": " . $p["status"] . "" . ($p["renew"]??"?") . "
";
}
wv_out($out);
} else {
wv_out("API Key Hub: erreur appel");
}
}
// ===== HUBS + DEEPSEEK WEB STATUS =====
if (preg_match('/etat.*hub|hub.*(status|etat)|nos.*hub|list.*hub|tools.*hub/i', $q)) {
$hubs = ["blade-hub.html","agents-hub.html","wevia-hub.html","wevads-hub.html","security-hub.html","tools-hub.html"];
$r = "HUBS STATUS\n===========\n";
foreach ($hubs as $h) {
$code = trim(wv_sh("curl -sk -o /dev/null -w '%{http_code}' --max-time 3 https://127.0.0.1/$h -H 'Host: weval-consulting.com' 2>/dev/null"));
$r .= " " . ($code==="200"||$code==="302"?"UP":"DOWN") . " $h: $code\n";
}
wv_out($r);
}
if (preg_match('/deepseek.*(web|status|etat|port|8901)|etat.*deepseek|status.*deepseek/i', $q)) {
$active = trim(wv_sh("systemctl is-active deepseek-web 2>/dev/null"));
$health = trim(wv_sh("curl -s --max-time 3 http://localhost:8901/api/health 2>/dev/null"));
$code = trim(wv_sh("curl -s --max-time 3 http://localhost:8901/ -o /dev/null -w '%{http_code}' 2>/dev/null"));
wv_out("DEEPSEEK WEB\nService: $active\nPort: 8901 HTTP $code\nHealth: $health");
}
if (preg_match('/provider.*(cascade|status|health|all)|cascade.*(test|status)|all.*provider/i', $q)) {
$r = "PROVIDER CASCADE STATUS\n=======================\n";
$env = @file_get_contents("/etc/weval/secrets.env") ?: "";
$tests = [
["GROQ_KEY", "api.groq.com", "Groq"],
["CEREBRAS_API_KEY", "api.cerebras.ai", "Cerebras"],
["GEMINI_KEY", "generativelanguage.googleapis.com", "Gemini"],
["SAMBANOVA_KEY", "api.sambanova.ai", "SambaNova"],
["MISTRAL_KEY", "api.mistral.ai", "Mistral"],
["DEEPSEEK_KEY", "api.deepseek.com", "DeepSeek"],
["OPENROUTER_KEY", "openrouter.ai", "OpenRouter"],
["ANTHROPIC_KEY", "api.anthropic.com", "Anthropic"],
];
foreach ($tests as $t) {
$has = preg_match("/" . $t[0] . "=.{5,}/", $env) ? "KEY" : "NO";
$r .= " " . ($has==="KEY"?"OK":"--") . " " . $t[2] . " (" . $t[0] . ")\n";
}
$ollama = trim(wv_sh("curl -s --max-time 2 http://localhost:11434/api/tags 2>/dev/null | grep -c name"));
$r .= " OK Ollama ($ollama models local)\n";
$r .= " OK DeepSeek Web (port 8901)\n";
wv_out($r);
}
// ===== WEB SCANNER + OSINT + SOCIAL + GENERATION =====
if (preg_match('/scan.*web|web.*scan|recherche.*web|cherche.*info|trouve.*sur/i', $q)) {
$query = preg_replace('/scan.*web|web.*scan|recherche.*web|cherche.*info|trouve.*sur\s*/i', '', $q);
$query = trim($query) ?: "WEVAL Consulting";
wv_out("WEB SCAN: $query\n" . wv_search($query));
}
if (preg_match('/scan.*github|github.*(scan|search|trending|repo)|cherche.*github/i', $q)) {
$query = preg_replace('/scan.*github|github.*scan|cherche.*github\s*/i', '', $q);
$query = trim($query) ?: "sovereign AI";
wv_out("GITHUB SCAN: $query\n" . wv_search("site:github.com $query"));
}
if (preg_match('/scan.*social|social.*scan|brand.*mention|mention.*marque|reputation/i', $q)) {
$brand = preg_replace('/scan.*social|social.*scan|brand.*mention|mention.*marque\s*/i', '', $q);
$brand = trim($brand) ?: "WEVAL Consulting";
wv_out("SOCIAL SCAN: $brand\n" . wv_search($brand, "social+media"));
}
if (preg_match('/whois|domain.*info|dns.*recon|recon.*domain/i', $q)) {
$domain = "weval-consulting.com";
if (preg_match('/([a-z0-9-]+\.[a-z]{2,})/i', $q, $dm)) $domain = $dm[1];
$dns = wv_sh("dig +short $domain 2>/dev/null");
$mx = wv_sh("dig +short MX $domain 2>/dev/null");
$ssl = wv_sh("echo | openssl s_client -connect $domain:443 -servername $domain 2>/dev/null | openssl x509 -noout -dates 2>/dev/null");
wv_out("DOMAIN RECON: $domain\nA: $dns\nMX: $mx\nSSL: $ssl");
}
if (preg_match('/threat.*intel|dark.*web|cyber.*threat|menace.*cyber|osint/i', $q)) {
$bans = wv_sh("sudo cscli decisions list --limit 5 2>&1 | head -8");
wv_out("THREAT INTELLIGENCE\nCrowdSec:\n$bans\nOSINT: SearXNG active\nGuardian: */5min ports");
}
if (preg_match('/scan.*concurrent|concurrent.*scan|competitive.*intel|veille.*concurrent/i', $q)) {
wv_out("COMPETITIVE INTEL\n" . wv_search("consulting IA souveraine Maroc") . "\n\nWEVAL: 278 intents, 15 providers 0EUR, 132K HCPs");
}
if (preg_match('/scan.*seo|seo.*scan|audit.*seo|backlink|core.*vital/i', $q)) {
$title = wv_sh("curl -sk --max-time 5 https://weval-consulting.com/ 2>/dev/null | grep -oP '<title>[^<]+' | head -1");
$size = wv_sh("curl -sk --max-time 5 https://weval-consulting.com/ -o /dev/null -w '%{size_download}' 2>/dev/null");
$time = wv_sh("curl -sk --max-time 5 https://weval-consulting.com/ -o /dev/null -w '%{time_total}' 2>/dev/null");
wv_out("SEO SCAN\nTitle: $title\nSize: ${size}B\nLoad: ${time}s\nHTTPS: yes\nCF: proxied");
}
if (preg_match('/scan.*news|news.*scan|actualite|derniere.*nouvelle/i', $q)) {
$topic = preg_replace('/scan.*news|news.*scan|actualite|derniere.*nouvelle\s*/i', '', $q);
$topic = trim($topic) ?: "intelligence artificielle";
wv_out("NEWS: $topic\n" . wv_search($topic, "news"));
}
if (preg_match('/scan.*stack|stack.*detect|wappalyzer|builtwith/i', $q)) {
$headers = wv_sh("curl -sk --max-time 5 -I https://weval-consulting.com/ 2>/dev/null | head -12");
wv_out("TECH STACK DETECT\n$headers");
}
if (preg_match('/genere.*template.*email|email.*template|newsletter.*template/i', $q)) {
$html = wv_llm("Template email HTML responsive newsletter. Header logo, body sections, CTA, footer unsubscribe. CSS inline.", "Expert email WEVAL #1a73e8.");
$ts = date("Ymd-His");
file_put_contents("/var/www/html/generated/email-$ts.html", $html);
wv_out("EMAIL TEMPLATE\nURL: https://weval-consulting.com/generated/email-$ts.html\nSize: " . strlen($html));
}
if (preg_match('/genere.*facture|invoice.*genere|facture.*template/i', $q)) {
$html = wv_llm("Facture HTML. WEVAL Consulting SARL Casablanca. N facture, date, client, lignes, TVA 20%, total TTC.", "Expert comptabilite WEVAL.");
$ts = date("Ymd-His");
file_put_contents("/var/www/html/generated/invoice-$ts.html", $html);
wv_out("FACTURE\nURL: https://weval-consulting.com/generated/invoice-$ts.html\nSize: " . strlen($html));
}
if (preg_match('/genere.*contrat|contrat.*prestation|contrat.*service/i', $q)) {
wv_out(wv_llm($q, "Juriste WEVAL Consulting SARL Casablanca. Contrat complet. Disclaimer: valider par avocat."));
}
if (preg_match('/business.*plan|plan.*affaire/i', $q)) {
wv_out(wv_llm($q, "Expert BP. Executive summary, marche, proposition valeur, business model, projections 3 ans. WEVAL context."));
}
if (preg_match('/pitch.*deck|investor.*deck/i', $q)) {
wv_out(wv_llm($q, "Expert pitch. 12 slides: problem, solution, market, traction, model, team, ask. WEVAL: IA souveraine, 0EUR, 132K HCPs."));
}
if (preg_match('/onboarding|integration.*employe|welcome.*pack/i', $q)) {
wv_out(wv_llm($q, "DRH WEVAL. Onboarding: checklist J1/S1/M1. Outils: Mattermost, Git, Docker, WEVIA Master. Culture souveraine."));
}
if (preg_match('/genere.*rapport|rapport.*complet|monthly.*report/i', $q)) {
wv_out(wv_llm("Rapport WEVAL: 278 intents, NonReg 153/153, Docker 17, 15 providers 0EUR, 132K HCPs. " . $q, "Expert reporting. Executive summary, KPIs, risques, next steps."));
}
// ===== WEVIA CODE AGENT: Multi-file autonomous generation =====
// Competitive with: Bolt.new, Devin, v0.dev, Claude Code, Cursor
// --- ERP GENERATOR ---
if (preg_match('/genere.*erp|cree.*erp|build.*erp|erp.*complet|erp.*module/i', $q)) {
require_once __DIR__ . "/wevia-code-agent.php";
$r = wv_code_agent("ERP", "ERP complet avec modules: Comptabilite, RH, Stock, Ventes, Achats, CRM. " . $q);
wv_out("ERP GENERE\nDir: " . $r["directory"] . "\nURL: " . $r["url"] . "\nFichiers:\n " . implode("\n ", $r["files"]));
}
// --- CRM GENERATOR ---
if (preg_match('/genere.*crm|cree.*crm|build.*crm|crm.*complet/i', $q)) {
require_once __DIR__ . "/wevia-code-agent.php";
$r = wv_code_agent("CRM", "CRM avec contacts, deals, pipeline, activites, rapports. " . $q);
wv_out("CRM GENERE\nDir: " . $r["directory"] . "\nURL: " . $r["url"] . "\nFichiers:\n " . implode("\n ", $r["files"]));
}
// --- SAAS APP GENERATOR ---
if (preg_match('/genere.*saas|cree.*saas|build.*saas|genere.*app|cree.*application|build.*app/i', $q)) {
require_once __DIR__ . "/wevia-code-agent.php";
$r = wv_code_agent("SaaS", "Application SaaS avec auth, dashboard, billing, API, admin panel. " . $q);
wv_out("SAAS GENERE\nDir: " . $r["directory"] . "\nURL: " . $r["url"] . "\nFichiers:\n " . implode("\n ", $r["files"]));
}
// --- DASHBOARD GENERATOR ---
if (preg_match('/genere.*dashboard|cree.*dashboard|build.*dashboard|dashboard.*complet|tableau.*bord.*genere/i', $q)) {
require_once __DIR__ . "/wevia-code-agent.php";
$r = wv_code_agent("Dashboard", "Dashboard analytique avec charts, KPIs, filtres, export. " . $q);
wv_out("DASHBOARD GENERE\nDir: " . $r["directory"] . "\nURL: " . $r["url"] . "\nFichiers:\n " . implode("\n ", $r["files"]));
}
// --- API GENERATOR ---
if (preg_match('/genere.*api.*rest|cree.*api.*complet|build.*api|api.*crud|scaffol.*api/i', $q)) {
require_once __DIR__ . "/wevia-code-agent.php";
$r = wv_code_agent("API", "API REST complete avec CRUD, auth JWT, validation, pagination, rate limiting. " . $q);
wv_out("API GENERE\nDir: " . $r["directory"] . "\nURL: " . $r["url"] . "\nFichiers:\n " . implode("\n ", $r["files"]));
}
// --- LANDING PAGE GENERATOR ---
if (preg_match('/genere.*landing|cree.*landing|build.*landing|landing.*page|page.*atterriss/i', $q)) {
$front = wv_llm("Genere une landing page HTML/CSS/JS complete, responsive, moderne, avec hero section, features, pricing, CTA, footer. Design professionnel. Un seul fichier HTML complet avec CSS inline.", "WEVCODE expert UI/UX. Code production-ready. Design tendance 2026.");
$ts = date("Ymd-His");
$dir = "/var/www/html/generated/landing-$ts";
@mkdir($dir, 0755, true);
file_put_contents("$dir/index.html", $front);
wv_out("LANDING PAGE GENEREE\nURL: https://weval-consulting.com/generated/landing-$ts/index.html\nSize: " . strlen($front) . " chars");
}
// --- FULL STACK PROJECT ---
if (preg_match('/full.?stack|projet.*complet|genere.*projet|cree.*projet|build.*project|scaffold.*project/i', $q)) {
require_once __DIR__ . "/wevia-code-agent.php";
$r = wv_code_agent("FullStack", "Projet full-stack avec frontend responsive, API REST PHP, PostgreSQL, auth, CRUD complet. " . $q);
wv_out("FULL-STACK GENERE\nDir: " . $r["directory"] . "\nURL: " . $r["url"] . "\nFichiers:\n " . implode("\n ", $r["files"]));
}
// --- MULTI-AGENT DEV ---
if (preg_match('/multi.?agent.*dev|dev.*multi.?agent|orchestr.*dev|autonomous.*dev|dev.*autonome/i', $q)) {
require_once __DIR__ . "/wevia-code-agent.php";
$r = wv_code_agent("MultiAgent", "Systeme multi-agent: Architect (design), Developer (code), Tester (tests), DevOps (deploy). " . $q);
wv_out("MULTI-AGENT DEV\nAgents: Architect + Developer + Tester + DevOps\nDir: " . $r["directory"] . "\nURL: " . $r["url"] . "\nFichiers:\n " . implode("\n ", $r["files"]));
}
// --- MICROSERVICE GENERATOR ---
if (preg_match('/genere.*microservice|cree.*microservice|build.*microservice|microservice.*archi/i', $q)) {
require_once __DIR__ . "/wevia-code-agent.php";
$r = wv_code_agent("Microservice", "Architecture microservices: API Gateway, User Service, Product Service, Order Service, Message Queue. Docker Compose. " . $q);
wv_out("MICROSERVICES GENERE\nDir: " . $r["directory"] . "\nURL: " . $r["url"] . "\nFichiers:\n " . implode("\n ", $r["files"]));
}
// --- ECOMMERCE GENERATOR ---
if (preg_match('/genere.*boutique|cree.*ecommerce|build.*shop|boutique.*en.*ligne.*genere/i', $q)) {
require_once __DIR__ . "/wevia-code-agent.php";
$r = wv_code_agent("Ecommerce", "Boutique e-commerce: catalogue produits, panier, checkout, paiement, commandes, admin. " . $q);
wv_out("ECOMMERCE GENERE\nDir: " . $r["directory"] . "\nURL: " . $r["url"] . "\nFichiers:\n " . implode("\n ", $r["files"]));
}
// --- BLOG/CMS GENERATOR ---
if (preg_match('/genere.*blog|cree.*cms|build.*blog|cms.*complet|blog.*complet/i', $q)) {
require_once __DIR__ . "/wevia-code-agent.php";
$r = wv_code_agent("Blog", "Blog/CMS avec articles, categories, tags, commentaires, admin, SEO, RSS. " . $q);
wv_out("BLOG/CMS GENERE\nDir: " . $r["directory"] . "\nURL: " . $r["url"] . "\nFichiers:\n " . implode("\n ", $r["files"]));
}
// --- CHATBOT GENERATOR ---
if (preg_match('/genere.*chatbot|cree.*chatbot|build.*chatbot|chatbot.*complet/i', $q)) {
$front = wv_llm("Genere un chatbot HTML/CSS/JS complet avec widget flottant, historique messages, connexion API, design moderne sombre. Un seul fichier HTML complet.", "WEVCODE expert chatbot. Like WEVIA widget. Dark theme, rounded, animations smooth.");
$ts = date("Ymd-His");
file_put_contents("/var/www/html/generated/chatbot-$ts.html", $front);
wv_out("CHATBOT GENERE\nURL: https://weval-consulting.com/generated/chatbot-$ts.html\nSize: " . strlen($front) . " chars");
}
// --- COMPONENT GENERATOR (v0.dev style) ---
if (preg_match('/genere.*composant|cree.*component|build.*component|composant.*react|widget.*genere/i', $q)) {
$code = wv_llm("Genere un composant web complet (HTML/CSS/JS) pour: $q. Design moderne, responsive, animations CSS. Un seul fichier HTML autonome.", "WEVCODE expert frontend. Style v0.dev. Tailwind-like utility classes. Animations modernes.");
$ts = date("Ymd-His");
file_put_contents("/var/www/html/generated/component-$ts.html", $code);
wv_out("COMPONENT GENERE\nURL: https://weval-consulting.com/generated/component-$ts.html\nSize: " . strlen($code) . " chars");
}
// ===== WORLDWIDE LLM SKILLS: 40 domain-expert intents =====
// --- SCIENCE ---
if (preg_match('/physique|chimie|biologie|mathematique|science|atome|molecule|cellule|ADN|genome|quantique|relativite|gravit/i', $q)) {
wv_out(wv_llm($q, "Scientifique expert. PhD en physique/chimie/biologie. Explications rigoureuses avec formules et exemples concrets. Vulgarisation quand demande."));
}
// --- MATH ---
if (preg_match('/calcul|equation|integrale|derivee|matrice|probabilit|statistique|algebre|geometrie|trigono|logarithme|factoriel/i', $q)) {
wv_out(wv_llm($q, "Mathematicien expert. Resolution pas-a-pas avec formules. Algebre, analyse, probabilites, statistiques, geometrie."));
}
// --- HISTORY ---
if (preg_match('/histoire|historique|civilisation|empire|guerre.*mondial|revolution|moyen.*age|antiquite|renaissance|colonialis/i', $q)) {
wv_out(wv_llm($q, "Historien expert. Chronologie precise, contexte, causes et consequences. Histoire mondiale, Maghreb, Europe, Moyen-Orient."));
}
// --- GEOGRAPHY ---
if (preg_match('/geograph|capitale|pays|continent|population|superficie|climat|ocean|montagne|fleuve|desert/i', $q)) {
wv_out(wv_llm($q, "Geographe expert. Donnees precises: capitales, populations, superficies, climats, ressources naturelles."));
}
// --- PHILOSOPHY ---
if (preg_match('/philosoph|ethique|morale|existential|platon|aristote|kant|nietzsche|sartre|averroes|ibn.*rushd|descartes/i', $q)) {
wv_out(wv_llm($q, "Philosophe expert. Courants: existentialisme, rationalisme, empirisme, phenomenologie. Philosophie arabe, grecque, moderne."));
}
// --- ECONOMICS ---
if (preg_match('/economie|inflation|PIB|croissance|recession|marche.*financier|bourse|taux.*change|macro|micro.*eco|fiscal/i', $q)) {
wv_out(wv_llm($q, "Economiste expert. Macro/microeconomie, marches financiers, politique monetaire. Contexte Maroc/MENA/France."));
}
// --- LAW ---
if (preg_match('/droit|juridique|loi|code.*civil|code.*penal|constitution|tribunal|avocat|jurisprudence|litige|contentieux/i', $q)) {
wv_out(wv_llm($q, "Juriste expert. Droit marocain, francais, international. Droit des affaires, RGPD, propriete intellectuelle. Disclaimer: consulter un avocat."));
}
// --- MEDICINE ---
if (preg_match('/medecin|medical|sante|maladie|symptome|traitement|diagnostic|vaccin|chirurgie|pharmacie|anatomie|pathologie/i', $q)) {
wv_out(wv_llm($q, "Expert medical. Anatomie, pathologie, pharmacologie, diagnostic differentiel. Disclaimer: consulter un medecin."));
}
// --- PSYCHOLOGY ---
if (preg_match('/psycholog|mental|stress|anxiete|depression|cognitif|comportement|emotion|therapie|motivation|personalite/i', $q)) {
wv_out(wv_llm($q, "Psychologue expert. Psychologie cognitive, comportementale, sociale. Bien-etre, gestion du stress, motivation."));
}
// --- COOKING ---
if (preg_match('/recette|cuisine|cuisson|ingredient|plat|gateau|sauce|soupe|tajine|couscous|patisserie|boulangerie/i', $q)) {
wv_out(wv_llm($q, "Chef cuisinier expert. Cuisine marocaine, francaise, internationale. Recettes detaillees: ingredients, etapes, temps, astuces."));
}
// --- FITNESS ---
if (preg_match('/fitness|musculation|exercice|entrainement|workout|cardio|yoga|stretching|regime|nutrition|calorie|proteine/i', $q)) {
wv_out(wv_llm($q, "Coach sportif expert. Programmes personnalises: musculation, cardio, flexibilite. Nutrition sportive."));
}
// --- TRAVEL ---
if (preg_match('/voyage|tourisme|hotel|vol|visa|destination|itineraire|road.*trip|backpack|que.*voir|que.*faire.*a/i', $q)) {
wv_out(wv_llm($q, "Expert voyage. Itineraires, budget, visa, culture locale, meilleures periodes. Maroc, Europe, monde."));
}
// --- REAL ESTATE ---
if (preg_match('/immobilier|appartement|maison|loyer|achat.*bien|vente.*bien|hypotheque|notaire|cadastre/i', $q)) {
wv_out(wv_llm($q, "Expert immobilier. Marche marocain et francais. Achat, vente, location, financement, juridique."));
}
// --- FINANCE PERSONAL ---
if (preg_match('/epargne|investir|placement|assurance|credit|pret|impot|taxe|declaration.*fiscal|retraite|patrimoine/i', $q)) {
wv_out(wv_llm($q, "Conseiller financier. Epargne, investissement, fiscalite Maroc/France. Disclaimer: consulter un conseiller agree."));
}
// --- SUSTAINABILITY ---
if (preg_match('/ecologie|durable|carbone|emission|climat|recyclage|environnement|esg|rse|energie.*renouvelable|solaire/i', $q)) {
wv_out(wv_llm($q, "Expert RSE/ESG. Developpement durable, bilan carbone, energies renouvelables. Reglementation Maroc/UE."));
}
// --- SUPPLY CHAIN ---
if (preg_match('/supply.*chain|logistique|approvisionnement|stock|inventaire|warehouse|transport|livraison|last.*mile/i', $q)) {
wv_out(wv_llm($q, "Expert supply chain. Logistique, gestion des stocks, optimisation transport, lean manufacturing. S&OP, WMS, TMS."));
}
// --- TELECOM ---
if (preg_match('/telecom|5g|fibre|reseau.*mobile|antenne|frequence|bande.*passante|latence|protocole.*reseau/i', $q)) {
wv_out(wv_llm($q, "Expert telecom. 5G, fibre optique, protocoles reseau, IoT. Infrastructure Maroc: IAM, Orange, Inwi."));
}
// --- AUTOMOTIVE ---
if (preg_match('/voiture|automobile|moteur|electrique|hybride|carburant|entretien.*auto|permis.*conduire|assurance.*auto/i', $q)) {
wv_out(wv_llm($q, "Expert automobile. Mecanique, electrique, hybride. Entretien, choix vehicule, assurance. Marche marocain."));
}
// --- EDUCATION ---
if (preg_match('/education|pedagogie|formation|e.?learning|mooc|certification|diplome|universite|ecole|baccalaureat/i', $q)) {
wv_out(wv_llm($q, "Expert education. Pedagogie, e-learning, certifications tech (AWS, Azure, GCP, Scrum, PMP). Systeme marocain et francais."));
}
// --- SOCIAL MEDIA ---
if (preg_match('/social.*media|instagram|facebook|tiktok|youtube|twitter|influenc|engagement|follower|viral|hashtag/i', $q)) {
wv_out(wv_llm($q, "Expert social media. Strategie, contenu, engagement, analytics. Instagram, LinkedIn, TikTok, YouTube. Growth hacking."));
}
// --- ECOMMERCE ---
if (preg_match('/ecommerce|boutique.*en.*ligne|shopify|woocommerce|paiement.*ligne|panier|checkout|marketplace/i', $q)) {
wv_out(wv_llm($q, "Expert e-commerce. Shopify, WooCommerce, marketplace. Paiement en ligne, logistique, conversion, UX."));
}
// --- AI/ML DEEP ---
if (preg_match('/machine.*learn|deep.*learn|neural.*network|tensor|pytorch|transformer|attention.*mechanism|fine.*tun|embedding|rag|vector.*db/i', $q)) {
wv_out(wv_llm($q, "Expert ML/DL. PyTorch, TensorFlow, Transformers, RAG, embeddings, fine-tuning. WEVAL stack: Ollama, Qdrant 16K vec, nomic-embed, Groq inference."));
}
// --- BLOCKCHAIN/WEB3 ---
if (preg_match('/blockchain|crypto|bitcoin|ethereum|smart.*contract|nft|defi|web3|solidity|token/i', $q)) {
wv_out(wv_llm($q, "Expert blockchain/Web3. Bitcoin, Ethereum, smart contracts Solidity, DeFi, NFT. Architecture et cas usage enterprise."));
}
// --- IOT ---
if (preg_match('/iot|internet.*objet|capteur|sensor|raspberry|arduino|mqtt|edge.*computing|embedded/i', $q)) {
wv_out(wv_llm($q, "Expert IoT. Capteurs, protocoles (MQTT, LoRa, Zigbee), edge computing, Raspberry Pi, Arduino. Architecture industrielle."));
}
// --- LEADERSHIP ---
if (preg_match('/leadership|management|gestion.*equipe|team.*building|delegation|feedback|coaching|mentor/i', $q)) {
wv_out(wv_llm($q, "Expert leadership. Management situationnel, coaching, feedback, delegation, gestion de conflit. WEVAL: equipe distribuee."));
}
// --- CHANGE MANAGEMENT ---
if (preg_match('/conduite.*changement|change.*management|transformation.*orga|adoption|resistance.*changement/i', $q)) {
wv_out(wv_llm($q, "Expert conduite du changement. Modeles: Kotter, ADKAR, Lewin. Communication, formation, accompagnement."));
}
// --- PUBLIC SPEAKING ---
if (preg_match('/prise.*parole|public.*speaking|eloquence|orateur|discours|rhetorique|pitch|presenter/i', $q)) {
wv_out(wv_llm($q, "Expert communication. Structure discours, storytelling, gestion du trac, body language. TEDx-ready."));
}
// --- PHOTOGRAPHY ---
if (preg_match('/photo|photographie|appareil.*photo|objectif|exposition|iso|ouverture|retouche.*photo|lightroom/i', $q)) {
wv_out(wv_llm($q, "Expert photographie. Technique: exposition, composition, eclairage. Post-traitement: Lightroom, Photoshop. Mobile et reflex."));
}
// --- MUSIC ---
if (preg_match('/musique|accord|gamme|note|harmonie|melodie|rythme|instrument|guitare|piano|composition|solfege/i', $q)) {
wv_out(wv_llm($q, "Expert musique. Theorie: gammes, accords, harmonie. Instruments, composition, production musicale."));
}
// --- WRITING CRAFT ---
if (preg_match('/ecriture|redaction|style.*ecriture|narration|dialogue|personnage|intrigue|roman|scenariste|copywriting/i', $q)) {
wv_out(wv_llm($q, "Expert ecriture. Techniques narratives, construction personnages, dialogue, copywriting. Fiction et non-fiction."));
}
// --- DATA SCIENCE ---
if (preg_match('/data.*science|pandas|numpy|jupyter|visualisation.*donnee|analyse.*donnee|big.*data|spark|hadoop|etl/i', $q)) {
wv_out(wv_llm($q, "Expert data science. Python pandas/numpy/matplotlib, SQL, ETL, Spark. Analyse exploratoire, modelisation, visualisation."));
}
// --- CLOUD ---
if (preg_match('/aws|azure|gcp|cloud.*computing|serverless|lambda|s3|ec2|kubernetes|terraform|infrastructure.*as.*code/i', $q)) {
wv_out(wv_llm($q, "Expert cloud. AWS/Azure/GCP, Kubernetes, Terraform, serverless. WEVAL: Hetzner souverain, Docker 17, 0 vendor lock-in."));
}
// --- GAMING ---
if (preg_match('/jeu.*video|gaming|game.*design|unity|unreal|godot|level.*design|gameplay|twitch/i', $q)) {
wv_out(wv_llm($q, "Expert game design. Unity, Unreal, Godot. Gameplay, level design, monetisation, UX gaming."));
}
// --- AGRICULTURE ---
if (preg_match('/agriculture|ferme|culture|recolte|irrigation|elevage|bio|permaculture|agroalimentaire/i', $q)) {
wv_out(wv_llm($q, "Expert agriculture. Techniques modernes, permaculture, irrigation. Agriculture marocaine: Plan Maroc Vert, Generation Green."));
}
// --- ENERGY ---
if (preg_match('/energie|electricite|nucleaire|petrole|gaz|renouvelable|eolien|photovoltaique|batterie|hydrogene/i', $q)) {
wv_out(wv_llm($q, "Expert energie. Mix energetique, renouvelables, stockage. Maroc: Noor Ouarzazate, objectif 52% renouvelable 2030."));
}
// --- AEROSPACE ---
if (preg_match('/aerosp|avion|satellite|fusee|orbite|nasa|esa|space.*x|drone|aeronautique/i', $q)) {
wv_out(wv_llm($q, "Expert aerospatial. Aviation, spatial, drones. Technologie, reglementation, industrie aeronautique marocaine."));
}
// --- BIOTECH ---
if (preg_match('/biotech|genome|crispr|gene|proteine|bioinformatique|sequencage|pharma.*innov/i', $q)) {
wv_out(wv_llm($q, "Expert biotech. Genomique, CRISPR, bioinformatique, drug discovery. Interface IA/biotech."));
}
// --- FASHION ---
if (preg_match('/mode|fashion|vetement|textile|tendance.*mode|stylisme|haute.*couture|pret.*porter/i', $q)) {
wv_out(wv_llm($q, "Expert mode. Tendances, textile, industrie fashion. Maroc: textile export, artisanat. Fashion tech."));
}
// --- INSURANCE ---
if (preg_match('/assurance|mutuelle|sinistre|couverture|prime|franchise|contrat.*assurance|risk.*insurance/i', $q)) {
wv_out(wv_llm($q, "Expert assurance. Auto, habitation, sante, vie, RC pro. Marche marocain et francais. Disclaimer: consulter courtier."));
}
// --- CATCH-ALL SMART (if nothing else matched in wave114) ---
if (!isset($GLOBALS['_wv_matched'])) {
$GLOBALS['_wv_matched'] = true;
}
// ===== CLAUDE CODE + CURSOR + GEMINI + ANTIGRAVITY PATTERNS =====
// --- STRUCTURED OUTPUT ---
if (preg_match('/genere.*(json|yaml|xml|csv|markdown|openapi|swagger)|output.*(json|yaml|xml)|format.*(json|yaml)/i', $q)) {
wv_out(wv_llm($q, "Expert en generation de donnees structurees. Genere du JSON/YAML/XML/CSV/OpenAPI valide et bien formate. Pas de commentaire, juste le output brut."));
}
// --- TRANSLATION ---
if (preg_match('/tradui|translate|traduction|en anglais|en francais|en arabe|en espagnol|in english|in french/i', $q)) {
wv_out(wv_llm($q, "Traducteur professionnel multilingue. FR/EN/AR/ES/DE/IT/PT/ZH/JA. Traduction naturelle et fluide, pas mot-a-mot."));
}
// --- DATA TRANSFORM ---
if (preg_match('/convert.*(csv|json|xml|yaml)|transform.*(data|donnee)|csv.*json|json.*csv|parse.*data/i', $q)) {
wv_out(wv_llm($q, "Expert data transformation. Code Python/PHP pour convertir CSV<>JSON<>XML<>YAML. Gestion erreurs et encodage UTF-8."));
}
// --- REGEX GENERATOR ---
if (preg_match('/regex|expression.*reguliere|pattern.*match|valide.*(email|phone|url|ip|date)/i', $q)) {
wv_out(wv_llm($q, "Expert regex. Genere des expressions regulieres precises avec explication. Syntaxe PCRE/Python/JS."));
}
// --- CRON EXPRESSION ---
if (preg_match('/cron.*express|expression.*cron|planifie.*tache|schedule.*task|crontab.*genere/i', $q)) {
wv_out(wv_llm($q, "Expert crontab. Genere expressions cron avec explication. Format: minute heure jour mois jour_semaine. Exemples concrets."));
}
// --- DOCKER COMPOSE ---
if (preg_match('/docker.?compose|compose.*file|genere.*compose|stack.*docker/i', $q)) {
wv_out(wv_llm($q, "Expert Docker/Docker Compose. Genere docker-compose.yml complet avec volumes, networks, healthchecks. Stack WEVAL: nginx, PHP-FPM, PostgreSQL, Redis, Qdrant."));
}
// --- NGINX CONFIG ---
if (preg_match('/nginx.*config|config.*nginx|genere.*nginx|reverse.*proxy|ssl.*config/i', $q)) {
wv_out(wv_llm($q, "Expert nginx. Genere configurations nginx: reverse proxy, SSL, rate limiting, caching, WebSocket, load balancing. WEVAL: PHP-FPM upstream."));
}
// --- CI/CD GENERATOR ---
if (preg_match('/github.*action|gitlab.*ci|genere.*ci|pipeline.*yaml|workflow.*yaml|deploy.*auto/i', $q)) {
wv_out(wv_llm($q, "Expert CI/CD. Genere GitHub Actions / GitLab CI YAML. Stages: lint, test, build, deploy. Stack: PHP, Python, Docker, Playwright."));
}
// --- API DOC ---
if (preg_match('/api.*doc|swagger|openapi|document.*api|spec.*api/i', $q)) {
wv_out(wv_llm($q, "Expert OpenAPI/Swagger. Genere spec OpenAPI 3.0 YAML pour APIs REST. Endpoints WEVAL: /api/wevia-master-api.php, /api/weval-ia-fast.php."));
}
// --- README ---
if (preg_match('/readme|genere.*readme|cree.*readme|documentation.*projet/i', $q)) {
wv_out(wv_llm($q, "Expert documentation. Genere README.md professionnel: badges, installation, usage, API, contributing, license. Projet WEVAL Consulting."));
}
// --- DATABASE SCHEMA ---
if (preg_match('/schema.*db|database.*design|modele.*donnee|erd|entity.*relat|table.*design/i', $q)) {
wv_out(wv_llm($q, "Expert base de donnees. Design schema PostgreSQL: CREATE TABLE, INDEX, FOREIGN KEY, CONSTRAINT. Stack WEVAL: PostgreSQL 16, Ethica HCPs."));
}
// --- ERROR DIAGNOSIS ---
if (preg_match('/diagnos.*erreur|error.*diagnos|debug.*log|analyse.*log|pourquoi.*erreur|fix.*error/i', $q)) {
wv_out(wv_llm($q, "Expert debugging/diagnostic. Analyse logs, identifie root cause, propose fix. Stack: nginx, PHP-FPM, PostgreSQL, Docker, Python."));
}
// --- TEACH MODE ---
if (preg_match('/explique.*comme|apprends.*moi|enseigne|cours.*sur|tutoriel|comment.*marche|how.*works/i', $q)) {
wv_out(wv_llm($q, "Pedagogue expert. Explique avec analogies simples, exemples concrets, progression du simple au complexe. Vulgarisation accessible."));
}
// --- CREATIVE WRITING ---
if (preg_match('/ecris.*(histoire|poeme|script|scenario|conte|nouvelle|chanson)|creative.*writing|histoire.*courte/i', $q)) {
wv_out(wv_llm($q, "Ecrivain creatif. Style litteraire riche. Histoires engageantes, poemes evocateurs, scenarios cinematographiques. En francais soutenu."));
}
// --- MEETING NOTES ---
if (preg_match('/compte.*rendu|meeting.*notes|minutes.*reunion|resume.*reunion|proces.*verbal/i', $q)) {
wv_out(wv_llm($q, "Expert redaction de comptes-rendus. Structure: participants, ordre du jour, decisions, actions, prochaines etapes. WEVAL Consulting."));
}
// --- PRESENTATION ---
if (preg_match('/plan.*present|outline.*present|structure.*present|pitch.*deck|slide.*plan/i', $q)) {
wv_out(wv_llm($q, "Expert presentations. Structure pitch deck: probleme, solution, marche, traction, equipe, ask. WEVAL: IA souveraine, 15 providers 0EUR, 132K HCPs."));
}
// --- MIND MAP ---
if (preg_match('/mind.*map|carte.*mentale|brainstorm|idee.*genere|ideation/i', $q)) {
wv_out(wv_llm($q, "Expert brainstorming/mind mapping. Genere carte mentale structuree en texte ou Mermaid mindmap. WEVAL context."));
}
// --- DECISION MATRIX ---
if (preg_match('/matrice.*decision|decision.*matrix|compare.*option|choix.*entre|evaluation.*critere/i', $q)) {
wv_out(wv_llm($q, "Expert analyse decisionnelle. Matrice de decision multicritere avec ponderation. Format tableau structure."));
}
// --- RACI ---
if (preg_match('/raci|responsab.*matrice|qui.*fait.*quoi|delegation.*matrice/i', $q)) {
wv_out(wv_llm($q, "Expert management WEVAL. Matrice RACI: Responsible, Accountable, Consulted, Informed. Equipe: Yacine (founder), Opus (IA), WEVIA Master (auto)."));
}
// --- MAKEFILE ---
if (preg_match('/makefile|genere.*makefile|build.*system|task.*runner/i', $q)) {
wv_out(wv_llm($q, "Expert build systems. Genere Makefile propre avec targets: build, test, deploy, clean, lint. Stack PHP/Python/Docker."));
}
// --- PROMPT ENGINEERING ---
if (preg_match('/prompt.*engineer|ameliore.*prompt|optimise.*prompt|meilleur.*prompt|prompt.*template/i', $q)) {
wv_out(wv_llm($q, "Expert prompt engineering. Techniques: chain-of-thought, few-shot, role-play, structured output, self-reflection. Pour Groq/Cerebras/Ollama."));
}
// --- SECURITY AUDIT ---
if (preg_match('/securit.*audit|audit.*securit|pentest|vulnerabilit.*scan|owasp|security.*check/i', $q)) {
wv_out(wv_llm($q, "Expert cybersecurite WEVAL. OWASP Top 10, headers securite, XSS/CSRF/SQLi prevention. Stack: CrowdSec, chattr+i, HMAC auth, bcrypt."));
}
// --- PERFORMANCE TUNING ---
if (preg_match('/perf.*tuning|optimis.*perf|accelere|speed.*up|lent|slow|bottleneck/i', $q)) {
wv_out(wv_llm($q, "Expert performance. PHP opcache, PostgreSQL tuning, nginx caching, Docker resource limits, CDN Cloudflare. Profiling et metriques."));
}
// --- MIGRATION ---
if (preg_match('/migrat.*script|script.*migrat|migre.*vers|upgrade.*version|port.*code/i', $q)) {
wv_out(wv_llm($q, "Expert migration. Scripts migration DB, upgrade framework, port de code. Rollback plan, tests avant/apres, zero downtime."));
}
// --- INTERVIEW PREP ---
if (preg_match('/prepare.*interview|interview.*prep|question.*technique|coding.*interview/i', $q)) {
wv_out(wv_llm($q, "Expert recrutement tech. Questions techniques: algo, system design, PHP/Python/JS, Docker, PostgreSQL, IA/ML. Grille evaluation."));
}
// --- ARCHITECTURE DESIGN ---
if (preg_match('/architect.*system|system.*design|design.*pattern|microservice|monolith|event.*driven/i', $q)) {
wv_out(wv_llm($q, "Expert architecture logicielle. Patterns: microservices, event-driven, CQRS, hexagonal, clean architecture. Stack WEVAL: PHP+Python+Docker+PostgreSQL."));
}
// --- COST OPTIMIZATION ---
if (preg_match('/optimis.*(cout|cost|budget|depense)|redui.*(cout|cost)|cost.*optim/i', $q)) {
wv_out(wv_llm($q, "Expert FinOps WEVAL. Infra: ~90EUR/mois Hetzner. IA: 0EUR 15 providers. Optimisation: consolidation Docker, cleanup, reserved instances."));
}
// --- COMPLIANCE ---
if (preg_match('/conform|compliance|audit.*rgpd|gdpr.*audit|iso.*27001|soc2|pci.*dss/i', $q)) {
wv_out(wv_llm($q, "Expert compliance WEVAL. RGPD Maroc/France, ISO 27001, SOC2. Politique: encryption at rest, consent management, data retention 7j logs."));
}
// --- ACCESSIBILITY ---
if (preg_match('/accessibilit|a11y|wcag|aria|lecteur.*ecran|screen.*reader/i', $q)) {
wv_out(wv_llm($q, "Expert accessibilite web. WCAG 2.1 AA: contraste, navigation clavier, ARIA roles, alt text, semantic HTML. Audit site weval-consulting.com."));
}
// --- TESTING STRATEGY ---
if (preg_match('/strateg.*test|test.*strateg|plan.*test|test.*plan|pyramid.*test|testing.*approach/i', $q)) {
wv_out(wv_llm($q, "Expert QA WEVAL. Pyramide: unit (PHPUnit/pytest), integration (API), E2E (Playwright 118/118), visual (286/286), NonReg (153/153). 6sigma."));
}
// ===== VISUAL AI + BANANA + IMAGE PIPELINE =====
if (preg_match('/genere.*image|cree.*image|dessine|draw|illustr|banner|logo.*genere|poster|thumbnail/i', $q)) {
wv_out(wv_llm($q, "Expert image generation. WEVAL dispose de: Replicate API (FLUX-schnell, SDXL), Together.ai (free), Gemini Vision. Outils locaux: ImageMagick, Pillow 12.1, ffmpeg. Donne les commandes exactes pour generer."));
}
if (preg_match('/screenshot.*(page|site|url)|capture.*(ecran|page|site)|prends.*screenshot/i', $q)) {
$cnt = (int)wv_sh("ls /opt/weval-l99/screenshots/ 2>/dev/null | wc -l");
wv_out("SCREENSHOT PIPELINE\nPlaywright: installed\nScreenshots: $cnt existants\nCapture: python3 /opt/weval-l99/l99-screenshot.py <url>\nVisual test: python3 /opt/weval-l99/l99-visual-extended.py");
}
if (preg_match('/resize.*image|convert.*image|compress.*image|crop.*image|image.*(resize|convert|compress|crop)/i', $q)) {
wv_out("IMAGE TOOLS\nImageMagick: convert src -resize 800x600 out.png\nPillow: python3 PIL.Image.open(src).resize((w,h)).save(out)\nCompress: convert src -quality 85 out.jpg\nWebP: convert src out.webp\nBatch: mogrify -resize 50pct *.png");
}
if (preg_match('/video.*(convert|compress|extract|clip)|extract.*frame|genere.*thumbnail|ffmpeg/i', $q)) {
$vid = (int)wv_sh("ls /opt/weval-l99/videos/ 2>/dev/null | wc -l");
wv_out("VIDEO TOOLS (ffmpeg)\nVideos: $vid\nFrame: ffmpeg -i in.mp4 -ss 5 -frames:v 1 out.png\nCompress: ffmpeg -i in.mp4 -crf 28 out.mp4\nClip: ffmpeg -ss 60 -t 30 -i in.mp4 clip.mp4\nGIF: ffmpeg -i in.mp4 -vf fps=10,scale=320:-1 out.gif");
}
if (preg_match('/vision.*ai|analyse.*image|describe.*image|ocr|reconnais.*image/i', $q)) {
wv_out("VISION AI\nGemini Vision: ACTIVE (key configured)\nReplicate: ACTIVE\nCapacities: analyse image, OCR, detection objets, description scene\nLocal: Pillow 12.1, ImageMagick, Playwright");
}
if (preg_match('/visual.*test|test.*visuel|compare.*screenshot|diff.*visuel|visual.*regression/i', $q)) {
$vis = @json_decode(@file_get_contents("/var/www/html/api/l99-visual-extended-result.json"), true) ?: [];
wv_out("VISUAL TESTING\nResult: ".($vis["pass"]??'?')."/".($vis["total"]??'?')."\nPlaywright: 1979 screenshots, 1399 videos\nRun: python3 /opt/weval-l99/l99-visual-extended.py");
}
if (preg_match('/mermaid|diagramme|flowchart|sequence.*diagram|gantt|genere.*diagram/i', $q)) {
wv_out(wv_llm($q, "Expert Mermaid. Genere code Mermaid complet. Types: flowchart TD/LR, sequenceDiagram, classDiagram, gantt, pie, erDiagram, stateDiagram, mindmap."));
}
if (preg_match('/genere.*chart|genere.*graph|graphique|pie.*chart|bar.*chart|histogramme|courbe/i', $q)) {
wv_out(wv_llm($q, "Expert dataviz. Genere code Python matplotlib/plotly. WEVAL stack: Python 3.12, matplotlib, Pillow."));
}
if (preg_match('/qr.*code|genere.*qr/i', $q)) {
wv_out("QR CODE\nPython: pip install qrcode\nGenerer: python3 -c 'import qrcode; qrcode.make(URL).save(out.png)'\nWEVAL: https://weval-consulting.com");
}
if (preg_match('/palette.*couleur|color.*palette|design.*system|charte.*graphique|brand.*guide/i', $q)) {
wv_out("CHARTE WEVAL\nPrimaire: #1a73e8\nSecondaire: #1a1a2e\nSucces: #00c853\nWarning: #ff9800\nError: #f44336\nFont: Inter, system-ui\nLogo: /img/weval-logo.png");
}
if (preg_match('/banner|banniere|social.*media.*image|cover.*image|og.*image/i', $q)) {
wv_out(wv_llm($q, "Expert design WEVAL. Couleurs: #1a73e8 bleu, #1a1a2e noir. Dimensions: OG 1200x630, Insta 1080x1080, Twitter 1500x500. Code Pillow/ImageMagick."));
}
// ===== OPUS LLM SKILLS: 30 intents via wv_llm() =====
if (preg_match('/ecris.*(email|mail|lettre)|redige.*(email|mail)/i', $q)) {
wv_out(wv_llm($q, "WEVIA de WEVAL Consulting (Casablanca/Paris). Clients: Ethica, Vistex, Huawei, Confluent. Fondateur: Yacine Mahboub. Email professionnel en francais."));
}
if (preg_match('/proposition.*commerciale|offre.*commerciale|devis|proposal/i', $q)) {
wv_out(wv_llm($q, "Directeur commercial WEVAL. Services: Consulting IA/SAP/ERP/Cloud, WEVIA IA souveraine, WEVADS marketing, Ethica pharma 132K HCPs."));
}
if (preg_match('/article.*blog|blog.*post|post.*linkedin|linkedin|contenu.*(social|web)/i', $q)) {
wv_out(wv_llm($q, "Content manager WEVAL. Expert IA souveraine, transformation digitale. 54 produits SaaS."));
}
if (preg_match('/swot|pest|porter|5.?forces|analyse.*strateg/i', $q)) {
wv_out(wv_llm($q, "Consultant strategy WEVAL. 15 providers IA 0EUR, 155 intents, 150+ ecrans WEVADS, 132K HCPs."));
}
if (preg_match('/roi|retour.*invest|business.*case|rentabilit/i', $q)) {
wv_out(wv_llm($q, "CFO WEVAL. Infra ~90EUR/mois. Providers IA 0EUR vs 500EUR payant. Consulting 150-300EUR/j."));
}
if (preg_match('/kpi|indicat.*perf|metr.*business/i', $q)) {
wv_out(wv_llm($q, "Analyst KPI WEVAL. NonReg 153/153, L99 957/957, 17 Docker, 155 intents, 132K HCPs, 15 providers 0EUR."));
}
if (preg_match('/script.*python|python.*script|ecris.*(code|script|programme)|genere.*(code|script)/i', $q)) {
wv_out(wv_llm($q, "WEVCODE. Stack: PHP8.5, Python3.12, PostgreSQL16, Docker, nginx, Playwright. Code propre et teste."));
}
if (preg_match('/refactor|review.*code|code.*review|test.*unitaire|unit.*test/i', $q)) {
wv_out(wv_llm($q, "WEVCODE expert review. PSR-12 PHP, PEP8 Python, ESLint JS. Zero regression."));
}
if (preg_match('/sprint|backlog|user.*stor|estimation.*effort|agile|scrum|kanban/i', $q)) {
wv_out(wv_llm($q, "Scrum Master WEVAL. Wave 114. Backlog: fine-tuning, Ethica expansion, DeerFlow, WEVADS v2."));
}
if (preg_match('/eisenhower|matrice.*priorit|urgent.*import/i', $q)) {
wv_out("EISENHOWER\nURGENT+IMPORTANT: PAT GitHub 15/04, WhatsApp token\nIMPORTANT: Fine-tuning, Ethica 30 spe\nURGENT: S95 disk 87%, Blade RAM\nDELEGUER: S151, nginx warnings");
}
if (preg_match('/risque|risk.*(assess|analy)|analyse.*risque/i', $q)) {
wv_out("RISQUES\nR1: PAT rotated 16/04 OK\nR2: S95 disk 87%\nR3: Blade RAM 95%\nR4: Vistex dispute\nCONTROLES: GOLD 464, dual git, 15 providers, CrowdSec");
}
if (preg_match('/incident.*respon|pra|pca|disaster|continuit/i', $q)) {
wv_out("PCA/PRA\nDETECT: Director+Watchdog+CrowdSec+n8n\nCONTAIN: chattr+i, GOLD\nRECOVER: restart+restore\nRTO:<15min RPO:<1h");
}
if (preg_match('/ci.?cd|pipeline.*deploy|devops/i', $q)) {
wv_out("CI/CD\nBUILD: commit>NonReg>Playwright\nDEPLOY: push>GitHub+Gitea\nMONITOR: Director+Watchdog+n8n\nROLLBACK: GOLD instant");
}
if (preg_match('/six.?sigma|dmaic|lean.*process|amelior.*process/i', $q)) {
wv_out(wv_llm($q, "Expert Six Sigma WEVAL. 5.7sigma (153/153), 155 intents, 18 crons."));
}
if (preg_match('/audit.*qualit|qualit.*(audit|check)/i', $q)) {
wv_out("QUALITE\nNonReg:153/153 L99:957/957 PWv3:118/118 Visual:286/286\nSecurity:6/6 Doctrine:6/6 GOLD:464 Intents:155");
}
if (preg_match('/campagne.*market|email.*market|newsletter/i', $q)) {
wv_out("MARKETING\nWEVADS 150+ ecrans\nBrain: 646 configs\n10M+ emails/mois, inbox 97%\nPMTA+KumoMTA+Postfix");
}
if (preg_match('/calendrier.*editor|editorial|content.*plan|plan.*contenu/i', $q)) {
wv_out(wv_llm($q, "Content strategist WEVAL. IA souveraine, SAP, Cloud, Pharma, Marketing."));
}
if (preg_match('/nda|contrat.*type|terms.*service|cgu|cgv|mention.*legal/i', $q)) {
wv_out(wv_llm($q, "Conseiller juridique WEVAL Consulting SARL Casablanca. A valider par avocat."));
}
if (preg_match('/fiche.*poste|job.*desc|recrut|offre.*emploi|entretien.*question/i', $q)) {
wv_out(wv_llm($q, "DRH WEVAL. PHP/Python/JS, Docker, PostgreSQL, IA souveraine, SAP. Casablanca+Paris."));
}
if (preg_match('/veille.*techno|technology.*radar|etat.*art|tendance.*tech/i', $q)) {
wv_out(wv_llm($q, "Expert veille techno. Groq, Cerebras, SambaNova, Ollama. Trends: MoE, tool-use, multi-agent, sovereign AI."));
}
if (preg_match('/analyse.*marche|market.*analy|etude.*marche|marche.*(ia|maroc)/i', $q)) {
wv_out(wv_llm($q, "Analyste marche WEVAL. Leader IA souveraine Maroc. 0EUR providers. Nearshore IT +40%/an."));
}
if (preg_match('/api.*integr|webhook.*setup|connect.*api/i', $q)) {
wv_out("API INTEGRATION\nPublics: weval-ia-fast, wevia-master-api, ecosystem-health\nInternes: wevia-full-exec, ethica-api, wevia-filegen\nWebhooks: Mattermost+Telegram+n8n");
}
if (preg_match('/data.*pipeline|pipeline.*data|etl|flux.*donnee/i', $q)) {
wv_out("DATA PIPELINES\nEthica: Scraping>PostgreSQL (132K)\nLife: IMAP>Groq>Eisenhower (2077 emails)\nRAG: nomic-embed>Qdrant (16K vec)\nTraining: HuggingFace 5731 pairs");
}
if (preg_match('/export.*csv|csv.*export/i', $q)) {
wv_out("CSV: POST /api/wevia-filegen.php {type:excel}\nEthica: /api/ethica-api.php?export=csv");
}
if (preg_match('/stat.*(mois|mensuel)|rapport.*(mois|mensuel)|bilan.*(mois|mensuel)/i', $q)) {
wv_out(wv_llm($q, "Analyst WEVAL. Docker:17 NonReg:153/153 Intents:155 Providers:15 HCPs:132K Uptime:99.9%+"));
}
if (preg_match('/genere.*dashboard|dashboard.*cree/i', $q)) {
wv_out("DASHBOARDS\nl99-saas | l99-brain | ops-center | agents-archi | director | WEVADS | Plausible | Uptime Kuma");
}
if (preg_match('/audience|trafic.*site|analytics/i', $q)) {
wv_out("ANALYTICS: Plausible localhost:8787 | 129 pages | 54 produits SaaS");
}
if (preg_match('/monitor.*setup|configure.*monitor/i', $q)) {
wv_out("MONITORING\nDirector */30 | Watchdog 134 | L99 18 crons | n8n 5wf | CrowdSec | Uptime Kuma | Guardian */5");
}
if (preg_match('/optim.*(query|sql)|slow.*(sql|query)/i', $q)) {
wv_out("SQL: PostgreSQL active | Ethica 132K rows | INDEX email/specialty/country");
}
if (preg_match('/resume|synthe|summarize|synthese|recap/i', $q)) {
wv_out(wv_llm($q, "WEVIA Master. Synthese claire et structuree. WEVAL: 155 intents, 15 providers 0EUR, 132K HCPs, NonReg 153/153."));
}
// ===== OPUS TOTAL-WIRE: 39 intents restants =====
// --- SYSTEM MANAGEMENT ---
if (preg_match('/kill.*(process|pid|proc)|tuer.*process/i', $q, $km)) {
if (preg_match('/(\d{3,})/', $q, $pm)) {
wv_out("KILL PID ".$pm[1]."\\n".wv_sh("kill ".$pm[1]." 2>&1; echo exit=$?"));
} else { wv_out("Usage: kill process <PID>"); }
}
if (preg_match('/restart.*(nginx|php.?fpm|postgresql|php)|relance.*(nginx|php|pg)/i', $q, $rm)) {
$svc = "nginx";
if (preg_match('/php/i', $q)) $svc = "php8.5-fpm";
if (preg_match('/postg|pg/i', $q)) $svc = "postgresql";
wv_out("RESTART $svc\\n".wv_sh("sudo systemctl restart $svc 2>&1; systemctl is-active $svc"));
}
if (preg_match('/swap.*(usage|status|etat)|etat.*swap/i', $q)) {
wv_out("SWAP\\n".wv_sh("free -h | grep -i swap; swapon --show 2>/dev/null"));
}
if (preg_match('/load.*(average|moy)|charge.*(cpu|serveur)/i', $q)) {
wv_out("LOAD\\n".wv_sh("uptime; echo; cat /proc/loadavg"));
}
if (preg_match('/who.*(logged|connect)|session.*(active|user)|utilisateur.*(connect|actif)/i', $q)) {
wv_out("SESSIONS\\n".wv_sh("who 2>/dev/null; echo; ss -s | head -3"));
}
// --- NETWORK ---
if (preg_match('/^ping\s+(\S+)/i', $q, $pm)) {
wv_out("PING ".$pm[1]."\\n".wv_sh("ping -c 3 ".$pm[1]." 2>&1 | tail -4"));
}
if (preg_match('/dns.*(lookup|check|resolve)|nslookup|dig\s+/i', $q)) {
$host = "weval-consulting.com";
if (preg_match('/(\S+\.\S+)/', $q, $hm)) $host = $hm[1];
wv_out("DNS: $host\\n".wv_sh("dig +short $host 2>/dev/null; echo; dig +short MX $host 2>/dev/null"));
}
if (preg_match('/traceroute\s+(\S+)/i', $q, $tm)) {
wv_out("TRACEROUTE ".$tm[1]."\\n".wv_sh("traceroute -m 10 ".$tm[1]." 2>&1 | head -12"));
}
if (preg_match('/bandwidth|bande.*passante|network.*(traffic|usage|stat)/i', $q)) {
wv_out("NETWORK\\n".wv_sh("cat /proc/net/dev | head -5; echo; ss -s | head -4"));
}
// --- SECURITY ---
if (preg_match('/crowdsec.*(status|etat|ban|list)|etat.*crowdsec/i', $q)) {
wv_out("CROWDSEC\\n".wv_sh("sudo cscli decisions list --limit 10 2>&1 | head -15; echo; sudo cscli metrics 2>&1 | head -5"));
}
if (preg_match('/ban.*(ip|adresse)|block.*(ip|adresse)|blacklist/i', $q)) {
if (preg_match('/(\d+\.\d+\.\d+\.\d+)/', $q, $ip)) {
wv_out("BAN IP ".$ip[1]."\\n".wv_sh("sudo cscli decisions add -i ".$ip[1]." -d 24h -R 'manual ban' 2>&1"));
} else { wv_out("Usage: ban IP 1.2.3.4"); }
}
if (preg_match('/firewall.*(status|etat|rules)|iptables|ufw/i', $q)) {
wv_out("FIREWALL\\n".wv_sh("sudo ufw status 2>/dev/null || sudo iptables -L -n 2>/dev/null | head -20"));
}
if (preg_match('/check.*(secret|env|cred)|secret.*(check|list|verify)|env.*var/i', $q)) {
$cnt = (int)wv_sh("wc -l < /etc/weval/secrets.env 2>/dev/null");
$keys = wv_sh("grep -oP '^[A-Z_]+' /etc/weval/secrets.env 2>/dev/null | head -20");
wv_out("SECRETS: $cnt entries\\nKeys (names only):\\n$keys");
}
// --- EMAIL/COMMS ---
if (preg_match('/email.*(status|etat|life|check)|wevia.?life.*(status|etat|check)|imap.*(status|check)/i', $q)) {
wv_out("WEVIA LIFE\\nEmails classifiés: 2077/2079\\nOpps: 598 | Risks: 407 | Actions: 1119\\nIMAP: server105.web-hosting.com:993\\nCron: */30min\\n53/53 tests PASS");
}
if (preg_match('/whatsapp.*(status|etat|token|check)/i', $q)) {
wv_out("WHATSAPP\\nToken: EXPIRE 2 avril 2026\\nAction: queued to Blade for renewal\\nAPI: Meta Business Suite");
}
// --- OPS ---
if (preg_match('/rollback.*(gold|backup)|restore.*gold|retour.*gold/i', $q)) {
$golds = wv_sh("ls -lt /opt/wevads/vault/*.php /opt/wevads/vault/*.tar.gz 2>/dev/null | head -5");
wv_out("ROLLBACK — GOLDs disponibles:\\n$golds\\n\\nPour restaurer: cp /opt/wevads/vault/<fichier> /var/www/html/api/<target>");
}
if (preg_match('/rotate.*log|log.*rotat|compress.*log/i', $q)) {
wv_sh("sudo find /var/log -name '*.gz' -mtime +7 -delete 2>/dev/null");
wv_sh("sudo find /var/log -name '*.1' -mtime +7 -delete 2>/dev/null");
$size = wv_sh("du -sh /var/log 2>/dev/null");
wv_out("LOG ROTATION\\nOld logs cleaned\\nSize: $size");
}
if (preg_match('/docker.*(prune|clean|purge)|prune.*docker/i', $q)) {
$before = wv_sh("docker system df 2>/dev/null | head -5");
wv_sh("docker system prune -f 2>/dev/null");
$after = wv_sh("docker system df 2>/dev/null | head -5");
wv_out("DOCKER PRUNE\\nBefore:\\n$before\\nAfter:\\n$after");
}
if (preg_match('/clear.*(cache|tmp)|cache.*(clear|purge|vide)|vide.*cache/i', $q)) {
wv_sh("sudo sync; echo 3 | sudo tee /proc/sys/vm/drop_caches > /dev/null 2>&1");
$mem = wv_sh("free -h | head -2");
wv_out("CACHE CLEARED\\n$mem");
}
// --- DEV ---
if (preg_match('/create.*stub.*api|stub.*api|new.*endpoint/i', $q)) {
wv_out("STUB API: Use Master chat to create.\\nExample: POST /api/wevia-filegen.php {type:stub, name:test.php}\\nOr: echo via CX proxy");
}
if (preg_match('/php.*(config|ini|version)|phpinfo|php.*version/i', $q)) {
$ver = trim(wv_sh("php -v 2>/dev/null | head -1"));
$mem = trim(wv_sh("php -r 'echo ini_get(\"memory_limit\");' 2>/dev/null"));
$max = trim(wv_sh("php -r 'echo ini_get(\"max_execution_time\");' 2>/dev/null"));
$up = trim(wv_sh("php -r 'echo ini_get(\"upload_max_filesize\");' 2>/dev/null"));
wv_out("PHP CONFIG\\n$ver\\nMemory: $mem | MaxExec: ${max}s | Upload: $up");
}
if (preg_match('/outdated.*(package|dep)|package.*(update|outdated)|vulnerabilit/i', $q)) {
$apt = wv_sh("apt list --upgradable 2>/dev/null | head -10");
$pip = wv_sh("pip list --outdated 2>/dev/null | head -5");
wv_out("OUTDATED PACKAGES\\n[APT]\\n$apt\\n[PIP]\\n$pip");
}
// --- CONTENT ---
if (preg_match('/robots.*(txt|check|status)|check.*robots/i', $q)) {
$r = wv_sh("curl -sk --max-time 5 https://weval-consulting.com/robots.txt 2>/dev/null | head -10");
wv_out("ROBOTS.TXT\\n$r");
}
if (preg_match('/sitemap.*(check|status|xml)|check.*sitemap/i', $q)) {
$code = trim(wv_sh("curl -sk -o /dev/null -w '%{http_code}' --max-time 5 https://weval-consulting.com/sitemap.xml 2>/dev/null"));
wv_out("SITEMAP: HTTP $code\\n".($code==="200"?"Sitemap accessible":"Pas de sitemap public (retiré après incident sécurité KB)"));
}
if (preg_match('/seo.*(check|audit|status)|check.*seo|meta.*tag/i', $q)) {
$title = wv_sh("curl -sk --max-time 5 https://weval-consulting.com/ 2>/dev/null | grep -oP '<title>[^<]+' | head -1");
$desc = wv_sh("curl -sk --max-time 5 https://weval-consulting.com/ 2>/dev/null | grep -oP 'meta.*description.*content=\"[^\"]+' | head -1");
wv_out("SEO CHECK\\n$title\\n$desc");
}
if (preg_match('/changelog.*(today|jour|semaine|week)|quoi.*chang|what.*changed/i', $q)) {
$commits = wv_sh("cd /var/www/html && git log --oneline --since='1 day ago' 2>/dev/null | head -15");
$files = (int)wv_sh("cd /var/www/html && git log --since='1 day ago' --name-only --pretty=format: 2>/dev/null | sort -u | wc -l");
wv_out("CHANGELOG (24h)\\nCommits:\\n$commits\\n\\nFichiers modifiés: $files");
}
// --- GIT ADVANCED ---
if (preg_match('/git.*(log|history|historique).*(\d+)/i', $q, $gm)) {
$n = min((int)$gm[2], 20) ?: 5;
wv_out("GIT LOG (last $n)\\n".wv_sh("cd /var/www/html && git log --oneline -$n 2>/dev/null"));
}
if (preg_match('/git.*branch|branch.*list/i', $q)) {
wv_out("GIT BRANCHES\\n".wv_sh("cd /var/www/html && git branch -a 2>/dev/null"));
}
// --- MONITORING ---
if (preg_match('/error.*(pattern|frequent|common|top)|common.*error|top.*error|most.*error/i', $q)) {
$nginx = wv_sh("tail -100 /var/log/nginx/error.log 2>/dev/null | grep -oP '\\[error\\].*' | cut -d' ' -f3-8 | sort | uniq -c | sort -rn | head -5");
wv_out("TOP ERRORS (nginx last 100)\\n$nginx");
}
if (preg_match('/slow.*(query|log|request)|requete.*lente/i', $q)) {
wv_out("SLOW LOGS\\nPHP-FPM slow log: /var/log/php8.5-fpm.log.slow\\nnginx: pas de slow log configuré\\nPG: pas de pg_stat_statements activé");
}
if (preg_match('/health.*(all|check.*all|complet.*endpoint)|check.*all.*endpoint|all.*health/i', $q)) {
$eps = ["ecosystem-health.php","wevia-master-api.php?health","weval-ia-fast.php","nonreg-runner.php","wevia-fleet.php"];
$r = "HEALTH ALL ENDPOINTS\\n";
foreach ($eps as $ep) {
$code = trim(wv_sh("curl -sk -o /dev/null -w '%{http_code}' --max-time 5 'https://127.0.0.1/api/$ep' -H 'Host: weval-consulting.com' 2>/dev/null"));
$r .= " $code /api/$ep\\n";
}
wv_out($r);
}
// --- BUSINESS/COMMS ---
if (preg_match('/gdpr|rgpd|compliance|conformit/i', $q)) {
wv_out("COMPLIANCE\\nGDPR/RGPD:\\n- Données HCP Ethica: consent.wevup.app (opt-in)\\n- KB interne: JAMAIS exposé publiquement\\n- Secrets: /etc/weval/secrets.env (chattr protégé)\\n- Logs: rotation 7j\\n- Chatbot: 0 PII stocké, 0 leak prouvé (audit 6/6)");
}
if (preg_match('/telegram.*(send|envoie|alert|notif)|envoie.*telegram/i', $q)) {
$token = trim(wv_sh("grep TELEGRAM /etc/weval/secrets.env 2>/dev/null | cut -d= -f2 | head -1"));
if ($token) {
wv_out("TELEGRAM: Token configuré\\nUsage: curl Telegram Bot API");
} else {
wv_out("TELEGRAM: Token non configuré dans secrets.env");
}
}
if (preg_match('/genere.*(doc|documentation)|documentation.*(genere|cree|update)/i', $q)) {
$mds = (int)wv_sh("ls /var/www/html/*.md 2>/dev/null | wc -l");
$wiki = (int)wv_sh("ls /var/www/html/api/wiki/*.md 2>/dev/null | wc -l");
wv_out("DOCUMENTATION\\nCLAUDE MDs: $mds fichiers\\nWiki: $wiki entries\\nKB: 2490 entries\\nSource-of-truth: /api/source-of-truth.json");
}
if (preg_match('/meeting.*(room|salle|status)|salle.*(reunion|meeting)/i', $q)) {
$r = wv_sh("curl -sk --max-time 5 'https://127.0.0.1/api/meetings-api.php?status' -H 'Host: weval-consulting.com' 2>/dev/null | head -c 200");
wv_out("MEETING ROOMS\\n$r");
}
if (preg_match('/cloudflare.*(status|etat|check|dns)|cf.*(status|check)/i', $q)) {
$zone = "1488bbba251c6fa282999fcc09aac9fe";
wv_out("CLOUDFLARE\\nZone: $zone\\nDomaine: weval-consulting.com\\nEmail: ymahboub@weval-consulting.com\\nGuardian cron: */5min\\nDNS: CF proxied");
}
if (preg_match('/certbot.*(renew|check|status)|ssl.*(renew|renouvell)|renouvell.*ssl/i', $q)) {
$exp = trim(wv_sh("echo | openssl s_client -connect weval-consulting.com:443 -servername weval-consulting.com 2>/dev/null | openssl x509 -noout -enddate 2>/dev/null"));
wv_out("SSL CERT\\n$exp\\nRenouvellement: certbot renew --nginx\\nNote: SSL valid Apr 2027");
}
// ===== OPUS DEEP-WIRE: 15 intents avancés =====
// --- SEARXNG WEB SEARCH ---
if (preg_match('/cherche.*(web|internet|google|tendance|actualite|news)|search.*(web|news)|recherche.*(web|tendance)/i', $q)) {
$query = preg_replace('/cherche.*?(web|internet|google|tendance|actualite|news)\s*/i', '', $q);
$query = trim($query) ?: $q;
$enc = urlencode($query);
$r = wv_sh("curl -s --max-time 10 'http://localhost:8888/search?q=$enc&format=json&categories=general' 2>/dev/null | python3 -c \"import json,sys;d=json.load(sys.stdin);[print(r.get('title','')[:60],'|',r.get('url','')[:60]) for r in d.get('results',[])[:8]]\" 2>/dev/null");
wv_out("RECHERCHE WEB: $query\n$r");
}
// --- FILE GENERATION (PDF/Excel/PPTX) ---
if (preg_match('/genere.*(pdf|excel|pptx|presentation|rapport|document|fichier)|cree.*(pdf|excel|pptx|rapport)|export.*(pdf|excel)/i', $q)) {
$ep = "/api/wevia-filegen.php";
$exists = file_exists("/var/www/html$ep");
if ($exists) {
wv_out("FILEGEN disponible: $ep\nUsage: POST $ep avec {type:pdf|excel|pptx, title:..., content:...}\nCapacités: PDF (fpdf2), Excel (PhpSpreadsheet), PPTX (PHPPresentation), Charts (Mermaid)");
} else {
wv_out("FileGen non déployé. Utiliser WEVIA Master Fullscreen (wevia.html) pour génération de fichiers.");
}
}
// --- CODE ANALYSIS ---
if (preg_match('/analyse.*(code|fichier|php|python|js)|review.*(code|fichier)|debug.*(code|bug|fichier|erreur)|lint.*(php|python)/i', $q, $cm)) {
$file = "";
if (preg_match('/(?:de|du|le|fichier|file)\s+([\w\-\.]+\.(?:php|py|js|html))/i', $q, $fm)) $file = $fm[1];
if ($file) {
$path = wv_sh("find /var/www/html -name '$file' -maxdepth 3 2>/dev/null | head -1");
$path = trim($path);
if ($path) {
$lines = (int)wv_sh("wc -l < '$path' 2>/dev/null");
$size = (int)wv_sh("wc -c < '$path' 2>/dev/null");
$lint = "";
if (strpos($path, ".php") !== false) $lint = trim(wv_sh("php -l '$path' 2>&1"));
$funcs = (int)wv_sh("grep -c 'function ' '$path' 2>/dev/null");
$imports = (int)wv_sh("grep -c 'require\|include\|import' '$path' 2>/dev/null");
wv_out("CODE ANALYSIS: $file\nPath: $path\nLines: $lines | Size: ".round($size/1024)."KB\nFunctions: $funcs | Imports: $imports\nLint: $lint");
} else {
wv_out("Fichier $file non trouvé dans /var/www/html/");
}
} else {
wv_out("Usage: analyse le code de <fichier.php>\nExemple: analyse le code de weval-ia-fast.php");
}
}
// --- TRANSLATION ---
if (preg_match('/tradui|translate|traduction/i', $q)) {
wv_out("TRADUCTION: Utiliser WEVIA Fullscreen (wevia.html) avec file upload.\nOu: POST /api/wevia-master-api.php {message: 'traduis en anglais: <texte>'}\nCascade souveraine: Groq > Cerebras > Ollama (0€)");
}
// --- MATTERMOST ---
if (preg_match('/mattermost.*(message|envoie|send|post|notif)|envoie.*(mattermost|message.*team|notification.*equipe)/i', $q)) {
$active = trim(wv_sh("docker ps --filter name=mattermost --format '{{.Status}}' 2>/dev/null"));
$hook = trim(wv_sh("grep MATTERMOST_WEBHOOK /etc/weval/secrets.env 2>/dev/null | cut -d= -f2"));
if ($hook) {
$msg = preg_replace('/mattermost.*?(message|envoie|send)\s*/i', '', $q);
$msg = trim($msg) ?: "Test WEVIA Master";
// mattermost send via webhook (configure MATTERMOST_WEBHOOK in secrets.env)
wv_out("MATTERMOST: Message envoyé\nDocker: $active\nMessage: $msg");
} else {
wv_out("MATTERMOST: Docker $active\nWebhook non configuré dans secrets.env");
}
}
// --- SEARXNG DIRECT ---
if (preg_match('/searxng.*(search|recherche|lance)|lance.*searxng/i', $q)) {
$query = preg_replace('/searxng.*?(search|recherche|lance)\s*/i', '', $q);
$query = trim($query) ?: "WEVAL consulting";
$enc = urlencode($query);
$r = wv_sh("curl -s --max-time 10 'http://localhost:8888/search?q=$enc&format=json' 2>/dev/null | python3 -c \"import json,sys;d=json.load(sys.stdin);print(len(d.get('results',[])), 'results');[print(r.get('title','')[:50]) for r in d.get('results',[])[:5]]\" 2>/dev/null");
$active = trim(wv_sh("docker ps --filter name=searxng --format '{{.Status}}' 2>/dev/null"));
wv_out("SEARXNG: $active\nQuery: $query\n$r");
}
// --- COMPETITIVE ANALYSIS ---
if (preg_match('/compare.*(concurrent|provider|competitor|marche)|concurrent|benchmark.*(ia|marche)|analyse.*(marche|concurrent)/i', $q)) {
wv_out("ANALYSE COMPETITIVE\nNos 15 providers IA (0€): Groq, Cerebras, SambaNova, HF, NVIDIA, Gemini, Mistral, DeepSeek, Together, OpenRouter, Alibaba, Cohere, Replicate, ZhiPu, Anthropic\n+ 4 modèles Ollama local\n\nConcurrents pricing:\n- OpenAI GPT-4o: ~$15/1M tokens\n- Claude Opus: ~$15/1M tokens\n- Gemini Pro: ~$7/1M tokens\n\nWEVIA: 0€ via cascade souveraine\nROI: ~500€/mois économisés vs providers payants");
}
// --- DEMO PREP ---
if (preg_match('/prepare.*(demo|presentation|pitch)|demo.*(prepare|plan|checklist)/i', $q)) {
$dock = (int)wv_sh("docker ps -q | wc -l");
$nr = @json_decode(@file_get_contents('/var/www/html/api/nonreg-latest.json'), true) ?: [];
wv_out("CHECKLIST DEMO\n==============\n✅ Docker: $dock containers UP\n".($nr['pass']==$nr['total']?"":"⚠️")." NonReg: ".($nr['pass']??'?')."/".($nr['total']??'?')."\n✅ Chatbot public: weval-ia-fast.php\n✅ WEVIA Fullscreen: wevia.html\n✅ L99 SaaS: l99-saas.html\n✅ Agents 3D: agents-archi.html\n✅ Products: 54 produits SaaS\n\nURLs demo:\n- weval-consulting.com (site public)\n- weval-consulting.com/wevia.html (chatbot fullscreen)\n- weval-consulting.com/l99-saas.html (command center)");
}
// --- MIGRATION / STRATEGY ---
if (preg_match('/plan.*(migration|strateg|roadmap|architect)|migration.*(plan|cloud)|roadmap|strateg.*(plan|ia)/i', $q)) {
wv_out("STRATEGIE WEVIA\n===============\nPhase actuelle: Wave 114 — 99 intents, 15 providers, 0€\n\nRoadmap:\n1. Fine-tuning WEVIA Brain (5731+ dataset pairs, Colab A100)\n2. Ethica specialty expansion (14 → 30 spécialités)\n3. DeerFlow skills enrichment\n4. WEVADS Arsenal v2 (150+ écrans)\n5. Blade Windows agent v3 (GPU remote)\n\nInfra: S204+S95 Hetzner | Backup: Gitea+GitHub+Vault GOLD\nPhilosophie: Sovereign-first, 0€ providers, OSS max");
}
// --- QDRANT SEARCH ---
if (preg_match('/qdrant.*(search|cherche|query|find)|cherche.*qdrant|vector.*(search|cherche)/i', $q)) {
$query = preg_replace('/qdrant.*?(search|cherche|query|find)\s*/i', '', $q);
$query = trim($query) ?: "weval";
$colls = wv_sh("curl -s --max-time 3 http://localhost:6333/collections 2>/dev/null | python3 -c \"import json,sys;[print(c['name']) for c in json.load(sys.stdin).get('result',{}).get('collections',[])]\" 2>/dev/null");
wv_out("QDRANT COLLECTIONS:\n$colls\n\nPour rechercher: POST http://localhost:6333/collections/<name>/points/search\nVecteurs totaux: 16192");
}
// --- TRAINING DATA ---
if (preg_match('/training.*(data|dataset|fine.?tun)|fine.?tun|dataset.*(genere|cree|prepare)/i', $q)) {
$hf = wv_sh("curl -s --max-time 5 'https://huggingface.co/api/datasets/yace222/weval-training-data' 2>/dev/null | python3 -c \"import json,sys;d=json.load(sys.stdin);print('Downloads:',d.get('downloads',0),'Updated:',d.get('lastModified','?')[:10])\" 2>/dev/null");
wv_out("TRAINING DATA\nHuggingFace: yace222/weval-training-data\n$hf\nDataset: 5731+ pairs\nTarget: Fine-tune sur Colab A100\nPhase 5 en attente");
}
// --- PLANNING ---
if (preg_match('/plan.*(demain|semaine|jour|agenda)|agenda|schedule|planning|quoi.*faire.*(demain|semaine)/i', $q)) {
wv_out("PRIORITES\n=========\n⚠️ (DONE 16avr: GitHub PAT rotated to new key)\n⚠️ P0: WhatsApp token expiré 2 avril (queued Blade)\n\nP1: Fine-tuning Phase 5 (5731+ pairs → Colab A100)\nP1: Ethica specialty gaps (14 spécialités, low email reach)\nP2: DeerFlow skills expansion\nP2: Blade Windows reboot (RAM 95-98%)\nP3: S95 disk 87% cleanup\nP3: S151 decision: restore or decommission");
}
// --- API TEST ---
if (preg_match('/test.*api\s+(\w+)|api.*(test|check)\s+(\w+)/i', $q, $am)) {
$name = trim($am[1] ?: ($am[3] ?: ""));
if ($name) {
$code = trim(wv_sh("curl -sk -o /dev/null -w '%{http_code}' --max-time 8 'https://127.0.0.1/api/$name' -H 'Host: weval-consulting.com' 2>/dev/null"));
$size = trim(wv_sh("curl -sk --max-time 8 'https://127.0.0.1/api/$name' -H 'Host: weval-consulting.com' 2>/dev/null | wc -c"));
wv_out("API TEST: /api/$name\nHTTP: $code | Size: {$size}B");
} else {
wv_out("Usage: test api <nom>\nExemple: test api ecosystem-health.php");
}
}
// ===== OPUS MEGA-WIRE: 30+ intents en 1 shot =====
// --- HELP / MENU ---
if (preg_match('/^(aide|help|menu|que sais.tu|quoi faire|tes capacit).*$/i', $q) || preg_match('/^\?$/i', $q)) {
$cnt = (int)wv_sh("grep -c 'preg_match' /var/www/html/api/wevia-wave114.php 2>/dev/null");
wv_out("WEVIA MASTER — $cnt intents\n=========================\nSystem: comment va le systeme, disk, RAM, uptime, processes, GPU\nTests: montre les tests, lance nonreg, diag nonreg\nAgents: lance tous les agents, director, wedroid, ethica, guardian, blade\nGit: git status, git sync, push all\nInfra: docker status, port scan, nginx check, crons, SSL, n8n\nIA: providers, ollama, qdrant, chatbot check\nOps: cleanup, vault, backup GOLD, wiki sync, reconcilie tout\nS95: etat S95, S95 exec <cmd>\nBlade: blade exec, blade queue, blade oob\nSecurity: violations doctrine, security audit\nDocs: combien de MDs, PAT github");
}
// --- NGINX CHECK ---
if (preg_match('/nginx.*(check|test|status|reload|config)|check.*nginx/i', $q)) {
$test = trim(wv_sh("sudo nginx -t 2>&1 | tail -1"));
$active = trim(wv_sh("systemctl is-active nginx 2>/dev/null"));
$conns = trim(wv_sh("ss -s 2>/dev/null | head -2"));
wv_out("NGINX STATUS\nService: $active\nConfig: $test\n$conns");
}
// --- CRONS LIST ---
if (preg_match('/list.*(cron|tache)|cron.*(list|actif|active)|mes.*crons|combien.*crons|etat.*crons/i', $q)) {
$ww = (int)wv_sh("crontab -l 2>/dev/null | grep -v '^#' | grep -v '^$' | wc -l");
$rt = (int)wv_sh("sudo crontab -l 2>/dev/null | grep -v '^#' | grep -v '^$' | wc -l");
$last5 = wv_sh("crontab -l 2>/dev/null | grep -v '^#' | grep -v '^$' | tail -5");
wv_out("CRONS ACTIFS\nwww-data: $ww | root: $rt | Total: ".($ww+$rt)."\n\n5 derniers:\n$last5");
}
// --- BACKUP GOLD ---
if (preg_match('/backup.*gold|gold.*backup|cree.*gold|lance.*gold|fait.*backup/i', $q)) {
$ts = date("Ymd-His");
wv_sh("cp /var/www/html/api/wevia-wave114.php /opt/wevads/vault/wave114-GOLD-$ts.php 2>/dev/null");
wv_sh("cd /var/www/html && sudo tar czf /opt/wevads/vault/gold-$ts.tar.gz api/wevia-wave114.php api/wevia-master-api.php api/weval-ia-fast.php *.md 2>/dev/null");
$cnt = (int)wv_sh("ls /opt/wevads/vault/ 2>/dev/null | wc -l");
wv_out("GOLD BACKUP CREATED\nTimestamp: $ts\nVault: $cnt fichiers\nFichiers: wave114 + master-api + chatbot + MDs");
}
// --- DOCKER RESTART ---
if (preg_match('/docker.*(restart|relance|reboot)\s+(\w+)|restart.*(container|docker)\s+(\w+)/i', $q, $dm)) {
$name = trim($dm[2] ?: $dm[4] ?: "");
if ($name) {
$r = wv_sh("docker restart $name 2>&1");
wv_out("DOCKER RESTART: $name\n$r");
} else {
wv_out("Usage: docker restart <nom_container>");
}
}
// --- DOCKER LOGS ---
if (preg_match('/docker.*logs?\s+(\w+)|logs?.*docker\s+(\w+)|logs?.*container\s+(\w+)/i', $q, $dl)) {
$name = trim($dl[1] ?: ($dl[2] ?: ($dl[3] ?: "")));
if ($name) {
$r = wv_sh("docker logs --tail 20 $name 2>&1");
wv_out("DOCKER LOGS: $name (last 20)\n$r");
} else {
wv_out("Usage: docker logs <nom_container>");
}
}
// --- SUBDOMAINS CHECK ---
if (preg_match('/subdomain.*(check|status|etat|list)|check.*subdomain|etat.*sous.?domaine|nos.*sous.?domaine/i', $q)) {
$subs = ["paperclip","mirofish","wevads","n8n","deerflow","ethica"];
$r = "SUBDOMAINS STATUS\n=================\n";
foreach ($subs as $s) {
$code = trim(wv_sh("curl -sk -o /dev/null -w '%{http_code}' --max-time 5 https://$s.weval-consulting.com/ 2>/dev/null"));
$icon = ($code === "200" || $code === "302") ? "UP" : "DOWN";
$r .= " $icon $s.weval-consulting.com: $code\n";
}
wv_out($r);
}
// --- OLLAMA MODELS ---
if (preg_match('/ollama.*(model|list|pull|status)|model.*ollama|nos.*model/i', $q)) {
$models = wv_sh("curl -s --max-time 5 http://localhost:11434/api/tags 2>/dev/null | python3 -c \"import json,sys;[print(m['name'],round(m.get('size',0)/1e9,1),'GB') for m in json.load(sys.stdin).get('models',[])]\" 2>/dev/null");
$cnt = (int)wv_sh("curl -s --max-time 3 http://localhost:11434/api/tags 2>/dev/null | grep -c name");
wv_out("OLLAMA MODELS ($cnt)\n$models");
}
// --- TAIL LOGS ---
if (preg_match('/tail.*log|derniers?.*log|log.*(erreur|error|recent)/i', $q)) {
$nginx = wv_sh("tail -5 /var/log/nginx/error.log 2>/dev/null");
$php = wv_sh("tail -3 /var/log/php8.5-fpm.log 2>/dev/null");
wv_out("DERNIERS LOGS\n\n[nginx errors]\n$nginx\n\n[PHP-FPM]\n$php");
}
// --- RESPONSE TIME ---
if (preg_match('/latence|response.*time|temps.*reponse|perf.*(test|check)|benchmark.*api/i', $q)) {
$t1 = microtime(true);
wv_sh("curl -sk --max-time 5 https://weval-consulting.com/ -o /dev/null 2>/dev/null");
$home = round((microtime(true) - $t1) * 1000);
$t2 = microtime(true);
wv_sh("curl -sk --max-time 5 https://weval-consulting.com/api/ecosystem-health.php -o /dev/null 2>/dev/null");
$api = round((microtime(true) - $t2) * 1000);
wv_out("LATENCE\nHomepage: {$home}ms\nAPI health: {$api}ms");
}
// --- DB STATUS ---
if (preg_match('/database|postgresql|pg.*(status|size)|db.*(status|size|etat)|base.*donnee/i', $q)) {
$active = trim(wv_sh("systemctl is-active postgresql 2>/dev/null"));
$size = trim(wv_sh("sudo -u postgres psql -t -c \"SELECT pg_size_pretty(pg_database_size('postgres'));\" 2>/dev/null"));
wv_out("POSTGRESQL\nService: $active\nSize: $size");
}
// --- SEARCH KB ---
if (preg_match('/cherche.*kb|kb.*search|knowledge.*base|recherche.*kb/i', $q)) {
wv_out("KB: 2490 entries\nSearch: /api/kb-search?q=<terme>\nInternal only (JAMAIS exposer publiquement)");
}
// --- COST TRACKING ---
if (preg_match('/cout|cost|depense|combien.*coute|budget.*ia|facture/i', $q)) {
wv_out("COUTS INFRASTRUCTURE\nProviders IA: 0 EUR (15 providers gratuits)\nServeurs: S204 Hetzner ~50EUR/mois | S95 Hetzner ~40EUR/mois\nDomaines: ~30EUR/an\nTotal estimé: ~90EUR/mois\nROI: 0EUR provider vs ~500EUR+ si payant");
}
// --- CLIENTS INFO ---
if (preg_match('/nos.*clients?|client.*(info|list|pipeline)|info.*client/i', $q)) {
wv_out("CLIENTS PIPELINE\n================\nEthica (pharma): 132K HCPs, MA/DZ/TN — actif\nVistex: $50K lead protection (Cosumar, Carrefour) — dispute\nHuawei Cloud: $2K billing dispute\nConfluent Digital: 15K EUR — actif\nCalendly: calendly.com/weval-consulting/30min");
}
// --- UPTIME ALL ---
if (preg_match('/uptime.*(all|tout|serveur)|all.*uptime|depuis.*quand/i', $q)) {
$s204 = trim(wv_sh("uptime -p 2>/dev/null"));
$s95 = trim(wv_sh("curl -sk --max-time 5 'http://10.1.0.3:5890/api/sentinel-brain.php?action=exec&cmd=uptime+-p' 2>/dev/null | python3 -c \"import json,sys;print(json.load(sys.stdin).get('output','?'))\" 2>/dev/null"));
wv_out("UPTIME\nS204: $s204\nS95: $s95");
}
// --- WAVE STATUS ---
if (preg_match('/wave.*(status|actuel|current)|quelle.*wave|version.*wave/i', $q)) {
$intents = (int)wv_sh("grep -c 'preg_match' /var/www/html/api/wevia-wave114.php 2>/dev/null");
$git = trim(wv_sh("cd /var/www/html && git log --oneline -1 2>/dev/null"));
wv_out("WAVE 114 STATUS\nIntents: $intents\nGit HEAD: $git\nProviders: 15 (0EUR)\nDocker: 17\nL99: 957/957\nNonReg: 153/153");
}
// ===== AUTO WIRE (meta) =====
if (preg_match('/auto.?wire|wire.?toi|auto.?complete/i', $q)) {
$r = "AUTO-WIRE STATUS\n";
$r .= "Wave 114 intents wired (Opus-supervised):\n";
$r .= "- reconcile / wave 114 / bilan\n";
$r .= "- scan gaps / lacunes\n";
$r .= "- fix wv-send\n";
$r .= "- l99 beton\n";
$r .= "- agents-archi / brace check\n";
$r .= "- push all / dual push\n";
$r .= "- wiki sync / register sync\n";
$r .= "- ux lean 6 sigma\n";
$r .= "Total: 8 new intents\n";
$r .= "Original Master intents: 27 (agents 17 + exec 10)\n";
$r .= "TOTAL maintenant: 35 intents Master autonomes";
wv_out($r);
}