@ryantest/openclaw-qqbot 0.0.3 → 1.6.6-alpha.0
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/README.md +2 -15
- package/README.zh.md +3 -16
- package/dist/src/admin-resolver.d.ts +12 -6
- package/dist/src/admin-resolver.js +69 -34
- package/dist/src/api.d.ts +105 -1
- package/dist/src/api.js +164 -15
- package/dist/src/channel.js +13 -0
- package/dist/src/config.js +3 -10
- package/dist/src/deliver-debounce.d.ts +74 -0
- package/dist/src/deliver-debounce.js +174 -0
- package/dist/src/gateway.js +450 -248
- package/dist/src/image-server.d.ts +27 -8
- package/dist/src/image-server.js +179 -71
- package/dist/src/inbound-attachments.d.ts +3 -1
- package/dist/src/inbound-attachments.js +28 -14
- package/dist/src/outbound-deliver.js +77 -148
- package/dist/src/outbound.d.ts +6 -4
- package/dist/src/outbound.js +266 -442
- package/dist/src/reply-dispatcher.js +4 -4
- package/dist/src/request-context.d.ts +18 -0
- package/dist/src/request-context.js +30 -0
- package/dist/src/slash-commands.js +277 -32
- package/dist/src/startup-greeting.d.ts +5 -5
- package/dist/src/startup-greeting.js +32 -13
- package/dist/src/streaming.d.ts +244 -0
- package/dist/src/streaming.js +907 -0
- package/dist/src/tools/remind.js +11 -10
- package/dist/src/types.d.ts +101 -0
- package/dist/src/types.js +17 -1
- package/dist/src/update-checker.js +2 -8
- package/dist/src/utils/audio-convert.d.ts +9 -0
- package/dist/src/utils/audio-convert.js +51 -0
- package/dist/src/utils/chunked-upload.d.ts +59 -0
- package/dist/src/utils/chunked-upload.js +289 -0
- package/dist/src/utils/file-utils.d.ts +7 -1
- package/dist/src/utils/file-utils.js +24 -2
- package/dist/src/utils/media-send.d.ts +147 -0
- package/dist/src/utils/media-send.js +434 -0
- package/dist/src/utils/pkg-version.d.ts +5 -0
- package/dist/src/utils/pkg-version.js +51 -0
- package/dist/src/utils/ssrf-guard.d.ts +25 -0
- package/dist/src/utils/ssrf-guard.js +91 -0
- package/node_modules/ws/index.js +15 -6
- package/node_modules/ws/lib/permessage-deflate.js +6 -6
- package/node_modules/ws/lib/websocket-server.js +5 -5
- package/node_modules/ws/lib/websocket.js +6 -6
- package/node_modules/ws/package.json +4 -3
- package/node_modules/ws/wrapper.mjs +14 -1
- package/openclaw.plugin.json +1 -0
- package/package.json +11 -22
- package/scripts/postinstall-link-sdk.js +113 -0
- package/scripts/upgrade-via-npm.ps1 +161 -6
- package/scripts/upgrade-via-npm.sh +311 -104
- package/scripts/upgrade-via-source.sh +117 -0
- package/skills/qqbot-media/SKILL.md +9 -5
- package/skills/qqbot-remind/SKILL.md +3 -3
- package/src/admin-resolver.ts +76 -35
- package/src/api.ts +284 -12
- package/src/channel.ts +12 -0
- package/src/config.ts +3 -10
- package/src/deliver-debounce.ts +229 -0
- package/src/gateway.ts +277 -67
- package/src/image-server.ts +213 -77
- package/src/inbound-attachments.ts +32 -15
- package/src/outbound-deliver.ts +77 -157
- package/src/outbound.ts +304 -451
- package/src/reply-dispatcher.ts +4 -4
- package/src/request-context.ts +39 -0
- package/src/slash-commands.ts +303 -33
- package/src/startup-greeting.ts +35 -13
- package/src/streaming.ts +1096 -0
- package/src/tools/remind.ts +15 -11
- package/src/types.ts +111 -0
- package/src/update-checker.ts +2 -7
- package/src/utils/audio-convert.ts +56 -0
- package/src/utils/chunked-upload.ts +419 -0
- package/src/utils/file-utils.ts +28 -2
- package/src/utils/media-send.ts +563 -0
- package/src/utils/pkg-version.ts +54 -0
- package/src/utils/ssrf-guard.ts +102 -0
- package/clawdbot.plugin.json +0 -16
- package/dist/src/user-messages.d.ts +0 -8
- package/dist/src/user-messages.js +0 -8
- package/moltbot.plugin.json +0 -16
- package/scripts/upgrade-via-alt-pkg.sh +0 -307
- package/src/bot-logs-2026-03-21T11-21-47(2).txt +0 -46
- package/src/gateway.log +0 -43
- package/src/openclaw-2026-03-21.log +0 -3729
- package/src/user-messages.ts +0 -7
|
@@ -1,24 +1,30 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
2
|
|
|
3
|
-
# qqbot 通过
|
|
3
|
+
# qqbot 通过 openclaw 原生插件指令升级
|
|
4
4
|
#
|
|
5
|
-
#
|
|
6
|
-
#
|
|
7
|
-
#
|
|
5
|
+
# 使用 openclaw plugins install/update 原生命令进行安装和升级,
|
|
6
|
+
# 保留 appid/secret 配置写入、热更新 (--no-restart)、结构化输出等功能。
|
|
7
|
+
#
|
|
8
|
+
# 升级策略:
|
|
9
|
+
# 1. 已安装(plugins.installs 有记录)→ openclaw plugins update
|
|
10
|
+
# 2. 未安装 / update 失败 → 删除旧目录 + openclaw plugins install
|
|
8
11
|
#
|
|
9
12
|
# 用法:
|
|
10
13
|
# upgrade-via-npm.sh # 升级到 latest(默认)
|
|
11
14
|
# upgrade-via-npm.sh --version <version> # 升级到指定版本
|
|
12
15
|
# upgrade-via-npm.sh --self-version # 升级到当前仓库 package.json 版本
|
|
13
16
|
# upgrade-via-npm.sh --appid <appid> --secret <secret> # 首次安装时配置 appid/secret
|
|
14
|
-
# upgrade-via-npm.sh --no-restart
|
|
17
|
+
# upgrade-via-npm.sh --no-restart # 只做文件替换,不重启 gateway(供热更指令使用)
|
|
15
18
|
|
|
16
19
|
set -eo pipefail
|
|
17
20
|
|
|
18
21
|
PKG_NAME="@tencent-connect/openclaw-qqbot"
|
|
22
|
+
PLUGIN_ID="openclaw-qqbot"
|
|
19
23
|
INSTALL_SRC=""
|
|
24
|
+
TARGET_VERSION=""
|
|
20
25
|
APPID=""
|
|
21
26
|
SECRET=""
|
|
27
|
+
STREAMING=""
|
|
22
28
|
NO_RESTART=false
|
|
23
29
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
24
30
|
PROJECT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
@@ -45,6 +51,7 @@ print_usage() {
|
|
|
45
51
|
echo ""
|
|
46
52
|
echo " --appid <appid> QQ机器人 appid(首次安装时必填)"
|
|
47
53
|
echo " --secret <secret> QQ机器人 secret(首次安装时必填)"
|
|
54
|
+
echo " --streaming <yes|no> 是否启用流式消息(默认: no,仅 C2C 私聊)"
|
|
48
55
|
echo ""
|
|
49
56
|
echo "也可以通过环境变量设置:"
|
|
50
57
|
echo " QQBOT_APPID QQ机器人 appid"
|
|
@@ -56,16 +63,19 @@ while [[ $# -gt 0 ]]; do
|
|
|
56
63
|
case "$1" in
|
|
57
64
|
--tag)
|
|
58
65
|
[ -z "$2" ] && echo "❌ --tag 需要参数" && exit 1
|
|
66
|
+
TARGET_VERSION="$2"
|
|
59
67
|
INSTALL_SRC="${PKG_NAME}@$2"
|
|
60
68
|
shift 2
|
|
61
69
|
;;
|
|
62
70
|
--version)
|
|
63
71
|
[ -z "$2" ] && echo "❌ --version 需要参数" && exit 1
|
|
72
|
+
TARGET_VERSION="$2"
|
|
64
73
|
INSTALL_SRC="${PKG_NAME}@$2"
|
|
65
74
|
shift 2
|
|
66
75
|
;;
|
|
67
76
|
--self-version)
|
|
68
77
|
[ -z "$LOCAL_VERSION" ] && echo "❌ 无法从 package.json 读取版本" && exit 1
|
|
78
|
+
TARGET_VERSION="$LOCAL_VERSION"
|
|
69
79
|
INSTALL_SRC="${PKG_NAME}@${LOCAL_VERSION}"
|
|
70
80
|
shift 1
|
|
71
81
|
;;
|
|
@@ -79,6 +89,11 @@ while [[ $# -gt 0 ]]; do
|
|
|
79
89
|
SECRET="$2"
|
|
80
90
|
shift 2
|
|
81
91
|
;;
|
|
92
|
+
--streaming)
|
|
93
|
+
[ -z "$2" ] && echo "❌ --streaming 需要参数" && exit 1
|
|
94
|
+
STREAMING="$2"
|
|
95
|
+
shift 2
|
|
96
|
+
;;
|
|
82
97
|
--no-restart)
|
|
83
98
|
NO_RESTART=true
|
|
84
99
|
shift 1
|
|
@@ -100,7 +115,7 @@ if [ -z "$APPID" ] && [ -z "$SECRET" ] && [ -n "$QQBOT_TOKEN" ]; then
|
|
|
100
115
|
SECRET="${QQBOT_TOKEN#*:}"
|
|
101
116
|
fi
|
|
102
117
|
|
|
103
|
-
# 检测 CLI
|
|
118
|
+
# 检测 CLI
|
|
104
119
|
CMD=""
|
|
105
120
|
for name in openclaw clawdbot moltbot; do
|
|
106
121
|
command -v "$name" &>/dev/null && CMD="$name" && break
|
|
@@ -109,113 +124,267 @@ done
|
|
|
109
124
|
|
|
110
125
|
EXTENSIONS_DIR="$HOME/.$CMD/extensions"
|
|
111
126
|
|
|
127
|
+
# 检测 openclaw 版本
|
|
128
|
+
OPENCLAW_VERSION="$($CMD --version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+(\.[0-9]+)?' | head -1 || true)"
|
|
129
|
+
|
|
112
130
|
echo "==========================================="
|
|
113
|
-
echo " qqbot
|
|
131
|
+
echo " qqbot 升级: $INSTALL_SRC"
|
|
132
|
+
echo " openclaw 版本: ${OPENCLAW_VERSION:-unknown}"
|
|
114
133
|
echo "==========================================="
|
|
115
134
|
echo ""
|
|
116
135
|
|
|
117
|
-
#
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
136
|
+
# 记录升级前的版本
|
|
137
|
+
OLD_VERSION=""
|
|
138
|
+
OLD_PKG="$EXTENSIONS_DIR/$PLUGIN_ID/package.json"
|
|
139
|
+
if [ -f "$OLD_PKG" ]; then
|
|
140
|
+
OLD_VERSION="$(node -e "
|
|
141
|
+
try {
|
|
142
|
+
const v = JSON.parse(require('fs').readFileSync('$OLD_PKG', 'utf8')).version;
|
|
143
|
+
if (v) process.stdout.write(String(v));
|
|
144
|
+
} catch {}
|
|
145
|
+
" 2>/dev/null || true)"
|
|
146
|
+
echo " 当前版本: ${OLD_VERSION:-unknown}"
|
|
147
|
+
fi
|
|
148
|
+
|
|
149
|
+
# [1/4] 通过 openclaw 原生指令安装/升级
|
|
150
|
+
echo ""
|
|
151
|
+
echo "[1/4] 安装/升级插件..."
|
|
152
|
+
|
|
153
|
+
# ── 兼容 openclaw 3.23+ 配置严格校验 ──
|
|
154
|
+
# 3.23+ 在 plugins install/update 时会校验整个配置文件,
|
|
155
|
+
# 如果 channels.qqbot 已存在但 qqbot 插件尚未加载,校验会失败。
|
|
156
|
+
# 解决:install/update 前临时移除 channels.qqbot,成功后恢复。
|
|
157
|
+
CONFIG_FILE="$HOME/.$CMD/$CMD.json"
|
|
158
|
+
QQBOT_CHANNEL_BACKUP=""
|
|
159
|
+
if [ -f "$CONFIG_FILE" ]; then
|
|
160
|
+
QQBOT_CHANNEL_BACKUP="$(node -e "
|
|
161
|
+
try {
|
|
162
|
+
const fs = require('fs');
|
|
163
|
+
const cfg = JSON.parse(fs.readFileSync('$CONFIG_FILE', 'utf8'));
|
|
164
|
+
if (cfg.channels && cfg.channels.qqbot) {
|
|
165
|
+
process.stdout.write(JSON.stringify(cfg.channels.qqbot));
|
|
166
|
+
delete cfg.channels.qqbot;
|
|
167
|
+
if (Object.keys(cfg.channels).length === 0) delete cfg.channels;
|
|
168
|
+
fs.writeFileSync('$CONFIG_FILE', JSON.stringify(cfg, null, 4) + '\n');
|
|
169
|
+
}
|
|
170
|
+
} catch {}
|
|
171
|
+
" 2>/dev/null || true)"
|
|
172
|
+
if [ -n "$QQBOT_CHANNEL_BACKUP" ]; then
|
|
173
|
+
echo " [兼容] 临时移除 channels.qqbot 以通过配置校验"
|
|
133
174
|
fi
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
#
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
175
|
+
fi
|
|
176
|
+
|
|
177
|
+
# 恢复 channels.qqbot 的函数(install/update 完成后调用)
|
|
178
|
+
restore_qqbot_channel() {
|
|
179
|
+
if [ -n "$QQBOT_CHANNEL_BACKUP" ] && [ -f "$CONFIG_FILE" ]; then
|
|
180
|
+
node -e "
|
|
181
|
+
try {
|
|
182
|
+
const fs = require('fs');
|
|
183
|
+
const cfg = JSON.parse(fs.readFileSync('$CONFIG_FILE', 'utf8'));
|
|
184
|
+
if (!cfg.channels) cfg.channels = {};
|
|
185
|
+
cfg.channels.qqbot = $QQBOT_CHANNEL_BACKUP;
|
|
186
|
+
fs.writeFileSync('$CONFIG_FILE', JSON.stringify(cfg, null, 4) + '\n');
|
|
187
|
+
} catch {}
|
|
188
|
+
" 2>/dev/null || true
|
|
189
|
+
echo " [兼容] 已恢复 channels.qqbot 配置"
|
|
190
|
+
fi
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
UPGRADE_OK=false
|
|
194
|
+
|
|
195
|
+
# 检测安装状态:同时检查配置记录和磁盘目录
|
|
196
|
+
HAS_INSTALL_RECORD="$(node -e "
|
|
197
|
+
try {
|
|
198
|
+
const fs = require('fs');
|
|
199
|
+
const p = '$HOME/.$CMD/$CMD.json';
|
|
200
|
+
const cfg = JSON.parse(fs.readFileSync(p, 'utf8'));
|
|
201
|
+
const inst = cfg.plugins && cfg.plugins.installs && cfg.plugins.installs['$PLUGIN_ID'];
|
|
202
|
+
if (inst) process.stdout.write('yes');
|
|
203
|
+
} catch {}
|
|
204
|
+
" 2>/dev/null || true)"
|
|
205
|
+
HAS_PLUGIN_DIR=false
|
|
206
|
+
[ -d "$EXTENSIONS_DIR/$PLUGIN_ID" ] && [ -f "$EXTENSIONS_DIR/$PLUGIN_ID/package.json" ] && HAS_PLUGIN_DIR=true
|
|
207
|
+
|
|
208
|
+
# 决策矩阵:
|
|
209
|
+
# 配置有记录 + 目录存在 → update(最佳路径)
|
|
210
|
+
# 配置有记录 + 目录不存在 → 清理残留记录,走 install
|
|
211
|
+
# 配置无记录 + 目录存在 → 删目录,走 install(配置与文件不一致)
|
|
212
|
+
# 配置无记录 + 目录不存在 → 走 install(全新安装)
|
|
213
|
+
#
|
|
214
|
+
# 指定了具体版本(--version/--tag/--self-version)时:
|
|
215
|
+
# update 不支持指定版本,直接走 删除 + install
|
|
216
|
+
|
|
217
|
+
USE_UPDATE=false
|
|
218
|
+
|
|
219
|
+
if [ "$HAS_INSTALL_RECORD" = "yes" ] && [ "$HAS_PLUGIN_DIR" = "true" ] && [ -z "$TARGET_VERSION" ]; then
|
|
220
|
+
# 配置和目录都齐全,且未指定版本 → 走 update
|
|
221
|
+
USE_UPDATE=true
|
|
222
|
+
echo " [检测] 配置记录 ✓ | 插件目录 ✓ | 未指定版本 → 使用 update"
|
|
223
|
+
elif [ "$HAS_INSTALL_RECORD" = "yes" ] && [ "$HAS_PLUGIN_DIR" = "true" ]; then
|
|
224
|
+
echo " [检测] 配置记录 ✓ | 插件目录 ✓ | 指定版本 $TARGET_VERSION → 使用 reinstall"
|
|
225
|
+
elif [ "$HAS_INSTALL_RECORD" = "yes" ]; then
|
|
226
|
+
echo " [检测] 配置记录 ✓ | 插件目录 ✗ → 配置与文件不一致,使用 install"
|
|
227
|
+
elif [ "$HAS_PLUGIN_DIR" = "true" ]; then
|
|
228
|
+
echo " [检测] 配置记录 ✗ | 插件目录 ✓ → 目录残留,清理后 install"
|
|
158
229
|
else
|
|
159
|
-
echo "
|
|
160
|
-
NPM_TMP_CACHE=$(mktemp -d)
|
|
161
|
-
(cd "$STAGING_DIR" && npm install --omit=dev --omit=peer --ignore-scripts --cache="$NPM_TMP_CACHE" --quiet 2>&1) || echo " ⚠️ 依赖安装失败"
|
|
162
|
-
rm -rf "$NPM_TMP_CACHE"
|
|
230
|
+
echo " [检测] 配置记录 ✗ | 插件目录 ✗ → 全新安装"
|
|
163
231
|
fi
|
|
164
232
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
233
|
+
if [ "$USE_UPDATE" = "true" ]; then
|
|
234
|
+
echo " 尝试 update..."
|
|
235
|
+
if $CMD plugins update "$PLUGIN_ID" 2>&1; then
|
|
236
|
+
UPGRADE_OK=true
|
|
237
|
+
echo " ✅ update 成功"
|
|
238
|
+
else
|
|
239
|
+
echo " ⚠️ update 失败,回退到 reinstall..."
|
|
240
|
+
fi
|
|
241
|
+
fi
|
|
242
|
+
|
|
243
|
+
if [ "$UPGRADE_OK" != "true" ]; then
|
|
244
|
+
# 备份旧目录(而非直接删除),install 失败时可回滚
|
|
245
|
+
BACKUP_DIR=""
|
|
246
|
+
if [ -d "$EXTENSIONS_DIR/$PLUGIN_ID" ]; then
|
|
247
|
+
BACKUP_DIR="$EXTENSIONS_DIR/.openclaw-qqbot-backup-$$"
|
|
248
|
+
mv "$EXTENSIONS_DIR/$PLUGIN_ID" "$BACKUP_DIR"
|
|
249
|
+
echo " 已备份旧目录: $BACKUP_DIR"
|
|
250
|
+
fi
|
|
168
251
|
|
|
169
|
-
#
|
|
170
|
-
|
|
252
|
+
# 清理历史遗留名称(这些不需要回滚)
|
|
253
|
+
for dir_name in qqbot openclaw-qq; do
|
|
254
|
+
[ -d "$EXTENSIONS_DIR/$dir_name" ] && rm -rf "$EXTENSIONS_DIR/$dir_name" && echo " 已清理历史目录: $EXTENSIONS_DIR/$dir_name"
|
|
255
|
+
done
|
|
256
|
+
|
|
257
|
+
echo " 执行 install: $INSTALL_SRC"
|
|
258
|
+
if $CMD plugins install "$INSTALL_SRC" --pin 2>&1; then
|
|
259
|
+
UPGRADE_OK=true
|
|
260
|
+
echo " ✅ install 成功"
|
|
261
|
+
# install 成功,清理备份
|
|
262
|
+
if [ -n "$BACKUP_DIR" ] && [ -d "$BACKUP_DIR" ]; then
|
|
263
|
+
rm -rf "$BACKUP_DIR"
|
|
264
|
+
echo " 已清理旧版备份"
|
|
265
|
+
fi
|
|
266
|
+
# 清理 openclaw CLI install 可能留下的额外 backup 目录
|
|
267
|
+
find "$EXTENSIONS_DIR" -maxdepth 1 -name ".openclaw-qqbot-backup-*" -exec rm -rf {} + 2>/dev/null || true
|
|
268
|
+
else
|
|
269
|
+
echo " ❌ install 失败"
|
|
270
|
+
# 回滚:恢复旧目录
|
|
271
|
+
if [ -n "$BACKUP_DIR" ] && [ -d "$BACKUP_DIR" ]; then
|
|
272
|
+
mv "$BACKUP_DIR" "$EXTENSIONS_DIR/$PLUGIN_ID"
|
|
273
|
+
echo " ↩️ 已回滚到旧版本"
|
|
274
|
+
fi
|
|
275
|
+
restore_qqbot_channel
|
|
276
|
+
echo "QQBOT_NEW_VERSION=unknown"
|
|
277
|
+
echo "QQBOT_REPORT=❌ QQBot 安装失败(已回滚到旧版本),请检查网络和 npm registry"
|
|
278
|
+
exit 1
|
|
279
|
+
fi
|
|
280
|
+
fi
|
|
281
|
+
|
|
282
|
+
# install/update 完成,恢复 channels.qqbot
|
|
283
|
+
restore_qqbot_channel
|
|
284
|
+
|
|
285
|
+
# [2/4] 验证安装
|
|
171
286
|
echo ""
|
|
172
|
-
echo "[2/
|
|
173
|
-
TARGET_DIR="$EXTENSIONS_DIR/openclaw-qqbot"
|
|
174
|
-
OLD_DIR="$(dirname "$EXTENSIONS_DIR")/.qqbot-upgrade-old"
|
|
287
|
+
echo "[2/4] 验证安装..."
|
|
175
288
|
|
|
176
|
-
|
|
289
|
+
PKG_JSON="$EXTENSIONS_DIR/$PLUGIN_ID/package.json"
|
|
290
|
+
if [ -f "$PKG_JSON" ]; then
|
|
291
|
+
NEW_VERSION="$(node -e "process.stdout.write(JSON.parse(require('fs').readFileSync(process.argv[1],'utf8')).version||'')" "$PKG_JSON" 2>/dev/null || true)"
|
|
292
|
+
fi
|
|
177
293
|
|
|
178
|
-
#
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
mv "$STAGING_DIR" "$STAGING_IN_EXT"
|
|
294
|
+
# Preflight 检查
|
|
295
|
+
PREFLIGHT_OK=true
|
|
296
|
+
TARGET_DIR="$EXTENSIONS_DIR/$PLUGIN_ID"
|
|
182
297
|
|
|
183
|
-
if [ -
|
|
184
|
-
|
|
185
|
-
|
|
298
|
+
if [ -z "$NEW_VERSION" ]; then
|
|
299
|
+
echo " ❌ 无法读取新版本号"
|
|
300
|
+
PREFLIGHT_OK=false
|
|
186
301
|
else
|
|
187
|
-
|
|
302
|
+
echo " ✅ 版本号: $NEW_VERSION"
|
|
188
303
|
fi
|
|
189
|
-
rm -rf "$OLD_DIR"
|
|
190
304
|
|
|
191
|
-
#
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
305
|
+
# 入口文件
|
|
306
|
+
ENTRY_FILE=""
|
|
307
|
+
for candidate in "dist/index.js" "index.js"; do
|
|
308
|
+
if [ -f "$TARGET_DIR/$candidate" ]; then
|
|
309
|
+
ENTRY_FILE="$candidate"
|
|
310
|
+
break
|
|
311
|
+
fi
|
|
312
|
+
done
|
|
313
|
+
if [ -z "$ENTRY_FILE" ]; then
|
|
314
|
+
echo " ❌ 缺少入口文件(dist/index.js 或 index.js)"
|
|
315
|
+
PREFLIGHT_OK=false
|
|
316
|
+
else
|
|
317
|
+
echo " ✅ 入口文件: $ENTRY_FILE"
|
|
318
|
+
fi
|
|
195
319
|
|
|
196
|
-
#
|
|
197
|
-
|
|
198
|
-
|
|
320
|
+
# 核心目录
|
|
321
|
+
if [ -d "$TARGET_DIR/dist/src" ]; then
|
|
322
|
+
CORE_JS_COUNT=$(find "$TARGET_DIR/dist/src" -name "*.js" -type f 2>/dev/null | wc -l | tr -d ' ')
|
|
323
|
+
echo " ✅ dist/src/ 包含 ${CORE_JS_COUNT} 个 JS 文件"
|
|
324
|
+
if [ "$CORE_JS_COUNT" -lt 5 ]; then
|
|
325
|
+
echo " ❌ JS 文件数量异常偏少(预期 ≥ 5,实际 ${CORE_JS_COUNT})"
|
|
326
|
+
PREFLIGHT_OK=false
|
|
327
|
+
fi
|
|
328
|
+
else
|
|
329
|
+
echo " ❌ 缺少核心目录 dist/src/"
|
|
330
|
+
PREFLIGHT_OK=false
|
|
331
|
+
fi
|
|
332
|
+
|
|
333
|
+
# 关键模块
|
|
334
|
+
MISSING_MODULES=""
|
|
335
|
+
for module in "dist/src/gateway.js" "dist/src/api.js" "dist/src/admin-resolver.js"; do
|
|
336
|
+
if [ ! -f "$TARGET_DIR/$module" ]; then
|
|
337
|
+
MISSING_MODULES="$MISSING_MODULES $module"
|
|
338
|
+
fi
|
|
199
339
|
done
|
|
200
|
-
|
|
340
|
+
if [ -n "$MISSING_MODULES" ]; then
|
|
341
|
+
echo " ❌ 缺少关键模块:$MISSING_MODULES"
|
|
342
|
+
PREFLIGHT_OK=false
|
|
343
|
+
else
|
|
344
|
+
echo " ✅ 关键模块完整"
|
|
345
|
+
fi
|
|
346
|
+
|
|
347
|
+
# bundled 依赖
|
|
348
|
+
if [ -d "$TARGET_DIR/node_modules" ]; then
|
|
349
|
+
BUNDLED_OK=true
|
|
350
|
+
for dep in "ws" "silk-wasm"; do
|
|
351
|
+
if [ ! -d "$TARGET_DIR/node_modules/$dep" ]; then
|
|
352
|
+
echo " ⚠️ bundled 依赖缺失: $dep"
|
|
353
|
+
BUNDLED_OK=false
|
|
354
|
+
fi
|
|
355
|
+
done
|
|
356
|
+
if $BUNDLED_OK; then
|
|
357
|
+
echo " ✅ 核心 bundled 依赖完整"
|
|
358
|
+
fi
|
|
359
|
+
fi
|
|
360
|
+
|
|
361
|
+
if [ "$PREFLIGHT_OK" != "true" ]; then
|
|
362
|
+
echo ""
|
|
363
|
+
echo "❌ 验证未通过"
|
|
364
|
+
echo "QQBOT_NEW_VERSION=unknown"
|
|
365
|
+
echo "QQBOT_REPORT=⚠️ QQBot 升级异常,验证未通过"
|
|
366
|
+
exit 1
|
|
367
|
+
fi
|
|
368
|
+
echo " ✅ 验证全部通过"
|
|
369
|
+
|
|
370
|
+
# 确保 openclaw/plugin-sdk 可解析:
|
|
371
|
+
# openclaw plugins install 不会执行 npm lifecycle scripts,
|
|
372
|
+
# 需要手动调用 postinstall-link-sdk.js 创建 node_modules/openclaw → 全局 openclaw 的符号链接
|
|
373
|
+
POSTINSTALL_SCRIPT="$TARGET_DIR/scripts/postinstall-link-sdk.js"
|
|
374
|
+
if [ -f "$POSTINSTALL_SCRIPT" ]; then
|
|
375
|
+
echo " 执行 postinstall-link-sdk..."
|
|
376
|
+
if node "$POSTINSTALL_SCRIPT" 2>&1; then
|
|
377
|
+
echo " ✅ plugin-sdk 链接就绪"
|
|
378
|
+
else
|
|
379
|
+
echo " ⚠️ postinstall-link-sdk 失败,插件可能无法加载"
|
|
380
|
+
fi
|
|
381
|
+
fi
|
|
201
382
|
|
|
202
|
-
# [3/
|
|
383
|
+
# [3/4] 输出结构化信息(供 TS handler 解析)
|
|
203
384
|
echo ""
|
|
204
|
-
echo "[3/
|
|
205
|
-
NEW_VERSION="$(node -e "
|
|
206
|
-
try {
|
|
207
|
-
const fs = require('fs');
|
|
208
|
-
const path = require('path');
|
|
209
|
-
const p = path.join('$EXTENSIONS_DIR', 'openclaw-qqbot', 'package.json');
|
|
210
|
-
if (fs.existsSync(p)) {
|
|
211
|
-
const v = JSON.parse(fs.readFileSync(p, 'utf8')).version;
|
|
212
|
-
if (v) { process.stdout.write(v); process.exit(0); }
|
|
213
|
-
}
|
|
214
|
-
} catch {}
|
|
215
|
-
" 2>/dev/null || true)"
|
|
385
|
+
echo "[3/4] 升级结果..."
|
|
216
386
|
echo "QQBOT_NEW_VERSION=${NEW_VERSION:-unknown}"
|
|
217
387
|
|
|
218
|
-
# 输出结构化升级报告(QQBOT_REPORT=...),供 TS handler 解析后直接回复用户
|
|
219
388
|
if [ -n "$NEW_VERSION" ] && [ "$NEW_VERSION" != "unknown" ]; then
|
|
220
389
|
echo "QQBOT_REPORT=✅ QQBot 升级完成: v${NEW_VERSION}"
|
|
221
390
|
else
|
|
@@ -224,13 +393,10 @@ fi
|
|
|
224
393
|
|
|
225
394
|
echo ""
|
|
226
395
|
echo "==========================================="
|
|
227
|
-
echo " ✅
|
|
396
|
+
echo " ✅ 安装完成"
|
|
228
397
|
echo "==========================================="
|
|
229
398
|
|
|
230
|
-
# --no-restart
|
|
231
|
-
# 让调用方尽快触发 gateway restart,避免 openclaw 配置轮询
|
|
232
|
-
# 在旧进程中检测到插件变更产生 "plugin not found" warning 刷屏。
|
|
233
|
-
# appid/secret 配置在热更新场景下已经存在,无需重新写入。
|
|
399
|
+
# --no-restart 模式(热更新场景):立即退出,让调用方触发 gateway restart
|
|
234
400
|
if [ "$NO_RESTART" = "true" ]; then
|
|
235
401
|
echo ""
|
|
236
402
|
echo "[跳过重启] --no-restart 已指定,脚本立即退出以便调用方触发 gateway restart"
|
|
@@ -239,7 +405,7 @@ fi
|
|
|
239
405
|
|
|
240
406
|
# 以下步骤仅在非热更新(手动执行)场景中执行
|
|
241
407
|
|
|
242
|
-
# [
|
|
408
|
+
# [配置] appid/secret(仅在提供了参数时执行)
|
|
243
409
|
if [ -n "$APPID" ] && [ -n "$SECRET" ]; then
|
|
244
410
|
echo ""
|
|
245
411
|
echo "[配置] 写入 qqbot 通道配置..."
|
|
@@ -266,10 +432,9 @@ if [ -n "$APPID" ] && [ -n "$SECRET" ]; then
|
|
|
266
432
|
|
|
267
433
|
if [ "$CURRENT_TOKEN" = "$DESIRED_TOKEN" ]; then
|
|
268
434
|
echo " ✅ 当前配置已是目标值,跳过写入"
|
|
269
|
-
elif $CMD channels add --channel qqbot --token "$DESIRED_TOKEN" 2>&1; then
|
|
270
|
-
echo " ✅ 通道配置写入成功"
|
|
271
435
|
else
|
|
272
|
-
|
|
436
|
+
# qqbot 是插件自定义通道,openclaw channels add --channel 不支持,
|
|
437
|
+
# 直接编辑配置文件写入 channels.qqbot
|
|
273
438
|
CONFIG_FILE="$HOME/.$CMD/$CMD.json"
|
|
274
439
|
if [ -f "$CONFIG_FILE" ] && node -e "
|
|
275
440
|
const fs = require('fs');
|
|
@@ -280,10 +445,10 @@ if [ -n "$APPID" ] && [ -n "$SECRET" ]; then
|
|
|
280
445
|
cfg.channels.qqbot.clientSecret = '$SECRET';
|
|
281
446
|
fs.writeFileSync('$CONFIG_FILE', JSON.stringify(cfg, null, 4) + '\n');
|
|
282
447
|
" 2>&1; then
|
|
283
|
-
echo " ✅
|
|
448
|
+
echo " ✅ 通道配置写入成功"
|
|
284
449
|
else
|
|
285
|
-
echo " ❌
|
|
286
|
-
echo "
|
|
450
|
+
echo " ❌ 配置写入失败,请手动编辑 $CONFIG_FILE 添加 channels.qqbot:"
|
|
451
|
+
echo " { \"channels\": { \"qqbot\": { \"appId\": \"$APPID\", \"clientSecret\": \"...\" } } }"
|
|
287
452
|
fi
|
|
288
453
|
fi
|
|
289
454
|
elif [ -n "$APPID" ] || [ -n "$SECRET" ]; then
|
|
@@ -291,11 +456,53 @@ elif [ -n "$APPID" ] || [ -n "$SECRET" ]; then
|
|
|
291
456
|
echo "⚠️ --appid 和 --secret 必须同时提供"
|
|
292
457
|
fi
|
|
293
458
|
|
|
294
|
-
# [
|
|
459
|
+
# [配置] streaming(流式消息)
|
|
460
|
+
if [ -n "$STREAMING" ]; then
|
|
461
|
+
echo ""
|
|
462
|
+
echo "[配置] 写入 streaming(流式消息)配置..."
|
|
463
|
+
STREAMING_VALUE=""
|
|
464
|
+
if [ "$STREAMING" = "yes" ] || [ "$STREAMING" = "y" ] || [ "$STREAMING" = "true" ]; then
|
|
465
|
+
STREAMING_VALUE="true"
|
|
466
|
+
else
|
|
467
|
+
STREAMING_VALUE="false"
|
|
468
|
+
fi
|
|
469
|
+
|
|
470
|
+
CONFIG_FILE="$HOME/.$CMD/$CMD.json"
|
|
471
|
+
if [ -f "$CONFIG_FILE" ] && node -e "
|
|
472
|
+
const fs = require('fs');
|
|
473
|
+
const cfg = JSON.parse(fs.readFileSync('$CONFIG_FILE', 'utf8'));
|
|
474
|
+
if (!cfg.channels) cfg.channels = {};
|
|
475
|
+
if (!cfg.channels.qqbot) cfg.channels.qqbot = {};
|
|
476
|
+
const target = $STREAMING_VALUE;
|
|
477
|
+
if (cfg.channels.qqbot.streaming === target) process.exit(0);
|
|
478
|
+
cfg.channels.qqbot.streaming = target;
|
|
479
|
+
fs.writeFileSync('$CONFIG_FILE', JSON.stringify(cfg, null, 4) + '\n');
|
|
480
|
+
" 2>&1; then
|
|
481
|
+
echo " ✅ streaming 配置写入成功 (streaming=$STREAMING_VALUE)"
|
|
482
|
+
else
|
|
483
|
+
echo " ⚠️ streaming 配置写入失败,不影响后续运行"
|
|
484
|
+
fi
|
|
485
|
+
fi
|
|
486
|
+
|
|
487
|
+
# [4/4] 重启 gateway 使新版本生效
|
|
295
488
|
echo ""
|
|
489
|
+
|
|
490
|
+
# 手动升级场景:提前写入 startup-marker,阻止重启后 bot 重复推送升级通知
|
|
491
|
+
if [ -n "$NEW_VERSION" ] && [ "$NEW_VERSION" != "unknown" ]; then
|
|
492
|
+
MARKER_DIR="$HOME/.openclaw/qqbot/data"
|
|
493
|
+
mkdir -p "$MARKER_DIR"
|
|
494
|
+
MARKER_FILE="$MARKER_DIR/startup-marker.json"
|
|
495
|
+
NOW="$(date -u +%Y-%m-%dT%H:%M:%S.000Z 2>/dev/null || date +%Y-%m-%dT%H:%M:%SZ)"
|
|
496
|
+
echo "{\"version\":\"$NEW_VERSION\",\"startedAt\":\"$NOW\",\"greetedAt\":\"$NOW\"}" > "$MARKER_FILE"
|
|
497
|
+
fi
|
|
498
|
+
|
|
296
499
|
echo "[重启] 重启 gateway 使新版本生效..."
|
|
297
500
|
if $CMD gateway restart 2>&1; then
|
|
298
501
|
echo " ✅ gateway 已重启"
|
|
502
|
+
echo ""
|
|
503
|
+
if [ -n "$NEW_VERSION" ] && [ "$NEW_VERSION" != "unknown" ]; then
|
|
504
|
+
echo "🎉 QQBot 插件已更新至 v${NEW_VERSION},在线等候你的吩咐。"
|
|
505
|
+
fi
|
|
299
506
|
else
|
|
300
507
|
echo " ⚠️ gateway 重启失败,请手动执行: $CMD gateway restart"
|
|
301
508
|
fi
|