@openclaw/qqbot 2026.7.1-beta.1 → 2026.7.1-beta.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/dist/api.js CHANGED
@@ -1,8 +1,8 @@
1
- import { t as qqbotPlugin } from "./channel-Bh0MrYvU.js";
1
+ import { t as qqbotPlugin } from "./channel-D1UztsnG.js";
2
2
  import { a as resolveQQBotAccount, i as resolveDefaultQQBotAccountId, n as applyQQBotAccountConfig, r as listQQBotAccountIds, t as DEFAULT_ACCOUNT_ID } from "./config-C1qZbh0K.js";
3
- import { t as qqbotSetupPlugin } from "./channel.setup-CldhUlTO.js";
4
- import { o as getFrameworkCommands } from "./group-DQQsZ6Y0.js";
5
- import { C as getMessageReplyConfig, D as OUTBOUND_ERROR_CODES, E as DEFAULT_MEDIA_SEND_ERROR, O as setOutboundAudioPort, S as checkMessageReplyLimit, T as recordMessageReply, _ as sendVideoMsg, a as sendText, b as resolveUserFacingMediaError, f as buildMediaTarget, g as sendPhoto, h as sendDocument, i as sendProactiveMessage, m as resolveOutboundMediaPath, n as sendCronMessage, p as parseTarget, r as sendMedia, v as sendVoice, w as getMessageReplyStats, x as MESSAGE_REPLY_LIMIT } from "./outbound-Dfa2uOEp.js";
6
- import { n as registerRemindTool, r as registerChannelTool, t as registerQQBotTools } from "./tools-BvXe7bTq.js";
7
- import { t as registerQQBotFull } from "./channel-entry-LMtNY-J6.js";
3
+ import { t as qqbotSetupPlugin } from "./channel.setup-2ItDYKhz.js";
4
+ import { o as getFrameworkCommands } from "./group-o0GmovSf.js";
5
+ import { A as OUTBOUND_ERROR_CODES, C as resolveUserFacingMediaError, D as getMessageReplyStats, E as getMessageReplyConfig, O as recordMessageReply, T as checkMessageReplyLimit, _ as sendVideoMsg, a as sendText, f as buildMediaTarget, g as sendPhoto, h as sendDocument, i as sendProactiveMessage, j as setOutboundAudioPort, k as DEFAULT_MEDIA_SEND_ERROR, m as resolveOutboundMediaPath, n as sendCronMessage, p as parseTarget, r as sendMedia, v as sendVoice, w as MESSAGE_REPLY_LIMIT } from "./outbound-BIrfvvFJ.js";
6
+ import { n as registerRemindTool, r as registerChannelTool, t as registerQQBotTools } from "./tools-UJJ-tLHP.js";
7
+ import { t as registerQQBotFull } from "./channel-entry-C5YdhX3Y.js";
8
8
  export { DEFAULT_ACCOUNT_ID, DEFAULT_MEDIA_SEND_ERROR, MESSAGE_REPLY_LIMIT, OUTBOUND_ERROR_CODES, applyQQBotAccountConfig, buildMediaTarget, checkMessageReplyLimit, getFrameworkCommands, getMessageReplyConfig, getMessageReplyStats, listQQBotAccountIds, parseTarget, qqbotPlugin, qqbotSetupPlugin, recordMessageReply, registerChannelTool, registerQQBotFull, registerQQBotTools, registerRemindTool, resolveDefaultQQBotAccountId, resolveOutboundMediaPath, resolveQQBotAccount, resolveUserFacingMediaError, sendCronMessage, sendDocument, sendMedia, sendPhoto, sendProactiveMessage, sendText, sendVideoMsg, sendVoice, setOutboundAudioPort };
@@ -1,26 +1,36 @@
1
1
  import { t as asOptionalObjectRecord } from "./string-normalize-R_0cKO7Q.js";
2
- import { a as qqbotSetupAdapterShared, i as qqbotMeta, n as qqbotSetupWizard, o as ensurePlatformAdapter, r as qqbotConfigAdapter, s as getBridgeLogger, t as qqbotChannelConfigSchema } from "./config-schema-gMW9zKvQ.js";
2
+ import { a as qqbotSetupAdapterShared, i as qqbotMeta, n as qqbotSetupWizard, o as ensurePlatformAdapter, r as qqbotConfigAdapter, s as getBridgeLogger, t as qqbotChannelConfigSchema } from "./config-schema-JZEf1dvB.js";
3
3
  import { a as resolveQQBotAccount, n as applyQQBotAccountConfig, r as listQQBotAccountIds, t as DEFAULT_ACCOUNT_ID$1 } from "./config-C1qZbh0K.js";
