You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

129 lines
7.0 KiB

'use strict';
(function () {
var UI_ID = 'dshmem-panel';
var LOG_CAP = 60;
var state = {
phase: 'off',
connected: false,
loopsLeft: 0, loopsMax: 0,
dailyCount: 0, dailyMax: 0,
resetCbs: [], stopCbs: [], saveCbs: [], startCbs: [], dotMode: null
};
var el = {};
function byId(id) { return document.getElementById(id); }
function mk(tag, cls, txt) {
var n = document.createElement(tag);
if (cls) n.className = cls;
if (txt !== undefined) n.textContent = txt;
return n;
}
function build() {
if (byId(UI_ID)) return;
var root = mk('div', 'dshmem-panel');
root.id = UI_ID;
var head = mk('div', 'dshmem-head');
el.dot = mk('span', 'dshmem-dot');
el.dot.id = 'dshmem-dot';
var title = mk('span', 'dshmem-title', 'DSH Memory');
el.phase = mk('span', 'dshmem-phase', 'Off');
el.phase.id = 'dshmem-phase';
el.toggle = mk('span', 'dshmem-toggle', '-');
head.appendChild(el.dot); head.appendChild(title); head.appendChild(el.phase); head.appendChild(el.toggle);
el.body = mk('div', 'dshmem-body');
root.appendChild(head); root.appendChild(el.body);
var row1 = mk('div', 'dshmem-row');
el.start = mk('button', 'dshmem-btn primary', 'Start'); el.reset = mk('button', 'dshmem-btn', 'Reset queue');
el.stop = mk('button', 'dshmem-btn danger', 'Stop');
row1.appendChild(el.start); row1.appendChild(el.reset); row1.appendChild(el.stop);
el.body.appendChild(row1); el.stats = mk('div','dshmem-stats'); el.stats.id='dshmem-stats'; el.body.appendChild(el.stats); el.metrics = mk('div','dshmem-stats'); el.metrics.id='dshmem-metrics'; el.metrics.textContent='metrics: —'; el.body.appendChild(el.metrics);
var set = mk('div', 'dshmem-settings');
var lbl = mk('div', 'dshmem-label', 'Token (save, then reload page)');
el.token = mk('input', 'dshmem-input');
el.token.type = 'password';
el.token.placeholder = 'dshmem-bridge-token';
var row2 = mk('div', 'dshmem-row');
el.save = mk('button', 'dshmem-btn primary', 'Save');
el.health = mk('button', 'dshmem-btn', 'Health');
row2.appendChild(el.save); row2.appendChild(el.health);
set.appendChild(lbl); set.appendChild(el.token); set.appendChild(row2);
el.body.appendChild(set);
el.log = mk('div', 'dshmem-log');
el.log.id = 'dshmem-log';
el.body.appendChild(el.log);
el.preview = mk('div', 'dshmem-preview');
el.preview.style.display = 'none';
el.body.appendChild(el.preview);
el.confirm = mk('div', 'dshmem-confirm-box');
el.confirm.style.display = 'none';
el.body.appendChild(el.confirm);
document.body.appendChild(root);
}
function wire() {
el.toggle.addEventListener('click', function () {
el.body.style.display = el.body.style.display === 'none' ? '' : 'none';
});
el.reset.addEventListener('click', function () { el.start.disabled = false; state.resetCbs.forEach(function (cb) { try { cb(); } catch (e) {} }); });
el.stop.addEventListener('click', function () { el.start.disabled = false; state.stopCbs.forEach(function (cb) { try { cb(); } catch (e) {} }); }); el.start.addEventListener('click', function () { el.start.disabled = true; state.startCbs.forEach(function (cb) { try { cb(); } catch (e) {} }); });
el.save.addEventListener('click', function () { var v = el.token.value || ''; state.saveCbs.forEach(function (cb) { try { cb(v); } catch (e) {} }); });
el.health.addEventListener('click', function () {
try { globalThis.DSH_BRIDGE.health().then(function (r) {
if (r && r.ok) { API.setConnected(true); API.log('health ok, bridge up'); }
else { API.setConnected(false); API.log('health fail: ' + ((r && r.error && r.error.message) || '?')); }
}); } catch (e) { API.log('health throw: ' + String(e)); }
});
}
var API = {
setPhase: function (p) { state.phase = p; if (el.phase) el.phase.textContent = p; },
setConnected: function (b) { state.connected = !!b; API._applyDot(); }, setDot: function (m) { state.dotMode = (m === 'ok') ? null : m; API._applyDot(); }, _applyDot: function () { if (!el.dot) return; var md = state.dotMode || (state.connected ? 'ok' : 'err'); var cls = 'dshmem-dot'; if (md === 'ok' || md === 'err' || md === 'busy' || md === 'ok-busy') cls += ' ' + md; el.dot.className = cls; },
setStartEnabled: function (b) { if (el.start) el.start.disabled = !b; }, setStats: function (ws, memN, skillN) { if (!el.stats) return; el.stats.textContent = 'WS: ' + (ws || '?') + ' mem: ' + (memN || 0) + ' skills: ' + (skillN || 0); }, setMetrics: function (m) { if (!el.metrics) return; if (!m) { el.metrics.textContent = 'metrics: —'; return; } el.metrics.textContent = 'acc: ' + m.accum + ' · turn: ' + m.delta + ' · msg: ' + m.chars + 'ch (~' + m.est_tok + 't) ctx ' + (m.ctx_tok || 0) + 't ' + (m.ctx_pct || 0) + 'pct'; },
log: function (m) {
if (!el.log) return;
var t = new Date().toLocaleTimeString();
var line = '[' + t + '] ' + m;
var txt = (line + String.fromCharCode(10) + (el.log.textContent || '')).split(String.fromCharCode(10)).slice(0, LOG_CAP).join(String.fromCharCode(10));
el.log.textContent = txt;
},
onResetLoops: function (cb) { state.resetCbs.push(cb); },
onStop: function (cb) { state.stopCbs.push(cb); }, onStart: function (cb) { state.startCbs.push(cb); },
onSaveToken: function (cb) { state.saveCbs.push(cb); },
getToken: function () { return el.token ? el.token.value : ''; },
setToken: function (v) { if (el.token) el.token.value = v || ''; },
showConfirm: function (opt) {
if (!el.confirm) return;
opt = opt || {};
el.confirm.textContent = '';
el.confirm.appendChild(mk('div', 'dshmem-confirm-title', opt.title || 'Confirm'));
el.confirm.appendChild(mk('div', 'dshmem-label', opt.detail || ''));
var r = mk('div', 'dshmem-row');
var ok = mk('button', 'dshmem-btn primary', 'Allow');
var no = mk('button', 'dshmem-btn danger', 'Deny');
ok.addEventListener('click', function () { API.hideConfirm(); if (opt.onAllow) opt.onAllow(); });
no.addEventListener('click', function () { API.hideConfirm(); if (opt.onDeny) opt.onDeny(); });
r.appendChild(ok); r.appendChild(no); el.confirm.appendChild(r);
el.confirm.style.display = 'block';
},
hideConfirm: function () { if (el.confirm) el.confirm.style.display = 'none'; },
showPreview: function (opt) {
if (!el.preview) return;
opt = opt || {};
var sec = opt.seconds || 2;
var text = opt.text || '';
var cancelled = false;
el.preview.style.display = 'block';
var render = function () { el.preview.textContent = 'Sending in ' + sec + 's (click to cancel):' + String.fromCharCode(10) + text.slice(0, 500); };
render();
var iv = setInterval(function () {
sec--;
if (sec <= 0) { clearInterval(iv); el.preview.style.display = 'none'; el.preview.onclick = null; if (!cancelled && opt.onSend) opt.onSend(); }
else render();
}, 1000);
el.preview.onclick = function () { cancelled = true; clearInterval(iv); el.preview.style.display = 'none'; el.preview.onclick = null; if (opt.onCancel) opt.onCancel(); };
},
hidePreview: function () { if (el.preview) el.preview.style.display = 'none'; },
init: function () { build(); wire(); }
};
globalThis.DSHMEM = API;
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', function () { API.init(); });
} else { API.init(); }
})();