rosie / console.html
betterwithage's picture
Mobile retrofit: viewport-fit + PWA/iOS meta + responsive safety on landing pages
6ae1409 verified
<!DOCTYPE html>
<!-- SPDX-License-Identifier: Apache-2.0 © 2026 SZL Holdings · Doctrine v11 · Sign: Yachay · Co-Authored-By: Perplexity Computer Agent -->
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover, user-scalable=yes">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="theme-color" content="#0a0e14">
<title>Rosie · Operator Console v3.0.0</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
<style>
:root{
--bg:#0a0e14; --panel:#10151f; --panel2:#0d1219; --line:#1d2533;
--gold:#d4a444; --gold-dim:#8a6d2c; --text:#f4eede; --muted:#8b94a3;
--green:#3fa66a; --red:#c0504d; --mono:'SF Mono',ui-monospace,'Cascadia Code',Menlo,monospace;
}
*{box-sizing:border-box;margin:0;padding:0}
body{background:var(--bg);color:var(--text);font:13px/1.5 var(--mono);overflow-x:hidden}
a{color:var(--gold);text-decoration:none}
.hdr{display:flex;align-items:center;gap:18px;padding:10px 18px;border-bottom:1px solid var(--line);
background:linear-gradient(180deg,#10151f,#0a0e14);position:sticky;top:0;z-index:50}
.hdr h1{font-size:14px;font-weight:600;letter-spacing:.04em;color:var(--gold)}
.hdr .meta{color:var(--muted);font-size:11px}
.badge{padding:2px 8px;border:1px solid var(--line);border-radius:3px;font-size:11px}
.badge.ok{color:var(--green);border-color:var(--green)}
.badge.bad{color:var(--red);border-color:var(--red)}
.grid{display:grid;grid-template-columns:360px 1fr 380px;gap:1px;background:var(--line);min-height:calc(100vh - 44px)}
.col{background:var(--bg);padding:14px;overflow-y:auto;max-height:calc(100vh - 44px)}
.card{background:var(--panel);border:1px solid var(--line);border-radius:5px;padding:12px;margin-bottom:12px}
.card h2{font-size:11px;text-transform:uppercase;letter-spacing:.1em;color:var(--gold-dim);margin-bottom:10px;font-weight:600}
label{display:block;color:var(--muted);font-size:11px;margin:8px 0 4px}
select,textarea,input{width:100%;background:var(--panel2);border:1px solid var(--line);color:var(--text);
padding:8px;border-radius:4px;font:12px var(--mono)}
textarea{resize:vertical;min-height:90px}
button{background:var(--gold);color:#0a0e14;border:none;padding:9px 16px;border-radius:4px;font-weight:600;
cursor:pointer;font:12px var(--mono);margin-top:10px}
button:hover{background:#e6b955}
button.ghost{background:transparent;color:var(--gold);border:1px solid var(--gold-dim)}
pre{background:#080b10;border:1px solid var(--line);border-radius:4px;padding:10px;overflow:auto;
font-size:11px;max-height:340px;white-space:pre-wrap;word-break:break-all}
table{width:100%;border-collapse:collapse;font-size:11px}
th{text-align:left;color:var(--gold-dim);font-weight:600;padding:5px 6px;border-bottom:1px solid var(--line);
text-transform:uppercase;letter-spacing:.06em;font-size:10px}
td{padding:4px 6px;border-bottom:1px solid #131922;color:var(--muted);font-size:10.5px}
td.h{color:var(--text);font-family:var(--mono)}
.dot{display:inline-block;width:7px;height:7px;border-radius:50%;margin-right:5px}
.dot.up{background:var(--green)} .dot.down{background:var(--red)}
.kv{display:flex;justify-content:space-between;padding:3px 0;border-bottom:1px solid #131922}
.kv span:first-child{color:var(--muted)} .kv span:last-child{color:var(--text)}
#scene{width:100%;height:240px;border:1px solid var(--line);border-radius:5px;background:#070a0f}
.pass{color:var(--green)} .fail{color:var(--red)}
.wire-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:6px}
.wire{background:var(--panel2);border:1px solid var(--line);border-radius:4px;padding:6px;text-align:center}
.wire b{color:var(--gold);font-size:12px}
.small{font-size:10px;color:var(--muted)}
</style>
<style id="szl-mobile-safety">
/* SZL mobile-first safety net (ADDITIVE — Yachay) */
:root { --vh: 1vh; }
html, body { -webkit-tap-highlight-color: transparent; }
@media (max-width: 768px) {
html, body { max-width: 100vw; overflow-x: hidden; }
body { font-size: 16px; }
h1 { font-size: 24px; line-height: 1.2; }
img, canvas, svg, video, iframe { max-width: 100%; height: auto; }
a, button, [role="button"], input[type="submit"] { min-height: 44px; min-width: 44px; }
.row, .grid, .flex, [class*="grid"], [class*="flex"] { flex-wrap: wrap; }
pre, code, table { max-width: 100%; overflow-x: auto; }
}
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after { animation-duration: 0.001ms !important; animation-iteration-count: 1 !important; transition-duration: 0.001ms !important; scroll-behavior: auto !important; }
}
</style>
<script>
/* SZL --vh fix for iOS Safari dynamic viewport (ADDITIVE) */
(function(){
function setVH(){ document.documentElement.style.setProperty('--vh', (window.innerHeight*0.01)+'px'); }
setVH(); window.addEventListener('resize', setVH); window.addEventListener('orientationchange', setVH);
})();
</script>
</head>
<body>
<div class="hdr">
<h1>Rosie · Operator Console v3.0.0</h1>
<span class="meta">Doctrine v11</span>
<span class="meta" id="numbers">749 decl / 14 axioms / 163 sorries</span>
<span class="meta">SHA <span id="sha"></span></span>
<span class="meta">key <span id="fp"></span></span>
<span class="badge" id="signbadge">signing…</span>
<span style="flex:1"></span>
<span class="meta">receipts <b id="rcount" style="color:var(--gold)">0</b></span>
</div>
<div class="grid">
<!-- LEFT: command prompt -->
<div class="col">
<div class="card">
<h2>Command Surface</h2>
<label>Command</label>
<select id="cmd"></select>
<label>Caller</label>
<input id="caller" value="betterwithage">
<label>Args (JSON)</label>
<textarea id="args">{}</textarea>
<button id="dispatch">Dispatch</button>
<button class="ghost" id="fillexample" style="margin-left:8px">Example args</button>
</div>
<div class="card">
<h2>Signed Receipt</h2>
<pre id="receipt">— dispatch a command —</pre>
</div>
</div>
<!-- CENTER: 3D + command log -->
<div class="col">
<div class="card">
<h2>Operator Field · head rotation bound to live receipt count</h2>
<div id="scene"></div>
</div>
<div class="card">
<h2>Command Log · chain-verified · polls every 5s</h2>
<div id="chaininfo" class="small">chain: …</div>
<table>
<thead><tr><th>seq</th><th>kind</th><th>command</th><th>gate</th><th>hash</th><th>prev</th></tr></thead>
<tbody id="logbody"></tbody>
</table>
</div>
</div>
<!-- RIGHT: connections + wires + state -->
<div class="col">
<div class="card">
<h2>Operator State</h2>
<div id="state"></div>
</div>
<div class="card">
<h2>Sibling Connection Matrix</h2>
<div id="conns"><span class="small">probing 4 organs…</span></div>
</div>
<div class="card">
<h2>Mesh Wires (rosie)</h2>
<div class="wire-grid">
<div class="wire"><b>B</b><div class="small">immune</div></div>
<div class="wire"><b>C</b><div class="small">receipt</div></div>
<div class="wire"><b id="wd">D</b><div class="small">traceparent</div></div>
<div class="wire"><b>E</b><div class="small">field</div></div>
<div class="wire"><b>F</b><div class="small">khipu</div></div>
<div class="wire"><b>G</b><div class="small">sockets</div></div>
</div>
<div class="small" style="margin-top:8px">Wire D status: <span id="wdstat"></span></div>
</div>
</div>
</div>
<script>
const API='/api/rosie/v2';
const CMDS=[
["health.check.flagship",{flagship:"a11oy"}],
["khipu.write",{payload:{note:"operator note"},tags:["ops"]}],
["khipu.verify",{receipt_id:""}],
["yuyay.gate.evaluate",{signal:{caller:"betterwithage",command:"deploy"}}],
["puriq.formula.run",{formula_id:"F1",inputs:{}}],
["sentra.threat.scan",{target:"payload-sample"}],
["killinchu.drone.lookup",{drone_id:1}],
["lean.theorem.lookup",{theorem_name:"lambda_floor"}],
["dsse.sign.payload",{payload:{claim:"operator"}}],
["dsse.verify.envelope",{envelope:{},pubkey_id:"rosie-operator-p256"}],
["wire.b.signal",{}],
["wire.c.receipt",{}],
["wire.d.traceparent",{}],
["escalate.operator",{severity:"warning",msg:"operator test"}],
["metrics.snapshot",{}],
["provenance.dump",{}]
];
const sel=document.getElementById('cmd');
CMDS.forEach(([c])=>{const o=document.createElement('option');o.value=c;o.textContent=c;sel.appendChild(o)});
const exMap=Object.fromEntries(CMDS);
document.getElementById('fillexample').onclick=()=>{document.getElementById('args').value=JSON.stringify(exMap[sel.value],null,2)};
sel.onchange=document.getElementById('fillexample').onclick;
document.getElementById('fillexample').onclick();
async function jget(p){try{const r=await fetch(p);return await r.json()}catch(e){return{error:String(e)}}}
async function header(){
const id=await jget(API+'/identity');
if(id.build_sha)document.getElementById('sha').textContent=(id.build_sha||'').slice(0,8);
if(id.numbers)document.getElementById('numbers').textContent=`${id.numbers.declarations} decl / ${id.numbers.axioms} axioms / ${id.numbers.sorries} sorries`;
const fp=await jget(API+'/keys/fingerprint');
document.getElementById('fp').textContent=(fp.sha256||'').slice(0,10);
const b=document.getElementById('signbadge');
if(fp.signing_available){b.textContent='ECDSA P-256 loaded';b.className='badge ok'}
else{b.textContent='signing placeholder';b.className='badge bad'}
}
document.getElementById('dispatch').onclick=async()=>{
let args={};try{args=JSON.parse(document.getElementById('args').value||'{}')}catch(e){alert('bad JSON');return}
const body={command:sel.value,caller:document.getElementById('caller').value,args};
const r=await fetch(API+'/command',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(body)});
const j=await r.json();
document.getElementById('receipt').textContent=JSON.stringify(j,null,2);
refreshLog();
};
let receiptCount=0;
async function refreshLog(){
const j=await jget(API+'/command-log?limit=40');
const tb=document.getElementById('logbody');tb.innerHTML='';
(j.receipts||[]).slice().reverse().forEach(r=>{
const tr=document.createElement('tr');
const g=r.gate_pass===1?'<span class=pass>pass</span>':(r.gate_pass===0?'<span class=fail>fail</span>':'—');
tr.innerHTML=`<td class=h>${r.seq}</td><td>${r.kind}</td><td class=h>${r.command||''}</td><td>${g}</td>`+
`<td title="${r.hash}">${(r.hash||'').slice(0,10)}</td><td title="${r.prev_hash}">${(r.prev_hash||'').slice(0,8)}</td>`;
tb.appendChild(tr);
});
document.getElementById('chaininfo').innerHTML=
`chain ${j.chain_verified?'<span class=pass>VERIFIED</span>':'<span class=fail>BROKEN</span>'} · depth ${j.depth} · genesis ${(j.genesis_hash||'').slice(0,10)} → final ${(j.final_hash||'').slice(0,10)}`;
receiptCount=j.depth||0;
document.getElementById('rcount').textContent=receiptCount;
}
async function refreshState(){
const s=await jget(API+'/state');
document.getElementById('state').innerHTML=
['status','current_command','uptime_seconds','command_count','chain_depth','last_receipt_hash']
.map(k=>`<div class=kv><span>${k}</span><span>${k==='last_receipt_hash'?String(s[k]||'').slice(0,16):(s[k]??'—')}</span></div>`).join('');
}
async function refreshConns(){
const c=await jget(API+'/connections');
const el=document.getElementById('conns');
if(!c.siblings){el.innerHTML='<span class=small>unavailable</span>';return}
el.innerHTML=Object.entries(c.siblings).map(([s,v])=>
`<div class=kv><span><span class="dot ${v.up?'up':'down'}"></span>${s}</span>`+
`<span>${v.up?(v.latency_ms+'ms'):'down'}${v.wire_d_live?' · D':''}</span></div>`).join('')+
`<div class=small style="margin-top:6px">${c.summary}</div>`;
}
async function refreshWireD(){
const w=await jget('/api/rosie/wires/D');
const ok=w.status==='LIVE';
document.getElementById('wdstat').innerHTML=ok?'<span class=pass>LIVE</span>':'<span class=fail>down</span>';
document.getElementById('wd').style.color=ok?'var(--green)':'var(--red)';
}
// 3D scene — rotating wireframe head, rotation speed bound to live receipt count
let renderer,scene,camera,head,rings=[];
function init3D(){
const el=document.getElementById('scene');
scene=new THREE.Scene();
camera=new THREE.PerspectiveCamera(45,el.clientWidth/240,0.1,100);camera.position.z=4;
renderer=new THREE.WebGLRenderer({antialias:true,alpha:true});
renderer.setSize(el.clientWidth,240);el.appendChild(renderer.domElement);
const geo=new THREE.IcosahedronGeometry(1.2,1);
head=new THREE.LineSegments(new THREE.WireframeGeometry(geo),
new THREE.LineBasicMaterial({color:0xd4a444}));
scene.add(head);
for(let i=0;i<3;i++){
const r=new THREE.Mesh(new THREE.TorusGeometry(1.7+i*0.25,0.006,8,80),
new THREE.MeshBasicMaterial({color:0x8a6d2c}));
r.rotation.x=Math.PI/2*(i%2);r.rotation.y=i*0.5;scene.add(r);rings.push(r);
}
animate();
}
function animate(){
requestAnimationFrame(animate);
const speed=0.002+Math.min(0.05,receiptCount*0.0004); // bound to real receipt count
if(head)head.rotation.y+=speed,head.rotation.x+=speed*0.4;
rings.forEach((r,i)=>r.rotation.z+=speed*(i+1)*0.5);
renderer.render(scene,camera);
}
header();refreshLog();refreshState();refreshConns();refreshWireD();
try{init3D()}catch(e){console.warn('3d',e)}
setInterval(refreshLog,5000);
setInterval(refreshState,5000);
setInterval(refreshConns,15000);
setInterval(refreshWireD,15000);
</script>
</body>
</html>