diff --git a/packaging/mother/colibri-mcp-ssh b/packaging/mother/colibri-mcp-ssh index 029e429..ad3230d 100755 --- a/packaging/mother/colibri-mcp-ssh +++ b/packaging/mother/colibri-mcp-ssh @@ -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 ;; *) diff --git a/packaging/mother/dashboard/index.html b/packaging/mother/dashboard/index.html index dc109de..8584fa9 100644 --- a/packaging/mother/dashboard/index.html +++ b/packaging/mother/dashboard/index.html @@ -190,7 +190,6 @@ h1 .dot{display:inline-block; width:8px; height:8px; border-radius:50%; margin-r @@ -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) {
${fmtTokens(t.input_tokens||0)} in · ${fmtTokens(t.output_tokens||0)} out ${cachePct>0?` · ${cachePct}% cache` : ''}
- ${hasScreenshot ? '
▸ screenshot
' : hasProofText ? '
▸ text
' : ''} + ${hasProof ? '
▸ proof
' : ''} `; } @@ -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 = `${esc(taskId)} ${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'); }