#!/bin/bash # /root/scripts/zulip-monitor.sh — Zulip Mesh Health Monitor # Implements zulip-health.prose.md v2 # Runs every 15 min via cron. Alerts via Telegram. set -euo pipefail ZULIP_SITE="https://chat.sysloggh.net" ZULIP_EMAIL="abiba-bot@chat.sysloggh.net" ZULIP_KEY="cKTDMZAPW08dk3zl05sStzO7HRztzyn8" OWNER_ZULIP_ID="9" # Email config GMAIL_USER="jtabiri@gmail.com" GMAIL_PASS="rgbuomwcydxwbszd" EMAIL_TO="jerome@sysloggh.com" notify() { local severity="$1" msg="$2" echo "[$severity] $msg" # Zulip DM to owner local content="${severity} Zulip Monitor: ${msg}" local form="type=private&to=%5B${OWNER_ZULIP_ID}%5D&content=$(python3 -c "import urllib.parse; print(urllib.parse.quote('''${content}'''))")" curl -sf -X POST "${ZULIP_SITE}/api/v1/messages" \ -u "${ZULIP_EMAIL}:${ZULIP_KEY}" \ -d "${form}" > /dev/null 2>&1 || true # Email alert local subject="${severity} Zulip Monitor Alert" python3 -c " import smtplib from email.mime.text import MIMEText m = MIMEText('''${msg}''') m['From'] = 'abiba@sysloggh.com' m['To'] = '${EMAIL_TO}' m['Subject'] = '${subject}' s = smtplib.SMTP('smtp.gmail.com', 587) s.starttls() s.login('${GMAIL_USER}', '${GMAIL_PASS}') s.sendmail('abiba@sysloggh.com', ['${EMAIL_TO}'], m.as_string()) s.quit() " 2>/dev/null || true } TIMESTAMP=$(date -u '+%Y-%m-%d %H:%M UTC') ISSUES=0 LOG="/root/zulip-health-monitor.log" echo "=== Zulip Health Check — $TIMESTAMP ===" >> "$LOG" # ── Global: Zulip Server ── SERVER_CODE=$(curl -s -o /dev/null -w "%{http_code}" --connect-timeout 10 \ https://chat.sysloggh.net/api/v1/server_settings \ -u 'abiba-bot@chat.sysloggh.net:cKTDMZAPW08dk3zl05sStzO7HRztzyn8' 2>/dev/null || echo "000") if [ "$SERVER_CODE" != "200" ]; then notify "🔴" "Zulip server returned HTTP $SERVER_CODE" ISSUES=$((ISSUES + 1)) else echo " Server: ✅ HTTP 200" >> "$LOG" fi # ── Platform A: pi (Abiba) ── PI_HEALTH=$(curl -sf --connect-timeout 5 http://localhost:9200/health 2>/dev/null || echo "{}") PI_CONNECTED=$(echo "$PI_HEALTH" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('connected',False))" 2>/dev/null) PI_ERROR=$(echo "$PI_HEALTH" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('last_error') or '')" 2>/dev/null) PI_RETRIES=$(echo "$PI_HEALTH" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('retry_count',0))" 2>/dev/null) if [ "$PI_CONNECTED" != "True" ]; then notify "🔴" "Abiba pi extension DISCONNECTED — restarting" pm2 restart abiba-zulip 2>/dev/null || true ISSUES=$((ISSUES + 1)) echo " Abiba: ❌ Disconnected — restarted" >> "$LOG" elif [ -n "$PI_ERROR" ]; then notify "🟡" "Abiba pi extension error: ${PI_ERROR:0:100}" echo " Abiba: 🟡 Error: ${PI_ERROR:0:100}" >> "$LOG" elif [ "$PI_RETRIES" -ge 3 ]; then notify "🟡" "Abiba pi extension: $PI_RETRIES retries — restarting" pm2 restart abiba-zulip 2>/dev/null || true echo " Abiba: 🟡 $PI_RETRIES retries — restarted" >> "$LOG" else echo " Abiba: ✅ Connected (processed=$(echo "$PI_HEALTH" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('messages_processed',0))" 2>/dev/null))" >> "$LOG" fi # ── Platform B: Hermes (Tanko) ── TANKO_STATE=$(ssh -o StrictHostKeyChecking=no -o ConnectTimeout=5 jerome@192.168.68.122 \ "cat ~/.hermes/gateway_state.json 2>/dev/null" 2>/dev/null || echo "{}") TANKO_ZULIP=$(echo "$TANKO_STATE" | python3 -c " import sys,json d=json.load(sys.stdin) p=d.get('platforms',{}).get('zulip',{}) print(p.get('state','unknown')) " 2>/dev/null) if [ "$TANKO_ZULIP" != "connected" ]; then notify "🔴" "Tanko (Hermes) Zulip state: $TANKO_ZULIP — needs restart" ISSUES=$((ISSUES + 1)) echo " Tanko: ❌ state=$TANKO_ZULIP" >> "$LOG" else echo " Tanko: ✅ Zulip connected" >> "$LOG" fi # ── Platform B: Hermes (Mumuni) ── MUMUNI_STATE=$(ssh -o StrictHostKeyChecking=no -o ConnectTimeout=5 root@192.168.68.123 \ "cat ~/.hermes/gateway_state.json 2>/dev/null" 2>/dev/null || echo "{}") MUMUNI_ZULIP=$(echo "$MUMUNI_STATE" | python3 -c " import sys,json d=json.load(sys.stdin) p=d.get('platforms',{}).get('zulip',{}) print(p.get('state','unknown')) " 2>/dev/null) if [ "$MUMUNI_ZULIP" != "connected" ]; then notify "🔴" "Mumuni (Hermes) Zulip state: $MUMUNI_ZULIP" ISSUES=$((ISSUES + 1)) echo " Mumuni: ❌ state=$MUMUNI_ZULIP" >> "$LOG" else echo " Mumuni: ✅ Zulip connected" >> "$LOG" fi # ── Platform C: Agent Zero (kagentz) ── AZ_A2A=$(ssh -o StrictHostKeyChecking=no -o ConnectTimeout=5 root@192.168.68.14 \ "docker exec agent-zero curl -s --connect-timeout 5 http://127.0.0.1:8001/.well-known/agent.json 2>/dev/null" 2>/dev/null || echo "") AZ_ALIVE=$(echo "$AZ_A2A" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('name',''))" 2>/dev/null) if [ "$AZ_ALIVE" != "kagentz" ]; then notify "🔴" "kagentz A2A server DOWN — restarting" ssh -o StrictHostKeyChecking=no -o ConnectTimeout=5 root@192.168.68.14 \ "docker exec agent-zero bash -c 'pkill -9 -f a2a_agent; sleep 1; cd /a0 && /opt/venv-a0/bin/python3 -u /a0/usr/a2a_agent.py > /tmp/a2a.log 2>&1 &'" 2>/dev/null || true ISSUES=$((ISSUES + 1)) echo " kagentz: ❌ A2A down — restarted" >> "$LOG" else echo " kagentz: ✅ A2A alive" >> "$LOG" # Check adapter process AZ_ADAPTER=$(ssh -o StrictHostKeyChecking=no -o ConnectTimeout=5 root@192.168.68.14 \ "docker exec agent-zero ps aux 2>/dev/null | grep adapter | grep -v grep | wc -l" 2>/dev/null || echo "0") if [ "$AZ_ADAPTER" -lt 1 ]; then notify "🔴" "kagentz Zulip adapter DOWN — restarting" ssh -o StrictHostKeyChecking=no -o ConnectTimeout=5 root@192.168.68.14 \ "docker exec agent-zero bash -c 'cd /a0/usr/kagentz-zulip && ZULIP_SITE=https://chat.sysloggh.net ZULIP_EMAIL=kagentz-bot@chat.sysloggh.net ZULIP_API_KEY=E9q9PXJTxftPYBkb5pBDWupDO7KK21ty ZULIP_AGENT_NAME=kagentz A2A_URL=http://localhost:8001/a2a A2A_TOKEN=8zNgdOEXzYxjQvTl /opt/venv-a0/bin/python3 -u adapter.py > /tmp/zulip-adapter.log 2>&1 &'" 2>/dev/null || true ISSUES=$((ISSUES + 1)) echo " kagentz: ❌ Adapter down — restarted" >> "$LOG" else echo " kagentz: ✅ Adapter running" >> "$LOG" fi fi # ── Summary ── if [ "$ISSUES" -eq 0 ]; then echo " Result: ✅ All healthy" >> "$LOG" else echo " Result: 🔴 $ISSUES issue(s) found" >> "$LOG" notify "🔴" "$ISSUES issue(s) found — check /root/zulip-health-monitor.log" fi echo "" >> "$LOG"