@tencent-connect/openclaw-qqbot 1.6.4-alpha.7 → 1.6.4-alpha.9
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.
|
@@ -65,6 +65,12 @@ function registerCommand(cmd) {
|
|
|
65
65
|
registerCommand({
|
|
66
66
|
name: "bot-ping",
|
|
67
67
|
description: "测试当前 openclaw 与 QQ 连接的网络延迟",
|
|
68
|
+
usage: [
|
|
69
|
+
`/bot-ping`,
|
|
70
|
+
``,
|
|
71
|
+
`测试 OpenClaw 主机与 QQ 服务器之间的网络延迟。`,
|
|
72
|
+
`返回网络传输耗时和插件处理耗时。`,
|
|
73
|
+
].join("\n"),
|
|
68
74
|
handler: (ctx) => {
|
|
69
75
|
const now = Date.now();
|
|
70
76
|
const eventTime = new Date(ctx.eventTimestamp).getTime();
|
|
@@ -90,6 +96,12 @@ registerCommand({
|
|
|
90
96
|
registerCommand({
|
|
91
97
|
name: "bot-version",
|
|
92
98
|
description: "查看插件版本号",
|
|
99
|
+
usage: [
|
|
100
|
+
`/bot-version`,
|
|
101
|
+
``,
|
|
102
|
+
`查看当前 QQBot 插件版本和 OpenClaw 框架版本。`,
|
|
103
|
+
`同时检查是否有新版本可用。`,
|
|
104
|
+
].join("\n"),
|
|
93
105
|
handler: () => {
|
|
94
106
|
const frameworkVersion = getFrameworkVersion();
|
|
95
107
|
const lines = [
|
|
@@ -116,6 +128,12 @@ registerCommand({
|
|
|
116
128
|
registerCommand({
|
|
117
129
|
name: "bot-help",
|
|
118
130
|
description: "查看所有指令以及用途",
|
|
131
|
+
usage: [
|
|
132
|
+
`/bot-help`,
|
|
133
|
+
``,
|
|
134
|
+
`列出所有可用的 QQBot 插件内置指令及其简要说明。`,
|
|
135
|
+
`使用 /指令名 ? 可查看某条指令的详细用法。`,
|
|
136
|
+
].join("\n"),
|
|
119
137
|
handler: () => {
|
|
120
138
|
const lines = [`### QQBot插件内置调试指令`, ``];
|
|
121
139
|
for (const [name, cmd] of commands) {
|
|
@@ -205,6 +223,31 @@ function findBash() {
|
|
|
205
223
|
return null;
|
|
206
224
|
}
|
|
207
225
|
}
|
|
226
|
+
/**
|
|
227
|
+
* 将 openclaw.json 中的 qqbot 插件 source 从 "path" 切换为 "npm"。
|
|
228
|
+
* 用于热更新场景:从 npm 拉取新版本后,确保 openclaw 不再从本地源码加载。
|
|
229
|
+
*/
|
|
230
|
+
function switchPluginSourceToNpm() {
|
|
231
|
+
try {
|
|
232
|
+
const homeDir = getHomeDir();
|
|
233
|
+
for (const cli of ["openclaw", "clawdbot", "moltbot"]) {
|
|
234
|
+
const cfgPath = path.join(homeDir, `.${cli}`, `${cli}.json`);
|
|
235
|
+
if (!fs.existsSync(cfgPath))
|
|
236
|
+
continue;
|
|
237
|
+
const cfg = JSON.parse(fs.readFileSync(cfgPath, "utf8"));
|
|
238
|
+
const inst = cfg?.plugins?.installs?.["openclaw-qqbot"];
|
|
239
|
+
if (inst && inst.source !== "npm") {
|
|
240
|
+
inst.source = "npm";
|
|
241
|
+
delete inst.sourcePath;
|
|
242
|
+
fs.writeFileSync(cfgPath, JSON.stringify(cfg, null, 4) + "\n");
|
|
243
|
+
}
|
|
244
|
+
break;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
catch {
|
|
248
|
+
// 非关键操作,静默忽略
|
|
249
|
+
}
|
|
250
|
+
}
|
|
208
251
|
/**
|
|
209
252
|
* 执行热更新:执行脚本(--no-restart) → 立即触发 gateway restart
|
|
210
253
|
*
|
|
@@ -243,6 +286,11 @@ function fireHotUpgrade(targetVersion) {
|
|
|
243
286
|
// 文件替换异常,不执行 restart 以保持现有服务
|
|
244
287
|
return;
|
|
245
288
|
}
|
|
289
|
+
// 文件替换成功,在 restart 之前把 source 从 path 切换为 npm,
|
|
290
|
+
// 确保新进程启动时读到的是 npm source,不会被本地源码覆盖。
|
|
291
|
+
// 必须在 restart 之前同步完成,避免 openclaw 轮询检测到配置变更后
|
|
292
|
+
// 先于我们的 restart 触发非预期的 reload。
|
|
293
|
+
switchPluginSourceToNpm();
|
|
246
294
|
// 文件替换成功,立即触发 gateway restart(不再等后续步骤)
|
|
247
295
|
execFile(cli, ["gateway", "restart"], { timeout: 30_000 }, (restartErr) => {
|
|
248
296
|
if (restartErr) {
|
|
@@ -270,6 +318,14 @@ let _upgrading = false; // 升级锁
|
|
|
270
318
|
registerCommand({
|
|
271
319
|
name: "bot-upgrade",
|
|
272
320
|
description: "检查更新并自动热更(失败则返回升级指引)",
|
|
321
|
+
usage: [
|
|
322
|
+
`/bot-upgrade 检查是否有新版本(展示信息+确认按钮)`,
|
|
323
|
+
`/bot-upgrade --latest 确认升级到最新版本`,
|
|
324
|
+
`/bot-upgrade --version X 升级到指定版本(如 1.6.4-alpha.7)`,
|
|
325
|
+
`/bot-upgrade --force 强制重新安装当前版本`,
|
|
326
|
+
``,
|
|
327
|
+
`⚠️ 仅在私聊中可用。升级过程约 30~60 秒,期间服务短暂不可用。`,
|
|
328
|
+
].join("\n"),
|
|
273
329
|
handler: async (ctx) => {
|
|
274
330
|
// 升级相关指令仅在私聊中可用
|
|
275
331
|
if (ctx.type !== "c2c") {
|
|
@@ -507,6 +563,12 @@ function collectRecentLogFiles(logDirs) {
|
|
|
507
563
|
registerCommand({
|
|
508
564
|
name: "bot-logs",
|
|
509
565
|
description: "导出本地日志文件",
|
|
566
|
+
usage: [
|
|
567
|
+
`/bot-logs`,
|
|
568
|
+
``,
|
|
569
|
+
`导出最近的 OpenClaw 日志文件(最多 4 个)。`,
|
|
570
|
+
`每个文件最多保留最后 1000 行,以文件形式返回。`,
|
|
571
|
+
].join("\n"),
|
|
510
572
|
handler: () => {
|
|
511
573
|
const logDirs = collectCandidateLogDirs();
|
|
512
574
|
const recentFiles = collectRecentLogFiles(logDirs).slice(0, 4);
|
|
@@ -577,6 +639,13 @@ export async function matchSlashCommand(ctx) {
|
|
|
577
639
|
const cmd = commands.get(cmdName);
|
|
578
640
|
if (!cmd)
|
|
579
641
|
return null; // 不是插件级指令,交给框架
|
|
642
|
+
// /指令 ? — 返回用法说明
|
|
643
|
+
if (args === "?") {
|
|
644
|
+
if (cmd.usage) {
|
|
645
|
+
return `📖 /${cmd.name} 用法:\n\n${cmd.usage}`;
|
|
646
|
+
}
|
|
647
|
+
return `/${cmd.name} — ${cmd.description}`;
|
|
648
|
+
}
|
|
580
649
|
ctx.args = args;
|
|
581
650
|
const result = await cmd.handler(ctx);
|
|
582
651
|
return result;
|
|
@@ -71,7 +71,7 @@ async function fetchDistTags(log) {
|
|
|
71
71
|
export function triggerUpdateCheck(log) {
|
|
72
72
|
if (_checking)
|
|
73
73
|
return;
|
|
74
|
-
const INTERVAL_MS =
|
|
74
|
+
const INTERVAL_MS = 1 * 60 * 1000;
|
|
75
75
|
if (_lastInfo.checkedAt > 0 && Date.now() - _lastInfo.checkedAt < INTERVAL_MS) {
|
|
76
76
|
return;
|
|
77
77
|
}
|
package/package.json
CHANGED
|
@@ -259,6 +259,25 @@ else
|
|
|
259
259
|
echo "✅ 插件安装命令执行完成"
|
|
260
260
|
echo "安装日志已保存到: $INSTALL_LOG"
|
|
261
261
|
|
|
262
|
+
# 确保 openclaw.json 中的 source 为 path(从 npm 切回 path)
|
|
263
|
+
for _app in openclaw clawdbot moltbot; do
|
|
264
|
+
_cfg="$HOME/.$_app/$_app.json"
|
|
265
|
+
if [ -f "$_cfg" ]; then
|
|
266
|
+
node -e "
|
|
267
|
+
const fs = require('fs');
|
|
268
|
+
const cfg = JSON.parse(fs.readFileSync('$_cfg', 'utf8'));
|
|
269
|
+
const inst = cfg.plugins && cfg.plugins.installs && cfg.plugins.installs['openclaw-qqbot'];
|
|
270
|
+
if (inst && inst.source !== 'path') {
|
|
271
|
+
inst.source = 'path';
|
|
272
|
+
inst.sourcePath = '$PROJ_DIR';
|
|
273
|
+
fs.writeFileSync('$_cfg', JSON.stringify(cfg, null, 4) + '\n');
|
|
274
|
+
console.log(' 已将 plugins.installs.openclaw-qqbot.source 更新为 path');
|
|
275
|
+
}
|
|
276
|
+
" 2>/dev/null || true
|
|
277
|
+
break
|
|
278
|
+
fi
|
|
279
|
+
done
|
|
280
|
+
|
|
262
281
|
# 验证插件目录是否真正创建(防止 "安装成功" 但目录缺失的情况)
|
|
263
282
|
_plugin_dir_ok=0
|
|
264
283
|
for _candidate_name in openclaw-qqbot qqbot openclaw-qq; do
|
package/src/slash-commands.ts
CHANGED
|
@@ -116,6 +116,8 @@ interface SlashCommand {
|
|
|
116
116
|
name: string;
|
|
117
117
|
/** 简要描述 */
|
|
118
118
|
description: string;
|
|
119
|
+
/** 详细用法说明(支持多行),用于 /指令 ? 查询 */
|
|
120
|
+
usage?: string;
|
|
119
121
|
/** 处理函数 */
|
|
120
122
|
handler: (ctx: SlashCommandContext) => SlashCommandResult | Promise<SlashCommandResult>;
|
|
121
123
|
}
|
|
@@ -136,6 +138,12 @@ function registerCommand(cmd: SlashCommand): void {
|
|
|
136
138
|
registerCommand({
|
|
137
139
|
name: "bot-ping",
|
|
138
140
|
description: "测试当前 openclaw 与 QQ 连接的网络延迟",
|
|
141
|
+
usage: [
|
|
142
|
+
`/bot-ping`,
|
|
143
|
+
``,
|
|
144
|
+
`测试 OpenClaw 主机与 QQ 服务器之间的网络延迟。`,
|
|
145
|
+
`返回网络传输耗时和插件处理耗时。`,
|
|
146
|
+
].join("\n"),
|
|
139
147
|
handler: (ctx) => {
|
|
140
148
|
const now = Date.now();
|
|
141
149
|
const eventTime = new Date(ctx.eventTimestamp).getTime();
|
|
@@ -162,6 +170,12 @@ registerCommand({
|
|
|
162
170
|
registerCommand({
|
|
163
171
|
name: "bot-version",
|
|
164
172
|
description: "查看插件版本号",
|
|
173
|
+
usage: [
|
|
174
|
+
`/bot-version`,
|
|
175
|
+
``,
|
|
176
|
+
`查看当前 QQBot 插件版本和 OpenClaw 框架版本。`,
|
|
177
|
+
`同时检查是否有新版本可用。`,
|
|
178
|
+
].join("\n"),
|
|
165
179
|
handler: () => {
|
|
166
180
|
const frameworkVersion = getFrameworkVersion();
|
|
167
181
|
const lines = [
|
|
@@ -187,6 +201,12 @@ registerCommand({
|
|
|
187
201
|
registerCommand({
|
|
188
202
|
name: "bot-help",
|
|
189
203
|
description: "查看所有指令以及用途",
|
|
204
|
+
usage: [
|
|
205
|
+
`/bot-help`,
|
|
206
|
+
``,
|
|
207
|
+
`列出所有可用的 QQBot 插件内置指令及其简要说明。`,
|
|
208
|
+
`使用 /指令名 ? 可查看某条指令的详细用法。`,
|
|
209
|
+
].join("\n"),
|
|
190
210
|
handler: () => {
|
|
191
211
|
const lines = [`### QQBot插件内置调试指令`, ``];
|
|
192
212
|
for (const [name, cmd] of commands) {
|
|
@@ -289,6 +309,30 @@ function findBash(): string | null {
|
|
|
289
309
|
}
|
|
290
310
|
}
|
|
291
311
|
|
|
312
|
+
/**
|
|
313
|
+
* 将 openclaw.json 中的 qqbot 插件 source 从 "path" 切换为 "npm"。
|
|
314
|
+
* 用于热更新场景:从 npm 拉取新版本后,确保 openclaw 不再从本地源码加载。
|
|
315
|
+
*/
|
|
316
|
+
function switchPluginSourceToNpm(): void {
|
|
317
|
+
try {
|
|
318
|
+
const homeDir = getHomeDir();
|
|
319
|
+
for (const cli of ["openclaw", "clawdbot", "moltbot"]) {
|
|
320
|
+
const cfgPath = path.join(homeDir, `.${cli}`, `${cli}.json`);
|
|
321
|
+
if (!fs.existsSync(cfgPath)) continue;
|
|
322
|
+
const cfg = JSON.parse(fs.readFileSync(cfgPath, "utf8"));
|
|
323
|
+
const inst = cfg?.plugins?.installs?.["openclaw-qqbot"];
|
|
324
|
+
if (inst && inst.source !== "npm") {
|
|
325
|
+
inst.source = "npm";
|
|
326
|
+
delete inst.sourcePath;
|
|
327
|
+
fs.writeFileSync(cfgPath, JSON.stringify(cfg, null, 4) + "\n");
|
|
328
|
+
}
|
|
329
|
+
break;
|
|
330
|
+
}
|
|
331
|
+
} catch {
|
|
332
|
+
// 非关键操作,静默忽略
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
|
|
292
336
|
/**
|
|
293
337
|
* 执行热更新:执行脚本(--no-restart) → 立即触发 gateway restart
|
|
294
338
|
*
|
|
@@ -329,6 +373,12 @@ function fireHotUpgrade(targetVersion?: string): HotUpgradeStartResult {
|
|
|
329
373
|
return;
|
|
330
374
|
}
|
|
331
375
|
|
|
376
|
+
// 文件替换成功,在 restart 之前把 source 从 path 切换为 npm,
|
|
377
|
+
// 确保新进程启动时读到的是 npm source,不会被本地源码覆盖。
|
|
378
|
+
// 必须在 restart 之前同步完成,避免 openclaw 轮询检测到配置变更后
|
|
379
|
+
// 先于我们的 restart 触发非预期的 reload。
|
|
380
|
+
switchPluginSourceToNpm();
|
|
381
|
+
|
|
332
382
|
// 文件替换成功,立即触发 gateway restart(不再等后续步骤)
|
|
333
383
|
execFile(cli, ["gateway", "restart"], { timeout: 30_000 }, (restartErr) => {
|
|
334
384
|
if (restartErr) {
|
|
@@ -359,6 +409,14 @@ let _upgrading = false; // 升级锁
|
|
|
359
409
|
registerCommand({
|
|
360
410
|
name: "bot-upgrade",
|
|
361
411
|
description: "检查更新并自动热更(失败则返回升级指引)",
|
|
412
|
+
usage: [
|
|
413
|
+
`/bot-upgrade 检查是否有新版本(展示信息+确认按钮)`,
|
|
414
|
+
`/bot-upgrade --latest 确认升级到最新版本`,
|
|
415
|
+
`/bot-upgrade --version X 升级到指定版本(如 1.6.4-alpha.7)`,
|
|
416
|
+
`/bot-upgrade --force 强制重新安装当前版本`,
|
|
417
|
+
``,
|
|
418
|
+
`⚠️ 仅在私聊中可用。升级过程约 30~60 秒,期间服务短暂不可用。`,
|
|
419
|
+
].join("\n"),
|
|
362
420
|
handler: async (ctx) => {
|
|
363
421
|
// 升级相关指令仅在私聊中可用
|
|
364
422
|
if (ctx.type !== "c2c") {
|
|
@@ -615,6 +673,12 @@ function collectRecentLogFiles(logDirs: string[]): LogCandidate[] {
|
|
|
615
673
|
registerCommand({
|
|
616
674
|
name: "bot-logs",
|
|
617
675
|
description: "导出本地日志文件",
|
|
676
|
+
usage: [
|
|
677
|
+
`/bot-logs`,
|
|
678
|
+
``,
|
|
679
|
+
`导出最近的 OpenClaw 日志文件(最多 4 个)。`,
|
|
680
|
+
`每个文件最多保留最后 1000 行,以文件形式返回。`,
|
|
681
|
+
].join("\n"),
|
|
618
682
|
handler: () => {
|
|
619
683
|
const logDirs = collectCandidateLogDirs();
|
|
620
684
|
const recentFiles = collectRecentLogFiles(logDirs).slice(0, 4);
|
|
@@ -691,6 +755,14 @@ export async function matchSlashCommand(ctx: SlashCommandContext): Promise<Slash
|
|
|
691
755
|
const cmd = commands.get(cmdName);
|
|
692
756
|
if (!cmd) return null; // 不是插件级指令,交给框架
|
|
693
757
|
|
|
758
|
+
// /指令 ? — 返回用法说明
|
|
759
|
+
if (args === "?") {
|
|
760
|
+
if (cmd.usage) {
|
|
761
|
+
return `📖 /${cmd.name} 用法:\n\n${cmd.usage}`;
|
|
762
|
+
}
|
|
763
|
+
return `/${cmd.name} — ${cmd.description}`;
|
|
764
|
+
}
|
|
765
|
+
|
|
694
766
|
ctx.args = args;
|
|
695
767
|
const result = await cmd.handler(ctx);
|
|
696
768
|
return result;
|
package/src/update-checker.ts
CHANGED
|
@@ -84,7 +84,7 @@ export function triggerUpdateCheck(log?: {
|
|
|
84
84
|
debug?: (msg: string) => void;
|
|
85
85
|
}): void {
|
|
86
86
|
if (_checking) return;
|
|
87
|
-
const INTERVAL_MS =
|
|
87
|
+
const INTERVAL_MS = 1 * 60 * 1000;
|
|
88
88
|
if (_lastInfo.checkedAt > 0 && Date.now() - _lastInfo.checkedAt < INTERVAL_MS) {
|
|
89
89
|
return;
|
|
90
90
|
}
|