@openclaw/qqbot 2026.7.1-beta.6 → 2026.7.2-beta.1

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.
Files changed (41) hide show
  1. package/dist/api.js +8 -7
  2. package/dist/{channel-D1UztsnG.js → channel-BbwpkiY3.js} +99 -54
  3. package/dist/{channel-entry-C5YdhX3Y.js → channel-entry-Cj1lWXpt.js} +4 -4
  4. package/dist/channel-entry-api.js +1 -1
  5. package/dist/channel-plugin-api.js +1 -1
  6. package/dist/{channel.setup-2ItDYKhz.js → channel.setup-DfhritPL.js} +1 -1
  7. package/dist/{config-C1qZbh0K.js → config-CpOXnoEc.js} +2 -2
  8. package/dist/{config-schema-JZEf1dvB.js → config-schema-B5Mle_87.js} +38 -47
  9. package/dist/doctor-contract-api.js +1 -1
  10. package/dist/{gateway-pJQppxe4.js → gateway-be5-Ckdc.js} +284 -174
  11. package/dist/{group-o0GmovSf.js → group-Dbpnjalm.js} +19 -17
  12. package/dist/{handler-runtime-zQvT6SrI.js → handler-runtime-BvR-ayNW.js} +8 -12
  13. package/dist/{log-DEtcoDWe.js → log-Da4jz75I.js} +4 -8
  14. package/dist/{outbound-BIrfvvFJ.js → outbound-BLl8Tsu7.js} +8 -142
  15. package/dist/{runtime-DodcT_fQ.js → runtime-Du28LbOJ.js} +2 -2
  16. package/dist/runtime-api.js +1 -1
  17. package/dist/secret-contract-api.js +6 -22
  18. package/dist/{sender-CjDuU-uz.js → sender-0vqsivoI.js} +220 -66
  19. package/dist/setup-plugin-api.js +1 -1
  20. package/dist/state-keys-jLJ2SmJA.js +225 -0
  21. package/dist/{tools-UJJ-tLHP.js → tools-DYb23LBU.js} +48 -6
  22. package/dist/tools-api.js +1 -1
  23. package/node_modules/p-map/index.d.ts +155 -0
  24. package/node_modules/p-map/index.js +284 -0
  25. package/node_modules/p-map/license +9 -0
  26. package/node_modules/p-map/package.json +57 -0
  27. package/node_modules/p-map/readme.md +190 -0
  28. package/node_modules/parse-ms/index.d.ts +30 -0
  29. package/node_modules/parse-ms/index.js +45 -0
  30. package/node_modules/parse-ms/license +9 -0
  31. package/node_modules/parse-ms/package.json +47 -0
  32. package/node_modules/parse-ms/readme.md +46 -0
  33. package/node_modules/pretty-ms/index.d.ts +157 -0
  34. package/node_modules/pretty-ms/index.js +149 -0
  35. package/node_modules/pretty-ms/license +9 -0
  36. package/node_modules/pretty-ms/package.json +55 -0
  37. package/node_modules/pretty-ms/readme.md +179 -0
  38. package/npm-shrinkwrap.json +44 -3
  39. package/openclaw.plugin.json +61 -89
  40. package/package.json +8 -4
  41. package/dist/state-keys-CQKlAFyo.js +0 -141
