← 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 &nbsp;|&nbsp; UPLINK OK &nbsp;|&nbsp; HERMES READY &nbsp;|&nbsp; $(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>