Commit edfe7ab45cb70d02edf931f7965af44e8faca846

Authored by yibo
1 parent caf680f2

chore: 清理收尾 — 群昵称查询 + wake-lock 保活 + Frida 残留

#17 群昵称查询:
- android-wechat-tracker-sqlcipher.js:getContactNickname 删掉
  if (wxid.endsWith('@chatroom')) return wxid 的早退分支
- 群(xxxx@chatroom)和私聊都走同一 rcontact 表查询,nickname 就是群名
- A11y 现在可以用群名搜索进入群聊
- 在 Pixel 已部署并重启 auto-reply (PID 18678)

#18 wake-lock + keepalive 重写:
- 通过 am startservice com.termux.service_wake_lock 启用 wake-lock
  (确认 dumpsys power 已持有 'termux:service-wakelock')
- 重写 keepalive.sh 对齐当前部署:
  - 守护 4 项:wake-lock / A11y service / hermes gateway / auto-reply
  - hermes 走 termux native gateway 而不是 proot-distro Ubuntu(已淘汰)
  - 健康检查端口 8642(不再是 3010)
  - A11y 被关掉时自动 settings put secure 重新启用
- 在 Pixel 已部署到 ~/hermes-wechat/keepalive.sh

#16 残留清理(仅 phone 操作,无 git 文件):
- pkill -9 frida-server + rm -rf ~/.frida_queue/
- ~/.hermes/auth.json 删掉 credential_pool['kimi-coding'] 老 sk-kimi 条目
  保留 anthropic + kimi-coding-cn

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
server/services/wechat/android-wechat-tracker-sqlcipher.js
@@ -144,11 +144,7 @@ class AndroidWechatTrackerSQLCipher extends EventEmitter { @@ -144,11 +144,7 @@ class AndroidWechatTrackerSQLCipher extends EventEmitter {
144 }; 144 };
145 if (builtin[wxid]) return builtin[wxid]; 145 if (builtin[wxid]) return builtin[wxid];
146 146
147 - // 群聊 ID 走另一个表(chatroom),先简单返回 wxid 让上层处理  
148 - if (wxid.endsWith('@chatroom')) {  
149 - return wxid;  
150 - }  
151 - 147 + // 群(xxxx@chatroom)和私聊都用 rcontact 表 — nickname 就是群名 / 个人昵称
152 const safeWxid = String(wxid).replace(/'/g, "''"); 148 const safeWxid = String(wxid).replace(/'/g, "''");
153 const sql = `SELECT conRemark, nickname FROM rcontact WHERE username='${safeWxid}' LIMIT 1;`; 149 const sql = `SELECT conRemark, nickname FROM rcontact WHERE username='${safeWxid}' LIMIT 1;`;
154 try { 150 try {
wechat_plain/scripts/local-testkit/keepalive.sh
1 -#!/bin/bash  
2 -# keepalive.sh — Termux 保活 + 进程守护脚本 1 +#!/data/data/com.termux/files/usr/bin/bash
  2 +# keepalive.sh — Pixel 微信自动回复保活脚本
3 # 3 #
4 -# 功能:  
5 -# 1. 获取 wake-lock,防止息屏后 CPU 被冻结  
6 -# 2. 检查并启动 hermes server  
7 -# 3. 检查并启动 wechat auto-reply plugin  
8 -# 4. 进程死了自动重启 4 +# 守护以下进程,挂了就重启:
  5 +# 1. termux wake-lock — 防 Doze 冻结 Termux:API(通知监听依赖它)
  6 +# 2. HermesAccessibilityService — A11y 易被系统/更新关掉,发现 enabled_accessibility_services=null 就重启
  7 +# 3. hermes-agent gateway — :8642,LLM 网关
  8 +# 4. auto-reply.js — 微信回复主程序
9 # 9 #
10 -# 用法:  
11 -# chmod +x keepalive.sh  
12 -# nohup ./keepalive.sh > keepalive.log 2>&1 & 10 +# 用法(在 Termux 用户 shell 里运行;不要在 root shell 起,wake-lock 拿不住 Termux 进程):
  11 +# nohup bash ~/hermes-wechat/keepalive.sh > ~/hermes-wechat/keepalive.log 2>&1 &
13 # 12 #
14 -# 前置条件(必须手动设置):  
15 -# 1. Android 设置 → 应用 → Termux → 电池优化 → 不优化  
16 -# 2. Android 设置 → 应用 → Termux:API → 电池优化 → 不优化  
17 -# 3. Android 设置 → 应用 → 微信 → 电池优化 → 不优化  
18 -# 4. Android 设置 → 应用 → Termux → 允许自启动  
19 -# 5. Termux:API 已安装,并已授予通知访问权限 13 +# 前置条件(一次性设置):
  14 +# 1. Android 设置 → 应用 → Termux / Termux:API / 微信 → 电池优化 → 不优化
  15 +# 2. Termux:API 已安装,并已授予通知访问权限
  16 +# 3. lsposed-wechat-sendmsg APK 已安装(含 HermesAccessibilityService)
  17 +# 4. ~/hermes-wechat/start-ar.sh 存在并已设置 MY_WXID / MY_NICKNAME
20 18
21 -set -e  
22 -  
23 -# 确保 Termux 工具在 PATH 中(su 环境下可能缺失)  
24 export PATH="/data/data/com.termux/files/usr/bin:$PATH" 19 export PATH="/data/data/com.termux/files/usr/bin:$PATH"
25 -  
26 -HERMES_DIR="${HERMES_DIR:-/data/data/com.termux/files/home/hermes-wechat}"  
27 -HERMES_HOST="${HERMES_HOST:-localhost}"  
28 -HERMES_PORT="${HERMES_PORT:-3010}"  
29 -MY_WXID="${MY_WXID:-}"  
30 -MY_NICKNAME="${MY_NICKNAME:-}"  
31 -CHECK_INTERVAL_SEC="${CHECK_INTERVAL_SEC:-10}"  
32 -  
33 -log() {  
34 - echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*"  
35 -}  
36 -  
37 -# ── 1. Wake lock ─────────────────────────────────────────────────  
38 -termux-wake-lock 2>/dev/null || true  
39 -log "Wake lock acquired"  
40 -  
41 -# ── 2. 检查前置条件 ──────────────────────────────────────────────  
42 -check_prerequisites() {  
43 - _ok=0  
44 -  
45 - if ! command -v termux-notification-list >/dev/null 2>&1; then  
46 - log "[WARN] termux-notification-list not found. Install: pkg install termux-api"  
47 - _ok=1 20 +export HOME="/data/data/com.termux/files/home"
  21 +
  22 +HERMES_DIR="${HERMES_DIR:-$HOME/hermes-wechat}"
  23 +HERMES_PORT="${HERMES_PORT:-8642}"
  24 +GATEWAY_START="${GATEWAY_START:-$HOME/.hermes/scripts/start-gateway.sh}"
  25 +AR_START="${AR_START:-$HERMES_DIR/start-ar.sh}"
  26 +A11Y_SVC="com.hermes.wechat.xposed/com.hermes.wechat.xposed.accessibility.HermesAccessibilityService"
  27 +CHECK_INTERVAL_SEC="${CHECK_INTERVAL_SEC:-15}"
  28 +
  29 +log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*"; }
  30 +
  31 +# ── 1. Termux wake-lock ──────────────────────────────────────────
  32 +ensure_wake_lock() {
  33 + # 用命令行 termux-wake-lock(依赖 Termux:API app);am startservice 是备用
  34 + if command -v termux-wake-lock >/dev/null 2>&1; then
  35 + termux-wake-lock 2>/dev/null
  36 + else
  37 + # 后备:用 su 调系统 ServiceManager
  38 + su -c "am startservice --user 0 -a com.termux.service_wake_lock com.termux/.app.TermuxService" 2>/dev/null || true
48 fi 39 fi
  40 +}
49 41
50 - if [ ! -d "$HERMES_DIR" ]; then  
51 - log "[WARN] HERMES_DIR not found: $HERMES_DIR"  
52 - _ok=1  
53 - fi 42 +is_wake_lock_held() {
  43 + su -c "dumpsys power 2>/dev/null | grep -q 'termux:service-wakelock'"
  44 +}
54 45
55 - if [ -z "$MY_WXID" ] || [ -z "$MY_NICKNAME" ]; then  
56 - log "[WARN] MY_WXID or MY_NICKNAME not set"  
57 - log " export MY_WXID=wxid_xxxxxx"  
58 - log " export MY_NICKNAME=你的昵称"  
59 - _ok=1  
60 - fi 46 +# ── 2. A11y service ──────────────────────────────────────────────
  47 +is_a11y_enabled() {
  48 + out=$(su -c "settings get secure enabled_accessibility_services" 2>/dev/null)
  49 + case "$out" in
  50 + *com.hermes.wechat.xposed*HermesAccessibilityService*) return 0 ;;
  51 + *) return 1 ;;
  52 + esac
  53 +}
61 54
62 - return $_ok 55 +enable_a11y() {
  56 + log "Enabling HermesAccessibilityService..."
  57 + su -c "settings put secure enabled_accessibility_services $A11Y_SVC; settings put secure accessibility_enabled 1" 2>/dev/null
63 } 58 }
64 59
65 -# ── 3. 检查 hermes server 是否运行 ───────────────────────────────  
66 -is_hermes_running() {  
67 - curl -s "http://${HERMES_HOST}:${HERMES_PORT}/api/health" >/dev/null 2>&1 60 +# ── 3. hermes gateway ────────────────────────────────────────────
  61 +is_gateway_running() {
  62 + # 用 /sys/class/net 风格的端口探测:通过 nc 或 curl,二选一
  63 + if command -v curl >/dev/null 2>&1; then
  64 + # gateway 在 termux 用户下需要 Clash 代理(与本机回环无关);
  65 + # 但 127.0.0.1:8642 走本机,不用代理
  66 + env -u HTTPS_PROXY -u HTTP_PROXY \
  67 + curl -s --max-time 3 "http://127.0.0.1:${HERMES_PORT}/v1/models" >/dev/null 2>&1
  68 + else
  69 + # nc fallback
  70 + echo > /dev/tcp/127.0.0.1/$HERMES_PORT 2>/dev/null
  71 + fi
68 } 72 }
69 73
70 -# ── 4. 启动 hermes server ────────────────────────────────────────  
71 -# 必须在 proot Ubuntu 内以 ubuntu 用户运行(Claude CLI 拒绝 root + --dangerously-skip-permissions)  
72 -start_hermes() {  
73 - log "Starting hermes server in proot Ubuntu user=ubuntu..."  
74 - cd "$HERMES_DIR"  
75 - nohup proot-distro login ubuntu --user ubuntu -- bash -c \  
76 - "cd $HERMES_DIR && . .env && node server/index.js" \  
77 - > hermes-server.log 2>&1 &  
78 - sleep 5  
79 - if is_hermes_running; then  
80 - log "Hermes server started PID=$!" 74 +start_gateway() {
  75 + log "Starting hermes gateway..."
  76 + if [ -x "$GATEWAY_START" ]; then
  77 + bash "$GATEWAY_START" >> "$HOME/.hermes/logs/gateway-start.log" 2>&1
81 else 78 else
82 - log "[WARN] Hermes server may have failed to start, check hermes-server.log" 79 + log "[ERROR] $GATEWAY_START not found"
83 fi 80 fi
84 } 81 }
85 82
86 -# ── 5. 检查 auto-reply 是否运行 ────────────────────────────────── 83 +# ── 4. auto-reply.js ─────────────────────────────────────────────
87 is_auto_reply_running() { 84 is_auto_reply_running() {
88 - pgrep -f "node auto-reply.js" >/dev/null 2>&1 85 + pgrep -f "node.*auto-reply.js" >/dev/null 2>&1
89 } 86 }
90 87
91 -# ── 6. 启动 auto-reply ───────────────────────────────────────────  
92 start_auto_reply() { 88 start_auto_reply() {
93 log "Starting auto-reply..." 89 log "Starting auto-reply..."
94 - cd "$HERMES_DIR/server/services/wechat"  
95 - env MY_WXID="$MY_WXID" MY_NICKNAME="$MY_NICKNAME" \  
96 - nohup node auto-reply.js > auto-reply.log 2>&1 &  
97 - log "Auto-reply started PID=$!" 90 + if [ -x "$AR_START" ]; then
  91 + # auto-reply 走 root 才能 input keyevent / am broadcast / 读微信 DB
  92 + su -c "nohup bash $AR_START > /dev/null 2>&1 &"
  93 + else
  94 + log "[ERROR] $AR_START not found"
  95 + fi
98 } 96 }
99 97
100 -# ── 7. 主循环 ──────────────────────────────────────────────────── 98 +# ── 5. 主循环 ────────────────────────────────────────────────────
101 log "=== Keepalive started ===" 99 log "=== Keepalive started ==="
102 -log "HERMES_DIR=$HERMES_DIR"  
103 -log "MY_WXID=${MY_WXID:-not-set}"  
104 -log "MY_NICKNAME=${MY_NICKNAME:-not-set}" 100 +log "HERMES_DIR=$HERMES_DIR GATEWAY_START=$GATEWAY_START AR_START=$AR_START"
  101 +log "Check interval: ${CHECK_INTERVAL_SEC}s"
