quick-start.sh 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. #!/usr/bin/env bash
  2. # quick-start.sh - v1.2.1
  3. # 一键升级到 v1.2.0 auto-reply daemon 并启动,绕开 agent 的不稳定代码生成。
  4. #
  5. # 用法(在 Linux 服务器上):
  6. # unzip -o openclaw-wechat-skill-v1.2.x.zip -d openclaw-wechat-skill
  7. # cd openclaw-wechat-skill
  8. # bash quick-start.sh
  9. #
  10. # 可选环境变量:
  11. # WECHAT_API_BASE=http://your-host:port # 跳过自动探测
  12. # SKIP_DEPLOY=1 # 只启动 daemon,不重新部署
  13. set -uo pipefail
  14. SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
  15. OPENCLAW_DIR="$HOME/.openclaw"
  16. SKILLS_ROOT="$OPENCLAW_DIR/skills"
  17. DAEMON_DST="$OPENCLAW_DIR/auto-reply-daemon.js"
  18. CRED_FILE="$OPENCLAW_DIR/wechat-credentials.json"
  19. PID_FILE="$OPENCLAW_DIR/wechat-auto-reply.pid"
  20. LOG_FILE="$OPENCLAW_DIR/logs/auto-reply.log"
  21. GREEN=$'\e[32m'; YELLOW=$'\e[33m'; RED=$'\e[31m'; CYAN=$'\e[36m'; NC=$'\e[0m'
  22. section() { echo ""; echo "${CYAN}==== $* ====${NC}"; }
  23. ok() { echo " ${GREEN}[OK]${NC} $*"; }
  24. warn() { echo " ${YELLOW}[!]${NC} $*"; }
  25. err() { echo " ${RED}[ERR]${NC} $*"; }
  26. # ---------------- 1. Kill any running daemon (ours + agent's) ----------------
  27. section "1. 停止任何正在运行的 auto-reply daemon"
  28. # our daemon via pid file
  29. if [ -f "$PID_FILE" ]; then
  30. PID=$(cat "$PID_FILE" 2>/dev/null || echo "")
  31. if [ -n "$PID" ] && kill -0 "$PID" 2>/dev/null; then
  32. kill "$PID" 2>/dev/null
  33. sleep 1
  34. kill -0 "$PID" 2>/dev/null && kill -9 "$PID" 2>/dev/null
  35. ok "已停止旧 daemon (PID=$PID)"
  36. fi
  37. rm -f "$PID_FILE"
  38. fi
  39. # agent's hallucinated daemon: kill any node process running *auto-reply*
  40. # (pattern-match to avoid killing unrelated node processes)
  41. STALE=$(pgrep -f 'node.*auto.reply' 2>/dev/null || true)
  42. if [ -n "$STALE" ]; then
  43. echo "$STALE" | xargs -r kill 2>/dev/null || true
  44. sleep 1
  45. STALE2=$(pgrep -f 'node.*auto.reply' 2>/dev/null || true)
  46. [ -n "$STALE2" ] && echo "$STALE2" | xargs -r kill -9 2>/dev/null || true
  47. ok "已停止 agent 遗留的 daemon 进程: $STALE"
  48. fi
  49. # ---------------- 2. Check prerequisites ----------------
  50. section "2. 检查依赖"
  51. if ! command -v node >/dev/null 2>&1; then
  52. err "未找到 node, 请先安装 Node.js (>=14)"
  53. exit 1
  54. fi
  55. ok "node $(node --version)"
  56. if ! command -v curl >/dev/null 2>&1; then
  57. err "未找到 curl"
  58. exit 1
  59. fi
  60. ok "curl OK"
  61. # ---------------- 3. Deploy skills + daemon (unless SKIP_DEPLOY=1) ----------------
  62. if [ "${SKIP_DEPLOY:-0}" != "1" ]; then
  63. section "3. 部署 skills 和 daemon"
  64. if [ -f "$SCRIPT_DIR/deploy-to-openclaw.js" ]; then
  65. node "$SCRIPT_DIR/deploy-to-openclaw.js" --source-root="$SCRIPT_DIR" || {
  66. err "部署脚本失败,请检查上面的输出"
  67. exit 1
  68. }
  69. else
  70. err "找不到 $SCRIPT_DIR/deploy-to-openclaw.js, 确认你在解压目录里运行本脚本"
  71. exit 1
  72. fi
  73. else
  74. warn "SKIP_DEPLOY=1, 跳过部署"
  75. fi
  76. # ---------------- 4. Probe / set wechatApiBase ----------------
  77. section "4. 探测可用的 wechatApiBase"
  78. probe() {
  79. local base="$1"
  80. local resp
  81. resp=$(curl -s --max-time 5 -X POST "$base/login/check-online" \
  82. -H "Content-Type: application/json" -d '{}' 2>/dev/null || echo "")
  83. if echo "$resp" | grep -q '"ret":200'; then
  84. local ONLINE="?"
  85. echo "$resp" | grep -q '"data":true' && ONLINE="true"
  86. echo "$resp" | grep -q '"data":false' && ONLINE="false"
  87. echo " probe $base -> ret=200 online=$ONLINE"
  88. return 0
  89. fi
  90. echo " probe $base -> NO (resp=${resp:0:80})"
  91. return 1
  92. }
  93. WORKING_BASE=""
  94. if [ -n "${WECHAT_API_BASE:-}" ]; then
  95. echo "使用环境变量 WECHAT_API_BASE=$WECHAT_API_BASE"
  96. if probe "$WECHAT_API_BASE"; then WORKING_BASE="$WECHAT_API_BASE"; fi
  97. else
  98. # Read current config first
  99. CURRENT=""
  100. if [ -f "$CRED_FILE" ]; then
  101. CURRENT=$(node -e "try{console.log(require('$CRED_FILE').wechatApiBase||'')}catch(e){}" 2>/dev/null || echo "")
  102. fi
  103. CANDIDATES=(
  104. "$CURRENT"
  105. "http://127.0.0.1:8138"
  106. "http://127.0.0.1"
  107. "http://localhost:8138"
  108. "http://localhost"
  109. "http://8.138.37.248"
  110. "http://8.138.37.248/api/wechat-agent"
  111. )
  112. # de-dup + drop empty
  113. for base in "${CANDIDATES[@]}"; do
  114. [ -z "$base" ] && continue
  115. [ "$base" = "$WORKING_BASE" ] && continue
  116. # skip duplicates
  117. seen=0
  118. for done_base in "${TRIED[@]:-}"; do [ "$done_base" = "$base" ] && seen=1; done
  119. [ "$seen" = "1" ] && continue
  120. TRIED+=("$base")
  121. if probe "$base"; then
  122. WORKING_BASE="$base"
  123. break
  124. fi
  125. done
  126. fi
  127. if [ -z "$WORKING_BASE" ]; then
  128. err "所有候选 URL 都不通, 请手动确认后端地址再运行: WECHAT_API_BASE=http://your-host bash quick-start.sh"
  129. exit 1
  130. fi
  131. ok "使用 wechatApiBase = $WORKING_BASE"
  132. # Write into credentials file
  133. mkdir -p "$OPENCLAW_DIR"
  134. node -e "
  135. const fs=require('fs'),p='$CRED_FILE';
  136. let c={}; try{c=JSON.parse(fs.readFileSync(p,'utf8'))}catch(e){};
  137. c.wechatApiBase='$WORKING_BASE';
  138. fs.writeFileSync(p,JSON.stringify(c,null,2));
  139. "
  140. ok "已写入 $CRED_FILE"
  141. # ---------------- 5. Start our daemon ----------------
  142. section "5. 启动 v1.2.0 daemon"
  143. if [ ! -f "$DAEMON_DST" ]; then
  144. err "daemon 未部署到 $DAEMON_DST, 请检查上一步"
  145. exit 1
  146. fi
  147. mkdir -p "$(dirname "$LOG_FILE")"
  148. # Append separator to log
  149. echo "" >> "$LOG_FILE"
  150. echo "=== quick-start $(date -Iseconds) ===" >> "$LOG_FILE"
  151. nohup node "$DAEMON_DST" >> "$LOG_FILE" 2>&1 &
  152. NEW_PID=$!
  153. echo "$NEW_PID" > "$PID_FILE"
  154. sleep 2
  155. if kill -0 "$NEW_PID" 2>/dev/null; then
  156. ok "daemon 已启动, PID=$NEW_PID"
  157. else
  158. err "daemon 启动后立即退出, 看日志排查:"
  159. tail -n 30 "$LOG_FILE"
  160. exit 1
  161. fi
  162. # ---------------- 6. Watch log for 15 seconds ----------------
  163. section "6. 观察日志 15 秒 (期望看到 '配置载入' + 至少一次 get-messages)"
  164. sleep 15
  165. echo ""
  166. tail -n 30 "$LOG_FILE"
  167. echo ""
  168. if grep -q 'daemon start' "$LOG_FILE" && ! grep -q 'fatal\|uncaughtException' "$LOG_FILE"; then
  169. section "完成"
  170. ok "daemon 健康运行中, PID=$NEW_PID"
  171. echo ""
  172. echo "下一步:"
  173. echo " 1) 让测试微信号给这台机器登录的微信发条消息"
  174. echo " 2) 持续观察: tail -f $LOG_FILE"
  175. echo " 3) 改规则: vim $OPENCLAW_DIR/wechat-auto-reply-config.json (热加载)"
  176. echo " 4) 停服务: kill \$(cat $PID_FILE)"
  177. echo ""
  178. echo "如果测试消息发了但日志里没有 'received' -> 看后端 /messages 接口是否正常"
  179. echo "如果有 'received' 但没有 'replied' -> 看 'skip' / 'cooldown' / 'no-reply-rule' 原因"
  180. else
  181. warn "daemon 启动但日志异常, 请把上面的日志贴出来排查"
  182. fi