start_all.sh
4.62 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
#!/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"
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
# ── 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"