From 4f83465430c30443d6fa4050670b9c706eb83ce5 Mon Sep 17 00:00:00 2001 From: Alexander Whitestone Date: Sun, 22 Mar 2026 18:58:30 -0400 Subject: [PATCH] feat: add Gemini feed pane and stats to ops dashboard - 3 equal stacked feed panes on right (Kimi/Claude/Gemini) - Gemini service status, stats, and queue in ops-panel - Gemini live log feed with color highlighting Co-Authored-By: Claude Opus 4.6 --- bin/ops-dashboard-v2.sh | 30 +++++++++++++++---------- bin/ops-panel.sh | 50 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 12 deletions(-) diff --git a/bin/ops-dashboard-v2.sh b/bin/ops-dashboard-v2.sh index d1ee52a..2f14257 100755 --- a/bin/ops-dashboard-v2.sh +++ b/bin/ops-dashboard-v2.sh @@ -1,12 +1,12 @@ #!/usr/bin/env bash # ── Hermes Ops Dashboard v2 ──────────────────────────────────────────── -# 4-pane layout with dual agent feeds: +# 5-pane layout with triple agent feeds: # ┌───────────────────────────────────┬────────────────────────────────┐ # │ │ KIMI LIVE FEED │ -# │ STATUS + GITEA + QUEUE │ (tail log, colored) │ -# │ (auto-refresh 20s) ├────────────────────────────────┤ -# │ │ CLAUDE LIVE FEED │ -# │ │ (tail log, colored) │ +# │ STATUS + GITEA + QUEUE ├────────────────────────────────┤ +# │ (auto-refresh 20s) │ CLAUDE LIVE FEED │ +# │ ├────────────────────────────────┤ +# │ │ GEMINI LIVE FEED │ # ├───────────────────────────────────┴────────────────────────────────┤ # │ CONTROLS (bash prompt with helpers loaded) │ # └────────────────────────────────────────────────────────────────────┘ @@ -23,12 +23,14 @@ tmux split-window -h -p 45 -t "$SESSION" # Split left pane: top status (80%) | bottom controls (20%) tmux split-window -v -p 20 -t "$SESSION:1.1" -# Split right pane: top kimi (50%) | bottom claude (50%) -tmux split-window -v -p 50 -t "$SESSION:1.2" +# Split right pane into 3 equal feeds: kimi (top 33%) | claude (mid 33%) | gemini (bot 33%) +tmux split-window -v -p 67 -t "$SESSION:1.2" +tmux split-window -v -p 50 -t "$SESSION:1.3" # Initialize log files if they don't exist touch ~/.hermes/logs/kimi-loop.log 2>/dev/null touch ~/.hermes/logs/claude-loop.log 2>/dev/null +touch ~/.hermes/logs/gemini-loop.log 2>/dev/null # Pane 1 (top-left): consolidated status, auto-refresh tmux send-keys -t "$SESSION:1.1" "watch -n 20 -t -c 'bash ~/.hermes/bin/ops-panel.sh'" Enter @@ -36,17 +38,21 @@ tmux send-keys -t "$SESSION:1.1" "watch -n 20 -t -c 'bash ~/.hermes/bin/ops-pane # Pane 2 (top-right): kimi live feed with color tmux send-keys -t "$SESSION:1.2" "echo -e '\\033[1m\\033[33m KIMI FEED\\033[0m' && tail -f ~/.hermes/logs/kimi-loop.log | GREP_COLOR='1;32' grep --color=always -E 'SUCCESS|$' | GREP_COLOR='1;31' grep --color=always -E 'FAILED|BACKOFF|$' | GREP_COLOR='1;36' grep --color=always -E 'ISSUE #[0-9]+|$'" Enter -# Pane 3 (bottom-right): claude live feed with color +# Pane 3 (mid-right): claude live feed with color tmux send-keys -t "$SESSION:1.3" "echo -e '\\033[1m\\033[35m CLAUDE FEED\\033[0m' && tail -f ~/.hermes/logs/claude-loop.log | GREP_COLOR='1;32' grep --color=always -E 'SUCCESS|$' | GREP_COLOR='1;31' grep --color=always -E 'FAILED|BACKOFF|$' | GREP_COLOR='1;36' grep --color=always -E 'ISSUE #[0-9]+|$'" Enter -# Pane 4 (bottom-left): controls with helpers sourced -tmux send-keys -t "$SESSION:1.4" "source ~/.hermes/bin/ops-helpers.sh && ops-help" Enter +# Pane 4 (bottom-right): gemini live feed with color +tmux send-keys -t "$SESSION:1.4" "echo -e '\\033[1m\\033[32m GEMINI FEED\\033[0m' && tail -f ~/.hermes/logs/gemini-loop.log | GREP_COLOR='1;32' grep --color=always -E 'SUCCESS|$' | GREP_COLOR='1;31' grep --color=always -E 'FAILED|BACKOFF|$' | GREP_COLOR='1;36' grep --color=always -E 'ISSUE #[0-9]+|$'" Enter + +# Pane 5 (bottom-left): controls with helpers sourced +tmux send-keys -t "$SESSION:1.5" "source ~/.hermes/bin/ops-helpers.sh && ops-help" Enter # Set pane titles tmux select-pane -t "$SESSION:1.1" -T "Status" tmux select-pane -t "$SESSION:1.2" -T "Kimi Feed" tmux select-pane -t "$SESSION:1.3" -T "Claude Feed" -tmux select-pane -t "$SESSION:1.4" -T "Controls" +tmux select-pane -t "$SESSION:1.4" -T "Gemini Feed" +tmux select-pane -t "$SESSION:1.5" -T "Controls" # Border styling tmux set-option -t "$SESSION" pane-border-status top @@ -55,6 +61,6 @@ tmux set-option -t "$SESSION" pane-border-style "fg=colour240" tmux set-option -t "$SESSION" pane-active-border-style "fg=cyan" # Focus on controls pane -tmux select-pane -t "$SESSION:1.4" +tmux select-pane -t "$SESSION:1.5" tmux attach -t "$SESSION" diff --git a/bin/ops-panel.sh b/bin/ops-panel.sh index 1ef0741..4ce8505 100755 --- a/bin/ops-panel.sh +++ b/bin/ops-panel.sh @@ -49,6 +49,19 @@ else echo -e " ${FAIL} Claude Loop ${RD}DOWN — run: ops-wake-claude${R}" fi +# Gemini Code loop +GEMINI_PID=$(pgrep -f "gemini-loop.sh" 2>/dev/null | head -1) +GEMINI_WORK=$(pgrep -f "gemini.*--print" 2>/dev/null | head -1) +if [ -n "$GEMINI_PID" ]; then + if [ -n "$GEMINI_WORK" ]; then + echo -e " ${OK} Gemini Loop ${D}pid $GEMINI_PID ${G}working${R}" + else + echo -e " ${WARN} Gemini Loop ${D}pid $GEMINI_PID ${Y}between issues${R}" + fi +else + echo -e " ${FAIL} Gemini Loop ${RD}DOWN — run: ops-wake-gemini${R}" +fi + # Gitea VPS if curl -s --max-time 3 "http://143.198.27.163:3000/api/v1/version" >/dev/null 2>&1; then echo -e " ${OK} Gitea VPS ${D}143.198.27.163:3000${R}" @@ -131,6 +144,26 @@ else fi echo "" +# ── GEMINI STATS ───────────────────────────────────────────────────── +echo -e " ${B}${U}GEMINI${R}" +echo "" +GEMINI_LOG="$HOME/.hermes/logs/gemini-loop.log" +if [ -f "$GEMINI_LOG" ]; then + GM_COMPLETED=$(grep -c "SUCCESS:" "$GEMINI_LOG" 2>/dev/null || echo 0) + GM_FAILED=$(grep -c "FAILED:" "$GEMINI_LOG" 2>/dev/null || echo 0) + GM_RATE="" + if [ "$GM_COMPLETED" -gt 0 ] || [ "$GM_FAILED" -gt 0 ]; then + GM_TOTAL=$((GM_COMPLETED + GM_FAILED)) + [ "$GM_TOTAL" -gt 0 ] && GM_PCT=$((GM_COMPLETED * 100 / GM_TOTAL)) && GM_RATE=" (${GM_PCT}%)" + fi + GM_LAST=$(grep "=== ISSUE" "$GEMINI_LOG" | tail -1 | sed 's/.*=== //' | sed 's/ ===//') + echo -e " ${G}${B}$GM_COMPLETED${R} done ${RD}$GM_FAILED${R} fail${D}$GM_RATE${R}" + [ -n "$GM_LAST" ] && echo -e " Current ${C}$GM_LAST${R}" +else + echo -e " ${D}(no log yet — start with ops-wake-gemini)${R}" +fi +echo "" + # ── OPEN PRS ─────────────────────────────────────────────────────────── echo -e " ${B}${U}PULL REQUESTS${R}" echo "" @@ -217,6 +250,23 @@ else: " 2>/dev/null echo "" +# ── GEMINI QUEUE ───────────────────────────────────────────────────── +echo -e " ${B}${U}GEMINI QUEUE${R}" +echo "" +curl -s --max-time 5 -H "Authorization: token $TOKEN" "$API/issues?state=open&assignee=gemini&limit=10&type=issues" 2>/dev/null | python3 -c " +import json,sys +try: + issues = json.loads(sys.stdin.read()) + if not issues: print(' \033[33m⚠ Queue empty — assign issues to gemini\033[0m') + for i in issues[:6]: + n = i['number'] + t = i['title'][:55] + print(f' #{n:<4d} {t}') + if len(issues) > 6: print(f' \033[2m... +{len(issues)-6} more\033[0m') +except: print(' \033[31m(error)\033[0m') +" 2>/dev/null +echo "" + # ── WARNINGS ─────────────────────────────────────────────────────────── HERMES_PROCS=$(ps aux | grep -E "hermes.*python" | grep -v grep | wc -l | tr -d ' ') STUCK_GIT=$(ps aux | grep "git.*push\|git-remote-http" | grep -v grep | wc -l | tr -d ' ')