Spaces:
Running
Running
File size: 7,531 Bytes
b58e0b6 320c18f b58e0b6 320c18f b58e0b6 320c18f b58e0b6 320c18f b58e0b6 320c18f b58e0b6 320c18f b58e0b6 320c18f b58e0b6 320c18f b58e0b6 320c18f b58e0b6 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 | // Codex panel — click any chakra -> its codex (recipes/theses/formulas) opens in
// the side panel. Click a kernel dot -> that kernel's docs + recent live activity.
// Top-right "All Codices" -> unified search across all 5 chakras' codices.
// Doctrine v11 LOCKED. ZERO BANDAID — links are real; live activity shows honest state.
import { CHAKRAS, UNIVERSAL_KERNELS } from './config.js';
import { kernelEntry, lastHeartbeats } from './heartbeats.js';
let panel, body, closeBtn;
export function initCodex(){
panel = document.getElementById('panel');
body = document.getElementById('panelBody');
closeBtn = document.getElementById('panelClose');
closeBtn.onclick = closePanel;
document.getElementById('allCodices').onclick = openAllCodices;
addEventListener('keydown', e => { if (e.key==='Escape') closePanel(); });
}
function openPanel(){ panel.classList.add('open'); }
function closePanel(){ panel.classList.remove('open'); }
function chakraById(id){ return CHAKRAS.find(c => c.id===id); }
// ---------- chakra codex ----------
export function openChakraCodex(id){
const c = chakraById(id); if (!c) return;
const col = '#'+c.color.toString(16).padStart(6,'0');
const kernels = UNIVERSAL_KERNELS.map(k => `<span class="ktag">${k.name}</span>`).join('')
+ c.vertical.map(k => `<span class="ktag vert">${k.name}</span>`).join('');
body.innerHTML = `
<h2 style="color:${col}">${c.label}</h2>
<div class="sub">${c.glyph} · 9 kernels (7 universal + 2 vertical)</div>
<h3>Codex</h3>
${c.codex.map(x => `<a class="link" href="${x.href}" target="_blank" rel="noopener">${x.label}</a>`).join('')}
<h3>Kernels (wheel)</h3>
<div id="kernelList">${kernels}</div>
<h3>Live</h3>
<div class="kv" id="liveBox">polling ${c.label}…</div>
`;
openPanel();
pollChakraLive(c);
}
async function pollChakraLive(c){
const boxEl = document.getElementById('liveBox');
try {
const r = await fetch(c.health.url, { cache:'no-store' });
if (!r.ok){ boxEl.textContent = `health → HTTP ${r.status}`; return; }
let j; try { j = await r.json(); } catch(e){ boxEl.textContent='health → 200 (non-JSON)'; return; }
const bits = [];
if (j.status) bits.push(`status: <b>${j.status}</b>`);
if (j.version) bits.push(`version: ${j.version}`);
if (j.doctrine) bits.push(`doctrine: ${j.doctrine}`);
if (j.numbers) bits.push(`numbers: ${j.numbers.declarations}/${j.numbers.axioms}/${j.numbers.sorries}`);
else if (j.declarations!==undefined) bits.push(`decl: ${j.declarations} · sorries: ${j.sorries}`);
if (j.gates) bits.push(`gates: ${j.gates}`);
if (j.traceparent_propagating) bits.push('traceparent: LIVE');
boxEl.innerHTML = bits.length ? bits.join('<br>') : '200 OK (no detail fields)';
} catch(e){ boxEl.textContent = 'flagship unreachable (honest offline state)'; }
}
// ---------- kernel panel ----------
const STATUS_LABEL = { green:'● live', amber:'● degraded', red:'● offline' };
const STATUS_HEX = { green:'#34d399', amber:'#fbbf24', red:'#f87171' };
export function openKernelPanel(c, kernel, vertical){
const col = '#'+c.color.toString(16).padStart(6,'0');
const sub = vertical ? 'vertical kernel' : `universal kernel · substrate: ${kernel.substrate}`;
const e = kernelEntry(c.id, kernel.name);
const st = e ? e.status : 'red';
const stHex = STATUS_HEX[st] || '#6b7280';
const ago = (e && e.agoSec != null) ? `${e.agoSec}s ago` : '—';
const ticks = (e && e.ticks != null) ? e.ticks.toLocaleString() : '—';
const endpoint = `${c.base}/api/${c.id}/v3/kernels/${kernel.name.toLowerCase()}`;
body.innerHTML = `
<h2 style="color:${col}">${kernel.name}</h2>
<div class="sub">${c.label} · ${sub}</div>
<div class="kv" style="display:flex;gap:14px;flex-wrap:wrap;margin:8px 0 2px">
<span style="color:${stHex};font-weight:700">${STATUS_LABEL[st]||'●'}</span>
<span>last beat: <b>${ago}</b></span>
<span>signed receipts: <b>${ticks}</b></span>
</div>
<h3>What it does</h3>
<div class="kv">${kernel.does}</div>
${kernel.substrate ? `<h3>Substrate</h3><div class="kv">package: <b>${kernel.substrate}</b></div>` : ''}
<h3>Last 5 heartbeats</h3>
<div class="kv" id="hbBox">polling ${kernel.name}…</div>
<h3>Kernel endpoint</h3>
<a class="link" href="${endpoint}" target="_blank" rel="noopener">GET /api/${c.id}/v3/kernels/${kernel.name.toLowerCase()}</a>
<h3>Chakra codex</h3>
${c.codex.map(x => `<a class="link" href="${x.href}" target="_blank" rel="noopener">${x.label}</a>`).join('')}
<h3>Flagship health</h3>
<div class="kv" id="liveBox">polling ${c.label}…</div>
<p style="font-size:11px;color:#6b7c90;margin-top:18px">Each kernel is a perpetual OODA loop (observe→decide→act→sign) rooted in a hash-linked, DSSE-signed codex. The Ouroboros loop threads SIGN→GATE→CHAIN→MEMORY→REPLAY through every chakra. Doctrine v11 LOCKED (749/14/163).</p>
`;
openPanel();
pollKernelHeartbeats(c, kernel);
pollChakraLive(c);
}
async function pollKernelHeartbeats(c, kernel){
const box = document.getElementById('hbBox');
if (!box) return;
const beats = await lastHeartbeats(c.id, kernel.name, 5);
if (!document.getElementById('hbBox')) return; // panel changed while awaiting
if (!beats.length){ box.textContent = 'no heartbeats yet (or flagship unreachable — honest offline state)'; return; }
box.innerHTML = beats.map(b => {
// codex entries may wrap the receipt under .payload / .data / be the receipt itself
const rcpt = b.payload || b.data || b.receipt || b;
const tick = rcpt.tick != null ? `#${rcpt.tick}` : '';
const ts = rcpt.ts || b.ts || b.created_at || '';
const sum = rcpt.summary || rcpt.did_work === false ? (rcpt.summary || 'no-op') : (rcpt.summary || 'tick');
const signed = (rcpt.signed_payload || rcpt.signatures || (rcpt.signed_payload && rcpt.signed_payload.signatures)) ? '🔏' : '';
return `<div style="padding:6px 0;border-bottom:1px solid #ffffff10;font-size:12px">
<b>${tick}</b> <span style="color:#9fb0c4">${String(ts).replace('T',' ').replace('Z','')}</span> ${signed}<br>
<span style="color:#cfe0f2">${sum}</span></div>`;
}).join('');
}
// ---------- unified "All Codices" search ----------
function openAllCodices(){
const all = CHAKRAS.flatMap(c => c.codex.map(x => ({...x, chakra:c.label, color:c.color, id:c.id})));
body.innerHTML = `
<h2>All Codices</h2>
<div class="sub">Unified search across all 5 chakras (${all.length} codex links · 45 kernels)</div>
<input id="codexSearch" placeholder="filter recipes / formulas / theses…"
style="width:100%;padding:10px;border-radius:8px;border:1px solid #ffffff22;background:#0a0e14;color:#e8eef6;font-size:14px;margin-bottom:12px" />
<div id="codexResults"></div>
`;
openPanel();
const input = document.getElementById('codexSearch');
const out = document.getElementById('codexResults');
const render = (q='') => {
const ql = q.toLowerCase();
const rows = all.filter(x => (x.label+x.chakra).toLowerCase().includes(ql));
out.innerHTML = rows.map(x => {
const col = '#'+x.color.toString(16).padStart(6,'0');
return `<a class="link" href="${x.href}" target="_blank" rel="noopener">
<span style="color:${col};font-weight:700">${x.chakra}</span> · ${x.label}</a>`;
}).join('') || '<div class="kv">no match</div>';
};
render();
input.oninput = () => render(input.value);
input.focus();
}
|