4
- import { t as getQQBotRuntime } from "./runtime-BL0xZzWe.js";
4
+ import { t as getQQBotRuntime } from "./runtime-DodcT_fQ.js";
5
5
  import { n as legacyConfigRules, r as normalizeCompatibilityConfig, t as buildQQBotStateKey } from "./state-keys-CQKlAFyo.js";
6
- import { n as normalizeTarget, t as looksLikeQQBotTarget } from "./target-parser-DagYRQkP.js";
6
+ import { n as normalizeTarget, r as parseTarget, t as looksLikeQQBotTarget } from "./target-parser-DagYRQkP.js";
7
7
  import { getExecApprovalReplyMetadata } from "openclaw/plugin-sdk/approval-runtime";
8
+ import { buildChannelOutboundSessionRoute } from "openclaw/plugin-sdk/channel-core";
8
9
  import { createMessageReceiptFromOutboundResults, defineChannelMessageAdapter } from "openclaw/plugin-sdk/channel-outbound";
10
+ import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime";
9
11
  import { sanitizeAssistantVisibleText } from "openclaw/plugin-sdk/text-chunking";
10
12
  import { createChannelApprovalCapability } from "openclaw/plugin-sdk/approval-delivery-runtime";
11
13
  import { createLazyChannelApprovalNativeRuntimeAdapter } from "openclaw/plugin-sdk/approval-handler-adapter-runtime";
12
14
  import { resolveApprovalRequestChannelAccountId, resolveApprovalRequestSessionConversation } from "openclaw/plugin-sdk/approval-native-runtime";
13
15
  import { normalizeLowercaseStringOrEmpty, normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
16
+ import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
14
17
  import { markImplicitSameChatApprovalAuthorization, resolveApprovalApprovers } from "openclaw/plugin-sdk/approval-auth-runtime";
15
18
  import { createChannelExecApprovalProfile, isChannelExecApprovalClientEnabledFromConfig, matchesApprovalRequestFilters } from "openclaw/plugin-sdk/approval-client-runtime";
16
19
  import { normalizeAccountId } from "openclaw/plugin-sdk/routing";
17
20
  import { resolveChannelGroupToolsPolicy } from "openclaw/plugin-sdk/channel-policy";
18
21
  //#region extensions/qqbot/src/engine/approval/index.ts
22
+ /**
23
+ * Approval helpers — pure functions, zero framework dependencies.
24
+ *
25
+ * - Build approval message text + inline keyboard
26
+ * - Resolve delivery target from session metadata
27
+ * - Parse INTERACTION_CREATE button data
28
+ */
19
29
  function buildExecApprovalText(request) {
20
30
  const expiresIn = Math.max(0, Math.round((request.expiresAtMs - Date.now()) / 1e3));
21
31
  const lines = ["🔐 命令执行审批", ""];
22
32
  const cmd = request.request.commandPreview ?? request.request.command ?? "";
23
- if (cmd) lines.push(`\`\`\`\n${cmd.slice(0, 300)}\n\`\`\``);
33
+ if (cmd) lines.push(`\`\`\`\n${truncateUtf16Safe(cmd, 300)}\n\`\`\``);
24
34
  if (request.request.cwd) lines.push(`\u{1f4c1} \u76ee\u5f55: ${request.request.cwd}`);
25
35
  if (request.request.agentId) lines.push(`\u{1f916} Agent: ${request.request.agentId}`);
26
36
  lines.push("", `\u23f1\ufe0f \u8d85\u65f6: ${expiresIn} \u79d2`);
@@ -365,7 +375,7 @@ function createQQBotApprovalCapability() {
365
375
  },
366
376
  load: async () => {
367
377
  ensurePlatformAdapter();
368
- return (await import("./handler-runtime-BQ72YPsH.js")).qqbotApprovalNativeRuntime;
378
+ return (await import("./handler-runtime-zQvT6SrI.js")).qqbotApprovalNativeRuntime;
369
379
  }
370
380
  })
371
381
  });
@@ -998,16 +1008,8 @@ function resolveQQBotGroupToolPolicy(params) {
998
1008
  }
999
1009
  //#endregion
1000
1010
  //#region extensions/qqbot/src/channel.ts
