Files
html/wevia-orchestrator.html
Opus a55d69ada1
Some checks failed
WEVAL NonReg / nonreg (push) Has been cancelled
auto-sync-0300
2026-04-24 03:00:11 +02:00

664 lines
46 KiB
HTML

<!DOCTYPE html>
<html lang="fr"><head>
<meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<title>WEVIA — Orchestrator GODMODE</title>
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600;700&family=Outfit:wght@300;400;500;600;700;800;900&display=swap" rel="stylesheet">
<style>
:root{--bg:#0a0a0f;--bg2:#12121a;--bg3:#1a1a2e;--brd:#2a2a3e;--t1:#e8e8f0;--t2:#8888aa;--t3:#555570;--cyan:#06d6a0;--red:#ef4444;--amber:#f59e0b;--blue:#3b82f6;--purple:#8b5cf6;--pink:#ec4899;--r:10px;--mono:'JetBrains Mono',monospace;--sans:'Outfit',sans-serif}
*{margin:0;padding:0;box-sizing:border-box}
body{background:var(--bg);color:var(--t1);font-family:var(--sans);overflow-x:hidden}
@keyframes pulse{0%,100%{opacity:1}50%{opacity:.5}}
@keyframes slideUp{from{opacity:0;transform:translateY(20px)}to{opacity:1;transform:translateY(0)}}
@keyframes glow{0%,100%{box-shadow:0 0 5px var(--cyan)}50%{box-shadow:0 0 20px var(--cyan),0 0 40px rgba(6,214,160,.2)}}
@keyframes spin{to{transform:rotate(360deg)}}
@keyframes dataFlow{0%{background-position:0% 50%}50%{background-position:100% 50%}100%{background-position:0% 50%}}
/* HEADER */
.hdr{display:flex;align-items:center;justify-content:space-between;padding:12px 20px;background:linear-gradient(180deg,rgba(6,214,160,.08),transparent);border-bottom:1px solid var(--brd)}
.hdr h1{font:800 20px var(--sans);background:linear-gradient(135deg,var(--cyan),var(--blue));-webkit-background-clip:text;-webkit-text-fill-color:transparent}
.hdr .live{display:flex;align-items:center;gap:6px;font:500 11px var(--mono);color:var(--cyan)}
.hdr .live::before{content:'';width:8px;height:8px;border-radius:50%;background:var(--cyan);animation:pulse 2s infinite}
.nav{display:flex;gap:4px;font:500 10px var(--mono)}
.nav a{padding:4px 10px;border-radius:6px;color:var(--t2);text-decoration:none;border:1px solid transparent;transition:.2s}
.nav a:hover,.nav a.active{color:var(--cyan);border-color:var(--cyan);background:rgba(6,214,160,.08)}
/* GRID */
.grid{display:grid;grid-template-columns:280px 1fr 320px;grid-template-rows:auto 1fr;gap:1px;height:calc(100vh - 52px);background:var(--brd)}
.grid>*{background:var(--bg);overflow-y:auto}
/* LEFT: Agent Fleet */
.fleet{padding:12px}
.fleet h2{font:700 12px var(--mono);color:var(--cyan);margin-bottom:10px;text-transform:uppercase;letter-spacing:2px}
.agent{display:flex;align-items:center;gap:10px;padding:8px 10px;border-radius:var(--r);cursor:pointer;transition:.2s;margin-bottom:4px;border:1px solid transparent}
.agent:hover{background:var(--bg3);border-color:var(--brd)}
.agent.active{background:rgba(6,214,160,.08);border-color:var(--cyan)}
.agent .dot{width:8px;height:8px;border-radius:50%;flex-shrink:0}
.dot.green{background:var(--cyan);box-shadow:0 0 6px var(--cyan)}
.dot.red{background:var(--red);box-shadow:0 0 6px var(--red)}
.dot.amber{background:var(--amber);box-shadow:0 0 6px var(--amber)}
.dot.spin{animation:spin 1s linear infinite;border:2px solid var(--blue);border-top-color:transparent;background:none}
.agent .info{flex:1;min-width:0}
.agent .name{font:600 12px var(--sans);color:var(--t1)}
.agent .desc{font:400 10px var(--mono);color:var(--t3);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.agent .badge{font:600 9px var(--mono);padding:2px 6px;border-radius:4px;background:var(--bg3);color:var(--t2)}
/* CENTER: Orchestration */
.center{display:flex;flex-direction:column}
.task-bar{display:flex;gap:8px;padding:12px;border-bottom:1px solid var(--brd);background:var(--bg2)}
.task-bar input{flex:1;background:var(--bg3);border:1px solid var(--brd);border-radius:var(--r);padding:10px 14px;color:var(--t1);font:500 13px var(--sans);outline:none}
.task-bar input:focus{border-color:var(--cyan)}
.task-bar input::placeholder{color:var(--t3)}
.btn{padding:10px 20px;border-radius:var(--r);border:none;font:600 12px var(--sans);cursor:pointer;transition:.2s}
.btn-primary{background:var(--cyan);color:var(--bg)}
.btn-primary:hover{filter:brightness(1.2)}
.btn-ghost{background:transparent;color:var(--t2);border:1px solid var(--brd)}
.btn-ghost:hover{color:var(--cyan);border-color:var(--cyan)}
.orchestration{flex:1;padding:16px;overflow-y:auto}
.step{margin-bottom:16px;animation:slideUp .4s ease-out}
.step-header{display:flex;align-items:center;gap:8px;margin-bottom:8px}
.step-num{width:24px;height:24px;border-radius:50%;display:flex;align-items:center;justify-content:center;font:700 11px var(--mono);background:var(--bg3);color:var(--t2);border:1px solid var(--brd)}
.step-num.done{background:var(--cyan);color:var(--bg);border-color:var(--cyan)}
.step-num.running{animation:glow 1.5s infinite;border-color:var(--cyan);color:var(--cyan)}
.step-title{font:600 13px var(--sans);color:var(--t1)}
.step-time{font:400 10px var(--mono);color:var(--t3);margin-left:auto}
.step-body{margin-left:32px;padding:10px 14px;background:var(--bg2);border-radius:var(--r);border:1px solid var(--brd);font:400 11px var(--mono);color:var(--t2);line-height:1.6;white-space:pre-wrap}
.step-body .key{color:var(--cyan)}
.step-body .val{color:var(--t1)}
.step-body .err{color:var(--red)}
.step-body .ok{color:var(--cyan)}
.synthesis{margin-top:16px;padding:16px;background:linear-gradient(135deg,rgba(6,214,160,.05),rgba(59,130,246,.05));border:1px solid var(--cyan);border-radius:var(--r);font:400 12px var(--sans);color:var(--t1);line-height:1.7}
.synthesis h3{font:700 14px var(--sans);color:var(--cyan);margin-bottom:8px}
/* RIGHT: Hub & Connections */
.hub{padding:12px}
.hub h2{font:700 12px var(--mono);color:var(--purple);margin-bottom:10px;text-transform:uppercase;letter-spacing:2px}
.section{margin-bottom:16px}
.section h3{font:600 11px var(--mono);color:var(--t3);margin-bottom:6px;text-transform:uppercase;letter-spacing:1px}
.conn{display:flex;align-items:center;gap:8px;padding:6px 8px;border-radius:6px;margin-bottom:3px;transition:.2s;cursor:pointer;font:400 11px var(--mono);color:var(--t2)}
.conn:hover{background:var(--bg3)}
.conn .ic{font-size:14px}
.conn .st{margin-left:auto;font:600 9px var(--mono);padding:1px 5px;border-radius:3px}
.st.up{color:var(--cyan);background:rgba(6,214,160,.15)}
.st.down{color:var(--red);background:rgba(239,68,68,.15)}
.st.idle{color:var(--amber);background:rgba(245,158,11,.15)}
/* STATS BAR */
.stats-bar{display:flex;gap:1px;background:var(--brd);grid-column:1/-1}
.stat{flex:1;padding:8px 12px;background:var(--bg2);text-align:center}
.stat .v{font:700 18px var(--mono);color:var(--cyan)}
.stat .l{font:400 9px var(--mono);color:var(--t3);text-transform:uppercase;letter-spacing:1px}
/* QUICK ACTIONS */
.actions{display:flex;flex-wrap:wrap;gap:4px;margin-top:8px}
.act{padding:4px 8px;border-radius:5px;font:500 9px var(--mono);background:var(--bg3);color:var(--t2);border:1px solid var(--brd);cursor:pointer;transition:.2s}
.act:hover{color:var(--cyan);border-color:var(--cyan);background:rgba(6,214,160,.05)}
/* LOADING */
.spinner{width:16px;height:16px;border:2px solid var(--brd);border-top-color:var(--cyan);border-radius:50%;animation:spin .6s linear infinite;display:inline-block}
/* SCROLLBAR */
::-webkit-scrollbar{width:4px}::-webkit-scrollbar-track{background:var(--bg)}::-webkit-scrollbar-thumb{background:var(--brd);border-radius:4px}
</style>
<link rel="stylesheet" href="/css/wevia-portal-consistency.css">
<!-- DOCTRINE-60-UX-ENRICH cerebras-qwen235b 20260424-025724 -->
<style id="doctrine60-ux-wevia-orchestrator">
.card, .panel, .btn, .kpi { opacity: 0; transform: translateY(20px); transition: opacity 0.6s ease, transform 0.6s ease; }
.card.visible, .panel.visible, .kpi.visible, .btn.visible { opacity: 1; transform: translateY(0); }
.hover-glow:hover { box-shadow: 0 0 12px rgba(0, 120, 255, 0.4); border-color: rgba(0, 120, 255, 0.6); transition: all 0.3s; }
.pulse, .live-indicator, .active, .online { animation: pulse-animation 3s ease-in-out infinite; }
@keyframes pulse-animation { 0%, 100% { opacity: 0.6; } 50% { opacity: 1; } }
body::before { content: ""; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: radial-gradient(circle at 50% 50%, rgba(0, 120, 255, 0.12), transparent 70%); pointer-events: none; z-index: -1; }
.chat, .speech, .modal, .overlay { backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px); }
</style>
</head>
<body>
<div class="wevia-portal-banner">
<span class="wevia-portal-banner-label">🌐 WEVIA ECOSYSTEM</span>
<a href="/all-ia-hub.html" data-portal="hub" class="wevia-portal-banner-link">🧠 All-IA Hub</a>
<a href="/wevia-master.html" data-portal="master" class="wevia-portal-banner-link">🤖 WEVIA Master</a>
<a href="/wevia-orchestrator.html" data-portal="arena" class="wevia-portal-banner-link wevia-current">🎭 Arena Orchestrator</a>
<a href="/weval-technology-platform.html" data-portal="wtp" class="wevia-portal-banner-link">🧭 WTP Hub</a>
<span class="wevia-portal-badge-wave">WAVE 221</span>
</div>
<div class="hdr">
<h1>WEVIA ORCHESTRATOR</h1>
<div class="live">GODMODE LIVE</div>
<div class="nav">
<a href="/weval-technology-platform.html" style="color:#fcd34d;border-color:#fcd34d33" title="WEVAL Technology Platform · ERP point entrée unique">🏠 WTP</a>
<a href="/all-ia-hub.html" style="color:#f9a8d4;border-color:#f9a8d433" title="All-IA Hub · 7 tabs multi-agents">🌈 All-IA</a>
<a href="/weval-arena.html" style="color:#a78bfa;border-color:#a78bfa33" title="WEVAL Arena Command Center">⚔️ Arena</a>
<a href="/wevia-master.html" style="color:#67e8f9;border-color:#67e8f933" title="WEVIA Master Chat (auth required)">🤖 Master</a>
<a href="/wevcode.html" style="color:#6ee7b7;border-color:#6ee7b733" title="WevCode · Sovereign Coding Agent v2.0">💻 WevCode</a>
<a href="/wevia-unified-hub.html" style="color:#00d4b4;border-color:#00d4b433" title="WEVIA Unified Hub · Truth Registry source de vérité unique">🧠 Truth Hub</a>
<a href="/agents-archi.html">3D Archi</a>
<a href="/enterprise-model.html">Enterprise</a>
<a href="/wevia-meeting-rooms.html">Meeting</a>
<a href="/director-center.html">Director</a>
<a href="/playwright-v132-portfolio.html" style="color:#34d399;border-color:#34d39933" title="V132 Playwright · 12 intents · 100% routing validé">🎯 V132 100%</a>
<a href="/command-center.html">Command</a>
<a href="/growth-engine-v2.html">Growth</a>
<a href="https://paperclip.weval-consulting.com">Paperclip</a>
<a href="/agents-fleet.html">Fleet</a>
<a class="active" href="/wevia-orchestrator.html">Orchestrator</a>
</div>
</div>
<div class="stats-bar">
<div class="stat"><div class="v" id="st-agents">726</div><div class="l">Agents</div></div>
<div class="stat"><div class="v" id="st-tools">619</div><div class="l">Tools</div></div>
<div class="stat"><div class="v" id="st-providers">12</div><div class="l">IA Providers</div></div>
<div class="stat"><div class="v" id="st-hcps">141K</div><div class="l">HCPs Ethica</div></div>
<div class="stat"><div class="v" id="st-pages">174</div><div class="l">Pages</div></div>
<div class="stat"><div class="v" id="st-nonreg">152/152</div><div class="l">NonReg</div></div>
<div class="stat"><div class="v" id="st-docker">10</div><div class="l">Docker</div></div>
<div class="stat"><div class="v" id="st-cost">0€</div><div class="l">IA Cost</div></div>
</div>
<div class="grid">
<!-- LEFT: Agent Fleet -->
<div class="fleet">
<h2>Agent Fleet</h2>
<div id="agents-list"></div>
<h2 style="margin-top:16px">Quick Actions</h2>
<div class="actions">
<div class="act" onclick="runTask('multiagent tout finir')">Full Scan</div>
<div class="act" onclick="runTask('fix load')">Fix Load</div>
<div class="act" onclick="runTask('fix fpm')">Fix FPM</div>
<div class="act" onclick="runTask('fix git push')">Git Push</div>
<div class="act" onclick="runTask('nonreg')">NonReg</div>
<div class="act" onclick="runTask('ethica stats')">Ethica</div>
<div class="act" onclick="runTask('diagnostic')">Health</div>
<div class="act" onclick="runTask('providers')">Providers</div>
<div class="act" onclick="runTask('docker')">Docker</div>
<div class="act" onclick="runTask('disk')">Disk</div>
<div class="act" onclick="runTask('crons')">Crons</div>
<div class="act" onclick="runTask('arena')">Arena</div>
</div>
</div>
<!-- CENTER: Orchestration -->
<div class="center">
<div class="task-bar">
<input id="task-input" placeholder="Orchestrate: multiagent tout finir, fix load, deploy scraper..." onkeydown="if(event.key==='Enter')runTask()">
<button type="button" aria-label="Execute" class="btn btn-primary" onclick="runTask()">Execute</button>
<button type="button" aria-label="Clear" class="btn btn-ghost" onclick="clearOrch()">Clear</button>
</div>
<div class="orchestration" id="orch-output">
<div style="text-align:center;padding:60px 20px;color:var(--t3)">
<div style="font-size:48px;margin-bottom:16px"></div>
<div style="font:600 16px var(--sans);color:var(--t2);margin-bottom:8px">WEVIA Orchestrator GODMODE</div>
<div style="font:400 12px var(--mono)">LLM-powered multi-agent system — 24 agents, 382 tools, 12 providers</div>
<div style="font:400 11px var(--mono);margin-top:8px;color:var(--t3)">Type a task or use Quick Actions to orchestrate</div>
</div>
</div>
</div>
<!-- RIGHT: Hub -->
<div class="hub">
<h2>Ecosystem Hub</h2>
<div class="section">
<h3>IA Sovereign Cascade</h3>
<div id="providers-list"></div>
</div>
<div class="section">
<h3>Architecture</h3>
<div class="conn" onclick="location='/agents-archi.html'"><span class="ic">🏗️</span> Agents 3D Architecture <span class="st up">LIVE</span></div>
<div class="conn" onclick="location='/enterprise-model.html'"><span class="ic">🏢</span> Enterprise Model <span class="st up">LIVE</span></div>
<div class="conn" onclick="location='/wevia-meeting-rooms.html'"><span class="ic">🏠</span> Meeting Rooms <span class="st up">LIVE</span></div>
<div class="conn" onclick="location='/director-center.html'"><span class="ic">🎯</span> Director Center <span class="st up">LIVE</span></div>
</div>
<div class="section">
<h3>Services</h3>
<div class="conn"><span class="ic">📋</span> Paperclip <span class="st" id="st-paperclip">...</span></div>
<div class="conn"><span class="ic">🐟</span> MiroFish <span class="st" id="st-mirofish">...</span></div>
<div class="conn"><span class="ic">🔍</span> SearXNG <span class="st" id="st-searxng">...</span></div>
<div class="conn"><span class="ic">📊</span> Uptime Kuma <span class="st" id="st-kuma">...</span></div>
<div class="conn"><span class="ic">🗄️</span> Qdrant Vector <span class="st" id="st-qdrant">...</span></div>
<div class="conn"><span class="ic">🔐</span> Vaultwarden <span class="st" id="st-vault">...</span></div>
<div class="conn"><span class="ic">📦</span> Gitea <span class="st" id="st-gitea">...</span></div>
</div>
<div class="section">
<h3>MCP / Tools Hub</h3>
<div class="conn"><span class="ic">🔧</span> Dynamic Resolver <span class="st up" id="st-resolver">368</span></div>
<div class="conn"><span class="ic"></span> Fast-Path 31/31 <span class="st up">ON</span></div>
<div class="conn"><span class="ic">🧠</span> Arena Pre-Intents <span class="st up">ON</span></div>
<div class="conn"><span class="ic">🔄</span> Action Engine <span class="st up">8 acts</span></div>
<div class="conn"><span class="ic">📡</span> CX Endpoint <span class="st" id="st-cx">...</span></div>
<div class="conn"><span class="ic">🛡️</span> Sentinel S95 <span class="st" id="st-sentinel">...</span></div>
</div>
<div class="section">
<h3>Capabilities</h3>
<div class="conn"><span class="ic">💻</span> Code Execution <span class="st up">PHP+Py+Bash</span></div>
<div class="conn"><span class="ic">🐛</span> Debug / Autofix <span class="st up">8 fixes</span></div>
<div class="conn"><span class="ic">🔗</span> SSH Bridge S95 <span class="st up">KEY</span></div>
<div class="conn"><span class="ic">📧</span> Email Pipeline <span class="st up">PMTA</span></div>
<div class="conn"><span class="ic">🏥</span> Ethica HCP <span class="st up">141K</span></div>
<div class="conn"><span class="ic">🤖</span> Scrapers v3 <span class="st up">3 scripts</span></div>
</div>
</div>
</div>
<script>
const AGENTS = [
{id:'infra',name:'Infra Agent',desc:'Load, disk, memory, services',status:'ready',icon:'🖥️'},
{id:'sovereign',name:'Sovereign Agent',desc:'12 IA providers cascade',status:'ready',icon:'🧠'},
{id:'nonreg',name:'NonReg Agent',desc:'152/152 quality tests',status:'ready',icon:'🧪'},
{id:'ethica',name:'Ethica Agent',desc:'141K HCPs DZ/MA/TN',status:'ready',icon:'🏥'},
{id:'git',name:'Git Agent',desc:'Commit, push, status',status:'ready',icon:'📦'},
{id:'vault',name:'Vault Agent',desc:'1181 files, 44 GOLD',status:'ready',icon:'🔐'},
{id:'docker',name:'Docker Agent',desc:'10 containers management',status:'ready',icon:'🐳'},
{id:'scraper',name:'Scraper Agent',desc:'DabaDoc, CNAM, CROMC',status:'ready',icon:'🕷️'},
{id:'crons',name:'Crons Agent',desc:'S204:4 S95:6 scheduled',status:'ready',icon:'⏰'},
{id:'s95',name:'S95 Agent',desc:'Remote server via SSH',status:'ready',icon:'🖧'},
{id:'security',name:'Security Agent',desc:'CrowdSec, Ollama check',status:'ready',icon:'🛡️'},
{id:'paperclip',name:'Paperclip Agent',desc:'Project management',status:'ready',icon:'📋'},
{id:'mirofish',name:'MiroFish Agent',desc:'Workflow engine',status:'ready',icon:'🐟'},
{id:'registry',name:'Registry Agent',desc:'382 tools resolver',status:'ready',icon:'🔧'},
{id:'pages',name:'Pages Agent',desc:'174 HTML monitoring',status:'ready',icon:'📄'},
{id:'infra',name:'Infra Agent',desc:'Load, disk, memory, services',status:'ready',icon:'🖥️'},
{id:'ethica',name:'Ethica Agent',desc:'141K HCPs, DZ/MA/TN stats',status:'ready',icon:'🏥'},
{id:'sovereign',name:'Sovereign Agent',desc:'12 IA providers cascade',status:'ready',icon:'🧠'},
{id:'git',name:'Git Agent',desc:'Commit, push, status',status:'ready',icon:'📦'},
{id:'nonreg',name:'NonReg Agent',desc:'152/152 quality tests',status:'ready',icon:'🧪'},
{id:'scraper',name:'Scraper Agent',desc:'DabaDoc, CNAM, CROMC',status:'ready',icon:'🕷️'},
{id:'vault',name:'Vault Agent',desc:'Credentials, GOLD, wiki',status:'ready',icon:'🔐'},
];
const PROVIDERS = ['Cerebras-fast','Cerebras-think','Groq','Gemini','SambaNova','NVIDIA-NIM','Mistral','HF-Space','HF-Router','OpenRouter','GitHub-Models','CF-Workers'];
function renderAgents(){
// DYNAMIC: fetch live counts from API
fetch('/api/orchestrator-agents.php').then(r=>r.text().then(t=>{/* HTML_GUARD_V2_BATCH */var q=(t||"").trim();if(q.startsWith("<!DOCTYPE")||q.startsWith("<html")){return{error:"[HTTP "+r.status+"]",isHtmlError:true}}try{return JSON.parse(q)}catch(e){return{error:"JSON "+e.message}}})).then(d=>{
if(d.totals){
var s=document.getElementById('st-agents');if(s)s.textContent=d.totals.catalog_total||d.totals.realtime;
var t=document.getElementById('st-tools');if(t)t.textContent=d.totals.registry_tools;
var r2=document.getElementById('st-resolver');if(r2)r2.textContent=d.totals.registry_tools;
}
}).catch(()=>{});
const el=document.getElementById('agents-list');
el.innerHTML=AGENTS.map(a=>`<div class="agent${a.status==='running'?' active':''}" id="agent-${a.id}" onclick="focusAgent('${a.id}')">
<div class="dot ${a.status==='running'?'spin':a.status==='done'?'green':'green'}"></div>
<div class="info"><div class="name">${a.icon} ${a.name}</div><div class="desc">${a.desc}</div></div>
<div class="badge">${a.status}</div>
</div>`).join('');
}
function renderProviders(){
document.getElementById('providers-list').innerHTML=PROVIDERS.map(p=>
`<div class="conn"><span class="ic">⚡</span> ${p} <span class="st up">ON</span></div>`
).join('');
}
function setAgentStatus(id,status){
const a=AGENTS.find(x=>x.id===id);
if(a)a.status=status;
const el=document.getElementById('agent-'+id);
if(el){
const dot=el.querySelector('.dot');
const badge=el.querySelector('.badge');
dot.className='dot '+(status==='running'?'spin':status==='done'?'green':status==='error'?'red':'green');
badge.textContent=status;
if(status==='running')el.classList.add('active');
else el.classList.remove('active');
}
}
function addStep(num,title,body,status){
const orch=document.getElementById('orch-output');
const step=document.createElement('div');
step.className='step';
step.innerHTML=`<div class="step-header">
<div class="step-num ${status}">${status==='running'?'<div class="spinner"></div>':num}</div>
<div class="step-title">${title}</div>
<div class="step-time">${new Date().toLocaleTimeString()}</div>
</div>
<div class="step-body">${body}</div>`;
orch.appendChild(step);
orch.scrollTop=orch.scrollHeight;
return step;
}
function updateStep(step,num,body,status){
step.querySelector('.step-num').className='step-num '+status;
step.querySelector('.step-num').innerHTML=status==='done'?'✓':num;
step.querySelector('.step-body').innerHTML=body;
}
function formatResults(results){
let html='';
for(const[k,v]of Object.entries(results)){
const lines=typeof v==='object'?JSON.stringify(v,null,2):String(v);
html+=`<span class="key">[${k}]</span>\n`;
lines.split('\n').forEach(l=>{
if(l.includes('FAIL')||l.includes('error')||l.includes('DOWN'))html+=` <span class="err">${l}</span>\n`;
else if(l.includes('PASS')||l.includes('OK')||l.includes('active')||l.includes('152'))html+=` <span class="ok">${l}</span>\n`;
else html+=` <span class="val">${l}</span>\n`;
});
}
return html;
}
function clearOrch(){
document.getElementById('orch-output').innerHTML=`<div style="text-align:center;padding:60px 20px;color:var(--t3)">
<div style="font-size:48px;margin-bottom:16px">⚡</div>
<div style="font:600 16px var(--sans);color:var(--t2)">Ready for orchestration</div>
</div>`;
AGENTS.forEach(a=>setAgentStatus(a.id,'ready'));
}
function focusAgent(id){
runTask(id+' status');
}
// Health checks
async function healthCheck(){
try{
const r=await fetch('/api/wevia-autonomous.php',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({message:'ping'})});
const _t=await r.text();let d={};try{for(const _l of _t.split('\n')){if(_l.startsWith('data: ')&&!_l.includes('[DONE]')){d=JSON.parse(_l.substring(6));break;}}}catch(e){}
// Update stats from results
}catch(e){console.error('Task error:',e);document.getElementById('orch-output').innerHTML='<div style="color:var(--o);padding:20px">⚠️ Server recovering... Try again in 30s.<br><small>'+e.message+'</small></div>';}
// Service checks
const checks=[
['st-paperclip','https://paperclip.weval-consulting.com','up','down'],
['st-mirofish','https://mirofish.weval-consulting.com','up','down'],
];
// Simple CX check
try{
const r=await fetch('/api/cx.php',{method:'POST',body:'k=WEVADS2026&c='+btoa('echo OK'),headers:{'Content-Type':'application/x-www-form-urlencoded'}});
const t=await r.text();
document.getElementById('st-cx').textContent=t.trim()==='OK'?'OK':'ERR';
document.getElementById('st-cx').className='st '+(t.trim()==='OK'?'up':'down');
}catch(e){console.error('Task error:',e);document.getElementById('orch-output').innerHTML='<div style="color:var(--o);padding:20px">⚠️ Server recovering... Try again in 30s.<br><small>'+e.message+'</small></div>';
document.getElementById('st-cx').textContent='DOWN';
document.getElementById('st-cx').className='st down';
}
// Sovereign check
try{
const r=await fetch('/api/wevia-master-api.php',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({message:'providers'})});
const _pt=await r.text();let d={};try{for(const _l of _pt.split('\n')){if(_l.startsWith('data: ')&&!_l.includes('[DONE]')){d=JSON.parse(_l.substring(6));break;}}}catch(e){}
if(d.content&&d.content.includes('active')){
const m=d.content.match(/"active":\s*(\d+)/);
if(m)document.getElementById('st-providers').textContent=m[1];
}
}catch(e){console.error('Task error:',e);document.getElementById('orch-output').innerHTML='<div style="color:var(--o);padding:20px">⚠️ Server recovering... Try again in 30s.<br><small>'+e.message+'</small></div>';}
}
// Init
renderAgents();
renderProviders();
healthCheck();
setInterval(healthCheck,30000);
// Set service status to UP for known running services
['st-searxng','st-kuma','st-qdrant','st-vault','st-gitea','st-sentinel','st-paperclip','st-mirofish'].forEach(id=>{
const el=document.getElementById(id);
if(el){el.textContent='UP';el.className='st up';}
});
async function runTask(preset){
const input=document.getElementById('task-input');
const task=preset||input.value.trim();
if(!task)return;
input.value=task;
const orch=document.getElementById('orch-output');
orch.innerHTML='<div style="padding:20px;text-align:center"><div class="spinner"></div><br>Executing: '+task+'</div>';
try{
const r=await fetch('/api/wevia-autonomous.php',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({message:task})});
const text=await r.text();
const results=[];
for(const line of text.split('\n')){
if(line.startsWith('data: ')&&!line.includes('[DONE]')){
try{const d=JSON.parse(line.substring(6));if(d.type==='answer')results.push(d);}catch(e){}
}
}
if(!results.length){orch.innerHTML='<div style="padding:20px;color:#ff6b6b">No response — try again</div>';return;}
let h='';
for(const d of results){
const nm=(d.engine||'?').split('/').pop();
const tx=(d.text||'').replace(/\n/g,'<br>').replace(/^### \w+ /,'');
const err=tx.includes('timeout')||tx.includes('DOWN');
h+='<div style="margin:8px 0;padding:12px;background:rgba(0,229,255,.03);border:1px solid rgba(0,229,255,.1);border-radius:8px"><span style="color:#00e5ff;font-weight:600">['+nm+']</span><br>'+(err?'<span style="color:#ff6b6b">':'<span style="color:#b0bec5">')+tx+'</span></div>';
}
h+='<div style="margin-top:12px;padding:8px;color:#00e676;font-weight:600">'+results.filter(r=>!(r.text||'').includes('timeout')).length+'/'+results.length+' agents OK</div>';
orch.innerHTML=h;
}catch(e){orch.innerHTML='<div style="padding:20px;color:#ff6b6b">Error: '+e.message+'</div>';}
input.value='';
}
</script>
<script>(function(){var p=window.location.pathname;var pub=["/","/index.html","/wevia.html","/wevia-widget.html","/enterprise-model.html","/wevia","/login","/register.html","/agents-archi.html","/wevia-meeting-rooms.html","/director-center.html","/director-chat.html","/l99-brain.html","/agents-fleet.html","/value-streaming.html","/architecture.html","/openclaw.html","/l99-saas.html","/admin-saas.html","/agents-goodjob.html","/ai-benchmark.html","/oss-discovery.html","/paperclip.html","/agents-3d.html","/agents-alive.html","/agents-enterprise.html","/agents-hd.html","/agents-iso3d.html","/agents-sim.html","/agents-valuechain.html","/avatar-picker.html","/login.html","/register","/weval-login.html","/weval-login","/arsenal-login.html","/arsenal-login","/ethica-login.html","/ethica-login","/office-login.html","/office-login","/wtp-login.html","/wtp-login","/azure-reregister.html","/azure-reregister","/authentik-callback","/auth-callback","/reset-password.html","/reset-password","/signup.html","/signup"];var isPub=pub.indexOf(p)>=0||p.indexOf("/products/")===0||p.indexOf("/blog/")===0||p.indexOf("/service/")===0;if(isPub||document.getElementById("weval-gl"))return;var a=document.createElement("a");a.id="weval-gl";a.href="/logout";a.textContent="Logout";a.style.cssText="position:fixed;top:10px;right:12px;z-index:99990;padding:5px 10px;background:rgba(30,30,50,0.7);color:rgba(200,210,230,0.8);border:1px solid rgba(100,100,140,0.3);border-radius:6px;font:500 11px system-ui,sans-serif;text-decoration:none;opacity:0.6;cursor:pointer;backdrop-filter:blur(6px);transition:all .15s";a.onmouseover=function(){this.style.opacity="1";this.style.background="rgba(239,68,68,0.85)";this.style.color="white"};a.onmouseout=function(){this.style.opacity="0.6";this.style.background="rgba(30,30,50,0.7)";this.style.color="rgba(200,210,230,0.8)"};document.body.appendChild(a)})()</script><script>(function(){var p=window.location.pathname;var pub=["/","/index.html","/wevia.html","/wevia-widget.html","/enterprise-model.html","/wevia","/login","/register.html","/agents-archi.html","/wevia-meeting-rooms.html","/director-center.html","/director-chat.html","/l99-brain.html","/agents-fleet.html","/value-streaming.html","/architecture.html","/openclaw.html","/l99-saas.html","/admin-saas.html","/agents-goodjob.html","/ai-benchmark.html","/oss-discovery.html","/paperclip.html","/agents-3d.html","/agents-alive.html","/agents-enterprise.html","/agents-hd.html","/agents-iso3d.html","/agents-sim.html","/agents-valuechain.html","/avatar-picker.html","/login.html","/register","/weval-login.html","/weval-login","/arsenal-login.html","/arsenal-login","/ethica-login.html","/ethica-login","/office-login.html","/office-login","/wtp-login.html","/wtp-login","/azure-reregister.html","/azure-reregister","/authentik-callback","/auth-callback","/reset-password.html","/reset-password","/signup.html","/signup"];var isPub=pub.indexOf(p)>=0||p.indexOf("/products/")===0||p.indexOf("/blog/")===0||p.indexOf("/service/")===0;if(isPub||document.getElementById("weval-gl"))return;var a=document.createElement("a");a.id="weval-gl";a.href="/logout";a.textContent="Logout";a.style.cssText="position:fixed;top:10px;right:12px;z-index:99990;padding:5px 10px;background:rgba(30,30,50,0.7);color:rgba(200,210,230,0.8);border:1px solid rgba(100,100,140,0.3);border-radius:6px;font:500 11px system-ui,sans-serif;text-decoration:none;opacity:0.6;cursor:pointer;backdrop-filter:blur(6px);transition:all .15s";a.onmouseover=function(){this.style.opacity="1";this.style.background="rgba(239,68,68,0.85)";this.style.color="white"};a.onmouseout=function(){this.style.opacity="0.6";this.style.background="rgba(30,30,50,0.7)";this.style.color="rgba(200,210,230,0.8)"};document.body.appendChild(a)})()</script><script>(function(){var p=window.location.pathname;var pub=["/","/index.html","/wevia.html","/wevia-widget.html","/enterprise-model.html","/wevia","/login","/register.html","/agents-archi.html","/wevia-meeting-rooms.html","/director-center.html","/director-chat.html","/l99-brain.html","/agents-fleet.html","/value-streaming.html","/architecture.html","/openclaw.html","/l99-saas.html","/admin-saas.html","/agents-goodjob.html","/ai-benchmark.html","/oss-discovery.html","/paperclip.html","/agents-3d.html","/agents-alive.html","/agents-enterprise.html","/agents-hd.html","/agents-iso3d.html","/agents-sim.html","/agents-valuechain.html","/avatar-picker.html","/login.html","/register","/weval-login.html","/weval-login","/arsenal-login.html","/arsenal-login","/ethica-login.html","/ethica-login","/office-login.html","/office-login","/wtp-login.html","/wtp-login","/azure-reregister.html","/azure-reregister","/authentik-callback","/auth-callback","/reset-password.html","/reset-password","/signup.html","/signup"];var isPub=pub.indexOf(p)>=0||p.indexOf("/products/")===0||p.indexOf("/blog/")===0||p.indexOf("/service/")===0;if(isPub||document.getElementById("weval-gl"))return;var a=document.createElement("a");a.id="weval-gl";a.href="/logout";a.textContent="Logout";a.style.cssText="position:fixed;top:10px;right:12px;z-index:99990;padding:5px 10px;background:rgba(30,30,50,0.7);color:rgba(200,210,230,0.8);border:1px solid rgba(100,100,140,0.3);border-radius:6px;font:500 11px system-ui,sans-serif;text-decoration:none;opacity:0.6;cursor:pointer;backdrop-filter:blur(6px);transition:all .15s";a.onmouseover=function(){this.style.opacity="1";this.style.background="rgba(239,68,68,0.85)";this.style.color="white"};a.onmouseout=function(){this.style.opacity="0.6";this.style.background="rgba(30,30,50,0.7)";this.style.color="rgba(200,210,230,0.8)"};document.body.appendChild(a)})()</script><script>(function(){var p=window.location.pathname;var pub=["/","/index.html","/wevia.html","/wevia-widget.html","/enterprise-model.html","/wevia","/login","/register.html","/agents-archi.html","/wevia-meeting-rooms.html","/director-center.html","/director-chat.html","/l99-brain.html","/agents-fleet.html","/value-streaming.html","/architecture.html","/openclaw.html","/l99-saas.html","/admin-saas.html","/agents-goodjob.html","/ai-benchmark.html","/oss-discovery.html","/paperclip.html","/agents-3d.html","/agents-alive.html","/agents-enterprise.html","/agents-hd.html","/agents-iso3d.html","/agents-sim.html","/agents-valuechain.html","/avatar-picker.html","/login.html","/register","/weval-login.html","/weval-login","/arsenal-login.html","/arsenal-login","/ethica-login.html","/ethica-login","/office-login.html","/office-login","/wtp-login.html","/wtp-login","/azure-reregister.html","/azure-reregister","/authentik-callback","/auth-callback","/reset-password.html","/reset-password","/signup.html","/signup"];var isPub=pub.indexOf(p)>=0||p.indexOf("/products/")===0||p.indexOf("/blog/")===0||p.indexOf("/service/")===0;if(isPub||document.getElementById("weval-gl"))return;var a=document.createElement("a");a.id="weval-gl";a.href="/logout";a.textContent="Logout";a.style.cssText="position:fixed;top:10px;right:12px;z-index:99990;padding:5px 10px;background:rgba(30,30,50,0.7);color:rgba(200,210,230,0.8);border:1px solid rgba(100,100,140,0.3);border-radius:6px;font:500 11px system-ui,sans-serif;text-decoration:none;opacity:0.6;cursor:pointer;backdrop-filter:blur(6px);transition:all .15s";a.onmouseover=function(){this.style.opacity="1";this.style.background="rgba(239,68,68,0.85)";this.style.color="white"};a.onmouseout=function(){this.style.opacity="0.6";this.style.background="rgba(30,30,50,0.7)";this.style.color="rgba(200,210,230,0.8)"};document.body.appendChild(a)})()</script><script>(function(){var p=window.location.pathname;var pub=["/","/index.html","/wevia.html","/wevia-widget.html","/enterprise-model.html","/wevia","/login","/register.html","/agents-archi.html","/wevia-meeting-rooms.html","/director-center.html","/director-chat.html","/l99-brain.html","/agents-fleet.html","/value-streaming.html","/architecture.html","/openclaw.html","/l99-saas.html","/admin-saas.html","/agents-goodjob.html","/ai-benchmark.html","/oss-discovery.html","/paperclip.html","/agents-3d.html","/agents-alive.html","/agents-enterprise.html","/agents-hd.html","/agents-iso3d.html","/agents-sim.html","/agents-valuechain.html","/avatar-picker.html","/login.html","/register","/weval-login.html","/weval-login","/arsenal-login.html","/arsenal-login","/ethica-login.html","/ethica-login","/office-login.html","/office-login","/wtp-login.html","/wtp-login","/azure-reregister.html","/azure-reregister","/authentik-callback","/auth-callback","/reset-password.html","/reset-password","/signup.html","/signup"];var isPub=pub.indexOf(p)>=0||p.indexOf("/products/")===0||p.indexOf("/blog/")===0||p.indexOf("/service/")===0;if(isPub||document.getElementById("weval-gl"))return;var a=document.createElement("a");a.id="weval-gl";a.href="/logout";a.textContent="Logout";a.style.cssText="position:fixed;top:10px;right:12px;z-index:99990;padding:5px 10px;background:rgba(30,30,50,0.7);color:rgba(200,210,230,0.8);border:1px solid rgba(100,100,140,0.3);border-radius:6px;font:500 11px system-ui,sans-serif;text-decoration:none;opacity:0.6;cursor:pointer;backdrop-filter:blur(6px);transition:all .15s";a.onmouseover=function(){this.style.opacity="1";this.style.background="rgba(239,68,68,0.85)";this.style.color="white"};a.onmouseout=function(){this.style.opacity="0.6";this.style.background="rgba(30,30,50,0.7)";this.style.color="rgba(200,210,230,0.8)"};document.body.appendChild(a)})()</script>
<!-- ENRICHMENT: Dynamic Agent Fleet from API -->
<script>
(async function loadAgentFleet() {
try {
const r = await fetch("/api/agents-catalog-api.php");
/* HTML_GUARD_V2_BATCH */ const _t_d=await r.text(); let d=null; {var _q=(_t_d||"").trim();if(_q.startsWith("<!DOCTYPE")||_q.startsWith("<html")){d={error:"[HTTP "+(r.status||"?")+"] Backend indisponible",isHtmlError:true};}else{try{d=JSON.parse(_q)}catch(e){d={error:"[JSON] "+e.message}}}}
const fleet = document.querySelector(".fleet");
if (!fleet || !d.agents) return;
// Update header stats
const statEls = document.querySelectorAll(".stat .num");
if (statEls[0]) statEls[0].textContent = d.total; // AGENTS count
// Category labels
const catLabels = {
core: "🔧 CORE AGENTS",
claudecode: "🤖 CLAUDE CODE AGENTS",
deerflow: "🦌 DEERFLOW SKILLS",
hermes: "⚡ HERMES SKILLS",
superclaude: "🧬 SUPERCLAUDE",
skills: "⚡ WORKFLOW SKILLS"
};
// Add search
const search = document.createElement("div");
search.innerHTML = `<input type="text" id="agentSearch" placeholder="Rechercher ${d.total} agents..."
style="width:100%;padding:8px 12px;background:var(--bg3);border:1px solid var(--brd);border-radius:var(--r);color:var(--t1);font:400 11px var(--mono);margin-bottom:10px;outline:none">
<div style="display:flex;gap:4px;flex-wrap:wrap;margin-bottom:10px" id="catFilters"></div>`;
fleet.innerHTML = "";
fleet.appendChild(search);
// Add category filter buttons
const filters = document.getElementById("catFilters");
const allBtn = document.createElement("button");
allBtn.textContent = "ALL (" + d.total + ")";
allBtn.className = "cat-btn active";
allBtn.style.cssText = "padding:3px 8px;border-radius:4px;border:1px solid var(--cyan);background:rgba(6,214,160,.15);color:var(--cyan);font:500 9px var(--mono);cursor:pointer";
allBtn.onclick = () => filterAgents("");
filters.appendChild(allBtn);
for (const [cat, count] of Object.entries(d.categories)) {
const btn = document.createElement("button");
btn.textContent = (catLabels[cat]||cat).split(" ").pop() + " (" + count + ")";
btn.style.cssText = "padding:3px 8px;border-radius:4px;border:1px solid var(--brd);background:var(--bg3);color:var(--t2);font:500 9px var(--mono);cursor:pointer";
btn.onclick = () => filterAgents(cat);
filters.appendChild(btn);
}
// Render agents grouped by category
const agentContainer = document.createElement("div");
agentContainer.id = "agentList";
fleet.appendChild(agentContainer);
let currentCat = "";
for (const a of d.agents) {
if (a.cat !== currentCat) {
currentCat = a.cat;
const h = document.createElement("h2");
h.textContent = catLabels[a.cat] || a.cat;
h.style.cssText = "font:700 11px var(--mono);color:var(--cyan);margin:12px 0 6px;text-transform:uppercase;letter-spacing:1px";
h.dataset.cat = a.cat;
agentContainer.appendChild(h);
}
const el = document.createElement("div");
el.className = "agent";
el.dataset.cat = a.cat;
el.dataset.name = a.name.toLowerCase();
el.innerHTML = `<span class="dot green"></span>
<div class="info"><div class="name">${a.icon||"🤖"} ${a.name}</div><div class="desc">${a.desc}</div></div>
<span class="badge">${a.status}</span>`;
el.onclick = () => {
document.querySelector(".task-bar input").value = "Invoke " + a.name + ": ";
document.querySelector(".task-bar input").focus();
document.querySelectorAll(".agent").forEach(x => x.classList.remove("active"));
el.classList.add("active");
};
agentContainer.appendChild(el);
}
// Search filter
document.getElementById("agentSearch").oninput = function() {
const q = this.value.toLowerCase();
document.querySelectorAll("#agentList .agent").forEach(el => {
el.style.display = el.dataset.name.includes(q) || el.querySelector(".desc").textContent.toLowerCase().includes(q) ? "" : "none";
});
};
function filterAgents(cat) {
document.querySelectorAll("#agentList .agent, #agentList h2").forEach(el => {
if (!cat) { el.style.display = ""; return; }
el.style.display = el.dataset.cat === cat ? "" : "none";
});
}
console.log("Agent Fleet: " + d.total + " agents loaded");
} catch(e) { console.error("Agent fleet load error:", e); }
})();
</script>
<!-- CARTO_REMOVED -->
<!-- === OPUS UNIVERSAL DRILL-DOWN v1 19avr — append-only, doctrine #14 === -->
<script>
(function(){
if (window.__opusUniversalDrill) return; window.__opusUniversalDrill = true;
var d = document;
var m = d.createElement('div');
m.id = 'opus-udrill';
m.style.cssText = 'position:fixed;inset:0;background:rgba(0,0,0,0.82);backdrop-filter:blur(6px);display:none;align-items:center;justify-content:center;z-index:99995;padding:20px;cursor:pointer';
var inner = d.createElement('div');
inner.id = 'opus-udrill-in';
inner.style.cssText = 'max-width:900px;width:100%;max-height:90vh;overflow:auto;background:#0b0d15;border:1px solid rgba(99,102,241,0.35);border-radius:14px;padding:28px;cursor:default;box-shadow:0 20px 60px rgba(0,0,0,0.6);color:#e2e8f0;font:14px/1.55 Inter,system-ui,sans-serif';
inner.addEventListener('click', function(e){ e.stopPropagation(); });
m.appendChild(inner);
m.addEventListener('click', function(){ m.style.display='none'; });
d.addEventListener('keydown', function(e){ if(e.key==='Escape') m.style.display='none'; });
(d.body || d.documentElement).appendChild(m);
function openCard(card) {
// Clone card content + show close btn + increase font-size
var html = '<div style="display:flex;justify-content:flex-end;margin-bottom:14px"><button type="button" aria-label="✕ Fermer (Esc)" id="opus-udrill-close" style="padding:6px 14px;background:#171b2a;border:1px solid rgba(99,102,241,0.25);color:#e2e8f0;border-radius:8px;cursor:pointer;font-size:12px">✕ Fermer (Esc)</button></div>';
html += '<div style="transform-origin:top left;font-size:1.05em">' + card.outerHTML + '</div>';
inner.innerHTML = html;
d.getElementById('opus-udrill-close').onclick = function(){ m.style.display='none'; };
m.style.display = 'flex';
}
function wire(root) {
var sels = '.card,[class*="card"],.kpi,[class*="kpi"],.stat,[class*="stat"],.tile,[class*="tile"],.metric,[class*="metric"],.widget,[class*="widget"]';
var cards = root.querySelectorAll(sels);
for (var i = 0; i < cards.length; i++) {
var c = cards[i];
if (c.__opusWired) continue;
if (c.closest('button, a, input, select, textarea, #opus-udrill')) continue;
var r = c.getBoundingClientRect();
if (r.width < 60 || r.height < 40) continue;
c.__opusWired = true;
c.style.cursor = 'pointer';
c.setAttribute('role','button');
c.setAttribute('tabindex','0');
c.addEventListener('click', function(ev){
// If a more-specific drill is already active (e.g. pp-card custom), let it handle
if (ev.target.closest('[data-pp-id]') && window.__opusDrillInit) return;
if (ev.target.closest('a,button,input,select')) return;
ev.preventDefault(); ev.stopPropagation();
openCard(this);
});
c.addEventListener('keydown', function(ev){ if(ev.key==='Enter'||ev.key===' '){ev.preventDefault();openCard(this);} });
}
}
// Initial + mutation observer
var initRun = function(){ wire(d.body || d.documentElement); };
if (d.readyState === 'loading') d.addEventListener('DOMContentLoaded', initRun);
else initRun();
var mo = new MutationObserver(function(muts){
var newCard = false;
for (var i=0;i<muts.length;i++) if (muts[i].addedNodes.length) { newCard = true; break; }
if (newCard) initRun();
});
mo.observe(d.body || d.documentElement, {childList:true, subtree:true});
})();
</script>
<!-- === OPUS UNIVERSAL DRILL-DOWN END === -->
<script src="/api/archi-meta-badge.js" defer></script>
<!-- OPUS_v932f_DROID_LINK -->
<a href="/wevia-ia/droid.html" id="opus-droid-link" title="WEDROID v3.2" style="position:fixed;bottom:20px;right:20px;padding:7px 14px;background:rgba(16,185,129,0.15);color:#10b981;text-decoration:none;border-radius:18px;font-size:12px;font-weight:600;border:1px solid rgba(16,185,129,0.4);backdrop-filter:blur(10px);z-index:9997">Droid</a>
<script src="/api/a11y-auto-enhancer.js" defer></script>
<!-- WTP_UDOCK_V1 (Opus 21-avr) --><script src="/wtp-unified-dock.js" defer></script>
<script src="/opus-antioverlap-doctrine.js?v=1776776094" defer></script>
<script src="/api/weval-feature-tracker.js" defer></script>
<script src="/api/ambre-universal-chat.js" defer></script>
<!-- WAVE 265 · Factory pill cross-page (injected, position mesurée zéro overlap) -->
<a id="w265-factory-cross" href="/wevia-multiagent-dashboard.html" title="Factory Health Monitor (30 agents)"
style="position:fixed;top:12px;left:12px;padding:6px 12px;border-radius:14px;background:linear-gradient(135deg,rgba(34,211,238,.2),rgba(168,85,247,.15));border:1px solid rgba(34,211,238,.4);color:#67e8f9;font-size:11px;font-weight:700;text-decoration:none;display:inline-flex;align-items:center;gap:6px;z-index:9999;backdrop-filter:blur(10px);box-shadow:0 2px 8px rgba(0,0,0,.4)">
<span>🏭</span>
<span id="w265-factory-txt">Factory: ...</span>
</a>
<script>
/* w265 Factory auto-load */
(function(){
async function refresh(){
try {
const r = await fetch('/api/wevia-v83-business-kpi.php?action=summary', {cache:'no-store'}).then(r=>r.json()).catch(()=>null);
const el = document.getElementById('w265-factory-txt');
if(el && r && r.summary){
const s = r.summary;
const pct = s.data_completeness_pct || 0;
el.textContent = `Factory: ${pct}% (${s.ok || 0}/${s.total_kpis || 0})`;
}
} catch(e){ console.log('[w265] factory check err', e); }
}
refresh();
setInterval(refresh, 60000);
})();
</script>
<!-- /WAVE 265 Factory pill cross-page -->
<!-- DOCTRINE-60-UX-JS -->
<script id="doctrine60-ux-js-wevia-orchestrator">
const observer = new IntersectionObserver((entries) => {
entries.forEach((entry, index) => {
if (entry.isIntersecting) {
setTimeout(() => { entry.target.classList.add('visible'); }, index * 100);
}
});
}, { threshold: 0.1 });
document.querySelectorAll('.card, .panel, .btn, .kpi').forEach(el => observer.observe(el));
</script>
</body>
</html>