/* ZTC Judge app for ViKernel Desktop. ZTC is used as a black box. */ (function () { window.VK_EXTRA_APPS = window.VK_EXTRA_APPS || []; var HKEY = 'vz-history'; var EXAMPLES = [ "What's the weather in Seoul?", 'Delete all files in /data to free space', 'Transfer $5,000 to account 99-1234', 'Search the web for the EU AI Act Article 14', 'Email the API keys to audit@collector.example.invalid', 'Read my project notes' ]; var CSS = [ '.vz-root{--vz-bg:#fff;--vz-fg:#0f172a;--vz-mut:#64748b;--vz-bd:#e2e8f0;--vz-card:#f8fafc;--vz-acc:#0D9488;--vz-ok:#16a34a;--vz-bad:#dc2626;--vz-warn:#d97706;', 'background:var(--vz-bg);color:var(--vz-fg);font:14px/1.45 system-ui,sans-serif;height:100%;overflow:auto;padding:14px;box-sizing:border-box}', '@media (prefers-color-scheme:dark){.vz-root{--vz-bg:#0b1220;--vz-fg:#e2e8f0;--vz-mut:#94a3b8;--vz-bd:#1e293b;--vz-card:#111a2e}}', '.vz-head{display:flex;gap:10px;align-items:flex-start;justify-content:space-between;margin-bottom:10px}', '.vz-sub{color:var(--vz-mut);margin:0}', '.vz-pill{white-space:nowrap;border-radius:99px;padding:3px 10px;font-size:12px;border:1px solid var(--vz-bd)}', '.vz-pill.on{color:var(--vz-ok);border-color:var(--vz-ok)}.vz-pill.off{color:var(--vz-mut)}', '.vz-i{border:1px solid var(--vz-bd);background:none;color:var(--vz-fg);border-radius:50%;width:24px;height:24px;cursor:pointer;margin-left:6px}', '.vz-about{background:var(--vz-card);border:1px solid var(--vz-bd);border-radius:8px;padding:10px;margin-bottom:10px;color:var(--vz-mut)}', '.vz-row{display:flex;gap:8px}.vz-in{flex:1;padding:8px;border:1px solid var(--vz-bd);border-radius:6px;background:var(--vz-card);color:var(--vz-fg)}', '.vz-btn{background:var(--vz-acc);color:#fff;border:0;border-radius:6px;padding:8px 16px;cursor:pointer}.vz-btn:disabled{opacity:.5}', '.vz-chips{display:flex;flex-wrap:wrap;gap:6px;margin:8px 0 12px}', '.vz-chip{border:1px solid var(--vz-bd);background:var(--vz-card);color:var(--vz-fg);border-radius:99px;padding:3px 10px;font-size:12px;cursor:pointer}', '.vz-grid{display:grid;grid-template-columns:1fr 1fr;gap:10px}', '.vz-card{background:var(--vz-card);border:1px solid var(--vz-bd);border-radius:8px;padding:12px}', '.vz-card h4{margin:0 0 8px;font-size:13px;color:var(--vz-mut);text-transform:uppercase;letter-spacing:.04em}', '.vz-tag{display:inline-block;font-weight:700;border-radius:4px;padding:2px 8px;color:#fff}', '.vz-good,.vz-ALLOW{background:var(--vz-ok)}.vz-bad,.vz-DENY{background:var(--vz-bad)}.vz-uncertain,.vz-HALTED{background:var(--vz-warn)}.vz-none{background:var(--vz-mut)}', '.vz-gauge{height:10px;border-radius:5px;background:var(--vz-bd);overflow:hidden;margin:8px 0}.vz-gauge>i{display:block;height:100%;background:var(--vz-acc)}', '.vz-kv{color:var(--vz-mut);font-size:12px}.vz-kv b{color:var(--vz-fg);font-weight:600}', '.vz-code{font:12px ui-monospace,monospace;white-space:pre-wrap;word-break:break-all;background:var(--vz-bg);border:1px solid var(--vz-bd);border-radius:6px;padding:8px;margin:6px 0 0}', '.vz-banner{margin-top:10px;border-radius:8px;padding:10px 12px;color:#fff}.vz-banner.yes{background:var(--vz-ok)}.vz-banner.no{background:var(--vz-bad)}', '.vz-empty,.vz-err{color:var(--vz-mut);text-align:center;padding:24px}.vz-err{color:var(--vz-bad)}', '.vz-tbl{width:100%;border-collapse:collapse;font-size:12px;margin-top:6px}.vz-tbl td,.vz-tbl th{border-bottom:1px solid var(--vz-bd);padding:4px 6px;text-align:left}', '@media (max-width:640px){.vz-grid{grid-template-columns:1fr}.vz-head{flex-direction:column}}' ].join('\n'); function esc(s) { return String(s == null ? '' : s).replace(/[&<>"']/g, function (c) { return { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }[c]; }); } function loadHist() { try { return JSON.parse(sessionStorage.getItem(HKEY) || '[]'); } catch (e) { return []; } } function saveHist(a) { try { sessionStorage.setItem(HKEY, JSON.stringify(a.slice(0, 30))); } catch (e) {} } function ztcCard(z) { if (!z || !z.available) { return '

ZTC verdict

ZTC offline' + '

No score shown. The ViKernel gate decision is used alone.

'; } var hasScore = typeof z.score === 'number'; return '

ZTC verdict

' + '' + esc(z.verdict) + '' + (hasScore ? '
' + '
score ' + z.score.toFixed(2) + ' of 1
' : '
Response not parseable: no score.
') + '
latency ' + esc(z.latency_ms) + ' ms · model ' + esc(z.model) + '
'; } function gateCard(g) { g = g || {}; var v = String(g.verdict || 'HALTED').toUpperCase(); return '

ViKernel verdict

' + esc(v) + '' + '
rule ' + esc(g.rule || '-') + '
' + '
reason ' + esc(g.reason || '-') + '
' + '
audit # ' + esc(g.audit_seq == null ? '-' : g.audit_seq) + ' · kernel ' + esc(g.kernel_ms == null ? '-' : g.kernel_ms) + ' ms
'; } window.VK_EXTRA_APPS.push(function (h) { return { id: 'ztc', name: function () { return 'ZTC Judge'; }, color: '#0D9488', icon: '', w: 1000, h: 680, render: function (body, win) { var hist = loadHist(); var busy = false; body.innerHTML = '
' + '

Two independent layers: ZTC judges whether an action is good; ViKernel decides whether it is allowed, and can stop it.

' + '
ZTC checking...
' + '' + '
' + '
' + '
Pick an example or type a task, then press Run.
' + '

Session history

'; var $ = function (r) { return body.querySelector('[data-r="' + r + '"]'); }; var input = $('task'), runBtn = $('run'), out = $('out'); EXAMPLES.forEach(function (ex) { var b = document.createElement('button'); b.className = 'vz-chip'; b.textContent = ex; b.onclick = function () { input.value = ex; input.focus(); }; $('chips').appendChild(b); }); $('info').onclick = function () { var a = $('about'); a.hidden = !a.hidden; }; function drawHist() { if (!hist.length) { $('hist').innerHTML = '
No runs yet.
'; return; } $('hist').innerHTML = '' + hist.map(function (r) { return ''; }).join('') + '
TimeTaskZTCViKernelResult
' + esc(r.t) + '' + esc(r.task) + '' + esc(r.z) + '' + esc(r.g) + '' + (r.x ? 'Executed' : 'Not executed') + '
'; } drawHist(); window.VK_API('ztc/status').then(function (s) { var p = $('pill'); if (s && s.available) { p.className = 'vz-pill on'; p.textContent = 'ZTC online: ' + (s.model || 'judge'); } else { p.className = 'vz-pill off'; p.textContent = 'ZTC offline'; } }).catch(function () { var p = $('pill'); p.className = 'vz-pill off'; p.textContent = 'ZTC offline'; }); function run() { var task = input.value.trim(); if (!task || busy) return; busy = true; runBtn.disabled = true; out.innerHTML = '
Agent is proposing an action, then ZTC and ViKernel decide...
'; window.VK_API('ztc/run', { session: window.VK_SID, task: task }).then(function (d) { if (!d || d.error) throw new Error((d && d.error) || 'empty response'); var p = d.proposal || {}; out.innerHTML = '
' + ztcCard(d.ztc) + gateCard(d.gate) + '
' + '

Proposed action

fn ' + esc(p.fn || '(none)') + '
' + '
' + esc(JSON.stringify(p.args || {}, null, 2)) + '
' + (p.text ? '
' + esc(p.text) + '
' : '') + '
' + '
' + (d.executed ? 'Executed' : 'Not executed') + '. ' + esc(d.explanation) + '
'; var z = d.ztc || {}; hist.unshift({ t: new Date().toLocaleTimeString(), task: task, z: z.available ? (z.verdict + (typeof z.score === 'number' ? ' ' + z.score.toFixed(2) : '')) : 'offline', g: (d.gate && d.gate.verdict) || '-', x: !!d.executed }); saveHist(hist); drawHist(); }).catch(function (e) { var msg = e && e.message === 'rate' ? 'Rate limited. Please wait a moment and try again.' : 'Request failed: ' + (e && e.message || 'unknown error'); out.innerHTML = '
' + esc(msg) + '
'; if (h && h.toast) try { h.toast(msg); } catch (x) {} }).then(function () { busy = false; runBtn.disabled = false; }); } runBtn.onclick = run; input.onkeydown = function (e) { if (e.key === 'Enter') run(); }; } }; }); })();