@tencent-connect/openclaw-qqbot 1.7.2 → 2.0.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 +25 -8
- package/README.zh.md +24 -8
- package/bin/qqbot-cli.js +5 -2
- package/dist/index.cjs +15549 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +890 -0
- package/index.ts +56 -19
- package/openclaw.plugin.json +19 -3
- package/package.json +14 -23
- package/preload.cjs +17 -14
- package/scripts/link-sdk-core.cjs +133 -50
- package/scripts/upgrade-via-npm.sh +42 -11
- package/scripts/upgrade-via-source.sh +4 -4
- package/skills/qqbot-channel/SKILL.md +34 -12
- package/src/adapter/contract.ts +69 -0
- package/src/adapter/gateway.ts +61 -0
- package/src/adapter/index.ts +15 -0
- package/src/adapter/lint.ts +144 -0
- package/src/adapter/media.ts +112 -0
- package/src/adapter/pairing.ts +99 -0
- package/src/adapter/resolve.ts +333 -0
- package/src/adapter/setup.ts +55 -0
- package/src/adapter/webhook.ts +248 -0
- package/src/adapter/workspace.ts +29 -0
- package/src/bot-instance.ts +60 -0
- package/src/channel.ts +202 -413
- package/src/commands/bot-approve.ts +143 -0
- package/src/commands/bot-clear-storage.ts +114 -0
- package/src/commands/bot-group-always.ts +62 -0
- package/src/commands/bot-help.ts +40 -0
- package/src/commands/bot-logs.ts +248 -0
- package/src/commands/bot-me.ts +18 -0
- package/src/commands/bot-pairing.ts +57 -0
- package/src/commands/bot-ping.ts +33 -0
- package/src/commands/bot-streaming.ts +55 -0
- package/src/commands/bot-upgrade.ts +56 -0
- package/src/commands/bot-version.ts +41 -0
- package/src/commands/config-util.ts +96 -0
- package/src/commands/index.ts +49 -0
- package/src/config.ts +46 -19
- package/src/dispatch/body-assembler.ts +356 -0
- package/src/dispatch/ctx-builder.ts +110 -0
- package/src/dispatch/dispatch.ts +352 -0
- package/src/dispatch/envelope-builder.ts +112 -0
- package/src/dispatch/index.ts +2 -0
- package/src/{approval-handler.ts → features/approval-handler.ts} +40 -94
- package/src/features/approval-utils.ts +41 -0
- package/src/features/credential-backup.ts +82 -0
- package/src/features/history-store.ts +19 -0
- package/src/features/msgid-cache.ts +55 -0
- package/src/features/onboarding.ts +38 -0
- package/src/{proactive.ts → features/proactive.ts} +68 -49
- package/src/features/ref-index-store.ts +282 -0
- package/src/{update-checker.ts → features/update-checker.ts} +15 -35
- package/src/gateway/event-handlers.ts +241 -0
- package/src/gateway/index.ts +3 -0
- package/src/gateway/lifecycle.ts +221 -0
- package/src/gateway/middleware-setup.ts +139 -0
- package/src/gateway/qqbot-gateway.ts +342 -0
- package/src/middleware/access-control.ts +130 -0
- package/src/middleware/attachment.ts +314 -0
- package/src/middleware/policy-injector.ts +66 -0
- package/src/openclaw-plugin-sdk.d.ts +81 -10
- package/src/outbound/cron-scheduler.ts +130 -0
- package/src/outbound/debounce.ts +102 -0
- package/src/outbound/deliver-pipeline.ts +235 -0
- package/src/outbound/image-size.ts +123 -0
- package/src/outbound/index.ts +3 -0
- package/src/outbound/local-file-router.ts +145 -0
- package/src/outbound/media-send.ts +377 -0
- package/src/outbound/outbound-service.ts +222 -0
- package/src/outbound/reply-limiter.ts +128 -0
- package/src/outbound/sanitize.ts +32 -0
- package/src/outbound/streaming-controller.ts +228 -0
- package/src/outbound/target.ts +63 -0
- package/src/outbound/tts-provider.ts +84 -0
- package/src/request-context.ts +9 -8
- package/src/runtime.ts +31 -6
- package/src/setup/account-key.ts +41 -0
- package/src/setup/finalize.ts +110 -0
- package/src/setup/login.ts +197 -0
- package/src/setup/surface.ts +40 -0
- package/src/tools/platform.ts +149 -0
- package/src/tools/remind.ts +2 -0
- package/src/types-augment.d.ts +54 -0
- package/src/types.ts +51 -9
- package/src/utils/mention.ts +52 -0
- package/src/utils/pkg-version.ts +84 -47
- package/src/utils/platform.ts +31 -7
- package/src/utils/plugin-logger.ts +104 -0
- package/src/utils/ssrf-guard.ts +32 -2
- package/src/utils/stt.ts +137 -0
- package/src/utils/voice-text.ts +61 -0
- package/tsconfig.json +2 -1
- package/tsup.config.ts +57 -0
- package/dist/index.d.ts +0 -18
- package/dist/index.js +0 -27
- package/dist/src/admin-resolver.d.ts +0 -33
- package/dist/src/admin-resolver.js +0 -157
- package/dist/src/api.d.ts +0 -309
- package/dist/src/api.js +0 -923
- package/dist/src/approval-handler.d.ts +0 -47
- package/dist/src/approval-handler.js +0 -372
- package/dist/src/channel.d.ts +0 -29
- package/dist/src/channel.js +0 -528
- package/dist/src/config.d.ts +0 -60
- package/dist/src/config.js +0 -288
- package/dist/src/credential-backup.d.ts +0 -31
- package/dist/src/credential-backup.js +0 -66
- package/dist/src/deliver-debounce.d.ts +0 -74
- package/dist/src/deliver-debounce.js +0 -174
- package/dist/src/gateway.d.ts +0 -18
- package/dist/src/gateway.js +0 -2025
- package/dist/src/group-history.d.ts +0 -136
- package/dist/src/group-history.js +0 -226
- package/dist/src/image-server.d.ts +0 -87
- package/dist/src/image-server.js +0 -570
- package/dist/src/inbound-attachments.d.ts +0 -60
- package/dist/src/inbound-attachments.js +0 -248
- package/dist/src/known-users.d.ts +0 -100
- package/dist/src/known-users.js +0 -263
- package/dist/src/message-gating.d.ts +0 -53
- package/dist/src/message-gating.js +0 -107
- package/dist/src/message-queue.d.ts +0 -91
- package/dist/src/message-queue.js +0 -257
- package/dist/src/onboarding.d.ts +0 -10
- package/dist/src/onboarding.js +0 -203
- package/dist/src/outbound-deliver.d.ts +0 -48
- package/dist/src/outbound-deliver.js +0 -392
- package/dist/src/outbound.d.ts +0 -220
- package/dist/src/outbound.js +0 -975
- package/dist/src/proactive.d.ts +0 -170
- package/dist/src/proactive.js +0 -399
- package/dist/src/ref-index-store.d.ts +0 -101
- package/dist/src/ref-index-store.js +0 -298
- package/dist/src/reply-dispatcher.d.ts +0 -35
- package/dist/src/reply-dispatcher.js +0 -311
- package/dist/src/request-context.d.ts +0 -25
- package/dist/src/request-context.js +0 -37
- package/dist/src/runtime.d.ts +0 -3
- package/dist/src/runtime.js +0 -13
- package/dist/src/session-store.d.ts +0 -52
- package/dist/src/session-store.js +0 -254
- package/dist/src/slash-commands.d.ts +0 -82
- package/dist/src/slash-commands.js +0 -2233
- package/dist/src/startup-greeting.d.ts +0 -30
- package/dist/src/startup-greeting.js +0 -97
- package/dist/src/streaming.d.ts +0 -247
- package/dist/src/streaming.js +0 -899
- package/dist/src/stt.d.ts +0 -21
- package/dist/src/stt.js +0 -70
- package/dist/src/tools/channel.d.ts +0 -16
- package/dist/src/tools/channel.js +0 -231
- package/dist/src/tools/remind.d.ts +0 -2
- package/dist/src/tools/remind.js +0 -255
- package/dist/src/transport/index.d.ts +0 -10
- package/dist/src/transport/index.js +0 -9
- package/dist/src/transport/webhook-transport.d.ts +0 -67
- package/dist/src/transport/webhook-transport.js +0 -245
- package/dist/src/transport/webhook-verify.d.ts +0 -48
- package/dist/src/transport/webhook-verify.js +0 -98
- package/dist/src/types.d.ts +0 -462
- package/dist/src/types.js +0 -22
- package/dist/src/typing-keepalive.d.ts +0 -27
- package/dist/src/typing-keepalive.js +0 -64
- package/dist/src/update-checker.d.ts +0 -36
- package/dist/src/update-checker.js +0 -171
- package/dist/src/utils/audio-convert.d.ts +0 -98
- package/dist/src/utils/audio-convert.js +0 -783
- package/dist/src/utils/chunked-upload.d.ts +0 -68
- package/dist/src/utils/chunked-upload.js +0 -341
- package/dist/src/utils/file-utils.d.ts +0 -61
- package/dist/src/utils/file-utils.js +0 -172
- package/dist/src/utils/image-size.d.ts +0 -51
- package/dist/src/utils/image-size.js +0 -234
- package/dist/src/utils/media-send.d.ts +0 -158
- package/dist/src/utils/media-send.js +0 -502
- package/dist/src/utils/media-tags.d.ts +0 -14
- package/dist/src/utils/media-tags.js +0 -165
- package/dist/src/utils/payload.d.ts +0 -112
- package/dist/src/utils/payload.js +0 -186
- package/dist/src/utils/pkg-version.d.ts +0 -5
- package/dist/src/utils/pkg-version.js +0 -61
- package/dist/src/utils/platform.d.ts +0 -137
- package/dist/src/utils/platform.js +0 -390
- package/dist/src/utils/ssrf-guard.d.ts +0 -25
- package/dist/src/utils/ssrf-guard.js +0 -91
- package/dist/src/utils/text-parsing.d.ts +0 -31
- package/dist/src/utils/text-parsing.js +0 -74
- package/dist/src/utils/upload-cache.d.ts +0 -34
- package/dist/src/utils/upload-cache.js +0 -93
- package/node_modules/@eshaz/web-worker/LICENSE +0 -201
- package/node_modules/@eshaz/web-worker/README.md +0 -134
- package/node_modules/@eshaz/web-worker/browser.js +0 -17
- package/node_modules/@eshaz/web-worker/cjs/browser.js +0 -16
- package/node_modules/@eshaz/web-worker/cjs/node.js +0 -219
- package/node_modules/@eshaz/web-worker/index.d.ts +0 -4
- package/node_modules/@eshaz/web-worker/node.js +0 -223
- package/node_modules/@eshaz/web-worker/package.json +0 -54
- package/node_modules/@wasm-audio-decoders/common/index.js +0 -5
- package/node_modules/@wasm-audio-decoders/common/package.json +0 -36
- package/node_modules/@wasm-audio-decoders/common/src/WASMAudioDecoderCommon.js +0 -231
- package/node_modules/@wasm-audio-decoders/common/src/WASMAudioDecoderWorker.js +0 -129
- package/node_modules/@wasm-audio-decoders/common/src/puff/README +0 -67
- package/node_modules/@wasm-audio-decoders/common/src/puff/build_puff.js +0 -31
- package/node_modules/@wasm-audio-decoders/common/src/puff/puff.c +0 -863
- package/node_modules/@wasm-audio-decoders/common/src/puff/puff.h +0 -35
- package/node_modules/@wasm-audio-decoders/common/src/utilities.js +0 -3
- package/node_modules/@wasm-audio-decoders/common/types.d.ts +0 -7
- package/node_modules/mpg123-decoder/README.md +0 -265
- package/node_modules/mpg123-decoder/dist/mpg123-decoder.min.js +0 -185
- package/node_modules/mpg123-decoder/dist/mpg123-decoder.min.js.map +0 -1
- package/node_modules/mpg123-decoder/index.js +0 -8
- package/node_modules/mpg123-decoder/package.json +0 -58
- package/node_modules/mpg123-decoder/src/EmscriptenWasm.js +0 -464
- package/node_modules/mpg123-decoder/src/MPEGDecoder.js +0 -200
- package/node_modules/mpg123-decoder/src/MPEGDecoderWebWorker.js +0 -21
- package/node_modules/mpg123-decoder/types.d.ts +0 -30
- package/node_modules/silk-wasm/LICENSE +0 -21
- package/node_modules/silk-wasm/README.md +0 -85
- package/node_modules/silk-wasm/lib/index.cjs +0 -16
- package/node_modules/silk-wasm/lib/index.d.ts +0 -70
- package/node_modules/silk-wasm/lib/index.mjs +0 -16
- package/node_modules/silk-wasm/lib/silk.wasm +0 -0
- package/node_modules/silk-wasm/lib/utils.d.ts +0 -4
- package/node_modules/silk-wasm/package.json +0 -39
- package/node_modules/simple-yenc/.github/FUNDING.yml +0 -1
- package/node_modules/simple-yenc/.prettierignore +0 -1
- package/node_modules/simple-yenc/LICENSE +0 -7
- package/node_modules/simple-yenc/README.md +0 -163
- package/node_modules/simple-yenc/dist/esm.js +0 -1
- package/node_modules/simple-yenc/dist/index.js +0 -1
- package/node_modules/simple-yenc/package.json +0 -50
- package/node_modules/simple-yenc/rollup.config.js +0 -27
- package/node_modules/simple-yenc/src/simple-yenc.js +0 -302
- package/node_modules/ws/LICENSE +0 -20
- package/node_modules/ws/README.md +0 -548
- package/node_modules/ws/browser.js +0 -8
- package/node_modules/ws/index.js +0 -13
- package/node_modules/ws/lib/buffer-util.js +0 -131
- package/node_modules/ws/lib/constants.js +0 -19
- package/node_modules/ws/lib/event-target.js +0 -292
- package/node_modules/ws/lib/extension.js +0 -203
- package/node_modules/ws/lib/limiter.js +0 -55
- package/node_modules/ws/lib/permessage-deflate.js +0 -528
- package/node_modules/ws/lib/receiver.js +0 -706
- package/node_modules/ws/lib/sender.js +0 -602
- package/node_modules/ws/lib/stream.js +0 -161
- package/node_modules/ws/lib/subprotocol.js +0 -62
- package/node_modules/ws/lib/validation.js +0 -152
- package/node_modules/ws/lib/websocket-server.js +0 -554
- package/node_modules/ws/lib/websocket.js +0 -1393
- package/node_modules/ws/package.json +0 -69
- package/node_modules/ws/wrapper.mjs +0 -8
- package/scripts/postinstall-link-sdk.js +0 -170
- package/skills/qqbot-media/SKILL.md +0 -60
- package/src/admin-resolver.ts +0 -181
- package/src/api.ts +0 -1333
- package/src/credential-backup.ts +0 -72
- package/src/deliver-debounce.ts +0 -229
- package/src/gateway.ts +0 -2272
- package/src/group-history.ts +0 -328
- package/src/image-server.ts +0 -675
- package/src/inbound-attachments.ts +0 -321
- package/src/known-users.ts +0 -353
- package/src/message-gating.ts +0 -190
- package/src/message-queue.ts +0 -354
- package/src/onboarding.ts +0 -282
- package/src/outbound-deliver.ts +0 -486
- package/src/outbound.ts +0 -1179
- package/src/ref-index-store.ts +0 -412
- package/src/reply-dispatcher.ts +0 -334
- package/src/session-store.ts +0 -303
- package/src/slash-commands.ts +0 -2431
- package/src/startup-greeting.ts +0 -120
- package/src/streaming.ts +0 -1077
- package/src/stt.ts +0 -86
- package/src/tools/channel.ts +0 -275
- package/src/transport/index.ts +0 -11
- package/src/transport/webhook-transport.ts +0 -332
- package/src/transport/webhook-verify.ts +0 -119
- package/src/typing-keepalive.ts +0 -59
- package/src/utils/audio-convert.ts +0 -887
- package/src/utils/chunked-upload.ts +0 -483
- package/src/utils/file-utils.ts +0 -193
- package/src/utils/image-size.ts +0 -266
- package/src/utils/media-send.ts +0 -636
- package/src/utils/media-tags.ts +0 -183
- package/src/utils/payload.ts +0 -265
- package/src/utils/text-parsing.ts +0 -85
- package/src/utils/upload-cache.ts +0 -128
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { SlashCommand } from '@tencent-connect/qqbot-nodejs';
|
|
2
|
+
|
|
3
|
+
/** /bot-ping — 测试当前 openclaw 与 QQ 连接的网络延迟 */
|
|
4
|
+
export function botPing(): SlashCommand {
|
|
5
|
+
return {
|
|
6
|
+
name: 'bot-ping',
|
|
7
|
+
description: '测试当前 openclaw 与 QQ 连接的网络延迟',
|
|
8
|
+
usage: [
|
|
9
|
+
'/bot-ping',
|
|
10
|
+
'',
|
|
11
|
+
'测试 OpenClaw 主机与 QQ 服务器之间的网络延迟。',
|
|
12
|
+
'返回网络传输耗时和插件处理耗时。',
|
|
13
|
+
].join('\n'),
|
|
14
|
+
handler: (ctx) => {
|
|
15
|
+
const now = Date.now();
|
|
16
|
+
const ts = (ctx.message as any).timestamp;
|
|
17
|
+
const eventTime = ts ? new Date(ts).getTime() : NaN;
|
|
18
|
+
if (isNaN(eventTime)) {
|
|
19
|
+
return '✅ pong!';
|
|
20
|
+
}
|
|
21
|
+
const totalMs = now - eventTime;
|
|
22
|
+
const qqToPlugin = ctx.receivedAt - eventTime;
|
|
23
|
+
const pluginProcess = now - ctx.receivedAt;
|
|
24
|
+
return [
|
|
25
|
+
'✅ pong!',
|
|
26
|
+
'',
|
|
27
|
+
`⏱ 延迟: ${totalMs}ms`,
|
|
28
|
+
` ├ 网络传输: ${qqToPlugin}ms`,
|
|
29
|
+
` └ 插件处理: ${pluginProcess}ms`,
|
|
30
|
+
].join('\n');
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { SlashCommand } from '@tencent-connect/qqbot-nodejs';
|
|
2
|
+
import type { PluginRuntime } from 'openclaw/plugin-sdk';
|
|
3
|
+
import type { ResolvedQQBotAccount } from '../types.js';
|
|
4
|
+
import { updateAccountConfig, checkCommandAuth } from './config-util.js';
|
|
5
|
+
|
|
6
|
+
/** /bot-streaming — 一键开关流式消息 */
|
|
7
|
+
export function botStreaming(account: ResolvedQQBotAccount, getRuntime: () => PluginRuntime): SlashCommand {
|
|
8
|
+
return {
|
|
9
|
+
name: 'bot-streaming',
|
|
10
|
+
description: '一键开关流式消息',
|
|
11
|
+
scope: 'c2c',
|
|
12
|
+
authorized: checkCommandAuth,
|
|
13
|
+
usage: `/bot-streaming
|
|
14
|
+
|
|
15
|
+
查看当前流式消息状态,或切换开/关。
|
|
16
|
+
流式消息仅支持 C2C(私聊)场景。`,
|
|
17
|
+
handler: async (ctx) => {
|
|
18
|
+
const args = (Array.isArray(ctx.command.args) ? ctx.command.args.join(' ') : String(ctx.command.args ?? '')).trim().toLowerCase();
|
|
19
|
+
const streaming = account.config?.streaming;
|
|
20
|
+
const currentEnabled = typeof streaming === 'boolean'
|
|
21
|
+
? streaming
|
|
22
|
+
: (streaming as any)?.mode !== 'off';
|
|
23
|
+
|
|
24
|
+
// 无参数 → 显示状态
|
|
25
|
+
if (!args) {
|
|
26
|
+
const status = currentEnabled ? '✅ 已启用' : '❌ 未启用';
|
|
27
|
+
const toggleHint = currentEnabled
|
|
28
|
+
? '<qqbot-cmd-input text="/bot-streaming off" show="关闭流式"/>'
|
|
29
|
+
: '<qqbot-cmd-input text="/bot-streaming on" show="开启流式"/>';
|
|
30
|
+
return [
|
|
31
|
+
`🌊 流式消息状态: ${status}`,
|
|
32
|
+
'',
|
|
33
|
+
'流式消息仅支持 C2C(私聊)场景。',
|
|
34
|
+
`点击 ${toggleHint} 切换。`,
|
|
35
|
+
].join('\n');
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// on / off → 切换
|
|
39
|
+
const targetEnabled = args === 'on' || args === '1' || args === 'true';
|
|
40
|
+
if (targetEnabled === currentEnabled) {
|
|
41
|
+
return `ℹ️ 流式消息已经是${currentEnabled ? '开启' : '关闭'}状态,无需切换。`;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const error = await updateAccountConfig(account, getRuntime, (acfg) => {
|
|
45
|
+
(acfg as any).streaming = { mode: targetEnabled ? 'partial' : 'off' };
|
|
46
|
+
});
|
|
47
|
+
if (error) return error;
|
|
48
|
+
|
|
49
|
+
account.config.streaming = { mode: targetEnabled ? 'partial' : 'off' };
|
|
50
|
+
return targetEnabled
|
|
51
|
+
? '✅ 流式消息已开启,私聊消息将以流式方式发送。'
|
|
52
|
+
: '✅ 流式消息已关闭,私聊消息将以静态方式发送。';
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { SlashCommand } from '@tencent-connect/qqbot-nodejs';
|
|
2
|
+
import type { ResolvedQQBotAccount } from '../types.js';
|
|
3
|
+
import { getPackageVersion } from '../utils/pkg-version.js';
|
|
4
|
+
import { getUpdateInfo } from '../features/update-checker.js';
|
|
5
|
+
import { checkCommandAuth } from './config-util.js';
|
|
6
|
+
|
|
7
|
+
const PLUGIN_VERSION = getPackageVersion();
|
|
8
|
+
const DEFAULT_UPGRADE_URL = 'https://docs.qq.com/doc/DSGxOZk1oVnVKVkpq';
|
|
9
|
+
const GITHUB_URL = 'https://github.com/nicepkg/openclaw';
|
|
10
|
+
|
|
11
|
+
/** /bot-upgrade — 检查更新并查看升级指引 */
|
|
12
|
+
export function botUpgrade(account: ResolvedQQBotAccount): SlashCommand {
|
|
13
|
+
return {
|
|
14
|
+
name: 'bot-upgrade',
|
|
15
|
+
description: '检查更新并查看升级指引',
|
|
16
|
+
scope: 'c2c',
|
|
17
|
+
authorized: checkCommandAuth,
|
|
18
|
+
usage: [
|
|
19
|
+
'/bot-upgrade 检查是否有新版本',
|
|
20
|
+
].join('\n'),
|
|
21
|
+
handler: async () => {
|
|
22
|
+
const url = account.config.upgradeUrl ?? DEFAULT_UPGRADE_URL;
|
|
23
|
+
const info = await getUpdateInfo();
|
|
24
|
+
|
|
25
|
+
if (info.checkedAt === 0) {
|
|
26
|
+
return '⏳ 版本检查中,请稍后再试';
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (info.error) {
|
|
30
|
+
return [
|
|
31
|
+
'❌ 主机网络访问异常,无法检查更新',
|
|
32
|
+
'',
|
|
33
|
+
`查看升级指引:[点击查看](${url})`,
|
|
34
|
+
].join('\n');
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (!info.hasUpdate) {
|
|
38
|
+
return [
|
|
39
|
+
`✅ 当前已是最新版本 v${PLUGIN_VERSION}`,
|
|
40
|
+
'',
|
|
41
|
+
`项目地址:[GitHub](${GITHUB_URL})`,
|
|
42
|
+
].join('\n');
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return [
|
|
46
|
+
'🆕 发现新版本',
|
|
47
|
+
'',
|
|
48
|
+
`当前版本:**v${PLUGIN_VERSION}**`,
|
|
49
|
+
`最新版本:**v${info.latest}**`,
|
|
50
|
+
'',
|
|
51
|
+
`📖 升级指引:[点击查看](${url})`,
|
|
52
|
+
`🌟 官方 GitHub 仓库:[点击前往](${GITHUB_URL})`,
|
|
53
|
+
].join('\n');
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { SlashCommand } from '@tencent-connect/qqbot-nodejs';
|
|
2
|
+
import type { ResolvedQQBotAccount } from '../types.js';
|
|
3
|
+
import { getPackageVersion } from '../utils/pkg-version.js';
|
|
4
|
+
import { getUpdateInfo } from '../features/update-checker.js';
|
|
5
|
+
import { getOpenClawVersion } from '../bot-instance.js';
|
|
6
|
+
|
|
7
|
+
const PLUGIN_VERSION = getPackageVersion();
|
|
8
|
+
const GITHUB_URL = 'https://github.com/nicepkg/openclaw';
|
|
9
|
+
|
|
10
|
+
/** /bot-version — 查看插件版本号 */
|
|
11
|
+
export function botVersion(_account: ResolvedQQBotAccount): SlashCommand {
|
|
12
|
+
return {
|
|
13
|
+
name: 'bot-version',
|
|
14
|
+
description: '查看插件版本号',
|
|
15
|
+
usage: [
|
|
16
|
+
'/bot-version',
|
|
17
|
+
'',
|
|
18
|
+
'查看当前 QQBot 插件版本和 OpenClaw 框架版本。',
|
|
19
|
+
'同时检查是否有新版本可用。',
|
|
20
|
+
].join('\n'),
|
|
21
|
+
handler: async () => {
|
|
22
|
+
const frameworkVersion = getOpenClawVersion();
|
|
23
|
+
const lines = [
|
|
24
|
+
`🦞框架版本:${frameworkVersion}`,
|
|
25
|
+
`🤖QQBot 插件版本:v${PLUGIN_VERSION}`,
|
|
26
|
+
];
|
|
27
|
+
|
|
28
|
+
const info = await getUpdateInfo();
|
|
29
|
+
if (info.checkedAt === 0) {
|
|
30
|
+
lines.push('⏳ 版本检查中...');
|
|
31
|
+
} else if (info.error) {
|
|
32
|
+
lines.push('⚠️ 版本检查失败');
|
|
33
|
+
} else if (info.hasUpdate && info.latest) {
|
|
34
|
+
lines.push(`🆕最新可用版本:v${info.latest},点击 <qqbot-cmd-input text="/bot-upgrade" show="/bot-upgrade"/> 查看升级指引`);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
lines.push(`🌟官方 GitHub 仓库:[点击前往](${GITHUB_URL})`);
|
|
38
|
+
return lines.join('\n');
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import type { ResolvedQQBotAccount } from '../types.js';
|
|
2
|
+
import type { SlashCommandHandlerContext } from '@tencent-connect/qqbot-nodejs';
|
|
3
|
+
import type { PluginRuntime } from 'openclaw/plugin-sdk';
|
|
4
|
+
import { getAdapters } from '../adapter/resolve.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* 命令授权检查(用于 SlashCommand.authorized 回调)。
|
|
8
|
+
*
|
|
9
|
+
* 规则:
|
|
10
|
+
* - mode=open → 允许
|
|
11
|
+
* - allowFrom 为空或含 "*" → 允许
|
|
12
|
+
* - senderId 在 allowFrom 中 → 允许
|
|
13
|
+
* - 否则 → 返回错误消息
|
|
14
|
+
*/
|
|
15
|
+
export function checkCommandAuth(ctx: SlashCommandHandlerContext): boolean | string {
|
|
16
|
+
const p = (ctx.state as any).policy;
|
|
17
|
+
const mode = p?.c2cMode ?? 'allowlist';
|
|
18
|
+
const allowFrom: string[] = p?.allowFrom ?? [];
|
|
19
|
+
if (mode === 'open' || !allowFrom.length || allowFrom.includes('*')) return true;
|
|
20
|
+
return allowFrom.includes(ctx.message.senderId) || '⚠️ 无权限执行此命令';
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
interface PersistResult {
|
|
24
|
+
persist: (updater: (cfg: any) => void) => Promise<void>;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* 底层:获取 persistConfig,统一处理 runtime/adapters 判空。
|
|
29
|
+
* @returns [error, result] — error 非空时不可用;result.persist 直接调 persistConfig。
|
|
30
|
+
*/
|
|
31
|
+
async function resolvePersistFn(getRuntime: () => PluginRuntime): Promise<[string | null, PersistResult | null]> {
|
|
32
|
+
const runtime = getRuntime();
|
|
33
|
+
if (!runtime) return ['⚠️ runtime 不可用,无法修改配置。', null];
|
|
34
|
+
|
|
35
|
+
const adapters = getAdapters(runtime);
|
|
36
|
+
if (!adapters.persistConfig) {
|
|
37
|
+
return ['⚠️ 当前框架版本不支持在线修改配置,请手动编辑配置文件。', null];
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return [
|
|
41
|
+
null,
|
|
42
|
+
{ persist: (updater: (cfg: any) => void) => adapters.persistConfig!(updater) },
|
|
43
|
+
];
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* 持久化更新**账户**配置。自动处理命名账户 / 默认账户路径差异。
|
|
48
|
+
*/
|
|
49
|
+
export async function updateAccountConfig(
|
|
50
|
+
account: ResolvedQQBotAccount,
|
|
51
|
+
getRuntime: () => PluginRuntime,
|
|
52
|
+
updater: (accountConfig: Record<string, unknown>) => void,
|
|
53
|
+
): Promise<string | null> {
|
|
54
|
+
const [err, result] = await resolvePersistFn(getRuntime);
|
|
55
|
+
if (err || !result) return err;
|
|
56
|
+
|
|
57
|
+
try {
|
|
58
|
+
await result.persist((cfg: any) => {
|
|
59
|
+
cfg.channels ??= {};
|
|
60
|
+
cfg.channels.qqbot ??= {};
|
|
61
|
+
|
|
62
|
+
const qqbot = cfg.channels.qqbot;
|
|
63
|
+
const accountId = account.accountId;
|
|
64
|
+
const isNamedAccount = accountId !== 'default' && qqbot.accounts?.[accountId];
|
|
65
|
+
|
|
66
|
+
if (isNamedAccount) {
|
|
67
|
+
qqbot.accounts[accountId] ??= {};
|
|
68
|
+
updater(qqbot.accounts[accountId]);
|
|
69
|
+
} else {
|
|
70
|
+
updater(qqbot);
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
return null;
|
|
74
|
+
} catch (e) {
|
|
75
|
+
return `⚠️ 配置修改失败:${e instanceof Error ? e.message : String(e)}`;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* 持久化更新**框架通用**配置(不从 channels.qqbot.accounts 走)。
|
|
81
|
+
* 适用于 tools.exec 等非账户级字段。
|
|
82
|
+
*/
|
|
83
|
+
export async function updateGlobalConfig(
|
|
84
|
+
getRuntime: () => PluginRuntime,
|
|
85
|
+
updater: (cfg: any) => void,
|
|
86
|
+
): Promise<string | null> {
|
|
87
|
+
const [err, result] = await resolvePersistFn(getRuntime);
|
|
88
|
+
if (err || !result) return err;
|
|
89
|
+
|
|
90
|
+
try {
|
|
91
|
+
await result.persist(updater);
|
|
92
|
+
return null;
|
|
93
|
+
} catch (e) {
|
|
94
|
+
return `⚠️ 配置修改失败:${e instanceof Error ? e.message : String(e)}`;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 斜杠命令注册表
|
|
3
|
+
*
|
|
4
|
+
* 通过 SDK 的 slashCommand 中间件统一注册所有内置命令。
|
|
5
|
+
* 每个命令拆分为独立文件,此处仅编排。
|
|
6
|
+
*/
|
|
7
|
+
import type { SlashCommand } from '@tencent-connect/qqbot-nodejs';
|
|
8
|
+
import type { PluginRuntime } from 'openclaw/plugin-sdk';
|
|
9
|
+
import type { ResolvedQQBotAccount } from '../types.js';
|
|
10
|
+
import { botHelp } from './bot-help.js';
|
|
11
|
+
import { botPing } from './bot-ping.js';
|
|
12
|
+
import { botVersion } from './bot-version.js';
|
|
13
|
+
import { botMe } from './bot-me.js';
|
|
14
|
+
import { botUpgrade } from './bot-upgrade.js';
|
|
15
|
+
import { botStreaming } from './bot-streaming.js';
|
|
16
|
+
import { botClearStorage } from './bot-clear-storage.js';
|
|
17
|
+
import { botLogs } from './bot-logs.js';
|
|
18
|
+
import { botApprove } from './bot-approve.js';
|
|
19
|
+
import { botGroupAlways } from './bot-group-always.js';
|
|
20
|
+
import { botPairing } from './bot-pairing.js';
|
|
21
|
+
|
|
22
|
+
export interface CommandBuildOptions {
|
|
23
|
+
getRuntime: () => PluginRuntime;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* 构建标准命令列表(匹配后直接回复,不进入 AI)
|
|
28
|
+
*/
|
|
29
|
+
export function buildCommandList(account: ResolvedQQBotAccount, opts: CommandBuildOptions): SlashCommand[] {
|
|
30
|
+
const commands: SlashCommand[] = [];
|
|
31
|
+
|
|
32
|
+
// help 需要访问完整命令列表,延迟绑定
|
|
33
|
+
const help = botHelp(account, () => commands);
|
|
34
|
+
commands.push(
|
|
35
|
+
help,
|
|
36
|
+
botPing(),
|
|
37
|
+
botVersion(account),
|
|
38
|
+
botMe(),
|
|
39
|
+
botUpgrade(account),
|
|
40
|
+
botLogs(opts.getRuntime()),
|
|
41
|
+
botStreaming(account, opts.getRuntime),
|
|
42
|
+
botClearStorage(account),
|
|
43
|
+
botApprove(opts.getRuntime),
|
|
44
|
+
botGroupAlways(account, opts.getRuntime),
|
|
45
|
+
botPairing(opts.getRuntime),
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
return commands;
|
|
49
|
+
}
|
package/src/config.ts
CHANGED
|
@@ -79,7 +79,10 @@ interface QQBotChannelConfig extends QQBotAccountConfig {
|
|
|
79
79
|
const DEFAULT_GROUP_POLICY: GroupPolicy = "open";
|
|
80
80
|
|
|
81
81
|
/** 群历史缓存条数默认值 */
|
|
82
|
-
const DEFAULT_GROUP_HISTORY_LIMIT =
|
|
82
|
+
const DEFAULT_GROUP_HISTORY_LIMIT = 20;
|
|
83
|
+
|
|
84
|
+
/** 单条消息默认处理超时(0 = 不限制) */
|
|
85
|
+
const DEFAULT_PROCESSING_TIMEOUT_MS = 0;
|
|
83
86
|
|
|
84
87
|
const DEFAULT_GROUP_CONFIG: Omit<Required<GroupConfig>, "prompt"> = {
|
|
85
88
|
requireMention: true,
|
|
@@ -110,8 +113,9 @@ export function resolveGroupAllowFrom(cfg: OpenClawConfig, accountId?: string):
|
|
|
110
113
|
|
|
111
114
|
/** 检查指定群是否被允许(使用标准策略引擎) */
|
|
112
115
|
export function isGroupAllowed(cfg: OpenClawConfig, groupOpenid: string, accountId?: string): boolean {
|
|
113
|
-
const
|
|
114
|
-
const
|
|
116
|
+
const account = resolveQQBotAccount(cfg, accountId);
|
|
117
|
+
const policy = account.config?.groupPolicy ?? DEFAULT_GROUP_POLICY;
|
|
118
|
+
const allowList = (account.config?.groupAllowFrom ?? []).map((id) => String(id).trim().toUpperCase());
|
|
115
119
|
const allowlistConfigured = allowList.length > 0;
|
|
116
120
|
const allowlistMatched = allowList.some((id) => id === "*" || id === groupOpenid.toUpperCase());
|
|
117
121
|
|
|
@@ -122,16 +126,12 @@ export function isGroupAllowed(cfg: OpenClawConfig, groupOpenid: string, account
|
|
|
122
126
|
}).allowed;
|
|
123
127
|
}
|
|
124
128
|
|
|
125
|
-
type ResolvedGroupConfig =
|
|
129
|
+
export type ResolvedGroupConfig = Required<GroupConfig>;
|
|
126
130
|
|
|
127
|
-
|
|
128
|
-
export function resolveGroupConfig(cfg: OpenClawConfig, groupOpenid: string, accountId?: string): ResolvedGroupConfig {
|
|
129
|
-
const account = resolveQQBotAccount(cfg, accountId);
|
|
131
|
+
export function resolveGroupConfigFromAccount(account: ResolvedQQBotAccount, groupOpenid: string): ResolvedGroupConfig {
|
|
130
132
|
const groups = account.config?.groups ?? {};
|
|
131
|
-
|
|
132
133
|
const wildcardCfg = groups["*"] ?? {};
|
|
133
134
|
const specificCfg = groups[groupOpenid] ?? {};
|
|
134
|
-
// 账户级默认值:defaultRequireMention 配置 > 硬编码默认 true
|
|
135
135
|
const accountDefaultRequireMention = account.config?.defaultRequireMention ?? DEFAULT_GROUP_CONFIG.requireMention;
|
|
136
136
|
|
|
137
137
|
return {
|
|
@@ -139,11 +139,15 @@ export function resolveGroupConfig(cfg: OpenClawConfig, groupOpenid: string, acc
|
|
|
139
139
|
ignoreOtherMentions: specificCfg.ignoreOtherMentions ?? wildcardCfg.ignoreOtherMentions ?? DEFAULT_GROUP_CONFIG.ignoreOtherMentions,
|
|
140
140
|
toolPolicy: specificCfg.toolPolicy ?? wildcardCfg.toolPolicy ?? DEFAULT_GROUP_CONFIG.toolPolicy,
|
|
141
141
|
name: specificCfg.name ?? wildcardCfg.name ?? DEFAULT_GROUP_CONFIG.name,
|
|
142
|
-
prompt: specificCfg.prompt ?? wildcardCfg.prompt,
|
|
142
|
+
prompt: specificCfg.prompt ?? wildcardCfg.prompt ?? DEFAULT_GROUP_PROMPT,
|
|
143
143
|
historyLimit: specificCfg.historyLimit ?? wildcardCfg.historyLimit ?? DEFAULT_GROUP_CONFIG.historyLimit,
|
|
144
144
|
};
|
|
145
145
|
}
|
|
146
146
|
|
|
147
|
+
export function resolveGroupConfig(cfg: OpenClawConfig, groupOpenid: string, accountId?: string): ResolvedGroupConfig {
|
|
148
|
+
return resolveGroupConfigFromAccount(resolveQQBotAccount(cfg, accountId), groupOpenid);
|
|
149
|
+
}
|
|
150
|
+
|
|
147
151
|
/** 解析群历史消息缓存条数 */
|
|
148
152
|
export function resolveHistoryLimit(cfg: OpenClawConfig, groupOpenid: string, accountId?: string): number {
|
|
149
153
|
return Math.max(0, resolveGroupConfig(cfg, groupOpenid, accountId).historyLimit);
|
|
@@ -151,10 +155,7 @@ export function resolveHistoryLimit(cfg: OpenClawConfig, groupOpenid: string, ac
|
|
|
151
155
|
|
|
152
156
|
/** 解析群行为 PE(具体群 > "*" > 默认值) */
|
|
153
157
|
export function resolveGroupPrompt(cfg: OpenClawConfig, groupOpenid: string, accountId?: string): string {
|
|
154
|
-
|
|
155
|
-
const groups = account.config?.groups ?? {};
|
|
156
|
-
|
|
157
|
-
return groups[groupOpenid]?.prompt ?? groups["*"]?.prompt ?? DEFAULT_GROUP_PROMPT;
|
|
158
|
+
return resolveGroupConfig(cfg, groupOpenid, accountId).prompt;
|
|
158
159
|
}
|
|
159
160
|
|
|
160
161
|
/** 解析群是否需要 @机器人才响应 */
|
|
@@ -232,6 +233,25 @@ export function resolveDefaultQQBotAccountId(cfg: OpenClawConfig): string {
|
|
|
232
233
|
return DEFAULT_ACCOUNT_ID;
|
|
233
234
|
}
|
|
234
235
|
|
|
236
|
+
/**
|
|
237
|
+
* 解析单条消息处理超时时间(ms)。
|
|
238
|
+
* 优先级:账户配置 > 环境变量 OPENCLAW_PROCESSING_TIMEOUT_MS > 默认
|
|
239
|
+
* 返回 0 表示不限制超时。
|
|
240
|
+
*/
|
|
241
|
+
export function resolveProcessingTimeoutMs(
|
|
242
|
+
accountConfig?: QQBotAccountConfig,
|
|
243
|
+
): number {
|
|
244
|
+
if (accountConfig?.processingTimeoutMs !== undefined) {
|
|
245
|
+
return accountConfig.processingTimeoutMs;
|
|
246
|
+
}
|
|
247
|
+
const env = process.env.OPENCLAW_PROCESSING_TIMEOUT_MS;
|
|
248
|
+
if (env) {
|
|
249
|
+
const v = Number(env);
|
|
250
|
+
if (!Number.isNaN(v) && v >= 0) return v;
|
|
251
|
+
}
|
|
252
|
+
return DEFAULT_PROCESSING_TIMEOUT_MS;
|
|
253
|
+
}
|
|
254
|
+
|
|
235
255
|
/**
|
|
236
256
|
* 解析 QQBot 账户配置
|
|
237
257
|
*/
|
|
@@ -288,20 +308,29 @@ export function resolveQQBotAccount(
|
|
|
288
308
|
clientSecret,
|
|
289
309
|
secretSource,
|
|
290
310
|
systemPrompt: accountConfig.systemPrompt,
|
|
291
|
-
imageServerBaseUrl: accountConfig.imageServerBaseUrl || process.env.QQBOT_IMAGE_SERVER_BASE_URL,
|
|
292
311
|
markdownSupport: accountConfig.markdownSupport !== false,
|
|
293
312
|
userAgentSuffix: resolveUserAgentSuffix(cfg),
|
|
294
|
-
|
|
313
|
+
processingTimeoutMs: resolveProcessingTimeoutMs(accountConfig),
|
|
314
|
+
config: normalizeAccountConfig(accountConfig),
|
|
295
315
|
};
|
|
296
316
|
}
|
|
297
317
|
|
|
318
|
+
/** 兼容旧版 streaming: boolean 格式 → { mode: "partial" | "off" },对齐框架 schema */
|
|
319
|
+
function normalizeAccountConfig(raw: QQBotAccountConfig): QQBotAccountConfig {
|
|
320
|
+
if (typeof (raw as any).streaming === 'boolean') {
|
|
321
|
+
const { streaming, ...rest } = raw as any;
|
|
322
|
+
return { ...rest, streaming: { mode: streaming ? 'partial' : 'off' } };
|
|
323
|
+
}
|
|
324
|
+
return raw;
|
|
325
|
+
}
|
|
326
|
+
|
|
298
327
|
/**
|
|
299
328
|
* 应用账户配置
|
|
300
329
|
*/
|
|
301
330
|
export function applyQQBotAccountConfig(
|
|
302
331
|
cfg: OpenClawConfig,
|
|
303
332
|
accountId: string,
|
|
304
|
-
input: { appId?: string; clientSecret?: string; clientSecretFile?: string; name?: string
|
|
333
|
+
input: { appId?: string; clientSecret?: string; clientSecretFile?: string; name?: string }
|
|
305
334
|
): OpenClawConfig {
|
|
306
335
|
const next = { ...cfg };
|
|
307
336
|
|
|
@@ -323,7 +352,6 @@ export function applyQQBotAccountConfig(
|
|
|
323
352
|
? { clientSecretFile: input.clientSecretFile }
|
|
324
353
|
: {}),
|
|
325
354
|
...(input.name ? { name: input.name } : {}),
|
|
326
|
-
...(input.imageServerBaseUrl ? { imageServerBaseUrl: input.imageServerBaseUrl } : {}),
|
|
327
355
|
},
|
|
328
356
|
};
|
|
329
357
|
} else {
|
|
@@ -349,7 +377,6 @@ export function applyQQBotAccountConfig(
|
|
|
349
377
|
? { clientSecretFile: input.clientSecretFile }
|
|
350
378
|
: {}),
|
|
351
379
|
...(input.name ? { name: input.name } : {}),
|
|
352
|
-
...(input.imageServerBaseUrl ? { imageServerBaseUrl: input.imageServerBaseUrl } : {}),
|
|
353
380
|
},
|
|
354
381
|
},
|
|
355
382
|
},
|