@tencent-connect/openclaw-qqbot 1.6.5-alpha.3 → 1.6.5-alpha.4
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/package.json +6 -2
- package/scripts/upgrade-via-npm.sh +142 -189
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tencent-connect/openclaw-qqbot",
|
|
3
|
-
"version": "1.6.5-alpha.
|
|
3
|
+
"version": "1.6.5-alpha.4",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -22,7 +22,11 @@
|
|
|
22
22
|
"id": "openclaw-qqbot",
|
|
23
23
|
"extensions": [
|
|
24
24
|
"./dist/index.js"
|
|
25
|
-
]
|
|
25
|
+
],
|
|
26
|
+
"channel": {
|
|
27
|
+
"id": "qqbot",
|
|
28
|
+
"label": "QQ Bot"
|
|
29
|
+
}
|
|
26
30
|
},
|
|
27
31
|
"scripts": {
|
|
28
32
|
"build": "tsc || true",
|
|
@@ -1,22 +1,27 @@
|
|
|
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=""
|
|
22
27
|
NO_RESTART=false
|
|
@@ -56,16 +61,19 @@ while [[ $# -gt 0 ]]; do
|
|
|
56
61
|
case "$1" in
|
|
57
62
|
--tag)
|
|
58
63
|
[ -z "$2" ] && echo "❌ --tag 需要参数" && exit 1
|
|
64
|
+
TARGET_VERSION="$2"
|
|
59
65
|
INSTALL_SRC="${PKG_NAME}@$2"
|
|
60
66
|
shift 2
|
|
61
67
|
;;
|
|
62
68
|
--version)
|
|
63
69
|
[ -z "$2" ] && echo "❌ --version 需要参数" && exit 1
|
|
70
|
+
TARGET_VERSION="$2"
|
|
64
71
|
INSTALL_SRC="${PKG_NAME}@$2"
|
|
65
72
|
shift 2
|
|
66
73
|
;;
|
|
67
74
|
--self-version)
|
|
68
75
|
[ -z "$LOCAL_VERSION" ] && echo "❌ 无法从 package.json 读取版本" && exit 1
|
|
76
|
+
TARGET_VERSION="$LOCAL_VERSION"
|
|
69
77
|
INSTALL_SRC="${PKG_NAME}@${LOCAL_VERSION}"
|
|
70
78
|
shift 1
|
|
71
79
|
;;
|
|
@@ -100,7 +108,7 @@ if [ -z "$APPID" ] && [ -z "$SECRET" ] && [ -n "$QQBOT_TOKEN" ]; then
|
|
|
100
108
|
SECRET="${QQBOT_TOKEN#*:}"
|
|
101
109
|
fi
|
|
102
110
|
|
|
103
|
-
# 检测 CLI
|
|
111
|
+
# 检测 CLI
|
|
104
112
|
CMD=""
|
|
105
113
|
for name in openclaw clawdbot moltbot; do
|
|
106
114
|
command -v "$name" &>/dev/null && CMD="$name" && break
|
|
@@ -110,91 +118,126 @@ done
|
|
|
110
118
|
EXTENSIONS_DIR="$HOME/.$CMD/extensions"
|
|
111
119
|
|
|
112
120
|
echo "==========================================="
|
|
113
|
-
echo " qqbot
|
|
121
|
+
echo " qqbot 升级: $INSTALL_SRC"
|
|
114
122
|
echo "==========================================="
|
|
115
123
|
echo ""
|
|
116
124
|
|
|
117
|
-
#
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
125
|
+
# 记录升级前的版本
|
|
126
|
+
OLD_VERSION=""
|
|
127
|
+
OLD_PKG="$EXTENSIONS_DIR/$PLUGIN_ID/package.json"
|
|
128
|
+
if [ -f "$OLD_PKG" ]; then
|
|
129
|
+
OLD_VERSION="$(node -e "
|
|
130
|
+
try {
|
|
131
|
+
const v = JSON.parse(require('fs').readFileSync('$OLD_PKG', 'utf8')).version;
|
|
132
|
+
if (v) process.stdout.write(String(v));
|
|
133
|
+
} catch {}
|
|
134
|
+
" 2>/dev/null || true)"
|
|
135
|
+
echo " 当前版本: ${OLD_VERSION:-unknown}"
|
|
136
|
+
fi
|
|
137
|
+
|
|
138
|
+
# [1/4] 通过 openclaw 原生指令安装/升级
|
|
139
|
+
echo ""
|
|
140
|
+
echo "[1/4] 安装/升级插件..."
|
|
141
|
+
|
|
142
|
+
UPGRADE_OK=false
|
|
143
|
+
|
|
144
|
+
# 检测安装状态:同时检查配置记录和磁盘目录
|
|
145
|
+
HAS_INSTALL_RECORD="$(node -e "
|
|
146
|
+
try {
|
|
147
|
+
const fs = require('fs');
|
|
148
|
+
const p = '$HOME/.$CMD/$CMD.json';
|
|
149
|
+
const cfg = JSON.parse(fs.readFileSync(p, 'utf8'));
|
|
150
|
+
const inst = cfg.plugins && cfg.plugins.installs && cfg.plugins.installs['$PLUGIN_ID'];
|
|
151
|
+
if (inst) process.stdout.write('yes');
|
|
152
|
+
} catch {}
|
|
153
|
+
" 2>/dev/null || true)"
|
|
154
|
+
HAS_PLUGIN_DIR=false
|
|
155
|
+
[ -d "$EXTENSIONS_DIR/$PLUGIN_ID" ] && [ -f "$EXTENSIONS_DIR/$PLUGIN_ID/package.json" ] && HAS_PLUGIN_DIR=true
|
|
156
|
+
|
|
157
|
+
# 决策矩阵:
|
|
158
|
+
# 配置有记录 + 目录存在 → update(最佳路径)
|
|
159
|
+
# 配置有记录 + 目录不存在 → 清理残留记录,走 install
|
|
160
|
+
# 配置无记录 + 目录存在 → 删目录,走 install(配置与文件不一致)
|
|
161
|
+
# 配置无记录 + 目录不存在 → 走 install(全新安装)
|
|
162
|
+
#
|
|
163
|
+
# 指定了具体版本(--version/--tag/--self-version)时:
|
|
164
|
+
# update 不支持指定版本,直接走 删除 + install
|
|
165
|
+
|
|
166
|
+
USE_UPDATE=false
|
|
167
|
+
|
|
168
|
+
if [ "$HAS_INSTALL_RECORD" = "yes" ] && [ "$HAS_PLUGIN_DIR" = "true" ] && [ -z "$TARGET_VERSION" ]; then
|
|
169
|
+
# 配置和目录都齐全,且未指定版本 → 走 update
|
|
170
|
+
USE_UPDATE=true
|
|
171
|
+
echo " [检测] 配置记录 ✓ | 插件目录 ✓ | 未指定版本 → 使用 update"
|
|
172
|
+
elif [ "$HAS_INSTALL_RECORD" = "yes" ] && [ "$HAS_PLUGIN_DIR" = "true" ]; then
|
|
173
|
+
echo " [检测] 配置记录 ✓ | 插件目录 ✓ | 指定版本 $TARGET_VERSION → 使用 reinstall"
|
|
174
|
+
elif [ "$HAS_INSTALL_RECORD" = "yes" ]; then
|
|
175
|
+
echo " [检测] 配置记录 ✓ | 插件目录 ✗ → 配置与文件不一致,使用 install"
|
|
176
|
+
elif [ "$HAS_PLUGIN_DIR" = "true" ]; then
|
|
177
|
+
echo " [检测] 配置记录 ✗ | 插件目录 ✓ → 目录残留,清理后 install"
|
|
178
|
+
else
|
|
179
|
+
echo " [检测] 配置记录 ✗ | 插件目录 ✗ → 全新安装"
|
|
180
|
+
fi
|
|
181
|
+
|
|
182
|
+
if [ "$USE_UPDATE" = "true" ]; then
|
|
183
|
+
echo " 尝试 update..."
|
|
184
|
+
if $CMD plugins update "$PLUGIN_ID" 2>&1; then
|
|
185
|
+
UPGRADE_OK=true
|
|
186
|
+
echo " ✅ update 成功"
|
|
130
187
|
else
|
|
131
|
-
echo "
|
|
132
|
-
npm pack "$INSTALL_SRC" --quiet 2>&1 && PACK_OK=true && break
|
|
188
|
+
echo " ⚠️ update 失败,回退到 reinstall..."
|
|
133
189
|
fi
|
|
134
|
-
done
|
|
135
|
-
$PACK_OK || { echo "❌ npm pack 失败(所有 registry 均不可用)"; exit 1; }
|
|
136
|
-
TGZ_FILE=$(ls -1 *.tgz 2>/dev/null | head -1)
|
|
137
|
-
[ -z "$TGZ_FILE" ] && echo "❌ 未找到下载的 tgz 文件" && exit 1
|
|
138
|
-
echo " 已下载: $TGZ_FILE"
|
|
139
|
-
|
|
140
|
-
tar xzf "$TGZ_FILE" -C "$EXTRACT_DIR"
|
|
141
|
-
PACKAGE_DIR="$EXTRACT_DIR/package"
|
|
142
|
-
[ ! -d "$PACKAGE_DIR" ] && echo "❌ 解压失败,未找到 package 目录" && exit 1
|
|
143
|
-
|
|
144
|
-
# 准备 staging 目录:放在 ~/.openclaw/ 下(extensions 的父目录),
|
|
145
|
-
# 同一文件系统保证 mv 原子操作,同时避免 OpenClaw 扫描 extensions/ 时发现它。
|
|
146
|
-
STAGING_DIR="$(dirname "$EXTENSIONS_DIR")/.qqbot-upgrade-staging"
|
|
147
|
-
rm -rf "$STAGING_DIR"
|
|
148
|
-
mkdir -p "$STAGING_DIR"
|
|
149
|
-
cp -R "$PACKAGE_DIR/"* "$STAGING_DIR/"
|
|
150
|
-
|
|
151
|
-
# 依赖处理:所有 production dependencies 都声明为 bundledDependencies,
|
|
152
|
-
# npm pack 时已打包进 tgz,解压后 node_modules/ 已包含全部依赖,无需 npm install。
|
|
153
|
-
# 注意:不能执行 npm install,否则会安装 peerDependencies(openclaw 平台及其 400+ 传递依赖),
|
|
154
|
-
# 导致插件目录膨胀到 900MB+,而这些依赖在运行时由宿主 openclaw 提供。
|
|
155
|
-
if [ -d "$STAGING_DIR/node_modules" ]; then
|
|
156
|
-
BUNDLED_COUNT=$(ls -d "$STAGING_DIR/node_modules"/*/ "$STAGING_DIR/node_modules"/@*/*/ 2>/dev/null | wc -l | tr -d ' ')
|
|
157
|
-
echo " bundled 依赖已就绪(${BUNDLED_COUNT} 个包)"
|
|
158
|
-
else
|
|
159
|
-
echo " ⚠️ 未找到 bundled node_modules,尝试安装依赖..."
|
|
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"
|
|
163
190
|
fi
|
|
164
191
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
192
|
+
if [ "$UPGRADE_OK" != "true" ]; then
|
|
193
|
+
# 清理旧目录(包含当前插件和历史遗留名称)
|
|
194
|
+
for dir_name in "$PLUGIN_ID" qqbot openclaw-qq; do
|
|
195
|
+
[ -d "$EXTENSIONS_DIR/$dir_name" ] && rm -rf "$EXTENSIONS_DIR/$dir_name" && echo " 已清理: $EXTENSIONS_DIR/$dir_name"
|
|
196
|
+
done
|
|
197
|
+
|
|
198
|
+
echo " 执行 install: $INSTALL_SRC"
|
|
199
|
+
if $CMD plugins install "$INSTALL_SRC" --pin 2>&1; then
|
|
200
|
+
UPGRADE_OK=true
|
|
201
|
+
echo " ✅ install 成功"
|
|
202
|
+
else
|
|
203
|
+
echo "❌ install 失败"
|
|
204
|
+
echo "QQBOT_NEW_VERSION=unknown"
|
|
205
|
+
echo "QQBOT_REPORT=❌ QQBot 安装失败,请检查网络和 npm registry"
|
|
206
|
+
exit 1
|
|
207
|
+
fi
|
|
208
|
+
fi
|
|
168
209
|
|
|
169
|
-
#
|
|
210
|
+
# [2/4] 验证安装
|
|
170
211
|
echo ""
|
|
171
|
-
echo "[2/
|
|
212
|
+
echo "[2/4] 验证安装..."
|
|
213
|
+
|
|
214
|
+
NEW_VERSION="$(node -e "
|
|
215
|
+
try {
|
|
216
|
+
const fs = require('fs');
|
|
217
|
+
const path = require('path');
|
|
218
|
+
const p = path.join('$EXTENSIONS_DIR', '$PLUGIN_ID', 'package.json');
|
|
219
|
+
if (fs.existsSync(p)) {
|
|
220
|
+
const v = JSON.parse(fs.readFileSync(p, 'utf8')).version;
|
|
221
|
+
if (v) { process.stdout.write(v); process.exit(0); }
|
|
222
|
+
}
|
|
223
|
+
} catch {}
|
|
224
|
+
" 2>/dev/null || true)"
|
|
225
|
+
|
|
226
|
+
# Preflight 检查
|
|
172
227
|
PREFLIGHT_OK=true
|
|
228
|
+
TARGET_DIR="$EXTENSIONS_DIR/$PLUGIN_ID"
|
|
173
229
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
if [ ! -f "$STAGING_PKG" ]; then
|
|
177
|
-
echo " ❌ 新包缺少 package.json"
|
|
230
|
+
if [ -z "$NEW_VERSION" ]; then
|
|
231
|
+
echo " ❌ 无法读取新版本号"
|
|
178
232
|
PREFLIGHT_OK=false
|
|
179
233
|
else
|
|
180
|
-
|
|
181
|
-
try {
|
|
182
|
-
const v = JSON.parse(require('fs').readFileSync('$STAGING_PKG', 'utf8')).version;
|
|
183
|
-
if (v) process.stdout.write(String(v));
|
|
184
|
-
} catch {}
|
|
185
|
-
" 2>/dev/null || true)"
|
|
186
|
-
if [ -z "$STAGING_VERSION" ]; then
|
|
187
|
-
echo " ❌ package.json 无法解析或缺少 version 字段"
|
|
188
|
-
PREFLIGHT_OK=false
|
|
189
|
-
else
|
|
190
|
-
echo " ✅ 版本号: $STAGING_VERSION"
|
|
191
|
-
fi
|
|
234
|
+
echo " ✅ 版本号: $NEW_VERSION"
|
|
192
235
|
fi
|
|
193
236
|
|
|
194
|
-
#
|
|
237
|
+
# 入口文件
|
|
195
238
|
ENTRY_FILE=""
|
|
196
239
|
for candidate in "dist/index.js" "index.js"; do
|
|
197
|
-
if [ -f "$
|
|
240
|
+
if [ -f "$TARGET_DIR/$candidate" ]; then
|
|
198
241
|
ENTRY_FILE="$candidate"
|
|
199
242
|
break
|
|
200
243
|
fi
|
|
@@ -206,23 +249,23 @@ else
|
|
|
206
249
|
echo " ✅ 入口文件: $ENTRY_FILE"
|
|
207
250
|
fi
|
|
208
251
|
|
|
209
|
-
#
|
|
210
|
-
if [
|
|
211
|
-
|
|
212
|
-
PREFLIGHT_OK=false
|
|
213
|
-
else
|
|
214
|
-
CORE_JS_COUNT=$(find "$STAGING_DIR/dist/src" -name "*.js" -type f 2>/dev/null | wc -l | tr -d ' ')
|
|
252
|
+
# 核心目录
|
|
253
|
+
if [ -d "$TARGET_DIR/dist/src" ]; then
|
|
254
|
+
CORE_JS_COUNT=$(find "$TARGET_DIR/dist/src" -name "*.js" -type f 2>/dev/null | wc -l | tr -d ' ')
|
|
215
255
|
echo " ✅ dist/src/ 包含 ${CORE_JS_COUNT} 个 JS 文件"
|
|
216
256
|
if [ "$CORE_JS_COUNT" -lt 5 ]; then
|
|
217
257
|
echo " ❌ JS 文件数量异常偏少(预期 ≥ 5,实际 ${CORE_JS_COUNT})"
|
|
218
258
|
PREFLIGHT_OK=false
|
|
219
259
|
fi
|
|
260
|
+
else
|
|
261
|
+
echo " ❌ 缺少核心目录 dist/src/"
|
|
262
|
+
PREFLIGHT_OK=false
|
|
220
263
|
fi
|
|
221
264
|
|
|
222
|
-
#
|
|
265
|
+
# 关键模块
|
|
223
266
|
MISSING_MODULES=""
|
|
224
267
|
for module in "dist/src/gateway.js" "dist/src/api.js" "dist/src/admin-resolver.js"; do
|
|
225
|
-
if [ ! -f "$
|
|
268
|
+
if [ ! -f "$TARGET_DIR/$module" ]; then
|
|
226
269
|
MISSING_MODULES="$MISSING_MODULES $module"
|
|
227
270
|
fi
|
|
228
271
|
done
|
|
@@ -233,11 +276,11 @@ else
|
|
|
233
276
|
echo " ✅ 关键模块完整"
|
|
234
277
|
fi
|
|
235
278
|
|
|
236
|
-
#
|
|
237
|
-
if [ -d "$
|
|
279
|
+
# bundled 依赖
|
|
280
|
+
if [ -d "$TARGET_DIR/node_modules" ]; then
|
|
238
281
|
BUNDLED_OK=true
|
|
239
282
|
for dep in "ws" "silk-wasm"; do
|
|
240
|
-
if [ ! -d "$
|
|
283
|
+
if [ ! -d "$TARGET_DIR/node_modules/$dep" ]; then
|
|
241
284
|
echo " ⚠️ bundled 依赖缺失: $dep"
|
|
242
285
|
BUNDLED_OK=false
|
|
243
286
|
fi
|
|
@@ -247,104 +290,20 @@ if [ -d "$STAGING_DIR/node_modules" ]; then
|
|
|
247
290
|
fi
|
|
248
291
|
fi
|
|
249
292
|
|
|
250
|
-
# (f) 如果有旧版本,检查新版本是否合理(不允许降级到 0.x 等异常版本)
|
|
251
|
-
if [ -n "$STAGING_VERSION" ]; then
|
|
252
|
-
STAGING_MAJOR="$(echo "$STAGING_VERSION" | cut -d. -f1)"
|
|
253
|
-
if [ "$STAGING_MAJOR" = "0" ]; then
|
|
254
|
-
echo " ⚠️ 新版本主版本号为 0($STAGING_VERSION),可能不是正式发布版"
|
|
255
|
-
fi
|
|
256
|
-
fi
|
|
257
|
-
|
|
258
|
-
# 检查结果
|
|
259
293
|
if [ "$PREFLIGHT_OK" != "true" ]; then
|
|
260
294
|
echo ""
|
|
261
|
-
echo "❌
|
|
262
|
-
|
|
295
|
+
echo "❌ 验证未通过"
|
|
296
|
+
echo "QQBOT_NEW_VERSION=unknown"
|
|
297
|
+
echo "QQBOT_REPORT=⚠️ QQBot 升级异常,验证未通过"
|
|
263
298
|
exit 1
|
|
264
299
|
fi
|
|
265
|
-
echo " ✅
|
|
300
|
+
echo " ✅ 验证全部通过"
|
|
266
301
|
|
|
267
|
-
# [3/
|
|
268
|
-
# 策略:先把 staging 放到 extensions/ 同级的临时名,再做单次 mv 替换
|
|
302
|
+
# [3/4] 输出结构化信息(供 TS handler 解析)
|
|
269
303
|
echo ""
|
|
270
|
-
echo "[3/
|
|
271
|
-
mkdir -p "$EXTENSIONS_DIR"
|
|
272
|
-
TARGET_DIR="$EXTENSIONS_DIR/openclaw-qqbot"
|
|
273
|
-
OLD_DIR="$(dirname "$EXTENSIONS_DIR")/.qqbot-upgrade-old"
|
|
274
|
-
|
|
275
|
-
rm -rf "$OLD_DIR"
|
|
276
|
-
|
|
277
|
-
# 先把 staging 目录移到 extensions/ 下的临时位置(同文件系统,确保 mv 是 rename 操作)
|
|
278
|
-
STAGING_IN_EXT="$EXTENSIONS_DIR/.openclaw-qqbot-new"
|
|
279
|
-
rm -rf "$STAGING_IN_EXT"
|
|
280
|
-
mv "$STAGING_DIR" "$STAGING_IN_EXT"
|
|
281
|
-
|
|
282
|
-
if [ -d "$TARGET_DIR" ]; then
|
|
283
|
-
# 使用连续两个 mv 但中间零操作,最小化目录不存在的时间窗口
|
|
284
|
-
mv "$TARGET_DIR" "$OLD_DIR" && mv "$STAGING_IN_EXT" "$TARGET_DIR"
|
|
285
|
-
else
|
|
286
|
-
mv "$STAGING_IN_EXT" "$TARGET_DIR"
|
|
287
|
-
fi
|
|
288
|
-
rm -rf "$OLD_DIR"
|
|
289
|
-
|
|
290
|
-
# 清理可能残留的旧版 staging 目录(extensions 内外都清理)
|
|
291
|
-
rm -rf "$EXTENSIONS_DIR/openclaw-qqbot.staging"
|
|
292
|
-
rm -rf "$EXTENSIONS_DIR/.qqbot-upgrade-staging"
|
|
293
|
-
rm -rf "$EXTENSIONS_DIR/.qqbot-upgrade-old"
|
|
294
|
-
|
|
295
|
-
# 同时清理历史遗留的其他目录名
|
|
296
|
-
for dir_name in qqbot openclaw-qq; do
|
|
297
|
-
[ -d "$EXTENSIONS_DIR/$dir_name" ] && rm -rf "$EXTENSIONS_DIR/$dir_name"
|
|
298
|
-
done
|
|
299
|
-
echo " 已安装到: $TARGET_DIR"
|
|
300
|
-
|
|
301
|
-
# 执行 postinstall 脚本创建 openclaw SDK symlink
|
|
302
|
-
# (upgrade-via-npm 是纯文件操作,不走 npm install,所以 postinstall 不会自动触发)
|
|
303
|
-
POSTINSTALL_SCRIPT="$TARGET_DIR/scripts/postinstall-link-sdk.js"
|
|
304
|
-
if [ -f "$POSTINSTALL_SCRIPT" ]; then
|
|
305
|
-
echo " 执行 postinstall: 创建 openclaw SDK symlink..."
|
|
306
|
-
POSTINSTALL_OUTPUT="$(cd "$TARGET_DIR" && node "$POSTINSTALL_SCRIPT" 2>&1)" || true
|
|
307
|
-
[ -n "$POSTINSTALL_OUTPUT" ] && echo " $POSTINSTALL_OUTPUT"
|
|
308
|
-
# 验证 symlink 是否创建成功
|
|
309
|
-
if [ -d "$TARGET_DIR/node_modules/openclaw" ]; then
|
|
310
|
-
echo " ✅ openclaw SDK symlink 已就绪"
|
|
311
|
-
else
|
|
312
|
-
echo " ⚠️ openclaw SDK symlink 未创建,插件可能无法加载"
|
|
313
|
-
echo " 尝试手动创建 symlink..."
|
|
314
|
-
# 手动 fallback:尝试从 CLI 数据目录名推断全局包名
|
|
315
|
-
_CLI_DATA_DIR="$(dirname "$EXTENSIONS_DIR")"
|
|
316
|
-
_CLI_NAME="$(basename "$_CLI_DATA_DIR" | sed 's/^\.//')"
|
|
317
|
-
_GLOBAL_ROOT="$(npm root -g 2>/dev/null || true)"
|
|
318
|
-
if [ -n "$_GLOBAL_ROOT" ] && [ -n "$_CLI_NAME" ] && [ -d "$_GLOBAL_ROOT/$_CLI_NAME" ]; then
|
|
319
|
-
mkdir -p "$TARGET_DIR/node_modules"
|
|
320
|
-
ln -sf "$_GLOBAL_ROOT/$_CLI_NAME" "$TARGET_DIR/node_modules/openclaw" 2>/dev/null && \
|
|
321
|
-
echo " ✅ 手动 symlink 创建成功: -> $_GLOBAL_ROOT/$_CLI_NAME" || \
|
|
322
|
-
echo " ❌ 手动 symlink 创建也失败了"
|
|
323
|
-
else
|
|
324
|
-
echo " ❌ 无法定位全局 $_CLI_NAME 安装路径(npm root -g: $_GLOBAL_ROOT)"
|
|
325
|
-
fi
|
|
326
|
-
fi
|
|
327
|
-
else
|
|
328
|
-
echo " ⚠️ 未找到 postinstall 脚本,跳过 symlink 创建"
|
|
329
|
-
fi
|
|
330
|
-
|
|
331
|
-
# [4/5] 输出新版本号和升级报告(供调用方解析)
|
|
332
|
-
echo ""
|
|
333
|
-
echo "[4/5] 验证安装..."
|
|
334
|
-
NEW_VERSION="$(node -e "
|
|
335
|
-
try {
|
|
336
|
-
const fs = require('fs');
|
|
337
|
-
const path = require('path');
|
|
338
|
-
const p = path.join('$EXTENSIONS_DIR', 'openclaw-qqbot', 'package.json');
|
|
339
|
-
if (fs.existsSync(p)) {
|
|
340
|
-
const v = JSON.parse(fs.readFileSync(p, 'utf8')).version;
|
|
341
|
-
if (v) { process.stdout.write(v); process.exit(0); }
|
|
342
|
-
}
|
|
343
|
-
} catch {}
|
|
344
|
-
" 2>/dev/null || true)"
|
|
304
|
+
echo "[3/4] 升级结果..."
|
|
345
305
|
echo "QQBOT_NEW_VERSION=${NEW_VERSION:-unknown}"
|
|
346
306
|
|
|
347
|
-
# 输出结构化升级报告(QQBOT_REPORT=...),供 TS handler 解析后直接回复用户
|
|
348
307
|
if [ -n "$NEW_VERSION" ] && [ "$NEW_VERSION" != "unknown" ]; then
|
|
349
308
|
echo "QQBOT_REPORT=✅ QQBot 升级完成: v${NEW_VERSION}"
|
|
350
309
|
else
|
|
@@ -353,13 +312,10 @@ fi
|
|
|
353
312
|
|
|
354
313
|
echo ""
|
|
355
314
|
echo "==========================================="
|
|
356
|
-
echo " ✅
|
|
315
|
+
echo " ✅ 安装完成"
|
|
357
316
|
echo "==========================================="
|
|
358
317
|
|
|
359
|
-
# --no-restart
|
|
360
|
-
# 让调用方尽快触发 gateway restart,避免 openclaw 配置轮询
|
|
361
|
-
# 在旧进程中检测到插件变更产生 "plugin not found" warning 刷屏。
|
|
362
|
-
# appid/secret 配置在热更新场景下已经存在,无需重新写入。
|
|
318
|
+
# --no-restart 模式(热更新场景):立即退出,让调用方触发 gateway restart
|
|
363
319
|
if [ "$NO_RESTART" = "true" ]; then
|
|
364
320
|
echo ""
|
|
365
321
|
echo "[跳过重启] --no-restart 已指定,脚本立即退出以便调用方触发 gateway restart"
|
|
@@ -395,10 +351,9 @@ if [ -n "$APPID" ] && [ -n "$SECRET" ]; then
|
|
|
395
351
|
|
|
396
352
|
if [ "$CURRENT_TOKEN" = "$DESIRED_TOKEN" ]; then
|
|
397
353
|
echo " ✅ 当前配置已是目标值,跳过写入"
|
|
398
|
-
elif $CMD channels add --channel qqbot --token "$DESIRED_TOKEN" 2>&1; then
|
|
399
|
-
echo " ✅ 通道配置写入成功"
|
|
400
354
|
else
|
|
401
|
-
|
|
355
|
+
# qqbot 是插件自定义通道,openclaw channels add --channel 不支持,
|
|
356
|
+
# 直接编辑配置文件写入 channels.qqbot
|
|
402
357
|
CONFIG_FILE="$HOME/.$CMD/$CMD.json"
|
|
403
358
|
if [ -f "$CONFIG_FILE" ] && node -e "
|
|
404
359
|
const fs = require('fs');
|
|
@@ -409,10 +364,10 @@ if [ -n "$APPID" ] && [ -n "$SECRET" ]; then
|
|
|
409
364
|
cfg.channels.qqbot.clientSecret = '$SECRET';
|
|
410
365
|
fs.writeFileSync('$CONFIG_FILE', JSON.stringify(cfg, null, 4) + '\n');
|
|
411
366
|
" 2>&1; then
|
|
412
|
-
echo " ✅
|
|
367
|
+
echo " ✅ 通道配置写入成功"
|
|
413
368
|
else
|
|
414
|
-
echo " ❌
|
|
415
|
-
echo "
|
|
369
|
+
echo " ❌ 配置写入失败,请手动编辑 $CONFIG_FILE 添加 channels.qqbot:"
|
|
370
|
+
echo " { \"channels\": { \"qqbot\": { \"appId\": \"$APPID\", \"clientSecret\": \"...\" } } }"
|
|
416
371
|
fi
|
|
417
372
|
fi
|
|
418
373
|
elif [ -n "$APPID" ] || [ -n "$SECRET" ]; then
|
|
@@ -420,11 +375,10 @@ elif [ -n "$APPID" ] || [ -n "$SECRET" ]; then
|
|
|
420
375
|
echo "⚠️ --appid 和 --secret 必须同时提供"
|
|
421
376
|
fi
|
|
422
377
|
|
|
423
|
-
# [
|
|
378
|
+
# [4/4] 重启 gateway 使新版本生效
|
|
424
379
|
echo ""
|
|
425
380
|
|
|
426
381
|
# 手动升级场景:提前写入 startup-marker,阻止重启后 bot 重复推送升级通知
|
|
427
|
-
# (控制台已打印同款提示语,无需 bot 再发一次)
|
|
428
382
|
if [ -n "$NEW_VERSION" ] && [ "$NEW_VERSION" != "unknown" ]; then
|
|
429
383
|
MARKER_DIR="$HOME/.openclaw/qqbot/data"
|
|
430
384
|
mkdir -p "$MARKER_DIR"
|
|
@@ -436,7 +390,6 @@ fi
|
|
|
436
390
|
echo "[重启] 重启 gateway 使新版本生效..."
|
|
437
391
|
if $CMD gateway restart 2>&1; then
|
|
438
392
|
echo " ✅ gateway 已重启"
|
|
439
|
-
# 打印与 bot 通知同款的更新提示语(手动升级场景无需通过 bot 推送)
|
|
440
393
|
echo ""
|
|
441
394
|
if [ -n "$NEW_VERSION" ] && [ "$NEW_VERSION" != "unknown" ]; then
|
|
442
395
|
echo "🎉 QQBot 插件已更新至 v${NEW_VERSION},在线等候你的吩咐。"
|