1001
- let gatewayModulePromise;
1002
- function loadGatewayModule() {
1003
- gatewayModulePromise ??= import("./gateway-BgfQAYxB.js");
1004
- return gatewayModulePromise;
1005
- }
1006
- let outboundMessagingModulePromise;
1007
- function loadOutboundMessagingModule() {
1008
- outboundMessagingModulePromise ??= import("./outbound-Dfa2uOEp.js").then((n) => n.t);
1009
- return outboundMessagingModulePromise;
1010
- }
1011
+ const loadGatewayModule = createLazyRuntimeModule(() => import("./gateway-pJQppxe4.js"));
1012
+ const loadOutboundMessagingModule = createLazyRuntimeModule(() => import("./outbound-BIrfvvFJ.js").then((n) => n.t));
1011
1013
  function createQQBotSendReceipt(params) {
1012
1014
  const messageId = params.messageId?.trim();
1013
1015
  return createMessageReceiptFromOutboundResults({
@@ -1020,6 +1022,25 @@ function createQQBotSendReceipt(params) {
1020
1022
  kind: params.kind
1021
1023
  });
1022
1024
  }
1025
+ function resolveQQBotOutboundSessionRoute(params) {
1026
+ const target = parseTarget(params.target);
1027
+ const chatType = target.type === "c2c" ? "direct" : "group";
1028
+ const qualifiedTarget = `qqbot:${target.type}:${target.id}`;
1029
+ return buildChannelOutboundSessionRoute({
1030
+ cfg: params.cfg,
1031
+ agentId: params.agentId,
1032
+ channel: "qqbot",
1033
+ accountId: params.accountId,
1034
+ recipientSessionExact: true,
1035
+ peer: {
1036
+ kind: chatType,
1037
+ id: target.id
1038
+ },
1039
+ chatType,
1040
+ from: qualifiedTarget,
1041
+ to: qualifiedTarget
1042
+ });
1043
+ }
1023
1044
  async function sendQQBotText(params) {
1024
1045
  await loadGatewayModule();
1025
1046
  const account = resolveQQBotAccount(params.cfg, params.accountId);
@@ -1029,7 +1050,10 @@ async function sendQQBotText(params) {
1029
1050
  text: params.text,
1030
1051
  accountId: params.accountId,
1031
1052
  replyToId: params.replyToId,
1032
- account: toGatewayAccount(account)
1053
+ account: toGatewayAccount(account),
1054
+ ...params.mediaAccess ? { mediaAccess: params.mediaAccess } : {},
1055
+ ...params.mediaLocalRoots ? { mediaLocalRoots: params.mediaLocalRoots } : {},
1056
+ ...params.mediaReadFile ? { mediaReadFile: params.mediaReadFile } : {}
1033
1057
  });
1034
1058
  return {
1035
1059
  channel: "qqbot",
@@ -1052,7 +1076,10 @@ async function sendQQBotMedia(params) {
1052
1076
  mediaUrl: params.mediaUrl ?? "",
1053
1077
  accountId: params.accountId,
1054
1078
  replyToId: params.replyToId,
1055
- account: toGatewayAccount(account)
1079
+ account: toGatewayAccount(account),
1080
+ ...params.mediaAccess ? { mediaAccess: params.mediaAccess } : {},
1081
+ ...params.mediaLocalRoots ? { mediaLocalRoots: params.mediaLocalRoots } : {},
1082
+ ...params.mediaReadFile ? { mediaReadFile: params.mediaReadFile } : {}
1056
1083
  });
1057
1084
  return {
1058
1085
  channel: "qqbot",
@@ -1065,6 +1092,14 @@ async function sendQQBotMedia(params) {
1065
1092
  meta: result.error ? { error: result.error } : void 0
1066
1093
  };
1067
1094
  }
1095
+ function resolveQQBotOutboundMediaAccessContext(ctx) {
1096
+ const record = ctx && typeof ctx === "object" ? ctx : void 0;
1097
+ return {
1098
+ ...record?.mediaAccess ? { mediaAccess: record.mediaAccess } : {},
1099
+ ...record?.mediaLocalRoots ? { mediaLocalRoots: record.mediaLocalRoots } : {},
1100
+ ...record?.mediaReadFile ? { mediaReadFile: record.mediaReadFile } : {}
1101
+ };
1102
+ }
1068
1103
  function toQQBotMessageSendResult(result) {
1069
1104
  if (result.meta?.error) throw new Error(result.meta.error);
1070
1105
  if (result.receipt.platformMessageIds.length === 0) throw new Error("QQBot message adapter send did not return a platform message id");
@@ -1086,7 +1121,8 @@ const qqbotMessageAdapter = defineChannelMessageAdapter({
1086
1121
  to: ctx.to,
1087
1122
  text: ctx.text,
1088
1123
  accountId: ctx.accountId,
1089
- replyToId: ctx.replyToId
1124
+ replyToId: ctx.replyToId,
1125
+ ...resolveQQBotOutboundMediaAccessContext(ctx)
1090
1126
  })),
1091
1127
  media: async (ctx) => toQQBotMessageSendResult(await sendQQBotMedia({
1092
1128
  cfg: ctx.cfg,
@@ -1094,7 +1130,8 @@ const qqbotMessageAdapter = defineChannelMessageAdapter({
1094
1130
  text: ctx.text,
1095
1131
  mediaUrl: ctx.mediaUrl,
1096
1132
  accountId: ctx.accountId,
1097
- replyToId: ctx.replyToId
1133
+ replyToId: ctx.replyToId,
1134
+ ...resolveQQBotOutboundMediaAccessContext(ctx)
1098
1135
  }))
1099
1136
  }
1100
1137
  });