105 102
106 -if ! check_prerequisites; then  
107 - log "[ERROR] Prerequisites check failed, exiting"  
108 - exit 1  
109 -fi 103 +# 首次进入:把所有依赖拉到位
  104 +ensure_wake_lock
  105 +is_a11y_enabled || enable_a11y
  106 +is_gateway_running || start_gateway
  107 +sleep 5
  108 +is_auto_reply_running || start_auto_reply
110 109
111 while true; do 110 while true; do
112 - # 检查 hermes  
113 - if ! is_hermes_running; then  
114 - log "Hermes server not responding, restarting..."  
115 - start_hermes 111 + sleep "$CHECK_INTERVAL_SEC"
  112 +
  113 + # wake-lock 偶尔会因 Termux 重启 / 系统重启而丢,保险起见周期性 re-acquire
  114 + if ! is_wake_lock_held; then
  115 + log "Wake lock lost, re-acquiring..."
  116 + ensure_wake_lock
  117 + fi
  118 +
  119 + # A11y 易被系统升级 / 用户在设置中关掉
  120 + if ! is_a11y_enabled; then
  121 + log "A11y service disabled, re-enabling..."
  122 + enable_a11y
  123 + fi
  124 +
  125 + if ! is_gateway_running; then
  126 + log "Gateway not responding on :$HERMES_PORT, restarting..."
  127 + start_gateway
  128 + sleep 6
116 fi 129 fi
117 130
118 - # 检查 auto-reply  
119 if ! is_auto_reply_running; then 131 if ! is_auto_reply_running; then
120 - log "Auto-reply not running, restarting..." 132 + log "auto-reply.js not running, restarting..."
121 start_auto_reply 133 start_auto_reply
122 fi 134 fi
123 -  
124 - sleep "$CHECK_INTERVAL_SEC"  
125 done 135 done