diff --git a/packaging/mother/colibri-mcp-ssh b/packaging/mother/colibri-mcp-ssh index 9417e7c..754a130 100755 --- a/packaging/mother/colibri-mcp-ssh +++ b/packaging/mother/colibri-mcp-ssh @@ -30,12 +30,14 @@ case "${SSH_ORIGINAL_COMMAND:-}" in # 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":"a1b2c3d4e5f6", + # "cost_usd":0.0042,"success":true, + # "proof_text":"agent:hermes|cost:0.0042|tokens:150/80", + # "screenshot_uuid":"a1b2c3d4e5f6", # "finished_at":"2026-06-27T12:00:00Z"} psql -d mother_hive -tA -v ON_ERROR_STOP=1 <<'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, finished_at) + cost_usd, success, proof_text, screenshot_uuid, finished_at) SELECT (SELECT id FROM hive_nodes WHERE hostname = j->>'node_hostname'), j->>'task_id', @@ -48,6 +50,7 @@ SELECT COALESCE((j->>'cost_usd')::DOUBLE PRECISION, 0.0), COALESCE((j->>'success')::BOOLEAN, false), 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 _; PSQL diff --git a/packaging/mother/dashboard/deploy.sh b/packaging/mother/dashboard/deploy.sh index 1536919..79f25e1 100755 --- a/packaging/mother/dashboard/deploy.sh +++ b/packaging/mother/dashboard/deploy.sh @@ -5,7 +5,7 @@ # Places: # /usr/local/www/clawdie/dashboard/index.html — dashboard page # /usr/local/www/clawdie/dashboard/export-costs.sh — JSON export (cron) -# /usr/local/etc/cron.d/clawdie-dashboard — cron job +# /etc/crontab entry — cron job (FreeBSD) # # The dashboard reads task_costs.json (exported every 60s by cron) and # links screenshots from ../screenshots/ (tmux-screenshot publish dir). @@ -22,7 +22,7 @@ set -eu SRC="$(dirname "$0")" WEBROOT="/usr/local/www/clawdie/dashboard" -CRON_FILE="/usr/local/etc/cron.d/clawdie-dashboard" +CRON_MARKER="# clawdie-dashboard — auto-managed by deploy.sh" echo "=== deploy cost dashboard ===" @@ -32,18 +32,24 @@ cp "$SRC/index.html" "$WEBROOT/index.html" cp "$SRC/export-costs.sh" "$WEBROOT/export-costs.sh" chmod +x "$WEBROOT/export-costs.sh" -# Idempotent cron entry: export every 60s -cat > "$CRON_FILE" <<'CRON' -# clawdie cost dashboard — export task_costs to JSON every 60s -* * * * * root /usr/local/www/clawdie/dashboard/export-costs.sh -CRON +# FreeBSD cron: add to /etc/crontab (idempotent via marker line). +CRON_ENTRY="* * * * * root /usr/local/www/clawdie/dashboard/export-costs.sh ${CRON_MARKER}" +if ! grep -qF "${CRON_MARKER}" /etc/crontab 2>/dev/null; then + echo "${CRON_ENTRY}" >> /etc/crontab + echo " cron → /etc/crontab (added)" +else + echo " cron → /etc/crontab (already present)" +fi echo " dashboard → $WEBROOT/index.html" -echo " cron → $CRON_FILE" echo "" # Run once immediately to seed the data echo "=== initial export ===" -"$WEBROOT/export-costs.sh" || echo " (no data yet — tasks will appear as agents complete)" +if "$WEBROOT/export-costs.sh"; then + echo "" +else + echo " (no data yet — tasks will appear as agents complete)" +fi echo "" -echo "Done. Dashboard at: https://mother.clawdie.si/dashboard/" +echo "Done. Dashboard at: https://osa.smilepowered.org/dashboard/" diff --git a/packaging/mother/dashboard/export-costs.sh b/packaging/mother/dashboard/export-costs.sh index d704b18..d63bfce 100755 --- a/packaging/mother/dashboard/export-costs.sh +++ b/packaging/mother/dashboard/export-costs.sh @@ -7,7 +7,7 @@ set -eu OUTDIR="/usr/local/www/clawdie/dashboard" mkdir -p "$OUTDIR" -psql -d mother_hive -tA <<'SQL' > "${OUTDIR}/task_costs.json" +sudo -u postgres psql -d mother_hive -tA <<'SQL' > "${OUTDIR}/task_costs.json" SELECT json_build_object( 'updated_at', now(), 'summary', json_build_object( @@ -63,14 +63,15 @@ SELECT json_build_object( tc.cost_usd, tc.success, tc.finished_at, - tc.proof_text + tc.proof_text, + tc.screenshot_uuid FROM task_costs tc LEFT JOIN hive_nodes hn ON hn.id = tc.node_id ORDER BY tc.finished_at DESC LIMIT 200 ) AS t ) -) AS result; +) AS result FROM task_costs; SQL echo "dashboard: $(date -Iseconds) — $(jq '.summary.total_tasks' "${OUTDIR}/task_costs.json") tasks" >&2 diff --git a/packaging/mother/dashboard/index.html b/packaging/mother/dashboard/index.html index a23eec9..dc109de 100644 --- a/packaging/mother/dashboard/index.html +++ b/packaging/mother/dashboard/index.html @@ -114,6 +114,7 @@ h1 .dot{display:inline-block; width:8px; height:8px; border-radius:50%; margin-r .lightbox{display:none; position:fixed; inset:0; background:rgba(0,0,0,.94); z-index:1000; align-items:center; justify-content:center; padding:1.5rem} .lightbox.open{display:flex} +.lightbox img{max-width:94vw; max-height:88vh; border-radius:4px; box-shadow:0 0 40px rgba(0,180,216,.15)} .lightbox pre{max-width:94vw; max-height:88vh; border-radius:4px; box-shadow:0 0 40px rgba(0,180,216,.15)} .lightbox-close{position:fixed; top:1rem; right:1.5rem; background:var(--surface); color:var(--fg2); border:1px solid var(--border); border-radius:4px; padding:.4rem 1rem; font-family:inherit; @@ -189,6 +190,7 @@ h1 .dot{display:inline-block; width:8px; height:8px; border-radius:50%; margin-r