fix/dashboard-dead-screenshot-code #242

Merged
clawdie merged 2 commits from fix/dashboard-dead-screenshot-code into main 2026-06-27 22:10:51 +02:00
2 changed files with 17 additions and 29 deletions

View file

@ -27,14 +27,10 @@ case "${SSH_ORIGINAL_COMMAND:-}" in
;;
"report-task-cost")
# Read TaskCostSummary JSON from stdin, INSERT into mother_hive.task_costs.
# Input: {"node_hostname":"debby","task_id":"abc","provider":"deepseek",
# "model":"deepseek-chat","input_tokens":150,"output_tokens":80,
# "cache_read_tokens":200,"cache_write_tokens":50,
# "cost_usd":0.0042,"success":true,
# "proof_text":"{\"agent\":\"zot\",\"state\":\"Done\",\"tokens_in\":150}",
# "screenshot_uuid":"a1b2c3d4e5f6",
# "finished_at":"2026-06-27T12:00:00Z"}
psql -d mother_hive -tA -v ON_ERROR_STOP=1 <<'PSQL'
# Uses psql variable interpolation (no pg_read_file — works with non-superuser).
# Input: {"node_hostname":"debby","task_id":"abc",...}
_json=$(cat)
psql -d mother_hive -tA -v ON_ERROR_STOP=1 -v json_input="$_json" <<'PSQL'
INSERT INTO task_costs (node_id, task_id, provider, model,
input_tokens, output_tokens, cache_read_tokens, cache_write_tokens,
cost_usd, success, proof_text, screenshot_uuid, finished_at)
@ -52,7 +48,7 @@ SELECT
NULLIF(j->>'proof_text', ''),
NULLIF(j->>'screenshot_uuid', ''),
COALESCE((j->>'finished_at')::TIMESTAMPTZ, now())
FROM (SELECT (pg_read_file('/dev/stdin')::JSONB) AS j) AS _;
FROM (SELECT (:'json_input'::JSONB) AS j) AS _;
PSQL
;;
*)

View file

@ -190,7 +190,6 @@ h1 .dot{display:inline-block; width:8px; height:8px; border-radius:50%; margin-r
<div class="lightbox" id="lightbox">
<button class="lightbox-close">Esc to close</button>
<div class="lightbox-meta" id="lightbox-meta"></div>
<img id="lb-img" src="" alt="screenshot proof" style="display:none">
<pre id="lb-text"></pre>
</div>
@ -306,9 +305,10 @@ function renderCard(t) {
const total = (t.input_tokens||0) + (t.cache_read_tokens||0);
const cachePct = total > 0 ? Math.round((t.cache_read_tokens||0) / total * 100) : 0;
const freshPct = 100 - cachePct;
const hasProofText = !!t.proof_text;
const hasScreenshot = !!t.screenshot_uuid;
const hasProof = hasProofText || hasScreenshot;
// Only proof_text exists — daemon captures glasspane state at task exit.
// screenshot_uuid is a schema column for future visual capture, never
// populated by the current daemon (no screenshot.rs module on main).
const hasProof = !!t.proof_text;
const cls = hasProof ? 'card has-proof' : 'card';
const onClick = hasProof
? `onclick="openProof(this,'${esc(t.task_id||'')}')"`
@ -327,7 +327,7 @@ function renderCard(t) {
<div class="card-tokens">${fmtTokens(t.input_tokens||0)} in · ${fmtTokens(t.output_tokens||0)} out
${cachePct>0?` · ${cachePct}% cache` : ''}
</div>
${hasScreenshot ? '<div class="card-proof-badge">screenshot</div>' : hasProofText ? '<div class="card-proof-badge">▸ text</div>' : ''}
${hasProof ? '<div class="card-proof-badge">proof</div>' : ''}
</div>`;
}
@ -336,24 +336,16 @@ function openProof(_el, taskId) {
const t = (DATA.tasks || []).find(t => t.task_id === taskId);
const lb = document.getElementById('lightbox');
const meta = document.getElementById('lightbox-meta');
const img = document.getElementById('lb-img');
const pre = document.getElementById('lb-text');
meta.innerHTML = `<strong>${esc(taskId)}</strong> ${esc(t?.provider||'')} · $${(t?.cost_usd||0).toFixed(4)}`;
// Hide both, then show the appropriate one.
img.style.display = 'none';
pre.style.display = 'none';
if (t?.screenshot_uuid) {
img.src = `../screenshots/${t.screenshot_uuid}.png`;
img.style.display = 'block';
} else if (t?.proof_text) {
let display;
try { display = JSON.stringify(JSON.parse(t.proof_text), null, 2); }
catch(_) { display = t.proof_text; }
pre.textContent = display;
pre.style.display = 'block';
}
// Proof is always inline text (glasspane state JSON).
const raw = t?.proof_text || '{}';
let display;
try { display = JSON.stringify(JSON.parse(raw), null, 2); }
catch(_) { display = raw; }
pre.textContent = display;
pre.style.display = 'block';
lb.classList.add('open');
}
function closeLb() { document.getElementById('lightbox').classList.remove('open'); }