package/dist/api.js CHANGED
@@ -1,8 +1,9 @@
1
- import { t as qqbotPlugin } from "./channel-D1UztsnG.js";
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-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";
1
+ import { C as checkMessageReplyLimit, D as recordMessageReply, E as getMessageReplyStats, S as MESSAGE_REPLY_LIMIT, T as getMessageReplyConfig } from "./sender-0vqsivoI.js";
2
+ import { t as qqbotPlugin } from "./channel-BbwpkiY3.js";
3
+ import { a as resolveQQBotAccount, i as resolveDefaultQQBotAccountId, n as applyQQBotAccountConfig, r as listQQBotAccountIds, t as DEFAULT_ACCOUNT_ID } from "./config-CpOXnoEc.js";
4
+ import { t as qqbotSetupPlugin } from "./channel.setup-DfhritPL.js";
5
+ import { o as getFrameworkCommands } from "./group-Dbpnjalm.js";
6
+ import { C as resolveUserFacingMediaError, E as setOutboundAudioPort, T as OUTBOUND_ERROR_CODES, _ as sendVideoMsg, a as sendText, 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 DEFAULT_MEDIA_SEND_ERROR } from "./outbound-BLl8Tsu7.js";
7
+ import { n as registerRemindTool, r as registerChannelTool, t as registerQQBotTools } from "./tools-DYb23LBU.js";
8
+ import { t as registerQQBotFull } from "./channel-entry-Cj1lWXpt.js";
8
9
  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,10 +1,10 @@
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-JZEf1dvB.js";
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-DodcT_fQ.js";
5
- import { n as legacyConfigRules, r as normalizeCompatibilityConfig, t as buildQQBotStateKey } from "./state-keys-CQKlAFyo.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-B5Mle_87.js";
3
+ import { a as resolveQQBotAccount, n as applyQQBotAccountConfig, r as listQQBotAccountIds, t as DEFAULT_ACCOUNT_ID$1 } from "./config-CpOXnoEc.js";
4
+ import { t as getQQBotRuntime } from "./runtime-Du28LbOJ.js";
5
+ import { n as legacyConfigRules, r as normalizeCompatibilityConfig, t as buildQQBotStateKey } from "./state-keys-jLJ2SmJA.js";
6
6
  import { n as normalizeTarget, r as parseTarget, t as looksLikeQQBotTarget } from "./target-parser-DagYRQkP.js";
7
- import { getExecApprovalReplyMetadata } from "openclaw/plugin-sdk/approval-runtime";
7
+ import { getExecApprovalReplyMetadata, resolveExecApprovalCommandDisplay } from "openclaw/plugin-sdk/approval-runtime";
8
8
  import { buildChannelOutboundSessionRoute } from "openclaw/plugin-sdk/channel-core";
9
9
  import { createMessageReceiptFromOutboundResults, defineChannelMessageAdapter } from "openclaw/plugin-sdk/channel-outbound";
10
10
  import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime";
@@ -17,34 +17,66 @@ import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
17
17
  import { markImplicitSameChatApprovalAuthorization, resolveApprovalApprovers } from "openclaw/plugin-sdk/approval-auth-runtime";
18
18
  import { createChannelExecApprovalProfile, isChannelExecApprovalClientEnabledFromConfig, matchesApprovalRequestFilters } from "openclaw/plugin-sdk/approval-client-runtime";
19
19
  import { normalizeAccountId } from "openclaw/plugin-sdk/routing";
