@tencent-connect/openclaw-qqbot 1.6.5-alpha.6 → 1.6.5
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.
- package/dist/src/gateway.js +30 -1
- package/dist/src/slash-commands.js +46 -18
- package/package.json +1 -1
- package/scripts/upgrade-via-npm.sh +4 -0
- package/scripts/upgrade-via-source.sh +128 -122
- package/src/gateway.ts +30 -1
- package/src/slash-commands.ts +51 -20
package/dist/src/gateway.js
CHANGED
|
@@ -87,6 +87,22 @@ export async function startGateway(ctx) {
|
|
|
87
87
|
log?.info(`[qqbot:${account.accountId}] ${w}`);
|
|
88
88
|
}
|
|
89
89
|
}
|
|
90
|
+
// 预检 openclaw runtime 模块是否可正常解析(兼容性诊断)
|
|
91
|
+
// openclaw 3.23+ 存在 plugin-sdk/root-alias.cjs 回归 bug,
|
|
92
|
+
// 内置插件(qwen-portal-auth 等)全部加载失败,导致 AI agent 调用返回
|
|
93
|
+
// "Unable to resolve plugin runtime module"。提前检测并告警。
|
|
94
|
+
try {
|
|
95
|
+
const pluginRuntime = getQQBotRuntime();
|
|
96
|
+
if (pluginRuntime?.channel?.reply?.dispatchReplyWithBufferedBlockDispatcher) {
|
|
97
|
+
log?.info(`[qqbot:${account.accountId}] Runtime module preflight: OK`);
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
log?.error(`[qqbot:${account.accountId}] ⚠️ Runtime preflight: dispatchReply API 不可用,AI 消息处理可能失败。请检查 openclaw 版本兼容性`);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
catch (preflightErr) {
|
|
104
|
+
log?.error(`[qqbot:${account.accountId}] ⚠️ Runtime preflight failed: ${preflightErr}. AI 消息处理可能失败`);
|
|
105
|
+
}
|
|
90
106
|
// 后台版本检查(供 /bot-version、/bot-upgrade 指令被动查询)
|
|
91
107
|
triggerUpdateCheck(log);
|
|
92
108
|
// 初始化 API 配置(markdown 支持)
|
|
@@ -883,8 +899,13 @@ export async function startGateway(ctx) {
|
|
|
883
899
|
clearTimeout(timeoutId);
|
|
884
900
|
timeoutId = null;
|
|
885
901
|
}
|
|
886
|
-
// 发送错误提示给用户,显示完整错误信息
|
|
887
902
|
const errMsg = String(err);
|
|
903
|
+
// 兼容 openclaw 3.23+ 的 plugin-sdk/root-alias.cjs 模块解析失败
|
|
904
|
+
if (errMsg.includes("Unable to resolve plugin runtime module") || errMsg.includes("root-alias.cjs")) {
|
|
905
|
+
log?.error(`[qqbot:${account.accountId}] ⚠️ openclaw 框架 runtime 模块解析失败,可能是 openclaw 版本与 plugin-sdk 不兼容。请尝试: npm install -g openclaw@latest && openclaw gateway restart`);
|
|
906
|
+
await sendErrorMessage("⚠️ AI 服务暂时不可用:openclaw 框架运行时模块加载失败。\n\n请管理员执行:\nnpm install -g openclaw@latest\nopenclaw gateway restart\n\n斜杠命令(如 /bot-ping)不受影响。");
|
|
907
|
+
return;
|
|
908
|
+
}
|
|
888
909
|
if (errMsg.includes("401") || errMsg.includes("key") || errMsg.includes("auth")) {
|
|
889
910
|
log?.error(`[qqbot:${account.accountId}] AI auth error: ${errMsg}`);
|
|
890
911
|
}
|
|
@@ -929,7 +950,15 @@ export async function startGateway(ctx) {
|
|
|
929
950
|
}
|
|
930
951
|
}
|
|
931
952
|
catch (err) {
|
|
953
|
+
const errStr = String(err);
|
|
932
954
|
log?.error(`[qqbot:${account.accountId}] Message processing failed: ${err}`);
|
|
955
|
+
// 兼容 openclaw 3.23+ runtime 模块解析失败:给用户发可操作的提示
|
|
956
|
+
if (errStr.includes("Unable to resolve plugin runtime module") || errStr.includes("root-alias.cjs")) {
|
|
957
|
+
try {
|
|
958
|
+
await sendErrorMessage("⚠️ AI 服务暂时不可用:openclaw 框架运行时模块加载失败。\n\n请管理员执行:\nnpm install -g openclaw@latest\nopenclaw gateway restart\n\n斜杠命令(如 /bot-ping)不受影响。");
|
|
959
|
+
}
|
|
960
|
+
catch { /* best-effort */ }
|
|
961
|
+
}
|
|
933
962
|
}
|
|
934
963
|
finally {
|
|
935
964
|
// 无论成功/失败/超时,都停止输入状态续期
|
|
@@ -726,7 +726,11 @@ function fireHotUpgrade(targetVersion) {
|
|
|
726
726
|
/**
|
|
727
727
|
* /bot-upgrade — 统一升级入口
|
|
728
728
|
*
|
|
729
|
-
*
|
|
729
|
+
* upgradeMode 开关:
|
|
730
|
+
* - "doc"(默认):只展示升级指引文档,不执行热更新
|
|
731
|
+
* - "hot-reload":执行 npm 升级脚本进行热更新
|
|
732
|
+
*
|
|
733
|
+
* 热更新模式下的产品流程:
|
|
730
734
|
* /bot-upgrade — 展示版本信息+确认按钮(不直接升级)
|
|
731
735
|
* /bot-upgrade --latest — 确认升级到最新版本
|
|
732
736
|
* /bot-upgrade --version X — 升级到指定版本
|
|
@@ -735,21 +739,49 @@ function fireHotUpgrade(targetVersion) {
|
|
|
735
739
|
let _upgrading = false; // 升级锁
|
|
736
740
|
registerCommand({
|
|
737
741
|
name: "bot-upgrade",
|
|
738
|
-
description: "
|
|
742
|
+
description: "检查更新并查看升级指引",
|
|
739
743
|
usage: [
|
|
740
|
-
`/bot-upgrade
|
|
741
|
-
`/bot-upgrade --latest
|
|
742
|
-
`/bot-upgrade --version X
|
|
743
|
-
`/bot-upgrade --force
|
|
744
|
-
``,
|
|
745
|
-
`⚠️ 仅在私聊中可用。升级过程约 30~60 秒,期间服务短暂不可用。`,
|
|
746
|
-
``,
|
|
747
|
-
`环境要求:`,
|
|
748
|
-
` - 操作系统:macOS / Linux / Windows`,
|
|
749
|
-
` - OpenClaw 框架版本 ≥ ${UPGRADE_REQUIREMENTS.minFrameworkVersion}`,
|
|
750
|
-
` - Node.js ≥ v${UPGRADE_REQUIREMENTS.minNodeVersion}`,
|
|
744
|
+
`/bot-upgrade 检查是否有新版本`,
|
|
745
|
+
`/bot-upgrade --latest 确认升级到最新版本(需 upgradeMode=hot-reload)`,
|
|
746
|
+
`/bot-upgrade --version X 升级到指定版本(需 upgradeMode=hot-reload)`,
|
|
747
|
+
`/bot-upgrade --force 强制重新安装当前版本(需 upgradeMode=hot-reload)`,
|
|
751
748
|
].join("\n"),
|
|
752
749
|
handler: async (ctx) => {
|
|
750
|
+
const url = ctx.accountConfig?.upgradeUrl || DEFAULT_UPGRADE_URL;
|
|
751
|
+
const upgradeMode = ctx.accountConfig?.upgradeMode || "doc";
|
|
752
|
+
const args = ctx.args.trim();
|
|
753
|
+
const info = await getUpdateInfo();
|
|
754
|
+
const GITHUB_URL = "https://github.com/tencent-connect/openclaw-qqbot/";
|
|
755
|
+
// ── doc 模式(默认):只展示升级指引,不执行热更新 ──
|
|
756
|
+
if (upgradeMode !== "hot-reload") {
|
|
757
|
+
if (info.checkedAt === 0) {
|
|
758
|
+
return `⏳ 版本检查中,请稍后再试`;
|
|
759
|
+
}
|
|
760
|
+
if (info.error) {
|
|
761
|
+
return [
|
|
762
|
+
`❌ 主机网络访问异常,无法检查更新`,
|
|
763
|
+
``,
|
|
764
|
+
`查看升级指引:[点击查看](${url})`,
|
|
765
|
+
].join("\n");
|
|
766
|
+
}
|
|
767
|
+
if (!info.hasUpdate) {
|
|
768
|
+
return [
|
|
769
|
+
`✅ 当前已是最新版本 v${PLUGIN_VERSION}`,
|
|
770
|
+
``,
|
|
771
|
+
`项目地址:[GitHub](${GITHUB_URL})`,
|
|
772
|
+
].join("\n");
|
|
773
|
+
}
|
|
774
|
+
return [
|
|
775
|
+
`🆕 发现新版本`,
|
|
776
|
+
``,
|
|
777
|
+
`当前版本:**v${PLUGIN_VERSION}**`,
|
|
778
|
+
`最新版本:**v${info.latest}**`,
|
|
779
|
+
``,
|
|
780
|
+
`📖 升级指引:[点击查看](${url})`,
|
|
781
|
+
`🌟 官方 GitHub 仓库:[点击前往](${GITHUB_URL})`,
|
|
782
|
+
].join("\n");
|
|
783
|
+
}
|
|
784
|
+
// ── hot-reload 模式:执行热更新 ──
|
|
753
785
|
// 升级相关指令仅在私聊中可用
|
|
754
786
|
if (ctx.type !== "c2c") {
|
|
755
787
|
return `💡 请在私聊中使用此指令`;
|
|
@@ -758,9 +790,6 @@ registerCommand({
|
|
|
758
790
|
if (_upgrading) {
|
|
759
791
|
return `⏳ 正在升级中,请稍候...`;
|
|
760
792
|
}
|
|
761
|
-
const url = ctx.accountConfig?.upgradeUrl || DEFAULT_UPGRADE_URL;
|
|
762
|
-
const args = ctx.args.trim();
|
|
763
|
-
const info = await getUpdateInfo();
|
|
764
793
|
let isForce = false;
|
|
765
794
|
let isLatest = false;
|
|
766
795
|
let versionArg;
|
|
@@ -797,7 +826,6 @@ registerCommand({
|
|
|
797
826
|
continue;
|
|
798
827
|
}
|
|
799
828
|
}
|
|
800
|
-
const GITHUB_URL = "https://github.com/tencent-connect/openclaw-qqbot/";
|
|
801
829
|
// ── 无参数(也没有 --latest / --version / --force):只展示信息+确认按钮 ──
|
|
802
830
|
if (!versionArg && !isLatest && !isForce) {
|
|
803
831
|
if (info.checkedAt === 0) {
|
|
@@ -818,7 +846,7 @@ registerCommand({
|
|
|
818
846
|
];
|
|
819
847
|
return lines.join("\n");
|
|
820
848
|
}
|
|
821
|
-
// 有新版本:展示信息 +
|
|
849
|
+
// 有新版本:展示信息 + 确认按钮
|
|
822
850
|
return [
|
|
823
851
|
`🆕 发现新版本`,
|
|
824
852
|
``,
|
package/package.json
CHANGED
|
@@ -117,8 +117,12 @@ done
|
|
|
117
117
|
|
|
118
118
|
EXTENSIONS_DIR="$HOME/.$CMD/extensions"
|
|
119
119
|
|
|
120
|
+
# 检测 openclaw 版本
|
|
121
|
+
OPENCLAW_VERSION="$($CMD --version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+(\.[0-9]+)?' | head -1 || true)"
|
|
122
|
+
|
|
120
123
|
echo "==========================================="
|
|
121
124
|
echo " qqbot 升级: $INSTALL_SRC"
|
|
125
|
+
echo " openclaw 版本: ${OPENCLAW_VERSION:-unknown}"
|
|
122
126
|
echo "==========================================="
|
|
123
127
|
echo ""
|
|
124
128
|
|
|
@@ -483,40 +483,33 @@ else
|
|
|
483
483
|
' 2>/dev/null || echo "unknown")
|
|
484
484
|
fi
|
|
485
485
|
|
|
486
|
-
# ──
|
|
487
|
-
#
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
486
|
+
# ── 暂不恢复 channels.qqbot 配置 ──
|
|
487
|
+
# openclaw 3.23+ 启动时在插件加载前就校验 channels,
|
|
488
|
+
# 如果此时恢复 channels.qqbot,gateway 会因 "unknown channel id: qqbot" 拒绝启动。
|
|
489
|
+
# 延迟到 gateway 启动、插件加载完成后再恢复(见 Step 6)。
|
|
490
|
+
echo " [兼容] channels.qqbot 将在 gateway 启动后恢复(避免启动校验失败)"
|
|
491
|
+
|
|
492
|
+
# ── Step 4/5:不在此时写入 channels.qqbot 配置 ──
|
|
493
|
+
# openclaw 3.23+ 在插件加载前校验 channels,此时写入 channels.qqbot 会导致
|
|
494
|
+
# "unknown channel id: qqbot" 错误。所有 channels.qqbot 相关配置延迟到
|
|
495
|
+
# gateway 启动、插件加载完成后统一写入(见 Step 6 末尾)。
|
|
496
|
+
#
|
|
497
|
+
# 这里只计算出 DESIRED_QQBOT_TOKEN 和 MARKDOWN_VALUE,不实际写入。
|
|
497
498
|
|
|
498
|
-
# 4.
|
|
499
|
+
# 4. 确定机器人通道配置
|
|
499
500
|
echo ""
|
|
500
|
-
echo "[4/6]
|
|
501
|
+
echo "[4/6] 准备机器人通道配置..."
|
|
501
502
|
|
|
502
|
-
# 读取当前 qqbot token
|
|
503
|
+
# 读取当前 qqbot token(从暂存或配置文件)
|
|
504
|
+
# 注意:channels.qqbot 已被暂存移除,所以从 _QQBOT_CHANNEL_STASH 读取
|
|
503
505
|
CURRENT_QQBOT_TOKEN=""
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
const ch = cfg.channels && cfg.channels[key];
|
|
512
|
-
if (!ch) continue;
|
|
513
|
-
if (ch.token) { process.stdout.write(ch.token); process.exit(0); }
|
|
514
|
-
if (ch.appId && ch.clientSecret) { process.stdout.write(ch.appId + ':' + ch.clientSecret); process.exit(0); }
|
|
515
|
-
}
|
|
516
|
-
" 2>/dev/null || true)
|
|
517
|
-
[ -n "$CURRENT_QQBOT_TOKEN" ] && break
|
|
518
|
-
fi
|
|
519
|
-
done
|
|
506
|
+
if [ -n "$_QQBOT_CHANNEL_STASH" ]; then
|
|
507
|
+
CURRENT_QQBOT_TOKEN=$(node -e "
|
|
508
|
+
const ch = $_QQBOT_CHANNEL_STASH;
|
|
509
|
+
if (ch.token) { process.stdout.write(ch.token); }
|
|
510
|
+
else if (ch.appId && ch.clientSecret) { process.stdout.write(ch.appId + ':' + ch.clientSecret); }
|
|
511
|
+
" 2>/dev/null || true)
|
|
512
|
+
fi
|
|
520
513
|
|
|
521
514
|
DESIRED_QQBOT_TOKEN=""
|
|
522
515
|
if [ -n "$APPID" ] && [ -n "$SECRET" ]; then
|
|
@@ -531,104 +524,40 @@ elif [ -n "$SAVED_QQBOT_TOKEN" ]; then
|
|
|
531
524
|
fi
|
|
532
525
|
|
|
533
526
|
if [ -n "$DESIRED_QQBOT_TOKEN" ]; then
|
|
534
|
-
echo "
|
|
535
|
-
echo "
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
527
|
+
echo "目标 Token: ${DESIRED_QQBOT_TOKEN:0:10}..."
|
|
528
|
+
echo " [兼容] 将在 gateway 启动后写入 channels.qqbot"
|
|
529
|
+
elif [ -z "$CURRENT_QQBOT_TOKEN" ] && [ -z "$_QQBOT_CHANNEL_STASH" ]; then
|
|
530
|
+
echo ""
|
|
531
|
+
echo "❌ 未检测到 qqbot 通道配置!"
|
|
532
|
+
echo ""
|
|
533
|
+
echo "首次运行请提供 appid 和 appsecret:"
|
|
534
|
+
echo ""
|
|
535
|
+
echo " bash $0 --appid <你的appid> --secret <你的appsecret>"
|
|
536
|
+
echo ""
|
|
537
|
+
echo "也可以通过环境变量:"
|
|
538
|
+
echo ""
|
|
539
|
+
echo " QQBOT_APPID=<appid> QQBOT_SECRET=<appsecret> bash $0"
|
|
540
|
+
echo ""
|
|
541
|
+
echo "appid 和 appsecret 可在 QQ 开放平台 (https://q.qq.com) 获取。"
|
|
542
|
+
exit 1
|
|
549
543
|
else
|
|
550
|
-
|
|
551
|
-
_has_channel=0
|
|
552
|
-
if [ -n "$CURRENT_QQBOT_TOKEN" ]; then
|
|
553
|
-
_has_channel=1
|
|
554
|
-
fi
|
|
555
|
-
|
|
556
|
-
if [ "$_has_channel" -eq 0 ]; then
|
|
557
|
-
echo ""
|
|
558
|
-
echo "❌ 未检测到 qqbot 通道配置!"
|
|
559
|
-
echo ""
|
|
560
|
-
echo "首次运行请提供 appid 和 appsecret:"
|
|
561
|
-
echo ""
|
|
562
|
-
echo " bash $0 --appid <你的appid> --secret <你的appsecret>"
|
|
563
|
-
echo ""
|
|
564
|
-
echo "也可以通过环境变量:"
|
|
565
|
-
echo ""
|
|
566
|
-
echo " QQBOT_APPID=<appid> QQBOT_SECRET=<appsecret> bash $0"
|
|
567
|
-
echo ""
|
|
568
|
-
echo "appid 和 appsecret 可在 QQ 开放平台 (https://q.qq.com) 获取。"
|
|
569
|
-
exit 1
|
|
570
|
-
else
|
|
571
|
-
echo "使用已有配置"
|
|
572
|
-
fi
|
|
544
|
+
echo "使用已有配置(暂存中)"
|
|
573
545
|
fi
|
|
574
546
|
|
|
575
|
-
# 5.
|
|
547
|
+
# 5. 确定 markdown 选项
|
|
576
548
|
echo ""
|
|
577
|
-
echo "[5/6]
|
|
549
|
+
echo "[5/6] 准备 markdown 配置..."
|
|
578
550
|
|
|
551
|
+
MARKDOWN_VALUE=""
|
|
579
552
|
if [ -n "$MARKDOWN" ]; then
|
|
580
|
-
# 设置 markdown 配置
|
|
581
553
|
if [ "$MARKDOWN" = "yes" ] || [ "$MARKDOWN" = "y" ] || [ "$MARKDOWN" = "true" ]; then
|
|
582
554
|
MARKDOWN_VALUE="true"
|
|
583
|
-
echo "
|
|
555
|
+
echo "将启用 markdown 消息格式"
|
|
584
556
|
else
|
|
585
557
|
MARKDOWN_VALUE="false"
|
|
586
|
-
echo "
|
|
587
|
-
fi
|
|
588
|
-
|
|
589
|
-
CURRENT_MARKDOWN_VALUE=$(node -e "
|
|
590
|
-
const fs = require('fs');
|
|
591
|
-
const path = require('path');
|
|
592
|
-
const home = process.env.HOME;
|
|
593
|
-
for (const app of ['openclaw', 'clawdbot', 'moltbot']) {
|
|
594
|
-
const f = path.join(home, '.' + app, app + '.json');
|
|
595
|
-
if (!fs.existsSync(f)) continue;
|
|
596
|
-
try {
|
|
597
|
-
const cfg = JSON.parse(fs.readFileSync(f, 'utf8'));
|
|
598
|
-
const keys = ['qqbot', 'openclaw-qqbot', 'openclaw-qq'];
|
|
599
|
-
for (const key of keys) {
|
|
600
|
-
const ch = cfg.channels && cfg.channels[key];
|
|
601
|
-
if (!ch) continue;
|
|
602
|
-
if (typeof ch.markdownSupport === 'boolean') { process.stdout.write(String(ch.markdownSupport)); process.exit(0); }
|
|
603
|
-
}
|
|
604
|
-
} catch {}
|
|
605
|
-
}
|
|
606
|
-
" 2>/dev/null || true)
|
|
607
|
-
|
|
608
|
-
if [ "$CURRENT_MARKDOWN_VALUE" = "$MARKDOWN_VALUE" ]; then
|
|
609
|
-
echo "✅ markdown 配置已是目标值,跳过写入(避免配置覆盖提示)"
|
|
610
|
-
elif openclaw config set channels.qqbot.markdownSupport "$MARKDOWN_VALUE" 2>&1; then
|
|
611
|
-
echo "✅ markdown配置成功"
|
|
612
|
-
_config_changed=1
|
|
613
|
-
else
|
|
614
|
-
echo "⚠️ openclaw config set 失败,尝试直接编辑配置文件..."
|
|
615
|
-
OPENCLAW_CONFIG="$HOME/.openclaw/openclaw.json"
|
|
616
|
-
if [ -f "$OPENCLAW_CONFIG" ] && node -e "
|
|
617
|
-
const fs = require('fs');
|
|
618
|
-
const cfg = JSON.parse(fs.readFileSync('$OPENCLAW_CONFIG', 'utf-8'));
|
|
619
|
-
if (!cfg.channels) cfg.channels = {};
|
|
620
|
-
if (!cfg.channels.qqbot) cfg.channels.qqbot = {};
|
|
621
|
-
const target = $MARKDOWN_VALUE;
|
|
622
|
-
if (cfg.channels.qqbot.markdownSupport === target) process.exit(0);
|
|
623
|
-
cfg.channels.qqbot.markdownSupport = target;
|
|
624
|
-
fs.writeFileSync('$OPENCLAW_CONFIG', JSON.stringify(cfg, null, 4) + '\n');
|
|
625
|
-
" 2>&1; then
|
|
626
|
-
echo "✅ markdown配置成功(直接编辑配置文件)"
|
|
627
|
-
_config_changed=1
|
|
628
|
-
else
|
|
629
|
-
echo "⚠️ markdown配置设置失败,不影响后续运行"
|
|
630
|
-
fi
|
|
558
|
+
echo "将禁用 markdown 消息格式(使用纯文本)"
|
|
631
559
|
fi
|
|
560
|
+
echo " [兼容] 将在 gateway 启动后写入配置"
|
|
632
561
|
else
|
|
633
562
|
echo "未指定 markdown 选项,使用已有配置"
|
|
634
563
|
fi
|
|
@@ -727,10 +656,70 @@ case "$start_choice" in
|
|
|
727
656
|
fi
|
|
728
657
|
fi
|
|
729
658
|
|
|
730
|
-
#
|
|
659
|
+
# 端口就绪后:恢复 channels.qqbot 配置 + 检查连接 + 跟踪日志
|
|
731
660
|
if [ "$_port_ready" -eq 1 ]; then
|
|
732
|
-
echo "✅ Gateway
|
|
661
|
+
echo "✅ Gateway 端口已就绪(插件已加载)"
|
|
733
662
|
echo ""
|
|
663
|
+
|
|
664
|
+
# ── 恢复 channels.qqbot 配置 ──
|
|
665
|
+
# gateway 已启动、插件已注册 qqbot channel,现在可以安全写回配置
|
|
666
|
+
_need_reload=0
|
|
667
|
+
_target_cfg=""
|
|
668
|
+
for _app in openclaw clawdbot moltbot; do
|
|
669
|
+
_cfg="$HOME/.$_app/$_app.json"
|
|
670
|
+
if [ -f "$_cfg" ]; then
|
|
671
|
+
_target_cfg="$_cfg"
|
|
672
|
+
break
|
|
673
|
+
fi
|
|
674
|
+
done
|
|
675
|
+
|
|
676
|
+
if [ -n "$_target_cfg" ]; then
|
|
677
|
+
# 构建完整的 channels.qqbot 对象(合并暂存配置 + 新 token + markdown)
|
|
678
|
+
node -e "
|
|
679
|
+
const fs = require('fs');
|
|
680
|
+
const cfg = JSON.parse(fs.readFileSync('$_target_cfg', 'utf8'));
|
|
681
|
+
if (!cfg.channels) cfg.channels = {};
|
|
682
|
+
|
|
683
|
+
// 从暂存恢复基础配置
|
|
684
|
+
const stash = '$_QQBOT_CHANNEL_STASH';
|
|
685
|
+
if (stash) {
|
|
686
|
+
try { cfg.channels.qqbot = JSON.parse(stash); } catch {}
|
|
687
|
+
}
|
|
688
|
+
if (!cfg.channels.qqbot) cfg.channels.qqbot = {};
|
|
689
|
+
|
|
690
|
+
// 覆盖 token(如果有新值)
|
|
691
|
+
const desired = '$DESIRED_QQBOT_TOKEN';
|
|
692
|
+
if (desired && desired.includes(':')) {
|
|
693
|
+
const [appId, ...rest] = desired.split(':');
|
|
694
|
+
cfg.channels.qqbot.appId = appId;
|
|
695
|
+
cfg.channels.qqbot.clientSecret = rest.join(':');
|
|
696
|
+
delete cfg.channels.qqbot.token;
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
// 覆盖 markdown(如果有指定)
|
|
700
|
+
const md = '$MARKDOWN_VALUE';
|
|
701
|
+
if (md === 'true') cfg.channels.qqbot.markdownSupport = true;
|
|
702
|
+
else if (md === 'false') cfg.channels.qqbot.markdownSupport = false;
|
|
703
|
+
|
|
704
|
+
fs.writeFileSync('$_target_cfg', JSON.stringify(cfg, null, 4) + '\n');
|
|
705
|
+
" 2>/dev/null || true
|
|
706
|
+
echo " ✅ 已恢复 channels.qqbot 配置(含 token/markdown)"
|
|
707
|
+
_need_reload=1
|
|
708
|
+
fi
|
|
709
|
+
|
|
710
|
+
# 配置写回后 reload gateway 使其生效
|
|
711
|
+
if [ "$_need_reload" -eq 1 ]; then
|
|
712
|
+
echo " 重载配置..."
|
|
713
|
+
sleep 1
|
|
714
|
+
openclaw gateway restart 2>/dev/null || true
|
|
715
|
+
# 等待重启后端口重新就绪
|
|
716
|
+
for _k in $(seq 1 15); do
|
|
717
|
+
if lsof -i :18789 -sTCP:LISTEN >/dev/null 2>&1; then
|
|
718
|
+
break
|
|
719
|
+
fi
|
|
720
|
+
sleep 2
|
|
721
|
+
done
|
|
722
|
+
fi
|
|
734
723
|
# 检查 qqbot WS 是否连接成功(最多等 20 秒)
|
|
735
724
|
echo "检查 qqbot 插件连接状态..."
|
|
736
725
|
_LOG_FILE="/tmp/openclaw/openclaw-$(date +%Y-%m-%d).log"
|
|
@@ -775,10 +764,27 @@ case "$start_choice" in
|
|
|
775
764
|
n|no)
|
|
776
765
|
echo ""
|
|
777
766
|
echo "✅ 插件更新完毕,未启动服务"
|
|
767
|
+
# 不启动时也需要恢复 channels.qqbot,否则配置丢失
|
|
768
|
+
# 注意:下次 gateway 启动可能因 "unknown channel id" 失败,
|
|
769
|
+
# 需要用户手动 stop → 移除 channels.qqbot → start → 恢复
|
|
770
|
+
if [ -n "$_QQBOT_CHANNEL_STASH" ] && [ -n "$_STASH_CFG" ] && [ -f "$_STASH_CFG" ]; then
|
|
771
|
+
node -e "
|
|
772
|
+
const fs = require('fs');
|
|
773
|
+
const cfg = JSON.parse(fs.readFileSync('$_STASH_CFG', 'utf8'));
|
|
774
|
+
if (!cfg.channels) cfg.channels = {};
|
|
775
|
+
cfg.channels.qqbot = $_QQBOT_CHANNEL_STASH;
|
|
776
|
+
fs.writeFileSync('$_STASH_CFG', JSON.stringify(cfg, null, 4) + '\n');
|
|
777
|
+
" 2>/dev/null || true
|
|
778
|
+
echo " 已恢复 channels.qqbot 配置"
|
|
779
|
+
fi
|
|
778
780
|
echo ""
|
|
779
|
-
echo "
|
|
780
|
-
echo "
|
|
781
|
-
echo "
|
|
781
|
+
echo "后续启动方法(兼容 openclaw 3.23+):"
|
|
782
|
+
echo " 1. 先临时移除 channels.qqbot 再启动:"
|
|
783
|
+
echo " openclaw gateway restart"
|
|
784
|
+
echo " 2. 或使用本脚本自动处理:"
|
|
785
|
+
echo " bash $0"
|
|
786
|
+
echo " 3. 跟踪日志:"
|
|
787
|
+
echo " openclaw logs --follow"
|
|
782
788
|
;;
|
|
783
789
|
*)
|
|
784
790
|
echo "无效选择,按默认值 y 执行后台重启"
|
package/src/gateway.ts
CHANGED
|
@@ -112,6 +112,21 @@ export async function startGateway(ctx: GatewayContext): Promise<void> {
|
|
|
112
112
|
}
|
|
113
113
|
}
|
|
114
114
|
|
|
115
|
+
// 预检 openclaw runtime 模块是否可正常解析(兼容性诊断)
|
|
116
|
+
// openclaw 3.23+ 存在 plugin-sdk/root-alias.cjs 回归 bug,
|
|
117
|
+
// 内置插件(qwen-portal-auth 等)全部加载失败,导致 AI agent 调用返回
|
|
118
|
+
// "Unable to resolve plugin runtime module"。提前检测并告警。
|
|
119
|
+
try {
|
|
120
|
+
const pluginRuntime = getQQBotRuntime();
|
|
121
|
+
if (pluginRuntime?.channel?.reply?.dispatchReplyWithBufferedBlockDispatcher) {
|
|
122
|
+
log?.info(`[qqbot:${account.accountId}] Runtime module preflight: OK`);
|
|
123
|
+
} else {
|
|
124
|
+
log?.error(`[qqbot:${account.accountId}] ⚠️ Runtime preflight: dispatchReply API 不可用,AI 消息处理可能失败。请检查 openclaw 版本兼容性`);
|
|
125
|
+
}
|
|
126
|
+
} catch (preflightErr) {
|
|
127
|
+
log?.error(`[qqbot:${account.accountId}] ⚠️ Runtime preflight failed: ${preflightErr}. AI 消息处理可能失败`);
|
|
128
|
+
}
|
|
129
|
+
|
|
115
130
|
// 后台版本检查(供 /bot-version、/bot-upgrade 指令被动查询)
|
|
116
131
|
triggerUpdateCheck(log);
|
|
117
132
|
|
|
@@ -1019,8 +1034,15 @@ export async function startGateway(ctx: GatewayContext): Promise<void> {
|
|
|
1019
1034
|
timeoutId = null;
|
|
1020
1035
|
}
|
|
1021
1036
|
|
|
1022
|
-
// 发送错误提示给用户,显示完整错误信息
|
|
1023
1037
|
const errMsg = String(err);
|
|
1038
|
+
|
|
1039
|
+
// 兼容 openclaw 3.23+ 的 plugin-sdk/root-alias.cjs 模块解析失败
|
|
1040
|
+
if (errMsg.includes("Unable to resolve plugin runtime module") || errMsg.includes("root-alias.cjs")) {
|
|
1041
|
+
log?.error(`[qqbot:${account.accountId}] ⚠️ openclaw 框架 runtime 模块解析失败,可能是 openclaw 版本与 plugin-sdk 不兼容。请尝试: npm install -g openclaw@latest && openclaw gateway restart`);
|
|
1042
|
+
await sendErrorMessage("⚠️ AI 服务暂时不可用:openclaw 框架运行时模块加载失败。\n\n请管理员执行:\nnpm install -g openclaw@latest\nopenclaw gateway restart\n\n斜杠命令(如 /bot-ping)不受影响。");
|
|
1043
|
+
return;
|
|
1044
|
+
}
|
|
1045
|
+
|
|
1024
1046
|
if (errMsg.includes("401") || errMsg.includes("key") || errMsg.includes("auth")) {
|
|
1025
1047
|
log?.error(`[qqbot:${account.accountId}] AI auth error: ${errMsg}`);
|
|
1026
1048
|
} else {
|
|
@@ -1062,7 +1084,14 @@ export async function startGateway(ctx: GatewayContext): Promise<void> {
|
|
|
1062
1084
|
}
|
|
1063
1085
|
}
|
|
1064
1086
|
} catch (err) {
|
|
1087
|
+
const errStr = String(err);
|
|
1065
1088
|
log?.error(`[qqbot:${account.accountId}] Message processing failed: ${err}`);
|
|
1089
|
+
// 兼容 openclaw 3.23+ runtime 模块解析失败:给用户发可操作的提示
|
|
1090
|
+
if (errStr.includes("Unable to resolve plugin runtime module") || errStr.includes("root-alias.cjs")) {
|
|
1091
|
+
try {
|
|
1092
|
+
await sendErrorMessage("⚠️ AI 服务暂时不可用:openclaw 框架运行时模块加载失败。\n\n请管理员执行:\nnpm install -g openclaw@latest\nopenclaw gateway restart\n\n斜杠命令(如 /bot-ping)不受影响。");
|
|
1093
|
+
} catch { /* best-effort */ }
|
|
1094
|
+
}
|
|
1066
1095
|
} finally {
|
|
1067
1096
|
// 无论成功/失败/超时,都停止输入状态续期
|
|
1068
1097
|
typing.keepAlive?.stop();
|
package/src/slash-commands.ts
CHANGED
|
@@ -830,7 +830,11 @@ function fireHotUpgrade(targetVersion?: string): HotUpgradeStartResult {
|
|
|
830
830
|
/**
|
|
831
831
|
* /bot-upgrade — 统一升级入口
|
|
832
832
|
*
|
|
833
|
-
*
|
|
833
|
+
* upgradeMode 开关:
|
|
834
|
+
* - "doc"(默认):只展示升级指引文档,不执行热更新
|
|
835
|
+
* - "hot-reload":执行 npm 升级脚本进行热更新
|
|
836
|
+
*
|
|
837
|
+
* 热更新模式下的产品流程:
|
|
834
838
|
* /bot-upgrade — 展示版本信息+确认按钮(不直接升级)
|
|
835
839
|
* /bot-upgrade --latest — 确认升级到最新版本
|
|
836
840
|
* /bot-upgrade --version X — 升级到指定版本
|
|
@@ -840,21 +844,54 @@ let _upgrading = false; // 升级锁
|
|
|
840
844
|
|
|
841
845
|
registerCommand({
|
|
842
846
|
name: "bot-upgrade",
|
|
843
|
-
description: "
|
|
847
|
+
description: "检查更新并查看升级指引",
|
|
844
848
|
usage: [
|
|
845
|
-
`/bot-upgrade
|
|
846
|
-
`/bot-upgrade --latest
|
|
847
|
-
`/bot-upgrade --version X
|
|
848
|
-
`/bot-upgrade --force
|
|
849
|
-
``,
|
|
850
|
-
`⚠️ 仅在私聊中可用。升级过程约 30~60 秒,期间服务短暂不可用。`,
|
|
851
|
-
``,
|
|
852
|
-
`环境要求:`,
|
|
853
|
-
` - 操作系统:macOS / Linux / Windows`,
|
|
854
|
-
` - OpenClaw 框架版本 ≥ ${UPGRADE_REQUIREMENTS.minFrameworkVersion}`,
|
|
855
|
-
` - Node.js ≥ v${UPGRADE_REQUIREMENTS.minNodeVersion}`,
|
|
849
|
+
`/bot-upgrade 检查是否有新版本`,
|
|
850
|
+
`/bot-upgrade --latest 确认升级到最新版本(需 upgradeMode=hot-reload)`,
|
|
851
|
+
`/bot-upgrade --version X 升级到指定版本(需 upgradeMode=hot-reload)`,
|
|
852
|
+
`/bot-upgrade --force 强制重新安装当前版本(需 upgradeMode=hot-reload)`,
|
|
856
853
|
].join("\n"),
|
|
857
854
|
handler: async (ctx) => {
|
|
855
|
+
const url = ctx.accountConfig?.upgradeUrl || DEFAULT_UPGRADE_URL;
|
|
856
|
+
const upgradeMode = ctx.accountConfig?.upgradeMode || "doc";
|
|
857
|
+
const args = ctx.args.trim();
|
|
858
|
+
const info = await getUpdateInfo();
|
|
859
|
+
|
|
860
|
+
const GITHUB_URL = "https://github.com/tencent-connect/openclaw-qqbot/";
|
|
861
|
+
|
|
862
|
+
// ── doc 模式(默认):只展示升级指引,不执行热更新 ──
|
|
863
|
+
if (upgradeMode !== "hot-reload") {
|
|
864
|
+
if (info.checkedAt === 0) {
|
|
865
|
+
return `⏳ 版本检查中,请稍后再试`;
|
|
866
|
+
}
|
|
867
|
+
if (info.error) {
|
|
868
|
+
return [
|
|
869
|
+
`❌ 主机网络访问异常,无法检查更新`,
|
|
870
|
+
``,
|
|
871
|
+
`查看升级指引:[点击查看](${url})`,
|
|
872
|
+
].join("\n");
|
|
873
|
+
}
|
|
874
|
+
if (!info.hasUpdate) {
|
|
875
|
+
return [
|
|
876
|
+
`✅ 当前已是最新版本 v${PLUGIN_VERSION}`,
|
|
877
|
+
``,
|
|
878
|
+
`项目地址:[GitHub](${GITHUB_URL})`,
|
|
879
|
+
].join("\n");
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
return [
|
|
883
|
+
`🆕 发现新版本`,
|
|
884
|
+
``,
|
|
885
|
+
`当前版本:**v${PLUGIN_VERSION}**`,
|
|
886
|
+
`最新版本:**v${info.latest}**`,
|
|
887
|
+
``,
|
|
888
|
+
`📖 升级指引:[点击查看](${url})`,
|
|
889
|
+
`🌟 官方 GitHub 仓库:[点击前往](${GITHUB_URL})`,
|
|
890
|
+
].join("\n");
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
// ── hot-reload 模式:执行热更新 ──
|
|
894
|
+
|
|
858
895
|
// 升级相关指令仅在私聊中可用
|
|
859
896
|
if (ctx.type !== "c2c") {
|
|
860
897
|
return `💡 请在私聊中使用此指令`;
|
|
@@ -865,10 +902,6 @@ registerCommand({
|
|
|
865
902
|
return `⏳ 正在升级中,请稍候...`;
|
|
866
903
|
}
|
|
867
904
|
|
|
868
|
-
const url = ctx.accountConfig?.upgradeUrl || DEFAULT_UPGRADE_URL;
|
|
869
|
-
const args = ctx.args.trim();
|
|
870
|
-
const info = await getUpdateInfo();
|
|
871
|
-
|
|
872
905
|
let isForce = false;
|
|
873
906
|
let isLatest = false;
|
|
874
907
|
let versionArg: string | undefined;
|
|
@@ -906,8 +939,6 @@ registerCommand({
|
|
|
906
939
|
}
|
|
907
940
|
}
|
|
908
941
|
|
|
909
|
-
const GITHUB_URL = "https://github.com/tencent-connect/openclaw-qqbot/";
|
|
910
|
-
|
|
911
942
|
// ── 无参数(也没有 --latest / --version / --force):只展示信息+确认按钮 ──
|
|
912
943
|
if (!versionArg && !isLatest && !isForce) {
|
|
913
944
|
if (info.checkedAt === 0) {
|
|
@@ -929,7 +960,7 @@ registerCommand({
|
|
|
929
960
|
return lines.join("\n");
|
|
930
961
|
}
|
|
931
962
|
|
|
932
|
-
// 有新版本:展示信息 +
|
|
963
|
+
// 有新版本:展示信息 + 确认按钮
|
|
933
964
|
return [
|
|
934
965
|
`🆕 发现新版本`,
|
|
935
966
|
``,
|