@cxyhhhhh/openclaw-qqbot 2.0.0-dev.202607101541 → 2.0.0-dev.202607101939

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/index.cjs CHANGED
@@ -6,6 +6,9 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
6
  var __getOwnPropNames = Object.getOwnPropertyNames;
7
7
  var __getProtoOf = Object.getPrototypeOf;
8
8
  var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __esm = (fn, res) => function __init() {
10
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
11
+ };
9
12
  var __commonJS = (cb, mod) => function __require() {
10
13
  return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
11
14
  };
@@ -31,6 +34,272 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
31
34
  ));
32
35
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
33
36
 
37
+ // src/config.ts
38
+ var config_exports = {};
39
+ __export(config_exports, {
40
+ DEFAULT_ACCOUNT_ID: () => DEFAULT_ACCOUNT_ID,
41
+ applyQQBotAccountConfig: () => applyQQBotAccountConfig,
42
+ isGroupAllowed: () => isGroupAllowed,
43
+ listQQBotAccountIds: () => listQQBotAccountIds,
44
+ resolveDefaultQQBotAccountId: () => resolveDefaultQQBotAccountId,
45
+ resolveGroupAllowFrom: () => resolveGroupAllowFrom,
46
+ resolveGroupConfig: () => resolveGroupConfig,
47
+ resolveGroupConfigFromAccount: () => resolveGroupConfigFromAccount,
48
+ resolveGroupName: () => resolveGroupName,
49
+ resolveGroupPolicy: () => resolveGroupPolicy,
50
+ resolveGroupPrompt: () => resolveGroupPrompt,
51
+ resolveHistoryLimit: () => resolveHistoryLimit,
52
+ resolveIgnoreOtherMentions: () => resolveIgnoreOtherMentions,
53
+ resolveMentionPatterns: () => resolveMentionPatterns,
54
+ resolveProcessingTimeoutMs: () => resolveProcessingTimeoutMs,
55
+ resolveQQBotAccount: () => resolveQQBotAccount,
56
+ resolveRequireMention: () => resolveRequireMention,
57
+ resolveToolPolicy: () => resolveToolPolicy,
58
+ resolveUserAgentSuffix: () => resolveUserAgentSuffix
59
+ });
60
+ function resolveMentionPatterns(cfg, agentId) {
61
+ if (agentId) {
62
+ const agents = cfg.agents;
63
+ const entry = agents?.list?.find((a) => a.id?.trim().toLowerCase() === agentId.trim().toLowerCase());
64
+ const agentGroupChat = entry?.groupChat;
65
+ if (agentGroupChat && Object.hasOwn(agentGroupChat, "mentionPatterns")) {
66
+ return agentGroupChat.mentionPatterns ?? [];
67
+ }
68
+ }
69
+ const globalGroupChat = cfg?.messages?.groupChat;
70
+ if (globalGroupChat && typeof globalGroupChat === "object" && Object.hasOwn(globalGroupChat, "mentionPatterns")) {
71
+ return globalGroupChat.mentionPatterns ?? [];
72
+ }
73
+ return [];
74
+ }
75
+ function evaluateMatchedGroupAccessForPolicy(params) {
76
+ if (params.groupPolicy === "disabled") {
77
+ return { allowed: false, groupPolicy: params.groupPolicy, reason: "disabled" };
78
+ }
79
+ if (params.groupPolicy === "allowlist") {
80
+ if (params.requireMatchInput && !params.hasMatchInput) {
81
+ return { allowed: false, groupPolicy: params.groupPolicy, reason: "missing_match_input" };
82
+ }
83
+ if (!params.allowlistConfigured) {
84
+ return { allowed: false, groupPolicy: params.groupPolicy, reason: "empty_allowlist" };
85
+ }
86
+ if (!params.allowlistMatched) {
87
+ return { allowed: false, groupPolicy: params.groupPolicy, reason: "not_allowlisted" };
88
+ }
89
+ }
90
+ return { allowed: true, groupPolicy: params.groupPolicy, reason: "allowed" };
91
+ }
92
+ function resolveGroupPolicy(cfg, accountId) {
93
+ const account = resolveQQBotAccount(cfg, accountId);
94
+ return account.config?.groupPolicy ?? DEFAULT_GROUP_POLICY;
95
+ }
96
+ function resolveGroupAllowFrom(cfg, accountId) {
97
+ const account = resolveQQBotAccount(cfg, accountId);
98
+ return (account.config?.groupAllowFrom ?? []).map((id) => String(id).trim().toUpperCase());
99
+ }
100
+ function isGroupAllowed(cfg, groupOpenid, accountId) {
101
+ const account = resolveQQBotAccount(cfg, accountId);
102
+ const policy = account.config?.groupPolicy ?? DEFAULT_GROUP_POLICY;
103
+ const allowList = (account.config?.groupAllowFrom ?? []).map((id) => String(id).trim().toUpperCase());
104
+ const allowlistConfigured = allowList.length > 0;
105
+ const allowlistMatched = allowList.some((id) => id === "*" || id === groupOpenid.toUpperCase());
106
+ return evaluateMatchedGroupAccessForPolicy({
107
+ groupPolicy: policy,
108
+ allowlistConfigured,
109
+ allowlistMatched
110
+ }).allowed;
111
+ }
112
+ function resolveGroupConfigFromAccount(account, groupOpenid) {
113
+ const groups = account.config?.groups ?? {};
114
+ const wildcardCfg = groups["*"] ?? {};
115
+ const specificCfg = groups[groupOpenid] ?? {};
116
+ const accountDefaultRequireMention = account.config?.defaultRequireMention ?? DEFAULT_GROUP_CONFIG.requireMention;
117
+ return {
118
+ requireMention: specificCfg.requireMention ?? wildcardCfg.requireMention ?? accountDefaultRequireMention,
119
+ ignoreOtherMentions: specificCfg.ignoreOtherMentions ?? wildcardCfg.ignoreOtherMentions ?? DEFAULT_GROUP_CONFIG.ignoreOtherMentions,
120
+ toolPolicy: specificCfg.toolPolicy ?? wildcardCfg.toolPolicy ?? DEFAULT_GROUP_CONFIG.toolPolicy,
121
+ name: specificCfg.name ?? wildcardCfg.name ?? DEFAULT_GROUP_CONFIG.name,
122
+ prompt: specificCfg.prompt ?? wildcardCfg.prompt ?? DEFAULT_GROUP_PROMPT,
123
+ historyLimit: specificCfg.historyLimit ?? wildcardCfg.historyLimit ?? DEFAULT_GROUP_CONFIG.historyLimit
124
+ };
125
+ }
126
+ function resolveGroupConfig(cfg, groupOpenid, accountId) {
127
+ return resolveGroupConfigFromAccount(resolveQQBotAccount(cfg, accountId), groupOpenid);
128
+ }
129
+ function resolveHistoryLimit(cfg, groupOpenid, accountId) {
130
+ return Math.max(0, resolveGroupConfig(cfg, groupOpenid, accountId).historyLimit);
131
+ }
132
+ function resolveGroupPrompt(cfg, groupOpenid, accountId) {
133
+ return resolveGroupConfig(cfg, groupOpenid, accountId).prompt;
134
+ }
135
+ function resolveRequireMention(cfg, groupOpenid, accountId) {
136
+ return resolveGroupConfig(cfg, groupOpenid, accountId).requireMention;
137
+ }
138
+ function resolveIgnoreOtherMentions(cfg, groupOpenid, accountId) {
139
+ return resolveGroupConfig(cfg, groupOpenid, accountId).ignoreOtherMentions;
140
+ }
141
+ function resolveToolPolicy(cfg, groupOpenid, accountId) {
142
+ return resolveGroupConfig(cfg, groupOpenid, accountId).toolPolicy;
143
+ }
144
+ function resolveGroupName(cfg, groupOpenid, accountId) {
145
+ const name = resolveGroupConfig(cfg, groupOpenid, accountId).name;
146
+ return name || groupOpenid.slice(0, 8);
147
+ }
148
+ function normalizeAppId(raw) {
149
+ if (raw === null || raw === void 0) return "";
150
+ return String(raw).trim();
151
+ }
152
+ function listQQBotAccountIds(cfg) {
153
+ const ids = /* @__PURE__ */ new Set();
154
+ const qqbot = cfg.channels?.qqbot;
155
+ if (qqbot?.appId) {
156
+ ids.add(DEFAULT_ACCOUNT_ID);
157
+ }
158
+ if (qqbot?.accounts) {
159
+ for (const accountId of Object.keys(qqbot.accounts)) {
160
+ if (qqbot.accounts[accountId]?.appId) {
161
+ ids.add(accountId);
162
+ }
163
+ }
164
+ }
165
+ return Array.from(ids);
166
+ }
167
+ function resolveDefaultQQBotAccountId(cfg) {
168
+ const qqbot = cfg.channels?.qqbot;
169
+ if (qqbot?.appId) {
170
+ return DEFAULT_ACCOUNT_ID;
171
+ }
172
+ if (qqbot?.accounts) {
173
+ const ids = Object.keys(qqbot.accounts);
174
+ if (ids.length > 0) {
175
+ return ids[0];
176
+ }
177
+ }
178
+ return DEFAULT_ACCOUNT_ID;
179
+ }
180
+ function resolveUserAgentSuffix(cfg) {
181
+ const qqbot = cfg.channels?.qqbot;
182
+ return qqbot?.userAgentSuffix ? String(qqbot.userAgentSuffix).trim() : "";
183
+ }
184
+ function resolveProcessingTimeoutMs(accountConfig) {
185
+ if (accountConfig?.processingTimeoutMs !== void 0) {
186
+ return accountConfig.processingTimeoutMs;
187
+ }
188
+ const env = process.env.OPENCLAW_PROCESSING_TIMEOUT_MS;
189
+ if (env) {
190
+ const v = Number(env);
191
+ if (!Number.isNaN(v) && v >= 0) return v;
192
+ }
193
+ return DEFAULT_PROCESSING_TIMEOUT_MS;
194
+ }
195
+ function resolveQQBotAccount(cfg, accountId) {
196
+ const resolvedAccountId = accountId ?? resolveDefaultQQBotAccountId(cfg);
197
+ const qqbot = cfg.channels?.qqbot;
198
+ let accountConfig = {};
199
+ let appId = "";
200
+ let clientSecret = "";
201
+ let secretSource = "none";
202
+ if (resolvedAccountId === DEFAULT_ACCOUNT_ID) {
203
+ const { accounts: _accounts, ...topLevelConfig } = qqbot ?? {};
204
+ accountConfig = {
205
+ ...topLevelConfig,
206
+ markdownSupport: qqbot?.markdownSupport ?? true
207
+ };
208
+ appId = normalizeAppId(qqbot?.appId);
209
+ } else {
210
+ const account = qqbot?.accounts?.[resolvedAccountId];
211
+ accountConfig = account ?? {};
212
+ appId = normalizeAppId(account?.appId);
213
+ }
214
+ if (accountConfig.clientSecret) {
215
+ clientSecret = accountConfig.clientSecret;
216
+ secretSource = "config";
217
+ } else if (accountConfig.clientSecretFile) {
218
+ secretSource = "file";
219
+ } else if (process.env.QQBOT_CLIENT_SECRET && resolvedAccountId === DEFAULT_ACCOUNT_ID) {
220
+ clientSecret = process.env.QQBOT_CLIENT_SECRET;
221
+ secretSource = "env";
222
+ }
223
+ if (!appId && process.env.QQBOT_APP_ID && resolvedAccountId === DEFAULT_ACCOUNT_ID) {
224
+ appId = normalizeAppId(process.env.QQBOT_APP_ID);
225
+ }
226
+ return {
227
+ accountId: resolvedAccountId,
228
+ name: accountConfig.name,
229
+ enabled: accountConfig.enabled !== false,
230
+ appId,
231
+ clientSecret,
232
+ secretSource,
233
+ systemPrompt: accountConfig.systemPrompt,
234
+ markdownSupport: accountConfig.markdownSupport !== false,
235
+ userAgentSuffix: resolveUserAgentSuffix(cfg),
236
+ processingTimeoutMs: resolveProcessingTimeoutMs(accountConfig),
237
+ config: accountConfig
238
+ };
239
+ }
240
+ function applyQQBotAccountConfig(cfg, accountId, input) {
241
+ const next = { ...cfg };
242
+ if (accountId === DEFAULT_ACCOUNT_ID) {
243
+ const existingConfig = next.channels?.qqbot || {};
244
+ const allowFrom = existingConfig.allowFrom ?? ["*"];
245
+ next.channels = {
246
+ ...next.channels,
247
+ qqbot: {
248
+ ...next.channels?.qqbot || {},
249
+ enabled: true,
250
+ allowFrom,
251
+ ...input.appId ? { appId: input.appId } : {},
252
+ ...input.clientSecret ? { clientSecret: input.clientSecret } : input.clientSecretFile ? { clientSecretFile: input.clientSecretFile } : {},
253
+ ...input.name ? { name: input.name } : {}
254
+ }
255
+ };
256
+ } else {
257
+ const existingAccountConfig = next.channels?.qqbot?.accounts?.[accountId] || {};
258
+ const allowFrom = existingAccountConfig.allowFrom ?? ["*"];
259
+ next.channels = {
260
+ ...next.channels,
261
+ qqbot: {
262
+ ...next.channels?.qqbot || {},
263
+ enabled: true,
264
+ accounts: {
265
+ ...next.channels?.qqbot?.accounts || {},
266
+ [accountId]: {
267
+ ...next.channels?.qqbot?.accounts?.[accountId] || {},
268
+ enabled: true,
269
+ allowFrom,
270
+ ...input.appId ? { appId: input.appId } : {},
271
+ ...input.clientSecret ? { clientSecret: input.clientSecret } : input.clientSecretFile ? { clientSecretFile: input.clientSecretFile } : {},
272
+ ...input.name ? { name: input.name } : {}
273
+ }
274
+ }
275
+ }
276
+ };
277
+ }
278
+ return next;
279
+ }
280
+ var DEFAULT_ACCOUNT_ID, DEFAULT_GROUP_POLICY, DEFAULT_GROUP_HISTORY_LIMIT, DEFAULT_PROCESSING_TIMEOUT_MS, DEFAULT_GROUP_CONFIG, DEFAULT_GROUP_PROMPT;
281
+ var init_config = __esm({
282
+ "src/config.ts"() {
283
+ "use strict";
284
+ DEFAULT_ACCOUNT_ID = "default";
285
+ DEFAULT_GROUP_POLICY = "open";
286
+ DEFAULT_GROUP_HISTORY_LIMIT = 20;
287
+ DEFAULT_PROCESSING_TIMEOUT_MS = 0;
288
+ DEFAULT_GROUP_CONFIG = {
289
+ requireMention: true,
290
+ ignoreOtherMentions: false,
291
+ toolPolicy: "restricted",
292
+ name: "",
293
+ historyLimit: DEFAULT_GROUP_HISTORY_LIMIT
294
+ };
295
+ DEFAULT_GROUP_PROMPT = [
296
+ "\u82E5\u53D1\u9001\u8005\u4E3A\u673A\u5668\u4EBA\uFF0C\u4EC5\u5728\u5BF9\u65B9\u660E\u786E@\u4F60\u63D0\u95EE\u6216\u8BF7\u6C42\u534F\u52A9\u5177\u4F53\u4EFB\u52A1\u65F6\uFF0C\u4EE5\u7B80\u6D01\u660E\u4E86\u7684\u5185\u5BB9\u56DE\u590D\uFF0C",
297
+ "\u907F\u514D\u4E0E\u5176\u4ED6\u673A\u5668\u4EBA\u4EA7\u751F\u62A2\u7B54\u6216\u591A\u8F6E\u65E0\u610F\u4E49\u5BF9\u8BDD\u3002",
298
+ "\u5728\u7FA4\u804A\u4E2D\u4F18\u5148\u8BA9\u4EBA\u7C7B\u7528\u6237\u7684\u6D88\u606F\u5F97\u5230\u54CD\u5E94\uFF0C\u673A\u5668\u4EBA\u4E4B\u95F4\u4FDD\u6301\u534F\u4F5C\u800C\u975E\u7ADE\u4E89\uFF0C\u786E\u4FDD\u5BF9\u8BDD\u6709\u5E8F\u4E0D\u5237\u5C4F\u3002"
299
+ ].join("");
300
+ }
301
+ });
302
+
34
303
  // node_modules/.pnpm/ws@8.21.0/node_modules/ws/lib/constants.js
