| "use strict";
|
| (() => {
|
| const config = window.__WOZ_CONFIG__ || {};
|
| const API_BASE = String(config.OS_URL || "").replace(/\/$/, "");
|
|
|
| const state = {
|
| health: null,
|
| knownEntries: new Set(),
|
| entrySeq: 0,
|
| soundEnabled: false,
|
| audioContext: null,
|
| };
|
|
|
| const $ = (id) => document.getElementById(id);
|
| const el = {
|
| agentOrb: $("agent-orb"),
|
| agentName: $("agent-name"),
|
| agentState: $("agent-state"),
|
| agentUptime: $("agent-uptime"),
|
| agentLatency: $("agent-latency"),
|
| agentNode: $("agent-node"),
|
| agentVersion: $("agent-version"),
|
| agentIntegrity: $("agent-integrity"),
|
| chainTerminal: $("chain-terminal"),
|
| chainStatus: $("chain-status"),
|
| chainTip: $("chain-tip"),
|
| streamDot: $("stream-dot"),
|
| immutableState: $("immutable-state"),
|
| entryCount: $("entry-count"),
|
| raceList: $("race-list"),
|
| raceSource: $("race-source"),
|
| vectorHealth: $("vector-health"),
|
| vectorRate: $("vector-rate"),
|
| vectorLastSeal: $("vector-last-seal"),
|
| vectorApi: $("vector-api"),
|
| soundToggle: $("sound-toggle"),
|
| cmdHistory: $("command-history"),
|
| magmaInput: $("magma-input"),
|
| footerSession: $("footer-session"),
|
| utcDate: $("utc-date"),
|
| utcClock: $("utc-clock"),
|
| };
|
|
|
| function api(path) { return `${API_BASE}${path}`; }
|
|
|
| async function request(path, options = {}, timeout = 8000) {
|
| const ctrl = new AbortController();
|
| const timer = setTimeout(() => ctrl.abort(), timeout);
|
| try {
|
| const res = await fetch(api(path), {
|
| ...options,
|
| signal: ctrl.signal,
|
| headers: {
|
| Accept: "application/json",
|
| ...(options.body ? { "Content-Type": "application/json" } : {}),
|
| ...options.headers,
|
| },
|
| });
|
| const body = await res.json().catch(() => ({}));
|
| if (!res.ok) throw new Error(body.message || body.error || `HTTP ${res.status}`);
|
| return body;
|
| } finally { clearTimeout(timer); }
|
| }
|
|
|
| function pick(obj, paths, fallback) {
|
| for (const p of paths) {
|
| const v = p.split(".").reduce((o, k) => o?.[k], obj);
|
| if (v !== undefined && v !== null) return v;
|
| }
|
| return fallback;
|
| }
|
|
|
| function formatUptime(v) {
|
| if (typeof v === "string") return v;
|
| const s = Math.max(0, v > 1_000_000 ? Math.floor(v / 1000) : Math.floor(Number(v || 0)));
|
| const h = String(Math.floor(s / 3600)).padStart(2, "0");
|
| const m = String(Math.floor((s % 3600) / 60)).padStart(2, "0");
|
| const r = String(s % 60).padStart(2, "0");
|
| return `${h}:${m}:${r}`;
|
| }
|
|
|
| function normalizeHealth(payload, latency) {
|
| const src = payload.data || payload;
|
| const status = String(pick(src, ["status", "health", "state"], "online")).toLowerCase();
|
| const online = !["offline", "down", "error", "failed", "unhealthy"].includes(status);
|
| return {
|
| online,
|
| status: online ? status.toUpperCase() : "OFFLINE",
|
| name: String(pick(src, ["agent.name", "agentName", "name"], "CIPHER")),
|
| uptime: formatUptime(pick(src, ["uptime", "system.uptime", "agent.uptime"], 0)),
|
| latency,
|
| node: String(pick(src, ["node", "nodeId", "instance", "agent.node"], "OS-01")),
|
| version: String(pick(src, ["version", "build.version", "agent.version"], "v2.2.0")),
|
| integrity: String(pick(src, ["integrity", "worm.integrity", "chain.integrity"], online ? "VERIFIED" : "UNVERIFIED")),
|
| agents: normalizeAgents(pick(src, ["agents", "race", "agentRace", "metrics.agents"], [])),
|
| };
|
| }
|
|
|
| function normalizeAgents(raw) {
|
| if (!Array.isArray(raw) || raw.length === 0) return [];
|
| return raw.map(a => ({
|
| name: String(a.name || a.agent || a.key || "AGENT").toUpperCase(),
|
| score: Math.min(100, Math.max(0, Number(a.score ?? a.value ?? a.decisions ?? 0))),
|
| }));
|
| }
|
|
|
|
|
| function tickClock() {
|
| const now = new Date();
|
| if (el.utcDate) el.utcDate.textContent = now.toISOString().slice(0, 10);
|
| if (el.utcClock) el.utcClock.textContent = now.toUTCString().slice(17, 25) + " UTC";
|
| }
|
| tickClock();
|
| setInterval(tickClock, 1000);
|
|
|
|
|
| async function pollHealth() {
|
| const t0 = performance.now();
|
| try {
|
| const raw = await request("/api/health");
|
| const latency = Math.round(performance.now() - t0);
|
| const h = normalizeHealth(raw, latency);
|
| applyHealth(h);
|
| } catch {
|
| applyHealth({ online: false, status: "OFFLINE", latency: "β", uptime: "--:--:--",
|
| node: "β", version: "β", integrity: "UNREACHABLE", agents: [] });
|
| }
|
| }
|
|
|
| function applyHealth(h) {
|
| state.health = h;
|
|
|
| if (el.agentOrb) {
|
| el.agentOrb.className = `agent-orb ${h.online ? "online" : "offline"}`;
|
| }
|
| if (el.agentName) el.agentName.textContent = h.name;
|
| if (el.agentState) {
|
| el.agentState.textContent = h.status;
|
| el.agentState.className = `state ${h.online ? "online" : "offline"}`;
|
| }
|
| if (el.agentUptime) el.agentUptime.textContent = h.uptime;
|
| if (el.agentLatency) el.agentLatency.textContent = typeof h.latency === "number" ? `${h.latency} MS` : String(h.latency);
|
| if (el.agentNode) el.agentNode.textContent = h.node;
|
| if (el.agentVersion) el.agentVersion.textContent = h.version;
|
| if (el.agentIntegrity) el.agentIntegrity.textContent = h.integrity;
|
|
|
|
|
| if (el.vectorHealth) el.vectorHealth.textContent = h.online ? "NOMINAL" : "DEGRADED";
|
| if (el.vectorApi) el.vectorApi.textContent = h.online ? "ONLINE" : "OFFLINE";
|
|
|
|
|
| if (h.agents.length > 0) renderRace(h.agents);
|
| }
|
|
|
| pollHealth();
|
| setInterval(pollHealth, 3000);
|
|
|
|
|
| let chainPollRate = 0;
|
| async function pollChain() {
|
| const candidates = ["/api/worm/entries", "/api/agents/history", "/api/worm/tail"];
|
| let data = null;
|
| for (const path of candidates) {
|
| try { data = await request(path, {}, 5000); if (data) break; } catch {}
|
| }
|
| if (!data) return;
|
|
|
| const entries = Array.isArray(data) ? data : (data.entries ?? data.results ?? []);
|
| chainPollRate++;
|
|
|
| if (el.streamDot) el.streamDot.className = "stream-dot live";
|
| if (el.chainStatus) el.chainStatus.textContent = "STREAMING";
|
|
|
| let added = 0;
|
| for (const entry of entries.slice(-20)) {
|
| const id = entry.id ?? entry.worm_entry_id ?? entry.decision_seal ?? JSON.stringify(entry).slice(0, 32);
|
| if (state.knownEntries.has(id)) continue;
|
| state.knownEntries.add(id);
|
| state.entrySeq++;
|
| appendChainLine(entry, id);
|
| added++;
|
| }
|
|
|
| if (added > 0) {
|
| beep(880, 0.05);
|
| const tip = entries.at(-1);
|
| const hash = tip?.seal ?? tip?.decision_seal ?? tip?.worm_entry_id ?? "β";
|
| if (el.chainTip) el.chainTip.textContent = String(hash).slice(0, 16);
|
| if (el.entryCount) el.entryCount.textContent = String(state.knownEntries.size);
|
| if (el.immutableState) el.immutableState.textContent = "CONFIRMED";
|
| if (el.vectorLastSeal) el.vectorLastSeal.textContent = String(hash).slice(0, 12) + "β¦";
|
| }
|
|
|
| const evPerMin = Math.round(chainPollRate * 2);
|
| if (el.vectorRate) el.vectorRate.textContent = `${evPerMin}/MIN`;
|
| }
|
|
|
| function appendChainLine(entry, id) {
|
| const seq = String(state.entrySeq).padStart(4, "0");
|
| const ts = (entry.created_at ?? entry.timestamp ?? entry.ts ?? new Date().toISOString()).slice(11, 23);
|
| const actor = entry.agent ?? entry.actor ?? entry.source ?? "SYSTEM";
|
| const evt = entry.event_type ?? entry.decision ?? entry.type ?? "SEAL";
|
| const hash = (entry.seal ?? entry.decision_seal ?? id ?? "").slice(0, 12);
|
|
|
| const line = document.createElement("div");
|
| line.className = "chain-line new-entry";
|
| line.innerHTML = `
|
| <span class="seq">${seq}</span>
|
| <span class="ts">${ts}</span>
|
| <span class="event">${actor}Β·${evt}</span>
|
| <span class="hash">${hash}β¦</span>
|
| `;
|
| if (el.chainTerminal) {
|
| const boot = el.chainTerminal.querySelector(".boot-line");
|
| if (boot) boot.remove();
|
| el.chainTerminal.appendChild(line);
|
| el.chainTerminal.scrollTop = el.chainTerminal.scrollHeight;
|
| }
|
| if (state.soundEnabled) beep(440 + (state.entrySeq % 8) * 55, 0.04);
|
| }
|
|
|
| pollChain();
|
| setInterval(pollChain, 5000);
|
|
|
|
|
| const STATIC_AGENTS = ["CIPHER","VAULT","SENTINEL","ATLAS","ORACLE","FORGE","NOVA","LOC"];
|
|
|
| function renderRace(agents) {
|
| if (!el.raceList) return;
|
| const list = agents.length > 0 ? agents : STATIC_AGENTS.map((n, i) => ({ name: n, score: Math.floor(Math.random() * 60 + 20) }));
|
| el.raceList.innerHTML = list.map(a => `
|
| <div class="race-row">
|
| <span class="race-name">${a.name}</span>
|
| <div class="race-track"><div class="race-fill" style="width:${a.score}%"></div></div>
|
| <span class="race-score">${a.score}</span>
|
| </div>
|
| `).join("");
|
| if (el.raceSource) el.raceSource.textContent = agents.length > 0 ? "SOURCE: HEALTH API" : "SOURCE: STATIC";
|
| }
|
|
|
| renderRace([]);
|
|
|
|
|
| function beep(freq = 440, gain = 0.1) {
|
| if (!state.soundEnabled) return;
|
| try {
|
| state.audioContext = state.audioContext ?? new AudioContext();
|
| const o = state.audioContext.createOscillator();
|
| const g = state.audioContext.createGain();
|
| o.type = "square";
|
| o.frequency.value = freq;
|
| g.gain.value = gain;
|
| o.connect(g);
|
| g.connect(state.audioContext.destination);
|
| o.start();
|
| g.gain.exponentialRampToValueAtTime(0.001, state.audioContext.currentTime + 0.08);
|
| o.stop(state.audioContext.currentTime + 0.08);
|
| } catch {}
|
| }
|
|
|
| if (el.soundToggle) {
|
| el.soundToggle.addEventListener("click", () => {
|
| state.soundEnabled = !state.soundEnabled;
|
| el.soundToggle.textContent = `[ SOUND: ${state.soundEnabled ? "ON " : "OFF"} ]`;
|
| el.soundToggle.ariaPressed = String(state.soundEnabled);
|
| if (state.soundEnabled) beep(660, 0.15);
|
| });
|
| }
|
|
|
|
|
| function appendHistory(line, cls = "muted") {
|
| if (!el.cmdHistory) return;
|
| const span = document.createElement("div");
|
| span.style.color = cls === "ok" ? "var(--green)" : cls === "err" ? "var(--danger)" : "var(--muted)";
|
| span.textContent = line;
|
| el.cmdHistory.appendChild(span);
|
| el.cmdHistory.scrollTop = el.cmdHistory.scrollHeight;
|
| }
|
|
|
| async function sendMagma() {
|
| if (!el.magmaInput) return;
|
| const cmd = el.magmaInput.value.trim();
|
| if (!cmd) return;
|
| el.magmaInput.value = "";
|
| appendHistory(`> ${cmd}`);
|
| try {
|
| const res = await request("/api/agents/ask", {
|
| method: "POST",
|
| body: JSON.stringify({ message: cmd, agent: "forge" }),
|
| }, 15000);
|
| const reply = res.reply ?? res.message ?? res.text ?? JSON.stringify(res);
|
| appendHistory(reply, "ok");
|
| beep(660, 0.1);
|
| } catch (err) {
|
| appendHistory(`ERR: ${err.message}`, "err");
|
| }
|
| }
|
|
|
| window.__wozSend = sendMagma;
|
|
|
| if (el.magmaInput) {
|
| el.magmaInput.addEventListener("keydown", e => {
|
| if (e.key === "Enter") { e.preventDefault(); sendMagma(); }
|
| });
|
| }
|
|
|
|
|
| if (el.footerSession) {
|
| const id = Math.random().toString(36).slice(2, 10).toUpperCase();
|
| el.footerSession.textContent = `SESSION: ${id}`;
|
| }
|
| })();
|
|
|