@cxyhhhhh/openclaw-qqbot 2.0.0-dev.202607101321 → 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 +1476 -1158
- package/dist/index.cjs.map +1 -1
- package/package.json +2 -2
- package/src/adapter/contract.ts +1 -1
- package/src/adapter/resolve.ts +38 -0
- package/src/channel.ts +15 -0
- package/src/dispatch/body-assembler.ts +2 -2
- package/src/features/approval-utils.ts +0 -4
- package/src/gateway/middleware-setup.ts +17 -11
- package/src/openclaw-plugin-sdk.d.ts +16 -0
- package/src/outbound/media-send.ts +48 -9
- package/src/setup/account-key.ts +41 -0
- package/src/setup/finalize.ts +15 -14
- package/src/setup/login.ts +197 -0
- package/src/setup/surface.ts +9 -1
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
|
-
//
|
|
3714
|
-
var
|
|
3715
|
-
|
|
3716
|
-
|
|
3717
|
-
|
|
3718
|
-
|
|
3719
|
-
|
|
3720
|
-
|
|
3721
|
-
|
|
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
|
-
//
|
|
4795
|
-
|
|
4796
|
-
|
|
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;
|
|
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];
|
|
4898
5298
|
}
|
|
4899
|
-
function
|
|
4900
|
-
|
|
4901
|
-
return (account.config?.groupAllowFrom ?? []).map((id) => String(id).trim().toUpperCase());
|
|
5299
|
+
function l() {
|
|
5300
|
+
return import_node_crypto.default.randomBytes(32).toString("base64");
|
|
4902
5301
|
}
|
|
4903
|
-
function
|
|
4904
|
-
const
|
|
4905
|
-
|
|
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;
|
|
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");
|
|
4914
5305
|
}
|
|
4915
|
-
function
|
|
4916
|
-
|
|
4917
|
-
|
|
4918
|
-
|
|
4919
|
-
|
|
4920
|
-
|
|
4921
|
-
|
|
4922
|
-
|
|
4923
|
-
|
|
4924
|
-
|
|
4925
|
-
|
|
4926
|
-
|
|
4927
|
-
|
|
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
|
+
});
|
|
4928
5328
|
}
|
|
4929
|
-
function
|
|
4930
|
-
|
|
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 };
|
|
4931
5334
|
}
|
|
4932
|
-
function
|
|
4933
|
-
|
|
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 };
|
|
4934
5339
|
}
|
|
4935
|
-
function
|
|
4936
|
-
return
|
|
5340
|
+
function w(t, r = "") {
|
|
5341
|
+
return `https://${d("production")}/qqbot/openclaw/connect.html?task_id=${encodeURIComponent(t)}&source=${encodeURIComponent(r)}&_wv=2`;
|
|
4937
5342
|
}
|
|
4938
|
-
|
|
4939
|
-
|
|
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
|
+
});
|
|
4940
5363
|
}
|
|
4941
|
-
function
|
|
4942
|
-
return
|
|
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
|
+
});
|
|
4943
5375
|
}
|
|
4944
|
-
function
|
|
4945
|
-
|
|
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 };
|
|
5388
|
+
}
|
|
5389
|
+
if (t.status === u.EXPIRED) return { outcome: "expired" };
|
|
5390
|
+
await d2(p, e);
|
|
5391
|
+
}
|
|
5392
|
+
throw new DOMException("Aborted", "AbortError");
|
|
4946
5393
|
}
|
|
4947
|
-
function
|
|
4948
|
-
const
|
|
4949
|
-
return
|
|
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
|
+
`);
|
|
5420
|
+
}
|
|
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();
|
|
4950
5428
|
}
|
|
4951
|
-
function
|
|
4952
|
-
|
|
4953
|
-
|
|
5429
|
+
function m2(r) {
|
|
5430
|
+
return new Promise((o, e) => {
|
|
5431
|
+
l2({ onSuccess: o, onFailure: e }, { ...r, displayQrCodeToConsole: true });
|
|
5432
|
+
});
|
|
4954
5433
|
}
|
|
4955
|
-
|
|
4956
|
-
|
|
4957
|
-
|
|
4958
|
-
|
|
4959
|
-
|
|
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;
|
|
4960
5441
|
}
|
|
4961
|
-
|
|
4962
|
-
|
|
4963
|
-
|
|
4964
|
-
|
|
4965
|
-
|
|
4966
|
-
|
|
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();
|
|
4967
5449
|
}
|
|
4968
|
-
|
|
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;
|
|
4969
5464
|
}
|
|
4970
|
-
|
|
4971
|
-
|
|
4972
|
-
|
|
4973
|
-
|
|
5465
|
+
var init_account_key = __esm({
|
|
5466
|
+
"src/setup/account-key.ts"() {
|
|
5467
|
+
"use strict";
|
|
5468
|
+
init_config();
|
|
4974
5469
|
}
|
|
4975
|
-
|
|
4976
|
-
|
|
4977
|
-
|
|
4978
|
-
|
|
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})`);
|
|
4979
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;
|
|
4980
5502
|
}
|
|
4981
|
-
return DEFAULT_ACCOUNT_ID;
|
|
4982
5503
|
}
|
|
4983
|
-
function
|
|
4984
|
-
const
|
|
4985
|
-
|
|
4986
|
-
|
|
4987
|
-
|
|
4988
|
-
|
|
4989
|
-
|
|
4990
|
-
|
|
4991
|
-
|
|
4992
|
-
if (env) {
|
|
4993
|
-
const v = Number(env);
|
|
4994
|
-
if (!Number.isNaN(v) && v >= 0) return v;
|
|
4995
|
-
}
|
|
4996
|
-
return DEFAULT_PROCESSING_TIMEOUT_MS;
|
|
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;
|
|
4997
5513
|
}
|
|
4998
|
-
function
|
|
4999
|
-
const
|
|
5000
|
-
const
|
|
5001
|
-
|
|
5002
|
-
|
|
5003
|
-
|
|
5004
|
-
|
|
5005
|
-
|
|
5006
|
-
|
|
5007
|
-
|
|
5008
|
-
|
|
5009
|
-
|
|
5010
|
-
|
|
5011
|
-
|
|
5012
|
-
} else {
|
|
5013
|
-
|
|
5014
|
-
|
|
5015
|
-
|
|
5016
|
-
}
|
|
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";
|
|
5025
|
-
}
|
|
5026
|
-
if (!appId && process.env.QQBOT_APP_ID && resolvedAccountId === DEFAULT_ACCOUNT_ID) {
|
|
5027
|
-
appId = normalizeAppId(process.env.QQBOT_APP_ID);
|
|
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
|
|
5044
|
-
const next = { ...cfg };
|
|
5045
|
-
|
|
5046
|
-
|
|
5047
|
-
|
|
5048
|
-
|
|
5049
|
-
|
|
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
|
|
5061
|
-
|
|
5062
|
-
|
|
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);
|
|
@@ -5087,11 +5616,11 @@ var import_node_os = __toESM(require("os"), 1);
|
|
|
5087
5616
|
// src/outbound/outbound-service.ts
|
|
5088
5617
|
var path3 = __toESM(require("path"), 1);
|
|
5089
5618
|
|
|
5090
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.
|
|
5619
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607101530/node_modules/@cxyhhhhh/qqbot-nodejs/dist/QQBot.js
|
|
5091
5620
|
var fs3 = __toESM(require("fs"), 1);
|
|
5092
5621
|
var path = __toESM(require("path"), 1);
|
|
5093
5622
|
|
|
5094
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.
|
|
5623
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607101530/node_modules/@cxyhhhhh/qqbot-nodejs/dist/middleware/types.js
|
|
5095
5624
|
function resolvePolicy(ctx, path22, explicit, defaultValue) {
|
|
5096
5625
|
if (explicit !== void 0 && explicit !== null) {
|
|
5097
5626
|
return explicit;
|
|
@@ -5167,7 +5696,7 @@ function createMiddlewareContext(params) {
|
|
|
5167
5696
|
return ctx;
|
|
5168
5697
|
}
|
|
5169
5698
|
|
|
5170
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.
|
|
5699
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607101530/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/types.js
|
|
5171
5700
|
var ApiError = class extends Error {
|
|
5172
5701
|
httpStatus;
|
|
5173
5702
|
path;
|
|
@@ -5200,7 +5729,7 @@ var StreamContentType = {
|
|
|
5200
5729
|
MARKDOWN: "markdown"
|
|
5201
5730
|
};
|
|
5202
5731
|
|
|
5203
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.
|
|
5732
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607101530/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/utils/format.js
|
|
5204
5733
|
function formatErrorMessage(err) {
|
|
5205
5734
|
if (err instanceof Error) {
|
|
5206
5735
|
let formatted = err.message || err.name || "Error";
|
|
@@ -5247,7 +5776,7 @@ function formatFileSize(bytes) {
|
|
|
5247
5776
|
return `${(bytes / 1024 / 1024 / 1024).toFixed(2)} GB`;
|
|
5248
5777
|
}
|
|
5249
5778
|
|
|
5250
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.
|
|
5779
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607101530/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/api/api-client.js
|
|
5251
5780
|
var DEFAULT_BASE_URL = "https://api.sgroup.qq.com";
|
|
5252
5781
|
var DEFAULT_TIMEOUT_MS = 3e4;
|
|
5253
5782
|
var FILE_UPLOAD_TIMEOUT_MS = 12e4;
|
|
@@ -5342,12 +5871,12 @@ var ApiClient = class {
|
|
|
5342
5871
|
}
|
|
5343
5872
|
};
|
|
5344
5873
|
|
|
5345
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.
|
|
5874
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607101530/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/api/media-chunked.js
|
|
5346
5875
|
var crypto = __toESM(require("crypto"), 1);
|
|
5347
5876
|
var fs = __toESM(require("fs"), 1);
|
|
5348
5877
|
var https = __toESM(require("https"), 1);
|
|
5349
5878
|
|
|
5350
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.
|
|
5879
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607101530/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/api/retry.js
|
|
5351
5880
|
async function withRetry(fn, policy, persistentPolicy, logger) {
|
|
5352
5881
|
let lastError = null;
|
|
5353
5882
|
for (let attempt = 0; attempt <= policy.maxRetries; attempt++) {
|
|
@@ -5439,7 +5968,7 @@ function buildPartFinishPersistentPolicy(retryTimeoutMs, retryableCodes = PART_F
|
|
|
5439
5968
|
var PART_FINISH_RETRYABLE_CODES = /* @__PURE__ */ new Set([40093001]);
|
|
5440
5969
|
var UPLOAD_PREPARE_FALLBACK_CODE = 40093002;
|
|
5441
5970
|
|
|
5442
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.
|
|
5971
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607101530/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/api/routes.js
|
|
5443
5972
|
function messagePath(scope, targetId) {
|
|
5444
5973
|
return scope === "c2c" ? `/v2/users/${targetId}/messages` : `/v2/groups/${targetId}/messages`;
|
|
5445
5974
|
}
|
|
@@ -5476,7 +6005,7 @@ function getNextMsgSeq(_msgId) {
|
|
|
5476
6005
|
return (timePart ^ random) % 65536;
|
|
5477
6006
|
}
|
|
5478
6007
|
|
|
5479
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.
|
|
6008
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607101530/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/api/media-chunked.js
|
|
5480
6009
|
var UploadDailyLimitExceededError = class extends Error {
|
|
5481
6010
|
filePath;
|
|
5482
6011
|
fileSize;
|
|
@@ -5738,8 +6267,32 @@ function sleep2(ms) {
|
|
|
5738
6267
|
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
5739
6268
|
}
|
|
5740
6269
|
|
|
5741
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.
|
|
6270
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607101530/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/api/media.js
|
|
5742
6271
|
var fs2 = __toESM(require("fs"), 1);
|
|
6272
|
+
|
|
6273
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607101530/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/utils/file-utils.js
|
|
6274
|
+
var MAX_UPLOAD_SIZE = 20 * 1024 * 1024;
|
|
6275
|
+
var CHUNKED_UPLOAD_MAX_SIZE = 100 * 1024 * 1024;
|
|
6276
|
+
var LARGE_FILE_THRESHOLD = 5 * 1024 * 1024;
|
|
6277
|
+
var MEDIA_FILE_TYPE_INFO = {
|
|
6278
|
+
[MediaFileType.IMAGE]: { maxSize: 30 * 1024 * 1024, name: "image" },
|
|
6279
|
+
[MediaFileType.VIDEO]: { maxSize: 100 * 1024 * 1024, name: "video" },
|
|
6280
|
+
[MediaFileType.VOICE]: { maxSize: 20 * 1024 * 1024, name: "voice" },
|
|
6281
|
+
[MediaFileType.FILE]: { maxSize: 100 * 1024 * 1024, name: "file" }
|
|
6282
|
+
};
|
|
6283
|
+
function sanitizeFileName(name) {
|
|
6284
|
+
if (!name) {
|
|
6285
|
+
return "file";
|
|
6286
|
+
}
|
|
6287
|
+
const cleaned = name.replace(/[\\/:*?"<>|]/g, "_").replace(/[\u0000-\u001f\u007f]/g, "").replace(/\s+/g, " ").trim();
|
|
6288
|
+
return cleaned || "file";
|
|
6289
|
+
}
|
|
6290
|
+
|
|
6291
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607101530/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/api/media.js
|
|
6292
|
+
var MAX_BASE64_CHECK_SIZE = Math.ceil(MAX_UPLOAD_SIZE * 1.4);
|
|
6293
|
+
function formatUploadSize() {
|
|
6294
|
+
return formatFileSize(MAX_UPLOAD_SIZE);
|
|
6295
|
+
}
|
|
5743
6296
|
var MediaApi = class {
|
|
5744
6297
|
client;
|
|
5745
6298
|
tokenManager;
|
|
@@ -5771,6 +6324,10 @@ var MediaApi = class {
|
|
|
5771
6324
|
const buf = await fs2.promises.readFile(opts.localPath);
|
|
5772
6325
|
fileData = buf.toString("base64");
|
|
5773
6326
|
}
|
|
6327
|
+
if (fileData && fileData.length > MAX_BASE64_CHECK_SIZE) {
|
|
6328
|
+
const sizeMB = (fileData.length / (1024 * 1024)).toFixed(1);
|
|
6329
|
+
throw new Error(`fileData too large (${sizeMB}MB decoded); QQ Bot single upload limit is ${formatUploadSize()}`);
|
|
6330
|
+
}
|
|
5774
6331
|
if (fileData && this.cache) {
|
|
5775
6332
|
const hash = this.cache.computeHash(fileData);
|
|
5776
6333
|
const cached = this.cache.get(hash, scope, targetId, fileType);
|
|
@@ -5819,7 +6376,7 @@ var MediaApi = class {
|
|
|
5819
6376
|
}
|
|
5820
6377
|
};
|
|
5821
6378
|
|
|
5822
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.
|
|
6379
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607101530/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/api/messages.js
|
|
5823
6380
|
var MessageApi = class {
|
|
5824
6381
|
client;
|
|
5825
6382
|
tokenManager;
|
|
@@ -6007,7 +6564,7 @@ var MessageApi = class {
|
|
|
6007
6564
|
}
|
|
6008
6565
|
};
|
|
6009
6566
|
|
|
6010
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.
|
|
6567
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607101530/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/api/token.js
|
|
6011
6568
|
var DEFAULT_TOKEN_BASE_URL = "https://bots.qq.com";
|
|
6012
6569
|
var TOKEN_PATH = "/app/getAppAccessToken";
|
|
6013
6570
|
var TokenManager = class {
|
|
@@ -6194,7 +6751,7 @@ var import_websocket = __toESM(require_websocket(), 1);
|
|
|
6194
6751
|
var import_websocket_server = __toESM(require_websocket_server(), 1);
|
|
6195
6752
|
var wrapper_default = import_websocket.default;
|
|
6196
6753
|
|
|
6197
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.
|
|
6754
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607101530/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/gateway/codec.js
|
|
6198
6755
|
function decodeGatewayMessageData(data) {
|
|
6199
6756
|
if (typeof data === "string") {
|
|
6200
6757
|
return data;
|
|
@@ -6221,7 +6778,7 @@ function readOptionalMessageSceneExt(event) {
|
|
|
6221
6778
|
return scene?.ext;
|
|
6222
6779
|
}
|
|
6223
6780
|
|
|
6224
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.
|
|
6781
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607101530/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/gateway/constants.js
|
|
6225
6782
|
var INTENTS = {
|
|
6226
6783
|
GUILDS: 1 << 0,
|
|
6227
6784
|
GUILD_MEMBERS: 1 << 1,
|
|
@@ -6294,7 +6851,7 @@ var GatewayEvent = {
|
|
|
6294
6851
|
MESSAGE_REACTION_REMOVE: "MESSAGE_REACTION_REMOVE"
|
|
6295
6852
|
};
|
|
6296
6853
|
|
|
6297
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.
|
|
6854
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607101530/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/gateway/event-dispatcher.js
|
|
6298
6855
|
var REF_INDEX_KEY = "msg_idx";
|
|
6299
6856
|
function parseRefIndices(ext, msgType, msgElements) {
|
|
6300
6857
|
let refMsgIdx;
|
|
@@ -6435,7 +6992,7 @@ function dispatchEvent(eventType, data, _accountId, _log) {
|
|
|
6435
6992
|
return { action: "raw", type: eventType, data };
|
|
6436
6993
|
}
|
|
6437
6994
|
|
|
6438
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.
|
|
6995
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607101530/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/gateway/reconnect.js
|
|
6439
6996
|
var ReconnectState = class {
|
|
6440
6997
|
accountId;
|
|
6441
6998
|
log;
|
|
@@ -6546,7 +7103,7 @@ var ReconnectState = class {
|
|
|
6546
7103
|
}
|
|
6547
7104
|
};
|
|
6548
7105
|
|
|
6549
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.
|
|
7106
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607101530/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/gateway/gateway-connection.js
|
|
6550
7107
|
var GatewayConnection = class {
|
|
6551
7108
|
isAborted = false;
|
|
6552
7109
|
currentWs = null;
|
|
@@ -6804,7 +7361,7 @@ function previewPayload(data) {
|
|
|
6804
7361
|
}
|
|
6805
7362
|
}
|
|
6806
7363
|
|
|
6807
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.
|
|
7364
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607101530/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/transport/webhook-verify.js
|
|
6808
7365
|
var crypto2 = __toESM(require("crypto"), 1);
|
|
6809
7366
|
function deriveSeed(botSecret) {
|
|
6810
7367
|
let seed = botSecret;
|
|
@@ -6856,7 +7413,7 @@ function signValidationResponse(params) {
|
|
|
6856
7413
|
};
|
|
6857
7414
|
}
|
|
6858
7415
|
|
|
6859
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.
|
|
7416
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607101530/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/transport/webhook-server-node.js
|
|
6860
7417
|
var http = __toESM(require("http"), 1);
|
|
6861
7418
|
var NodeHttpWebhookServer = class {
|
|
6862
7419
|
server = null;
|
|
@@ -6904,7 +7461,7 @@ var NodeHttpWebhookServer = class {
|
|
|
6904
7461
|
}
|
|
6905
7462
|
};
|
|
6906
7463
|
|
|
6907
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.
|
|
7464
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607101530/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/transport/webhook.js
|
|
6908
7465
|
var OP_DISPATCH = 0;
|
|
6909
7466
|
var OP_HTTP_CALLBACK_ACK = 12;
|
|
6910
7467
|
var OP_VALIDATION = 13;
|
|
@@ -7048,25 +7605,7 @@ function getHeader(headers, key) {
|
|
|
7048
7605
|
return val;
|
|
7049
7606
|
}
|
|
7050
7607
|
|
|
7051
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.
|
|
7052
|
-
var MAX_UPLOAD_SIZE = 20 * 1024 * 1024;
|
|
7053
|
-
var CHUNKED_UPLOAD_MAX_SIZE = 100 * 1024 * 1024;
|
|
7054
|
-
var LARGE_FILE_THRESHOLD = 5 * 1024 * 1024;
|
|
7055
|
-
var MEDIA_FILE_TYPE_INFO = {
|
|
7056
|
-
[MediaFileType.IMAGE]: { maxSize: 30 * 1024 * 1024, name: "image" },
|
|
7057
|
-
[MediaFileType.VIDEO]: { maxSize: 100 * 1024 * 1024, name: "video" },
|
|
7058
|
-
[MediaFileType.VOICE]: { maxSize: 20 * 1024 * 1024, name: "voice" },
|
|
7059
|
-
[MediaFileType.FILE]: { maxSize: 100 * 1024 * 1024, name: "file" }
|
|
7060
|
-
};
|
|
7061
|
-
function sanitizeFileName(name) {
|
|
7062
|
-
if (!name) {
|
|
7063
|
-
return "file";
|
|
7064
|
-
}
|
|
7065
|
-
const cleaned = name.replace(/[\\/:*?"<>|]/g, "_").replace(/[\u0000-\u001f\u007f]/g, "").replace(/\s+/g, " ").trim();
|
|
7066
|
-
return cleaned || "file";
|
|
7067
|
-
}
|
|
7068
|
-
|
|
7069
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607101142/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/utils/upload-cache.js
|
|
7608
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607101530/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/utils/upload-cache.js
|
|
7070
7609
|
var crypto3 = __toESM(require("crypto"), 1);
|
|
7071
7610
|
var MAX_CACHE_SIZE = 500;
|
|
7072
7611
|
function computeFileHash(data) {
|
|
@@ -7131,7 +7670,7 @@ var UploadCache = class {
|
|
|
7131
7670
|
}
|
|
7132
7671
|
};
|
|
7133
7672
|
|
|
7134
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.
|
|
7673
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607101530/node_modules/@cxyhhhhh/qqbot-nodejs/dist/streaming.js
|
|
7135
7674
|
var DEFAULT_THROTTLE_MS = 500;
|
|
7136
7675
|
var MIN_THROTTLE_MS = 300;
|
|
7137
7676
|
var MAX_FLUSH_RETRIES = 3;
|
|
@@ -7299,7 +7838,7 @@ var StreamSession = class {
|
|
|
7299
7838
|
}
|
|
7300
7839
|
};
|
|
7301
7840
|
|
|
7302
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.
|
|
7841
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607101530/node_modules/@cxyhhhhh/qqbot-nodejs/dist/QQBot.js
|
|
7303
7842
|
var MsgType = {
|
|
7304
7843
|
/** Plain text. */
|
|
7305
7844
|
TEXT: 0,
|
|
@@ -7987,7 +8526,7 @@ var QQBot = class {
|
|
|
7987
8526
|
}
|
|
7988
8527
|
};
|
|
7989
8528
|
|
|
7990
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.
|
|
8529
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607101530/node_modules/@cxyhhhhh/qqbot-nodejs/dist/middleware/message-filter.js
|
|
7991
8530
|
function messageFilter(options = {}) {
|
|
7992
8531
|
const skipSelfEcho = options.skipSelfEcho ?? true;
|
|
7993
8532
|
const dedupOpts = options.dedup !== false ? { windowMs: 5e3, maxSize: 1e3, ...options.dedup ?? {} } : null;
|
|
@@ -8025,7 +8564,7 @@ function messageFilter(options = {}) {
|
|
|
8025
8564
|
};
|
|
8026
8565
|
}
|
|
8027
8566
|
|
|
8028
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.
|
|
8567
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607101530/node_modules/@cxyhhhhh/qqbot-nodejs/dist/middleware/content-sanitizer.js
|
|
8029
8568
|
function contentSanitizer(options = {}) {
|
|
8030
8569
|
const { stripBotMention = true, stripAllMentions = false, collapseWhitespace = false, parseFaceTags: parseFaceTags2 = false, transform } = options;
|
|
8031
8570
|
return async (ctx, next) => {
|
|
@@ -8120,7 +8659,7 @@ function faceToEmoji(id) {
|
|
|
8120
8659
|
return map[id];
|
|
8121
8660
|
}
|
|
8122
8661
|
|
|
8123
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.
|
|
8662
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607101530/node_modules/@cxyhhhhh/qqbot-nodejs/dist/middleware/rate-limiter.js
|
|
8124
8663
|
var SlidingWindow = class {
|
|
8125
8664
|
buckets = /* @__PURE__ */ new Map();
|
|
8126
8665
|
max;
|
|
@@ -8174,7 +8713,7 @@ function rateLimiter(options = {}) {
|
|
|
8174
8713
|
};
|
|
8175
8714
|
}
|
|
8176
8715
|
|
|
8177
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.
|
|
8716
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607101530/node_modules/@cxyhhhhh/qqbot-nodejs/dist/middleware/concurrency-guard.js
|
|
8178
8717
|
function concurrencyGuard(options = {}) {
|
|
8179
8718
|
const strategy = options.strategy ?? "queue";
|
|
8180
8719
|
const maxQueue = options.maxQueue ?? 3;
|
|
@@ -8409,7 +8948,7 @@ function concurrencyGuard(options = {}) {
|
|
|
8409
8948
|
return guard;
|
|
8410
8949
|
}
|
|
8411
8950
|
|
|
8412
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.
|
|
8951
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607101530/node_modules/@cxyhhhhh/qqbot-nodejs/dist/middleware/mention-gate.js
|
|
8413
8952
|
function detectMentionInContent(content, appId) {
|
|
8414
8953
|
if (!content || !appId)
|
|
8415
8954
|
return false;
|
|
@@ -8465,7 +9004,7 @@ function mentionGate(options = {}) {
|
|
|
8465
9004
|
};
|
|
8466
9005
|
}
|
|
8467
9006
|
|
|
8468
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.
|
|
9007
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607101530/node_modules/@cxyhhhhh/qqbot-nodejs/dist/middleware/quote-ref.js
|
|
8469
9008
|
var MemoryRefIndexStore = class {
|
|
8470
9009
|
map = /* @__PURE__ */ new Map();
|
|
8471
9010
|
maxSize;
|
|
@@ -8583,7 +9122,7 @@ function buildText(content, attachments) {
|
|
|
8583
9122
|
return parts.join("\n") || "[empty message]";
|
|
8584
9123
|
}
|
|
8585
9124
|
|
|
8586
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.
|
|
9125
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607101530/node_modules/@cxyhhhhh/qqbot-nodejs/dist/middleware/envelope-formatter.js
|
|
8587
9126
|
function envelopeFormatter(options = {}) {
|
|
8588
9127
|
const { historyLimit = 5, includeQuote = true, includeSender = true, format } = options;
|
|
8589
9128
|
return async (ctx, next) => {
|
|
@@ -8655,7 +9194,7 @@ ${parts.join("\n")}
|
|
|
8655
9194
|
return sections.join("\n\n");
|
|
8656
9195
|
}
|
|
8657
9196
|
|
|
8658
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.
|
|
9197
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607101530/node_modules/@cxyhhhhh/qqbot-nodejs/dist/middleware/slash-command.js
|
|
8659
9198
|
function slashCommand(options = {}) {
|
|
8660
9199
|
const prefixes = options.prefixes ?? ["/"];
|
|
8661
9200
|
const catchErrors = options.catchErrors ?? true;
|
|
@@ -8718,8 +9257,9 @@ function slashCommand(options = {}) {
|
|
|
8718
9257
|
}
|
|
8719
9258
|
const cleaned = content.replace(/<@!?[^>]+>\s*/g, "").trim();
|
|
8720
9259
|
if (ctx.message.kind === "group") {
|
|
8721
|
-
const
|
|
8722
|
-
|
|
9260
|
+
const msg = ctx.message;
|
|
9261
|
+
const wasMentioned = msg.rawEventType === "GROUP_AT_MESSAGE_CREATE" || msg.mentions?.some((m3) => m3.is_you);
|
|
9262
|
+
if (!wasMentioned) {
|
|
8723
9263
|
await next();
|
|
8724
9264
|
return;
|
|
8725
9265
|
}
|
|
@@ -8807,7 +9347,7 @@ async function sendCommandResult(ctx, result) {
|
|
|
8807
9347
|
}
|
|
8808
9348
|
}
|
|
8809
9349
|
|
|
8810
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.
|
|
9350
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607101530/node_modules/@cxyhhhhh/qqbot-nodejs/dist/middleware/history-buffer.js
|
|
8811
9351
|
var MemoryHistoryStore = class {
|
|
8812
9352
|
buffers = /* @__PURE__ */ new Map();
|
|
8813
9353
|
append(groupKey, entry, limit) {
|
|
@@ -8872,7 +9412,7 @@ function historyBuffer(options = {}) {
|
|
|
8872
9412
|
return m3;
|
|
8873
9413
|
}
|
|
8874
9414
|
|
|
8875
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.
|
|
9415
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607101530/node_modules/@cxyhhhhh/qqbot-nodejs/dist/middleware/typing-indicator.js
|
|
8876
9416
|
var DEFAULT_DURATION_SEC = 60;
|
|
8877
9417
|
var DEFAULT_KEEPALIVE_INTERVAL_MS = 5e4;
|
|
8878
9418
|
function typingIndicator(options = {}) {
|
|
@@ -8909,7 +9449,7 @@ function typingIndicator(options = {}) {
|
|
|
8909
9449
|
};
|
|
8910
9450
|
}
|
|
8911
9451
|
|
|
8912
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.
|
|
9452
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607101530/node_modules/@cxyhhhhh/qqbot-nodejs/dist/middleware/error-handler.js
|
|
8913
9453
|
var DEFAULT_FORMAT = (err) => {
|
|
8914
9454
|
if (err instanceof ApiError) {
|
|
8915
9455
|
if (err.bizMessage)
|
|
@@ -8947,7 +9487,7 @@ function errorHandler(options = {}) {
|
|
|
8947
9487
|
};
|
|
8948
9488
|
}
|
|
8949
9489
|
|
|
8950
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.
|
|
9490
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607101530/node_modules/@cxyhhhhh/qqbot-nodejs/dist/storage/kv-store.js
|
|
8951
9491
|
var import_node_fs = __toESM(require("fs"), 1);
|
|
8952
9492
|
var import_node_path = __toESM(require("path"), 1);
|
|
8953
9493
|
var FileKVStore = class {
|
|
@@ -9057,7 +9597,7 @@ var FileKVStore = class {
|
|
|
9057
9597
|
}
|
|
9058
9598
|
};
|
|
9059
9599
|
|
|
9060
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.
|
|
9600
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607101530/node_modules/@cxyhhhhh/qqbot-nodejs/dist/storage/session-adapter.js
|
|
9061
9601
|
function kvSessionPersistence(opts) {
|
|
9062
9602
|
const prefix = opts.prefix ?? "qqbot:session:";
|
|
9063
9603
|
const key = `${prefix}${opts.accountId}`;
|
|
@@ -9284,7 +9824,7 @@ var import_node_path2 = __toESM(require("path"), 1);
|
|
|
9284
9824
|
var import_node_fs2 = __toESM(require("fs"), 1);
|
|
9285
9825
|
var _cachedOpenclawVersion;
|
|
9286
9826
|
function getPackageVersion() {
|
|
9287
|
-
return true ? "2.0.0-dev.
|
|
9827
|
+
return true ? "2.0.0-dev.202607101939" : "unknown";
|
|
9288
9828
|
}
|
|
9289
9829
|
function getOpenclawVersion(runtimeVersion) {
|
|
9290
9830
|
if (_cachedOpenclawVersion) return _cachedOpenclawVersion;
|
|
@@ -9615,856 +10155,485 @@ var PersistedRefIndexStore = class {
|
|
|
9615
10155
|
import_node_fs3.default.renameSync(tmpPath, this.filePath);
|
|
9616
10156
|
this.diskLineCount = lines.length;
|
|
9617
10157
|
} catch (err) {
|
|
9618
|
-
log.error(
|
|
9619
|
-
`compactSync failed: ${err instanceof Error ? err.message : String(err)}`
|
|
9620
|
-
);
|
|
9621
|
-
}
|
|
9622
|
-
}
|
|
9623
|
-
// ── 诊断 ──
|
|
9624
|
-
/** 当前内存中的条目数 */
|
|
9625
|
-
get size() {
|
|
9626
|
-
return this.memory.size;
|
|
9627
|
-
}
|
|
9628
|
-
/** 是否已完成初始化(磁盘回放) */
|
|
9629
|
-
get isInitialized() {
|
|
9630
|
-
return this.initialized;
|
|
9631
|
-
}
|
|
9632
|
-
/** 诊断快照 */
|
|
9633
|
-
stats() {
|
|
9634
|
-
return {
|
|
9635
|
-
memoryEntries: this.memory.size,
|
|
9636
|
-
diskLines: this.diskLineCount,
|
|
9637
|
-
maxEntries: this.maxEntries,
|
|
9638
|
-
filePath: this.filePath
|
|
9639
|
-
};
|
|
9640
|
-
}
|
|
9641
|
-
/**
|
|
9642
|
-
* 强制将当前内存状态持久化到磁盘(进程退出前调用)
|
|
9643
|
-
*/
|
|
9644
|
-
flush() {
|
|
9645
|
-
this.compactSync();
|
|
9646
|
-
}
|
|
9647
|
-
};
|
|
9648
|
-
var stores = /* @__PURE__ */ new Map();
|
|
9649
|
-
function getPersistedRefIndexStore(accountId) {
|
|
9650
|
-
let store = stores.get(accountId);
|
|
9651
|
-
if (!store) {
|
|
9652
|
-
const filePath = import_node_path3.default.join(getQQBotDataDir("data", accountId), DEFAULT_FILENAME);
|
|
9653
|
-
store = new PersistedRefIndexStore({ filePath });
|
|
9654
|
-
stores.set(accountId, store);
|
|
9655
|
-
}
|
|
9656
|
-
return store;
|
|
9657
|
-
}
|
|
9658
|
-
function flushAllRefIndexStores() {
|
|
9659
|
-
for (const store of stores.values()) {
|
|
9660
|
-
store.flush();
|
|
9661
|
-
}
|
|
9662
|
-
}
|
|
9663
|
-
|
|
9664
|
-
// src/runtime.ts
|
|
9665
|
-
var runtime = null;
|
|
9666
|
-
var exitHooksInstalled = false;
|
|
9667
|
-
function setQQBotRuntime(next) {
|
|
9668
|
-
runtime = next;
|
|
9669
|
-
const version = getOpenclawVersion(next.version);
|
|
9670
|
-
setOpenClawVersion(version);
|
|
9671
|
-
installExitHooksOnce();
|
|
9672
|
-
}
|
|
9673
|
-
function installExitHooksOnce() {
|
|
9674
|
-
if (exitHooksInstalled) return;
|
|
9675
|
-
exitHooksInstalled = true;
|
|
9676
|
-
const flush = () => {
|
|
9677
|
-
try {
|
|
9678
|
-
flushAllRefIndexStores();
|
|
9679
|
-
} catch {
|
|
9680
|
-
}
|
|
9681
|
-
};
|
|
9682
|
-
process.on("beforeExit", flush);
|
|
9683
|
-
process.on("SIGINT", () => {
|
|
9684
|
-
flush();
|
|
9685
|
-
process.exit(0);
|
|
9686
|
-
});
|
|
9687
|
-
process.on("SIGTERM", () => {
|
|
9688
|
-
flush();
|
|
9689
|
-
process.exit(0);
|
|
9690
|
-
});
|
|
9691
|
-
}
|
|
9692
|
-
function getQQBotRuntime() {
|
|
9693
|
-
if (!runtime) throw new Error("QQBot runtime not initialized");
|
|
9694
|
-
return runtime;
|
|
9695
|
-
}
|
|
9696
|
-
function tryGetQQBotRuntime() {
|
|
9697
|
-
return runtime;
|
|
9698
|
-
}
|
|
9699
|
-
|
|
9700
|
-
// src/adapter/resolve.ts
|
|
9701
|
-
function probeFunction(rt, paths) {
|
|
9702
|
-
for (const path22 of paths) {
|
|
9703
|
-
let target = rt;
|
|
9704
|
-
let parent = rt;
|
|
9705
|
-
for (let i = 0; i < path22.length; i++) {
|
|
9706
|
-
parent = target;
|
|
9707
|
-
target = target?.[path22[i]];
|
|
9708
|
-
if (target === void 0 || target === null) break;
|
|
9709
|
-
}
|
|
9710
|
-
if (typeof target === "function") {
|
|
9711
|
-
return target.bind(parent);
|
|
9712
|
-
}
|
|
9713
|
-
}
|
|
9714
|
-
return null;
|
|
9715
|
-
}
|
|
9716
|
-
function resolveRuntimeAdapters(rt, log4) {
|
|
9717
|
-
const version = rt.version ?? "unknown";
|
|
9718
|
-
const inboundRun = probeFunction(rt, [
|
|
9719
|
-
["channel", "inbound", "run"],
|
|
9720
|
-
// current (2026-05+)
|
|
9721
|
-
["channel", "turn", "run"]
|
|
9722
|
-
// legacy (removed 2026-05-27)
|
|
9723
|
-
]);
|
|
9724
|
-
const dispatchReply = probeFunction(rt, [
|
|
9725
|
-
["channel", "reply", "dispatchReplyWithBufferedBlockDispatcher"]
|
|
9726
|
-
]);
|
|
9727
|
-
const resolveAgentRoute = probeFunction(rt, [
|
|
9728
|
-
["channel", "routing", "resolveAgentRoute"]
|
|
9729
|
-
]);
|
|
9730
|
-
const rawBuildContext = probeFunction(rt, [
|
|
9731
|
-
["channel", "inbound", "buildContext"]
|
|
9732
|
-
]);
|
|
9733
|
-
const rawFinalizeContext = !rawBuildContext ? probeFunction(rt, [["channel", "reply", "finalizeInboundContext"]]) : null;
|
|
9734
|
-
const buildInboundContext = rawBuildContext ? (params) => rawBuildContext(params) : rawFinalizeContext ? (params) => {
|
|
9735
|
-
const isCommand = params.access?.commands?.authorized ?? false;
|
|
9736
|
-
const rawCtx = {
|
|
9737
|
-
Body: params.message.body,
|
|
9738
|
-
BodyForAgent: params.message.bodyForAgent,
|
|
9739
|
-
RawBody: params.message.rawBody,
|
|
9740
|
-
CommandBody: params.message.commandBody ?? params.message.rawBody,
|
|
9741
|
-
CommandSource: isCommand ? "text" : void 0,
|
|
9742
|
-
CommandTurn: params.command ?? void 0,
|
|
9743
|
-
CommandAuthorized: isCommand,
|
|
9744
|
-
From: params.from,
|
|
9745
|
-
To: params.reply.to,
|
|
9746
|
-
SessionKey: params.route.routeSessionKey,
|
|
9747
|
-
AccountId: params.route.accountId ?? params.accountId,
|
|
9748
|
-
ChatType: params.conversation.kind,
|
|
9749
|
-
GroupSystemPrompt: params.conversation.label,
|
|
9750
|
-
SenderId: params.sender.id,
|
|
9751
|
-
SenderName: params.sender.name,
|
|
9752
|
-
Provider: params.provider ?? params.channel,
|
|
9753
|
-
Surface: params.surface ?? params.channel,
|
|
9754
|
-
MessageSid: params.messageId,
|
|
9755
|
-
Timestamp: params.timestamp ?? Date.now(),
|
|
9756
|
-
OriginatingChannel: params.channel,
|
|
9757
|
-
OriginatingTo: params.reply.originatingTo ?? params.reply.to,
|
|
9758
|
-
...params.extra
|
|
9759
|
-
};
|
|
9760
|
-
return rawFinalizeContext(rawCtx);
|
|
9761
|
-
} : null;
|
|
9762
|
-
const resolveStorePath = probeFunction(rt, [
|
|
9763
|
-
["channel", "session", "resolveStorePath"]
|
|
9764
|
-
]);
|
|
9765
|
-
const recordInboundSession = probeFunction(rt, [
|
|
9766
|
-
["channel", "session", "recordInboundSession"]
|
|
9767
|
-
]);
|
|
9768
|
-
const formatEnvelope = probeFunction(rt, [
|
|
9769
|
-
["channel", "reply", "formatAgentEnvelope"],
|
|
9770
|
-
// current (2026-06+)
|
|
9771
|
-
["channel", "reply", "formatInboundEnvelope"]
|
|
9772
|
-
// deprecated,低版本兼容
|
|
9773
|
-
]);
|
|
9774
|
-
const resolveEnvelopeFormatOptions = probeFunction(rt, [
|
|
9775
|
-
["channel", "reply", "resolveEnvelopeFormatOptions"]
|
|
9776
|
-
]);
|
|
9777
|
-
const chunkMarkdownText = probeFunction(rt, [
|
|
9778
|
-
["channel", "text", "chunkMarkdownText"]
|
|
9779
|
-
]);
|
|
9780
|
-
const saveRemoteMedia = probeFunction(rt, [
|
|
9781
|
-
["channel", "media", "saveRemoteMedia"]
|
|
9782
|
-
]);
|
|
9783
|
-
const getConfig = probeFunction(rt, [
|
|
9784
|
-
["config", "current"]
|
|
9785
|
-
]) ?? probeFunction(rt, [
|
|
9786
|
-
["getConfig"]
|
|
9787
|
-
]) ?? probeFunction(rt, [
|
|
9788
|
-
["config", "loadConfig"]
|
|
9789
|
-
]);
|
|
9790
|
-
const rawMutateConfig = probeFunction(rt, [["config", "mutateConfigFile"]]);
|
|
9791
|
-
const rawWriteConfig = probeFunction(rt, [["config", "writeConfigFile"]]);
|
|
9792
|
-
const persistConfig = rawMutateConfig ? async (mutator) => {
|
|
9793
|
-
await rawMutateConfig({
|
|
9794
|
-
afterWrite: "hot-reload",
|
|
9795
|
-
mutate: mutator
|
|
9796
|
-
});
|
|
9797
|
-
} : rawWriteConfig && getConfig ? async (mutator) => {
|
|
9798
|
-
const current = JSON.parse(JSON.stringify(getConfig()));
|
|
9799
|
-
mutator(current);
|
|
9800
|
-
await rawWriteConfig(current);
|
|
9801
|
-
} : null;
|
|
9802
|
-
const resolved = [
|
|
9803
|
-
inboundRun && "inboundRun",
|
|
9804
|
-
dispatchReply && "dispatchReply",
|
|
9805
|
-
resolveAgentRoute && "resolveAgentRoute",
|
|
9806
|
-
buildInboundContext && "buildInboundContext",
|
|
9807
|
-
resolveStorePath && "resolveStorePath",
|
|
9808
|
-
recordInboundSession && "recordInboundSession",
|
|
9809
|
-
formatEnvelope && "formatEnvelope",
|
|
9810
|
-
chunkMarkdownText && "chunkMarkdownText",
|
|
9811
|
-
saveRemoteMedia && "saveRemoteMedia",
|
|
9812
|
-
getConfig && "getConfig",
|
|
9813
|
-
persistConfig && `persistConfig(${rawMutateConfig ? "mutate" : "write"})`
|
|
9814
|
-
].filter(Boolean);
|
|
9815
|
-
log4?.info(
|
|
9816
|
-
`[qqbot:adapter] openclaw=${version} resolved ${resolved.length} adapters: ${resolved.join(", ")}`
|
|
9817
|
-
);
|
|
9818
|
-
return {
|
|
9819
|
-
inboundRun,
|
|
9820
|
-
dispatchReply,
|
|
9821
|
-
resolveAgentRoute,
|
|
9822
|
-
buildInboundContext,
|
|
9823
|
-
resolveStorePath,
|
|
9824
|
-
recordInboundSession,
|
|
9825
|
-
formatEnvelope,
|
|
9826
|
-
resolveEnvelopeFormatOptions,
|
|
9827
|
-
chunkMarkdownText,
|
|
9828
|
-
saveRemoteMedia,
|
|
9829
|
-
getConfig,
|
|
9830
|
-
persistConfig,
|
|
9831
|
-
version
|
|
9832
|
-
};
|
|
9833
|
-
}
|
|
9834
|
-
var _cachedAdapters = null;
|
|
9835
|
-
var _cachedRuntimeRef = null;
|
|
9836
|
-
function getAdapters(rt, log4) {
|
|
9837
|
-
const cached = _cachedRuntimeRef?.deref();
|
|
9838
|
-
if (cached === rt && _cachedAdapters) {
|
|
9839
|
-
return _cachedAdapters;
|
|
9840
|
-
}
|
|
9841
|
-
_cachedAdapters = resolveRuntimeAdapters(rt, log4);
|
|
9842
|
-
_cachedRuntimeRef = new WeakRef(rt);
|
|
9843
|
-
return _cachedAdapters;
|
|
9844
|
-
}
|
|
9845
|
-
|
|
9846
|
-
// src/outbound/media-send.ts
|
|
9847
|
-
var path8 = __toESM(require("path"), 1);
|
|
9848
|
-
var fs9 = __toESM(require("fs"), 1);
|
|
9849
|
-
var os4 = __toESM(require("os"), 1);
|
|
9850
|
-
|
|
9851
|
-
// src/adapter/workspace.ts
|
|
9852
|
-
var import_node_module = require("module");
|
|
9853
|
-
var req = (0, import_node_module.createRequire)(__filename);
|
|
9854
|
-
var health = null;
|
|
9855
|
-
function resolveAgentWorkspace(cfg, agentId) {
|
|
9856
|
-
if (!health) {
|
|
9857
|
-
try {
|
|
9858
|
-
health = req("openclaw/plugin-sdk/health");
|
|
9859
|
-
} catch {
|
|
9860
|
-
health = null;
|
|
9861
|
-
}
|
|
9862
|
-
}
|
|
9863
|
-
if (health) {
|
|
9864
|
-
return health.resolveAgentWorkspaceDir(cfg, agentId ?? health.resolveDefaultAgentId(cfg));
|
|
9865
|
-
}
|
|
9866
|
-
return getQQBotMediaDir();
|
|
9867
|
-
}
|
|
9868
|
-
|
|
9869
|
-
// src/utils/ssrf-guard.ts
|
|
9870
|
-
var import_node_net = __toESM(require("net"), 1);
|
|
9871
|
-
var import_promises = __toESM(require("dns/promises"), 1);
|
|
9872
|
-
var RESERVED_V4_PREFIXES = [
|
|
9873
|
-
"127.",
|
|
9874
|
-
// loopback
|
|
9875
|
-
"10.",
|
|
9876
|
-
// class-A private
|
|
9877
|
-
"192.168.",
|
|
9878
|
-
// class-C private
|
|
9879
|
-
"169.254."
|
|
9880
|
-
// link-local / cloud metadata
|
|
9881
|
-
];
|
|
9882
|
-
var PRIVATE_172_RE = /^172\.(1[6-9]|2\d|3[01])\./;
|
|
9883
|
-
function isReservedAddr(ip) {
|
|
9884
|
-
if (ip === "0.0.0.0") return true;
|
|
9885
|
-
for (const pfx of RESERVED_V4_PREFIXES) {
|
|
9886
|
-
if (ip.startsWith(pfx)) return true;
|
|
9887
|
-
}
|
|
9888
|
-
if (PRIVATE_172_RE.test(ip)) return true;
|
|
9889
|
-
const lower = ip.toLowerCase();
|
|
9890
|
-
if (lower === "::1" || lower === "::") return true;
|
|
9891
|
-
if (lower.startsWith("fe80:")) return true;
|
|
9892
|
-
if (lower.startsWith("fc") || lower.startsWith("fd")) return true;
|
|
9893
|
-
return false;
|
|
9894
|
-
}
|
|
9895
|
-
var ALLOWED_SCHEMES = /* @__PURE__ */ new Set(["http:", "https:"]);
|
|
9896
|
-
var QQ_TRUSTED_DOMAINS = /* @__PURE__ */ new Set([
|
|
9897
|
-
// QQ Bot API
|
|
9898
|
-
"api.sgroup.qq.com",
|
|
9899
|
-
"sandbox.api.sgroup.qq.com",
|
|
9900
|
-
// QQ Bot Token
|
|
9901
|
-
"bots.qq.com",
|
|
9902
|
-
// QQ 多媒体上传/下载
|
|
9903
|
-
"multimedia.nt.qq.com.cn",
|
|
9904
|
-
"multimedia.nt.qq.com",
|
|
9905
|
-
// QQ 群文件
|
|
9906
|
-
"grouppro.grouppro.qq.com"
|
|
9907
|
-
]);
|
|
9908
|
-
function isQQTrustedDomain(hostname) {
|
|
9909
|
-
if (QQ_TRUSTED_DOMAINS.has(hostname)) return true;
|
|
9910
|
-
const dot = hostname.indexOf(".");
|
|
9911
|
-
if (dot > 0) {
|
|
9912
|
-
const parent = hostname.slice(dot + 1);
|
|
9913
|
-
return QQ_TRUSTED_DOMAINS.has(parent);
|
|
9914
|
-
}
|
|
9915
|
-
return false;
|
|
9916
|
-
}
|
|
9917
|
-
async function validateRemoteUrl(raw) {
|
|
9918
|
-
const url = new URL(raw);
|
|
9919
|
-
if (!ALLOWED_SCHEMES.has(url.protocol)) {
|
|
9920
|
-
throw new Error(
|
|
9921
|
-
`\u4E0D\u652F\u6301\u7684\u534F\u8BAE "${url.protocol}"\uFF0C\u4EC5\u5141\u8BB8 http/https\uFF08URL: ${raw}\uFF09`
|
|
9922
|
-
);
|
|
9923
|
-
}
|
|
9924
|
-
const host = url.hostname.replace(/^\[|\]$/g, "");
|
|
9925
|
-
if (isQQTrustedDomain(host)) return;
|
|
9926
|
-
if (import_node_net.default.isIP(host)) {
|
|
9927
|
-
assertPublicAddr(host, raw);
|
|
9928
|
-
return;
|
|
9929
|
-
}
|
|
9930
|
-
try {
|
|
9931
|
-
const ips = await import_promises.default.resolve(host);
|
|
9932
|
-
for (const ip of ips) {
|
|
9933
|
-
assertPublicAddr(ip, raw, host);
|
|
9934
|
-
}
|
|
9935
|
-
} catch (err) {
|
|
9936
|
-
if (err instanceof Error && err.message.includes("\u5185\u7F51")) throw err;
|
|
9937
|
-
console.warn(`[url-check] DNS \u89E3\u6790 "${host}" \u5931\u8D25: ${err}`);
|
|
9938
|
-
}
|
|
9939
|
-
}
|
|
9940
|
-
function assertPublicAddr(ip, originalUrl, domain) {
|
|
9941
|
-
if (!isReservedAddr(ip)) return;
|
|
9942
|
-
const target = domain ? `\u57DF\u540D "${domain}" \u89E3\u6790\u5230\u5185\u7F51\u5730\u5740 "${ip}"` : `\u5185\u7F51\u5730\u5740 "${ip}"`;
|
|
9943
|
-
throw new Error(
|
|
9944
|
-
`\u7981\u6B62\u8BBF\u95EE${target}\uFF0C\u5DF2\u62E6\u622A\u6F5C\u5728\u7684 SSRF \u8BF7\u6C42\uFF08URL: ${originalUrl}\uFF09`
|
|
9945
|
-
);
|
|
9946
|
-
}
|
|
9947
|
-
|
|
9948
|
-
// src/outbound/local-file-router.ts
|
|
9949
|
-
var path7 = __toESM(require("path"), 1);
|
|
9950
|
-
var fs8 = __toESM(require("fs"), 1);
|
|
9951
|
-
var os3 = __toESM(require("os"), 1);
|
|
9952
|
-
function normalizePath(p2) {
|
|
9953
|
-
let result = p2;
|
|
9954
|
-
if (result.startsWith("file://")) {
|
|
9955
|
-
result = result.slice("file://".length);
|
|
9956
|
-
if (/^\/[a-zA-Z]:[\\/]/.test(result)) {
|
|
9957
|
-
result = result.slice(1);
|
|
9958
|
-
}
|
|
9959
|
-
}
|
|
9960
|
-
try {
|
|
9961
|
-
result = decodeURIComponent(result);
|
|
9962
|
-
} catch {
|
|
9963
|
-
}
|
|
9964
|
-
if (result === "~" || result.startsWith("~/") || result.startsWith("~\\")) {
|
|
9965
|
-
result = result.replace(/^~/, os3.homedir());
|
|
9966
|
-
}
|
|
9967
|
-
return result;
|
|
9968
|
-
}
|
|
9969
|
-
function isLocalFilePath(source) {
|
|
9970
|
-
if (!source) return false;
|
|
9971
|
-
if (source.startsWith("http://") || source.startsWith("https://")) return false;
|
|
9972
|
-
if (source.startsWith("data:")) return false;
|
|
9973
|
-
if (source.startsWith("file://")) return true;
|
|
9974
|
-
if (source === "~" || source.startsWith("~/") || source.startsWith("~\\")) return true;
|
|
9975
|
-
if (source.startsWith("/")) return true;
|
|
9976
|
-
if (/^[a-zA-Z]:[\\/]/.test(source)) return true;
|
|
9977
|
-
if (source.startsWith("\\\\")) return true;
|
|
9978
|
-
if (source.startsWith("./") || source.startsWith("../")) return true;
|
|
9979
|
-
if (source.startsWith(".\\") || source.startsWith("..\\")) return true;
|
|
9980
|
-
return false;
|
|
9981
|
-
}
|
|
9982
|
-
function isDataUrl(source) {
|
|
9983
|
-
return source.startsWith("data:");
|
|
9984
|
-
}
|
|
9985
|
-
var IMAGE_EXTS = /* @__PURE__ */ new Set([".jpg", ".jpeg", ".png", ".gif", ".webp", ".bmp", ".svg", ".ico"]);
|
|
9986
|
-
var VOICE_EXTS = /* @__PURE__ */ new Set([".wav", ".mp3", ".silk", ".amr", ".ogg", ".flac", ".aac", ".m4a"]);
|
|
9987
|
-
var VIDEO_EXTS = /* @__PURE__ */ new Set([".mp4", ".avi", ".mov", ".mkv", ".webm", ".flv", ".wmv"]);
|
|
9988
|
-
function inferMediaKind(filePath) {
|
|
9989
|
-
const ext = path7.extname(filePath).toLowerCase();
|
|
9990
|
-
if (IMAGE_EXTS.has(ext)) return "image";
|
|
9991
|
-
if (VOICE_EXTS.has(ext)) return "voice";
|
|
9992
|
-
if (VIDEO_EXTS.has(ext)) return "video";
|
|
9993
|
-
return "file";
|
|
9994
|
-
}
|
|
9995
|
-
function inferMediaKindFromMime(mime) {
|
|
9996
|
-
const lower = mime.toLowerCase();
|
|
9997
|
-
if (lower.startsWith("image/")) return "image";
|
|
9998
|
-
if (lower.startsWith("audio/") || lower === "voice") return "voice";
|
|
9999
|
-
if (lower.startsWith("video/")) return "video";
|
|
10000
|
-
return "file";
|
|
10001
|
-
}
|
|
10002
|
-
function isPathInAllowedRoots(absPath, allowedRoots) {
|
|
10003
|
-
if (!allowedRoots.length) return false;
|
|
10004
|
-
try {
|
|
10005
|
-
const real = fs8.realpathSync(absPath);
|
|
10006
|
-
return allowedRoots.some((root) => {
|
|
10007
|
-
try {
|
|
10008
|
-
const rootReal = fs8.existsSync(root) ? fs8.realpathSync(root) : root;
|
|
10009
|
-
return real.startsWith(rootReal + path7.sep) || real === rootReal;
|
|
10010
|
-
} catch {
|
|
10011
|
-
return false;
|
|
10012
|
-
}
|
|
10013
|
-
});
|
|
10014
|
-
} catch {
|
|
10015
|
-
return false;
|
|
10016
|
-
}
|
|
10017
|
-
}
|
|
10018
|
-
|
|
10019
|
-
// src/outbound/media-send.ts
|
|
10020
|
-
function resolveTempRoots() {
|
|
10021
|
-
const roots = /* @__PURE__ */ new Set();
|
|
10022
|
-
try {
|
|
10023
|
-
const tmp = os4.tmpdir();
|
|
10024
|
-
roots.add(fs9.existsSync(tmp) ? fs9.realpathSync(tmp) : tmp);
|
|
10025
|
-
} catch {
|
|
10026
|
-
}
|
|
10027
|
-
if (process.platform !== "win32") {
|
|
10028
|
-
try {
|
|
10029
|
-
roots.add(fs9.realpathSync("/tmp"));
|
|
10030
|
-
} catch {
|
|
10031
|
-
}
|
|
10032
|
-
}
|
|
10033
|
-
return [...roots];
|
|
10034
|
-
}
|
|
10035
|
-
var ALLOWED_MEDIA_ROOTS = [
|
|
10036
|
-
path8.join(os4.homedir(), ".openclaw", "media"),
|
|
10037
|
-
path8.join(os4.homedir(), ".openclaw", "workspace"),
|
|
10038
|
-
// 框架 outbound 目录(saveMediaBuffer 写入)
|
|
10039
|
-
path8.join(os4.homedir(), ".openclaw", "outbound"),
|
|
10040
|
-
// TTS 语音临时目录(deliver-pipeline 已通过 isTtsPathSafe 预检)
|
|
10041
|
-
...resolveTempRoots()
|
|
10042
|
-
];
|
|
10043
|
-
var MAX_DATA_URL_BYTES = 10 * 1024 * 1024;
|
|
10044
|
-
async function sendMedia2(params) {
|
|
10045
|
-
const { source, accountId, log: log4 } = params;
|
|
10046
|
-
const mlog = log4?.child("media");
|
|
10047
|
-
if (!source) {
|
|
10048
|
-
mlog?.error("source is empty");
|
|
10049
|
-
return { error: "sendMedia: source is required" };
|
|
10050
|
-
}
|
|
10051
|
-
const wsDir = resolveWorkspaceFromAgent(params.agentId);
|
|
10052
|
-
mlog?.debug(`resolveMediaPath source=${source} agentId=${params.agentId ?? "none"} workspaceDir=${wsDir ?? "none"}`);
|
|
10053
|
-
const resolved = await resolveMediaPath(source, mlog, wsDir);
|
|
10054
|
-
if (!resolved.ok) {
|
|
10055
|
-
mlog?.error(`resolveMediaPath failed: ${resolved.error}`);
|
|
10056
|
-
return { error: resolved.error };
|
|
10057
|
-
}
|
|
10058
|
-
const kind = params.mediaKind ?? (params.mimeType ? inferMediaKindFromMime(params.mimeType) : void 0) ?? inferMediaKind(resolved.path);
|
|
10059
|
-
const gw = getGateway(accountId);
|
|
10060
|
-
if (!gw) {
|
|
10061
|
-
return { error: `Bot "${accountId}" not running` };
|
|
10062
|
-
}
|
|
10063
|
-
const target = parseTarget(params.to);
|
|
10064
|
-
switch (kind) {
|
|
10065
|
-
case "voice":
|
|
10066
|
-
return sendVoiceMedia(gw, target, resolved.path, params);
|
|
10067
|
-
case "video":
|
|
10068
|
-
return sendVideoMedia(gw, target, resolved.path, params);
|
|
10069
|
-
case "file":
|
|
10070
|
-
return sendFileMedia(gw, target, resolved.path, params);
|
|
10071
|
-
case "image":
|
|
10072
|
-
default:
|
|
10073
|
-
return sendImageMedia(gw, target, resolved.path, params);
|
|
10074
|
-
}
|
|
10075
|
-
}
|
|
10076
|
-
async function resolveMediaPath(source, log4, workspaceDir) {
|
|
10077
|
-
const normalized = normalizePath(source);
|
|
10078
|
-
if (isDataUrl(normalized)) {
|
|
10079
|
-
if (normalized.length > MAX_DATA_URL_BYTES) {
|
|
10080
|
-
const sizeMB = (normalized.length / (1024 * 1024)).toFixed(1);
|
|
10081
|
-
return { ok: false, error: `Data URL \u8FC7\u5927\uFF08${sizeMB}MB\uFF0C\u6700\u5927 10MB\uFF09` };
|
|
10082
|
-
}
|
|
10083
|
-
return { ok: true, path: normalized, isLocal: false };
|
|
10084
|
-
}
|
|
10085
|
-
if (normalized.startsWith("http://") || normalized.startsWith("https://")) {
|
|
10086
|
-
try {
|
|
10087
|
-
await validateRemoteUrl(normalized);
|
|
10088
|
-
} catch (err) {
|
|
10089
|
-
log4?.warn(`SSRF blocked for media URL: ${normalized}`);
|
|
10090
|
-
return { ok: false, error: `\u5A92\u4F53 URL \u88AB SSRF \u9632\u62A4\u62E6\u622A: ${err instanceof Error ? err.message : String(err)}` };
|
|
10158
|
+
log.error(
|
|
10159
|
+
`compactSync failed: ${err instanceof Error ? err.message : String(err)}`
|
|
10160
|
+
);
|
|
10091
10161
|
}
|
|
10092
|
-
return { ok: true, path: normalized, isLocal: false };
|
|
10093
10162
|
}
|
|
10094
|
-
|
|
10095
|
-
|
|
10096
|
-
|
|
10097
|
-
|
|
10098
|
-
}
|
|
10099
|
-
return { ok: true, path: normalized, isLocal: false };
|
|
10163
|
+
// ── 诊断 ──
|
|
10164
|
+
/** 当前内存中的条目数 */
|
|
10165
|
+
get size() {
|
|
10166
|
+
return this.memory.size;
|
|
10100
10167
|
}
|
|
10101
|
-
|
|
10102
|
-
|
|
10103
|
-
return
|
|
10168
|
+
/** 是否已完成初始化(磁盘回放) */
|
|
10169
|
+
get isInitialized() {
|
|
10170
|
+
return this.initialized;
|
|
10104
10171
|
}
|
|
10105
|
-
|
|
10106
|
-
|
|
10107
|
-
|
|
10108
|
-
|
|
10109
|
-
|
|
10172
|
+
/** 诊断快照 */
|
|
10173
|
+
stats() {
|
|
10174
|
+
return {
|
|
10175
|
+
memoryEntries: this.memory.size,
|
|
10176
|
+
diskLines: this.diskLineCount,
|
|
10177
|
+
maxEntries: this.maxEntries,
|
|
10178
|
+
filePath: this.filePath
|
|
10179
|
+
};
|
|
10110
10180
|
}
|
|
10111
|
-
|
|
10112
|
-
|
|
10113
|
-
|
|
10114
|
-
|
|
10181
|
+
/**
|
|
10182
|
+
* 强制将当前内存状态持久化到磁盘(进程退出前调用)
|
|
10183
|
+
*/
|
|
10184
|
+
flush() {
|
|
10185
|
+
this.compactSync();
|
|
10115
10186
|
}
|
|
10116
|
-
|
|
10117
|
-
|
|
10118
|
-
function
|
|
10119
|
-
|
|
10120
|
-
if (!
|
|
10121
|
-
|
|
10122
|
-
}
|
|
10123
|
-
|
|
10124
|
-
try {
|
|
10125
|
-
const rt = tryGetQQBotRuntime();
|
|
10126
|
-
if (!rt) return void 0;
|
|
10127
|
-
return getAdapters(rt).getConfig?.();
|
|
10128
|
-
} catch {
|
|
10129
|
-
return void 0;
|
|
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);
|
|
10130
10195
|
}
|
|
10196
|
+
return store;
|
|
10131
10197
|
}
|
|
10132
|
-
function
|
|
10133
|
-
for (const
|
|
10134
|
-
|
|
10198
|
+
function flushAllRefIndexStores() {
|
|
10199
|
+
for (const store of stores.values()) {
|
|
10200
|
+
store.flush();
|
|
10135
10201
|
}
|
|
10136
|
-
return null;
|
|
10137
10202
|
}
|
|
10138
|
-
|
|
10139
|
-
|
|
10140
|
-
|
|
10141
|
-
|
|
10142
|
-
|
|
10143
|
-
|
|
10144
|
-
|
|
10145
|
-
|
|
10146
|
-
|
|
10147
|
-
}
|
|
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();
|
|
10148
10212
|
}
|
|
10149
|
-
|
|
10150
|
-
|
|
10151
|
-
|
|
10152
|
-
|
|
10153
|
-
msgId: params.replyToId
|
|
10154
|
-
});
|
|
10155
|
-
return { messageId: result.id };
|
|
10156
|
-
} catch (err) {
|
|
10157
|
-
params.log?.child("media")?.warn(`sendVoice failed (${formatErr(err)}), falling back to sendFile`);
|
|
10213
|
+
function installExitHooksOnce() {
|
|
10214
|
+
if (exitHooksInstalled) return;
|
|
10215
|
+
exitHooksInstalled = true;
|
|
10216
|
+
const flush = () => {
|
|
10158
10217
|
try {
|
|
10159
|
-
|
|
10160
|
-
|
|
10161
|
-
|
|
10162
|
-
|
|
10163
|
-
|
|
10164
|
-
|
|
10165
|
-
|
|
10166
|
-
|
|
10167
|
-
|
|
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
|
+
|
|
10243
|
+
// src/outbound/media-send.ts
|
|
10244
|
+
var path8 = __toESM(require("path"), 1);
|
|
10245
|
+
var fs9 = __toESM(require("fs"), 1);
|
|
10246
|
+
var os4 = __toESM(require("os"), 1);
|
|
10247
|
+
|
|
10248
|
+
// src/adapter/workspace.ts
|
|
10249
|
+
var import_node_module = require("module");
|
|
10250
|
+
var req = (0, import_node_module.createRequire)(__filename);
|
|
10251
|
+
var health = null;
|
|
10252
|
+
function resolveAgentWorkspace(cfg, agentId) {
|
|
10253
|
+
if (!health) {
|
|
10254
|
+
try {
|
|
10255
|
+
health = req("openclaw/plugin-sdk/health");
|
|
10256
|
+
} catch {
|
|
10257
|
+
health = null;
|
|
10168
10258
|
}
|
|
10169
10259
|
}
|
|
10260
|
+
if (health) {
|
|
10261
|
+
return health.resolveAgentWorkspaceDir(cfg, agentId ?? health.resolveDefaultAgentId(cfg));
|
|
10262
|
+
}
|
|
10263
|
+
return getQQBotMediaDir();
|
|
10170
10264
|
}
|
|
10171
|
-
|
|
10172
|
-
|
|
10173
|
-
|
|
10174
|
-
|
|
10175
|
-
|
|
10176
|
-
|
|
10177
|
-
|
|
10178
|
-
|
|
10179
|
-
|
|
10265
|
+
|
|
10266
|
+
// src/outbound/media-send.ts
|
|
10267
|
+
init_resolve();
|
|
10268
|
+
|
|
10269
|
+
// src/utils/ssrf-guard.ts
|
|
10270
|
+
var import_node_net = __toESM(require("net"), 1);
|
|
10271
|
+
var import_promises = __toESM(require("dns/promises"), 1);
|
|
10272
|
+
var RESERVED_V4_PREFIXES = [
|
|
10273
|
+
"127.",
|
|
10274
|
+
// loopback
|
|
10275
|
+
"10.",
|
|
10276
|
+
// class-A private
|
|
10277
|
+
"192.168.",
|
|
10278
|
+
// class-C private
|
|
10279
|
+
"169.254."
|
|
10280
|
+
// link-local / cloud metadata
|
|
10281
|
+
];
|
|
10282
|
+
var PRIVATE_172_RE = /^172\.(1[6-9]|2\d|3[01])\./;
|
|
10283
|
+
function isReservedAddr(ip) {
|
|
10284
|
+
if (ip === "0.0.0.0") return true;
|
|
10285
|
+
for (const pfx of RESERVED_V4_PREFIXES) {
|
|
10286
|
+
if (ip.startsWith(pfx)) return true;
|
|
10180
10287
|
}
|
|
10288
|
+
if (PRIVATE_172_RE.test(ip)) return true;
|
|
10289
|
+
const lower = ip.toLowerCase();
|
|
10290
|
+
if (lower === "::1" || lower === "::") return true;
|
|
10291
|
+
if (lower.startsWith("fe80:")) return true;
|
|
10292
|
+
if (lower.startsWith("fc") || lower.startsWith("fd")) return true;
|
|
10293
|
+
return false;
|
|
10181
10294
|
}
|
|
10182
|
-
|
|
10183
|
-
|
|
10184
|
-
|
|
10185
|
-
|
|
10186
|
-
|
|
10187
|
-
|
|
10188
|
-
|
|
10189
|
-
|
|
10190
|
-
|
|
10191
|
-
|
|
10192
|
-
|
|
10295
|
+
var ALLOWED_SCHEMES = /* @__PURE__ */ new Set(["http:", "https:"]);
|
|
10296
|
+
var QQ_TRUSTED_DOMAINS = /* @__PURE__ */ new Set([
|
|
10297
|
+
// QQ Bot API
|
|
10298
|
+
"api.sgroup.qq.com",
|
|
10299
|
+
"sandbox.api.sgroup.qq.com",
|
|
10300
|
+
// QQ Bot Token
|
|
10301
|
+
"bots.qq.com",
|
|
10302
|
+
// QQ 多媒体上传/下载
|
|
10303
|
+
"multimedia.nt.qq.com.cn",
|
|
10304
|
+
"multimedia.nt.qq.com",
|
|
10305
|
+
// QQ 群文件
|
|
10306
|
+
"grouppro.grouppro.qq.com"
|
|
10307
|
+
]);
|
|
10308
|
+
function isQQTrustedDomain(hostname) {
|
|
10309
|
+
if (QQ_TRUSTED_DOMAINS.has(hostname)) return true;
|
|
10310
|
+
const dot = hostname.indexOf(".");
|
|
10311
|
+
if (dot > 0) {
|
|
10312
|
+
const parent = hostname.slice(dot + 1);
|
|
10313
|
+
return QQ_TRUSTED_DOMAINS.has(parent);
|
|
10193
10314
|
}
|
|
10315
|
+
return false;
|
|
10194
10316
|
}
|
|
10195
|
-
function
|
|
10196
|
-
|
|
10197
|
-
|
|
10317
|
+
async function validateRemoteUrl(raw) {
|
|
10318
|
+
const url = new URL(raw);
|
|
10319
|
+
if (!ALLOWED_SCHEMES.has(url.protocol)) {
|
|
10320
|
+
throw new Error(
|
|
10321
|
+
`\u4E0D\u652F\u6301\u7684\u534F\u8BAE "${url.protocol}"\uFF0C\u4EC5\u5141\u8BB8 http/https\uFF08URL: ${raw}\uFF09`
|
|
10322
|
+
);
|
|
10198
10323
|
}
|
|
10199
|
-
|
|
10200
|
-
|
|
10201
|
-
|
|
10324
|
+
const host = url.hostname.replace(/^\[|\]$/g, "");
|
|
10325
|
+
if (isQQTrustedDomain(host)) return;
|
|
10326
|
+
if (import_node_net.default.isIP(host)) {
|
|
10327
|
+
assertPublicAddr(host, raw);
|
|
10328
|
+
return;
|
|
10329
|
+
}
|
|
10330
|
+
try {
|
|
10331
|
+
const ips = await import_promises.default.resolve(host);
|
|
10332
|
+
for (const ip of ips) {
|
|
10333
|
+
assertPublicAddr(ip, raw, host);
|
|
10334
|
+
}
|
|
10335
|
+
} catch (err) {
|
|
10336
|
+
if (err instanceof Error && err.message.includes("\u5185\u7F51")) throw err;
|
|
10337
|
+
console.warn(`[url-check] DNS \u89E3\u6790 "${host}" \u5931\u8D25: ${err}`);
|
|
10202
10338
|
}
|
|
10203
|
-
return { localPath: source };
|
|
10204
10339
|
}
|
|
10205
|
-
function
|
|
10206
|
-
if (
|
|
10207
|
-
|
|
10340
|
+
function assertPublicAddr(ip, originalUrl, domain) {
|
|
10341
|
+
if (!isReservedAddr(ip)) return;
|
|
10342
|
+
const target = domain ? `\u57DF\u540D "${domain}" \u89E3\u6790\u5230\u5185\u7F51\u5730\u5740 "${ip}"` : `\u5185\u7F51\u5730\u5740 "${ip}"`;
|
|
10343
|
+
throw new Error(
|
|
10344
|
+
`\u7981\u6B62\u8BBF\u95EE${target}\uFF0C\u5DF2\u62E6\u622A\u6F5C\u5728\u7684 SSRF \u8BF7\u6C42\uFF08URL: ${originalUrl}\uFF09`
|
|
10345
|
+
);
|
|
10208
10346
|
}
|
|
10209
10347
|
|
|
10210
|
-
// src/
|
|
10211
|
-
var
|
|
10212
|
-
var
|
|
10213
|
-
var
|
|
10214
|
-
|
|
10215
|
-
|
|
10216
|
-
if (
|
|
10217
|
-
|
|
10218
|
-
|
|
10219
|
-
|
|
10220
|
-
|
|
10348
|
+
// src/outbound/local-file-router.ts
|
|
10349
|
+
var path7 = __toESM(require("path"), 1);
|
|
10350
|
+
var fs8 = __toESM(require("fs"), 1);
|
|
10351
|
+
var os3 = __toESM(require("os"), 1);
|
|
10352
|
+
function normalizePath(p2) {
|
|
10353
|
+
let result = p2;
|
|
10354
|
+
if (result.startsWith("file://")) {
|
|
10355
|
+
result = result.slice("file://".length);
|
|
10356
|
+
if (/^\/[a-zA-Z]:[\\/]/.test(result)) {
|
|
10357
|
+
result = result.slice(1);
|
|
10358
|
+
}
|
|
10221
10359
|
}
|
|
10222
|
-
return _setup;
|
|
10223
|
-
}
|
|
10224
|
-
function loadTools() {
|
|
10225
|
-
if (_tools !== void 0) return _tools;
|
|
10226
10360
|
try {
|
|
10227
|
-
|
|
10361
|
+
result = decodeURIComponent(result);
|
|
10228
10362
|
} catch {
|
|
10229
|
-
_tools = null;
|
|
10230
10363
|
}
|
|
10231
|
-
|
|
10232
|
-
|
|
10233
|
-
|
|
10234
|
-
|
|
10235
|
-
const mod = loadSetup();
|
|
10236
|
-
if (mod) return mod.createStandardChannelSetupStatus(...args);
|
|
10237
|
-
return {
|
|
10238
|
-
channelLabel: args[0]?.channelLabel ?? "QQ Bot",
|
|
10239
|
-
configuredLabel: "Configured",
|
|
10240
|
-
unconfiguredLabel: "Not configured",
|
|
10241
|
-
resolveConfigured: () => false
|
|
10242
|
-
};
|
|
10243
|
-
}
|
|
10244
|
-
function setSetupChannelEnabled(...args) {
|
|
10245
|
-
loadSetup()?.setSetupChannelEnabled?.(...args);
|
|
10364
|
+
if (result === "~" || result.startsWith("~/") || result.startsWith("~\\")) {
|
|
10365
|
+
result = result.replace(/^~/, os3.homedir());
|
|
10366
|
+
}
|
|
10367
|
+
return result;
|
|
10246
10368
|
}
|
|
10247
|
-
function
|
|
10248
|
-
|
|
10249
|
-
if (
|
|
10250
|
-
|
|
10369
|
+
function isLocalFilePath(source) {
|
|
10370
|
+
if (!source) return false;
|
|
10371
|
+
if (source.startsWith("http://") || source.startsWith("https://")) return false;
|
|
10372
|
+
if (source.startsWith("data:")) return false;
|
|
10373
|
+
if (source.startsWith("file://")) return true;
|
|
10374
|
+
if (source === "~" || source.startsWith("~/") || source.startsWith("~\\")) return true;
|
|
10375
|
+
if (source.startsWith("/")) return true;
|
|
10376
|
+
if (/^[a-zA-Z]:[\\/]/.test(source)) return true;
|
|
10377
|
+
if (source.startsWith("\\\\")) return true;
|
|
10378
|
+
if (source.startsWith("./") || source.startsWith("../")) return true;
|
|
10379
|
+
if (source.startsWith(".\\") || source.startsWith("..\\")) return true;
|
|
10380
|
+
return false;
|
|
10251
10381
|
}
|
|
10252
|
-
|
|
10253
|
-
|
|
10254
|
-
var import_qrcode_terminal = __toESM(require_main(), 1);
|
|
10255
|
-
|
|
10256
|
-
// node_modules/.pnpm/@tencent-connect+qqbot-connector@1.2.0/node_modules/@tencent-connect/qqbot-connector/dist/esm/qqbot-session.js
|
|
10257
|
-
var import_node_crypto = __toESM(require("crypto"), 1);
|
|
10258
|
-
var import_node_https = __toESM(require("https"), 1);
|
|
10259
|
-
var E = { production: "q.qq.com", test: "test.q.qq.com" };
|
|
10260
|
-
function d(t = "production") {
|
|
10261
|
-
return E[t];
|
|
10382
|
+
function isDataUrl(source) {
|
|
10383
|
+
return source.startsWith("data:");
|
|
10262
10384
|
}
|
|
10263
|
-
|
|
10264
|
-
|
|
10385
|
+
var IMAGE_EXTS = /* @__PURE__ */ new Set([".jpg", ".jpeg", ".png", ".gif", ".webp", ".bmp", ".svg", ".ico"]);
|
|
10386
|
+
var VOICE_EXTS = /* @__PURE__ */ new Set([".wav", ".mp3", ".silk", ".amr", ".ogg", ".flac", ".aac", ".m4a"]);
|
|
10387
|
+
var VIDEO_EXTS = /* @__PURE__ */ new Set([".mp4", ".avi", ".mov", ".mkv", ".webm", ".flv", ".wmv"]);
|
|
10388
|
+
function inferMediaKind(filePath) {
|
|
10389
|
+
const ext = path7.extname(filePath).toLowerCase();
|
|
10390
|
+
if (IMAGE_EXTS.has(ext)) return "image";
|
|
10391
|
+
if (VOICE_EXTS.has(ext)) return "voice";
|
|
10392
|
+
if (VIDEO_EXTS.has(ext)) return "video";
|
|
10393
|
+
return "file";
|
|
10265
10394
|
}
|
|
10266
|
-
|
|
10267
|
-
(
|
|
10268
|
-
|
|
10269
|
-
|
|
10270
|
-
|
|
10271
|
-
|
|
10272
|
-
return o.setAuthTag(c), Buffer.concat([o.update(s), o.final()]).toString("utf8");
|
|
10395
|
+
function inferMediaKindFromMime(mime) {
|
|
10396
|
+
const lower = mime.toLowerCase();
|
|
10397
|
+
if (lower.startsWith("image/")) return "image";
|
|
10398
|
+
if (lower.startsWith("audio/") || lower === "voice") return "voice";
|
|
10399
|
+
if (lower.startsWith("video/")) return "video";
|
|
10400
|
+
return "file";
|
|
10273
10401
|
}
|
|
10274
|
-
function
|
|
10275
|
-
|
|
10276
|
-
|
|
10277
|
-
|
|
10278
|
-
|
|
10279
|
-
|
|
10402
|
+
function isPathInAllowedRoots(absPath, allowedRoots) {
|
|
10403
|
+
if (!allowedRoots.length) return false;
|
|
10404
|
+
try {
|
|
10405
|
+
const real = fs8.realpathSync(absPath);
|
|
10406
|
+
return allowedRoots.some((root) => {
|
|
10407
|
+
try {
|
|
10408
|
+
const rootReal = fs8.existsSync(root) ? fs8.realpathSync(root) : root;
|
|
10409
|
+
return real.startsWith(rootReal + path7.sep) || real === rootReal;
|
|
10410
|
+
} catch {
|
|
10411
|
+
return false;
|
|
10280
10412
|
}
|
|
10281
|
-
let f = "";
|
|
10282
|
-
i.on("data", (p2) => {
|
|
10283
|
-
f += p2;
|
|
10284
|
-
}), i.on("end", () => {
|
|
10285
|
-
try {
|
|
10286
|
-
n(JSON.parse(f));
|
|
10287
|
-
} catch (p2) {
|
|
10288
|
-
e(p2);
|
|
10289
|
-
}
|
|
10290
|
-
});
|
|
10291
10413
|
});
|
|
10292
|
-
|
|
10293
|
-
|
|
10294
|
-
|
|
10295
|
-
});
|
|
10296
|
-
}
|
|
10297
|
-
async function y(t = "production", r = 1e4) {
|
|
10298
|
-
const a = `https://${d(t)}/lite/create_bind_task`, n = l(), e = await h(a, { key: n }, r);
|
|
10299
|
-
if (e.retcode !== 0) throw new Error(e.msg ?? "create_bind_task failed");
|
|
10300
|
-
if (!e.data?.task_id) throw new Error("create_bind_task: missing task_id");
|
|
10301
|
-
return { taskId: e.data.task_id, key: n };
|
|
10302
|
-
}
|
|
10303
|
-
async function g(t, r = "production", a = 1e4) {
|
|
10304
|
-
const n = `https://${d(r)}/lite/poll_bind_result`, e = await h(n, { task_id: t }, a);
|
|
10305
|
-
if (e.retcode !== 0) throw new Error(e.msg ?? "poll_bind_result failed");
|
|
10306
|
-
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 };
|
|
10307
|
-
}
|
|
10308
|
-
function w(t, r = "") {
|
|
10309
|
-
return `https://${d("production")}/qqbot/openclaw/connect.html?task_id=${encodeURIComponent(t)}&source=${encodeURIComponent(r)}&_wv=2`;
|
|
10414
|
+
} catch {
|
|
10415
|
+
return false;
|
|
10416
|
+
}
|
|
10310
10417
|
}
|
|
10311
10418
|
|
|
10312
|
-
//
|
|
10313
|
-
|
|
10314
|
-
|
|
10315
|
-
|
|
10316
|
-
|
|
10317
|
-
|
|
10318
|
-
|
|
10319
|
-
}
|
|
10320
|
-
|
|
10321
|
-
|
|
10322
|
-
|
|
10323
|
-
|
|
10324
|
-
t(new DOMException("Aborted", "AbortError"));
|
|
10325
|
-
return;
|
|
10419
|
+
// src/outbound/media-send.ts
|
|
10420
|
+
function resolveTempRoots() {
|
|
10421
|
+
const roots = /* @__PURE__ */ new Set();
|
|
10422
|
+
try {
|
|
10423
|
+
const tmp = os4.tmpdir();
|
|
10424
|
+
roots.add(fs9.existsSync(tmp) ? fs9.realpathSync(tmp) : tmp);
|
|
10425
|
+
} catch {
|
|
10426
|
+
}
|
|
10427
|
+
if (process.platform !== "win32") {
|
|
10428
|
+
try {
|
|
10429
|
+
roots.add(fs9.realpathSync("/tmp"));
|
|
10430
|
+
} catch {
|
|
10326
10431
|
}
|
|
10327
|
-
|
|
10328
|
-
|
|
10329
|
-
clearTimeout(n), t(new DOMException("Aborted", "AbortError"));
|
|
10330
|
-
}, { once: true });
|
|
10331
|
-
});
|
|
10432
|
+
}
|
|
10433
|
+
return [...roots];
|
|
10332
10434
|
}
|
|
10333
|
-
|
|
10334
|
-
|
|
10335
|
-
|
|
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) => {
|
|
10336
10441
|
try {
|
|
10337
|
-
|
|
10442
|
+
const real = fs9.existsSync(p2) ? fs9.realpathSync(p2) : p2;
|
|
10443
|
+
if (!added.has(real)) {
|
|
10444
|
+
added.add(real);
|
|
10445
|
+
roots.push(real);
|
|
10446
|
+
}
|
|
10338
10447
|
} catch {
|
|
10339
|
-
await d2(p, e);
|
|
10340
|
-
continue;
|
|
10341
|
-
}
|
|
10342
|
-
if (t.status === u.COMPLETED) {
|
|
10343
|
-
const n = b(t.botEncryptSecret, o);
|
|
10344
|
-
return { outcome: "scanned", appId: t.botAppId, appSecret: n, userOpenid: t.userOpenid };
|
|
10345
10448
|
}
|
|
10346
|
-
|
|
10347
|
-
|
|
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);
|
|
10348
10456
|
}
|
|
10349
|
-
|
|
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;
|
|
10350
10464
|
}
|
|
10351
|
-
|
|
10352
|
-
|
|
10353
|
-
|
|
10354
|
-
|
|
10355
|
-
|
|
10356
|
-
|
|
10357
|
-
|
|
10358
|
-
|
|
10359
|
-
|
|
10360
|
-
|
|
10361
|
-
|
|
10362
|
-
|
|
10363
|
-
|
|
10364
|
-
|
|
10365
|
-
|
|
10366
|
-
|
|
10367
|
-
|
|
10368
|
-
|
|
10369
|
-
|
|
10370
|
-
|
|
10371
|
-
|
|
10372
|
-
|
|
10373
|
-
|
|
10374
|
-
|
|
10375
|
-
|
|
10376
|
-
|
|
10465
|
+
var MAX_DATA_URL_BYTES = 10 * 1024 * 1024;
|
|
10466
|
+
async function sendMedia2(params) {
|
|
10467
|
+
const { source, accountId, log: log4 } = params;
|
|
10468
|
+
const mlog = log4?.child("media");
|
|
10469
|
+
if (!source) {
|
|
10470
|
+
mlog?.error("source is empty");
|
|
10471
|
+
return { error: "sendMedia: source is required" };
|
|
10472
|
+
}
|
|
10473
|
+
const wsDir = resolveWorkspaceFromAgent(params.agentId);
|
|
10474
|
+
mlog?.debug(`resolveMediaPath source=${source} agentId=${params.agentId ?? "none"} workspaceDir=${wsDir ?? "none"}`);
|
|
10475
|
+
const resolved = await resolveMediaPath(source, mlog, wsDir);
|
|
10476
|
+
if (!resolved.ok) {
|
|
10477
|
+
mlog?.error(`resolveMediaPath failed: ${resolved.error}`);
|
|
10478
|
+
return { error: resolved.error };
|
|
10479
|
+
}
|
|
10480
|
+
const kind = params.mediaKind ?? (params.mimeType ? inferMediaKindFromMime(params.mimeType) : void 0) ?? inferMediaKind(resolved.path);
|
|
10481
|
+
const gw = getGateway(accountId);
|
|
10482
|
+
if (!gw) {
|
|
10483
|
+
return { error: `Bot "${accountId}" not running` };
|
|
10484
|
+
}
|
|
10485
|
+
const target = parseTarget(params.to);
|
|
10486
|
+
switch (kind) {
|
|
10487
|
+
case "voice":
|
|
10488
|
+
return sendVoiceMedia(gw, target, resolved.path, params);
|
|
10489
|
+
case "video":
|
|
10490
|
+
return sendVideoMedia(gw, target, resolved.path, params);
|
|
10491
|
+
case "file":
|
|
10492
|
+
return sendFileMedia(gw, target, resolved.path, params);
|
|
10493
|
+
case "image":
|
|
10494
|
+
default:
|
|
10495
|
+
return sendImageMedia(gw, target, resolved.path, params);
|
|
10496
|
+
}
|
|
10497
|
+
}
|
|
10498
|
+
async function resolveMediaPath(source, log4, workspaceDir) {
|
|
10499
|
+
const normalized = normalizePath(source);
|
|
10500
|
+
if (isDataUrl(normalized)) {
|
|
10501
|
+
if (normalized.length > MAX_DATA_URL_BYTES) {
|
|
10502
|
+
const sizeMB = (normalized.length / (1024 * 1024)).toFixed(1);
|
|
10503
|
+
return { ok: false, error: `Data URL \u8FC7\u5927\uFF08${sizeMB}MB\uFF0C\u6700\u5927 10MB\uFF09` };
|
|
10504
|
+
}
|
|
10505
|
+
return { ok: true, path: normalized, isLocal: false };
|
|
10506
|
+
}
|
|
10507
|
+
if (normalized.startsWith("http://") || normalized.startsWith("https://")) {
|
|
10508
|
+
try {
|
|
10509
|
+
await validateRemoteUrl(normalized);
|
|
10510
|
+
} catch (err) {
|
|
10511
|
+
log4?.warn(`SSRF blocked for media URL: ${normalized}`);
|
|
10512
|
+
return { ok: false, error: `\u5A92\u4F53 URL \u88AB SSRF \u9632\u62A4\u62E6\u622A: ${err instanceof Error ? err.message : String(err)}` };
|
|
10377
10513
|
}
|
|
10378
|
-
|
|
10379
|
-
|
|
10380
|
-
|
|
10381
|
-
|
|
10514
|
+
return { ok: true, path: normalized, isLocal: false };
|
|
10515
|
+
}
|
|
10516
|
+
if (!isLocalFilePath(normalized)) {
|
|
10517
|
+
const resolved2 = resolveWorkingFile(normalized, workspaceDir);
|
|
10518
|
+
if (resolved2) {
|
|
10519
|
+
return { ok: true, path: resolved2, isLocal: true };
|
|
10382
10520
|
}
|
|
10383
|
-
|
|
10384
|
-
}
|
|
10521
|
+
return { ok: true, path: normalized, isLocal: false };
|
|
10522
|
+
}
|
|
10523
|
+
const resolved = path8.resolve(normalized);
|
|
10524
|
+
if (!fs9.existsSync(resolved)) {
|
|
10525
|
+
return { ok: false, error: `File not found: ${resolved}` };
|
|
10526
|
+
}
|
|
10527
|
+
let real;
|
|
10528
|
+
try {
|
|
10529
|
+
real = fs9.realpathSync(resolved);
|
|
10530
|
+
} catch {
|
|
10531
|
+
return { ok: false, error: `Cannot resolve path: ${resolved}` };
|
|
10532
|
+
}
|
|
10533
|
+
const dynamicRoots = buildDynamicAllowedRoots(workspaceDir);
|
|
10534
|
+
const allowed = isPathInAllowedRoots(real, dynamicRoots);
|
|
10535
|
+
if (!allowed) {
|
|
10536
|
+
log4?.warn(`path blocked \u2014 not in allowed directory: ${real}`);
|
|
10537
|
+
return { ok: false, error: `\u6587\u4EF6\u8DEF\u5F84\u4E0D\u5728\u5141\u8BB8\u7684\u76EE\u5F55\u4E2D` };
|
|
10538
|
+
}
|
|
10539
|
+
return { ok: true, path: real, isLocal: true };
|
|
10385
10540
|
}
|
|
10386
|
-
function
|
|
10387
|
-
|
|
10388
|
-
|
|
10389
|
-
|
|
10541
|
+
function resolveWorkspaceFromAgent(agentId) {
|
|
10542
|
+
const cfg = resolveConfigViaAdapter();
|
|
10543
|
+
if (!cfg) return void 0;
|
|
10544
|
+
return resolveAgentWorkspace(cfg, agentId);
|
|
10390
10545
|
}
|
|
10391
|
-
|
|
10392
|
-
|
|
10393
|
-
|
|
10394
|
-
|
|
10395
|
-
|
|
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
|
+
}
|
|
10554
|
+
}
|
|
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;
|
|
10396
10560
|
}
|
|
10397
|
-
async function
|
|
10561
|
+
async function sendImageMedia(gw, target, source, params) {
|
|
10398
10562
|
try {
|
|
10399
|
-
const
|
|
10400
|
-
|
|
10401
|
-
|
|
10402
|
-
|
|
10403
|
-
}
|
|
10404
|
-
let next = cfg;
|
|
10405
|
-
for (const { appId, appSecret, userOpenid } of accounts) {
|
|
10406
|
-
next = applyQQBotAccountConfig(next, appId, { appId, clientSecret: appSecret });
|
|
10407
|
-
next = applyAccountDefaults(next, appId, userOpenid);
|
|
10408
|
-
}
|
|
10409
|
-
if (accounts.length === 1) {
|
|
10410
|
-
rt.log(`\u2714 QQ Bot \u7ED1\u5B9A\u6210\u529F\uFF01(AppID: ${accounts[0].appId})`);
|
|
10411
|
-
} else {
|
|
10412
|
-
rt.log(`\u2714 ${accounts.length} \u4E2A QQ Bot \u7ED1\u5B9A\u6210\u529F\uFF01(AppID: ${accounts.map((a) => a.appId).join(", ")})`);
|
|
10413
|
-
}
|
|
10414
|
-
return next;
|
|
10563
|
+
const result = await gw.sendMedia(target, source, {
|
|
10564
|
+
text: params.text,
|
|
10565
|
+
msgId: params.replyToId
|
|
10566
|
+
});
|
|
10567
|
+
return { messageId: result.id };
|
|
10415
10568
|
} catch (err) {
|
|
10416
|
-
|
|
10417
|
-
await prompter.note(`\u7ED1\u5B9A\u5931\u8D25\uFF0C\u60A8\u53EF\u4EE5\u7A0D\u540E\u624B\u52A8\u914D\u7F6E\u3002
|
|
10418
|
-
\u6587\u6863: ${formatDocsLink("/channels/qqbot", "qqbot")}`, "QQ Bot");
|
|
10419
|
-
return cfg;
|
|
10569
|
+
return { error: formatErr(err) };
|
|
10420
10570
|
}
|
|
10421
10571
|
}
|
|
10422
|
-
async function
|
|
10423
|
-
const
|
|
10424
|
-
|
|
10425
|
-
|
|
10426
|
-
|
|
10427
|
-
|
|
10428
|
-
|
|
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`);
|
|
10581
|
+
try {
|
|
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)}` };
|
|
10591
|
+
}
|
|
10592
|
+
}
|
|
10429
10593
|
}
|
|
10430
|
-
async function
|
|
10431
|
-
|
|
10432
|
-
|
|
10433
|
-
|
|
10434
|
-
|
|
10435
|
-
|
|
10436
|
-
|
|
10437
|
-
|
|
10438
|
-
|
|
10439
|
-
]
|
|
10440
|
-
});
|
|
10441
|
-
let next = params.cfg;
|
|
10442
|
-
if (mode === "qr") {
|
|
10443
|
-
next = await linkViaQrCode(next, accountId, params.prompter, params.runtime);
|
|
10444
|
-
} else if (mode === "manual") {
|
|
10445
|
-
next = await linkViaManual(next, params.prompter);
|
|
10446
|
-
} else if (!configured) {
|
|
10447
|
-
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");
|
|
10594
|
+
async function sendVideoMedia(gw, target, source, params) {
|
|
10595
|
+
try {
|
|
10596
|
+
const result = await gw.sendVideo(target, source, {
|
|
10597
|
+
text: params.text,
|
|
10598
|
+
msgId: params.replyToId
|
|
10599
|
+
});
|
|
10600
|
+
return { messageId: result.id };
|
|
10601
|
+
} catch (err) {
|
|
10602
|
+
return { error: formatErr(err) };
|
|
10448
10603
|
}
|
|
10449
|
-
return { cfg: next };
|
|
10450
10604
|
}
|
|
10451
|
-
function
|
|
10452
|
-
|
|
10453
|
-
|
|
10454
|
-
|
|
10455
|
-
|
|
10456
|
-
|
|
10457
|
-
|
|
10458
|
-
|
|
10459
|
-
|
|
10460
|
-
|
|
10461
|
-
|
|
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) };
|
|
10462
10616
|
}
|
|
10463
|
-
|
|
10464
|
-
|
|
10617
|
+
}
|
|
10618
|
+
function resolveVoiceSource2(source) {
|
|
10619
|
+
if (source.startsWith("http://") || source.startsWith("https://")) {
|
|
10620
|
+
return { url: source };
|
|
10621
|
+
}
|
|
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);
|
|
10465
10631
|
}
|
|
10466
10632
|
|
|
10467
10633
|
// src/setup/surface.ts
|
|
10634
|
+
init_setup();
|
|
10635
|
+
init_config();
|
|
10636
|
+
init_finalize();
|
|
10468
10637
|
var CHANNEL = "qqbot";
|
|
10469
10638
|
var qqbotSetupWizard = {
|
|
10470
10639
|
channel: CHANNEL,
|
|
@@ -10481,6 +10650,14 @@ var qqbotSetupWizard = {
|
|
|
10481
10650
|
return Boolean(account.appId && account.clientSecret);
|
|
10482
10651
|
})
|
|
10483
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
|
+
},
|
|
10484
10661
|
credentials: [],
|
|
10485
10662
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
10486
10663
|
finalize: (async ({ cfg, accountId, prompter, runtime: runtime2 }) => finalizeQQBotSetup({ cfg, accountId, prompter, runtime: runtime2 })),
|
|
@@ -10490,6 +10667,118 @@ var qqbotSetupWizard = {
|
|
|
10490
10667
|
}
|
|
10491
10668
|
};
|
|
10492
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
|
+
|
|
10493
10782
|
// src/outbound/sanitize.ts
|
|
10494
10783
|
var INTERNAL_TAGS = [
|
|
10495
10784
|
// 框架脚手架标签
|
|
@@ -10515,6 +10804,10 @@ function sanitizeQQBotText(text) {
|
|
|
10515
10804
|
return result.trim();
|
|
10516
10805
|
}
|
|
10517
10806
|
|
|
10807
|
+
// src/gateway/lifecycle.ts
|
|
10808
|
+
init_config();
|
|
10809
|
+
init_resolve();
|
|
10810
|
+
|
|
10518
10811
|
// src/gateway/qqbot-gateway.ts
|
|
10519
10812
|
var import_node_os4 = __toESM(require("os"), 1);
|
|
10520
10813
|
|
|
@@ -10751,6 +11044,7 @@ function botMe() {
|
|
|
10751
11044
|
}
|
|
10752
11045
|
|
|
10753
11046
|
// src/commands/config-util.ts
|
|
11047
|
+
init_resolve();
|
|
10754
11048
|
function checkCommandAuth(ctx) {
|
|
10755
11049
|
const p2 = ctx.state.policy;
|
|
10756
11050
|
const mode = p2?.c2cMode ?? "allowlist";
|
|
@@ -10998,6 +11292,7 @@ var import_node_fs5 = __toESM(require("fs"), 1);
|
|
|
10998
11292
|
var import_node_path5 = __toESM(require("path"), 1);
|
|
10999
11293
|
var import_node_os3 = __toESM(require("os"), 1);
|
|
11000
11294
|
var import_node_crypto2 = __toESM(require("crypto"), 1);
|
|
11295
|
+
init_resolve();
|
|
11001
11296
|
var MAX_LINES_PER_FILE = 1e3;
|
|
11002
11297
|
var MAX_FILES = 4;
|
|
11003
11298
|
var LOG_KEYWORDS = ["gateway", "openclaw", "clawdbot", "moltbot"];
|
|
@@ -11202,6 +11497,7 @@ function botLogs(runtime2) {
|
|
|
11202
11497
|
}
|
|
11203
11498
|
|
|
11204
11499
|
// src/commands/bot-approve.ts
|
|
11500
|
+
init_resolve();
|
|
11205
11501
|
var PRESETS = {
|
|
11206
11502
|
on: { security: "allowlist", ask: "on-miss", desc: "\u5F00\u542F\u5BA1\u6279\uFF08\u767D\u540D\u5355\u6A21\u5F0F\uFF09" },
|
|
11207
11503
|
off: { security: "full", ask: "off", desc: "\u5173\u95ED\u5BA1\u6279" },
|
|
@@ -11505,10 +11801,10 @@ function buildCommandList(account, opts) {
|
|
|
11505
11801
|
// src/middleware/attachment.ts
|
|
11506
11802
|
var path17 = __toESM(require("path"), 1);
|
|
11507
11803
|
|
|
11508
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.
|
|
11804
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607101530/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/utils/reply-limiter.js
|
|
11509
11805
|
var DEFAULT_TTL_MS = 60 * 60 * 1e3;
|
|
11510
11806
|
|
|
11511
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.
|
|
11807
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607101530/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/utils/media-tags.js
|
|
11512
11808
|
var VALID_TAGS = ["qqimg", "qqvoice", "qqvideo", "qqfile", "qqmedia"];
|
|
11513
11809
|
var TAG_ALIASES = {
|
|
11514
11810
|
qq_img: "qqimg",
|
|
@@ -11557,30 +11853,30 @@ var SELF_CLOSING_TAG_REGEX = new RegExp("`?" + LEFT_BRACKET + "\\s*(" + TAG_NAME
|
|
|
11557
11853
|
var FUZZY_MEDIA_TAG_REGEX = new RegExp("`?" + LEFT_BRACKET + "\\s*(" + TAG_NAME_PATTERN + ")\\s*" + RIGHT_BRACKET + `["']?\\s*([^<\uFF1C<\uFF1E>"'\`]+?)\\s*["']?` + LEFT_BRACKET + "\\s*/?\\s*(?:" + TAG_NAME_PATTERN + ")\\s*" + RIGHT_BRACKET + "`?", "gi");
|
|
11558
11854
|
var MULTILINE_TAG_CLEANUP = new RegExp("(" + LEFT_BRACKET + "\\s*(?:" + TAG_NAME_PATTERN + ")\\s*" + RIGHT_BRACKET + ")([\\s\\S]*?)(" + LEFT_BRACKET + "\\s*/?\\s*(?:" + TAG_NAME_PATTERN + ")\\s*" + RIGHT_BRACKET + ")", "gi");
|
|
11559
11855
|
|
|
11560
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.
|
|
11856
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607101530/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/utils/ref-index-store.js
|
|
11561
11857
|
var import_node_fs6 = __toESM(require("fs"), 1);
|
|
11562
11858
|
var DEFAULT_TTL_MS2 = 7 * 24 * 60 * 60 * 1e3;
|
|
11563
11859
|
|
|
11564
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.
|
|
11860
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607101530/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/utils/session-store.js
|
|
11565
11861
|
var import_node_fs7 = __toESM(require("fs"), 1);
|
|
11566
11862
|
var import_node_path7 = __toESM(require("path"), 1);
|
|
11567
11863
|
var DEFAULT_EXPIRE_MS = 5 * 60 * 1e3;
|
|
11568
11864
|
|
|
11569
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.
|
|
11865
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607101530/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/utils/text-parsing.js
|
|
11570
11866
|
var MAX_FACE_EXT_BYTES = 64 * 1024;
|
|
11571
11867
|
|
|
11572
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.
|
|
11868
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607101530/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/utils/media-source.js
|
|
11573
11869
|
var fs14 = __toESM(require("fs"), 1);
|
|
11574
11870
|
|
|
11575
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.
|
|
11871
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607101530/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/utils/image-size.js
|
|
11576
11872
|
var import_node_buffer = require("buffer");
|
|
11577
11873
|
|
|
11578
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.
|
|
11874
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607101530/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/utils/ffmpeg.js
|
|
11579
11875
|
var import_node_child_process = require("child_process");
|
|
11580
11876
|
var fs15 = __toESM(require("fs"), 1);
|
|
11581
11877
|
var path13 = __toESM(require("path"), 1);
|
|
11582
11878
|
|
|
11583
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.
|
|
11879
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607101530/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/utils/audio.js
|
|
11584
11880
|
var import_node_child_process2 = require("child_process");
|
|
11585
11881
|
var fs16 = __toESM(require("fs"), 1);
|
|
11586
11882
|
var path14 = __toESM(require("path"), 1);
|
|
@@ -11854,6 +12150,7 @@ async function downloadViaFetch(opts) {
|
|
|
11854
12150
|
}
|
|
11855
12151
|
|
|
11856
12152
|
// src/middleware/attachment.ts
|
|
12153
|
+
init_resolve();
|
|
11857
12154
|
function attachmentProcessor(opts) {
|
|
11858
12155
|
return async (ctx, next) => {
|
|
11859
12156
|
const msg = ctx.message;
|
|
@@ -12057,6 +12354,7 @@ async function downloadMediaFile(url, filename, log4) {
|
|
|
12057
12354
|
}
|
|
12058
12355
|
|
|
12059
12356
|
// src/dispatch/body-assembler.ts
|
|
12357
|
+
init_resolve();
|
|
12060
12358
|
var QUOTE_BEGIN = "[Quoted message begins]";
|
|
12061
12359
|
var QUOTE_END = "[Quoted message ends]";
|
|
12062
12360
|
var REF_BEGIN = "[Reference message begins]";
|
|
@@ -12219,7 +12517,7 @@ function isNonEmpty(x) {
|
|
|
12219
12517
|
}
|
|
12220
12518
|
function buildAgentBody(input) {
|
|
12221
12519
|
const { userContent, base, isGroup, wasMentioned, history } = input;
|
|
12222
|
-
if (userContent.startsWith("/")) {
|
|
12520
|
+
if (userContent.trim().startsWith("/")) {
|
|
12223
12521
|
return userContent;
|
|
12224
12522
|
}
|
|
12225
12523
|
if (isGroup && wasMentioned && history && history.length > 0) {
|
|
@@ -12260,6 +12558,7 @@ function normalizeTimestamp(ts) {
|
|
|
12260
12558
|
}
|
|
12261
12559
|
|
|
12262
12560
|
// src/middleware/policy-injector.ts
|
|
12561
|
+
init_config();
|
|
12263
12562
|
function createPolicyInjector(account) {
|
|
12264
12563
|
return async (ctx, next) => {
|
|
12265
12564
|
const msg = ctx.message;
|
|
@@ -12386,6 +12685,25 @@ async function checkPairingMode(ctx, next, opts) {
|
|
|
12386
12685
|
}
|
|
12387
12686
|
}
|
|
12388
12687
|
|
|
12688
|
+
// src/utils/mention.ts
|
|
12689
|
+
function stripMentionText(text, mentions) {
|
|
12690
|
+
if (!text || !mentions?.length) return text;
|
|
12691
|
+
let cleaned = text;
|
|
12692
|
+
for (const m3 of mentions) {
|
|
12693
|
+
const openid = m3.member_openid ?? m3.id ?? m3.user_openid;
|
|
12694
|
+
if (!openid) continue;
|
|
12695
|
+
if (m3.is_you) {
|
|
12696
|
+
cleaned = cleaned.replace(new RegExp(`<@!?${openid}>`, "g"), "").trim();
|
|
12697
|
+
} else {
|
|
12698
|
+
const displayName = m3.nickname ?? m3.username;
|
|
12699
|
+
if (displayName) {
|
|
12700
|
+
cleaned = cleaned.replace(new RegExp(`<@!?${openid}>`, "g"), `@${displayName}`);
|
|
12701
|
+
}
|
|
12702
|
+
}
|
|
12703
|
+
}
|
|
12704
|
+
return cleaned;
|
|
12705
|
+
}
|
|
12706
|
+
|
|
12389
12707
|
// src/gateway/middleware-setup.ts
|
|
12390
12708
|
function setupMiddlewares(bot, account, opts) {
|
|
12391
12709
|
bot.use(errorHandler());
|
|
@@ -12404,8 +12722,13 @@ function setupMiddlewares(bot, account, opts) {
|
|
|
12404
12722
|
getRuntime: opts.getRuntime
|
|
12405
12723
|
}));
|
|
12406
12724
|
bot.use(mentionGate());
|
|
12407
|
-
bot.use(contentSanitizer({
|
|
12725
|
+
bot.use(contentSanitizer({
|
|
12726
|
+
parseFaceTags: true,
|
|
12727
|
+
transform: (content, ctx) => stripMentionText(content, ctx.message.mentions)
|
|
12728
|
+
}));
|
|
12408
12729
|
bot.use(rateLimiter());
|
|
12730
|
+
const slash = slashCommand({ commands: buildCommandList(account, { getRuntime: opts.getRuntime }) });
|
|
12731
|
+
bot.use(slash.middleware);
|
|
12409
12732
|
bot.use(concurrencyGuard({
|
|
12410
12733
|
strategy: "merge",
|
|
12411
12734
|
maxQueue: 50,
|
|
@@ -12438,8 +12761,6 @@ function setupMiddlewares(bot, account, opts) {
|
|
|
12438
12761
|
return assembled.agentBody;
|
|
12439
12762
|
}
|
|
12440
12763
|
}));
|
|
12441
|
-
const slash = slashCommand({ commands: buildCommandList(account, { getRuntime: opts.getRuntime }) });
|
|
12442
|
-
bot.use(slash.middleware);
|
|
12443
12764
|
}
|
|
12444
12765
|
|
|
12445
12766
|
// src/dispatch/envelope-builder.ts
|
|
@@ -12908,6 +13229,7 @@ function shouldUseStreaming(account, targetScope) {
|
|
|
12908
13229
|
}
|
|
12909
13230
|
|
|
12910
13231
|
// src/dispatch/dispatch.ts
|
|
13232
|
+
init_resolve();
|
|
12911
13233
|
async function dispatchToOpenClaw(ctx, msg, account, runtime2, log4) {
|
|
12912
13234
|
const dlog = log4?.child("dispatch");
|
|
12913
13235
|
const adapters = getAdapters(runtime2, dlog);
|
|
@@ -13469,6 +13791,7 @@ function getApprovalHandler(accountId) {
|
|
|
13469
13791
|
// src/features/proactive.ts
|
|
13470
13792
|
var fs19 = __toESM(require("fs"), 1);
|
|
13471
13793
|
var path20 = __toESM(require("path"), 1);
|
|
13794
|
+
init_config();
|
|
13472
13795
|
var log2 = createPluginLogger({ prefix: "[proactive]" });
|
|
13473
13796
|
var STORAGE_DIR = getQQBotDataDir("data");
|
|
13474
13797
|
var KNOWN_USERS_FILE = path20.join(STORAGE_DIR, "known-users.json");
|
|
@@ -13575,6 +13898,8 @@ function getCachedMsgId(scope, targetId) {
|
|
|
13575
13898
|
}
|
|
13576
13899
|
|
|
13577
13900
|
// src/gateway/event-handlers.ts
|
|
13901
|
+
init_resolve();
|
|
13902
|
+
init_config();
|
|
13578
13903
|
async function handleMessage(ctx, msg, account, runtime2, log4) {
|
|
13579
13904
|
const hlog = log4.child("handle");
|
|
13580
13905
|
const scope = msg.replyTarget.scope;
|
|
@@ -14419,10 +14744,6 @@ var approvalStubs = {
|
|
|
14419
14744
|
buildPendingPayload: () => null,
|
|
14420
14745
|
buildResolvedPayload: () => null
|
|
14421
14746
|
},
|
|
14422
|
-
auth: {
|
|
14423
|
-
authorizeActorAction: () => ({ authorized: true }),
|
|
14424
|
-
getActionAvailabilityState: () => ({ kind: "enabled" })
|
|
14425
|
-
},
|
|
14426
14747
|
approvals: {
|
|
14427
14748
|
delivery: {
|
|
14428
14749
|
hasConfiguredDmRoute: () => true,
|
|
@@ -14436,6 +14757,7 @@ var approvalStubs = {
|
|
|
14436
14757
|
};
|
|
14437
14758
|
|
|
14438
14759
|
// src/features/onboarding.ts
|
|
14760
|
+
init_config();
|
|
14439
14761
|
var qqbotOnboardingAdapter = {
|
|
14440
14762
|
getStatus: (ctx) => {
|
|
14441
14763
|
const cfg = ctx.config;
|
|
@@ -14455,25 +14777,6 @@ var qqbotOnboardingAdapter = {
|
|
|
14455
14777
|
}
|
|
14456
14778
|
};
|
|
14457
14779
|
|
|
14458
|
-
// src/utils/mention.ts
|
|
14459
|
-
function stripMentionText(text, mentions) {
|
|
14460
|
-
if (!text || !mentions?.length) return text;
|
|
14461
|
-
let cleaned = text;
|
|
14462
|
-
for (const m3 of mentions) {
|
|
14463
|
-
const openid = m3.member_openid ?? m3.id ?? m3.user_openid;
|
|
14464
|
-
if (!openid) continue;
|
|
14465
|
-
if (m3.is_you) {
|
|
14466
|
-
cleaned = cleaned.replace(new RegExp(`<@!?${openid}>`, "g"), "").trim();
|
|
14467
|
-
} else {
|
|
14468
|
-
const displayName = m3.nickname ?? m3.username;
|
|
14469
|
-
if (displayName) {
|
|
14470
|
-
cleaned = cleaned.replace(new RegExp(`<@!?${openid}>`, "g"), `@${displayName}`);
|
|
14471
|
-
}
|
|
14472
|
-
}
|
|
14473
|
-
}
|
|
14474
|
-
return cleaned;
|
|
14475
|
-
}
|
|
14476
|
-
|
|
14477
14780
|
// src/channel.ts
|
|
14478
14781
|
var TEXT_CHUNK_LIMIT2 = 5e3;
|
|
14479
14782
|
var GFM_TABLE_DATA_RE = /^\|.+\|.*\|/;
|
|
@@ -14498,6 +14801,7 @@ var qqbotPlugin = {
|
|
|
14498
14801
|
threads: false,
|
|
14499
14802
|
blockStreaming: false
|
|
14500
14803
|
},
|
|
14804
|
+
gatewayMethods: ["web.login.start", "web.login.wait"],
|
|
14501
14805
|
reload: { configPrefixes: ["channels.qqbot"] },
|
|
14502
14806
|
// ── 群消息策略 ──
|
|
14503
14807
|
groups: {
|
|
@@ -14676,7 +14980,19 @@ ${line}` : line;
|
|
|
14676
14980
|
log: ctx.log
|
|
14677
14981
|
});
|
|
14678
14982
|
},
|
|
14679
|
-
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" })
|
|
14680
14996
|
},
|
|
14681
14997
|
// ── 状态 ──
|
|
14682
14998
|
status: {
|
|
@@ -14740,6 +15056,7 @@ function createOutLog(accountId) {
|
|
|
14740
15056
|
}
|
|
14741
15057
|
|
|
14742
15058
|
// src/tools/platform.ts
|
|
15059
|
+
init_config();
|
|
14743
15060
|
var PlatformApiSchema = {
|
|
14744
15061
|
type: "object",
|
|
14745
15062
|
properties: {
|
|
@@ -15049,7 +15366,7 @@ function registerRemindTool(api) {
|
|
|
15049
15366
|
}
|
|
15050
15367
|
|
|
15051
15368
|
// src/adapter/contract.ts
|
|
15052
|
-
var log3 = createPluginLogger({ prefix: "[contract]", forceConsole:
|
|
15369
|
+
var log3 = createPluginLogger({ prefix: "[contract]", forceConsole: false });
|
|
15053
15370
|
var REQUIRED = [
|
|
15054
15371
|
{
|
|
15055
15372
|
name: "channel.reply.dispatchReplyWithBufferedBlockDispatcher",
|
|
@@ -15109,6 +15426,7 @@ var StreamContentType2 = {
|
|
|
15109
15426
|
};
|
|
15110
15427
|
|
|
15111
15428
|
// index.ts
|
|
15429
|
+
init_config();
|
|
15112
15430
|
var registered = false;
|
|
15113
15431
|
var plugin = {
|
|
15114
15432
|
id: "openclaw-qqbot",
|