35
304
  var require_constants = __commonJS({
36
305
  "node_modules/.pnpm/ws@8.21.0/node_modules/ws/lib/constants.js"(exports2, module2) {
@@ -3710,16 +3979,248 @@ var require_websocket_server = __commonJS({
3710
3979
  }
3711
3980
  });
3712
3981
 
3713
- // node_modules/.pnpm/qrcode-terminal@0.12.0/node_modules/qrcode-terminal/vendor/QRCode/QRMode.js
3714
- var require_QRMode = __commonJS({
3715
- "node_modules/.pnpm/qrcode-terminal@0.12.0/node_modules/qrcode-terminal/vendor/QRCode/QRMode.js"(exports2, module2) {
3716
- "use strict";
3717
- module2.exports = {
3718
- MODE_NUMBER: 1 << 0,
3719
- MODE_ALPHA_NUM: 1 << 1,
3720
- MODE_8BIT_BYTE: 1 << 2,
3721
- MODE_KANJI: 1 << 3
3722
- };
3982
+ // src/adapter/resolve.ts
3983
+ var resolve_exports = {};
3984
+ __export(resolve_exports, {
3985
+ _resetAdaptersCache: () => _resetAdaptersCache,
3986
+ getAdapters: () => getAdapters,
3987
+ persistAuthConfig: () => persistAuthConfig,
3988
+ resolveRuntimeAdapters: () => resolveRuntimeAdapters
3989
+ });
3990
+ function probeFunction(rt, paths) {
3991
+ for (const path22 of paths) {
3992
+ let target = rt;
3993
+ let parent = rt;
3994
+ for (let i = 0; i < path22.length; i++) {
3995
+ parent = target;
3996
+ target = target?.[path22[i]];
3997
+ if (target === void 0 || target === null) break;
3998
+ }
3999
+ if (typeof target === "function") {
4000
+ return target.bind(parent);
4001
+ }
4002
+ }
4003
+ return null;
4004
+ }
4005
+ function resolveRuntimeAdapters(rt, log4) {
4006
+ const version = rt.version ?? "unknown";
4007
+ const inboundRun = probeFunction(rt, [
4008
+ ["channel", "inbound", "run"],
4009
+ // current (2026-05+)
4010
+ ["channel", "turn", "run"]
4011
+ // legacy (removed 2026-05-27)
4012
+ ]);
4013
+ const dispatchReply = probeFunction(rt, [
4014
+ ["channel", "reply", "dispatchReplyWithBufferedBlockDispatcher"]
4015
+ ]);
4016
+ const resolveAgentRoute = probeFunction(rt, [
4017
+ ["channel", "routing", "resolveAgentRoute"]
4018
+ ]);
4019
+ const rawBuildContext = probeFunction(rt, [
4020
+ ["channel", "inbound", "buildContext"]
4021
+ ]);
4022
+ const rawFinalizeContext = !rawBuildContext ? probeFunction(rt, [["channel", "reply", "finalizeInboundContext"]]) : null;
4023
+ const buildInboundContext = rawBuildContext ? (params) => rawBuildContext(params) : rawFinalizeContext ? (params) => {
4024
+ const isCommand = params.access?.commands?.authorized ?? false;
4025
+ const rawCtx = {
4026
+ Body: params.message.body,
4027
+ BodyForAgent: params.message.bodyForAgent,
4028
+ RawBody: params.message.rawBody,
4029
+ CommandBody: params.message.commandBody ?? params.message.rawBody,
4030
+ CommandSource: isCommand ? "text" : void 0,
4031
+ CommandTurn: params.command ?? void 0,
4032
+ CommandAuthorized: isCommand,
4033
+ From: params.from,
4034
+ To: params.reply.to,
4035
+ SessionKey: params.route.routeSessionKey,
4036
+ AccountId: params.route.accountId ?? params.accountId,
4037
+ ChatType: params.conversation.kind,
4038
+ GroupSystemPrompt: params.conversation.label,
4039
+ SenderId: params.sender.id,
4040
+ SenderName: params.sender.name,
4041
+ Provider: params.provider ?? params.channel,
4042
+ Surface: params.surface ?? params.channel,
4043
+ MessageSid: params.messageId,
4044
+ Timestamp: params.timestamp ?? Date.now(),
4045
+ OriginatingChannel: params.channel,
4046
+ OriginatingTo: params.reply.originatingTo ?? params.reply.to,
4047
+ ...params.extra
4048
+ };
4049
+ return rawFinalizeContext(rawCtx);
4050
+ } : null;
4051
+ const resolveStorePath = probeFunction(rt, [
4052
+ ["channel", "session", "resolveStorePath"]
4053
+ ]);
4054
+ const recordInboundSession = probeFunction(rt, [
4055
+ ["channel", "session", "recordInboundSession"]
4056
+ ]);
4057
+ const formatEnvelope = probeFunction(rt, [
4058
+ ["channel", "reply", "formatAgentEnvelope"],
4059
+ // current (2026-06+)
4060
+ ["channel", "reply", "formatInboundEnvelope"]
4061
+ // deprecated,低版本兼容
4062
+ ]);
4063
+ const resolveEnvelopeFormatOptions = probeFunction(rt, [
4064
+ ["channel", "reply", "resolveEnvelopeFormatOptions"]
4065
+ ]);
4066
+ const chunkMarkdownText = probeFunction(rt, [
4067
+ ["channel", "text", "chunkMarkdownText"]
4068
+ ]);
4069
+ const saveRemoteMedia = probeFunction(rt, [
4070
+ ["channel", "media", "saveRemoteMedia"]
4071
+ ]);
4072
+ const getConfig = probeFunction(rt, [
4073
+ ["config", "current"]
4074
+ ]) ?? probeFunction(rt, [
4075
+ ["getConfig"]
4076
+ ]) ?? probeFunction(rt, [
4077
+ ["config", "loadConfig"]
4078
+ ]);
4079
+ const rawMutateConfig = probeFunction(rt, [["config", "mutateConfigFile"]]);
4080
+ const rawWriteConfig = probeFunction(rt, [["config", "writeConfigFile"]]);
4081
+ const persistConfig = rawMutateConfig ? async (mutator) => {
4082
+ await rawMutateConfig({
4083
+ afterWrite: "hot-reload",
4084
+ mutate: mutator
4085
+ });
4086
+ } : rawWriteConfig && getConfig ? async (mutator) => {
4087
+ const current = JSON.parse(JSON.stringify(getConfig()));
4088
+ mutator(current);
4089
+ await rawWriteConfig(current);
4090
+ } : null;
4091
+ const resolved = [
4092
+ inboundRun && "inboundRun",
4093
+ dispatchReply && "dispatchReply",
4094
+ resolveAgentRoute && "resolveAgentRoute",
4095
+ buildInboundContext && "buildInboundContext",
4096
+ resolveStorePath && "resolveStorePath",
4097
+ recordInboundSession && "recordInboundSession",
4098
+ formatEnvelope && "formatEnvelope",
4099
+ chunkMarkdownText && "chunkMarkdownText",
4100
+ saveRemoteMedia && "saveRemoteMedia",
4101
+ getConfig && "getConfig",
4102
+ persistConfig && `persistConfig(${rawMutateConfig ? "mutate" : "write"})`
4103
+ ].filter(Boolean);
4104
+ log4?.info(
4105
+ `[qqbot:adapter] openclaw=${version} resolved ${resolved.length} adapters: ${resolved.join(", ")}`
4106
+ );
4107
+ return {
4108
+ inboundRun,
4109
+ dispatchReply,
4110
+ resolveAgentRoute,
4111
+ buildInboundContext,
4112
+ resolveStorePath,
4113
+ recordInboundSession,
4114
+ formatEnvelope,
4115
+ resolveEnvelopeFormatOptions,
4116
+ chunkMarkdownText,
4117
+ saveRemoteMedia,
4118
+ getConfig,
4119
+ persistConfig,
4120
+ version
4121
+ };
4122
+ }
4123
+ function getAdapters(rt, log4) {
4124
+ const cached = _cachedRuntimeRef?.deref();
4125
+ if (cached === rt && _cachedAdapters) {
4126
+ return _cachedAdapters;
4127
+ }
4128
+ _cachedAdapters = resolveRuntimeAdapters(rt, log4);
4129
+ _cachedRuntimeRef = new WeakRef(rt);
4130
+ return _cachedAdapters;
4131
+ }
4132
+ async function persistAuthConfig(runtime2, cfg, afterWrite = "restart") {
4133
+ const config = runtime2.config;
4134
+ if (typeof config?.mutateConfigFile === "function") {
4135
+ await config.mutateConfigFile({
4136
+ mutate: () => cfg,
4137
+ afterWrite
4138
+ });
4139
+ return;
4140
+ }
4141
+ if (typeof config?.writeConfigFile === "function") {
4142
+ await config.writeConfigFile(cfg);
4143
+ return;
4144
+ }
4145
+ if (typeof runtime2.writeConfigFile === "function") {
4146
+ await runtime2.writeConfigFile(cfg);
4147
+ return;
4148
+ }
4149
+ const { homedir: homedir5 } = await import("os");
4150
+ const { join: join8 } = await import("path");
4151
+ const { writeFileSync: writeFileSync5 } = await import("fs");
4152
+ writeFileSync5(join8(homedir5(), ".openclaw", "openclaw.json"), JSON.stringify(cfg, null, 2) + "\n", "utf-8");
4153
+ }
4154
+ function _resetAdaptersCache() {
4155
+ _cachedAdapters = null;
4156
+ _cachedRuntimeRef = null;
4157
+ }
4158
+ var _cachedAdapters, _cachedRuntimeRef;
4159
+ var init_resolve = __esm({
4160
+ "src/adapter/resolve.ts"() {
4161
+ "use strict";
4162
+ _cachedAdapters = null;
4163
+ _cachedRuntimeRef = null;
4164
+ }
4165
+ });
4166
+
4167
+ // src/adapter/setup.ts
4168
+ function loadSetup() {
4169
+ if (_setup !== void 0) return _setup;
4170
+ try {
4171
+ _setup = req2("openclaw/plugin-sdk/setup");
4172
+ } catch {
4173
+ _setup = null;
4174
+ }
4175
+ return _setup;
4176
+ }
4177
+ function loadTools() {
4178
+ if (_tools !== void 0) return _tools;
4179
+ try {
4180
+ _tools = req2("openclaw/plugin-sdk/setup-tools");
4181
+ } catch {
4182
+ _tools = null;
4183
+ }
4184
+ return _tools;
4185
+ }
4186
+ function createStandardChannelSetupStatus(...args) {
4187
+ const mod = loadSetup();
4188
+ if (mod) return mod.createStandardChannelSetupStatus(...args);
4189
+ return {
4190
+ channelLabel: args[0]?.channelLabel ?? "QQ Bot",
4191
+ configuredLabel: "Configured",
4192
+ unconfiguredLabel: "Not configured",
4193
+ resolveConfigured: () => false
4194
+ };
4195
+ }
4196
+ function setSetupChannelEnabled(...args) {
4197
+ loadSetup()?.setSetupChannelEnabled?.(...args);
4198
+ }
4199
+ function formatDocsLink(...args) {
4200
+ const mod = loadTools();
4201
+ if (mod) return mod.formatDocsLink(...args);
4202
+ return args[1] ? `${args[1]}: ${args[0]}` : args[0];
4203
+ }
4204
+ var import_node_module2, req2, _setup, _tools, DEFAULT_ACCOUNT_ID2;
4205
+ var init_setup = __esm({
4206
+ "src/adapter/setup.ts"() {
4207
+ "use strict";
4208
+ import_node_module2 = require("module");
4209
+ req2 = (0, import_node_module2.createRequire)(__filename);
4210
+ DEFAULT_ACCOUNT_ID2 = "default";
4211
+ }
4212
+ });
4213
+
4214
+ // node_modules/.pnpm/qrcode-terminal@0.12.0/node_modules/qrcode-terminal/vendor/QRCode/QRMode.js
4215
+ var require_QRMode = __commonJS({
4216
+ "node_modules/.pnpm/qrcode-terminal@0.12.0/node_modules/qrcode-terminal/vendor/QRCode/QRMode.js"(exports2, module2) {
4217
+ "use strict";
4218
+ module2.exports = {
4219
+ MODE_NUMBER: 1 << 0,
4220
+ MODE_ALPHA_NUM: 1 << 1,
4221
+ MODE_8BIT_BYTE: 1 << 2,
4222
+ MODE_KANJI: 1 << 3
4223
+ };
3723
4224
  }
3724
4225
  });
3725
4226
 
@@ -4791,295 +5292,323 @@ var require_main = __commonJS({
4791
5292
  }
4792
5293
  });
4793
5294
 
4794
- // index.ts
4795
- var index_exports = {};
4796
- __export(index_exports, {
4797
- DEFAULT_ACCOUNT_ID: () => DEFAULT_ACCOUNT_ID,
4798
- MSG_TYPE_QUOTE: () => MSG_TYPE_QUOTE2,
4799
- MSG_TYPE_TEXT: () => MSG_TYPE_TEXT,
4800
- PersistedRefIndexStore: () => PersistedRefIndexStore,
4801
- QQBotGateway: () => QQBotGateway,
4802
- StreamContentType: () => StreamContentType2,
4803
- StreamInputMode: () => StreamInputMode2,
4804
- StreamInputState: () => StreamInputState2,
4805
- StreamingController: () => StreamingController,
4806
- applyQQBotAccountConfig: () => applyQQBotAccountConfig,
4807
- buildUserAgent: () => buildUserAgent,
4808
- default: () => index_default,
4809
- dispatchToOpenClaw: () => dispatchToOpenClaw,
4810
- flushAllRefIndexStores: () => flushAllRefIndexStores,
4811
- getBotForAccount: () => getBotForAccount,
4812
- getPersistedRefIndexStore: () => getPersistedRefIndexStore,
4813
- getQQBotRuntime: () => getQQBotRuntime,
4814
- isGroupAllowed: () => isGroupAllowed,
4815
- listQQBotAccountIds: () => listQQBotAccountIds,
4816
- parseTarget: () => parseTarget,
4817
- qqbotOnboardingAdapter: () => qqbotOnboardingAdapter,
4818
- qqbotPlugin: () => qqbotPlugin,
4819
- resolveDefaultQQBotAccountId: () => resolveDefaultQQBotAccountId,
4820
- resolveGroupAllowFrom: () => resolveGroupAllowFrom,
4821
- resolveGroupConfig: () => resolveGroupConfig,
4822
- resolveGroupConfigFromAccount: () => resolveGroupConfigFromAccount,
4823
- resolveGroupName: () => resolveGroupName,
4824
- resolveGroupPolicy: () => resolveGroupPolicy,
4825
- resolveGroupPrompt: () => resolveGroupPrompt,
4826
- resolveHistoryLimit: () => resolveHistoryLimit,
4827
- resolveIgnoreOtherMentions: () => resolveIgnoreOtherMentions,
4828
- resolveMentionPatterns: () => resolveMentionPatterns,
4829
- resolveProcessingTimeoutMs: () => resolveProcessingTimeoutMs,
4830
- resolveQQBotAccount: () => resolveQQBotAccount,
4831
- resolveRequireMention: () => resolveRequireMention,
4832
- resolveToolPolicy: () => resolveToolPolicy,
4833
- resolveUserAgentSuffix: () => resolveUserAgentSuffix,
4834
- sendMedia: () => sendMedia,
4835
- sendText: () => sendText,
4836
- setQQBotRuntime: () => setQQBotRuntime,
4837
- shouldUseStreaming: () => shouldUseStreaming,
4838
- tryGetBotForAccount: () => tryGetBotForAccount
4839
- });
4840
- module.exports = __toCommonJS(index_exports);
4841
- var import_plugin_sdk = require("openclaw/plugin-sdk");
4842
-
4843
- // src/channel.ts
4844
- var import_core = require("openclaw/plugin-sdk/core");
4845
-
4846
- // src/config.ts
4847
- function resolveMentionPatterns(cfg, agentId) {
4848
- if (agentId) {
4849
- const agents = cfg.agents;
4850
- const entry = agents?.list?.find((a) => a.id?.trim().toLowerCase() === agentId.trim().toLowerCase());
4851
- const agentGroupChat = entry?.groupChat;
4852
- if (agentGroupChat && Object.hasOwn(agentGroupChat, "mentionPatterns")) {
4853
- return agentGroupChat.mentionPatterns ?? [];
4854
- }
4855
- }
4856
- const globalGroupChat = cfg?.messages?.groupChat;
4857
- if (globalGroupChat && typeof globalGroupChat === "object" && Object.hasOwn(globalGroupChat, "mentionPatterns")) {
4858
- return globalGroupChat.mentionPatterns ?? [];
4859
- }
4860
- return [];
4861
- }
4862
- var DEFAULT_ACCOUNT_ID = "default";
4863
- function evaluateMatchedGroupAccessForPolicy(params) {
4864
- if (params.groupPolicy === "disabled") {
4865
- return { allowed: false, groupPolicy: params.groupPolicy, reason: "disabled" };
4866
- }
4867
- if (params.groupPolicy === "allowlist") {
4868
- if (params.requireMatchInput && !params.hasMatchInput) {
4869
- return { allowed: false, groupPolicy: params.groupPolicy, reason: "missing_match_input" };
4870
- }
4871
- if (!params.allowlistConfigured) {
4872
- return { allowed: false, groupPolicy: params.groupPolicy, reason: "empty_allowlist" };
4873
- }
4874
- if (!params.allowlistMatched) {
4875
- return { allowed: false, groupPolicy: params.groupPolicy, reason: "not_allowlisted" };
4876
- }
4877
- }
4878
- return { allowed: true, groupPolicy: params.groupPolicy, reason: "allowed" };
4879
- }
4880
- var DEFAULT_GROUP_POLICY = "open";
4881
- var DEFAULT_GROUP_HISTORY_LIMIT = 20;
4882
- var DEFAULT_PROCESSING_TIMEOUT_MS = 0;
4883
- var DEFAULT_GROUP_CONFIG = {
4884
- requireMention: true,
4885
- ignoreOtherMentions: false,
4886
- toolPolicy: "restricted",
4887
- name: "",
4888
- historyLimit: DEFAULT_GROUP_HISTORY_LIMIT
4889
- };
4890
- var DEFAULT_GROUP_PROMPT = [
4891
- "\u82E5\u53D1\u9001\u8005\u4E3A\u673A\u5668\u4EBA\uFF0C\u4EC5\u5728\u5BF9\u65B9\u660E\u786E@\u4F60\u63D0\u95EE\u6216\u8BF7\u6C42\u534F\u52A9\u5177\u4F53\u4EFB\u52A1\u65F6\uFF0C\u4EE5\u7B80\u6D01\u660E\u4E86\u7684\u5185\u5BB9\u56DE\u590D\uFF0C",
4892
- "\u907F\u514D\u4E0E\u5176\u4ED6\u673A\u5668\u4EBA\u4EA7\u751F\u62A2\u7B54\u6216\u591A\u8F6E\u65E0\u610F\u4E49\u5BF9\u8BDD\u3002",
4893
- "\u5728\u7FA4\u804A\u4E2D\u4F18\u5148\u8BA9\u4EBA\u7C7B\u7528\u6237\u7684\u6D88\u606F\u5F97\u5230\u54CD\u5E94\uFF0C\u673A\u5668\u4EBA\u4E4B\u95F4\u4FDD\u6301\u534F\u4F5C\u800C\u975E\u7ADE\u4E89\uFF0C\u786E\u4FDD\u5BF9\u8BDD\u6709\u5E8F\u4E0D\u5237\u5C4F\u3002"
4894
- ].join("");
4895
- function resolveGroupPolicy(cfg, accountId) {
4896
- const account = resolveQQBotAccount(cfg, accountId);
4897
- return account.config?.groupPolicy ?? DEFAULT_GROUP_POLICY;
4898
- }
4899
- function resolveGroupAllowFrom(cfg, accountId) {
4900
- const account = resolveQQBotAccount(cfg, accountId);
4901
- return (account.config?.groupAllowFrom ?? []).map((id) => String(id).trim().toUpperCase());
4902
- }
4903
- function isGroupAllowed(cfg, groupOpenid, accountId) {
4904
- const account = resolveQQBotAccount(cfg, accountId);
4905
- const policy = account.config?.groupPolicy ?? DEFAULT_GROUP_POLICY;
4906
- const allowList = (account.config?.groupAllowFrom ?? []).map((id) => String(id).trim().toUpperCase());
4907
- const allowlistConfigured = allowList.length > 0;
4908
- const allowlistMatched = allowList.some((id) => id === "*" || id === groupOpenid.toUpperCase());
4909
- return evaluateMatchedGroupAccessForPolicy({
4910
- groupPolicy: policy,
4911
- allowlistConfigured,
4912
- allowlistMatched
4913
- }).allowed;
4914
- }
4915
- function resolveGroupConfigFromAccount(account, groupOpenid) {
4916
- const groups = account.config?.groups ?? {};
4917
- const wildcardCfg = groups["*"] ?? {};
4918
- const specificCfg = groups[groupOpenid] ?? {};
4919
- const accountDefaultRequireMention = account.config?.defaultRequireMention ?? DEFAULT_GROUP_CONFIG.requireMention;
4920
- return {
4921
- requireMention: specificCfg.requireMention ?? wildcardCfg.requireMention ?? accountDefaultRequireMention,
4922
- ignoreOtherMentions: specificCfg.ignoreOtherMentions ?? wildcardCfg.ignoreOtherMentions ?? DEFAULT_GROUP_CONFIG.ignoreOtherMentions,
4923
- toolPolicy: specificCfg.toolPolicy ?? wildcardCfg.toolPolicy ?? DEFAULT_GROUP_CONFIG.toolPolicy,
4924
- name: specificCfg.name ?? wildcardCfg.name ?? DEFAULT_GROUP_CONFIG.name,
4925
- prompt: specificCfg.prompt ?? wildcardCfg.prompt ?? DEFAULT_GROUP_PROMPT,
4926
- historyLimit: specificCfg.historyLimit ?? wildcardCfg.historyLimit ?? DEFAULT_GROUP_CONFIG.historyLimit
4927
- };
5295
+ // node_modules/.pnpm/@tencent-connect+qqbot-connector@1.2.0/node_modules/@tencent-connect/qqbot-connector/dist/esm/qqbot-session.js
5296
+ function d(t = "production") {
5297
+ return E[t];
4928
5298
  }
4929
- function resolveGroupConfig(cfg, groupOpenid, accountId) {
4930
- return resolveGroupConfigFromAccount(resolveQQBotAccount(cfg, accountId), groupOpenid);
5299
+ function l() {
5300
+ return import_node_crypto.default.randomBytes(32).toString("base64");
4931
5301
  }
4932
- function resolveHistoryLimit(cfg, groupOpenid, accountId) {
4933
- return Math.max(0, resolveGroupConfig(cfg, groupOpenid, accountId).historyLimit);
5302
+ function b(t, r) {
5303
+ const a = Buffer.from(r, "base64"), n = Buffer.from(t, "base64"), e = n.subarray(0, 12), c = n.subarray(n.length - 16), s = n.subarray(12, n.length - 16), o = import_node_crypto.default.createDecipheriv("aes-256-gcm", a, e);
5304
+ return o.setAuthTag(c), Buffer.concat([o.update(s), o.final()]).toString("utf8");
4934
5305
  }
4935
- function resolveGroupPrompt(cfg, groupOpenid, accountId) {
4936
- return resolveGroupConfig(cfg, groupOpenid, accountId).prompt;
5306
+ function h(t, r, a) {
5307
+ return new Promise((n, e) => {
5308
+ const c = JSON.stringify(r), s = new URL(t), o = import_node_https.default.request({ hostname: s.hostname, path: s.pathname + s.search, method: "POST", timeout: a, headers: { "Content-Type": "application/json", Accept: "application/json", "Content-Length": Buffer.byteLength(c) } }, (i) => {
5309
+ if (i.statusCode !== 200) {
5310
+ i.resume(), e(new Error(`HTTP ${i.statusCode} from ${t}`));
5311
+ return;
5312
+ }
5313
+ let f = "";
5314
+ i.on("data", (p2) => {
5315
+ f += p2;
5316
+ }), i.on("end", () => {
5317
+ try {
5318
+ n(JSON.parse(f));
5319
+ } catch (p2) {
5320
+ e(p2);
5321
+ }
5322
+ });
5323
+ });
5324
+ o.on("error", e), o.on("timeout", () => {
5325
+ o.destroy(), e(new Error(`timeout fetching ${t}`));
5326
+ }), o.end(c);
5327
+ });
4937
5328
  }
4938
- function resolveRequireMention(cfg, groupOpenid, accountId) {
4939
- return resolveGroupConfig(cfg, groupOpenid, accountId).requireMention;
5329
+ async function y(t = "production", r = 1e4) {
5330
+ const a = `https://${d(t)}/lite/create_bind_task`, n = l(), e = await h(a, { key: n }, r);
5331
+ if (e.retcode !== 0) throw new Error(e.msg ?? "create_bind_task failed");
5332
+ if (!e.data?.task_id) throw new Error("create_bind_task: missing task_id");
5333
+ return { taskId: e.data.task_id, key: n };
4940
5334
  }
4941
- function resolveIgnoreOtherMentions(cfg, groupOpenid, accountId) {
4942
- return resolveGroupConfig(cfg, groupOpenid, accountId).ignoreOtherMentions;
5335
+ async function g(t, r = "production", a = 1e4) {
5336
+ const n = `https://${d(r)}/lite/poll_bind_result`, e = await h(n, { task_id: t }, a);
5337
+ if (e.retcode !== 0) throw new Error(e.msg ?? "poll_bind_result failed");
5338
+ return { status: e.data?.status ?? u.NONE, botAppId: String(e.data?.bot_appid ?? ""), botEncryptSecret: e.data?.bot_encrypt_secret ?? "", userOpenid: e.data?.user_openid || void 0 };
4943
5339
  }
4944
- function resolveToolPolicy(cfg, groupOpenid, accountId) {
4945
- return resolveGroupConfig(cfg, groupOpenid, accountId).toolPolicy;
5340
+ function w(t, r = "") {
5341
+ return `https://${d("production")}/qqbot/openclaw/connect.html?task_id=${encodeURIComponent(t)}&source=${encodeURIComponent(r)}&_wv=2`;
4946
5342
  }
4947
- function resolveGroupName(cfg, groupOpenid, accountId) {
4948
- const name = resolveGroupConfig(cfg, groupOpenid, accountId).name;
4949
- return name || groupOpenid.slice(0, 8);
5343
+ var import_node_crypto, import_node_https, E, u;
5344
+ var init_qqbot_session = __esm({
5345
+ "node_modules/.pnpm/@tencent-connect+qqbot-connector@1.2.0/node_modules/@tencent-connect/qqbot-connector/dist/esm/qqbot-session.js"() {
5346
+ "use strict";
5347
+ import_node_crypto = __toESM(require("crypto"), 1);
5348
+ import_node_https = __toESM(require("https"), 1);
5349
+ E = { production: "q.qq.com", test: "test.q.qq.com" };
5350
+ (function(t) {
5351
+ t[t.NONE = 0] = "NONE", t[t.PENDING = 1] = "PENDING", t[t.COMPLETED = 2] = "COMPLETED", t[t.EXPIRED = 3] = "EXPIRED";
5352
+ })(u || (u = {}));
5353
+ }
5354
+ });
5355
+
5356
+ // node_modules/.pnpm/@tencent-connect+qqbot-connector@1.2.0/node_modules/@tencent-connect/qqbot-connector/dist/esm/qr-connect.js
5357
+ function F(r) {
5358
+ return new Promise((o) => {
5359
+ import_qrcode_terminal.default.generate(r, { small: true }, (e) => {
5360
+ o(e);
5361
+ });
5362
+ });
4950
5363
  }
4951
- function normalizeAppId(raw) {
4952
- if (raw === null || raw === void 0) return "";
4953
- return String(raw).trim();
5364
+ function d2(r, o) {
5365
+ return new Promise((e, t) => {
5366
+ if (o?.aborted) {
5367
+ t(new DOMException("Aborted", "AbortError"));
5368
+ return;
5369
+ }
5370
+ const n = setTimeout(e, r);
5371
+ o?.addEventListener("abort", () => {
5372
+ clearTimeout(n), t(new DOMException("Aborted", "AbortError"));
5373
+ }, { once: true });
5374
+ });
4954
5375
  }
4955
- function listQQBotAccountIds(cfg) {
4956
- const ids = /* @__PURE__ */ new Set();
4957
- const qqbot = cfg.channels?.qqbot;
4958
- if (qqbot?.appId) {
4959
- ids.add(DEFAULT_ACCOUNT_ID);
4960
- }
4961
- if (qqbot?.accounts) {
4962
- for (const accountId of Object.keys(qqbot.accounts)) {
4963
- if (qqbot.accounts[accountId]?.appId) {
4964
- ids.add(accountId);
4965
- }
5376
+ async function C(r, o, e) {
5377
+ for (; !e?.aborted; ) {
5378
+ let t;
5379
+ try {
5380
+ t = await g(r);
5381
+ } catch {
5382
+ await d2(p, e);
5383
+ continue;
5384
+ }
5385
+ if (t.status === u.COMPLETED) {
5386
+ const n = b(t.botEncryptSecret, o);
5387
+ return { outcome: "scanned", appId: t.botAppId, appSecret: n, userOpenid: t.userOpenid };
4966
5388
  }
5389
+ if (t.status === u.EXPIRED) return { outcome: "expired" };
5390
+ await d2(p, e);
4967
5391
  }
4968
- return Array.from(ids);
5392
+ throw new DOMException("Aborted", "AbortError");
4969
5393
  }
4970
- function resolveDefaultQQBotAccountId(cfg) {
4971
- const qqbot = cfg.channels?.qqbot;
4972
- if (qqbot?.appId) {
4973
- return DEFAULT_ACCOUNT_ID;
4974
- }
4975
- if (qqbot?.accounts) {
4976
- const ids = Object.keys(qqbot.accounts);
4977
- if (ids.length > 0) {
4978
- return ids[0];
5394
+ function l2(r, o) {
5395
+ const e = new AbortController(), t = o?.signal ? AbortSignal.any([e.signal, o.signal]) : e.signal;
5396
+ return (async () => {
5397
+ const n = o?.displayQrCodeToConsole ?? true;
5398
+ for (; ; ) {
5399
+ if (t.aborted) throw new DOMException("Aborted", "AbortError");
5400
+ let a;
5401
+ try {
5402
+ a = await y();
5403
+ } catch (u2) {
5404
+ throw new Error(`\u83B7\u53D6\u7ED1\u5B9A\u4EFB\u52A1\u5931\u8D25: ${u2 instanceof Error ? u2.message : String(u2)}`, { cause: u2 });
5405
+ }
5406
+ const i = w(a.taskId, o?.source);
5407
+ if (n) {
5408
+ const u2 = await F(i);
5409
+ console.log(u2), console.log(`\u8BF7\u4F7F\u7528\u624B\u673A QQ \u626B\u63CF\u4E0A\u65B9\u4E8C\u7EF4\u7801\uFF0C\u5B8C\u6210\u673A\u5668\u4EBA\u7ED1\u5B9A\u3002
5410
+ `);
5411
+ }
5412
+ r.onQrDisplayed?.(i);
5413
+ const s = await C(a.taskId, a.key, t);
5414
+ if (s.outcome === "scanned") {
5415
+ r.onSuccess([{ appId: s.appId, appSecret: s.appSecret, userOpenid: s.userOpenid }]);
5416
+ return;
5417
+ }
5418
+ r.onQrExpired?.(), n && console.log(`\u4E8C\u7EF4\u7801\u5DF2\u8FC7\u671F\uFF0C\u6B63\u5728\u5237\u65B0\u2026
5419
+ `);
4979
5420
  }
4980
- }
4981
- return DEFAULT_ACCOUNT_ID;
5421
+ })().catch((n) => {
5422
+ if (n instanceof DOMException && n.name === "AbortError") {
5423
+ r.onFailure(new Error("\u5DF2\u53D6\u6D88"));
5424
+ return;
5425
+ }
5426
+ r.onFailure(n instanceof Error ? n : new Error(String(n)));
5427
+ }), () => e.abort();
4982
5428
  }
4983
- function resolveUserAgentSuffix(cfg) {
4984
- const qqbot = cfg.channels?.qqbot;
4985
- return qqbot?.userAgentSuffix ? String(qqbot.userAgentSuffix).trim() : "";
5429
+ function m2(r) {
5430
+ return new Promise((o, e) => {
5431
+ l2({ onSuccess: o, onFailure: e }, { ...r, displayQrCodeToConsole: true });
5432
+ });
4986
5433
  }
4987
- function resolveProcessingTimeoutMs(accountConfig) {
4988
- if (accountConfig?.processingTimeoutMs !== void 0) {
4989
- return accountConfig.processingTimeoutMs;
5434
+ var import_qrcode_terminal, p;
5435
+ var init_qr_connect = __esm({
5436
+ "node_modules/.pnpm/@tencent-connect+qqbot-connector@1.2.0/node_modules/@tencent-connect/qqbot-connector/dist/esm/qr-connect.js"() {
5437
+ "use strict";
5438
+ import_qrcode_terminal = __toESM(require_main(), 1);
5439
+ init_qqbot_session();
5440
+ p = 2e3;
4990
5441
  }
4991
- const env = process.env.OPENCLAW_PROCESSING_TIMEOUT_MS;
4992
- if (env) {
4993
- const v = Number(env);
4994
- if (!Number.isNaN(v) && v >= 0) return v;
5442
+ });
5443
+
5444
+ // node_modules/.pnpm/@tencent-connect+qqbot-connector@1.2.0/node_modules/@tencent-connect/qqbot-connector/dist/esm/index.js
5445
+ var init_esm = __esm({
5446
+ "node_modules/.pnpm/@tencent-connect+qqbot-connector@1.2.0/node_modules/@tencent-connect/qqbot-connector/dist/esm/index.js"() {
5447
+ "use strict";
5448
+ init_qr_connect();
4995
5449
  }
4996
- return DEFAULT_PROCESSING_TIMEOUT_MS;
5450
+ });
5451
+
5452
+ // src/setup/account-key.ts
5453
+ var account_key_exports = {};
5454
+ __export(account_key_exports, {
5455
+ resolveAccountKey: () => resolveAccountKey
5456
+ });
5457
+ function resolveAccountKey(cfg, appId, resolvedId) {
5458
+ if (resolvedId) return resolvedId;
5459
+ for (const id of listQQBotAccountIds(cfg)) {
5460
+ if (resolveQQBotAccount(cfg, id).appId === appId) return id;
5461
+ }
5462
+ if (listQQBotAccountIds(cfg).length === 0) return "default";
5463
+ return appId;
4997
5464
  }
4998
- function resolveQQBotAccount(cfg, accountId) {
4999
- const resolvedAccountId = accountId ?? resolveDefaultQQBotAccountId(cfg);
5000
- const qqbot = cfg.channels?.qqbot;
5001
- let accountConfig = {};
5002
- let appId = "";
5003
- let clientSecret = "";
5004
- let secretSource = "none";
5005
- if (resolvedAccountId === DEFAULT_ACCOUNT_ID) {
5006
- const { accounts: _accounts, ...topLevelConfig } = qqbot ?? {};
5007
- accountConfig = {
5008
- ...topLevelConfig,
5009
- markdownSupport: qqbot?.markdownSupport ?? true
5010
- };
5011
- appId = normalizeAppId(qqbot?.appId);
5012
- } else {
5013
- const account = qqbot?.accounts?.[resolvedAccountId];
5014
- accountConfig = account ?? {};
5015
- appId = normalizeAppId(account?.appId);
5465
+ var init_account_key = __esm({
5466
+ "src/setup/account-key.ts"() {
5467
+ "use strict";
5468
+ init_config();
5016
5469
  }
5017
- if (accountConfig.clientSecret) {
5018
- clientSecret = accountConfig.clientSecret;
5019
- secretSource = "config";
5020
- } else if (accountConfig.clientSecretFile) {
5021
- secretSource = "file";
5022
- } else if (process.env.QQBOT_CLIENT_SECRET && resolvedAccountId === DEFAULT_ACCOUNT_ID) {
5023
- clientSecret = process.env.QQBOT_CLIENT_SECRET;
5024
- secretSource = "env";
5470
+ });
5471
+
5472
+ // src/setup/finalize.ts
5473
+ var finalize_exports = {};
5474
+ __export(finalize_exports, {
5475
+ applyAccountDefaults: () => applyAccountDefaults,
5476
+ finalizeQQBotSetup: () => finalizeQQBotSetup
5477
+ });
5478
+ function isConfigured(cfg, accountId) {
5479
+ const account = resolveQQBotAccount(cfg, accountId);
5480
+ return Boolean(account.appId && account.clientSecret);
5481
+ }
5482
+ async function linkViaQrCode(cfg, _accountId, prompter, rt) {
5483
+ try {
5484
+ const accounts = await m2({ source: "openclaw" });
5485
+ if (accounts.length === 0) {
5486
+ await prompter.note("\u672A\u83B7\u53D6\u5230\u4EFB\u4F55 QQ Bot \u8D26\u53F7\u4FE1\u606F\u3002", "QQ Bot");
5487
+ return cfg;
5488
+ }
5489
+ let next = cfg;
5490
+ for (const { appId, appSecret, userOpenid } of accounts) {
5491
+ const key = resolveAccountKey(cfg, appId);
5492
+ next = applyQQBotAccountConfig(next, key, { appId, clientSecret: appSecret });
5493
+ next = applyAccountDefaults(next, key, userOpenid);
5494
+ rt.log(`\u7ED1\u5B9A\u6210\u529F\uFF01\u8D26\u6237: ${key} (AppID: ${appId})`);
5495
+ }
5496
+ return next;
5497
+ } catch (err) {
5498
+ rt.error(`QQ Bot \u7ED1\u5B9A\u5931\u8D25: ${String(err)}`);
5499
+ await prompter.note(`\u7ED1\u5B9A\u5931\u8D25\uFF0C\u60A8\u53EF\u4EE5\u7A0D\u540E\u624B\u52A8\u914D\u7F6E\u3002
5500
+ \u6587\u6863: ${formatDocsLink("/channels/qqbot", "qqbot")}`, "QQ Bot");
5501
+ return cfg;
5025
5502
  }
5026
- if (!appId && process.env.QQBOT_APP_ID && resolvedAccountId === DEFAULT_ACCOUNT_ID) {
5027
- appId = normalizeAppId(process.env.QQBOT_APP_ID);
5503
+ }
5504
+ async function linkViaManual(cfg, _accountId, prompter) {
5505
+ const appIdInput = await prompter.text({ message: "\u8BF7\u8F93\u5165 QQ Bot AppID", validate: (v) => v.trim() ? void 0 : "AppID \u4E0D\u80FD\u4E3A\u7A7A" });
5506
+ const secret = await prompter.text({ message: "\u8BF7\u8F93\u5165 QQ Bot AppSecret", validate: (v) => v.trim() ? void 0 : "AppSecret \u4E0D\u80FD\u4E3A\u7A7A" });
5507
+ const appId = appIdInput.trim();
5508
+ const key = resolveAccountKey(cfg, appId);
5509
+ let next = applyQQBotAccountConfig(cfg, key, { appId, clientSecret: secret.trim() });
5510
+ next = applyAccountDefaults(next, key);
5511
+ await prompter.note("\u2714 QQ Bot \u914D\u7F6E\u5B8C\u6210\uFF01", "QQ Bot");
5512
+ return next;
5513
+ }
5514
+ async function finalizeQQBotSetup(params) {
5515
+ const accountId = params.accountId.trim() || DEFAULT_ACCOUNT_ID2;
5516
+ const configured = isConfigured(params.cfg, accountId);
5517
+ const mode = await params.prompter.select({
5518
+ message: configured ? "QQ \u5DF2\u7ED1\u5B9A\uFF0C\u9009\u62E9\u64CD\u4F5C" : "\u9009\u62E9 QQ \u7ED1\u5B9A\u65B9\u5F0F",
5519
+ options: [
5520
+ { value: "qr", label: "\u626B\u7801\u7ED1\u5B9A\uFF08\u63A8\u8350\uFF09", hint: "\u4F7F\u7528 QQ \u626B\u63CF\u4E8C\u7EF4\u7801\u81EA\u52A8\u5B8C\u6210\u7ED1\u5B9A" },
5521
+ { value: "manual", label: "\u624B\u52A8\u8F93\u5165 QQ Bot AppID \u548C AppSecret", hint: "\u9700\u5230 QQ \u5F00\u653E\u5E73\u53F0 q.qq.com \u67E5\u770B" },
5522
+ { value: "skip", label: configured ? "\u4FDD\u6301\u5F53\u524D\u914D\u7F6E" : "\u7A0D\u540E\u914D\u7F6E" }
5523
+ ]
5524
+ });
5525
+ let next = params.cfg;
5526
+ if (mode === "qr") {
5527
+ next = await linkViaQrCode(next, accountId, params.prompter, params.runtime);
5528
+ } else if (mode === "manual") {
5529
+ next = await linkViaManual(next, accountId, params.prompter);
5530
+ } else if (!configured) {
5531
+ await params.prompter.note("\u60A8\u53EF\u4EE5\u7A0D\u540E\u8FD0\u884C\u4EE5\u4E0B\u547D\u4EE4\u91CD\u65B0\u914D\u7F6E\uFF1A\n openclaw channels add", "QQ Bot");
5028
5532
  }
5029
- return {
5030
- accountId: resolvedAccountId,
5031
- name: accountConfig.name,
5032
- enabled: accountConfig.enabled !== false,
5033
- appId,
5034
- clientSecret,
5035
- secretSource,
5036
- systemPrompt: accountConfig.systemPrompt,
5037
- markdownSupport: accountConfig.markdownSupport !== false,
5038
- userAgentSuffix: resolveUserAgentSuffix(cfg),
5039
- processingTimeoutMs: resolveProcessingTimeoutMs(accountConfig),
5040
- config: accountConfig
5041
- };
5533
+ return { cfg: next };
5042
5534
  }
5043
- function applyQQBotAccountConfig(cfg, accountId, input) {
5044
- const next = { ...cfg };
5045
- if (accountId === DEFAULT_ACCOUNT_ID) {
5046
- const existingConfig = next.channels?.qqbot || {};
5047
- const allowFrom = existingConfig.allowFrom ?? ["*"];
5048
- next.channels = {
5049
- ...next.channels,
5050
- qqbot: {
5051
- ...next.channels?.qqbot || {},
5052
- enabled: true,
5053
- allowFrom,
5054
- ...input.appId ? { appId: input.appId } : {},
5055
- ...input.clientSecret ? { clientSecret: input.clientSecret } : input.clientSecretFile ? { clientSecretFile: input.clientSecretFile } : {},
5056
- ...input.name ? { name: input.name } : {}
5057
- }
5058
- };
5535
+ function applyAccountDefaults(cfg, accountId, userOpenid) {
5536
+ const next = { ...cfg, channels: { ...cfg.channels } };
5537
+ const qqbot = { ...next.channels?.qqbot ?? {} };
5538
+ const defaults = { streaming: true, dmPolicy: "allowlist" };
5539
+ if (userOpenid) defaults.allowFrom = [userOpenid];
5540
+ if (accountId === DEFAULT_ACCOUNT_ID2) {
5541
+ Object.assign(qqbot, defaults);
5059
5542
  } else {
5060
- const existingAccountConfig = next.channels?.qqbot?.accounts?.[accountId] || {};
5061
- const allowFrom = existingAccountConfig.allowFrom ?? ["*"];
5062
- next.channels = {
5063
- ...next.channels,
5064
- qqbot: {
5065
- ...next.channels?.qqbot || {},
5066
- enabled: true,
5067
- accounts: {
5068
- ...next.channels?.qqbot?.accounts || {},
5069
- [accountId]: {
5070
- ...next.channels?.qqbot?.accounts?.[accountId] || {},
5071
- enabled: true,
5072
- allowFrom,
5073
- ...input.appId ? { appId: input.appId } : {},
5074
- ...input.clientSecret ? { clientSecret: input.clientSecret } : input.clientSecretFile ? { clientSecretFile: input.clientSecretFile } : {},
5075
- ...input.name ? { name: input.name } : {}
5076
- }
5077
- }
5078
- }
5079
- };
5543
+ const accounts = { ...qqbot.accounts ?? {} };
5544
+ accounts[accountId] = { ...accounts[accountId] ?? {}, ...defaults };
5545
+ qqbot.accounts = accounts;
5080
5546
  }
5547
+ next.channels = { ...next.channels, qqbot };
5081
5548
  return next;
5082
5549
  }
5550
+ var init_finalize = __esm({
5551
+ "src/setup/finalize.ts"() {
5552
+ "use strict";
5553
+ init_setup();
5554
+ init_esm();
5555
+ init_config();
5556
+ init_account_key();
5557
+ }
5558
+ });
5559
+
5560
+ // index.ts
5561
+ var index_exports = {};
5562
+ __export(index_exports, {
5563
+ DEFAULT_ACCOUNT_ID: () => DEFAULT_ACCOUNT_ID,
5564
+ MSG_TYPE_QUOTE: () => MSG_TYPE_QUOTE2,
5565
+ MSG_TYPE_TEXT: () => MSG_TYPE_TEXT,
5566
+ PersistedRefIndexStore: () => PersistedRefIndexStore,
5567
+ QQBotGateway: () => QQBotGateway,
5568
+ StreamContentType: () => StreamContentType2,
5569
+ StreamInputMode: () => StreamInputMode2,
5570
+ StreamInputState: () => StreamInputState2,
5571
+ StreamingController: () => StreamingController,
5572
+ applyQQBotAccountConfig: () => applyQQBotAccountConfig,
5573
+ buildUserAgent: () => buildUserAgent,
5574
+ default: () => index_default,
5575
+ dispatchToOpenClaw: () => dispatchToOpenClaw,
5576
+ flushAllRefIndexStores: () => flushAllRefIndexStores,
5577
+ getBotForAccount: () => getBotForAccount,
5578
+ getPersistedRefIndexStore: () => getPersistedRefIndexStore,
5579
+ getQQBotRuntime: () => getQQBotRuntime,
5580
+ isGroupAllowed: () => isGroupAllowed,
5581
+ listQQBotAccountIds: () => listQQBotAccountIds,
5582
+ parseTarget: () => parseTarget,
5583
+ qqbotOnboardingAdapter: () => qqbotOnboardingAdapter,
5584
+ qqbotPlugin: () => qqbotPlugin,
5585
+ resolveDefaultQQBotAccountId: () => resolveDefaultQQBotAccountId,
5586
+ resolveGroupAllowFrom: () => resolveGroupAllowFrom,
5587
+ resolveGroupConfig: () => resolveGroupConfig,
5588
+ resolveGroupConfigFromAccount: () => resolveGroupConfigFromAccount,
5589
+ resolveGroupName: () => resolveGroupName,
5590
+ resolveGroupPolicy: () => resolveGroupPolicy,
5591
+ resolveGroupPrompt: () => resolveGroupPrompt,
5592
+ resolveHistoryLimit: () => resolveHistoryLimit,
5593
+ resolveIgnoreOtherMentions: () => resolveIgnoreOtherMentions,
5594
+ resolveMentionPatterns: () => resolveMentionPatterns,
5595
+ resolveProcessingTimeoutMs: () => resolveProcessingTimeoutMs,
5596
+ resolveQQBotAccount: () => resolveQQBotAccount,
5597
+ resolveRequireMention: () => resolveRequireMention,
5598
+ resolveToolPolicy: () => resolveToolPolicy,
5599
+ resolveUserAgentSuffix: () => resolveUserAgentSuffix,
5600
+ sendMedia: () => sendMedia,
5601
+ sendText: () => sendText,
5602
+ setQQBotRuntime: () => setQQBotRuntime,
5603
+ shouldUseStreaming: () => shouldUseStreaming,
5604
+ tryGetBotForAccount: () => tryGetBotForAccount
5605
+ });
5606
+ module.exports = __toCommonJS(index_exports);
5607
+ var import_plugin_sdk = require("openclaw/plugin-sdk");
5608
+
5609
+ // src/channel.ts
5610
+ var import_core = require("openclaw/plugin-sdk/core");
5611
+ init_config();
5083
5612
 
5084
5613
  // src/bot-instance.ts
5085
5614
  var import_node_os = __toESM(require("os"), 1);
@@ -9295,7 +9824,7 @@ var import_node_path2 = __toESM(require("path"), 1);
9295
9824
  var import_node_fs2 = __toESM(require("fs"), 1);
9296
9825
  var _cachedOpenclawVersion;
9297
9826
  function getPackageVersion() {
9298
- return true ? "2.0.0-dev.202607101541" : "unknown";
9827
+ return true ? "2.0.0-dev.202607101939" : "unknown";
9299
9828
  }
9300
9829
  function getOpenclawVersion(runtimeVersion) {
9301
9830
  if (_cachedOpenclawVersion) return _cachedOpenclawVersion;
@@ -9636,224 +10165,81 @@ var PersistedRefIndexStore = class {
9636
10165
  get size() {
9637
10166
  return this.memory.size;
9638
10167
  }
9639
- /** 是否已完成初始化(磁盘回放) */
9640
- get isInitialized() {
9641
- return this.initialized;
9642
- }
9643
- /** 诊断快照 */
9644
- stats() {
9645
- return {
9646
- memoryEntries: this.memory.size,
9647
- diskLines: this.diskLineCount,
9648
- maxEntries: this.maxEntries,
9649
- filePath: this.filePath
9650
- };
9651
- }
9652
- /**
9653
- * 强制将当前内存状态持久化到磁盘(进程退出前调用)
9654
- */
9655
- flush() {
9656
- this.compactSync();
9657
- }
9658
- };
9659
- var stores = /* @__PURE__ */ new Map();
9660
- function getPersistedRefIndexStore(accountId) {
9661
- let store = stores.get(accountId);
9662
- if (!store) {
9663
- const filePath = import_node_path3.default.join(getQQBotDataDir("data", accountId), DEFAULT_FILENAME);
9664
- store = new PersistedRefIndexStore({ filePath });
9665
- stores.set(accountId, store);
9666
- }
9667
- return store;
9668
- }
9669
- function flushAllRefIndexStores() {
9670
- for (const store of stores.values()) {
9671
- store.flush();
9672
- }
9673
- }
9674
-
9675
- // src/runtime.ts
9676
- var runtime = null;
9677
- var exitHooksInstalled = false;
9678
- function setQQBotRuntime(next) {
9679
- runtime = next;
9680
- const version = getOpenclawVersion(next.version);
9681
- setOpenClawVersion(version);
9682
- installExitHooksOnce();
9683
- }
9684
- function installExitHooksOnce() {
9685
- if (exitHooksInstalled) return;
9686
- exitHooksInstalled = true;
9687
- const flush = () => {
9688
- try {
9689
- flushAllRefIndexStores();
9690
- } catch {
9691
- }
9692
- };
9693
- process.on("beforeExit", flush);
9694
- process.on("SIGINT", () => {
9695
- flush();
9696
- process.exit(0);
9697
- });
9698
- process.on("SIGTERM", () => {
9699
- flush();
9700
- process.exit(0);
9701
- });
9702
- }
9703
- function getQQBotRuntime() {
9704
- if (!runtime) throw new Error("QQBot runtime not initialized");
9705
- return runtime;
9706
- }
9707
- function tryGetQQBotRuntime() {
9708
- return runtime;
9709
- }
9710
-
9711
- // src/adapter/resolve.ts
9712
- function probeFunction(rt, paths) {
9713
- for (const path22 of paths) {
9714
- let target = rt;
9715
- let parent = rt;
9716
- for (let i = 0; i < path22.length; i++) {
9717
- parent = target;
9718
- target = target?.[path22[i]];
9719
- if (target === void 0 || target === null) break;
9720
- }
9721
- if (typeof target === "function") {
9722
- return target.bind(parent);
9723
- }
9724
- }
9725
- return null;
9726
- }
9727
- function resolveRuntimeAdapters(rt, log4) {
9728
- const version = rt.version ?? "unknown";
9729
- const inboundRun = probeFunction(rt, [
9730
- ["channel", "inbound", "run"],
9731
- // current (2026-05+)
9732
- ["channel", "turn", "run"]
9733
- // legacy (removed 2026-05-27)
9734
- ]);
9735
- const dispatchReply = probeFunction(rt, [
9736
- ["channel", "reply", "dispatchReplyWithBufferedBlockDispatcher"]
9737
- ]);
9738
- const resolveAgentRoute = probeFunction(rt, [
9739
- ["channel", "routing", "resolveAgentRoute"]
9740
- ]);
9741
- const rawBuildContext = probeFunction(rt, [
9742
- ["channel", "inbound", "buildContext"]
9743
- ]);
9744
- const rawFinalizeContext = !rawBuildContext ? probeFunction(rt, [["channel", "reply", "finalizeInboundContext"]]) : null;
9745
- const buildInboundContext = rawBuildContext ? (params) => rawBuildContext(params) : rawFinalizeContext ? (params) => {
9746
- const isCommand = params.access?.commands?.authorized ?? false;
9747
- const rawCtx = {
9748
- Body: params.message.body,
9749
- BodyForAgent: params.message.bodyForAgent,
9750
- RawBody: params.message.rawBody,
9751
- CommandBody: params.message.commandBody ?? params.message.rawBody,
9752
- CommandSource: isCommand ? "text" : void 0,
9753
- CommandTurn: params.command ?? void 0,
9754
- CommandAuthorized: isCommand,
9755
- From: params.from,
9756
- To: params.reply.to,
9757
- SessionKey: params.route.routeSessionKey,
9758
- AccountId: params.route.accountId ?? params.accountId,
9759
- ChatType: params.conversation.kind,
9760
- GroupSystemPrompt: params.conversation.label,
9761
- SenderId: params.sender.id,
9762
- SenderName: params.sender.name,
9763
- Provider: params.provider ?? params.channel,
9764
- Surface: params.surface ?? params.channel,
9765
- MessageSid: params.messageId,
9766
- Timestamp: params.timestamp ?? Date.now(),
9767
- OriginatingChannel: params.channel,
9768
- OriginatingTo: params.reply.originatingTo ?? params.reply.to,
9769
- ...params.extra
9770
- };
9771
- return rawFinalizeContext(rawCtx);
9772
- } : null;
9773
- const resolveStorePath = probeFunction(rt, [
9774
- ["channel", "session", "resolveStorePath"]
9775
- ]);
9776
- const recordInboundSession = probeFunction(rt, [
9777
- ["channel", "session", "recordInboundSession"]
9778
- ]);
9779
- const formatEnvelope = probeFunction(rt, [
9780
- ["channel", "reply", "formatAgentEnvelope"],
9781
- // current (2026-06+)
9782
- ["channel", "reply", "formatInboundEnvelope"]
9783
- // deprecated,低版本兼容
9784
- ]);
9785
- const resolveEnvelopeFormatOptions = probeFunction(rt, [
9786
- ["channel", "reply", "resolveEnvelopeFormatOptions"]
9787
- ]);
9788
- const chunkMarkdownText = probeFunction(rt, [
9789
- ["channel", "text", "chunkMarkdownText"]
9790
- ]);
9791
- const saveRemoteMedia = probeFunction(rt, [
9792
- ["channel", "media", "saveRemoteMedia"]
9793
- ]);
9794
- const getConfig = probeFunction(rt, [
9795
- ["config", "current"]
9796
- ]) ?? probeFunction(rt, [
9797
- ["getConfig"]
9798
- ]) ?? probeFunction(rt, [
9799
- ["config", "loadConfig"]
9800
- ]);
9801
- const rawMutateConfig = probeFunction(rt, [["config", "mutateConfigFile"]]);
9802
- const rawWriteConfig = probeFunction(rt, [["config", "writeConfigFile"]]);
9803
- const persistConfig = rawMutateConfig ? async (mutator) => {
9804
- await rawMutateConfig({
9805
- afterWrite: "hot-reload",
9806
- mutate: mutator
9807
- });
9808
- } : rawWriteConfig && getConfig ? async (mutator) => {
9809
- const current = JSON.parse(JSON.stringify(getConfig()));
9810
- mutator(current);
9811
- await rawWriteConfig(current);
9812
- } : null;
9813
- const resolved = [
9814
- inboundRun && "inboundRun",
9815
- dispatchReply && "dispatchReply",
9816
- resolveAgentRoute && "resolveAgentRoute",
9817
- buildInboundContext && "buildInboundContext",
9818
- resolveStorePath && "resolveStorePath",
9819
- recordInboundSession && "recordInboundSession",
9820
- formatEnvelope && "formatEnvelope",
9821
- chunkMarkdownText && "chunkMarkdownText",
9822
- saveRemoteMedia && "saveRemoteMedia",
9823
- getConfig && "getConfig",
9824
- persistConfig && `persistConfig(${rawMutateConfig ? "mutate" : "write"})`
9825
- ].filter(Boolean);
9826
- log4?.info(
9827
- `[qqbot:adapter] openclaw=${version} resolved ${resolved.length} adapters: ${resolved.join(", ")}`
9828
- );
9829
- return {
9830
- inboundRun,
9831
- dispatchReply,
9832
- resolveAgentRoute,
9833
- buildInboundContext,
9834
- resolveStorePath,
9835
- recordInboundSession,
9836
- formatEnvelope,
9837
- resolveEnvelopeFormatOptions,
9838
- chunkMarkdownText,
9839
- saveRemoteMedia,
9840
- getConfig,
9841
- persistConfig,
9842
- version
9843
- };
10168
+ /** 是否已完成初始化(磁盘回放) */
10169
+ get isInitialized() {
10170
+ return this.initialized;
10171
+ }
10172
+ /** 诊断快照 */
10173
+ stats() {
10174
+ return {
10175
+ memoryEntries: this.memory.size,
10176
+ diskLines: this.diskLineCount,
10177
+ maxEntries: this.maxEntries,
10178
+ filePath: this.filePath
10179
+ };
10180
+ }
10181
+ /**
10182
+ * 强制将当前内存状态持久化到磁盘(进程退出前调用)
10183
+ */
10184
+ flush() {
10185
+ this.compactSync();
10186
+ }
10187
+ };
10188
+ var stores = /* @__PURE__ */ new Map();
10189
+ function getPersistedRefIndexStore(accountId) {
10190
+ let store = stores.get(accountId);
10191
+ if (!store) {
10192
+ const filePath = import_node_path3.default.join(getQQBotDataDir("data", accountId), DEFAULT_FILENAME);
10193
+ store = new PersistedRefIndexStore({ filePath });
10194
+ stores.set(accountId, store);
10195
+ }
10196
+ return store;
9844
10197
  }
9845
- var _cachedAdapters = null;
9846
- var _cachedRuntimeRef = null;
9847
- function getAdapters(rt, log4) {
9848
- const cached = _cachedRuntimeRef?.deref();
9849
- if (cached === rt && _cachedAdapters) {
9850
- return _cachedAdapters;
10198
+ function flushAllRefIndexStores() {
10199
+ for (const store of stores.values()) {
10200
+ store.flush();
9851
10201
  }
9852
- _cachedAdapters = resolveRuntimeAdapters(rt, log4);
9853
- _cachedRuntimeRef = new WeakRef(rt);
9854
- return _cachedAdapters;
9855
10202
  }
9856
10203
 
10204
+ // src/runtime.ts
10205
+ var runtime = null;
10206
+ var exitHooksInstalled = false;
10207
+ function setQQBotRuntime(next) {
10208
+ runtime = next;
10209
+ const version = getOpenclawVersion(next.version);
10210
+ setOpenClawVersion(version);
10211
+ installExitHooksOnce();
10212
+ }
10213
+ function installExitHooksOnce() {
10214
+ if (exitHooksInstalled) return;
10215
+ exitHooksInstalled = true;
10216
+ const flush = () => {
10217
+ try {
10218
+ flushAllRefIndexStores();
10219
+ } catch {
10220
+ }
10221
+ };
10222
+ process.on("beforeExit", flush);
10223
+ process.on("SIGINT", () => {
10224
+ flush();
10225
+ process.exit(0);
10226
+ });
10227
+ process.on("SIGTERM", () => {
10228
+ flush();
10229
+ process.exit(0);
10230
+ });
10231
+ }
10232
+ function getQQBotRuntime() {
10233
+ if (!runtime) throw new Error("QQBot runtime not initialized");
10234
+ return runtime;
10235
+ }
10236
+ function tryGetQQBotRuntime() {
10237
+ return runtime;
10238
+ }
10239
+
10240
+ // src/channel.ts
10241
+ init_resolve();
10242
+
9857
10243
  // src/outbound/media-send.ts
9858
10244
  var path8 = __toESM(require("path"), 1);
9859
10245
  var fs9 = __toESM(require("fs"), 1);
@@ -9877,6 +10263,9 @@ function resolveAgentWorkspace(cfg, agentId) {
9877
10263
  return getQQBotMediaDir();
9878
10264
  }
9879
10265
 
10266
+ // src/outbound/media-send.ts
10267
+ init_resolve();
10268
+
9880
10269
  // src/utils/ssrf-guard.ts
9881
10270
  var import_node_net = __toESM(require("net"), 1);
9882
10271
  var import_promises = __toESM(require("dns/promises"), 1);
@@ -10043,14 +10432,36 @@ function resolveTempRoots() {
10043
10432
  }
10044
10433
  return [...roots];
10045
10434
  }
10046
- var ALLOWED_MEDIA_ROOTS = [
10047
- path8.join(os4.homedir(), ".openclaw", "media"),
10048
- path8.join(os4.homedir(), ".openclaw", "workspace"),
10049
- // 框架 outbound 目录(saveMediaBuffer 写入)
10050
- path8.join(os4.homedir(), ".openclaw", "outbound"),
10051
- // TTS 语音临时目录(deliver-pipeline 已通过 isTtsPathSafe 预检)
10052
- ...resolveTempRoots()
10053
- ];
10435
+ function buildDynamicAllowedRoots(workspaceDir) {
10436
+ const home = os4.homedir();
10437
+ const derivedBase = workspaceDir ? path8.dirname(workspaceDir) : path8.join(home, ".openclaw");
10438
+ const roots = [];
10439
+ const added = /* @__PURE__ */ new Set();
10440
+ const addRoot = (p2) => {
10441
+ try {
10442
+ const real = fs9.existsSync(p2) ? fs9.realpathSync(p2) : p2;
10443
+ if (!added.has(real)) {
10444
+ added.add(real);
10445
+ roots.push(real);
10446
+ }
10447
+ } catch {
10448
+ }
10449
+ };
10450
+ const knownBases = [path8.join(home, ".openclaw"), path8.join(home, ".openclaw-dev")];
10451
+ if (workspaceDir) {
10452
+ addRoot(path8.join(derivedBase, "media"));
10453
+ addRoot(path8.join(derivedBase, "workspace"));
10454
+ addRoot(path8.join(derivedBase, "outbound"));
10455
+ addRoot(workspaceDir);
10456
+ }
10457
+ for (const base of knownBases) {
10458
+ addRoot(path8.join(base, "media"));
10459
+ addRoot(path8.join(base, "workspace"));
10460
+ addRoot(path8.join(base, "outbound"));
10461
+ }
10462
+ for (const t of resolveTempRoots()) addRoot(t);
10463
+ return roots;
10464
+ }
10054
10465
  var MAX_DATA_URL_BYTES = 10 * 1024 * 1024;
10055
10466
  async function sendMedia2(params) {
10056
10467
  const { source, accountId, log: log4 } = params;
@@ -10119,363 +10530,110 @@ async function resolveMediaPath(source, log4, workspaceDir) {
10119
10530
  } catch {
10120
10531
  return { ok: false, error: `Cannot resolve path: ${resolved}` };
10121
10532
  }
10122
- const allowed = isPathInAllowedRoots(real, ALLOWED_MEDIA_ROOTS);
10533
+ const dynamicRoots = buildDynamicAllowedRoots(workspaceDir);
10534
+ const allowed = isPathInAllowedRoots(real, dynamicRoots);
10123
10535
  if (!allowed) {
10124
10536
  log4?.warn(`path blocked \u2014 not in allowed directory: ${real}`);
10125
10537
  return { ok: false, error: `\u6587\u4EF6\u8DEF\u5F84\u4E0D\u5728\u5141\u8BB8\u7684\u76EE\u5F55\u4E2D` };
10126
10538
  }
10127
- return { ok: true, path: real, isLocal: true };
10128
- }
10129
- function resolveWorkspaceFromAgent(agentId) {
10130
- const cfg = resolveConfigViaAdapter();
10131
- if (!cfg) return void 0;
10132
- return resolveAgentWorkspace(cfg, agentId);
10133
- }
10134
- function resolveConfigViaAdapter() {
10135
- try {
10136
- const rt = tryGetQQBotRuntime();
10137
- if (!rt) return void 0;
10138
- return getAdapters(rt).getConfig?.();
10139
- } catch {
10140
- return void 0;
10141
- }
10142
- }
10143
- function resolveWorkingFile(name, workspaceDir) {
10144
- for (const p2 of [path8.resolve(name), workspaceDir ? path8.join(workspaceDir, name) : null]) {
10145
- if (p2 && fs9.existsSync(p2)) return p2;
10146
- }
10147
- return null;
10148
- }
10149
- async function sendImageMedia(gw, target, source, params) {
10150
- try {
10151
- const result = await gw.sendMedia(target, source, {
10152
- text: params.text,
10153
- msgId: params.replyToId
10154
- });
10155
- return { messageId: result.id };
10156
- } catch (err) {
10157
- return { error: formatErr(err) };
10158
- }
10159
- }
10160
- async function sendVoiceMedia(gw, target, source, params) {
10161
- const voiceSource = resolveVoiceSource2(source);
10162
- try {
10163
- const result = await gw.sendVoice(target, voiceSource, {
10164
- msgId: params.replyToId
10165
- });
10166
- return { messageId: result.id };
10167
- } catch (err) {
10168
- params.log?.child("media")?.warn(`sendVoice failed (${formatErr(err)}), falling back to sendFile`);
10169
- try {
10170
- const fileName = path8.basename(source);
10171
- const fallback = await gw.sendFile(target, source, {
10172
- text: params.text,
10173
- msgId: params.replyToId,
10174
- fileName
10175
- });
10176
- return { messageId: fallback.id, fallback: true };
10177
- } catch (fallbackErr) {
10178
- return { error: `voice: ${formatErr(err)} | fallback file: ${formatErr(fallbackErr)}` };
10179
- }
10180
- }
10181
- }
10182
- async function sendVideoMedia(gw, target, source, params) {
10183
- try {
10184
- const result = await gw.sendVideo(target, source, {
10185
- text: params.text,
10186
- msgId: params.replyToId
10187
- });
10188
- return { messageId: result.id };
10189
- } catch (err) {
10190
- return { error: formatErr(err) };
10191
- }
10192
- }
10193
- async function sendFileMedia(gw, target, source, params) {
10194
- try {
10195
- const fileName = path8.basename(source);
10196
- const result = await gw.sendFile(target, source, {
10197
- text: params.text,
10198
- msgId: params.replyToId,
10199
- fileName
10200
- });
10201
- return { messageId: result.id };
10202
- } catch (err) {
10203
- return { error: formatErr(err) };
10204
- }
10205
- }
10206
- function resolveVoiceSource2(source) {
10207
- if (source.startsWith("http://") || source.startsWith("https://")) {
10208
- return { url: source };
10209
- }
10210
- if (source.startsWith("data:") || !source.startsWith("/") && !source.startsWith("./") && !source.startsWith("../") && !source.startsWith("~")) {
10211
- const commaIdx = source.indexOf(",");
10212
- return { base64: commaIdx > 0 ? source.slice(commaIdx + 1) : source };
10213
- }
10214
- return { localPath: source };
10215
- }
10216
- function formatErr(err) {
10217
- if (err instanceof Error) return err.message;
10218
- return String(err);
10219
- }
10220
-
10221
- // src/adapter/setup.ts
10222
- var import_node_module2 = require("module");
10223
- var req2 = (0, import_node_module2.createRequire)(__filename);
10224
- var _setup;
10225
- var _tools;
10226
- function loadSetup() {
10227
- if (_setup !== void 0) return _setup;
10228
- try {
10229
- _setup = req2("openclaw/plugin-sdk/setup");
10230
- } catch {
10231
- _setup = null;
10232
- }
10233
- return _setup;
10234
- }
10235
- function loadTools() {
10236
- if (_tools !== void 0) return _tools;
10237
- try {
10238
- _tools = req2("openclaw/plugin-sdk/setup-tools");
10239
- } catch {
10240
- _tools = null;
10241
- }
10242
- return _tools;
10243
- }
10244
- var DEFAULT_ACCOUNT_ID2 = "default";
10245
- function createStandardChannelSetupStatus(...args) {
10246
- const mod = loadSetup();
10247
- if (mod) return mod.createStandardChannelSetupStatus(...args);
10248
- return {
10249
- channelLabel: args[0]?.channelLabel ?? "QQ Bot",
10250
- configuredLabel: "Configured",
10251
- unconfiguredLabel: "Not configured",
10252
- resolveConfigured: () => false
10253
- };
10254
- }
10255
- function setSetupChannelEnabled(...args) {
10256
- loadSetup()?.setSetupChannelEnabled?.(...args);
10257
- }
10258
- function formatDocsLink(...args) {
10259
- const mod = loadTools();
10260
- if (mod) return mod.formatDocsLink(...args);
10261
- return args[1] ? `${args[1]}: ${args[0]}` : args[0];
10262
- }
10263
-
10264
- // node_modules/.pnpm/@tencent-connect+qqbot-connector@1.2.0/node_modules/@tencent-connect/qqbot-connector/dist/esm/qr-connect.js
10265
- var import_qrcode_terminal = __toESM(require_main(), 1);
10266
-
10267
- // node_modules/.pnpm/@tencent-connect+qqbot-connector@1.2.0/node_modules/@tencent-connect/qqbot-connector/dist/esm/qqbot-session.js
10268
- var import_node_crypto = __toESM(require("crypto"), 1);
10269
- var import_node_https = __toESM(require("https"), 1);
10270
- var E = { production: "q.qq.com", test: "test.q.qq.com" };
10271
- function d(t = "production") {
10272
- return E[t];
10273
- }
10274
- function l() {
10275
- return import_node_crypto.default.randomBytes(32).toString("base64");
10276
- }
10277
- var u;
10278
- (function(t) {
10279
- t[t.NONE = 0] = "NONE", t[t.PENDING = 1] = "PENDING", t[t.COMPLETED = 2] = "COMPLETED", t[t.EXPIRED = 3] = "EXPIRED";
10280
- })(u || (u = {}));
10281
- function b(t, r) {
10282
- const a = Buffer.from(r, "base64"), n = Buffer.from(t, "base64"), e = n.subarray(0, 12), c = n.subarray(n.length - 16), s = n.subarray(12, n.length - 16), o = import_node_crypto.default.createDecipheriv("aes-256-gcm", a, e);
10283
- return o.setAuthTag(c), Buffer.concat([o.update(s), o.final()]).toString("utf8");
10284
- }
10285
- function h(t, r, a) {
10286
- return new Promise((n, e) => {
10287
- const c = JSON.stringify(r), s = new URL(t), o = import_node_https.default.request({ hostname: s.hostname, path: s.pathname + s.search, method: "POST", timeout: a, headers: { "Content-Type": "application/json", Accept: "application/json", "Content-Length": Buffer.byteLength(c) } }, (i) => {
10288
- if (i.statusCode !== 200) {
10289
- i.resume(), e(new Error(`HTTP ${i.statusCode} from ${t}`));
10290
- return;
10291
- }
10292
- let f = "";
10293
- i.on("data", (p2) => {
10294
- f += p2;
10295
- }), i.on("end", () => {
10296
- try {
10297
- n(JSON.parse(f));
10298
- } catch (p2) {
10299
- e(p2);
10300
- }
10301
- });
10302
- });
10303
- o.on("error", e), o.on("timeout", () => {
10304
- o.destroy(), e(new Error(`timeout fetching ${t}`));
10305
- }), o.end(c);
10306
- });
10539
+ return { ok: true, path: real, isLocal: true };
10307
10540
  }
10308
- async function y(t = "production", r = 1e4) {
10309
- const a = `https://${d(t)}/lite/create_bind_task`, n = l(), e = await h(a, { key: n }, r);
10310
- if (e.retcode !== 0) throw new Error(e.msg ?? "create_bind_task failed");
10311
- if (!e.data?.task_id) throw new Error("create_bind_task: missing task_id");
10312
- return { taskId: e.data.task_id, key: n };
10541
+ function resolveWorkspaceFromAgent(agentId) {
10542
+ const cfg = resolveConfigViaAdapter();
10543
+ if (!cfg) return void 0;
10544
+ return resolveAgentWorkspace(cfg, agentId);
10313
10545
  }
10314
- async function g(t, r = "production", a = 1e4) {
10315
- const n = `https://${d(r)}/lite/poll_bind_result`, e = await h(n, { task_id: t }, a);
10316
- if (e.retcode !== 0) throw new Error(e.msg ?? "poll_bind_result failed");
10317
- return { status: e.data?.status ?? u.NONE, botAppId: String(e.data?.bot_appid ?? ""), botEncryptSecret: e.data?.bot_encrypt_secret ?? "", userOpenid: e.data?.user_openid || void 0 };
10546
+ function resolveConfigViaAdapter() {
10547
+ try {
10548
+ const rt = tryGetQQBotRuntime();
10549
+ if (!rt) return void 0;
10550
+ return getAdapters(rt).getConfig?.();
10551
+ } catch {
10552
+ return void 0;
10553
+ }
10318
10554
  }
10319
- function w(t, r = "") {
10320
- return `https://${d("production")}/qqbot/openclaw/connect.html?task_id=${encodeURIComponent(t)}&source=${encodeURIComponent(r)}&_wv=2`;
10555
+ function resolveWorkingFile(name, workspaceDir) {
10556
+ for (const p2 of [path8.resolve(name), workspaceDir ? path8.join(workspaceDir, name) : null]) {
10557
+ if (p2 && fs9.existsSync(p2)) return p2;
10558
+ }
10559
+ return null;
10321
10560
  }
10322
-
10323
- // node_modules/.pnpm/@tencent-connect+qqbot-connector@1.2.0/node_modules/@tencent-connect/qqbot-connector/dist/esm/qr-connect.js
10324
- var p = 2e3;
10325
- function F(r) {
10326
- return new Promise((o) => {
10327
- import_qrcode_terminal.default.generate(r, { small: true }, (e) => {
10328
- o(e);
10561
+ async function sendImageMedia(gw, target, source, params) {
10562
+ try {
10563
+ const result = await gw.sendMedia(target, source, {
10564
+ text: params.text,
10565
+ msgId: params.replyToId
10329
10566
  });
10330
- });
10331
- }
10332
- function d2(r, o) {
10333
- return new Promise((e, t) => {
10334
- if (o?.aborted) {
10335
- t(new DOMException("Aborted", "AbortError"));
10336
- return;
10337
- }
10338
- const n = setTimeout(e, r);
10339
- o?.addEventListener("abort", () => {
10340
- clearTimeout(n), t(new DOMException("Aborted", "AbortError"));
10341
- }, { once: true });
10342
- });
10567
+ return { messageId: result.id };
10568
+ } catch (err) {
10569
+ return { error: formatErr(err) };
10570
+ }
10343
10571
  }
10344
- async function C(r, o, e) {
10345
- for (; !e?.aborted; ) {
10346
- let t;
10572
+ async function sendVoiceMedia(gw, target, source, params) {
10573
+ const voiceSource = resolveVoiceSource2(source);
10574
+ try {
10575
+ const result = await gw.sendVoice(target, voiceSource, {
10576
+ msgId: params.replyToId
10577
+ });
10578
+ return { messageId: result.id };
10579
+ } catch (err) {
10580
+ params.log?.child("media")?.warn(`sendVoice failed (${formatErr(err)}), falling back to sendFile`);
10347
10581
  try {
10348
- t = await g(r);
10349
- } catch {
10350
- await d2(p, e);
10351
- continue;
10352
- }
10353
- if (t.status === u.COMPLETED) {
10354
- const n = b(t.botEncryptSecret, o);
10355
- return { outcome: "scanned", appId: t.botAppId, appSecret: n, userOpenid: t.userOpenid };
10582
+ const fileName = path8.basename(source);
10583
+ const fallback = await gw.sendFile(target, source, {
10584
+ text: params.text,
10585
+ msgId: params.replyToId,
10586
+ fileName
10587
+ });
10588
+ return { messageId: fallback.id, fallback: true };
10589
+ } catch (fallbackErr) {
10590
+ return { error: `voice: ${formatErr(err)} | fallback file: ${formatErr(fallbackErr)}` };
10356
10591
  }
10357
- if (t.status === u.EXPIRED) return { outcome: "expired" };
10358
- await d2(p, e);
10359
10592
  }
10360
- throw new DOMException("Aborted", "AbortError");
10361
- }
10362
- function l2(r, o) {
10363
- const e = new AbortController(), t = o?.signal ? AbortSignal.any([e.signal, o.signal]) : e.signal;
10364
- return (async () => {
10365
- const n = o?.displayQrCodeToConsole ?? true;
10366
- for (; ; ) {
10367
- if (t.aborted) throw new DOMException("Aborted", "AbortError");
10368
- let a;
10369
- try {
10370
- a = await y();
10371
- } catch (u2) {
10372
- throw new Error(`\u83B7\u53D6\u7ED1\u5B9A\u4EFB\u52A1\u5931\u8D25: ${u2 instanceof Error ? u2.message : String(u2)}`, { cause: u2 });
10373
- }
10374
- const i = w(a.taskId, o?.source);
10375
- if (n) {
10376
- const u2 = await F(i);
10377
- console.log(u2), console.log(`\u8BF7\u4F7F\u7528\u624B\u673A QQ \u626B\u63CF\u4E0A\u65B9\u4E8C\u7EF4\u7801\uFF0C\u5B8C\u6210\u673A\u5668\u4EBA\u7ED1\u5B9A\u3002
10378
- `);
10379
- }
10380
- r.onQrDisplayed?.(i);
10381
- const s = await C(a.taskId, a.key, t);
10382
- if (s.outcome === "scanned") {
10383
- r.onSuccess([{ appId: s.appId, appSecret: s.appSecret, userOpenid: s.userOpenid }]);
10384
- return;
10385
- }
10386
- r.onQrExpired?.(), n && console.log(`\u4E8C\u7EF4\u7801\u5DF2\u8FC7\u671F\uFF0C\u6B63\u5728\u5237\u65B0\u2026
10387
- `);
10388
- }
10389
- })().catch((n) => {
10390
- if (n instanceof DOMException && n.name === "AbortError") {
10391
- r.onFailure(new Error("\u5DF2\u53D6\u6D88"));
10392
- return;
10393
- }
10394
- r.onFailure(n instanceof Error ? n : new Error(String(n)));
10395
- }), () => e.abort();
10396
- }
10397
- function m2(r) {
10398
- return new Promise((o, e) => {
10399
- l2({ onSuccess: o, onFailure: e }, { ...r, displayQrCodeToConsole: true });
10400
- });
10401
- }
10402
-
10403
- // src/setup/finalize.ts
10404
- function isConfigured(cfg, accountId) {
10405
- const account = resolveQQBotAccount(cfg, accountId);
10406
- return Boolean(account.appId && account.clientSecret);
10407
10593
  }
10408
- async function linkViaQrCode(cfg, accountId, prompter, rt) {
10594
+ async function sendVideoMedia(gw, target, source, params) {
10409
10595
  try {
10410
- const accounts = await m2({ source: "openclaw" });
10411
- if (accounts.length === 0) {
10412
- await prompter.note("\u672A\u83B7\u53D6\u5230\u4EFB\u4F55 QQ Bot \u8D26\u53F7\u4FE1\u606F\u3002", "QQ Bot");
10413
- return cfg;
10414
- }
10415
- let next = cfg;
10416
- for (const { appId, appSecret, userOpenid } of accounts) {
10417
- next = applyQQBotAccountConfig(next, appId, { appId, clientSecret: appSecret });
10418
- next = applyAccountDefaults(next, appId, userOpenid);
10419
- }
10420
- if (accounts.length === 1) {
10421
- rt.log(`\u2714 QQ Bot \u7ED1\u5B9A\u6210\u529F\uFF01(AppID: ${accounts[0].appId})`);
10422
- } else {
10423
- rt.log(`\u2714 ${accounts.length} \u4E2A QQ Bot \u7ED1\u5B9A\u6210\u529F\uFF01(AppID: ${accounts.map((a) => a.appId).join(", ")})`);
10424
- }
10425
- return next;
10596
+ const result = await gw.sendVideo(target, source, {
10597
+ text: params.text,
10598
+ msgId: params.replyToId
10599
+ });
10600
+ return { messageId: result.id };
10426
10601
  } catch (err) {
10427
- rt.error(`QQ Bot \u7ED1\u5B9A\u5931\u8D25: ${String(err)}`);
10428
- await prompter.note(`\u7ED1\u5B9A\u5931\u8D25\uFF0C\u60A8\u53EF\u4EE5\u7A0D\u540E\u624B\u52A8\u914D\u7F6E\u3002
10429
- \u6587\u6863: ${formatDocsLink("/channels/qqbot", "qqbot")}`, "QQ Bot");
10430
- return cfg;
10602
+ return { error: formatErr(err) };
10431
10603
  }
10432
10604
  }
10433
- async function linkViaManual(cfg, prompter) {
10434
- const appId = await prompter.text({ message: "\u8BF7\u8F93\u5165 QQ Bot AppID", validate: (v) => v.trim() ? void 0 : "AppID \u4E0D\u80FD\u4E3A\u7A7A" });
10435
- const secret = await prompter.text({ message: "\u8BF7\u8F93\u5165 QQ Bot AppSecret", validate: (v) => v.trim() ? void 0 : "AppSecret \u4E0D\u80FD\u4E3A\u7A7A" });
10436
- let next = applyQQBotAccountConfig(cfg, appId.trim(), { appId: appId.trim(), clientSecret: secret.trim() });
10437
- next = applyAccountDefaults(next, appId.trim());
10438
- await prompter.note("\u2714 QQ Bot \u914D\u7F6E\u5B8C\u6210\uFF01", "QQ Bot");
10439
- return next;
10440
- }
10441
- async function finalizeQQBotSetup(params) {
10442
- const accountId = params.accountId.trim() || DEFAULT_ACCOUNT_ID2;
10443
- const configured = isConfigured(params.cfg, accountId);
10444
- const mode = await params.prompter.select({
10445
- message: configured ? "QQ \u5DF2\u7ED1\u5B9A\uFF0C\u9009\u62E9\u64CD\u4F5C" : "\u9009\u62E9 QQ \u7ED1\u5B9A\u65B9\u5F0F",
10446
- options: [
10447
- { value: "qr", label: "\u626B\u7801\u7ED1\u5B9A\uFF08\u63A8\u8350\uFF09", hint: "\u4F7F\u7528 QQ \u626B\u63CF\u4E8C\u7EF4\u7801\u81EA\u52A8\u5B8C\u6210\u7ED1\u5B9A" },
10448
- { value: "manual", label: "\u624B\u52A8\u8F93\u5165 QQ Bot AppID \u548C AppSecret", hint: "\u9700\u5230 QQ \u5F00\u653E\u5E73\u53F0 q.qq.com \u67E5\u770B" },
10449
- { value: "skip", label: configured ? "\u4FDD\u6301\u5F53\u524D\u914D\u7F6E" : "\u7A0D\u540E\u914D\u7F6E" }
10450
- ]
10451
- });
10452
- let next = params.cfg;
10453
- if (mode === "qr") {
10454
- next = await linkViaQrCode(next, accountId, params.prompter, params.runtime);
10455
- } else if (mode === "manual") {
10456
- next = await linkViaManual(next, params.prompter);
10457
- } else if (!configured) {
10458
- await params.prompter.note("\u60A8\u53EF\u4EE5\u7A0D\u540E\u8FD0\u884C\u4EE5\u4E0B\u547D\u4EE4\u91CD\u65B0\u914D\u7F6E\uFF1A\n openclaw channels add", "QQ Bot");
10605
+ async function sendFileMedia(gw, target, source, params) {
10606
+ try {
10607
+ const fileName = path8.basename(source);
10608
+ const result = await gw.sendFile(target, source, {
10609
+ text: params.text,
10610
+ msgId: params.replyToId,
10611
+ fileName
10612
+ });
10613
+ return { messageId: result.id };
10614
+ } catch (err) {
10615
+ return { error: formatErr(err) };
10459
10616
  }
10460
- return { cfg: next };
10461
10617
  }
10462
- function applyAccountDefaults(cfg, accountId, userOpenid) {
10463
- const next = { ...cfg, channels: { ...cfg.channels } };
10464
- const qqbot = { ...next.channels?.qqbot ?? {} };
10465
- const defaults = { streaming: true, dmPolicy: "allowlist" };
10466
- if (userOpenid) defaults.allowFrom = [userOpenid];
10467
- if (accountId === DEFAULT_ACCOUNT_ID2) {
10468
- Object.assign(qqbot, defaults);
10469
- } else {
10470
- const accounts = { ...qqbot.accounts ?? {} };
10471
- accounts[accountId] = { ...accounts[accountId] ?? {}, ...defaults };
10472
- qqbot.accounts = accounts;
10618
+ function resolveVoiceSource2(source) {
10619
+ if (source.startsWith("http://") || source.startsWith("https://")) {
10620
+ return { url: source };
10473
10621
  }
10474
- next.channels = { ...next.channels, qqbot };
10475
- return next;
10622
+ if (source.startsWith("data:") || !source.startsWith("/") && !source.startsWith("./") && !source.startsWith("../") && !source.startsWith("~")) {
10623
+ const commaIdx = source.indexOf(",");
10624
+ return { base64: commaIdx > 0 ? source.slice(commaIdx + 1) : source };
10625
+ }
10626
+ return { localPath: source };
10627
+ }
10628
+ function formatErr(err) {
10629
+ if (err instanceof Error) return err.message;
10630
+ return String(err);
10476
10631
  }
10477
10632
 
10478
10633
  // src/setup/surface.ts
10634
+ init_setup();
10635
+ init_config();
10636
+ init_finalize();
10479
10637
  var CHANNEL = "qqbot";
10480
10638
  var qqbotSetupWizard = {
10481
10639
  channel: CHANNEL,
@@ -10492,6 +10650,14 @@ var qqbotSetupWizard = {
10492
10650
  return Boolean(account.appId && account.clientSecret);
10493
10651
  })
10494
10652
  }),
10653
+ // 未配置时默认使用 default 账号,有账户时框架会提示选择
10654
+ resolveAccountIdForConfigure: async ({ cfg, shouldPromptAccountIds, accountOverride, defaultAccountId }) => {
10655
+ if (accountOverride) return accountOverride;
10656
+ const ids = listQQBotAccountIds(cfg);
10657
+ if (ids.length === 0) return "default";
10658
+ if (!shouldPromptAccountIds) return ids[0];
10659
+ return defaultAccountId || resolveDefaultQQBotAccountId(cfg);
10660
+ },
10495
10661
  credentials: [],
10496
10662
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
10497
10663
  finalize: (async ({ cfg, accountId, prompter, runtime: runtime2 }) => finalizeQQBotSetup({ cfg, accountId, prompter, runtime: runtime2 })),
@@ -10501,6 +10667,118 @@ var qqbotSetupWizard = {
10501
10667
  }
10502
10668
  };
10503
10669
 
10670
+ // src/setup/login.ts
10671
+ init_esm();
10672
+ var pendingSessions = /* @__PURE__ */ new Map();
10673
+ function startQrLogin(accountId, source = "openclaw") {
10674
+ const key = accountId ?? "default";
10675
+ pendingSessions.get(key)?.dispose();
10676
+ pendingSessions.delete(key);
10677
+ return new Promise((resolve2) => {
10678
+ let credentialsResolve;
10679
+ let credentialsReject;
10680
+ const credentialsPromise = new Promise((res, rej) => {
10681
+ credentialsResolve = res;
10682
+ credentialsReject = rej;
10683
+ });
10684
+ const dispose = l2(
10685
+ {
10686
+ onQrDisplayed(url) {
10687
+ resolve2({
10688
+ qrDataUrl: url,
10689
+ message: "\u8BF7\u4F7F\u7528\u624B\u673A QQ \u626B\u63CF\u4E8C\u7EF4\u7801\u5B8C\u6210\u7ED1\u5B9A"
10690
+ });
10691
+ },
10692
+ onSuccess: (creds) => credentialsResolve(creds),
10693
+ onFailure: (err) => credentialsReject(err)
10694
+ },
10695
+ { displayQrCodeToConsole: true, source }
10696
+ );
10697
+ pendingSessions.set(key, { dispose, credentialsPromise });
10698
+ });
10699
+ }
10700
+ async function waitQrLogin(accountId) {
10701
+ const key = accountId ?? "default";
10702
+ const session = pendingSessions.get(key);
10703
+ if (!session) {
10704
+ return { connected: false, message: "\u6CA1\u6709\u6B63\u5728\u8FDB\u884C\u7684\u767B\u5F55\u4F1A\u8BDD\uFF0C\u8BF7\u5148\u8FD0\u884C login \u547D\u4EE4\u3002" };
10705
+ }
10706
+ try {
10707
+ const credentials = await session.credentialsPromise;
10708
+ pendingSessions.delete(key);
10709
+ if (credentials.length === 0) {
10710
+ return { connected: false, message: "\u672A\u83B7\u53D6\u5230 QQ Bot \u51ED\u636E\u3002" };
10711
+ }
10712
+ return {
10713
+ connected: true,
10714
+ message: `\u7ED1\u5B9A\u6210\u529F\uFF01AppID: ${credentials.map((c) => c.appId).join(", ")}`,
10715
+ credentials
10716
+ };
10717
+ } catch (err) {
10718
+ pendingSessions.delete(key);
10719
+ return {
10720
+ connected: false,
10721
+ message: `\u7ED1\u5B9A\u5931\u8D25: ${err instanceof Error ? err.message : String(err)}`
10722
+ };
10723
+ }
10724
+ }
10725
+ function parseChannelInput(channelInput) {
10726
+ if (!channelInput) return null;
10727
+ const parts = channelInput.trim().split(":");
10728
+ if (parts.length === 2 && parts[0] && parts[1]) {
10729
+ return { appId: parts[0], clientSecret: parts[1] };
10730
+ }
10731
+ return null;
10732
+ }
10733
+ async function qqbotLogin({
10734
+ cfg,
10735
+ accountId,
10736
+ channelInput,
10737
+ verbose,
10738
+ ...rest
10739
+ }) {
10740
+ const { applyQQBotAccountConfig: applyQQBotAccountConfig2 } = await Promise.resolve().then(() => (init_config(), config_exports));
10741
+ const { persistAuthConfig: persistAuthConfig2 } = await Promise.resolve().then(() => (init_resolve(), resolve_exports));
10742
+ const { applyAccountDefaults: applyAccountDefaults2 } = await Promise.resolve().then(() => (init_finalize(), finalize_exports));
10743
+ const { resolveAccountKey: resolveAccountKey2 } = await Promise.resolve().then(() => (init_account_key(), account_key_exports));
10744
+ const runtime2 = rest;
10745
+ const resolvedId = accountId ? accountId.trim().toLowerCase() : null;
10746
+ const parsed = parseChannelInput(channelInput);
10747
+ if (parsed) {
10748
+ const key = resolveAccountKey2(cfg, parsed.appId, resolvedId);
10749
+ const result2 = applyQQBotAccountConfig2(cfg, key, {
10750
+ appId: parsed.appId,
10751
+ clientSecret: parsed.clientSecret
10752
+ });
10753
+ Object.assign(cfg, result2);
10754
+ const withDefaults = applyAccountDefaults2(cfg, key);
10755
+ Object.assign(cfg, withDefaults);
10756
+ await persistAuthConfig2(runtime2, cfg, "restart");
10757
+ if (verbose) console.log(`QQ Bot \u5DF2\u914D\u7F6E (${key}) AppID: ${parsed.appId}`);
10758
+ return;
10759
+ }
10760
+ const { qrDataUrl, message } = await startQrLogin(resolvedId || "pending");
10761
+ console.log(`
10762
+ ${message}`);
10763
+ if (qrDataUrl) console.log(`QR \u94FE\u63A5: ${qrDataUrl}`);
10764
+ const result = await waitQrLogin(resolvedId || "pending");
10765
+ if (!result.connected || !result.credentials) {
10766
+ throw new Error(result.message);
10767
+ }
10768
+ for (const cred of result.credentials) {
10769
+ const key = resolveAccountKey2(cfg, cred.appId, resolvedId);
10770
+ const next = applyQQBotAccountConfig2(cfg, key, {
10771
+ appId: cred.appId,
10772
+ clientSecret: cred.appSecret
10773
+ });
10774
+ Object.assign(cfg, next);
10775
+ const withDefaults = applyAccountDefaults2(cfg, key, cred.userOpenid);
10776
+ Object.assign(cfg, withDefaults);
10777
+ }
10778
+ await persistAuthConfig2(runtime2, cfg, "restart");
10779
+ console.log(`QQ Bot \u767B\u5F55\u6210\u529F\uFF01`);
10780
+ }
10781
+
10504
10782
  // src/outbound/sanitize.ts
10505
10783
  var INTERNAL_TAGS = [
10506
10784
  // 框架脚手架标签
@@ -10526,6 +10804,10 @@ function sanitizeQQBotText(text) {
10526
10804
  return result.trim();
10527
10805
  }
10528
10806
 
10807
+ // src/gateway/lifecycle.ts
10808
+ init_config();
10809
+ init_resolve();
10810
+
10529
10811
  // src/gateway/qqbot-gateway.ts
10530
10812
  var import_node_os4 = __toESM(require("os"), 1);
10531
10813
 
@@ -10762,6 +11044,7 @@ function botMe() {
10762
11044
  }
10763
11045
 
10764
11046
  // src/commands/config-util.ts
11047
+ init_resolve();
10765
11048
  function checkCommandAuth(ctx) {
10766
11049
  const p2 = ctx.state.policy;
10767
11050
  const mode = p2?.c2cMode ?? "allowlist";
@@ -11009,6 +11292,7 @@ var import_node_fs5 = __toESM(require("fs"), 1);
11009
11292
  var import_node_path5 = __toESM(require("path"), 1);
11010
11293
  var import_node_os3 = __toESM(require("os"), 1);
11011
11294
  var import_node_crypto2 = __toESM(require("crypto"), 1);
11295
+ init_resolve();
11012
11296
  var MAX_LINES_PER_FILE = 1e3;
11013
11297
  var MAX_FILES = 4;
11014
11298
  var LOG_KEYWORDS = ["gateway", "openclaw", "clawdbot", "moltbot"];
@@ -11213,6 +11497,7 @@ function botLogs(runtime2) {
11213
11497
  }
11214
11498
 
11215
11499
  // src/commands/bot-approve.ts
11500
+ init_resolve();
11216
11501
  var PRESETS = {
11217
11502
  on: { security: "allowlist", ask: "on-miss", desc: "\u5F00\u542F\u5BA1\u6279\uFF08\u767D\u540D\u5355\u6A21\u5F0F\uFF09" },
11218
11503
  off: { security: "full", ask: "off", desc: "\u5173\u95ED\u5BA1\u6279" },
@@ -11865,6 +12150,7 @@ async function downloadViaFetch(opts) {
11865
12150
  }
11866
12151
 
11867
12152
  // src/middleware/attachment.ts
12153
+ init_resolve();
11868
12154
  function attachmentProcessor(opts) {
11869
12155
  return async (ctx, next) => {
11870
12156
  const msg = ctx.message;
@@ -12068,6 +12354,7 @@ async function downloadMediaFile(url, filename, log4) {
12068
12354
  }
12069
12355
 
12070
12356
  // src/dispatch/body-assembler.ts
12357
+ init_resolve();
12071
12358
  var QUOTE_BEGIN = "[Quoted message begins]";
12072
12359
  var QUOTE_END = "[Quoted message ends]";
12073
12360
  var REF_BEGIN = "[Reference message begins]";
@@ -12271,6 +12558,7 @@ function normalizeTimestamp(ts) {
12271
12558
  }
12272
12559
 
12273
12560
  // src/middleware/policy-injector.ts
12561
+ init_config();
12274
12562
  function createPolicyInjector(account) {
12275
12563
  return async (ctx, next) => {
12276
12564
  const msg = ctx.message;
@@ -12941,6 +13229,7 @@ function shouldUseStreaming(account, targetScope) {
12941
13229
  }
12942
13230
 
12943
13231
  // src/dispatch/dispatch.ts
13232
+ init_resolve();
12944
13233
  async function dispatchToOpenClaw(ctx, msg, account, runtime2, log4) {
12945
13234
  const dlog = log4?.child("dispatch");
12946
13235
  const adapters = getAdapters(runtime2, dlog);
@@ -13502,6 +13791,7 @@ function getApprovalHandler(accountId) {
13502
13791
  // src/features/proactive.ts
13503
13792
  var fs19 = __toESM(require("fs"), 1);
13504
13793
  var path20 = __toESM(require("path"), 1);
13794
+ init_config();
13505
13795
  var log2 = createPluginLogger({ prefix: "[proactive]" });
13506
13796
  var STORAGE_DIR = getQQBotDataDir("data");
13507
13797
  var KNOWN_USERS_FILE = path20.join(STORAGE_DIR, "known-users.json");
@@ -13608,6 +13898,8 @@ function getCachedMsgId(scope, targetId) {
13608
13898
  }
13609
13899
 
13610
13900
  // src/gateway/event-handlers.ts
13901
+ init_resolve();
13902
+ init_config();
13611
13903
  async function handleMessage(ctx, msg, account, runtime2, log4) {
13612
13904
  const hlog = log4.child("handle");
13613
13905
  const scope = msg.replyTarget.scope;
@@ -14452,10 +14744,6 @@ var approvalStubs = {
14452
14744
  buildPendingPayload: () => null,
14453
14745
  buildResolvedPayload: () => null
14454
14746
  },
14455
- auth: {
14456
- authorizeActorAction: () => ({ authorized: true }),
14457
- getActionAvailabilityState: () => ({ kind: "enabled" })
14458
- },
14459
14747
  approvals: {
14460
14748
  delivery: {
14461
14749
  hasConfiguredDmRoute: () => true,
@@ -14469,6 +14757,7 @@ var approvalStubs = {
14469
14757
  };
14470
14758
 
14471
14759
  // src/features/onboarding.ts
14760
+ init_config();
14472
14761
  var qqbotOnboardingAdapter = {
14473
14762
  getStatus: (ctx) => {
14474
14763
  const cfg = ctx.config;
@@ -14512,6 +14801,7 @@ var qqbotPlugin = {
14512
14801
  threads: false,
14513
14802
  blockStreaming: false
14514
14803
  },
14804
+ gatewayMethods: ["web.login.start", "web.login.wait"],
14515
14805
  reload: { configPrefixes: ["channels.qqbot"] },
14516
14806
  // ── 群消息策略 ──
14517
14807
  groups: {
@@ -14690,7 +14980,19 @@ ${line}` : line;
14690
14980
  log: ctx.log
14691
14981
  });
14692
14982
  },
14693
- logoutAccount: (params) => logoutAndClearCredentials(params)
14983
+ logoutAccount: (params) => logoutAndClearCredentials(params),
14984
+ loginWithQrStart: async ({ accountId }) => startQrLogin(accountId),
14985
+ loginWithQrWait: async ({ accountId }) => {
14986
+ const result = await waitQrLogin(accountId);
14987
+ return { connected: result.connected, message: result.message };
14988
+ }
14989
+ },
14990
+ // ── 登录认证 ──
14991
+ auth: {
14992
+ login: qqbotLogin,
14993
+ // 审批权限(从 approvalStubs 迁移)
14994
+ authorizeActorAction: () => ({ authorized: true }),
14995
+ getActionAvailabilityState: () => ({ kind: "enabled" })
14694
14996
  },
14695
14997
  // ── 状态 ──
14696
14998
  status: {
@@ -14754,6 +15056,7 @@ function createOutLog(accountId) {
14754
15056
  }
14755
15057
 
14756
15058
  // src/tools/platform.ts
15059
+ init_config();
14757
15060
  var PlatformApiSchema = {
14758
15061
  type: "object",
14759
15062
  properties: {
@@ -15063,7 +15366,7 @@ function registerRemindTool(api) {
15063
15366
  }
15064
15367
 
15065
15368
  // src/adapter/contract.ts
15066
- var log3 = createPluginLogger({ prefix: "[contract]", forceConsole: true });
15369
+ var log3 = createPluginLogger({ prefix: "[contract]", forceConsole: false });
15067
15370
  var REQUIRED = [
15068
15371
  {
15069
15372
  name: "channel.reply.dispatchReplyWithBufferedBlockDispatcher",
@@ -15123,6 +15426,7 @@ var StreamContentType2 = {
15123
15426
  };
15124
15427
 
15125
15428
  // index.ts
15429
+ init_config();
15126
15430
  var registered = false;
15127
15431
  var plugin = {
15128
15432
  id: "openclaw-qqbot",