@@ -1147,6 +1184,7 @@ const qqbotPlugin = {
1147
1184
  targetPrefixes: ["qqbot"],
1148
1185
  /** Normalize common QQ Bot target formats into the canonical qqbot:... form. */
1149
1186
  normalizeTarget,
1187
+ resolveOutboundSessionRoute: (params) => resolveQQBotOutboundSessionRoute(params),
1150
1188
  targetResolver: {
1151
1189
  /** Return true when the id looks like a QQ Bot target. */
1152
1190
  looksLikeId: looksLikeQQBotTarget,
@@ -1165,20 +1203,22 @@ const qqbotPlugin = {
1165
1203
  payload,
1166
1204
  hint
1167
1205
  }),
1168
- sendText: async ({ to, text, accountId, replyToId, cfg }) => await sendQQBotText({
1169
- cfg,
1170
- to,
1171
- text,
1172
- accountId,
1173
- replyToId
1206
+ sendText: async (ctx) => await sendQQBotText({
1207
+ cfg: ctx.cfg,
1208
+ to: ctx.to,
1209
+ text: ctx.text,
1210
+ accountId: ctx.accountId,
1211
+ replyToId: ctx.replyToId,
1212
+ ...resolveQQBotOutboundMediaAccessContext(ctx)
1174
1213
  }),
1175
- sendMedia: async ({ to, text, mediaUrl, accountId, replyToId, cfg }) => await sendQQBotMedia({
1176
- cfg,
1177
- to,
1178
- text,
1179
- mediaUrl,
1180
- accountId,
1181
- replyToId
1214
+ sendMedia: async (ctx) => await sendQQBotMedia({
1215
+ cfg: ctx.cfg,
1216
+ to: ctx.to,
1217
+ text: ctx.text,
1218
+ mediaUrl: ctx.mediaUrl,
1219
+ accountId: ctx.accountId,
1220
+ replyToId: ctx.replyToId,
1221
+ ...resolveQQBotOutboundMediaAccessContext(ctx)
1182
1222
  })
1183
1223
  },
1184
1224
  gateway: {
@@ -1214,7 +1254,8 @@ const qqbotPlugin = {
1214
1254
  ...ctx.getStatus(),
1215
1255
  running: true,
1216
1256
  connected: true,
1217
- lastConnectedAt: Date.now()
1257
+ lastConnectedAt: Date.now(),
1258
+ lastError: null
1218
1259
  });
1219
1260
  persistAccountCredentialSnapshot(account);
1220
1261
  },
@@ -1224,7 +1265,8 @@ const qqbotPlugin = {
1224
1265
  ...ctx.getStatus(),
1225
1266
  running: true,
1226
1267
  connected: true,
1227
- lastConnectedAt: Date.now()
1268
+ lastConnectedAt: Date.now(),
1269
+ lastError: null
1228
1270
  });
1229
1271
  persistAccountCredentialSnapshot(account);
1230
1272
  },
@@ -1234,6 +1276,14 @@ const qqbotPlugin = {
1234
1276
  ...ctx.getStatus(),
1235
1277
  lastError: error.message
1236
1278
  });
