start_all.sh 5.33 KB
#!/data/data/com.termux/files/usr/bin/bash
# Start all Android Agent Runtime services
#
# MUST be run from within the Termux terminal app on the phone (not via adb run-as).
# Root is required for the notification monitor.
#
# Usage (in Termux terminal):
#   bash ~/.hermes/event_bus/start_all.sh

# Termux home is always here regardless of how the script is invoked
TERMUX_HOME="/data/data/com.termux/files/home"
export HOME="$TERMUX_HOME"

BASE="$HOME/.hermes/event_bus"
VENV="$HOME/.hermes/hermes-agent/venv/bin"
PY3="/data/data/com.termux/files/usr/bin/python3"
LOGS="$HOME/.hermes/logs"
mkdir -p "$LOGS"

# ── root check ─────────────────────────────────────────────────────────────────

if ! su -c 'echo ok' > /dev/null 2>&1; then
    echo "[!] ERROR: cannot get root via su."
    echo "    Run this script from inside the Termux terminal app on the phone."
    echo "    (adb run-as does not have su access)"
    exit 1
fi

# ── helpers ────────────────────────────────────────────────────────────────────

is_running() {
    local pid_file="$1"
    local pid
    [ -f "$pid_file" ] || return 1
    pid=$(cat "$pid_file" 2>/dev/null)
    [ -n "$pid" ] && [ -d "/proc/$pid" ]
}

start_service() {
    local name="$1"
    local pid_file="$2"
    local log_file="$3"
    shift 3

    if is_running "$pid_file"; then
        echo "[✓] $name already running (pid $(cat "$pid_file"))"
        return 0
    fi

    # setsid creates a new session so the process survives shell exit
    setsid nohup "$@" >> "$log_file" 2>&1 &
    local pid=$!
    echo $pid > "$pid_file"
    sleep 1

    if is_running "$pid_file"; then
        echo "[+] $name started (pid $pid)"
    else
        echo "[!] $name failed to start — check $log_file"
        return 1
    fi
}

# ── event server ───────────────────────────────────────────────────────────────

start_service "EventServer" \
    "$BASE/event_server.pid" \
    "$LOGS/event_server.log" \
    env EVENT_BUS_DB="$BASE/events.db" \
    "$VENV/uvicorn" event_server:app \
        --app-dir "$BASE" \
        --host 127.0.0.1 --port 8765 \
        --log-level warning

# Wait for EventServer to be ready
for i in $(seq 1 10); do
    "$VENV/python" -c "
import urllib.request
try:
    urllib.request.urlopen('http://127.0.0.1:8765/health', timeout=1)
    exit(0)
except:
    exit(1)
" 2>/dev/null && break
    sleep 1
done

# ── mitm proxy ─────────────────────────────────────────────────────────────────
# Pure-Python HTTPS-intercepting proxy used to capture WeChat traffic. Runs as
# root because ~/.hermes/mitm_ca (the CA + per-host certs) is root-owned from
# earlier setup, and the device's global HTTP proxy (Settings.Global.http_proxy)
# routes every app's HTTPS through MITM_PORT — not just WeChat's.

start_service "MitmProxy" \
    "$BASE/mitm_proxy.pid" \
    "$LOGS/mitm_proxy.log" \
    su -c "env HOME=$TERMUX_HOME MITM_PORT=8082 $PY3 $BASE/mitm_proxy.py"

# ── APK AgentRuntimeService ────────────────────────────────────────────────────
# The APK provides real-time NotificationListenerService + AccessibilityService
# events via EventServerRelay. Start it via root am if not already running.

APK_PKG="ai.lemon.phoneuse.debug"
APK_SVC="${APK_PKG}/ai.lemon.phoneuse.service.AgentRuntimeService"

apk_svc_running() {
    su -c "dumpsys activity services $APK_PKG 2>/dev/null" | grep -q "AgentRuntimeService"
}

if apk_svc_running; then
    echo "[✓] APK AgentRuntimeService already running"
else
    su -c "am start-foreground-service ${APK_SVC}" > /dev/null 2>&1
    sleep 2
    if apk_svc_running; then
        echo "[+] APK AgentRuntimeService started"
    else
        echo "[~] APK AgentRuntimeService not started (install APK first, or start manually)"
    fi
fi

# ── status ─────────────────────────────────────────────────────────────────────

echo ""
echo "── Status ────────────────────────────────────"
"$VENV/python" - << 'PYEOF'
import urllib.request, json
try:
    r = urllib.request.urlopen('http://127.0.0.1:8765/stats', timeout=3)
    s = json.loads(r.read().decode())
    print(f"  EventServer:         OK  total_events={s['total_events']} last_id={s['last_event_id']}")
except Exception as e:
    print(f"  EventServer:         ERROR ({e})")
PYEOF
echo "  APK EventServerRelay: real-time notifications + UI events via Kotlin APK"
echo "  MCP server:          android_mcp.py (spawned on demand by Hermes)"
echo "──────────────────────────────────────────────"
echo ""
echo "Logs: $LOGS/"
echo "Stop: bash $BASE/stop_all.sh"