/* Oracle7 Workbench - page logic. Talks only to the local server that served it (127.0.0.1). */ (function () { "use strict"; const $ = id => document.getElementById(id); const esc = s => String(s == null ? "" : s).replace(/[&<>"']/g, c => ({ "&": "&", "<": "<", ">": ">", '"': """, "'": "'" }[c])); const newId = () => (crypto.getRandomValues(new Uint32Array(2)).join("") + "abcdefgh").replace(/[^0-9a-z]/g, "").slice(0, 16); const store = { get(k) { try { return localStorage.getItem(k); } catch (e) { return null; } }, set(k, v) { try { localStorage.setItem(k, v); } catch (e) { /* private mode */ } } }; // the conversation id is also the core's session: reopening a conversation carries on its context let SID = /^[a-z0-9]{6,40}$/.test(store.get("o7wb.conv") || "") ? store.get("o7wb.conv") : newId(); store.set("o7wb.conv", SID); const turns = []; let head = "", explorer = null, specData = null, pendingExamples = [], filmTurns = new Set(), filmSeen = new Set(); async function api(path, body) { const r = await fetch(path, body === undefined ? {} : { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(body) }); const j = await r.json().catch(() => ({ error: "bad reply" })); if (!r.ok) throw new Error(j.error || ("HTTP " + r.status)); return j; } // ------------------------------------------------------------------ log pane function log(kind, text, cls) { const li = document.createElement("li"); const t = new Date().toTimeString().slice(0, 8); li.innerHTML = `${esc(kind)}${esc(text)}`; const ol = $("log"); ol.appendChild(li); while (ol.children.length > 400) ol.removeChild(ol.firstChild); ol.scrollTop = ol.scrollHeight; } $("log-clear").onclick = () => { $("log").innerHTML = ""; }; // ------------------------------------------------------------------ diagram try { explorer = O7Explorer($("diagram"), { mode: "improve", select: "L2", palette: { accent: 0x946d1e, lit: 0xc0602e, fresh: 0xc0602e, spec: 0x5c4416, hazard: 0xc49132, store: 0x2a3b52 }, onSelect(id) { const s = O7Explorer.data.STAGES.find(x => x.id === id); if (s) log("diagram", s.name + ": " + s.blurb); } }); } catch (e) { $("diagram").insertAdjacentHTML("beforeend", `

The diagram needs WebGL (${esc(e.message)}).

`); } document.querySelectorAll(".views [data-view]").forEach(b => b.onclick = () => { document.querySelectorAll(".views [data-view]").forEach(x => x.classList.toggle("on", x === b)); explorer && explorer.setView(b.dataset.view); }); let allLabels = false; $("labels-all").onclick = () => { allLabels = !allLabels; explorer && explorer.setShowAll(allLabels); $("labels-all").classList.toggle("on", allLabels); }; // ------------------------------------------------------------------ state async function refreshState() { const s = await api("/api/state"); head = s.head; $("f-head").textContent = "core " + String(s.head).replace("oracle_release_runtime_", ""); $("f-yours").textContent = s.yours.length + " of yours"; $("f-journal").textContent = s.journal ? "gap journal on" : "gap journal off"; $("f-journal").classList.toggle("on", s.journal); $("g-on").checked = s.journal; s.yours.forEach(id => explorer && explorer.addModule("S", "Yours: " + id)); return s; } // ------------------------------------------------------------------ ask function renderAnswer(text) { const t = String(text || ""); if (t.includes("```")) return t.split("```").map((p, i) => i % 2 ? `
${esc(p.replace(/^[a-z]*\n/, ""))}
` : esc(p)).join(""); const m = t.match(/^([\s\S]*?)((?:^|\n)(?:def |import |from |class )[\s\S]*)$/); return m ? esc(m[1]) + `
${esc(m[2].replace(/^\n/, ""))}
` : esc(t); } const stepNames = tr => (tr || []).filter(x => x[1]).map(x => x[1]); // one turn's answer, its path and its controls: used live and when a saved conversation is reopened function renderTurn(box, t, live) { const declined = t.status !== "answered"; box.classList.toggle("declined", declined); box.querySelector(".a").className = "a"; box.querySelector(".a").innerHTML = renderAnswer(t.response || (declined ? "(declined)" : "")); const lit = live && explorer ? explorer.trace(t.trace, declined) : []; const mine = /^yours:([a-z0-9-]+)/.exec(t.path || ""); const when = t.t ? new Date(t.t * 1000).toLocaleString([], { dateStyle: "medium", timeStyle: "short" }) + " · " : ""; box.insertAdjacentHTML("beforeend", `${t.why ? `
${esc(t.why)}
` : ""}
${esc(when)}${esc(t.status)} · ${t.ms} ms` + `${esc((lit.length ? lit.map(x => x[1]) : stepNames(t.trace)).join(" → "))}${mine ? `your specialist: ${esc(mine[1])}` : ""}` + `
`); box.querySelector('[data-act="trace"]').onclick = () => explorer && explorer.trace(t.trace, declined); box.querySelector('[data-act="film"]').onclick = () => { filmTurns = new Set([t.n]); showTab("film"); renderFilmList(); record(); }; box.querySelector('[data-act="raw"]').onclick = () => log("route", t.path); if (mine && live) { // marks teach your own specialists (tool specialists learn from them) box.querySelector(".meta").insertAdjacentHTML("beforeend", ``); const mark = async right => { const f = await api("/api/feedback", { path: t.path, response: t.response, q: t.q, right }); log("learn", f.learned ? `${mine[1]}: ${f.tool || "tool"} marked ${right ? "right" : "wrong"}; re-checking its lane` : f.note, f.learned ? "live" : ""); box.querySelectorAll('[data-act="right"],[data-act="wrong"]').forEach(b => b.disabled = true); }; box.querySelector('[data-act="right"]').onclick = () => mark(true); box.querySelector('[data-act="wrong"]').onclick = () => mark(false); } return lit; } function turnBox(q) { const hello = $("thread").querySelector(".hello"); if (hello) hello.hidden = true; const box = document.createElement("div"); box.className = "turn"; box.innerHTML = `
${esc(q)}
reading…
`; $("thread").appendChild(box); return box; } async function ask(text, asQuestion) { text = text.trim(); if (!text) return; if (text.startsWith("/") && !asQuestion) { $("q").value = ""; return command(text); } const box = turnBox(text); $("thread").scrollTop = $("thread").scrollHeight; $("q").value = ""; $("ask").querySelector("button").disabled = true; log("ask", text, "live"); try { const r = await api("/api/chat", { text, sid: SID }); const declined = r.status !== "answered"; const t = { q: text, ...r, t: Math.floor(Date.now() / 1000), n: turns.length + 1 }; turns.push(t); const lit = renderTurn(box, t, true); log(declined ? "declined" : "answered", `${r.ms} ms · ${lit.map(x => x[0] + ": " + x[1]).join(" → ") || r.path}`, declined ? "no" : "ok"); if (declined && r.why_kind) log("why", r.why_kind + " - " + r.why); renderFilmList(); loadConvs(); } catch (e) { box.querySelector(".a").textContent = "Error: " + e.message; log("error", e.message, "no"); } finally { $("ask").querySelector("button").disabled = false; $("thread").scrollTop = $("thread").scrollHeight; } } $("ask").onsubmit = e => { e.preventDefault(); ask($("q").value); }; $("q").addEventListener("keydown", e => { if (e.key === "Enter" && !e.shiftKey) { e.preventDefault(); ask($("q").value); } }); document.querySelectorAll(".tries button").forEach(b => b.onclick = () => ask(b.textContent)); // ------------------------------------------------------------------ tabs function showTab(name) { document.querySelectorAll(".tabs button").forEach(b => b.classList.toggle("on", b.dataset.tab === name)); document.querySelectorAll(".tab").forEach(t => t.classList.toggle("on", t.id === "t-" + name)); if (name === "gaps") loadGaps(); if (name === "build" || name === "share") loadYours(); if (name === "film") renderFilmList(); clearInterval(snTimer); if (name === "sensors") { loadSensors(); snTimer = setInterval(() => { if (!document.hidden) loadSensors(); }, 15000); } } document.querySelectorAll(".tabs button").forEach(b => b.onclick = () => showTab(b.dataset.tab)); // ------------------------------------------------------------------ specialists const md = s => esc(s).split(/\n{2,}/).map(block => { if (/^#{1,3} /.test(block)) return block.replace(/^(#{1,3}) (.*)$/gm, (m, h, t) => `${t}`); if (/^- /m.test(block)) return ""; return `

${block}

`; }).join("").replace(/\*\*(.+?)\*\*/g, "$1").replace(/`([^`]+)`/g, "$1"); let group = "All"; function renderSpecs() { const f = $("s-find").value.trim().toLowerCase(); const items = specData.items.filter(x => (group === "All" || x.group === group) && (!f || (x.name + " " + x.id + " " + x.takes.join(" ")).toLowerCase().includes(f))); const yours = group === "All" || group === "Yours" ? specData.yours.filter(x => !f || x.id.includes(f)) : []; $("s-list").innerHTML = yours.map(x => `
${esc(x.name)}${x.state}yours · ${esc(x.note || "built in this workbench")}
`).join("") + items.slice(0, 400).map(x => `
${esc(x.name)}` + `${x.heldout ? `${x.heldout[0]}/${x.heldout[2]} vs core ${x.heldout[1]}` : ""}` + `${esc(x.group)} · ${esc(x.takes.join(", ") || x.id)}
`).join("") + (items.length ? "" : `

No specialist matches.

`); $("s-list").querySelectorAll("[data-id]").forEach(el => el.onclick = () => openCard(el.dataset.id)); $("s-list").querySelectorAll("[data-mine]").forEach(el => el.onclick = () => { showTab("build"); openEditor(el.dataset.mine); }); } async function openCard(id) { const x = specData.items.find(i => i.id === id); const c = $("s-card"); c.hidden = false; let body = ""; if (x.card) { try { body = md((await api("/api/card?id=" + encodeURIComponent(x.card))).md); } catch (e) { body = ""; } } if (!body) body = `

${esc(x.name)}

${x.group === "Relation readers" ? "Reads one family of Wikidata relations (" + esc(x.takes.join(", ")) + ") from the relation store and answers with the record it read, both ends with ids." : "Takes: " + esc(x.takes.join(", "))}

`; c.innerHTML = body + (x.heldout ? `

Held-out exam, seen once: ${x.heldout[0]} of ${x.heldout[2]} right with it, ${x.heldout[1]} with the core alone. Admitted ${esc(x.admitted)}.

` : ""); c.scrollIntoView({ block: "nearest" }); log("card", x.name); } async function loadSpecs() { specData = await api("/api/specialists"); const counts = {}; specData.items.forEach(x => { counts[x.group] = (counts[x.group] || 0) + 1; }); const gs = [["All", specData.items.length]].concat(Object.entries(counts).sort((a, b) => b[1] - a[1])).concat([["Yours", specData.yours.length]]); $("s-groups").innerHTML = gs.map(([g, n]) => ``).join(""); $("s-groups").querySelectorAll("button").forEach(b => b.onclick = () => { group = b.dataset.g; $("s-groups").querySelectorAll("button").forEach(x => x.classList.toggle("on", x === b)); renderSpecs(); }); $("f-spec").textContent = specData.items.length + " specialists"; renderSpecs(); } $("s-find").oninput = renderSpecs; async function loadSystems() { const s = await api("/api/systems"); $("sys-about").textContent = s.about; $("sys-list").innerHTML = s.items.map(x => `

${esc(x.name)}${esc(x.id)}

${esc(x.does)}

runs on: ${esc(x.runs)} · for: ${esc(x.use)}
`).join(""); } // ------------------------------------------------------------------ build let edId = null, edFile = null; async function loadYours() { specData = await api("/api/specialists"); const rows = specData.yours.map(x => `
${esc(x.name)}${x.state}${esc(x.id)}${x.note ? " · " + esc(x.note) : ""}
`).join("") || `

None yet. Start one, or add the worked example.

`; $("b-list").innerHTML = rows; $("b-list").querySelectorAll("[data-id]").forEach(el => el.onclick = () => openEditor(el.dataset.id)); $("sh-list").innerHTML = specData.yours.map(x => `
${esc(x.name)}${x.state}` + ` ` + (x.state === "admitted" ? ` ` + ` ` : "") + `
`).join("") || `

Build or import a specialist first.

`; $("sh-list").querySelectorAll("[data-pack]").forEach(b => b.onclick = () => pack(b.dataset.pack)); $("sh-list").querySelectorAll("[data-reg]").forEach(b => b.onclick = () => solanaRecord(b.dataset.reg, "register")); $("sh-list").querySelectorAll("[data-att]").forEach(b => b.onclick = () => solanaRecord(b.dataset.att, "attest")); $("sh-list").querySelectorAll("[data-chk]").forEach(b => b.onclick = () => solanaCheck(b.dataset.chk)); } async function openEditor(id, file) { const r = await api("/api/files?id=" + encodeURIComponent(id)); edId = id; $("b-editor").hidden = false; $("b-title").textContent = id; const st = r.status; $("b-state").className = "state " + st.state; $("b-state").textContent = st.state; const files = r.files.filter(f => !/^(verdict_|shared_verdict_|exam_log)/.test(f)); const organ = files.find(f => /^organ_/.test(f)); file = file || edFile && files.includes(edFile) && edId === id ? file || edFile : organ || files[0]; $("b-files").innerHTML = files.map(f => ``).join(""); $("b-files").querySelectorAll("button").forEach(b => b.onclick = () => openEditor(id, b.dataset.f)); edFile = file; $("b-text").value = (await api(`/api/file?id=${encodeURIComponent(id)}&name=${encodeURIComponent(file)}`)).text; renderVerdict(st.verdict); } async function save() { if (!edId) return; const r = await api("/api/file", { id: edId, name: edFile, text: $("b-text").value }); $("b-state").className = "state " + r.status.state; $("b-state").textContent = r.status.state; log("saved", `${edId}/${edFile}${r.status.state === "changed" ? " - changed after its exam: out of your model until a new held-out set passes" : ""}`, "live"); refreshState(); loadYours(); } $("b-save").onclick = save; $("b-text").addEventListener("keydown", e => { if (e.key === "Tab") { e.preventDefault(); const t = e.target, s = t.selectionStart; t.setRangeText(" ", s, t.selectionEnd, "end"); } if ((e.ctrlKey || e.metaKey) && e.key === "s") { e.preventDefault(); save(); } }); function renderVerdict(v) { if (!v) { $("b-verdict").innerHTML = `

No exam yet. The dev exam is free to repeat; the held-out exam uses its items once.

`; return; } const ok = c => c ? `PASS` : `FAIL`; const gain = v.with_specialist.ok - v.head.ok, wrongCap = Math.max(1, Math.floor(0.02 * v.n)); $("b-verdict").innerHTML = `
${esc(v.split === "heldout" ? "HELD-OUT" : "DEV")} EXAM · ${esc(v.decision)} · ${esc(v.time)}
` + `` + `` + `` + `` + `` + `
Domain${ok(gain >= v.gain_needed)}${v.with_specialist.ok}/${v.n} with it, ${v.head.ok}/${v.n} core alone: gain ${gain}, needs ${v.gain_needed}
No false yes${ok(v.with_specialist.fy <= v.head.fy)}${v.with_specialist.fy} must-decline answered (core: ${v.head.fy})
Few wrong${ok(v.with_specialist.wrong <= wrongCap)}${v.with_specialist.wrong} answered wrong, cap ${wrongCap}
Stays in lane${ok(v.core.taken <= v.core.cap)}takes ${v.core.taken} of ${v.core.n} general questions, cap ${v.core.cap}${v.core.examples.length ? ": " + esc(v.core.examples.slice(0, 3).join(" | ")) : ""}
Self${ok(v.self_ok)}identity questions stay the core's
Budget${ok(v.p50_ms <= v.budget_ms)}median ${v.p50_ms} ms, budget ${v.budget_ms} ms
` + (v.fails.length ? `
NOT RIGHT (${v.fails.length})
${v.fails.map(f => ``).join("")}
${esc(f.q)}expected ${esc(f.expected)}${esc(f.by)}: ${esc(f.got || f.status)}
` : ""); } async function exam(split) { if (!edId) return; if (split === "heldout" && !confirm("Run the held-out exam? Its items are used once: the same held-out set cannot be run again.")) return; await save(); try { await api("/api/exam", { id: edId, split }); } catch (e) { log("exam", e.message, "no"); $("b-prog").textContent = e.message; return; } log("exam", `${edId}: ${split} exam started`, "live"); const id = edId; const poll = async () => { const p = await api("/api/exam?id=" + encodeURIComponent(id)); if (p.state === "running") { $("b-prog").textContent = `${p.phase || ""} ${p.done || 0}/${p.total || "?"}`; setTimeout(poll, 800); return; } if (p.state === "error") { $("b-prog").textContent = p.error; log("exam", id + ": " + p.error, "no"); return; } $("b-prog").textContent = p.result ? p.result.decision : ""; if (p.result) { renderVerdict(p.result); log("verdict", `${id} ${p.result.split}: ${p.result.decision}${p.result.reasons.length ? " - " + p.result.reasons.join("; ") : ""}`, p.result.decision === "ADMIT" || p.result.decision === "WOULD PASS" ? "ok" : "no"); } if (p.result && p.result.decision === "ADMIT" && p.result.split !== "dev") { explorer && explorer.addModule("S", "Yours: " + id); explorer && explorer.trace([["S", "Yours: " + id]], false); log("grow", `${id} joined your model; the diagram has a new node`, "live"); } refreshState(); loadYours(); openEditor(id, edFile); }; poll(); } $("b-dev").onclick = () => exam("dev"); $("b-held").onclick = () => exam("heldout"); $("b-new").onsubmit = async e => { e.preventDefault(); try { const r = await api("/api/new", { id: $("b-id").value.trim(), name: $("b-name").value.trim(), words: $("b-words").value, examples: pendingExamples }); pendingExamples = []; log("new", "specialist " + r.id + " scaffolded in workbench/local/specialists/" + r.id, "live"); $("b-new").reset(); await loadYours(); openEditor(r.id); } catch (err) { log("new", err.message, "no"); alert(err.message); } }; $("b-example").onclick = async () => { try { const r = await api("/api/example", {}); log("new", "added the worked example: " + r.id, "live"); await loadYours(); openEditor(r.id); } catch (err) { log("example", err.message, "no"); } }; // ------------------------------------------------------------------ gaps async function loadGaps() { const g = await api("/api/gaps"); $("g-on").checked = g.on; if (!g.turns) { $("g-list").innerHTML = `

${g.on ? "The journal is on. Ask questions and the gaps appear here." : "The journal is off."}

`; return; } $("g-list").innerHTML = `

${g.turns} turns kept, ${g.declined} declined.

` + g.groups.map(gr => `
${esc(gr.kind)} · ${gr.count}` + (gr.themes.length ? gr.themes.map((t, i) => `
“${esc(t.word)}” · ${t.count} questions
${esc(t.examples.join(" | "))}
`).join("") : `
${esc(gr.examples.join(" | "))}
`) + `
`).join(""); $("g-list").querySelectorAll("button[data-k]").forEach(b => b.onclick = () => { const t = g.groups.find(x => x.kind === b.dataset.k).themes[+b.dataset.i]; pendingExamples = t.examples; showTab("build"); $("b-id").value = t.word.replace(/[^a-z0-9-]/g, ""); $("b-name").value = t.word[0].toUpperCase() + t.word.slice(1); $("b-words").value = t.word; $("b-id").focus(); log("gap", `starting a specialist for "${t.word}" with ${t.examples.length} of your questions as dev items`, "live"); }); } $("g-on").onchange = async () => { const r = await api("/api/journal", { on: $("g-on").checked }); log("journal", r.on ? "on: kept on this machine only" : "off", "live"); refreshState(); loadGaps(); }; $("g-clear").onclick = async () => { if (!confirm("Delete the gap journal from this machine?")) return; await api("/api/journal/clear", {}); log("journal", "deleted", "live"); loadGaps(); }; // ------------------------------------------------------------------ code $("e-style").onchange = () => { $("e-voice").hidden = $("e-style").value !== "custom"; }; $("e-write").onclick = async () => { const topic = $("e-topic").value.trim(); if (!topic) { $("e-res").textContent = "name a topic"; return; } const body = { topic, length: $("e-length").value, level: $("e-level").value, depth: $("e-depth").value, style: $("e-style").value, voice_text: $("e-style").value === "custom" ? $("e-voice").value : "" }; $("e-res").textContent = "composing from the record…"; $("e-out").hidden = true; log("essay", topic, "live"); try { const r = await api("/api/essay", body); if (r.error) { $("e-res").textContent = r.error; return; } if (!r.sentences) { $("e-res").textContent = "no records about that topic, so no essay"; log("essay", "nothing on record: " + topic, "no"); return; } const band = r.level_band[1] >= 30 ? `grade ${r.level_band[0]}+` : `grades ${r.level_band[0]}-${r.level_band[1]}`; $("e-res").textContent = `${r.sentences} sentences from ${r.records_used} records · ${r.faithful} of ${r.sentences} checked word for word against their sources · reading grade ${r.reading_grade} (asked for ${band}${r.level_reached ? "" : "; the record could not get closer"}) · ${r.ms} ms · no language model`; $("e-out").innerHTML = md(r.essay_md); $("e-out").hidden = false; log("essay", `${topic}: ${r.sentences} sentences, grade ${r.reading_grade}, ${r.faithful}/${r.sentences} faithful`, "ok"); } catch (e) { $("e-res").textContent = e.message; } }; $("c-compose").onclick = async () => { const what = $("c-what").value.trim(), i = $("c-in").value.trim(), o = $("c-out").value.trim(); const prompt = `Write a Python function${what ? " to " + what.replace(/^(to |that )/, "") : ""}${i && o ? ", so " + i + " becomes " + o : ""}`; $("c-res").textContent = "composing…"; log("code", prompt, "live"); try { const r = await api("/api/chat", { text: prompt, sid: SID + "code", nokeep: true }); const t = String(r.response || ""), m = t.match(/```(?:python)?\n?([\s\S]*?)```/) || t.match(/((?:^|\n)(?:def |import |from )[\s\S]*)$/); if (r.status !== "answered" || !m) { $("c-res").textContent = "declined: " + (r.why || t.slice(0, 160)); log("code", "declined: " + r.path, "no"); return; } const code = m[1].trim(); $("c-code").value = code; const fn = (code.match(/def\s+([A-Za-z_]\w*)\s*\(/) || [])[1]; if (fn && i && o && !$("c-tests").value.trim()) $("c-tests").value = `assert ${fn}(${i}) == ${o}`; $("c-res").textContent = "composed; " + (r.response.split("\n")[0] || "").slice(0, 120); log("code", "composed " + (fn || "a function") + " via " + r.path, "ok"); } catch (e) { $("c-res").textContent = e.message; } }; $("c-run").onclick = async () => { $("c-res").textContent = "running…"; const r = await api("/api/code/run", { code: $("c-code").value, tests: $("c-tests").value }); $("c-res").textContent = r.ok ? "all tests passed" : "failed"; $("c-out-text").hidden = false; $("c-out-text").textContent = r.output; log("tests", r.ok ? "all tests passed" : "failed: " + r.output.trim().split("\n").slice(-1)[0], r.ok ? "ok" : "no"); }; [$("c-code"), $("c-tests")].forEach(t => t.addEventListener("keydown", e => { if (e.key === "Tab") { e.preventDefault(); t.setRangeText(" ", t.selectionStart, t.selectionEnd, "end"); } })); // ------------------------------------------------------------------ film (made in the browser; nothing uploaded) function renderFilmList() { if (!turns.length) { $("f-list").innerHTML = `

Ask something first; each answer can be filmed.

`; return; } turns.forEach(t => { if (!filmSeen.has(t.n)) { filmSeen.add(t.n); filmTurns.add(t.n); } }); // new answers start ticked $("f-list").innerHTML = turns.map(t => ``).join(""); $("f-list").querySelectorAll("input").forEach(c => c.onchange = () => { c.checked ? filmTurns.add(+c.dataset.n) : filmTurns.delete(+c.dataset.n); }); } // the film shows the answer without the chat's internal markers ([ev:direct], [enwiki_...], [specialist]) const clean = t => String(t || "").replace(/\[(?:ev|vessel):[^\]]*\]\s*/g, "").replace(/\s*\[(?:enwiki|simplewiki|dbpedia)_[0-9a-f]+\]/g, "").replace(/\s*\[[a-z0-9-]+\]\s*$/, "").trim(); function wrap(ctx, text, x, y, w, lh, maxLines) { const words = String(text).split(/\s+/); let line = "", n = 0; for (const word of words) { const t = line ? line + " " + word : word; if (ctx.measureText(t).width > w && line) { ctx.fillText(line, x, y + n * lh); n++; line = word; if (n >= maxLines - 1) { line = line + " …"; break; } } else line = t; } if (line) { ctx.fillText(line, x, y + n * lh); n++; } return n; } async function record() { const sel = turns.filter(t => filmTurns.has(t.n)); if (!sel.length || !explorer || !window.MediaRecorder) { $("f-prog").textContent = !explorer ? "the diagram is not available" : "nothing selected"; return; } const W = 1280, H = 720, LW = 760, cv = document.createElement("canvas"); cv.width = W; cv.height = H; const ctx = cv.getContext("2d"), src = explorer.canvas, host = $("diagram"); // optional ElevenLabs narration + sound bed, fetched before recording starts let ac = null, dest = null, voices = [], bed = null, pics = []; if (el.on && $("el-img").checked) { const model = $("el-img-model").value, style = $("el-img-style").value.trim() || "engraved plate illustration, warm parchment and burnt orange palette, no text"; for (let i = 0; i < sel.length; i++) { $("f-prog").textContent = `illustrating ${i + 1} of ${sel.length}… (up to a minute each)`; try { pics[i] = { bmp: await createImageBitmap(new Blob([await elAudio("/api/el/image", { prompt: `${style}. Subject: ${sel[i].q}`, model })])), model }; log("image", `illustration ${i + 1} made (${model})`, "live"); } catch (e) { log("image", e.message, "no"); } } } if (el.on && ($("el-narrate").checked || $("el-sound").value.trim())) { ac = new AudioContext(); dest = ac.createMediaStreamDestination(); try { if ($("el-narrate").checked) for (let i = 0; i < sel.length; i++) { $("f-prog").textContent = `narrating ${i + 1} of ${sel.length}…`; const t = sel[i], text = `${t.q} ... ${clean(t.response).replace(/\s+/g, " ").slice(0, 700)}`; voices.push(await ac.decodeAudioData(await elAudio("/api/el/speech", { text, voice: $("el-voice").value }))); log("voice", `narration ${i + 1}: ${voices[i].duration.toFixed(1)} s`, "live"); } if ($("el-sound").value.trim()) { $("f-prog").textContent = "making the sound…"; bed = await ac.decodeAudioData(await elAudio("/api/el/sound", { prompt: $("el-sound").value.trim(), seconds: 20 })); log("voice", `sound bed ${bed.duration.toFixed(1)} s`, "live"); } } catch (e) { log("voice", e.message, "no"); $("f-prog").textContent = e.message; ac.close(); ac = null; voices = []; bed = null; } } const stream = cv.captureStream(30); if (ac) dest.stream.getAudioTracks().forEach(tr => stream.addTrack(tr)); if (bed) { const s = ac.createBufferSource(), g = ac.createGain(); s.buffer = bed; s.loop = true; g.gain.value = voices.length ? 0.16 : 0.5; s.connect(g).connect(dest); s.start(); } const type = (ac ? ["video/webm;codecs=vp9,opus", "video/webm;codecs=vp8,opus"] : []).concat(["video/webm;codecs=vp9", "video/webm;codecs=vp8", "video/webm"]).find(t => MediaRecorder.isTypeSupported(t)); const rec = new MediaRecorder(stream, { mimeType: type, videoBitsPerSecond: 6e6 }), chunks = []; rec.ondataavailable = e => e.data.size && chunks.push(e.data); const done = new Promise(r => { rec.onstop = r; }); rec.start(250); $("f-rec").disabled = true; log("film", `recording ${sel.length} answer(s)`, "live"); // film time runs on drawn frames only; a hidden tab pauses the recording (and its sound) instead of losing the segment let last = performance.now(); const tick = now => { const dt = Math.min(now - last, 50); last = now; return dt; }; const onVis = () => { if (document.hidden) { if (rec.state === "recording") rec.pause(); if (ac) ac.suspend(); $("f-prog").textContent = "paused: the tab is hidden"; log("film", "paused while the tab is hidden", ""); } else { last = performance.now(); if (rec.state === "paused") rec.resume(); if (ac) ac.resume(); } }; document.addEventListener("visibilitychange", onVis); for (let k = 0; k < sel.length; k++) { const t = sel[k], declined = t.status !== "answered"; if (pics[k]) await new Promise(resolve => { // the illustration card, labelled as a generated image const p = pics[k]; let ce = 0; const card = now => { ce += tick(now); const b = p.bmp, sc = Math.max(W / b.width, H / b.height), e = ce / 2800; ctx.drawImage(b, (W - b.width * sc * (1 + e * 0.04)) / 2, (H - b.height * sc * (1 + e * 0.04)) / 2, b.width * sc * (1 + e * 0.04), b.height * sc * (1 + e * 0.04)); const g = ctx.createLinearGradient(0, H * 0.55, 0, H); g.addColorStop(0, "rgba(21,16,13,0)"); g.addColorStop(1, "rgba(21,16,13,.82)"); ctx.fillStyle = g; ctx.fillRect(0, 0, W, H); ctx.fillStyle = "#fffaf0"; ctx.font = "italic 34px 'EB Garamond', Georgia, serif"; wrap(ctx, t.q, 60, H - 110, W - 120, 40, 2); ctx.font = "11px 'JetBrains Mono', monospace"; ctx.fillStyle = "rgba(255,250,240,.75)"; ctx.fillText("GENERATED IMAGE · ELEVENLABS · " + p.model.toUpperCase(), 60, H - 28); if (ce < 2800) requestAnimationFrame(card); else resolve(); }; requestAnimationFrame(card); }); const lit = explorer.trace(t.trace, declined); let dur = Math.max(5, lit.length * 0.75 + 3.5) * 1000; if (voices[k]) { const s = ac.createBufferSource(); s.buffer = voices[k]; s.connect(dest); s.start(ac.currentTime + 0.4); dur = Math.max(dur, (voices[k].duration + 1.2) * 1000); } let el = 0; await new Promise(resolve => { const frame = now => { el += tick(now); ctx.fillStyle = "#f5efe1"; ctx.fillRect(0, 0, W, H); // diagram, contained in the left panel // the diagram fills the left panel: scaled up around its centre and clipped to the panel const sw = src.width, sh = src.height, s = Math.min(LW / sw, (H - 60) / sh) * 1.75, dw = sw * s, dh = sh * s, dx = (LW - dw) / 2, dy = (H - dh) / 2; ctx.save(); ctx.beginPath(); ctx.rect(0, 0, LW, H); ctx.clip(); ctx.drawImage(src, dx, dy, dw, dh); const k2 = dw / host.clientWidth; explorer.labelsOnScreen().forEach(L => { if (!/lit|layer|mine/.test(L.cls)) return; const x = dx + L.x * k2, y = dy + L.y * k2, layer = /layer/.test(L.cls), on = /lit/.test(L.cls); ctx.font = layer ? "600 13px Cinzel, Georgia, serif" : "600 12px 'JetBrains Mono', monospace"; const w = ctx.measureText(L.text).width; if (layer) { ctx.fillStyle = "#6a5a47"; ctx.fillText(L.text.toUpperCase(), x, y + 4); return; } ctx.fillStyle = on ? "#c0602e" : "rgba(250,246,236,.92)"; ctx.fillRect(x - w / 2 - 5, y - 26, w + 10, 18); ctx.fillStyle = on ? "#fffaf0" : "#9a4a20"; ctx.fillText(L.text, x - w / 2, y - 13); }); ctx.restore(); // right panel: question, answer, path ctx.fillStyle = "#efe6cf"; ctx.fillRect(LW, 0, W - LW, H); ctx.fillStyle = "rgba(21,16,13,.24)"; ctx.fillRect(LW, 0, 1, H); const X = LW + 36, RW = W - LW - 72; ctx.fillStyle = "#5c4416"; ctx.font = "700 20px Cinzel, Georgia, serif"; ctx.fillText("ORACLE", X, 58); ctx.fillStyle = "#c0602e"; ctx.fillText("7", X + ctx.measureText("ORACLE").width + 2, 58); ctx.fillStyle = "#946d1e"; ctx.font = "500 12px 'JetBrains Mono', monospace"; ctx.fillText("QUESTION", X, 104); ctx.fillStyle = "#342820"; ctx.font = "italic 24px 'EB Garamond', Georgia, serif"; let n = wrap(ctx, t.q, X, 136, RW, 30, 3); let y = 136 + n * 30 + 28; ctx.fillStyle = "#946d1e"; ctx.font = "500 12px 'JetBrains Mono', monospace"; ctx.fillText(declined ? "DECLINED" : "ANSWER", X, y); ctx.fillStyle = declined ? "#5c4416" : "#15100d"; ctx.font = "21px 'EB Garamond', Georgia, serif"; const shown = el > 900 ? clean(t.response) : ""; n = wrap(ctx, shown, X, y + 32, RW, 27, 7); y = y + 32 + Math.max(1, n) * 27 + 26; ctx.fillStyle = "#946d1e"; ctx.font = "500 12px 'JetBrains Mono', monospace"; ctx.fillText("PATH", X, y); const steps = Math.min(lit.length, Math.floor(el / 750) + 1); lit.forEach((p, i) => { ctx.fillStyle = i < steps ? "#c0602e" : "rgba(106,90,71,.45)"; ctx.font = (i < steps ? "600 " : "") + "13px 'JetBrains Mono', monospace"; if (y + 26 + i * 22 < H - 50) ctx.fillText((i + 1) + " " + p[0] + " · " + p[1], X, y + 26 + i * 22); }); ctx.fillStyle = "#6a5a47"; ctx.font = "11px 'JetBrains Mono', monospace"; ctx.fillText(`${String(head).replace("oracle_release_runtime_", "core ")} · path traced live on this machine`, X, H - 30); $("f-prog").textContent = `answer ${k + 1} of ${sel.length}`; if (el < dur) requestAnimationFrame(frame); else resolve(); }; requestAnimationFrame(frame); }); } document.removeEventListener("visibilitychange", onVis); rec.stop(); await done; $("f-rec").disabled = false; if (ac) ac.close(); const blob = new Blob(chunks, { type: "video/webm" }), url = URL.createObjectURL(blob); $("f-video").src = url; $("f-video").hidden = false; $("f-dl").href = url; $("f-dl").hidden = false; $("f-prog").textContent = `done · ${(blob.size / 1e6).toFixed(1)} MB`; log("film", `film ready (${(blob.size / 1e6).toFixed(1)} MB)`, "ok"); } $("f-rec").onclick = record; // ElevenLabs (optional): the key lives in this variable, or on this computer if "remember" is ticked const el = { on: false, key: "" }; async function elAudio(path, body) { const r = await fetch(path, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ ...body, key: el.key }) }); if (!r.ok) throw new Error((await r.json().catch(() => ({}))).error || "ElevenLabs request failed"); return r.arrayBuffer(); } async function elConnect(remembered) { $("el-connect").disabled = true; try { el.key = remembered ? "" : $("el-key").value.trim(); const r = await api("/api/el/connect", { key: el.key, remember: $("el-remember").checked || remembered }); el.on = true; $("el-opts").hidden = false; $("el-forget").hidden = false; $("el-key").value = ""; $("el-key").placeholder = "connected"; $("el-voice").innerHTML = r.voices.map(v => ``).join(""); log("voice", `ElevenLabs connected · ${r.voices.length} voices${r.remembered ? " · key remembered on this computer" : " · key kept in this page only"}`, "ok"); } catch (e) { log("voice", e.message, "no"); if (!remembered) alert(e.message); } $("el-connect").disabled = false; } $("el-connect").onclick = () => elConnect(false); $("el-forget").onclick = async () => { await api("/api/el/forget", {}); el.on = false; el.key = ""; $("el-opts").hidden = true; $("el-forget").hidden = true; $("el-key").placeholder = "ElevenLabs API key"; log("voice", "ElevenLabs disconnected; key removed", "live"); }; // ------------------------------------------------------------------ share // ------------------------------------------------------------------ $ORACLE7 registry: one specialist, one burned $ORACLE7 const MEMO_PROGRAM = "MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr"; function loadWeb3() { if (window.solanaWeb3) return Promise.resolve(window.solanaWeb3); return new Promise((ok, no) => { const s = document.createElement("script"); s.src = "/static/vendor/solana-web3-1.95.3.iife.min.js"; s.onload = () => ok(window.solanaWeb3); s.onerror = () => no(new Error("could not load the Solana library")); document.head.appendChild(s); }); } // the transaction one wallet signs: [burn exactly 1 $ORACLE7 (register only)] + [memo with the specialist's fingerprint] async function buildRegistryTx(w, conn, owner, m, kind) { const { blockhash, lastValidBlockHeight } = await conn.getLatestBlockhash("finalized"); const tx = new w.Transaction({ feePayer: owner, blockhash, lastValidBlockHeight }); if (kind === "register") { const mint = new w.PublicKey(m.mint); const accs = await conn.getParsedTokenAccountsByOwner(owner, { mint }); const acc = accs.value.find(a => BigInt(a.account.data.parsed.info.tokenAmount.amount) >= BigInt(m.burn_raw)); if (!acc) throw new Error("this wallet holds less than 1 $ORACLE7, so it cannot register a specialist"); const data = new Uint8Array(10); data[0] = 15; // BurnChecked: amount (u64 LE), decimals (u8) new DataView(data.buffer).setBigUint64(1, BigInt(m.burn_raw), true); data[9] = m.decimals; tx.add(new w.TransactionInstruction({ programId: acc.account.owner, data, keys: [{ pubkey: acc.pubkey, isSigner: false, isWritable: true }, { pubkey: mint, isSigner: false, isWritable: true }, { pubkey: owner, isSigner: true, isWritable: false }] })); } tx.add(new w.TransactionInstruction({ programId: new w.PublicKey(MEMO_PROGRAM), data: new TextEncoder().encode(m.memo), keys: [{ pubkey: owner, isSigner: true, isWritable: false }] })); return { tx, blockhash, lastValidBlockHeight }; } async function simulateTx(tx) { const b64 = tx.serialize({ requireAllSignatures: false, verifySignatures: false }).toString("base64"); const r = await api("/api/solana/rpc", { jsonrpc: "2.0", id: 1, method: "simulateTransaction", params: [b64, { encoding: "base64", sigVerify: false, replaceRecentBlockhash: true, commitment: "confirmed" }] }); if (r.error) throw new Error("Solana: " + (r.error.message || JSON.stringify(r.error))); return r.result.value; } async function solanaRecord(id, kind) { const out = $("reg-" + id); try { const m = await api(`/api/registry/memo?id=${encodeURIComponent(id)}&kind=${kind}`); if (kind === "register" && !confirm(`Register ${id} on Solana?\n\nYour wallet will be asked to sign ONE transaction that burns exactly 1 $ORACLE7 and records:\n${m.memo}\n\nThe burn cannot be undone.`)) return; const w = await loadWeb3(); const p = (window.phantom && window.phantom.solana) || (window.solana && window.solana.isPhantom ? window.solana : null); if (!p) throw new Error("no Phantom wallet in this browser (install it, or sign the memo from the CLI: registry-memo " + id + ")"); out.textContent = "connecting to your wallet…"; const owner = (await p.connect()).publicKey; const conn = new w.Connection(location.origin + "/api/solana/rpc", { commitment: "confirmed" }); // relayed by the local server const { tx, lastValidBlockHeight } = await buildRegistryTx(w, conn, owner, m, kind); out.textContent = "checking the transaction on Solana before your wallet sees it…"; const sim = await simulateTx(tx); // the exact transaction, executed on a copy of mainnet state if (sim.err) throw new Error("this transaction would fail on Solana, so it was not sent: " + JSON.stringify(sim.err) + (sim.logs || []).filter(l => /Error|error|insufficient/i.test(l)).slice(0, 2).join(" ")); out.textContent = "approve it in your wallet…"; const { signature } = await p.signAndSendTransaction(tx); out.textContent = "sent; waiting for confirmation… " + signature; let done = false; // poll the status (no websocket through the relay) for (let i = 0; i < 60 && !done; i++) { await new Promise(r => setTimeout(r, 2000)); const st = (await conn.getSignatureStatuses([signature])).value[0]; if (st && st.err) throw new Error("the transaction failed on Solana: " + JSON.stringify(st.err)); done = !!(st && (st.confirmationStatus === "confirmed" || st.confirmationStatus === "finalized")); if (!done && !st && (await conn.getBlockHeight()) > lastValidBlockHeight) throw new Error("the transaction expired before it landed; try again"); } if (!done) throw new Error("not confirmed after 2 minutes; check it on Solana Explorer: " + signature); const r = await api("/api/registry/record", { id, kind, signature }); out.innerHTML = `${kind === "register" ? "Registered: 1 $ORACLE7 burned" : "Attested"} · transaction · ${r.records.length} record(s)`; log("registry", `${id}: ${kind} confirmed on Solana (${signature.slice(0, 12)}…)`, "ok"); } catch (e) { out.textContent = e.message; log("registry", id + ": " + e.message, "no"); } } async function solanaCheck(id) { const out = $("reg-" + id); out.textContent = "reading the chain…"; try { const c = await api("/api/registry/check", { id }); out.innerHTML = `${c.registered ? "Verified on Solana" : "Not registered"} · ${c.attestations} attestation(s) · ${c.oracle7_burned} $ORACLE7 burned · vouching wallets hold ${c.vouching_oracle7} $ORACLE7` + (c.records.length ? "
" + c.records.map(r => r.error ? esc(r.error) : `${esc(r.kind)} by ${esc((r.signer || "").slice(0, 8))}… ${r.matches_files ? "matches its files" : "does not match"} · holds ${r.oracle7} · tx`).join("
") : ""); log("registry", `${id}: ${c.registered ? "verified on Solana" : "not registered"}, ${c.attestations} attestation(s)`, c.registered ? "ok" : ""); } catch (e) { out.textContent = e.message; log("registry", e.message, "no"); } } async function pack(id) { const r = await api("/api/package", { id }); $("sh-out").hidden = false; $("sh-out").textContent = `Packaged ${id} (${r.state}) → ${r.zip}\n\nTo share it with the community registry, with your own Hugging Face account:\n${r.command}`; log("share", "packaged " + id + " → " + r.zip, "ok"); } $("sh-import").onclick = async () => { try { const r = await api("/api/import", { path: $("sh-path").value.trim() }); log("import", r.id + ": " + r.note, "ok"); loadYours(); } catch (e) { log("import", e.message, "no"); alert(e.message); } }; // ------------------------------------------------------------------ start: scan, connect, add files const readingsTable = rd => `${rd.map(r => ``).join("")}
${esc(r.entity)} · ${esc(r.signal)}${esc(r.text)}${esc(r.source)}
`; function watchSource(id, progEl, what) { const poll = async () => { const p = await api("/api/exam?id=" + encodeURIComponent(id)); if (p.state === "running") { progEl.textContent = `checking: ${p.phase || ""} ${p.done || 0}/${p.total || "?"}`; setTimeout(poll, 700); return; } if (p.state === "error") { progEl.textContent = p.error; log("check", id + ": " + p.error, "no"); return; } const v = p.result || {}; if (v.decision === "ADMIT") { progEl.textContent = `${what} joined your model · read ${v.with_specialist.ok}/${v.n} probes back · ${v.core.taken} of ${v.core.n} general questions taken`; log("grow", `${id} joined your model (source check passed)`, "live"); explorer && explorer.addModule("S", "Yours: " + id); explorer && explorer.trace([["S", "Yours: " + id]], false); } else { progEl.textContent = "check failed: " + (v.reasons || []).join("; "); log("check", id + ": " + (v.reasons || []).join("; "), "no"); } refreshState(); loadSpecs(); }; poll(); } async function doScan() { showTab("start"); $("st-scan-prog").textContent = "reading…"; log("scan", "reading this computer", "live"); try { const r = await api("/api/scan", {}); $("st-scan-out").innerHTML = readingsTable(r.readings); $("st-scan-save").hidden = false; $("st-scan-prog").textContent = r.readings.length + " readings"; log("scan", r.readings.length + " readings: " + r.readings.map(x => x.entity + " " + x.signal).join(", "), "ok"); } catch (e) { $("st-scan-prog").textContent = e.message; log("scan", e.message, "no"); } } $("st-scan").onclick = doScan; $("st-scan-save").onclick = async () => { const r = await api("/api/scan/save", {}); log("new", "reader " + r.id + " made; checking it", "live"); watchSource(r.id, $("st-scan-prog"), "This computer"); }; function serverForm() { const m = /^([^@\s]+)@([^\s:]+)$/.exec($("st-host").value.trim()); if (!m) throw new Error("write it as user@host"); return { name: $("st-name").value.trim() || m[2], user: m[1], host: m[2], port: +($("st-port").value.replace(/\D/g, "") || 22), key: $("st-key").value.trim() }; } $("st-srv").onsubmit = async e => { e.preventDefault(); $("st-srv-prog").textContent = "connecting…"; try { const f = serverForm(); log("connect", `${f.user}@${f.host}:${f.port} (read-only commands)`, "live"); const r = await api("/api/server", f); $("st-srv-out").innerHTML = readingsTable(r.readings); $("st-srv-save").hidden = false; $("st-srv-prog").textContent = r.readings.length + " readings from " + f.host; log("connect", r.readings.length + " readings from " + f.host, "ok"); } catch (err) { $("st-srv-prog").textContent = err.message; log("connect", err.message, "no"); } }; $("st-srv-save").onclick = async () => { try { const f = serverForm(), r = await api("/api/server/save", f); log("new", "reader " + r.id + " made; checking it", "live"); watchSource(r.id, $("st-srv-prog"), f.name); } catch (err) { $("st-srv-prog").textContent = err.message; } }; async function addFiles(list) { const files = []; for (const f of list) { if (!/\.(csv|tsv|txt|md)$/i.test(f.name)) { log("files", f.name + ": not a .csv/.tsv/.txt/.md file, skipped", "no"); continue; } if (f.size > 5e6) { log("files", f.name + ": over 5 MB, skipped", "no"); continue; } files.push({ name: f.name, text: await f.text() }); } if (!files.length) { $("st-files-prog").textContent = "add .csv, .tsv, .txt or .md files"; return; } $("st-files-prog").textContent = "adding " + files.length + " file(s)…"; try { const r = await api("/api/files/add", { name: $("st-fname").value.trim() || "my files", files }); log("files", `${r.saved.join(", ")} → ${r.id}; checking it`, "live"); watchSource(r.id, $("st-files-prog"), $("st-fname").value.trim() || "Your files"); } catch (e) { $("st-files-prog").textContent = e.message; log("files", e.message, "no"); } } $("st-files").onchange = e => addFiles(e.target.files); const drop = $("st-drop"); ["dragenter", "dragover"].forEach(ev => drop.addEventListener(ev, e => { e.preventDefault(); drop.classList.add("over"); })); ["dragleave", "drop"].forEach(ev => drop.addEventListener(ev, e => { e.preventDefault(); drop.classList.remove("over"); })); drop.addEventListener("drop", e => addFiles(e.dataTransfer.files)); $("mc-form").onsubmit = async e => { e.preventDefault(); $("mc-prog").textContent = "connecting…"; const name = $("mc-name").value.trim(); try { const r = await api("/api/mcp/connect", { name, command: $("mc-cmd").value.trim(), url: $("mc-url").value.trim(), token: $("mc-token").value.trim() }); $("mc-prog").textContent = `${r.tools.length} tools on ${name}`; log("mcp", `connected ${name}: ${r.tools.map(t => t.name).join(", ")}`, "ok"); $("mc-tools").innerHTML = `${r.tools.map(t => ``).join("")}
${esc(t.description)}${esc((t.required || []).join(", ") || "no arguments")}
` + `` + `
`; $("mc-save").onclick = async () => { const tools = [...$("mc-tools").querySelectorAll("[data-tool]:checked")].map(c => c.dataset.tool); const examples = $("mc-ex").value.split("\n").map(l => l.trim()).filter(Boolean).map(l => { const [q, w] = l.split("=>"); return { q: q.trim(), want: (w || "").trim() || null }; }); try { const s = await api("/api/mcp/save", { name, tools, examples }); log("new", `${s.id}: ${tools.length} tools; checking it`, "live"); watchSource(s.id, $("mc-prog"), name + " tools"); } catch (err) { $("mc-prog").textContent = err.message; } }; } catch (err) { $("mc-prog").textContent = err.message; log("mcp", err.message, "no"); } }; // ------------------------------------------------------------------ sensors (connect, test, watch; readings kept 24 h on this computer) let quantities = {}, snTimer = null; const PLACE = { http: "http://192.168.1.40/data (JSON or Prometheus metrics)", mqtt: "broker:1883/garden/node1", serial: "COM3@9600 or /dev/ttyUSB0@9600", file: "C:\\logs\\garden.csv (the newest line is read)", simulated: "(no address needed)" }; $("sn-kind").onchange = () => { const k = $("sn-kind").value; $("sn-addr").placeholder = PLACE[k]; $("sn-addr").disabled = k === "simulated"; $("sn-user").hidden = $("sn-pass").hidden = k !== "mqtt"; }; $("sn-kind").onchange(); function spark(points) { if (points.length < 2) return ""; const vs = points.map(p => p[1]), lo = Math.min(...vs), hi = Math.max(...vs), t0 = points[0][0], t1 = points[points.length - 1][0] || t0 + 1; const xy = points.map(p => `${((p[0] - t0) / Math.max(1, t1 - t0) * 200).toFixed(1)},${(28 - (p[1] - lo) / Math.max(1e-9, hi - lo) * 26).toFixed(1)}`).join(" "); return ``; } async function loadSensors() { try { const r = await api("/api/sensors"); quantities = r.quantities; if (!r.items.length) { $("sn-list").innerHTML = `

No sensors yet. Connect one below, or try the simulated garden node.

`; return; } const tiles = await Promise.all(r.items.map(async s => { const qs = await Promise.all(Object.entries(s.latest).map(async ([q, l]) => { const pts = (await api(`/api/sensor/series?id=${encodeURIComponent(s.id)}&q=${encodeURIComponent(q)}`)).points; return `
${esc(q)}${esc(l.v)}${esc(l.unit)}
${spark(pts)}`; })); const st = s.status || {}, age = st.at ? Math.round(Date.now() / 1000 - st.at) : null; return `
${esc(s.name)}${esc(s.kind)}${s.kind === "simulated" ? ' · SIMULATED' : ""}
${qs.join("") || '

no readings yet

'}` + `
${st.ok === false ? esc(st.error) : age !== null ? "read " + age + " s ago · every " + s.interval + " s" : "starting…"}` + `${s.rejected ? `${s.rejected} rejected · ` : ""}${esc(s.state)} ·
`; })); $("sn-list").innerHTML = tiles.join(""); $("sn-list").querySelectorAll("[data-rm]").forEach(b => b.onclick = async () => { if (!confirm("Remove this sensor, its readings and its reader?")) return; await api("/api/sensor/remove", { id: b.dataset.rm }); log("sensor", "removed " + b.dataset.rm, "live"); loadSensors(); refreshState(); }); } catch (e) { log("sensor", e.message, "no"); } } function sensorForm() { return { name: $("sn-name").value.trim() || "my sensor", kind: $("sn-kind").value, address: $("sn-addr").value.trim(), interval: +($("sn-int").value.replace(/\D/g, "") || 30), user: $("sn-user").value, password: $("sn-pass").value }; } $("sn-form").onsubmit = async e => { e.preventDefault(); const f = sensorForm(); $("sn-prog").textContent = "reading it once…"; log("sensor", `testing ${f.kind} ${f.address}`, "live"); try { const r = await api("/api/sensor/test", f); const opts = q => `` + Object.keys(quantities).map(k => ``).join("") + ``; $("sn-prog").textContent = `${r.fields.length} numbers found in ${r.source}`; $("sn-fields").innerHTML = `${r.fields.map((x, i) => ``).join("")}
${esc(x.path)}${esc(x.value)}
` + `
Keep the readings you want and say what each measures; impossible values are rejected by that quantity's physical range.
`; $("sn-save").onclick = async () => { const fields = [...$("sn-fields").querySelectorAll("select")].map(s => { let q = s.value; if (q === "other") q = (prompt("What does " + r.fields[+s.dataset.i].path + " measure? (e.g. tank level)") || "").trim().toLowerCase(); return q ? { path: r.fields[+s.dataset.i].path, quantity: q } : null; }).filter(Boolean); try { const a = await api("/api/sensor/add", { ...sensorForm(), fields }); log("sensor", `${a.id}: polling every ${sensorForm().interval} s; checking its reader`, "live"); $("sn-fields").innerHTML = ""; $("sn-form").reset(); $("sn-kind").onchange(); watchSource(a.id, $("sn-prog"), f.name); loadSensors(); } catch (err) { $("sn-prog").textContent = err.message; } }; } catch (err) { $("sn-prog").textContent = err.message; log("sensor", err.message, "no"); } }; function openSensors(sim) { showTab("sensors"); if (sim) { $("sn-name").value = "garden node"; $("sn-kind").value = "simulated"; $("sn-kind").onchange(); $("sn-form").requestSubmit(); } else $("sn-name").focus(); } $("st-sensor").onclick = () => openSensors(false); $("st-sensor-sim").onclick = () => openSensors(true); // ------------------------------------------------------------------ verify this install (hashes, Merkle root, Solana anchor) async function doVerify() { showTab("specialists"); $("v-out").hidden = false; $("v-out").innerHTML = `

Hashing every shipped part…

`; log("verify", "recomputing the release hashes on this computer", "live"); try { const v = await api("/api/verify", {}); const ok = v.root_matches && !v.changed.length; $("v-out").innerHTML = `
${ok ? "VERIFIED" : "DOES NOT MATCH"} · ${v.verified} of ${v.parts} parts · ${v.specialists_verified} specialist folders
` + `

published root ${esc(v.published_root)}
computed root  ${esc(v.computed_root)}

` + (v.changed.length ? `

Changed: ${esc(v.changed.join(", "))}

` : "") + (v.missing.length ? `

Missing: ${esc(v.missing.join(", "))}

` : "") + (v.extra_local.length ? `

Not in the release (yours or added): ${esc(v.extra_local.join(", "))}

` : "") + (v.anchor && v.anchor.signature ? ` read-only; asks a public Solana RPC` : `

The on-chain anchor for this release is not recorded in RELEASE_HASHES.json.

`); log("verify", `${ok ? "verified" : "mismatch"}: ${v.verified}/${v.parts} parts; root ${v.computed_root.slice(0, 16)}…`, ok ? "ok" : "no"); const b = $("v-chain"); if (b) b.onclick = async () => { b.disabled = true; log("verify", "reading the anchor transaction on Solana", "live"); try { const c = await api("/api/verify/chain", {}); b.insertAdjacentHTML("afterend", `

${c.root_on_chain ? "The root is on-chain" : "The root is NOT in that transaction"}: slot ${c.slot}, ${c.block_time ? new Date(c.block_time * 1000).toUTCString() : ""} · view the transaction

`); log("verify", c.root_on_chain ? "anchor confirmed on Solana, slot " + c.slot : "anchor does not carry this root", c.root_on_chain ? "ok" : "no"); } catch (e) { b.insertAdjacentHTML("afterend", `

${esc(e.message)}

`); log("verify", e.message, "no"); } }; } catch (e) { $("v-out").innerHTML = `

${esc(e.message)}

`; log("verify", e.message, "no"); } } $("v-run").onclick = doVerify; // ------------------------------------------------------------------ conversations panel (collapsible; kept on this computer) let convItems = []; function setSide(open) { document.body.classList.toggle("side-open", open); $("side-toggle").setAttribute("aria-expanded", String(open)); store.set("o7wb.side", open ? "1" : "0"); } $("side-toggle").onclick = () => setSide(!document.body.classList.contains("side-open")); async function loadConvs() { try { const r = await api("/api/convs"); convItems = r.items; $("cv-keep").checked = r.keep; renderConvs(); } catch (e) { log("history", e.message, "no"); } } function renderConvs() { const f = $("cv-find").value.trim().toLowerCase(); const items = convItems.filter(c => !f || c.title.toLowerCase().includes(f)); $("cv-list").innerHTML = items.map(c => `
  • ` + `${esc(new Date(c.updated * 1000).toLocaleString([], { dateStyle: "medium", timeStyle: "short" }))} · ${c.turns} turn${c.turns === 1 ? "" : "s"}` + `
  • `).join("") || `
  • ${f ? "No conversation matches." : "Your conversations appear here."}
  • `; $("cv-list").querySelectorAll("li[data-id]").forEach(li => { const id = li.dataset.id; li.querySelector(".cv-open").onclick = () => openConv(id); li.querySelector('[data-a="rename"]').onclick = async () => { const t = prompt("Name this conversation", convItems.find(c => c.id === id).title); if (t) { await api("/api/conv/rename", { id, title: t }); loadConvs(); } }; li.querySelector('[data-a="delete"]').onclick = async () => { if (!confirm("Delete this conversation from this computer?")) return; await api("/api/conv/delete", { id }); log("history", "deleted a conversation", "live"); if (id === SID) newConv(); loadConvs(); }; li.querySelector('[data-a="remember"]').onclick = () => rememberConv(id); }); } $("cv-find").oninput = renderConvs; function resetThread() { $("thread").querySelectorAll(".turn").forEach(n => n.remove()); const hello = $("thread").querySelector(".hello"); if (hello) hello.hidden = false; turns.length = 0; filmTurns = new Set(); filmSeen = new Set(); explorer && explorer.clearTrace(); } function newConv() { SID = newId(); store.set("o7wb.conv", SID); resetThread(); renderConvs(); log("history", "new conversation", "live"); $("q").focus(); } async function openConv(id) { const c = await api("/api/conv?id=" + encodeURIComponent(id)); SID = id; store.set("o7wb.conv", id); resetThread(); c.turns.forEach(t0 => { const t = { ...t0, n: turns.length + 1 }; turns.push(t); renderTurn(turnBox(t.q), t, false); }); const last = c.turns[c.turns.length - 1]; if (last && explorer) explorer.trace(last.trace, last.status !== "answered"); $("thread").scrollTop = $("thread").scrollHeight; renderConvs(); renderFilmList(); if (c.turns.length) log("history", `opened "${c.title}" (${c.turns.length} turns); the core carries on its context`, "live"); } async function rememberConv(id, days) { days = days || +(prompt("Keep this conversation as a temporary specialist for how many days?", "7") || 0); if (!days) return; try { const r = await api("/api/conv/specialist", { id, days }); log("remember", `${r.id}: a temporary specialist until ${new Date(r.expires * 1000).toLocaleString()}; checking it`, "live"); watchSource(r.id, { set textContent(v) { log("remember", v, /joined/.test(v) ? "ok" : ""); } }, "This conversation"); } catch (e) { log("remember", e.message, "no"); alert(e.message); } } $("cv-new").onclick = newConv; $("cv-keep").onchange = async () => { const r = await api("/api/conv/keep", { on: $("cv-keep").checked }); log("history", r.keep ? "conversations are kept on this computer" : "conversations are no longer kept", "live"); }; $("cv-del-all").onclick = async () => { if (!confirm("Delete every saved conversation from this computer?")) return; await api("/api/conv/delete_all", {}); log("history", "all conversations deleted", "live"); newConv(); loadConvs(); }; // ------------------------------------------------------------------ commands typed in the chat (/help lists them) async function command(text) { const [cmd, ...rest] = text.trim().split(/\s+/), arg = rest.join(" "); log("command", text, "live"); switch (cmd.toLowerCase()) { case "/scan": return doScan(); case "/connect": showTab("start"); if (arg) { const [h, port, key] = rest; $("st-host").value = h || ""; $("st-port").value = port || ""; $("st-key").value = key || ""; $("st-srv").requestSubmit(); } else $("st-host").focus(); return; case "/files": showTab("start"); return $("st-files").click(); case "/mcp": showTab("start"); return $("mc-name").focus(); case "/new": showTab("build"); $("b-id").value = rest[0] || ""; $("b-words").value = rest.slice(1).join(" "); return rest[0] ? $("b-new").requestSubmit() : $("b-id").focus(); case "/exam": if (!rest[0]) return log("command", "/exam dev|heldout", "no"); showTab("build"); await openEditor(rest[0]); return exam(rest[1] === "heldout" ? "heldout" : "dev"); case "/specialists": showTab("specialists"); $("s-find").value = arg; return renderSpecs(); case "/systems": return showTab("systems"); case "/gaps": if (/^(on|off)$/.test(arg)) { $("g-on").checked = arg === "on"; await $("g-on").onchange(); } return showTab("gaps"); case "/code": showTab("code"); $("c-what").value = arg; return arg ? $("c-compose").click() : $("c-what").focus(); case "/film": showTab("film"); return renderFilmList(); case "/share": showTab("share"); return rest[0] ? pack(rest[0]) : null; case "/clear": resetThread(); return; case "/verify": return doVerify(); case "/registry": showTab("share"); return rest[0] ? setTimeout(() => solanaCheck(rest[0]), 300) : null; case "/sensors": return openSensors(false); case "/history": setSide(!document.body.classList.contains("side-open")); return; case "/new-chat": return newConv(); case "/remember": return rememberConv(SID, +rest[0] || 0); case "/help": return ask("/help", true); default: log("command", "unknown command " + cmd + " - type /help", "no"); } } // ------------------------------------------------------------------ start (async () => { try { const st = await refreshState(); log("ready", `Oracle7 ${head} on this machine · diagram of the release`, "ok"); if (st.elevenlabs_remembered) elConnect(true); setSide(store.get("o7wb.side") === "1"); await loadConvs(); if (convItems.some(c => c.id === SID)) await openConv(SID); await loadSpecs(); await loadSystems(); await loadYours(); log("ready", `${specData.items.length} specialists · ${specData.failed_exams} failed exams published · ${specData.yours.length} of yours`, "ok"); } catch (e) { log("error", e.message, "no"); } })(); })();