start_all.sh
5.33 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
#!/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"