← back to Cncp Failures Mockups
public/v1-terminal.html
80 lines
<!doctype html><html><head>
<meta charset="utf-8"><title>v1 — Terminal / log-stream</title>
<style>
:root { --green:#00ff41; --amber:#ffb300; --red:#ff3939; --dim:#0c4a17; --bg:#000; --grid:#031b08; }
body { margin:0; background:var(--bg); color:var(--green); font-family: ui-monospace,'Menlo','Consolas',monospace; font-size:13px; line-height:1.5; padding:24px; min-height:100vh;
background-image: linear-gradient(rgba(0,255,65,0.04) 1px, transparent 1px); background-size: 100% 22px; }
.crt { text-shadow: 0 0 4px rgba(0,255,65,0.5); }
h1 { font-weight:700; font-size:18px; letter-spacing:2px; margin:0 0 4px; }
.meta { color:var(--dim); margin-bottom:18px; }
.hr { border-top:1px dashed var(--dim); margin:18px 0; }
.row { display:grid; grid-template-columns:18px 70px 90px 30px 28px 1fr; gap:10px; padding:3px 0; align-items:start; }
.row .sev { font-weight:700; }
.sev.high { color:var(--red); }
.sev.medium { color:var(--amber); }
.sev.low { color:var(--green); }
.src { color:#5fbf6f; }
.ev { color:var(--amber); }
.when { color:#3a7a47; }
.msg { color:#a0eaa6; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.head { color:var(--dim); border-bottom:1px solid var(--dim); padding-bottom:4px; margin-bottom:6px; }
.hermes { margin-top:28px; padding:12px; border:1px dashed var(--dim); border-radius:0; }
.hermes h2 { font-size:13px; margin:0 0 6px; letter-spacing:2px; font-weight:700; }
.hermes-row { display:grid; grid-template-columns:180px 1fr; gap:8px; }
.bar { display:inline-block; height:6px; vertical-align:middle; }
.bar.high { background:var(--red); }
.bar.med { background:var(--amber); }
.bar.low { background:var(--green); }
.blink { animation: blink 1.1s steps(2) infinite; }
@keyframes blink { 0%,49% { opacity:1; } 50%,100% { opacity:0; } }
.cursor { display:inline-block; width:8px; height:14px; background:var(--green); vertical-align:middle; }
</style>
</head><body class="crt">
<h1>CNCP // FAILURE STREAM <span class="blink">█</span></h1>
<div class="meta">$ tail -f /failures | UPLINK OK | HERMES READY | $(date)</div>
<div class="hr"></div>
<div class="row head"><div></div><div>SRC</div><div>PROCESS</div><div>EV</div><div>SEV</div><div>SUMMARY</div></div>
<div id="rows"></div>
<div class="hr"></div>
<div class="hermes">
<h2>HERMES-3 // CLASSIFIER</h2>
<div class="hermes-row"><div>status</div><div>ONLINE · hermes3:8b · 4.3GB · IN-MEM ✓</div></div>
<div class="hermes-row"><div>last 24h</div><div id="h-counts"></div></div>
<div class="hermes-row"><div>severity dist</div><div id="h-dist"></div></div>
<div class="hermes-row"><div>queue</div><div>0 pending · idle</div></div>
<div class="hermes-row"><div>recent</div><div id="h-recent"></div></div>
</div>
<script>
fetch('/data' + location.search).then(r=>r.json()).then(d => {
const sev = s => s==='high'?'<span class="sev high">HIG</span>': s==='medium'?'<span class="sev medium">MED</span>' : s==='low'?'<span class="sev low">LOW</span>' : '<span style="color:#444;">---</span>';
const ts = t => new Date(t).toISOString().slice(11,16);
const rows = d.failures.map(f => `
<div class="row">
<div class="when">${ts(f.lastSeen)}</div>
<div class="src">[${f.source.toUpperCase().slice(0,3)}]</div>
<div>${f.processName.slice(0,12)}</div>
<div class="ev">×${f.eventCount}</div>
${sev(f.severity)}
<div class="msg">${(f.lastLines||'').split('\\n')[0].slice(0,110)}</div>
</div>
`).join('');
document.getElementById('rows').innerHTML = rows;
const h = d.hermes;
document.getElementById('h-counts').textContent = `total:${h.last24h.total} · cls:${h.last24h.byType.classify} · chat:${h.last24h.byType.chat} · idea:${h.last24h.byType['idea-chat']} · ${h.last24h.avgLatencyMs}ms avg`;
const max = Math.max(1, h.last24h.bySev.high, h.last24h.bySev.medium, h.last24h.bySev.low);
document.getElementById('h-dist').innerHTML = `
H<span class="bar high" style="width:${100*h.last24h.bySev.high/max}px"></span> ${h.last24h.bySev.high} ·
M<span class="bar med" style="width:${100*h.last24h.bySev.medium/max}px"></span> ${h.last24h.bySev.medium} ·
L<span class="bar low" style="width:${100*h.last24h.bySev.low/max}px"></span> ${h.last24h.bySev.low}`;
document.getElementById('h-recent').innerHTML = h.recent.slice(0,5).map(c => {
const ok = c.ok ? '✓' : '✗';
const col = c.ok ? 'var(--green)' : 'var(--red)';
return `<div style="color:${col}">${ok} ${new Date(c.ts).toISOString().slice(11,16)} ${c.type.padEnd(10)} ${c.target.slice(0,40)} ${(c.latencyMs/1000).toFixed(1)}s</div>`;
}).join('');
});
</script>
</body></html>