#!/usr/bin/env bash # ── Dashboard Control Helpers ────────────────────────────────────────── # Source this in the controls pane: source ~/.hermes/bin/ops-helpers.sh # ─────────────────────────────────────────────────────────────────────── export TOKEN=$(cat ~/.hermes/gitea_token_vps 2>/dev/null) export GITEA="http://143.198.27.163:3000" export REPO_API="$GITEA/api/v1/repos/rockachopa/Timmy-time-dashboard" ops-help() { echo "" echo -e "\033[1m\033[35m ◈ CONTROLS\033[0m" echo -e "\033[2m ──────────────────────────────────────\033[0m" echo "" echo -e " \033[1mWake Up\033[0m" echo " ops-wake-kimi Restart Kimi loop" echo " ops-wake-claude Restart Claude loop" echo " ops-wake-gemini Restart Gemini loop" echo " ops-wake-gateway Restart gateway" echo " ops-wake-all Restart everything" echo "" echo -e " \033[1mManage\033[0m" echo " ops-merge PR_NUM Squash-merge a PR" echo " ops-assign ISSUE Assign issue to Kimi" echo " ops-assign-claude ISSUE [REPO] Assign to Claude" echo " ops-audit Run efficiency audit now" echo " ops-prs List open PRs" echo " ops-queue Show Kimi's queue" echo " ops-claude-queue Show Claude's queue" echo " ops-gemini-queue Show Gemini's queue" echo "" echo -e " \033[1mEmergency\033[0m" echo " ops-kill-kimi Stop Kimi loop" echo " ops-kill-claude Stop Claude loop" echo " ops-kill-gemini Stop Gemini loop" echo " ops-kill-zombies Kill stuck git/pytest" echo "" echo -e " \033[1mOrchestrator\033[0m" echo " ops-wake-timmy Start Timmy (Ollama)" echo " ops-kill-timmy Stop Timmy" echo "" echo -e " \033[1mWatchdog\033[0m" echo " ops-wake-watchdog Start loop watchdog" echo " ops-kill-watchdog Stop loop watchdog" echo "" echo -e " \033[2m Type ops-help to see this again\033[0m" echo "" } ops-wake-kimi() { pkill -f "kimi-loop.sh" 2>/dev/null sleep 1 nohup bash ~/.hermes/bin/kimi-loop.sh >> ~/.hermes/logs/kimi-loop.log 2>&1 & echo " Kimi loop started (PID $!)" } ops-wake-gateway() { hermes gateway start 2>&1 } ops-wake-claude() { local workers="${1:-3}" pkill -f "claude-loop.sh" 2>/dev/null sleep 1 nohup bash ~/.hermes/bin/claude-loop.sh "$workers" >> ~/.hermes/logs/claude-loop.log 2>&1 & echo " Claude loop started — $workers workers (PID $!)" } ops-wake-gemini() { pkill -f "gemini-loop.sh" 2>/dev/null sleep 1 nohup bash ~/.hermes/bin/gemini-loop.sh >> ~/.hermes/logs/gemini-loop.log 2>&1 & echo " Gemini loop started (PID $!)" } ops-wake-all() { ops-wake-gateway sleep 1 ops-wake-kimi sleep 1 ops-wake-claude sleep 1 ops-wake-gemini echo " All services started" } ops-merge() { local pr=$1 [ -z "$pr" ] && { echo "Usage: ops-merge PR_NUMBER"; return 1; } curl -s -X POST -H "Authorization: token $TOKEN" -H "Content-Type: application/json" \ "$REPO_API/pulls/$pr/merge" -d '{"Do":"squash"}' | python3 -c " import json,sys d=json.loads(sys.stdin.read()) if 'sha' in d: print(f' ✓ PR #{$pr} merged ({d[\"sha\"][:8]})') else: print(f' ✗ {d.get(\"message\",\"unknown error\")}') " 2>/dev/null } ops-assign() { local issue=$1 [ -z "$issue" ] && { echo "Usage: ops-assign ISSUE_NUMBER"; return 1; } curl -s -X PATCH -H "Authorization: token $TOKEN" -H "Content-Type: application/json" \ "$REPO_API/issues/$issue" -d '{"assignees":["kimi"]}' | python3 -c " import json,sys; d=json.loads(sys.stdin.read()); print(f' ✓ #{$issue} assigned to kimi') " 2>/dev/null } ops-audit() { bash ~/.hermes/bin/efficiency-audit.sh } ops-prs() { curl -s -H "Authorization: token $TOKEN" "$REPO_API/pulls?state=open&limit=20" | python3 -c " import json,sys prs=json.loads(sys.stdin.read()) for p in prs: print(f' #{p[\"number\"]:4d} {p[\"user\"][\"login\"]:8s} {p[\"title\"][:60]}') if not prs: print(' (none)') " 2>/dev/null } ops-queue() { curl -s -H "Authorization: token $TOKEN" "$REPO_API/issues?state=open&assignee=kimi&limit=20&type=issues" | python3 -c " import json,sys issues=json.loads(sys.stdin.read()) for i in issues: print(f' #{i[\"number\"]:4d} {i[\"title\"][:60]}') if not issues: print(' (empty)') " 2>/dev/null } ops-kill-kimi() { pkill -f "kimi-loop.sh" 2>/dev/null pkill -f "kimi.*--print" 2>/dev/null echo " Kimi stopped" } ops-kill-claude() { pkill -f "claude-loop.sh" 2>/dev/null pkill -f "claude.*--print.*--dangerously" 2>/dev/null rm -rf ~/.hermes/logs/claude-locks/*.lock 2>/dev/null echo '{}' > ~/.hermes/logs/claude-active.json 2>/dev/null echo " Claude stopped (all workers)" } ops-kill-gemini() { pkill -f "gemini-loop.sh" 2>/dev/null pkill -f "gemini.*--print" 2>/dev/null echo " Gemini stopped" } ops-assign-claude() { local issue=$1 local repo="${2:-rockachopa/Timmy-time-dashboard}" [ -z "$issue" ] && { echo "Usage: ops-assign-claude ISSUE_NUMBER [owner/repo]"; return 1; } curl -s -X PATCH -H "Authorization: token $TOKEN" -H "Content-Type: application/json" \ "$GITEA/api/v1/repos/$repo/issues/$issue" -d '{"assignees":["claude"]}' | python3 -c " import json,sys; d=json.loads(sys.stdin.read()); print(f' ✓ #{$issue} assigned to claude') " 2>/dev/null } ops-claude-queue() { python3 -c " import json, urllib.request token = '$(cat ~/.hermes/claude_token 2>/dev/null)' base = 'http://143.198.27.163:3000' repos = ['rockachopa/Timmy-time-dashboard','rockachopa/alexanderwhitestone.com','replit/timmy-tower','replit/token-gated-economy','rockachopa/hermes-agent'] for repo in repos: url = f'{base}/api/v1/repos/{repo}/issues?state=open&assignee=claude&limit=20&type=issues' try: req = urllib.request.Request(url, headers={'Authorization': f'token {token}'}) resp = urllib.request.urlopen(req, timeout=5) issues = json.loads(resp.read()) for i in issues: print(f' #{i[\"number\"]:4d} {repo.split(\"/\")[1]:20s} {i[\"title\"][:50]}') except: continue " 2>/dev/null || echo " (error)" } ops-assign-gemini() { local issue=$1 local repo="${2:-rockachopa/Timmy-time-dashboard}" [ -z "$issue" ] && { echo "Usage: ops-assign-gemini ISSUE_NUMBER [owner/repo]"; return 1; } curl -s -X PATCH -H "Authorization: token $TOKEN" -H "Content-Type: application/json" \ "$GITEA/api/v1/repos/$repo/issues/$issue" -d '{"assignees":["gemini"]}' | python3 -c " import json,sys; d=json.loads(sys.stdin.read()); print(f' ✓ #{$issue} assigned to gemini') " 2>/dev/null } ops-gemini-queue() { curl -s -H "Authorization: token $TOKEN" "$REPO_API/issues?state=open&assignee=gemini&limit=20&type=issues" | python3 -c " import json,sys issues=json.loads(sys.stdin.read()) for i in issues: print(f' #{i[\"number\"]:4d} {i[\"title\"][:60]}') if not issues: print(' (empty)') " 2>/dev/null } ops-kill-zombies() { local killed=0 for pid in $(ps aux | grep "pytest tests/" | grep -v grep | awk '{print $2}'); do kill "$pid" 2>/dev/null && killed=$((killed+1)) done for pid in $(ps aux | grep "git.*push\|git-remote-http" | grep -v grep | awk '{print $2}'); do kill "$pid" 2>/dev/null && killed=$((killed+1)) done echo " Killed $killed zombie processes" } ops-wake-timmy() { pkill -f "timmy-orchestrator.sh" 2>/dev/null rm -f ~/.hermes/logs/timmy-orchestrator.pid sleep 1 nohup bash ~/.hermes/bin/timmy-orchestrator.sh >> ~/.hermes/logs/timmy-orchestrator.log 2>&1 & echo " Timmy orchestrator started (PID $!)" } ops-kill-timmy() { pkill -f "timmy-orchestrator.sh" 2>/dev/null rm -f ~/.hermes/logs/timmy-orchestrator.pid echo " Timmy stopped" } ops-wake-watchdog() { pkill -f "loop-watchdog.sh" 2>/dev/null sleep 1 nohup bash ~/.hermes/bin/loop-watchdog.sh >> ~/.hermes/logs/watchdog.log 2>&1 & echo " Watchdog started (PID $!)" } ops-kill-watchdog() { pkill -f "loop-watchdog.sh" 2>/dev/null echo " Watchdog stopped" }