20
- import { resolveChannelGroupToolsPolicy } from "openclaw/plugin-sdk/channel-policy";
20
+ import { buildChannelGroupsScopeTree, resolveScopeKeyCaseInsensitive, resolveScopeToolsPolicy } from "openclaw/plugin-sdk/channel-policy";
21
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
- */
29
- function buildExecApprovalText(request) {
30
- const expiresIn = Math.max(0, Math.round((request.expiresAtMs - Date.now()) / 1e3));
22
+ const COMMAND_PREVIEW_MAX_LENGTH = 300;
23
+ const COMMAND_PREVIEW_GRAPHEMES_PER_LINE = 24;
24
+ const COMMAND_PREVIEW_WRAP_MARKER = "↩";
25
+ const commandPreviewSegmenter = typeof Intl !== "undefined" && "Segmenter" in Intl ? new Intl.Segmenter(void 0, { granularity: "grapheme" }) : null;
26
+ function splitCommandPreviewGraphemes(commandText) {
27
+ return commandPreviewSegmenter ? Array.from(commandPreviewSegmenter.segment(commandText), ({ segment }) => segment) : Array.from(commandText);
28
+ }
29
+ function formatCommandPreview(commandText) {
30
+ const lines = [""];
31
+ const displayText = commandText.replaceAll(COMMAND_PREVIEW_WRAP_MARKER, "\\u{21A9}");
32
+ let previewLength = 0;
33
+ let lineGraphemes = 0;
34
+ let truncated = false;
35
+ let wrapped = false;
36
+ for (const grapheme of splitCommandPreviewGraphemes(displayText)) {
37
+ if (previewLength + grapheme.length > COMMAND_PREVIEW_MAX_LENGTH) {
38
+ if (previewLength === 0) lines[0] = truncateUtf16Safe(grapheme, COMMAND_PREVIEW_MAX_LENGTH);
39
+ truncated = true;
40
+ break;
41
+ }
42
+ previewLength += grapheme.length;
43
+ if (lineGraphemes === COMMAND_PREVIEW_GRAPHEMES_PER_LINE) {
44
+ lines[lines.length - 1] += COMMAND_PREVIEW_WRAP_MARKER;
45
+ lines.push("");
46
+ lineGraphemes = 0;
47
+ wrapped = true;
48
+ }
49
+ lines[lines.length - 1] += grapheme;
50
+ lineGraphemes += 1;
51
+ }
52
+ const preview = `${lines.join("\n")}${truncated ? "\n…[truncated]" : ""}`;
53
+ const longestBacktickRun = Math.max(0, ...preview.match(/`+/g)?.map((run) => run.length) ?? []);
54
+ const fence = "`".repeat(Math.max(3, longestBacktickRun + 1));
55
+ const block = `${fence}\n${preview}\n${fence}`;
56
+ return wrapped ? `${COMMAND_PREVIEW_WRAP_MARKER} = display wrap only; not command text\n${block}` : block;
57
+ }
58
+ function formatApprovalMetadata(value) {
59
+ const sanitized = resolveExecApprovalCommandDisplay({ command: value }).commandText;
60
+ return formatCommandPreview(sanitized);
61
+ }
62
+ function buildExecApprovalText(view, nowMs = Date.now()) {
63
+ const expiresIn = Math.max(0, Math.round((view.expiresAtMs - nowMs) / 1e3));
31
64
  const lines = ["🔐 命令执行审批", ""];
32
- const cmd = request.request.commandPreview ?? request.request.command ?? "";
33
- if (cmd) lines.push(`\`\`\`\n${truncateUtf16Safe(cmd, 300)}\n\`\`\``);
34
- if (request.request.cwd) lines.push(`\u{1f4c1} \u76ee\u5f55: ${request.request.cwd}`);
35
- if (request.request.agentId) lines.push(`\u{1f916} Agent: ${request.request.agentId}`);
65
+ if (view.commandText) lines.push(formatCommandPreview(view.commandText));
66
+ if (view.cwd) lines.push(`\u{1f4c1} \u76ee\u5f55:\n${formatApprovalMetadata(view.cwd)}`);
67
+ if (view.agentId) lines.push(`\u{1f916} Agent:\n${formatApprovalMetadata(view.agentId)}`);
36
68
  lines.push("", `\u23f1\ufe0f \u8d85\u65f6: ${expiresIn} \u79d2`);
37
69
  return lines.join("\n");
38
70
  }
39
- function buildPluginApprovalText(request) {
40
- const timeoutSec = Math.round((request.request.timeoutMs ?? 12e4) / 1e3);
41
- const lines = [`${request.request.severity === "critical" ? "🔴" : request.request.severity === "info" ? "🔵" : "🟡"} \u5ba1\u6279\u8bf7\u6c42`, ""];
42
- lines.push(`\u{1f4cb} ${request.request.title}`);
43
- if (request.request.description) lines.push(`\u{1f4dd} ${request.request.description}`);
44
- if (request.request.toolName) lines.push(`\u{1f527} \u5de5\u5177: ${request.request.toolName}`);
45
- if (request.request.pluginId) lines.push(`\u{1f50c} \u63d2\u4ef6: ${request.request.pluginId}`);
46
- if (request.request.agentId) lines.push(`\u{1f916} Agent: ${request.request.agentId}`);
47
- lines.push("", `\u23f1\ufe0f \u8d85\u65f6: ${timeoutSec} \u79d2`);
71
+ function buildPluginApprovalText(view, nowMs = Date.now()) {
72
+ const expiresIn = Math.max(0, Math.round((view.expiresAtMs - nowMs) / 1e3));
73
+ const lines = [`${view.severity === "critical" ? "🔴" : view.severity === "info" ? "🔵" : "🟡"} \u5ba1\u6279\u8bf7\u6c42`, ""];
74
+ lines.push(`\u{1f4cb} ${view.title}`);
75
+ if (view.description) lines.push(`\u{1f4dd} ${view.description}`);
76
+ if (view.toolName) lines.push(`\u{1f527} \u5de5\u5177: ${view.toolName}`);
77
+ if (view.pluginId) lines.push(`\u{1f50c} \u63d2\u4ef6: ${view.pluginId}`);
78
+ if (view.agentId) lines.push(`\u{1f916} Agent: ${view.agentId}`);
79
+ lines.push("", `\u23f1\ufe0f \u8d85\u65f6: ${expiresIn} \u79d2`);
48
80
  return lines.join("\n");
49
81
  }
50
82
  /**
@@ -55,11 +87,12 @@ function buildPluginApprovalText(request) {
55
87
  * click_limit=1: each user can only click once.
56
88
  * permission.type=2: all users can interact.
57
89
  */
58
- function buildApprovalKeyboard(approvalId, allowedDecisions = [
90
+ function buildApprovalKeyboard(approvalId, approvalKind, allowedDecisions = [
59
91
  "allow-once",
60
92
  "allow-always",
61
93
  "deny"
62
94
  ]) {
95
+ const actionPrefix = `approve:v2:${approvalKind}:${encodeURIComponent(approvalId)}`;
63
96
  const makeBtn = (id, label, visitedLabel, data, style) => ({
64
97
  id,
65
98
  render_data: {
@@ -76,9 +109,9 @@ function buildApprovalKeyboard(approvalId, allowedDecisions = [
76
109
  group_id: "approval"
77
110
  });
78
111
  const buttons = [];
79
- if (allowedDecisions.includes("allow-once")) buttons.push(makeBtn("allow", "✅ 允许一次", "已允许", `approve:${approvalId}:allow-once`, 1));
80
- if (allowedDecisions.includes("allow-always")) buttons.push(makeBtn("always", "⭐ 始终允许", "已始终允许", `approve:${approvalId}:allow-always`, 1));
81
- if (allowedDecisions.includes("deny")) buttons.push(makeBtn("deny", "❌ 拒绝", "已拒绝", `approve:${approvalId}:deny`, 0));
112
+ if (allowedDecisions.includes("allow-once")) buttons.push(makeBtn("allow", "✅ 允许一次", "已处理", `${actionPrefix}:allow-once`, 1));
113
+ if (allowedDecisions.includes("allow-always")) buttons.push(makeBtn("always", "⭐ 始终允许", "已处理", `${actionPrefix}:allow-always`, 1));
114
+ if (allowedDecisions.includes("deny")) buttons.push(makeBtn("deny", "❌ 拒绝", "已处理", `${actionPrefix}:deny`, 0));
82
115
  return { content: { rows: [{ buttons }] } };
83
116
  }
84
117
  /**
@@ -96,25 +129,39 @@ function resolveApprovalTarget(sessionKey, turnSourceTo) {
96
129
  if (!sk) return null;
97
130
  const m = sk.match(/qqbot:(c2c|direct|group):([A-F0-9]+)/i);
98
131
  if (!m) return null;
132
+ const scope = m[1];
133
+ const id = m[2];
134
+ if (scope === void 0 || id === void 0) return null;
99
135
  return {
100
- type: m[1].toLowerCase() === "group" ? "group" : "c2c",
101
- id: m[2]
136
+ type: scope.toLowerCase() === "group" ? "group" : "c2c",
137
+ id
102
138
  };
103
139
  }
104
140
  /**
105
141
  * Parse the button_data string from an INTERACTION_CREATE event.
106
142
  *
107
- * Expected format: `approve:<approvalId>:<decision>`
108
- * where approvalId may be prefixed with "exec:" or "plugin:".
143
+ * Expected format: `approve:v2:<approvalKind>:<encodedApprovalId>:<decision>`.
109
144
  *
110
145
  * Returns null if the data does not match the approval button format.
111
146
  */
112
147
  function parseApprovalButtonData(buttonData) {
113
- const m = buttonData.match(/^approve:((?:(?:exec|plugin):)?[0-9a-f-]+):(allow-once|allow-always|deny)$/i);
114
- if (!m) return null;
148
+ const m = buttonData.match(/^approve:v2:(exec|plugin):([^:]+):(allow-once|allow-always|deny)$/);
149
+ if (!m || m[0] !== buttonData) return null;
150
+ let approvalId;
151
+ const kind = m[1];
152
+ const encodedId = m[2];
153
+ const decision = m[3];
154
+ if (kind !== "exec" && kind !== "plugin" || encodedId === void 0 || decision !== "allow-once" && decision !== "allow-always" && decision !== "deny") return null;
155
+ try {
156
+ approvalId = decodeURIComponent(encodedId);
157
+ } catch {
158
+ return null;
159
+ }
160
+ if (!approvalId) return null;
115
161
  return {
116
- approvalId: m[1],
117
- decision: m[2]
162
+ approvalId,
163
+ approvalKind: kind,
164
+ decision
118
165
  };
119
166
  }
120
167
  //#endregion
@@ -375,7 +422,7 @@ function createQQBotApprovalCapability() {
375
422
  },
376
423
  load: async () => {
377
424
  ensurePlatformAdapter();
378
- return (await import("./handler-runtime-zQvT6SrI.js")).qqbotApprovalNativeRuntime;
425
+ return (await import("./handler-runtime-BvR-ayNW.js")).qqbotApprovalNativeRuntime;
379
426
  }
380
427
  })
381
428
  });
@@ -746,7 +793,8 @@ var QQBotMarkdownChunkingState = class {
746
793
  const bodyLines = pendingFenceOpenLine ? [...this.textLines] : this.textLines.slice(1);
747
794
  this.textLines = [];
748
795
  this.pendingTextFenceOpenLine = null;
749
- if (bodyLines.length > 0 && isClosingFenceLine(bodyLines[bodyLines.length - 1], fence)) bodyLines.pop();
796
+ const lastBodyLine = bodyLines.at(-1);
797
+ if (lastBodyLine !== void 0 && isClosingFenceLine(lastBodyLine, fence)) bodyLines.pop();
750
798
  if (this.activeFence && bodyLines.length === 0) return true;
751
799
  pushFenceLineChunks({
752
800
  chunks,
@@ -994,22 +1042,19 @@ function isClosingFenceLine(line, fence) {
994
1042
  //#endregion
995
1043
  //#region extensions/qqbot/src/group-policy.ts
996
1044
  function resolveQQBotGroupToolPolicy(params) {
997
- return resolveChannelGroupToolsPolicy({
998
- cfg: params.cfg,
999
- channel: "qqbot",
1000
- groupId: params.groupId,
1001
- groupIdCaseInsensitive: true,
1002
- accountId: params.accountId,
1003
- senderId: params.senderId,
1004
- senderName: params.senderName,
1005
- senderUsername: params.senderUsername,
1006
- senderE164: params.senderE164
1045
+ const tree = buildChannelGroupsScopeTree(params.cfg, "qqbot", params.accountId);
1046
+ const scopeKey = resolveScopeKeyCaseInsensitive(tree, params.groupId);
1047
+ return resolveScopeToolsPolicy({
1048
+ ...params,
1049
+ tree,
1050
+ path: scopeKey ? [scopeKey] : [],
1051
+ messageProvider: "qqbot"
1007
1052
  });
1008
1053
  }
1009
1054
  //#endregion
1010
1055
  //#region extensions/qqbot/src/channel.ts
1011
- const loadGatewayModule = createLazyRuntimeModule(() => import("./gateway-pJQppxe4.js"));
1012
- const loadOutboundMessagingModule = createLazyRuntimeModule(() => import("./outbound-BIrfvvFJ.js").then((n) => n.t));
1056
+ const loadGatewayModule = createLazyRuntimeModule(() => import("./gateway-be5-Ckdc.js"));
1057
+ const loadOutboundMessagingModule = createLazyRuntimeModule(() => import("./outbound-BLl8Tsu7.js").then((n) => n.t));
1013
1058
  function createQQBotSendReceipt(params) {
1014
1059
  const messageId = params.messageId?.trim();
1015
1060
  return createMessageReceiptFromOutboundResults({
@@ -1,7 +1,7 @@
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-o0GmovSf.js";
3
- import { h as sendDocument } from "./outbound-BIrfvvFJ.js";
4
- import { t as registerQQBotTools } from "./tools-UJJ-tLHP.js";
1
+ import { a as resolveQQBotAccount } from "./config-CpOXnoEc.js";
2
+ import { d as PRIVATE_CHAT_ONLY_TEXT, n as resolveGroupCommandLevelFromAccountConfig, o as getFrameworkCommands } from "./group-Dbpnjalm.js";
3
+ import { h as sendDocument } from "./outbound-BLl8Tsu7.js";
4
+ import { t as registerQQBotTools } from "./tools-DYb23LBU.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-C5YdhX3Y.js";
1
+ import { t as registerQQBotFull } from "./channel-entry-Cj1lWXpt.js";
2
2
  export { registerQQBotFull };
@@ -1,2 +1,2 @@
1
- import { t as qqbotPlugin } from "./channel-D1UztsnG.js";
1
+ import { t as qqbotPlugin } from "./channel-BbwpkiY3.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-JZEf1dvB.js";
1
+ import { a as qqbotSetupAdapterShared, i as qqbotMeta, n as qqbotSetupWizard, r as qqbotConfigAdapter, t as qqbotChannelConfigSchema } from "./config-schema-B5Mle_87.js";
2
2
  //#region extensions/qqbot/src/channel.setup.ts
3
3
  /**
4
4
  * Setup-only QQBot plugin — lightweight subset used during `openclaw onboard`
@@ -56,8 +56,8 @@ function resolveDefaultAccountId(cfg) {
56
56
  if (configuredDefaultAccountId && (configuredDefaultAccountId === "default" || Boolean(qqbot?.accounts?.[configuredDefaultAccountId]?.appId))) return configuredDefaultAccountId;
57
57
  if (qqbot?.appId || process.env.QQBOT_APP_ID) return DEFAULT_ACCOUNT_ID$1;
58
58
  if (qqbot?.accounts) {
59
- const ids = Object.keys(qqbot.accounts);
60
- if (ids.length > 0) return ids[0];
59
+ const firstId = Object.keys(qqbot.accounts).at(0);
60
+ if (firstId !== void 0) return firstId;
61
61
  }
62
62
  return DEFAULT_ACCOUNT_ID$1;
63
63
  }
@@ -1,10 +1,11 @@
1
1
  import { d as registerPlatformAdapterFactory, l as hasPlatformAdapter, n as normalizeLowercaseStringOrEmpty, u as registerPlatformAdapter } from "./string-normalize-R_0cKO7Q.js";
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";
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-CpOXnoEc.js";
3
3
  import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime";
4
4
  import { buildSecretInputSchema, hasConfiguredSecretInput, normalizeResolvedSecretInputString, normalizeSecretInputString } from "openclaw/plugin-sdk/secret-input";
5
5
  import { resolvePreferredOpenClawTmpDir } from "openclaw/plugin-sdk/temp-path";
6
6
  import { applyAccountNameToChannelSection, deleteAccountFromConfigSection, setAccountEnabledInConfigSection } from "openclaw/plugin-sdk/core";
7
7
  import { DEFAULT_ACCOUNT_ID, createStandardChannelSetupStatus, setSetupChannelEnabled } from "openclaw/plugin-sdk/setup";
8
+ import { expectDefined } from "openclaw/plugin-sdk/expect-runtime";
8
9
  import { formatDocsLink } from "openclaw/plugin-sdk/setup-tools";
9
10
  import { AllowFromListSchema, ToolPolicySchema, buildChannelConfigSchema } from "openclaw/plugin-sdk/channel-config-schema";
10
11
  import { z } from "zod";
@@ -24,30 +25,6 @@ function getBridgeLogger() {
24
25
  }
25
26
  //#endregion
26
27
  //#region extensions/qqbot/src/bridge/bootstrap.ts
27
- /**
28
- * Bootstrap the PlatformAdapter for the built-in version.
29
- *
30
- * ## Design
31
- *
32
- * The adapter is registered via two complementary mechanisms:
33
- *
34
- * 1. **Factory registration** (`registerPlatformAdapterFactory`) — a lightweight
35
- * callback stored in `adapter/index.ts` that is invoked lazily by
36
- * `getPlatformAdapter()` on first access. This guarantees the adapter is
37
- * available regardless of module evaluation order or bundler chunk splitting.
38
- *
39
- * 2. **Eager side-effect** (`ensurePlatformAdapter()`) — called at module
40
- * evaluation time when `channel.ts` imports this file. Provides the adapter
41
- * immediately for code that runs synchronously during startup.
42
- *
43
- * Heavy async-only dependencies (`media-runtime`, `config-runtime`,
44
- * `approval-gateway-runtime`) are lazy-imported inside each async method body
45
- * so that this module evaluates with minimal overhead.
46
- *
47
- * Synchronous dependencies (`secret-input`, `temp-path`) are imported
48
- * statically at the top level so they work reliably in both production and
49
- * vitest (which resolves bare specifiers via `resolve.alias`, not Node CJS).
50
- */
51
28
  const loadMediaRuntimeModule = createLazyRuntimeModule(() => import("openclaw/plugin-sdk/media-runtime"));
52
29
  function createBuiltinAdapter() {
53
30
  return {
@@ -75,6 +52,8 @@ function createBuiltinAdapter() {
75
52
  filePathHint: options.filePathHint,
76
53
  maxBytes: options.maxBytes,
77
54
  maxRedirects: options.maxRedirects,
55
+ timeoutMs: options.timeoutMs,
56
+ responseHeaderTimeoutMs: options.responseHeaderTimeoutMs,
78
57
  ssrfPolicy: options.ssrfPolicy,
79
58
  requestInit: options.requestInit
80
59
  });
@@ -95,20 +74,20 @@ function createBuiltinAdapter() {
95
74
  resolveSecretInputString(params) {
96
75
  return normalizeResolvedSecretInputString(params) ?? void 0;
97
76
  },
98
- async resolveApproval(approvalId, decision) {
77
+ async resolveApproval(params) {
99
78
  try {
100
79
  const { getRuntimeConfig } = await import("openclaw/plugin-sdk/runtime-config-snapshot");
101
80
  const { resolveApprovalOverGateway } = await import("openclaw/plugin-sdk/approval-gateway-runtime");
102
- await resolveApprovalOverGateway({
81
+ return await resolveApprovalOverGateway({
103
82
  cfg: getRuntimeConfig(),
104
- approvalId,
105
- decision,
83
+ approvalId: params.approvalId,
84
+ approvalKind: params.approvalKind,
85
+ decision: params.decision,
106
86
  clientDisplayName: "QQBot Approval Handler"
107
87
  });
108
- return true;
109
88
  } catch (err) {
110
89
  getBridgeLogger().error(`[qqbot] resolveApproval failed: ${String(err)}`);
111
- return false;
90
+ throw err;
112
91
  }
113
92
  }
114
93
  };
@@ -247,32 +226,43 @@ function isQQBotAccountConfigured(cfg, accountId) {
247
226
  const account = resolveQQBotAccount(cfg, accountId, { allowUnresolvedSecretRef: true });
248
227
  return Boolean(account.appId && account.clientSecret);
249
228
  }
229
+ async function reportQQBotLinkFailure(params, error) {
230
+ params.runtime.error(`QQ Bot 绑定失败: ${String(error)}`);
231
+ await params.prompter.note(["绑定失败,您可以稍后手动配置。", `文档: ${formatDocsLink("/channels/qqbot", "qqbot")}`].join("\n"), "QQ Bot");
232
+ }
250
233
  async function linkViaQrCode(params) {
234
+ let connector;
251
235
  try {
252
- const { qrConnect } = await import("@tencent-connect/qqbot-connector");
253
- const accounts = await qrConnect({ source: "openclaw" });
236
+ connector = await import("@tencent-connect/qqbot-connector");
237
+ } catch (error) {
238
+ await reportQQBotLinkFailure(params, error);
239
+ return params.cfg;
240
+ }
241
+ await params.beforePersistentEffect?.();
242
+ try {
243
+ const accounts = await connector.qrConnect({ source: "openclaw" });
254
244
  if (accounts.length === 0) {
255
245
  await params.prompter.note("未获取到任何 QQ Bot 账号信息。", "QQ Bot");
256
246
  return params.cfg;
257
247
  }
258
248
  let next = params.cfg;
259
- for (let i = 0; i < accounts.length; i++) {
260
- const { appId, appSecret } = accounts[i];
249
+ for (const [i, { appId, appSecret }] of accounts.entries()) {
261
250
  const targetAccountId = i === 0 ? params.accountId : appId;
262
251
  next = applyQQBotAccountConfig(next, targetAccountId, {
263
252
  appId,
264
253
  clientSecret: appSecret
265
254
  });
266
255
  }
267
- if (accounts.length === 1) params.runtime.log(`✔ QQ Bot 绑定成功!(AppID: ${accounts[0].appId})`);
268
- else {
256
+ if (accounts.length === 1) {
257
+ const account = expectDefined(accounts.at(0), "single linked QQ Bot account");
258
+ params.runtime.log(`✔ QQ Bot 绑定成功!(AppID: ${account.appId})`);
259
+ } else {
269
260
  const idList = accounts.map((a) => a.appId).join(", ");
270
261
  params.runtime.log(`✔ ${accounts.length} 个 QQ Bot 绑定成功!(AppID: ${idList})`);
271
262
  }
272
263
  return next;
273
264
  } catch (error) {
274
- params.runtime.error(`QQ Bot 绑定失败: ${String(error)}`);
275
- await params.prompter.note(["绑定失败,您可以稍后手动配置。", `文档: ${formatDocsLink("/channels/qqbot", "qqbot")}`].join("\n"), "QQ Bot");
265
+ await reportQQBotLinkFailure(params, error);
276
266
  return params.cfg;
277
267
  }
278
268
  }
@@ -319,7 +309,8 @@ async function finalizeQQBotSetup(params) {
319
309
  cfg: next,
320
310
  accountId,
321
311
  prompter: params.prompter,
322
- runtime: params.runtime
312
+ runtime: params.runtime,
313
+ beforePersistentEffect: params.options?.beforePersistentEffect
323
314
  });
324
315
  else if (mode === "manual") next = await linkViaManualInput({
325
316
  cfg: next,
@@ -347,12 +338,13 @@ const qqbotSetupWizard = {
347
338
  })
348
339
  }),
349
340
  credentials: [],
350
- finalize: async ({ cfg, accountId, forceAllowFrom, prompter, runtime }) => await finalizeQQBotSetup({
341
+ finalize: async ({ cfg, accountId, forceAllowFrom, prompter, runtime, options }) => await finalizeQQBotSetup({
351
342
  cfg,
352
343
  accountId,
353
344
  forceAllowFrom,
354
345
  prompter,
355
- runtime
346
+ runtime,
347
+ options
356
348
  }),
357
349
  disable: (cfg) => setSetupChannelEnabled(cfg, channel, false)
358
350
  };
@@ -370,13 +362,12 @@ const QQBotSttSchema = z.object({
370
362
  apiKey: z.string().optional(),
371
363
  model: z.string().optional()
372
364
  }).strict().optional();
373
- /** When `true`, same as `mode: "partial"` and `c2cStreamApi: true` for C2C. Object form kept for legacy configs. */
374
- const QQBotStreamingSchema = z.union([z.boolean(), z.object({
365
+ const QQBotStreamingSchema = z.object({
375
366
  /** "partial" (default) enables block streaming; "off" disables it. */
376
367
  mode: z.enum(["off", "partial"]).default("partial"),
377
- /** @deprecated Prefer `streaming: true`. */
378
- c2cStreamApi: z.boolean().optional()
379
- }).passthrough()]).optional();
368
+ /** Use QQ's official C2C `stream_messages` API for DM replies. */
369
+ nativeTransport: z.boolean().optional()
370
+ }).strict().optional();
380
371
  const QQBotExecApprovalsSchema = z.object({
381
372
  enabled: z.union([z.boolean(), z.literal("auto")]).optional(),
382
373
  approvers: z.array(z.string()).optional(),
@@ -1,4 +1,4 @@
1
- import { n as legacyConfigRules, r as normalizeCompatibilityConfig, t as buildQQBotStateKey } from "./state-keys-CQKlAFyo.js";
1
+ import { n as legacyConfigRules, r as normalizeCompatibilityConfig, t as buildQQBotStateKey } from "./state-keys-jLJ2SmJA.js";
2
2
  import path from "node:path";
3
3
  import fs from "node:fs/promises";
4
4
  //#region extensions/qqbot/src/state-migrations.ts