Commit 3d4fb0d1679343cde9b7be38dab6cebd04730feb
1 parent
0a537853
feat(keepalive): restart-flag 桥 — claude-run 无 su 也能自助重启 bot
claude-run 跑在 proot、拿不到 Magisk root,杀不了 root 的 auto-reply 进程。 keepalive.sh 主循环新增:检测到 ~/hermes-wechat/.restart-request flag 就以 root pkill auto-reply 并删 flag,随后既有的 is_auto_reply_running 检测用新代码重启。 只暴露「请求重启」一个动作,不是任意命令执行。已端到端验证:u0_a327 touch flag → keepalive ~15s 内重启 bot。 - keepalive.sh: 纳入版本控制 + 加 flag 桥 - deploy-to-phone.sh: 收 keepalive.sh(.sh 给 755)+ 末尾加重启 keepalive 提示 - AGENTS.md / HANDOFF.md §零: 文档化 flag 重启途径 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Showing
4 changed files
with
190 additions
and
6 deletions
server/services/wechat/AGENTS.md
| @@ -12,7 +12,7 @@ Pixel 本机的微信自动回复机器人(账号「小火子」`wxid_51ap3m6p | @@ -12,7 +12,7 @@ Pixel 本机的微信自动回复机器人(账号「小火子」`wxid_51ap3m6p | ||
| 12 | 12 | ||
| 13 | | 角色 | 跑在 | 能力 | 干什么 | | 13 | | 角色 | 跑在 | 能力 | 干什么 | |
| 14 | |------|------|------|--------| | 14 | |------|------|------|--------| |
| 15 | -| **claude-run(Claude)= 脑子** | proot 容器 | 能编辑本目录 `*.js`、读 `auto-reply.log`、读改 `.whitelist.json`;**不能 su** | 写 / 改 / 审代码、看日志诊断 | | 15 | +| **claude-run(Claude)= 脑子** | proot 容器 | 能编辑本目录 `*.js`、读 `auto-reply.log`、读改 `.whitelist.json`;**不能 su**,但可 `touch .restart-request` 让 keepalive 代为重启 | 写 / 改 / 审代码、看日志诊断 | |
| 16 | | **hermes(Kimi)= 手** | Termux(能 su) | 能 `su -c` 拿 Magisk root | 跑需要 root 的设备操作:重启 bot、查微信 DB、发测试消息、logcat、重开 A11y | | 16 | | **hermes(Kimi)= 手** | Termux(能 su) | 能 `su -c` 拿 Magisk root | 跑需要 root 的设备操作:重启 bot、查微信 DB、发测试消息、logcat、重开 A11y | |
| 17 | 17 | ||
| 18 | > claude-run 在 proot 里够不到 Magisk root,也看不到微信 DB(没挂载)。需要 root 的步骤交给 hermes 或 Termux shell 执行。 | 18 | > claude-run 在 proot 里够不到 Magisk root,也看不到微信 DB(没挂载)。需要 root 的步骤交给 hermes 或 Termux shell 执行。 |
| @@ -34,8 +34,10 @@ Pixel 本机的微信自动回复机器人(账号「小火子」`wxid_51ap3m6p | @@ -34,8 +34,10 @@ Pixel 本机的微信自动回复机器人(账号「小火子」`wxid_51ap3m6p | ||
| 34 | ## 改代码 → 生效(内循环) | 34 | ## 改代码 → 生效(内循环) |
| 35 | 35 | ||
| 36 | 1. **改**:claude-run 直接编辑本目录 `*.js`。 | 36 | 1. **改**:claude-run 直接编辑本目录 `*.js`。 |
| 37 | -2. **重启**(需 root → hermes / Termux 执行):`su -c 'pkill -f auto-reply.js'` → keepalive(每 15s 巡检)自动用新代码以 root 重启。 | ||
| 38 | - 确认新进程:`su -c 'ps -ef | grep -E node.auto-reply.js | grep -v grep'`(**别用 `pgrep -f`,会自匹配 su shell**)。 | 37 | +2. **重启**(让新代码生效): |
| 38 | + - **claude-run(无 su)**:`touch ~/hermes-wechat/.restart-request` —— keepalive(每 15s 巡检、已是 root)看到这个 flag 就杀掉 auto-reply 并用新代码重启,~15s 内生效。**这是 claude-run 自助重启的唯一方式**(它在 proot 里杀不了 root 进程)。 | ||
| 39 | + - **hermes / Termux(有 su)**:直接 `su -c 'pkill -f auto-reply.js'`,keepalive 随即重启。 | ||
| 40 | + - 确认新进程:`su -c 'ps -ef | grep -E node.auto-reply.js | grep -v grep'`(**别用 `pgrep -f`,会自匹配 su shell**)。 | ||
| 39 | 3. **看**:`tail -f ~/hermes-wechat/auto-reply.log`(claude-run 不带 su 也能读,日志 644)。 | 41 | 3. **看**:`tail -f ~/hermes-wechat/auto-reply.log`(claude-run 不带 su 也能读,日志 644)。 |
| 40 | 4. **同步回 Mac**:手机无 git,改完把改动同步回 Mac repo `server/services/wechat/`,否则下次 Mac 跑 `deploy-to-phone.sh` 会覆盖你的改动。 | 42 | 4. **同步回 Mac**:手机无 git,改完把改动同步回 Mac repo `server/services/wechat/`,否则下次 Mac 跑 `deploy-to-phone.sh` 会覆盖你的改动。 |
| 41 | 43 |
server/services/wechat/HANDOFF.md
| @@ -27,7 +27,10 @@ | @@ -27,7 +27,10 @@ | ||
| 27 | 27 | ||
| 28 | 4. **bot 实跑只依赖 3 个文件**:`auto-reply.js` + `android-wechat-tracker-sqlcipher.js` + `android-wechat-sender.js`(`auto-reply.js` 只 require 这俩)。其余 `index.js / wechat-tracker.js / wechat-reader.js / *-frida.js / *-sqlite.js` 都不参与 bot 运行,别被带偏。 | 28 | 4. **bot 实跑只依赖 3 个文件**:`auto-reply.js` + `android-wechat-tracker-sqlcipher.js` + `android-wechat-sender.js`(`auto-reply.js` 只 require 这俩)。其余 `index.js / wechat-tracker.js / wechat-reader.js / *-frida.js / *-sqlite.js` 都不参与 bot 运行,别被带偏。 |
| 29 | 29 | ||
| 30 | -5. **改代码 → 生效**:`~/hermes-wechat/*.js` 现在属主是 u0_a327,你可以直接编辑。改完 `su -c 'pkill -f auto-reply.js'`,keepalive(每 15s 巡检)会以 root 自动用新代码重启。改完记得把改动同步回 Mac repo(见 §六)。 | 30 | +5. **改代码 → 生效**:`~/hermes-wechat/*.js` 现在属主是 u0_a327,你可以直接编辑。重启让新代码生效: |
| 31 | + - 有 su(hermes/Termux):`su -c 'pkill -f auto-reply.js'`,keepalive(每 15s 巡检)以 root 自动重启。 | ||
| 32 | + - **无 su(proot 里的 claude-run):`touch ~/hermes-wechat/.restart-request`** —— keepalive 看到这个 flag 就代为杀掉并重启 bot(~15s 内生效)。这是 claude-run 自助重启的唯一途径(它杀不了 root 进程)。 | ||
| 33 | + 改完记得把改动同步回 Mac repo(见 §六)。 | ||
| 31 | 34 | ||
| 32 | --- | 35 | --- |
| 33 | 36 |
server/services/wechat/deploy-to-phone.sh
| @@ -20,7 +20,9 @@ TERMUX_UID="${TERMUX_UID:-u0_a327}" # Termux app 的 uid(claude-run 也是 | @@ -20,7 +20,9 @@ TERMUX_UID="${TERMUX_UID:-u0_a327}" # Termux app 的 uid(claude-run 也是 | ||
| 20 | RUNTIME="auto-reply.js android-wechat-tracker-sqlcipher.js android-wechat-sender.js" | 20 | RUNTIME="auto-reply.js android-wechat-tracker-sqlcipher.js android-wechat-sender.js" |
| 21 | # 文档(接手 / 维护必读)。AGENTS.md/CLAUDE.md 是 agent 一次性读的入口 | 21 | # 文档(接手 / 维护必读)。AGENTS.md/CLAUDE.md 是 agent 一次性读的入口 |
| 22 | DOCS="AGENTS.md CLAUDE.md HANDOFF.md README.md SKILL.md" | 22 | DOCS="AGENTS.md CLAUDE.md HANDOFF.md README.md SKILL.md" |
| 23 | -FILES="$RUNTIME $DOCS" | 23 | +# 守护脚本(改了要手动重启 keepalive,见末尾提示) |
| 24 | +SCRIPTS="keepalive.sh" | ||
| 25 | +FILES="$RUNTIME $DOCS $SCRIPTS" | ||
| 24 | 26 | ||
| 25 | # md5 工具:Mac 用 `md5 -q`,Linux 用 `md5sum` | 27 | # md5 工具:Mac 用 `md5 -q`,Linux 用 `md5sum` |
| 26 | md5_local() { | 28 | md5_local() { |
| @@ -37,9 +39,10 @@ adb shell "su -c 'mkdir -p $PHONE_DIR'" | @@ -37,9 +39,10 @@ adb shell "su -c 'mkdir -p $PHONE_DIR'" | ||
| 37 | fail=0 | 39 | fail=0 |
| 38 | for f in $FILES; do | 40 | for f in $FILES; do |
| 39 | if [ ! -f "$SCRIPT_DIR/$f" ]; then echo "SKIP (missing) $f"; continue; fi | 41 | if [ ! -f "$SCRIPT_DIR/$f" ]; then echo "SKIP (missing) $f"; continue; fi |
| 42 | + case "$f" in *.sh) mode=755;; *) mode=644;; esac | ||
| 40 | echo "Pushing $f ..." | 43 | echo "Pushing $f ..." |
| 41 | adb push "$SCRIPT_DIR/$f" "/sdcard/_deploy_$f" >/dev/null | 44 | adb push "$SCRIPT_DIR/$f" "/sdcard/_deploy_$f" >/dev/null |
| 42 | - adb shell "su -c 'dd if=/sdcard/_deploy_$f of=$PHONE_DIR/$f 2>/dev/null && chown $TERMUX_UID:$TERMUX_UID $PHONE_DIR/$f && chmod 644 $PHONE_DIR/$f'" | 45 | + adb shell "su -c 'dd if=/sdcard/_deploy_$f of=$PHONE_DIR/$f 2>/dev/null && chown $TERMUX_UID:$TERMUX_UID $PHONE_DIR/$f && chmod $mode $PHONE_DIR/$f'" |
| 43 | adb shell "rm -f /sdcard/_deploy_$f" >/dev/null 2>&1 || true | 46 | adb shell "rm -f /sdcard/_deploy_$f" >/dev/null 2>&1 || true |
| 44 | lmd5=$(md5_local "$SCRIPT_DIR/$f") | 47 | lmd5=$(md5_local "$SCRIPT_DIR/$f") |
| 45 | pmd5=$(adb shell "su -c 'md5sum $PHONE_DIR/$f'" | awk '{print $1}' | tr -d '\r') | 48 | pmd5=$(adb shell "su -c 'md5sum $PHONE_DIR/$f'" | awk '{print $1}' | tr -d '\r') |
| @@ -55,3 +58,7 @@ echo "确认新进程起来了(不能用 pgrep -f,会自匹配 su shell) | @@ -55,3 +58,7 @@ echo "确认新进程起来了(不能用 pgrep -f,会自匹配 su shell) | ||
| 55 | echo " adb shell \"su -c 'ps -ef | grep -E node.auto-reply.js | grep -v grep'\"" | 58 | echo " adb shell \"su -c 'ps -ef | grep -E node.auto-reply.js | grep -v grep'\"" |
| 56 | echo "看 live 日志(注意:唯一真日志在 hermes-wechat/,别处副本是死的):" | 59 | echo "看 live 日志(注意:唯一真日志在 hermes-wechat/,别处副本是死的):" |
| 57 | echo " adb shell \"su -c 'tail -f $PHONE_DIR/auto-reply.log'\"" | 60 | echo " adb shell \"su -c 'tail -f $PHONE_DIR/auto-reply.log'\"" |
| 61 | +echo "" | ||
| 62 | +echo "若改了 keepalive.sh,需重启守护进程才生效(它以 u0_a327 跑):" | ||
| 63 | +echo " adb shell \"su -c 'pkill -f keepalive.sh'\" # 杀掉旧的" | ||
| 64 | +echo " adb shell \"su u0_a327 -c 'cd $PHONE_DIR && export PATH=/data/data/com.termux/files/usr/bin:\\\$PATH HOME=/data/data/com.termux/files/home; nohup bash keepalive.sh > keepalive.log 2>&1 &'\"" |
server/services/wechat/keepalive.sh
0 → 100644
| 1 | +#!/data/data/com.termux/files/usr/bin/bash | ||
| 2 | +# keepalive.sh — Pixel 微信自动回复保活脚本 | ||
| 3 | +# | ||
| 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 | +# | ||
| 10 | +# 用法(在 Termux 用户 shell 里运行;不要在 root shell 起,wake-lock 拿不住 Termux 进程): | ||
| 11 | +# nohup bash ~/hermes-wechat/keepalive.sh > ~/hermes-wechat/keepalive.log 2>&1 & | ||
| 12 | +# | ||
| 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 | ||
| 18 | + | ||
| 19 | +export PATH="/data/data/com.termux/files/usr/bin:$PATH" | ||
| 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 | +A11Y_SVC="com.hermes.wechat.xposed/com.hermes.wechat.xposed.accessibility.HermesAccessibilityService" | ||
| 26 | +CHECK_INTERVAL_SEC="${CHECK_INTERVAL_SEC:-15}" | ||
| 27 | +# auto-reply 启动用的 env(避开 start-ar.sh 的 shell hook 污染) | ||
| 28 | +MY_WXID="${MY_WXID:-wxid_51ap3m6p9xs722}" | ||
| 29 | +MY_NICKNAME="${MY_NICKNAME:-小火子}" | ||
| 30 | +HERMES_TIMEOUT_MS="${HERMES_TIMEOUT_MS:-600000}" | ||
| 31 | +HISTORY_CONTEXT_SIZE="${HISTORY_CONTEXT_SIZE:-8}" | ||
| 32 | + | ||
| 33 | +log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*"; } | ||
| 34 | + | ||
| 35 | +# ── 1. Termux wake-lock ────────────────────────────────────────── | ||
| 36 | +ensure_wake_lock() { | ||
| 37 | + # 用命令行 termux-wake-lock(依赖 Termux:API app);am startservice 是备用 | ||
| 38 | + if command -v termux-wake-lock >/dev/null 2>&1; then | ||
| 39 | + termux-wake-lock 2>/dev/null | ||
| 40 | + else | ||
| 41 | + # 后备:用 su 调系统 ServiceManager | ||
| 42 | + su -c "am startservice --user 0 -a com.termux.service_wake_lock com.termux/.app.TermuxService" 2>/dev/null || true | ||
| 43 | + fi | ||
| 44 | +} | ||
| 45 | + | ||
| 46 | +is_wake_lock_held() { | ||
| 47 | + su -c "dumpsys power 2>/dev/null | grep -q 'termux:service-wakelock'" | ||
| 48 | +} | ||
| 49 | + | ||
| 50 | +# ── 2. A11y service ────────────────────────────────────────────── | ||
| 51 | +is_a11y_enabled() { | ||
| 52 | + out=$(su -c "settings get secure enabled_accessibility_services" 2>/dev/null) | ||
| 53 | + case "$out" in | ||
| 54 | + *com.hermes.wechat.xposed*HermesAccessibilityService*) return 0 ;; | ||
| 55 | + *) return 1 ;; | ||
| 56 | + esac | ||
| 57 | +} | ||
| 58 | + | ||
| 59 | +enable_a11y() { | ||
| 60 | + log "Enabling HermesAccessibilityService..." | ||
| 61 | + su -c "settings put secure enabled_accessibility_services $A11Y_SVC; settings put secure accessibility_enabled 1" 2>/dev/null | ||
| 62 | +} | ||
| 63 | + | ||
| 64 | +# ── 3. hermes gateway ──────────────────────────────────────────── | ||
| 65 | +is_gateway_running() { | ||
| 66 | + # 用 /sys/class/net 风格的端口探测:通过 nc 或 curl,二选一 | ||
| 67 | + if command -v curl >/dev/null 2>&1; then | ||
| 68 | + # gateway 在 termux 用户下需要 Clash 代理(与本机回环无关); | ||
| 69 | + # 但 127.0.0.1:8642 走本机,不用代理 | ||
| 70 | + env -u HTTPS_PROXY -u HTTP_PROXY \ | ||
| 71 | + curl -s --max-time 3 "http://127.0.0.1:${HERMES_PORT}/v1/models" >/dev/null 2>&1 | ||
| 72 | + else | ||
| 73 | + # nc fallback | ||
| 74 | + echo > /dev/tcp/127.0.0.1/$HERMES_PORT 2>/dev/null | ||
| 75 | + fi | ||
| 76 | +} | ||
| 77 | + | ||
| 78 | +start_gateway() { | ||
| 79 | + log "Starting hermes gateway..." | ||
| 80 | + if [ -x "$GATEWAY_START" ]; then | ||
| 81 | + bash "$GATEWAY_START" >> "$HOME/.hermes/logs/gateway-start.log" 2>&1 | ||
| 82 | + else | ||
| 83 | + log "[ERROR] $GATEWAY_START not found" | ||
| 84 | + fi | ||
| 85 | +} | ||
| 86 | + | ||
| 87 | +# ── 4. auto-reply.js ───────────────────────────────────────────── | ||
| 88 | +AR_PID_FILE="$HERMES_DIR/.auto-reply.pid" | ||
| 89 | + | ||
| 90 | +is_auto_reply_running() { | ||
| 91 | + # 不能用 pgrep -f node.*auto-reply.js — 它会自匹配 su shell 自己的 cmdline。 | ||
| 92 | + # 用 ps -ef + grep 精确匹配 'node auto-reply.js'(含空格,排除 sh wrapper)。 | ||
| 93 | + # su 提权因为 auto-reply 跑在 root 下,u0_a327 看不到 root 进程的 ps。 | ||
| 94 | + # 用 . 占位(任何单字符)避开嵌套引号问题 | ||
| 95 | + su -c "ps -ef 2>/dev/null | grep -E node.auto-reply.js | grep -v sh.-c | grep -v grep" \ | ||
| 96 | + 2>/dev/null | grep -q . | ||
| 97 | +} | ||
| 98 | + | ||
| 99 | +start_auto_reply() { | ||
| 100 | + log "Starting auto-reply..." | ||
| 101 | + # 不走 start-ar.sh wrapper(其 shebang 走 dash 后会触发 phone 上某个 | ||
| 102 | + # claude-run/hermes 会话的 shell snapshot hook,污染 hermes-wechat/*.js)。 | ||
| 103 | + # 直接以 root 起 node + 内联 env,跨过那个 shell session。 | ||
| 104 | + # 起完后用 pgrep + grep 严格匹配 cmdline 确切包含 'node auto-reply.js' | ||
| 105 | + # (不能用 pgrep -f 因为正则 .* 会自匹配 su shell 本身),写入 PID 文件 | ||
| 106 | + su -c "cd $HERMES_DIR && \ | ||
| 107 | + MY_WXID=${MY_WXID:-wxid_51ap3m6p9xs722} \ | ||
| 108 | + MY_NICKNAME=\"${MY_NICKNAME:-小火子}\" \ | ||
| 109 | + HERMES_HOST=127.0.0.1 \ | ||
| 110 | + HERMES_PORT=$HERMES_PORT \ | ||
| 111 | + HERMES_TIMEOUT=${HERMES_TIMEOUT_MS:-600000} \ | ||
| 112 | + NOTIFICATION_ENABLED=true \ | ||
| 113 | + HISTORY_CONTEXT_SIZE=${HISTORY_CONTEXT_SIZE:-8} \ | ||
| 114 | + nohup /data/data/com.termux/files/usr/bin/node auto-reply.js \ | ||
| 115 | + > $HERMES_DIR/auto-reply.log 2>&1 < /dev/null & | ||
| 116 | + echo \$! > $AR_PID_FILE" | ||
| 117 | + sleep 2 | ||
| 118 | + if [ -f "$AR_PID_FILE" ]; then | ||
| 119 | + log "Auto-reply started PID=$(cat $AR_PID_FILE 2>/dev/null)" | ||
| 120 | + fi | ||
| 121 | +} | ||
| 122 | + | ||
| 123 | +# ── 5. 主循环 ──────────────────────────────────────────────────── | ||
| 124 | +log "=== Keepalive started ===" | ||
| 125 | +log "HERMES_DIR=$HERMES_DIR GATEWAY_START=$GATEWAY_START" | ||
| 126 | +log "MY_WXID=$MY_WXID MY_NICKNAME=$MY_NICKNAME HERMES_TIMEOUT=${HERMES_TIMEOUT_MS}ms" | ||
| 127 | +log "Check interval: ${CHECK_INTERVAL_SEC}s" | ||
| 128 | + | ||
| 129 | +# 首次进入:把所有依赖拉到位 | ||
| 130 | +ensure_wake_lock | ||
| 131 | +is_a11y_enabled || enable_a11y | ||
| 132 | +is_gateway_running || start_gateway | ||
| 133 | +sleep 5 | ||
| 134 | +is_auto_reply_running || start_auto_reply | ||
| 135 | + | ||
| 136 | +while true; do | ||
| 137 | + sleep "$CHECK_INTERVAL_SEC" | ||
| 138 | + | ||
| 139 | + # wake-lock 偶尔会因 Termux 重启 / 系统重启而丢,保险起见周期性 re-acquire | ||
| 140 | + if ! is_wake_lock_held; then | ||
| 141 | + log "Wake lock lost, re-acquiring..." | ||
| 142 | + ensure_wake_lock | ||
| 143 | + fi | ||
| 144 | + | ||
| 145 | + # A11y 易被系统升级 / 用户在设置中关掉 | ||
| 146 | + if ! is_a11y_enabled; then | ||
| 147 | + log "A11y service disabled, re-enabling..." | ||
| 148 | + enable_a11y | ||
| 149 | + fi | ||
| 150 | + | ||
| 151 | + if ! is_gateway_running; then | ||
| 152 | + log "Gateway not responding on :$HERMES_PORT, restarting..." | ||
| 153 | + start_gateway | ||
| 154 | + sleep 6 | ||
| 155 | + fi | ||
| 156 | + | ||
| 157 | + # ── restart-flag 桥:让 claude-run(proot 里够不到 Magisk root)也能触发重启 ── | ||
| 158 | + # claude-run 改完 *.js 后 `touch ~/hermes-wechat/.restart-request`,keepalive(已是 root | ||
| 159 | + # 能力)看到就杀掉 auto-reply,下面的 is_auto_reply_running 检测会随即用新代码重启。 | ||
| 160 | + # 只暴露「请求重启」这一个动作,不是任意命令执行。 | ||
| 161 | + if [ -f "$HERMES_DIR/.restart-request" ]; then | ||
| 162 | + log "Restart requested via .restart-request flag, killing auto-reply..." | ||
| 163 | + rm -f "$HERMES_DIR/.restart-request" | ||
| 164 | + su -c "pkill -f auto-reply.js" 2>/dev/null | ||
| 165 | + sleep 1 | ||
| 166 | + fi | ||
| 167 | + | ||
| 168 | + if ! is_auto_reply_running; then | ||
| 169 | + log "auto-reply.js not running, restarting..." | ||
| 170 | + start_auto_reply | ||
| 171 | + fi | ||
| 172 | +done |