keepalive.sh 5.31 KB
#!/data/data/com.termux/files/usr/bin/bash
# keepalive.sh — Pixel 微信自动回复保活脚本
#
# 守护以下进程,挂了就重启:
#   1. termux wake-lock      — 防 Doze 冻结 Termux:API(通知监听依赖它)
#   2. HermesAccessibilityService — A11y 易被系统/更新关掉,发现 enabled_accessibility_services=null 就重启
#   3. hermes-agent gateway  — :8642,LLM 网关
#   4. auto-reply.js         — 微信回复主程序
#
# 用法(在 Termux 用户 shell 里运行;不要在 root shell 起,wake-lock 拿不住 Termux 进程):
#   nohup bash ~/hermes-wechat/keepalive.sh > ~/hermes-wechat/keepalive.log 2>&1 &
#
# 前置条件(一次性设置):
#   1. Android 设置 → 应用 → Termux / Termux:API / 微信 → 电池优化 → 不优化
#   2. Termux:API 已安装,并已授予通知访问权限
#   3. lsposed-wechat-sendmsg APK 已安装(含 HermesAccessibilityService)
#   4. ~/hermes-wechat/start-ar.sh 存在并已设置 MY_WXID / MY_NICKNAME

export PATH="/data/data/com.termux/files/usr/bin:$PATH"
export HOME="/data/data/com.termux/files/home"

HERMES_DIR="${HERMES_DIR:-$HOME/hermes-wechat}"
HERMES_PORT="${HERMES_PORT:-8642}"
GATEWAY_START="${GATEWAY_START:-$HOME/.hermes/scripts/start-gateway.sh}"
AR_START="${AR_START:-$HERMES_DIR/start-ar.sh}"
A11Y_SVC="com.hermes.wechat.xposed/com.hermes.wechat.xposed.accessibility.HermesAccessibilityService"
CHECK_INTERVAL_SEC="${CHECK_INTERVAL_SEC:-15}"

log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*"; }

# ── 1. Termux wake-lock ──────────────────────────────────────────
ensure_wake_lock() {
    # 用命令行 termux-wake-lock(依赖 Termux:API app);am startservice 是备用
    if command -v termux-wake-lock >/dev/null 2>&1; then
        termux-wake-lock 2>/dev/null
    else
        # 后备:用 su 调系统 ServiceManager
        su -c "am startservice --user 0 -a com.termux.service_wake_lock com.termux/.app.TermuxService" 2>/dev/null || true
    fi
}

is_wake_lock_held() {
    su -c "dumpsys power 2>/dev/null | grep -q 'termux:service-wakelock'"
}

# ── 2. A11y service ──────────────────────────────────────────────
is_a11y_enabled() {
    out=$(su -c "settings get secure enabled_accessibility_services" 2>/dev/null)
    case "$out" in
        *com.hermes.wechat.xposed*HermesAccessibilityService*) return 0 ;;
        *) return 1 ;;
    esac
}

enable_a11y() {
    log "Enabling HermesAccessibilityService..."
    su -c "settings put secure enabled_accessibility_services $A11Y_SVC; settings put secure accessibility_enabled 1" 2>/dev/null
}

# ── 3. hermes gateway ────────────────────────────────────────────
is_gateway_running() {
    # 用 /sys/class/net 风格的端口探测:通过 nc 或 curl,二选一
    if command -v curl >/dev/null 2>&1; then
        # gateway 在 termux 用户下需要 Clash 代理(与本机回环无关);
        # 但 127.0.0.1:8642 走本机,不用代理
        env -u HTTPS_PROXY -u HTTP_PROXY \
            curl -s --max-time 3 "http://127.0.0.1:${HERMES_PORT}/v1/models" >/dev/null 2>&1
    else
        # nc fallback
        echo > /dev/tcp/127.0.0.1/$HERMES_PORT 2>/dev/null
    fi
}

start_gateway() {
    log "Starting hermes gateway..."
    if [ -x "$GATEWAY_START" ]; then
        bash "$GATEWAY_START" >> "$HOME/.hermes/logs/gateway-start.log" 2>&1
    else
        log "[ERROR] $GATEWAY_START not found"
    fi
}

# ── 4. auto-reply.js ─────────────────────────────────────────────
is_auto_reply_running() {
    pgrep -f "node.*auto-reply.js" >/dev/null 2>&1
}

start_auto_reply() {
    log "Starting auto-reply..."
    if [ -x "$AR_START" ]; then
        # auto-reply 走 root 才能 input keyevent / am broadcast / 读微信 DB
        su -c "nohup bash $AR_START > /dev/null 2>&1 &"
    else
        log "[ERROR] $AR_START not found"
    fi
}

# ── 5. 主循环 ────────────────────────────────────────────────────
log "=== Keepalive started ==="
log "HERMES_DIR=$HERMES_DIR  GATEWAY_START=$GATEWAY_START  AR_START=$AR_START"
log "Check interval: ${CHECK_INTERVAL_SEC}s"

# 首次进入:把所有依赖拉到位
ensure_wake_lock
is_a11y_enabled || enable_a11y
is_gateway_running || start_gateway
sleep 5
is_auto_reply_running || start_auto_reply

while true; do
    sleep "$CHECK_INTERVAL_SEC"

    # wake-lock 偶尔会因 Termux 重启 / 系统重启而丢,保险起见周期性 re-acquire
    if ! is_wake_lock_held; then
        log "Wake lock lost, re-acquiring..."
        ensure_wake_lock
    fi

    # A11y 易被系统升级 / 用户在设置中关掉
    if ! is_a11y_enabled; then
        log "A11y service disabled, re-enabling..."
        enable_a11y
    fi

    if ! is_gateway_running; then
        log "Gateway not responding on :$HERMES_PORT, restarting..."
        start_gateway
        sleep 6
    fi

    if ! is_auto_reply_running; then
        log "auto-reply.js not running, restarting..."
        start_auto_reply
    fi
done