1279
+ },
1280
+ onDisconnected: ({ reason, fatal }) => {
1281
+ log?.info(`[qqbot:${account.accountId}] Gateway disconnected${reason ? `: ${reason}` : ""}`);
1282
+ ctx.setStatus({
1283
+ ...ctx.getStatus(),
1284
+ connected: false,
1285
+ ...fatal && reason ? { lastError: reason } : {}
1286
+ });
1237
1287
  }
1238
1288
  });
1239
1289
  },
@@ -1,7 +1,7 @@
1
1
  import { a as resolveQQBotAccount } from "./config-C1qZbh0K.js";
2
- import { d as PRIVATE_CHAT_ONLY_TEXT, n as resolveGroupCommandLevelFromAccountConfig, o as getFrameworkCommands } from "./group-DQQsZ6Y0.js";
3
- import { h as sendDocument } from "./outbound-Dfa2uOEp.js";
4
- import { t as registerQQBotTools } from "./tools-BvXe7bTq.js";
2
+ import { d as PRIVATE_CHAT_ONLY_TEXT, n as resolveGroupCommandLevelFromAccountConfig, o as getFrameworkCommands } from "./group-o0GmovSf.js";
3
+ import { h as sendDocument } from "./outbound-BIrfvvFJ.js";
4
+ import { t as registerQQBotTools } from "./tools-UJJ-tLHP.js";
5
5
  //#region extensions/qqbot/src/bridge/commands/framework-context-adapter.ts
6
6
  /**
7
7
  * Default queue snapshot used for framework-registered commands.
@@ -1,2 +1,2 @@
1
- import { t as registerQQBotFull } from "./channel-entry-LMtNY-J6.js";
1
+ import { t as registerQQBotFull } from "./channel-entry-C5YdhX3Y.js";
2
2
  export { registerQQBotFull };
@@ -1,2 +1,2 @@
1
- import { t as qqbotPlugin } from "./channel-Bh0MrYvU.js";
1
+ import { t as qqbotPlugin } from "./channel-D1UztsnG.js";
2
2
  export { qqbotPlugin };
@@ -1,4 +1,4 @@
1
- import { a as qqbotSetupAdapterShared, i as qqbotMeta, n as qqbotSetupWizard, r as qqbotConfigAdapter, t as qqbotChannelConfigSchema } from "./config-schema-gMW9zKvQ.js";
1
+ import { a as qqbotSetupAdapterShared, i as qqbotMeta, n as qqbotSetupWizard, r as qqbotConfigAdapter, t as qqbotChannelConfigSchema } from "./config-schema-JZEf1dvB.js";
2
2
  //#region extensions/qqbot/src/channel.setup.ts
3
3
  /**
4
4
  * Setup-only QQBot plugin — lightweight subset used during `openclaw onboard`
@@ -1,5 +1,6 @@
1
1
  import { d as registerPlatformAdapterFactory, l as hasPlatformAdapter, n as normalizeLowercaseStringOrEmpty, u as registerPlatformAdapter } from "./string-normalize-R_0cKO7Q.js";
2
2
  import { a as resolveQQBotAccount, c as describeAccount, i as resolveDefaultQQBotAccountId, l as formatAllowFrom, n as applyQQBotAccountConfig, r as listQQBotAccountIds, s as applyAccountConfig, u as isAccountConfigured } from "./config-C1qZbh0K.js";
3
+ import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime";
3
4
  import { buildSecretInputSchema, hasConfiguredSecretInput, normalizeResolvedSecretInputString, normalizeSecretInputString } from "openclaw/plugin-sdk/secret-input";
4
5
  import { resolvePreferredOpenClawTmpDir } from "openclaw/plugin-sdk/temp-path";
5
6
  import { applyAccountNameToChannelSection, deleteAccountFromConfigSection, setAccountEnabledInConfigSection } from "openclaw/plugin-sdk/core";
@@ -47,11 +48,7 @@ function getBridgeLogger() {
47
48
  * statically at the top level so they work reliably in both production and
48
49
  * vitest (which resolves bare specifiers via `resolve.alias`, not Node CJS).
49
50
  */
50
- let mediaRuntimeModulePromise = null;
51
- const loadMediaRuntimeModule = async () => {
52
- mediaRuntimeModulePromise ??= import("openclaw/plugin-sdk/media-runtime");
53
- return await mediaRuntimeModulePromise;
54
- };
51
+ const loadMediaRuntimeModule = createLazyRuntimeModule(() => import("openclaw/plugin-sdk/media-runtime"));
55
52
  function createBuiltinAdapter() {
56
53
  return {
57
54
  async validateRemoteUrl(_url, _options) {},