@openclaw/qqbot 2026.5.3 → 2026.5.4-beta.2
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/api.js +15 -3
- package/dist/{channel-N6Y_Rcjp.js → channel-CC2YO9fj.js} +1 -1
- package/dist/channel-plugin-api.js +1 -1
- package/dist/{gateway-CmSUJKSt.js → gateway-Cs3-_on9.js} +33 -6
- package/dist/{request-context-DXtpwWui.js → request-context-Cjwx7OwW.js} +7 -5
- package/package.json +5 -5
package/dist/api.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { C as recordMessageReply, E as setOutboundAudioPort, S as getMessageReplyStats, T as OUTBOUND_ERROR_CODES, _ as sendVoice, a as sendText, b as checkMessageReplyLimit, d as buildMediaTarget, f as parseTarget, g as sendVideoMsg, h as sendPhoto, i as sendProactiveMessage, m as sendDocument, n as sendCronMessage, p as resolveOutboundMediaPath, r as sendMedia, v as resolveUserFacingMediaError, w as DEFAULT_MEDIA_SEND_ERROR, x as getMessageReplyConfig, y as MESSAGE_REPLY_LIMIT } from "./outbound-BJfhwrPg.js";
|
|
2
2
|
import { a as resolveQQBotAccount, i as resolveDefaultQQBotAccountId, n as applyQQBotAccountConfig, r as listQQBotAccountIds, t as DEFAULT_ACCOUNT_ID } from "./config-D6545NkC.js";
|
|
3
|
-
import { t as qqbotPlugin } from "./channel-
|
|
3
|
+
import { t as qqbotPlugin } from "./channel-CC2YO9fj.js";
|
|
4
4
|
import { C as debugLog, L as formatErrorMessage, S as debugError, o as getAccessToken } from "./sender-p-B14eLG.js";
|
|
5
5
|
import { t as qqbotSetupPlugin } from "./channel.setup-ByCRAe5H.js";
|
|
6
|
-
import { r as getFrameworkCommands, t as getRequestContext } from "./request-context-
|
|
6
|
+
import { r as getFrameworkCommands, t as getRequestContext } from "./request-context-Cjwx7OwW.js";
|
|
7
7
|
import { callGatewayTool } from "openclaw/plugin-sdk/agent-harness-runtime";
|
|
8
8
|
//#region extensions/qqbot/src/engine/tools/channel-api.ts
|
|
9
9
|
/**
|
|
@@ -544,7 +544,7 @@ function buildFrameworkSlashContext({ ctx, account, from, commandName }) {
|
|
|
544
544
|
accountId: account.accountId,
|
|
545
545
|
appId: account.appId,
|
|
546
546
|
accountConfig: account.config,
|
|
547
|
-
commandAuthorized:
|
|
547
|
+
commandAuthorized: ctx.isAuthorizedSender,
|
|
548
548
|
queueSnapshot: { ...DEFAULT_QUEUE_SNAPSHOT }
|
|
549
549
|
};
|
|
550
550
|
}
|
|
@@ -612,13 +612,25 @@ async function dispatchFrameworkSlashResult({ result, account, from, logger }) {
|
|
|
612
612
|
}
|
|
613
613
|
//#endregion
|
|
614
614
|
//#region extensions/qqbot/src/bridge/commands/framework-registration.ts
|
|
615
|
+
const PRIVATE_CHAT_ONLY_TEXT = "💡 请在私聊中使用此指令";
|
|
616
|
+
function isExplicitQQBotC2cFrom(from) {
|
|
617
|
+
const raw = (from ?? "").trim();
|
|
618
|
+
const stripped = raw.replace(/^qqbot:/iu, "");
|
|
619
|
+
const colonIdx = stripped.indexOf(":");
|
|
620
|
+
if (colonIdx === -1) return false;
|
|
621
|
+
const kind = stripped.slice(0, colonIdx).toLowerCase();
|
|
622
|
+
const targetId = stripped.slice(colonIdx + 1).trim();
|
|
623
|
+
return /^qqbot:/iu.test(raw) && kind === "c2c" && targetId.length > 0;
|
|
624
|
+
}
|
|
615
625
|
function registerQQBotFrameworkCommands(api) {
|
|
616
626
|
for (const cmd of getFrameworkCommands()) api.registerCommand({
|
|
617
627
|
name: cmd.name,
|
|
618
628
|
description: cmd.description,
|
|
629
|
+
channels: ["qqbot"],
|
|
619
630
|
requireAuth: true,
|
|
620
631
|
acceptsArgs: true,
|
|
621
632
|
handler: async (ctx) => {
|
|
633
|
+
if (cmd.c2cOnly && !isExplicitQQBotC2cFrom(ctx.from)) return { text: PRIVATE_CHAT_ONLY_TEXT };
|
|
622
634
|
const from = parseQQBotFrom(ctx.from);
|
|
623
635
|
const account = resolveQQBotAccount(ctx.config, ctx.accountId ?? void 0);
|
|
624
636
|
const slashCtx = buildFrameworkSlashContext({
|
|
@@ -344,7 +344,7 @@ function clearAccountCredentials(cfg, accountId) {
|
|
|
344
344
|
//#region extensions/qqbot/src/channel.ts
|
|
345
345
|
let _gatewayModulePromise;
|
|
346
346
|
function loadGatewayModule() {
|
|
347
|
-
_gatewayModulePromise ??= import("./gateway-
|
|
347
|
+
_gatewayModulePromise ??= import("./gateway-Cs3-_on9.js");
|
|
348
348
|
return _gatewayModulePromise;
|
|
349
349
|
}
|
|
350
350
|
const EXEC_APPROVAL_COMMAND_RE = /\/approve(?:@[^\s]+)?\s+[A-Za-z0-9][A-Za-z0-9._:-]*\s+(?:allow-once|allow-always|always|deny)\b/i;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as qqbotPlugin } from "./channel-
|
|
1
|
+
import { t as qqbotPlugin } from "./channel-CC2YO9fj.js";
|
|
2
2
|
export { qqbotPlugin };
|
|
@@ -6,7 +6,7 @@ import { t as toGatewayAccount } from "./narrowing-BoieBTIU.js";
|
|
|
6
6
|
import { B as StreamInputState, C as debugLog, E as getNextMsgSeq, I as formatDuration, L as formatErrorMessage, N as getImageMimeType, P as getMaxUploadSize, R as StreamContentType, S as debugError, a as createRawInputNotifyFn, b as withTokenRetry, c as getMessageApi, d as initSender, f as onMessageSent, g as sendText, h as sendMedia$1, i as clearTokenCache, j as formatFileSize, k as downloadFile, l as getPluginUserAgent, m as sendInputNotify, n as acknowledgeInteraction, o as getAccessToken, p as registerAccount, r as buildDeliveryTarget, s as getGatewayUrl, t as accountToCreds, u as initApiConfig, v as startBackgroundTokenRefresh, w as debugWarn, x as openLocalFile, y as stopBackgroundTokenRefresh, z as StreamInputMode } from "./sender-p-B14eLG.js";
|
|
7
7
|
import { n as getQQBotRuntimeForEngine, t as getQQBotRuntime } from "./runtime-BJAS3eXW.js";
|
|
8
8
|
import { a as getHomeDir, c as getQQBotMediaDir, d as isLocalPath, f as isWindows, i as checkSilkWasmAvailable, m as resolveQQBotPayloadLocalFilePath, o as getQQBotDataDir, p as normalizePath$1, s as getQQBotDataPath, u as getTempDir } from "./target-parser-Y0prnrXD.js";
|
|
9
|
-
import { a as getPluginVersion, i as getFrameworkVersion, n as runWithRequestContext, o as initCommands, s as matchSlashCommand } from "./request-context-
|
|
9
|
+
import { a as getPluginVersion, i as getFrameworkVersion, n as runWithRequestContext, o as initCommands, s as matchSlashCommand } from "./request-context-Cjwx7OwW.js";
|
|
10
10
|
import * as fs$1 from "node:fs";
|
|
11
11
|
import fs from "node:fs";
|
|
12
12
|
import * as os$1 from "node:os";
|
|
@@ -642,22 +642,47 @@ function buildResultBase(ctx) {
|
|
|
642
642
|
* A wide-open DM policy means "anyone can chat", not "anyone can run
|
|
643
643
|
* admin commands".
|
|
644
644
|
*/
|
|
645
|
+
function isSlashCommandAuthEntry(value) {
|
|
646
|
+
return typeof value === "string" || typeof value === "number";
|
|
647
|
+
}
|
|
648
|
+
function readSlashCommandAuthList(value) {
|
|
649
|
+
if (!Array.isArray(value)) return;
|
|
650
|
+
return value.filter(isSlashCommandAuthEntry);
|
|
651
|
+
}
|
|
652
|
+
/**
|
|
653
|
+
* Resolve the command-specific QQBot allowlist from the root OpenClaw config.
|
|
654
|
+
*
|
|
655
|
+
* `commands.allowFrom.qqbot` takes precedence over the global
|
|
656
|
+
* `commands.allowFrom["*"]`, matching the framework command authorization
|
|
657
|
+
* contract used by registered plugin commands.
|
|
658
|
+
*/
|
|
659
|
+
function resolveQQBotCommandsAllowFrom(cfg) {
|
|
660
|
+
if (!cfg || typeof cfg !== "object") return;
|
|
661
|
+
const commands = cfg.commands;
|
|
662
|
+
if (!commands || typeof commands !== "object") return;
|
|
663
|
+
const allowFrom = commands.allowFrom;
|
|
664
|
+
if (!allowFrom || typeof allowFrom !== "object" || Array.isArray(allowFrom)) return;
|
|
665
|
+
const byProvider = allowFrom;
|
|
666
|
+
return readSlashCommandAuthList(byProvider.qqbot) ?? readSlashCommandAuthList(byProvider["*"]);
|
|
667
|
+
}
|
|
645
668
|
/**
|
|
646
669
|
* Determine whether `senderId` is authorized to execute `requireAuth`
|
|
647
670
|
* slash commands for the given account configuration.
|
|
648
671
|
*
|
|
649
672
|
* Authorization rules:
|
|
673
|
+
* - `commands.allowFrom.qqbot` / `commands.allowFrom["*"]` configured →
|
|
674
|
+
* use that command-specific list instead of channel allowFrom
|
|
650
675
|
* - `allowFrom` not configured / empty / only `["*"]` → **false**
|
|
651
676
|
* (wildcard means "open to everyone", not explicit authorization)
|
|
652
677
|
* - `allowFrom` contains at least one concrete entry AND sender
|
|
653
|
-
* matches → **true**
|
|
678
|
+
* matches a concrete entry → **true**
|
|
654
679
|
* - Group messages use `groupAllowFrom` when present, falling back
|
|
655
680
|
* to `allowFrom`.
|
|
656
681
|
*/
|
|
657
682
|
function resolveSlashCommandAuth(params) {
|
|
658
|
-
const
|
|
659
|
-
if (
|
|
660
|
-
return createQQBotSenderMatcher(params.senderId)(
|
|
683
|
+
const explicitEntries = normalizeQQBotAllowFrom(params.commandsAllowFrom ?? (params.isGroup && params.groupAllowFrom && params.groupAllowFrom.length > 0 ? params.groupAllowFrom : params.allowFrom)).filter((entry) => entry !== "*");
|
|
684
|
+
if (explicitEntries.length === 0) return false;
|
|
685
|
+
return createQQBotSenderMatcher(params.senderId)(explicitEntries);
|
|
661
686
|
}
|
|
662
687
|
//#endregion
|
|
663
688
|
//#region extensions/qqbot/src/engine/commands/slash-command-handler.ts
|
|
@@ -697,7 +722,8 @@ async function trySlashCommand(msg, ctx) {
|
|
|
697
722
|
senderId: msg.senderId,
|
|
698
723
|
isGroup: msg.type === "group" || msg.type === "guild",
|
|
699
724
|
allowFrom: account.config?.allowFrom,
|
|
700
|
-
groupAllowFrom: account.config?.groupAllowFrom
|
|
725
|
+
groupAllowFrom: account.config?.groupAllowFrom,
|
|
726
|
+
commandsAllowFrom: resolveQQBotCommandsAllowFrom(ctx.cfg)
|
|
701
727
|
}),
|
|
702
728
|
queueSnapshot: ctx.getQueueSnapshot(peerId)
|
|
703
729
|
};
|
|
@@ -1830,6 +1856,7 @@ var GatewayConnection = class {
|
|
|
1830
1856
|
this.currentWs = ws;
|
|
1831
1857
|
const slashCtx = {
|
|
1832
1858
|
account,
|
|
1859
|
+
cfg: this.ctx.cfg,
|
|
1833
1860
|
log,
|
|
1834
1861
|
getMessagePeerId: (msg) => this.msgQueue.getMessagePeerId(msg),
|
|
1835
1862
|
getQueueSnapshot: (peerId) => this.msgQueue.getSnapshot(peerId)
|
|
@@ -673,6 +673,7 @@ function registerStreamingCommands(registry) {
|
|
|
673
673
|
registry.register({
|
|
674
674
|
name: "bot-streaming",
|
|
675
675
|
description: "一键开关流式消息",
|
|
676
|
+
requireAuth: true,
|
|
676
677
|
c2cOnly: true,
|
|
677
678
|
usage: [
|
|
678
679
|
`/bot-streaming on 开启流式消息`,
|
|
@@ -781,8 +782,8 @@ function lc(s) {
|
|
|
781
782
|
* Slash command registry.
|
|
782
783
|
*
|
|
783
784
|
* Maintains two maps:
|
|
784
|
-
* - `commands` —
|
|
785
|
-
* - `frameworkCommands` — auth-gated commands
|
|
785
|
+
* - `commands` — QQBot message-flow commands
|
|
786
|
+
* - `frameworkCommands` — auth-gated commands that are safe on the framework surface
|
|
786
787
|
*/
|
|
787
788
|
var SlashCommandRegistry = class {
|
|
788
789
|
constructor() {
|
|
@@ -795,12 +796,13 @@ var SlashCommandRegistry = class {
|
|
|
795
796
|
this.commands.set(key, cmd);
|
|
796
797
|
if (cmd.requireAuth) this.frameworkCommands.set(key, cmd);
|
|
797
798
|
}
|
|
798
|
-
/** Return all
|
|
799
|
+
/** Return all commands that may be registered on the framework surface. */
|
|
799
800
|
getFrameworkCommands() {
|
|
800
801
|
return Array.from(this.frameworkCommands.values()).map((cmd) => ({
|
|
801
802
|
name: cmd.name,
|
|
802
803
|
description: cmd.description,
|
|
803
804
|
usage: cmd.usage,
|
|
805
|
+
c2cOnly: cmd.c2cOnly,
|
|
804
806
|
handler: cmd.handler
|
|
805
807
|
}));
|
|
806
808
|
}
|
|
@@ -854,8 +856,8 @@ function initCommands(port) {
|
|
|
854
856
|
initSlashCommandDeps(port);
|
|
855
857
|
}
|
|
856
858
|
/**
|
|
857
|
-
* Return
|
|
858
|
-
*
|
|
859
|
+
* Return commands that may be registered with the framework via
|
|
860
|
+
* api.registerCommand() in registerFull().
|
|
859
861
|
*/
|
|
860
862
|
function getFrameworkCommands() {
|
|
861
863
|
return registry.getFrameworkCommands();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openclaw/qqbot",
|
|
3
|
-
"version": "2026.5.
|
|
3
|
+
"version": "2026.5.4-beta.2",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "OpenClaw QQ Bot channel plugin",
|
|
6
6
|
"repository": {
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"mpg123-decoder": "^1.0.3",
|
|
14
14
|
"silk-wasm": "^3.7.1",
|
|
15
15
|
"ws": "^8.20.0",
|
|
16
|
-
"zod": "^4.4.
|
|
16
|
+
"zod": "^4.4.3"
|
|
17
17
|
},
|
|
18
18
|
"devDependencies": {
|
|
19
19
|
"@openclaw/plugin-sdk": "workspace:*",
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"openclaw": "workspace:*"
|
|
22
22
|
},
|
|
23
23
|
"peerDependencies": {
|
|
24
|
-
"openclaw": ">=2026.5.
|
|
24
|
+
"openclaw": ">=2026.5.4-beta.2"
|
|
25
25
|
},
|
|
26
26
|
"peerDependenciesMeta": {
|
|
27
27
|
"openclaw": {
|
|
@@ -50,10 +50,10 @@
|
|
|
50
50
|
"minHostVersion": ">=2026.4.10"
|
|
51
51
|
},
|
|
52
52
|
"compat": {
|
|
53
|
-
"pluginApi": ">=2026.5.
|
|
53
|
+
"pluginApi": ">=2026.5.4-beta.2"
|
|
54
54
|
},
|
|
55
55
|
"build": {
|
|
56
|
-
"openclawVersion": "2026.5.
|
|
56
|
+
"openclawVersion": "2026.5.4-beta.2"
|
|
57
57
|
},
|
|
58
58
|
"release": {
|
|
59
59
|
"publishToClawHub": true,
|