app
Shotlog - Screenshot Log
Public Made by Adomby adom
See the shots your AI never showed you, and know it actually SAW them. adom-shotlog streams every screenshot the AI gathers into a live gallery (webview/pup/browser/phone), reports whether a human is really watching and on which surface, and ingests Adom Bridge child-window arrays via --meta.
← Commit history
Publish 0.23.3
7 files changed
+32−19
Cargo.lock+1−1@@ -10,7 +10,7 @@ checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" [[package]] name = "adom-shotlog"-version = "0.23.2"+version = "0.23.3" dependencies = [ "axum", "base64",
Cargo.toml+1−1@@ -1,6 +1,6 @@ [package] name = "adom-shotlog"-version = "0.23.2"+version = "0.23.3" edition = "2021" description = "Screenshot log viewer and CLI for Adom" license = "MIT"
VERSION+1−1@@ -1 +1 @@-0.23.2+0.23.3
bin/adom-shotlog⋯ 1 unchanged line ⋯
package.json+1−1@@ -1,6 +1,6 @@ { "slug": "adom-shotlog",- "version": "0.23.2",+ "version": "0.23.3", "type": "app", "title": "Adom Shotlog", "description": "See the shots your AI never showed you, and know it actually SAW them. adom-shotlog streams every screenshot the AI gathers into a live gallery (webview/pup/browser/phone), reports whether a human is really watching and on which surface, and ingests Adom Desktop child-window arrays via --meta.",
page.json+1−1@@ -1,6 +1,6 @@ { "slug": "adom-shotlog",- "version": "0.23.2",+ "version": "0.23.3", "type": "app", "title": "Adom Shotlog", "description": "See the shots your AI never showed you, and know it actually SAW them. adom-shotlog streams every screenshot the AI gathers into a live gallery (webview/pup/browser/phone), reports whether a human is really watching and on which surface, and ingests Adom Desktop child-window arrays via --meta.",
src/html/index.html+27−14@@ -231,6 +231,9 @@ header { padding: 2px 0; border-top: 1px solid rgba(255,255,255,.04); } .card-nerd .row .k { color: var(--text3); min-width: 120px; } .card-nerd .row .v { color: var(--text); user-select: all; word-break: break-all; }+.card-nerd .nbody { max-height: 340px; overflow-y: auto; }+.card-nerd pre { margin: 8px 0 0; padding: 8px; background: #0c0f12; border-radius: 6px; max-height: 220px;+ overflow: auto; font-family: 'JetBrains Mono', monospace; font-size: 10px; color: var(--text2); user-select: all; white-space: pre-wrap; word-break: break-all; } /* Zoom modal — full card */ .modal { position: fixed; inset: 0; background: rgba(0,0,0,.88); display: none;@@ -649,19 +652,26 @@ header { }); } function popList(e){ const p=e&&e.popups; return Array.isArray(p)?p:(p&&Array.isArray(p.popups)?p.popups:[]); }- // Build a flat readable [key,value] view of the capture metadata for the nerd panel.+ // EVERY field of the entry, flattened to readable dotted-key rows.+ // "Show me metadata" means ALL of it - nothing curated away. The friendly+ // rows (when / sizes) lead, then every remaining key recurses: meta.coordMap.*,+ // meta.screenshots[n].*, popups[n].*, the lot. function metaRows(e){- const rows=[]; const m=e.meta||{}; const cm=m.coordMap||{};+ const rows=[]; const push=(k,v)=>{ if(v!==undefined&&v!==null&&v!=='') rows.push([k,typeof v==='object'?JSON.stringify(v):String(v)]); };- push('shotId', m.shotId);+ const flat=(prefix,v)=>{+ if (v===null||v===undefined||v==='') return;+ if (Array.isArray(v)){ v.forEach((it,i)=>flat(prefix+'['+i+']',it)); return; }+ if (typeof v==='object'){ Object.keys(v).forEach(k=>flat(prefix?prefix+'.'+k:k, v[k])); return; }+ push(prefix, v);+ };+ push('when', e.timestamp?new Date(e.timestamp).toLocaleString():undefined); push('image size', (e.w&&e.h)?e.w+'×'+e.h:undefined); if(e.orig_w&&e.orig_h) push('orig capture', e.orig_w+'×'+e.orig_h);- push('screenRect', cm.screenRect);- push('dpiScale', cm.dpiScale!==undefined?cm.dpiScale:m.dpiScale);- push('imageToScreen', cm.imageToScreen);- push('screen resolution', cm.screenResolution||cm.screen||m.screenResolution);- const np=m.ownedPopupCount!==undefined?m.ownedPopupCount:popList(e).length;- push('child windows', np||undefined);+ const handled=['timestamp','w','h','orig_w','orig_h'];+ const lead=['id','filename','description','kb','source','thread','context','full'];+ lead.forEach(k=>flat(k, e[k]));+ Object.keys(e).forEach(k=>{ if(!handled.includes(k)&&!lead.includes(k)) flat(k, e[k]); }); return rows; } @@ -695,6 +705,7 @@ header { const kk=document.createElement('span'); kk.className='k'; kk.textContent=k; const vv=document.createElement('span'); vv.className='v'; vv.textContent=v; r.appendChild(kk); r.appendChild(vv); body.appendChild(r); });+ const pre=document.createElement('pre'); pre.textContent=raw; body.appendChild(pre); panel.appendChild(body); return panel; }@@ -741,10 +752,12 @@ header { b.setAttribute('data-tooltip','This capture also grabbed '+pops.length+' child window'+(pops.length>1?'s':'')+' of the parent window (dropdowns / dialogs) — shown below.'); meta.appendChild(b); } // ⓘ meta chip toggles the inline metadata panel right here on the card.+ // EVERY card gets it - the full entry record is always worth seeing, not+ // just shots that happen to carry an AD sidecar. let nerd=null, chip=null;- if (e.meta){ const s=document.createElement('span'); s.className='sep'; s.textContent='·'; meta.appendChild(s);+ { const s=document.createElement('span'); s.className='sep'; s.textContent='·'; meta.appendChild(s); chip=document.createElement('span'); chip.className='badge-nerd'; chip.textContent='ⓘ meta';- chip.setAttribute('data-tooltip','Tap to reveal the capture metadata (coordMap, DPI, screen rect) inline.');+ chip.setAttribute('data-tooltip','Tap to reveal EVERYTHING shotlog knows about this shot: the full entry record (thread, context, source, sizes), all capture metadata (coordMap, DPI, screen rect, child windows), and the raw JSON.'); meta.appendChild(chip); } c.appendChild(meta); const img=document.createElement('img'); img.className='shot-card-img'; img.src=imgUrl(e); img.alt=e.description||e.filename;@@ -768,9 +781,9 @@ header { c.appendChild(row); } // Inline nerd panel + wire the chip to toggle it in place.- if (e.meta){ nerd=buildNerdInline(e); c.appendChild(nerd);- chip.addEventListener('click', ev=>{ ev.stopPropagation();- const open=nerd.classList.toggle('open'); chip.classList.toggle('active', open); }); }+ nerd=buildNerdInline(e); c.appendChild(nerd);+ chip.addEventListener('click', ev=>{ ev.stopPropagation();+ const open=nerd.classList.toggle('open'); chip.classList.toggle('active', open); }); return c; }