@ryantest/openclaw-qqbot 1.6.7-beta.2 → 1.6.7-beta.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -18,15 +18,58 @@
18
18
 
19
19
  set -eo pipefail
20
20
 
21
- # 异常退出时清理临时文件(防止泄露或残留)
21
+ # 确保 cwd 是一个存在的目录。
22
+ # 当从 gateway 进程 fork 时,继承的 cwd 可能已被删除(如旧插件目录被 mv/rm),
23
+ # 导致 openclaw CLI 启动时 process.cwd() 报 ENOENT: uv_cwd 错误。
24
+ cd "$HOME" 2>/dev/null || cd / 2>/dev/null || true
25
+
26
+ # 异常退出时清理临时文件并回滚(防止泄露或残留)
27
+ INSTALL_COMPLETED=false # 标记 install 是否已完成(用于区分正常退出和异常退出)
22
28
  cleanup_on_exit() {
29
+ local exit_code=$?
30
+
31
+ # 异常退出时同步临时配置中的 install 记录回真实配置
23
32
  if [ -n "$TEMP_CONFIG_FILE" ] && [ -f "$TEMP_CONFIG_FILE" ]; then
33
+ # 尝试同步 install 记录(即使异常退出也要保留)
34
+ node -e "
35
+ try {
36
+ const fs = require('fs');
37
+ const tmp = JSON.parse(fs.readFileSync('$TEMP_CONFIG_FILE', 'utf8'));
38
+ const real = JSON.parse(fs.readFileSync('$CONFIG_FILE', 'utf8'));
39
+ if (tmp.plugins && tmp.plugins.installs) {
40
+ if (!real.plugins) real.plugins = {};
41
+ real.plugins.installs = { ...(real.plugins.installs || {}), ...tmp.plugins.installs };
42
+ }
43
+ if (tmp.plugins && tmp.plugins.entries) {
44
+ if (!real.plugins) real.plugins = {};
45
+ real.plugins.entries = { ...(real.plugins.entries || {}), ...tmp.plugins.entries };
46
+ }
47
+ fs.writeFileSync('$CONFIG_FILE', JSON.stringify(real, null, 4) + '\n');
48
+ } catch {}
49
+ " 2>/dev/null || true
24
50
  rm -f "$TEMP_CONFIG_FILE" 2>/dev/null || true
25
51
  fi
26
- # 异常退出时清理本次备份目录(正常流程中备份已被删除或回滚,这里是兜底)
27
- if [ -n "$BACKUP_DIR" ] && [ -d "$BACKUP_DIR" ]; then
52
+
53
+ # 异常退出且 install 未完成时,回滚备份目录(而非删除)
54
+ if [ "$INSTALL_COMPLETED" != "true" ] && [ -n "$BACKUP_DIR" ] && [ -d "$BACKUP_DIR" ]; then
55
+ if [ ! -d "$EXTENSIONS_DIR/$PLUGIN_ID" ] || [ ! -f "$EXTENSIONS_DIR/$PLUGIN_ID/package.json" ]; then
56
+ # 插件目录不存在或不完整,回滚
57
+ rm -rf "$EXTENSIONS_DIR/$PLUGIN_ID" 2>/dev/null || true
58
+ mv "$BACKUP_DIR/$PLUGIN_ID" "$EXTENSIONS_DIR/$PLUGIN_ID" 2>/dev/null || \
59
+ mv "$BACKUP_DIR"/* "$EXTENSIONS_DIR/$PLUGIN_ID" 2>/dev/null || true
60
+ echo " ↩️ [cleanup] 异常退出,已回滚到旧版本"
61
+ else
62
+ # 插件目录完整,清理备份
63
+ rm -rf "$BACKUP_DIR" 2>/dev/null || true
64
+ fi
65
+ elif [ "$INSTALL_COMPLETED" = "true" ] && [ -n "$BACKUP_DIR" ] && [ -d "$BACKUP_DIR" ]; then
66
+ # 正常完成,清理备份
28
67
  rm -rf "$BACKUP_DIR" 2>/dev/null || true
29
68
  fi
69
+
70
+ # 清理 openclaw install 可能残留的暂存目录(extensions 和 /tmp 中都可能存在)
71
+ find "${EXTENSIONS_DIR:-/dev/null}" -maxdepth 1 -name ".openclaw-install-stage-*" -exec rm -rf {} + 2>/dev/null || true
72
+ find "${TMPDIR:-/tmp}" -maxdepth 1 -name ".openclaw-install-stage-*" -exec rm -rf {} + 2>/dev/null || true
30
73
  }
31
74
  trap cleanup_on_exit EXIT
32
75
 
@@ -63,6 +106,7 @@ print_usage() {
63
106
  echo " upgrade-via-npm.sh --self-version # 升级到当前仓库版本"
64
107
  fi
65
108
  echo ""
109
+ echo " --pkg <scope/name> 指定 npm 包名(如 ryantest/openclaw-qqbot)"
66
110
  echo " --appid <appid> QQ机器人 appid(首次安装时必填)"
67
111
  echo " --secret <secret> QQ机器人 secret(首次安装时必填)"
68
112
  echo ""
@@ -76,22 +120,17 @@ while [[ $# -gt 0 ]]; do
76
120
  case "$1" in
77
121
  --tag)
78
122
  [ -z "$2" ] && echo "❌ --tag 需要参数" && exit 1
79
- _ver="${2#v}" # 去掉 v 前缀(npm 版本号不带 v)
80
- TARGET_VERSION="$_ver"
81
- INSTALL_SRC="${PKG_NAME}@$_ver"
123
+ TARGET_VERSION="${2#v}" # 去掉 v 前缀(npm 版本号不带 v)
82
124
  shift 2
83
125
  ;;
84
126
  --version)
85
127
  [ -z "$2" ] && echo "❌ --version 需要参数" && exit 1
86
- _ver="${2#v}" # 去掉 v 前缀(npm 版本号不带 v)
87
- TARGET_VERSION="$_ver"
88
- INSTALL_SRC="${PKG_NAME}@$_ver"
128
+ TARGET_VERSION="${2#v}" # 去掉 v 前缀(npm 版本号不带 v)
89
129
  shift 2
90
130
  ;;
91
131
  --self-version)
92
132
  [ -z "$LOCAL_VERSION" ] && echo "❌ 无法从 package.json 读取版本" && exit 1
93
133
  TARGET_VERSION="$LOCAL_VERSION"
94
- INSTALL_SRC="${PKG_NAME}@${LOCAL_VERSION}"
95
134
  shift 1
96
135
  ;;
97
136
  --appid)
@@ -104,6 +143,14 @@ while [[ $# -gt 0 ]]; do
104
143
  SECRET="$2"
105
144
  shift 2
106
145
  ;;
146
+ --pkg)
147
+ [ -z "$2" ] && echo "❌ --pkg 需要参数" && exit 1
148
+ _pkg="$2"
149
+ # 支持 "scope/name" 自动补 @
150
+ if [[ "$_pkg" != @* ]]; then _pkg="@$_pkg"; fi
151
+ PKG_NAME="$_pkg"
152
+ shift 2
153
+ ;;
107
154
  --no-restart)
108
155
  NO_RESTART=true
109
156
  shift 1
@@ -115,7 +162,12 @@ while [[ $# -gt 0 ]]; do
115
162
  *) echo "未知选项: $1"; print_usage; exit 1 ;;
116
163
  esac
117
164
  done
118
- INSTALL_SRC="${INSTALL_SRC:-${PKG_NAME}@latest}"
165
+ # 参数解析完毕后统一拼接 INSTALL_SRC(确保 --pkg 无论在 --version 前后都能生效)
166
+ if [ -n "$TARGET_VERSION" ]; then
167
+ INSTALL_SRC="${PKG_NAME}@${TARGET_VERSION}"
168
+ else
169
+ INSTALL_SRC="${PKG_NAME}@latest"
170
+ fi
119
171
 
120
172
  # 环境变量 fallback
121
173
  APPID="${APPID:-$QQBOT_APPID}"
@@ -171,30 +223,46 @@ echo "[1/4] 安装/升级插件..."
171
223
  # 环境变量让 plugins install/update 使用临时配置,真实配置文件不受影响。
172
224
  CONFIG_FILE="$HOME/.$CMD/$CMD.json"
173
225
  TEMP_CONFIG_FILE=""
174
- HAS_QQBOT_CHANNEL=false
226
+ NEEDS_TEMP_CONFIG=false
175
227
 
176
228
  if [ -f "$CONFIG_FILE" ]; then
177
- HAS_QQBOT_CHANNEL="$(node -e "
229
+ NEEDS_TEMP_CONFIG="$(node -e "
178
230
  try {
179
231
  const fs = require('fs');
180
232
  const cfg = JSON.parse(fs.readFileSync('$CONFIG_FILE', 'utf8'));
181
- if (cfg.channels && cfg.channels.qqbot) process.stdout.write('true');
233
+ const hasChannel = !!(cfg.channels && cfg.channels.qqbot);
234
+ const hasAllow = Array.isArray(cfg.plugins?.allow) && cfg.plugins.allow.includes('$PLUGIN_ID');
235
+ const hasEntry = !!(cfg.plugins?.entries?.['$PLUGIN_ID']);
236
+ if (hasChannel || hasAllow || hasEntry) process.stdout.write('true');
182
237
  } catch {}
183
238
  " 2>/dev/null || true)"
184
239
 
185
- if [ "$HAS_QQBOT_CHANNEL" = "true" ]; then
240
+ if [ "$NEEDS_TEMP_CONFIG" = "true" ]; then
186
241
  TEMP_CONFIG_FILE="$(mktemp)"
187
242
  node -e "
188
243
  try {
189
244
  const fs = require('fs');
190
245
  const cfg = JSON.parse(fs.readFileSync('$CONFIG_FILE', 'utf8'));
191
- delete cfg.channels.qqbot;
192
- if (Object.keys(cfg.channels).length === 0) delete cfg.channels;
246
+ // 移除 channels.qqbot(插件自定义通道,校验时会 unknown channel id)
247
+ if (cfg.channels?.qqbot) {
248
+ delete cfg.channels.qqbot;
249
+ if (Object.keys(cfg.channels).length === 0) delete cfg.channels;
250
+ }
251
+ // 移除 plugins.allow 中的 openclaw-qqbot(插件目录被备份后校验找不到)
252
+ if (Array.isArray(cfg.plugins?.allow)) {
253
+ cfg.plugins.allow = cfg.plugins.allow.filter(p => p !== '$PLUGIN_ID');
254
+ if (cfg.plugins.allow.length === 0) delete cfg.plugins.allow;
255
+ }
256
+ // 移除 plugins.entries 中的 openclaw-qqbot(同理)
257
+ if (cfg.plugins?.entries?.['$PLUGIN_ID']) {
258
+ delete cfg.plugins.entries['$PLUGIN_ID'];
259
+ if (Object.keys(cfg.plugins.entries).length === 0) delete cfg.plugins.entries;
260
+ }
193
261
  fs.writeFileSync('$TEMP_CONFIG_FILE', JSON.stringify(cfg, null, 4) + '\n');
194
262
  } catch(e) { process.exit(1); }
195
263
  " 2>/dev/null
196
264
  if [ $? -eq 0 ]; then
197
- echo " [兼容] 创建临时配置副本(不含 channels.qqbot)以通过配置校验"
265
+ echo " [兼容] 创建临时配置副本(不含 channels.qqbot / plugins.allow / plugins.entries)以通过配置校验"
198
266
  export OPENCLAW_CONFIG_PATH="$TEMP_CONFIG_FILE"
199
267
  else
200
268
  echo " ⚠️ 创建临时配置失败,继续使用原配置"
@@ -207,22 +275,32 @@ fi
207
275
  # plugins install/update 可能把 install 记录写入了临时配置,需要同步回真实配置
208
276
  restore_qqbot_channel() {
209
277
  if [ -n "$TEMP_CONFIG_FILE" ] && [ -f "$TEMP_CONFIG_FILE" ]; then
210
- # 将临时配置中 plugins.installs 的变更同步回真实配置
278
+ # 将临时配置中 plugins.installs 和 plugins.entries 的变更同步回真实配置
211
279
  node -e "
212
280
  try {
213
281
  const fs = require('fs');
214
282
  const tmp = JSON.parse(fs.readFileSync('$TEMP_CONFIG_FILE', 'utf8'));
215
283
  const real = JSON.parse(fs.readFileSync('$CONFIG_FILE', 'utf8'));
284
+ let changed = false;
216
285
  if (tmp.plugins && tmp.plugins.installs) {
217
286
  if (!real.plugins) real.plugins = {};
218
287
  real.plugins.installs = { ...(real.plugins.installs || {}), ...tmp.plugins.installs };
288
+ changed = true;
289
+ }
290
+ // 同步 plugins.entries(openclaw plugins install 会写入 entries)
291
+ if (tmp.plugins && tmp.plugins.entries) {
292
+ if (!real.plugins) real.plugins = {};
293
+ real.plugins.entries = { ...(real.plugins.entries || {}), ...tmp.plugins.entries };
294
+ changed = true;
295
+ }
296
+ if (changed) {
219
297
  fs.writeFileSync('$CONFIG_FILE', JSON.stringify(real, null, 4) + '\n');
220
298
  }
221
299
  } catch {}
222
300
  " 2>/dev/null || true
223
301
  rm -f "$TEMP_CONFIG_FILE"
224
302
  unset OPENCLAW_CONFIG_PATH
225
- echo " [兼容] 已同步 install 记录并清理临时配置副本"
303
+ echo " [兼容] 已同步 install/entries 记录并清理临时配置副本"
226
304
  fi
227
305
  }
228
306
 
@@ -311,21 +389,57 @@ if [ "$UPGRADE_OK" != "true" ]; then
311
389
  echo " 执行 install: $INSTALL_SRC"
312
390
 
313
391
  if $CMD plugins install "$INSTALL_SRC" --pin 2>&1; then
314
- UPGRADE_OK=true
315
- echo " install 成功"
316
- # install 成功,清理备份
317
- if [ -n "$BACKUP_DIR" ] && [ -d "$BACKUP_DIR" ]; then
318
- rm -rf "$BACKUP_DIR"
319
- echo " 已清理旧版备份"
392
+ # install 返回 0,但需要验证插件目录是否真的存在且完整
393
+ if [ -d "$EXTENSIONS_DIR/$PLUGIN_ID" ] && [ -f "$EXTENSIONS_DIR/$PLUGIN_ID/package.json" ]; then
394
+ UPGRADE_OK=true
395
+ INSTALL_COMPLETED=true
396
+ echo " ✅ install 成功"
397
+ # install 成功,清理备份
398
+ if [ -n "$BACKUP_DIR" ] && [ -d "$BACKUP_DIR" ]; then
399
+ rm -rf "$BACKUP_DIR"
400
+ echo " 已清理旧版备份"
401
+ fi
402
+ # 清理 openclaw CLI install 可能留下的额外 backup 目录(extensions 内遗留 + 新路径)
403
+ find "$EXTENSIONS_DIR" -maxdepth 1 -name ".openclaw-qqbot-backup-*" -exec rm -rf {} + 2>/dev/null || true
404
+ find "${EXTENSIONS_DIR:-/dev/null}" -maxdepth 1 -name ".openclaw-install-stage-*" -exec rm -rf {} + 2>/dev/null || true
405
+ find "${TMPDIR:-/tmp}" -maxdepth 1 -name ".openclaw-install-stage-*" -exec rm -rf {} + 2>/dev/null || true
406
+ find "${TMPDIR:-/tmp}" -maxdepth 1 -name ".qqbot-upgrade-backup-*" -exec rm -rf {} + 2>/dev/null || true
407
+ else
408
+ echo " ❌ install 命令返回成功但插件目录不完整"
409
+ echo " [诊断] 目录存在: $([ -d "$EXTENSIONS_DIR/$PLUGIN_ID" ] && echo '是' || echo '否')"
410
+ echo " [诊断] package.json 存在: $([ -f "$EXTENSIONS_DIR/$PLUGIN_ID/package.json" ] && echo '是' || echo '否')"
411
+ # 清理可能残留的暂存目录(extensions 和 /tmp 中都可能存在)
412
+ find "${EXTENSIONS_DIR:-/dev/null}" -maxdepth 1 -name ".openclaw-install-stage-*" -exec rm -rf {} + 2>/dev/null || true
413
+ find "${TMPDIR:-/tmp}" -maxdepth 1 -name ".openclaw-install-stage-*" -exec rm -rf {} + 2>/dev/null || true
414
+ # 回滚
415
+ if [ -n "$BACKUP_DIR" ] && [ -d "$BACKUP_DIR" ]; then
416
+ rm -rf "$EXTENSIONS_DIR/$PLUGIN_ID" 2>/dev/null || true
417
+ # 备份目录内可能是 PLUGIN_ID 子目录或直接是内容
418
+ if [ -d "$BACKUP_DIR/$PLUGIN_ID" ]; then
419
+ mv "$BACKUP_DIR/$PLUGIN_ID" "$EXTENSIONS_DIR/$PLUGIN_ID"
420
+ else
421
+ mv "$BACKUP_DIR" "$EXTENSIONS_DIR/$PLUGIN_ID"
422
+ fi
423
+ echo " ↩️ 已回滚到旧版本"
424
+ fi
425
+ restore_qqbot_channel
426
+ echo "QQBOT_NEW_VERSION=unknown"
427
+ echo "QQBOT_REPORT=❌ QQBot 安装异常(目录不完整,已回滚),请重试或手动安装"
428
+ exit 1
320
429
  fi
321
- # 清理 openclaw CLI install 可能留下的额外 backup 目录(extensions 内遗留 + 新路径)
322
- find "$EXTENSIONS_DIR" -maxdepth 1 -name ".openclaw-qqbot-backup-*" -exec rm -rf {} + 2>/dev/null || true
323
- find "${TMPDIR:-/tmp}" -maxdepth 1 -name ".qqbot-upgrade-backup-*" -exec rm -rf {} + 2>/dev/null || true
324
430
  else
325
431
  echo " ❌ install 失败"
432
+ # 清理可能残留的暂存目录(extensions 和 /tmp 中都可能存在)
433
+ find "${EXTENSIONS_DIR:-/dev/null}" -maxdepth 1 -name ".openclaw-install-stage-*" -exec rm -rf {} + 2>/dev/null || true
434
+ find "${TMPDIR:-/tmp}" -maxdepth 1 -name ".openclaw-install-stage-*" -exec rm -rf {} + 2>/dev/null || true
326
435
  # 回滚:恢复旧目录
327
436
  if [ -n "$BACKUP_DIR" ] && [ -d "$BACKUP_DIR" ]; then
328
- mv "$BACKUP_DIR" "$EXTENSIONS_DIR/$PLUGIN_ID"
437
+ rm -rf "$EXTENSIONS_DIR/$PLUGIN_ID" 2>/dev/null || true
438
+ if [ -d "$BACKUP_DIR/$PLUGIN_ID" ]; then
439
+ mv "$BACKUP_DIR/$PLUGIN_ID" "$EXTENSIONS_DIR/$PLUGIN_ID"
440
+ else
441
+ mv "$BACKUP_DIR" "$EXTENSIONS_DIR/$PLUGIN_ID"
442
+ fi
329
443
  echo " ↩️ 已回滚到旧版本"
330
444
  fi
331
445
  restore_qqbot_channel
@@ -262,8 +262,9 @@ if lsof -i :18789 -sTCP:LISTEN >/dev/null 2>&1; then
262
262
  sleep 1
263
263
  fi
264
264
 
265
- # 清理之前可能残留的 staging 目录
265
+ # 清理之前可能残留的 staging 目录(extensions 和 /tmp 中都可能存在)
266
266
  find "$HOME/.openclaw/extensions/" -maxdepth 1 -name ".openclaw-install-stage-*" -exec rm -rf {} + 2>/dev/null || true
267
+ find "${TMPDIR:-/tmp}" -maxdepth 1 -name ".openclaw-install-stage-*" -exec rm -rf {} + 2>/dev/null || true
267
268
 
268
269
  # ── 清空并重新构建 dist/ ──
269
270
  # openclaw plugins install . 只做文件复制,不执行 npm lifecycle scripts。
@@ -344,13 +345,13 @@ if [ ! -f "$_INSTALL_DIR/dist/index.js" ] || [ ! -f "$_INSTALL_DIR/preload.cjs"
344
345
  echo "请先解决安装问题后再运行此脚本。"
345
346
  # 恢复 channels.qqbot 后再退出
346
347
  if [ -n "$_QQBOT_CHANNEL_STASH" ] && [ -n "$_STASH_CFG" ] && [ -f "$_STASH_CFG" ]; then
347
- node -e "
348
- const fs = require('fs');
349
- const cfg = JSON.parse(fs.readFileSync('$_STASH_CFG', 'utf8'));
348
+ _STASH="$_QQBOT_CHANNEL_STASH" _CFG="$_STASH_CFG" node -e '
349
+ const fs = require("fs");
350
+ const cfg = JSON.parse(fs.readFileSync(process.env._CFG, "utf8"));
350
351
  if (!cfg.channels) cfg.channels = {};
351
- cfg.channels.qqbot = $_QQBOT_CHANNEL_STASH;
352
- fs.writeFileSync('$_STASH_CFG', JSON.stringify(cfg, null, 4) + '\n');
353
- " 2>/dev/null || true
352
+ cfg.channels.qqbot = JSON.parse(process.env._STASH);
353
+ fs.writeFileSync(process.env._CFG, JSON.stringify(cfg, null, 4) + "\n");
354
+ ' 2>/dev/null || true
354
355
  fi
355
356
  exit 1
356
357
  ;;
@@ -398,6 +399,7 @@ else
398
399
  echo ""
399
400
  echo " 尝试自动修复: 清理残留并重试安装..."
400
401
  find "$HOME/.openclaw/extensions/" -maxdepth 1 -name ".openclaw-install-stage-*" -exec rm -rf {} + 2>/dev/null || true
402
+ find "${TMPDIR:-/tmp}" -maxdepth 1 -name ".openclaw-install-stage-*" -exec rm -rf {} + 2>/dev/null || true
401
403
  if openclaw plugins install . 2>&1 | tee -a "$INSTALL_LOG"; then
402
404
  for _candidate_name in openclaw-qqbot qqbot openclaw-qq; do
403
405
  if [ -d "$HOME/.openclaw/extensions/$_candidate_name" ]; then
@@ -592,11 +594,11 @@ echo "[4/6] 准备机器人通道配置..."
592
594
  # 注意:channels.qqbot 已被暂存移除,所以从 _QQBOT_CHANNEL_STASH 读取
593
595
  CURRENT_QQBOT_TOKEN=""
594
596
  if [ -n "$_QQBOT_CHANNEL_STASH" ]; then
595
- CURRENT_QQBOT_TOKEN=$(node -e "
596
- const ch = $_QQBOT_CHANNEL_STASH;
597
+ CURRENT_QQBOT_TOKEN=$(_STASH="$_QQBOT_CHANNEL_STASH" node -e '
598
+ const ch = JSON.parse(process.env._STASH);
597
599
  if (ch.token) { process.stdout.write(ch.token); }
598
- else if (ch.appId && ch.clientSecret) { process.stdout.write(ch.appId + ':' + ch.clientSecret); }
599
- " 2>/dev/null || true)
600
+ else if (ch.appId && ch.clientSecret) { process.stdout.write(ch.appId + ":" + ch.clientSecret); }
601
+ ' 2>/dev/null || true)
600
602
  fi
601
603
 
602
604
  DESIRED_QQBOT_TOKEN=""
@@ -787,34 +789,39 @@ case "$start_choice" in
787
789
 
788
790
  if [ -n "$_target_cfg" ]; then
789
791
  # 构建完整的 channels.qqbot 对象(合并暂存配置 + 新 token + markdown)
790
- node -e "
791
- const fs = require('fs');
792
- const cfg = JSON.parse(fs.readFileSync('$_target_cfg', 'utf8'));
792
+ # 通过环境变量传递,避免 JSON 双引号在 node -e "..." 中被 shell 错误解析
793
+ _STASH="$_QQBOT_CHANNEL_STASH" \
794
+ _DESIRED="$DESIRED_QQBOT_TOKEN" \
795
+ _MD="$MARKDOWN_VALUE" \
796
+ _CFG="$_target_cfg" \
797
+ node -e '
798
+ const fs = require("fs");
799
+ const cfg = JSON.parse(fs.readFileSync(process.env._CFG, "utf8"));
793
800
  if (!cfg.channels) cfg.channels = {};
794
801
 
795
802
  // 从暂存恢复基础配置
796
- const stash = '$_QQBOT_CHANNEL_STASH';
803
+ const stash = process.env._STASH;
797
804
  if (stash) {
798
805
  try { cfg.channels.qqbot = JSON.parse(stash); } catch {}
799
806
  }
800
807
  if (!cfg.channels.qqbot) cfg.channels.qqbot = {};
801
808
 
802
809
  // 覆盖 token(如果有新值)
803
- const desired = '$DESIRED_QQBOT_TOKEN';
804
- if (desired && desired.includes(':')) {
805
- const [appId, ...rest] = desired.split(':');
810
+ const desired = process.env._DESIRED;
811
+ if (desired && desired.includes(":")) {
812
+ const [appId, ...rest] = desired.split(":");
806
813
  cfg.channels.qqbot.appId = appId;
807
- cfg.channels.qqbot.clientSecret = rest.join(':');
814
+ cfg.channels.qqbot.clientSecret = rest.join(":");
808
815
  delete cfg.channels.qqbot.token;
809
816
  }
810
817
 
811
818
  // 覆盖 markdown(如果有指定)
812
- const md = '$MARKDOWN_VALUE';
813
- if (md === 'true') cfg.channels.qqbot.markdownSupport = true;
814
- else if (md === 'false') cfg.channels.qqbot.markdownSupport = false;
819
+ const md = process.env._MD;
820
+ if (md === "true") cfg.channels.qqbot.markdownSupport = true;
821
+ else if (md === "false") cfg.channels.qqbot.markdownSupport = false;
815
822
 
816
- fs.writeFileSync('$_target_cfg', JSON.stringify(cfg, null, 4) + '\n');
817
- " 2>/dev/null || true
823
+ fs.writeFileSync(process.env._CFG, JSON.stringify(cfg, null, 4) + "\n");
824
+ ' 2>&1 || echo " ⚠️ 配置写入失败"
818
825
  echo " ✅ 已恢复 channels.qqbot 配置(含 token/markdown)"
819
826
  _need_reload=1
820
827
  fi
@@ -884,13 +891,13 @@ case "$start_choice" in
884
891
  # 注意:下次 gateway 启动可能因 "unknown channel id" 失败,
885
892
  # 需要用户手动 stop → 移除 channels.qqbot → start → 恢复
886
893
  if [ -n "$_QQBOT_CHANNEL_STASH" ] && [ -n "$_STASH_CFG" ] && [ -f "$_STASH_CFG" ]; then
887
- node -e "
888
- const fs = require('fs');
889
- const cfg = JSON.parse(fs.readFileSync('$_STASH_CFG', 'utf8'));
894
+ _STASH="$_QQBOT_CHANNEL_STASH" _CFG="$_STASH_CFG" node -e '
895
+ const fs = require("fs");
896
+ const cfg = JSON.parse(fs.readFileSync(process.env._CFG, "utf8"));
890
897
  if (!cfg.channels) cfg.channels = {};
891
- cfg.channels.qqbot = $_QQBOT_CHANNEL_STASH;
892
- fs.writeFileSync('$_STASH_CFG', JSON.stringify(cfg, null, 4) + '\n');
893
- " 2>/dev/null || true
898
+ cfg.channels.qqbot = JSON.parse(process.env._STASH);
899
+ fs.writeFileSync(process.env._CFG, JSON.stringify(cfg, null, 4) + "\n");
900
+ ' 2>/dev/null || true
894
901
  echo " 已恢复 channels.qqbot 配置"
895
902
  fi
896
903
  echo ""
package/src/api.ts CHANGED
@@ -137,7 +137,7 @@ async function doFetchToken(appId: string, clientSecret: string): Promise<string
137
137
  const requestHeaders = { "Content-Type": "application/json", "User-Agent": PLUGIN_USER_AGENT };
138
138
 
139
139
  // 打印请求信息(隐藏敏感信息)
140
- console.log(`[qqbot-api:${appId}] >>> POST ${TOKEN_URL}`);
140
+ console.log(`[qqbot-api:${appId}] >>> POST ${TOKEN_URL} [secret: ${clientSecret.slice(0, 6)}...len=${clientSecret.length}]`);
141
141
 
142
142
  let response: Response;
143
143
  try {