@openclaw/qqbot 2026.5.12 → 2026.5.14-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api.js +6 -6
- package/dist/{channel-CmK-n3Oz.js → channel-BYNY5Nwb.js} +19 -34
- package/dist/channel-plugin-api.js +1 -1
- package/dist/{channel.setup-D_GS95Pk.js → channel.setup-DWWV_GAa.js} +2 -2
- package/dist/{resolve-D3lCbUze.js → config-DiBiPtf4.js} +100 -10
- package/dist/{config-schema-BCxobX3l.js → config-schema-BeJQUheK.js} +1 -2
- package/dist/{exec-approvals-W4oL9R6C.js → exec-approvals-Deww_EGt.js} +102 -2
- package/dist/{gateway-Bbsd8-ne.js → gateway-DEJhmN-p.js} +101 -33
- package/dist/{handler-runtime-ZgvjnyoH.js → handler-runtime-COWL4RMq.js} +3 -5
- package/dist/{outbound-BLWish89.js → outbound-BdQEr78b.js} +11 -3
- package/dist/{request-context-BwSBFANU.js → request-context-Betw4nJr.js} +2 -2
- package/dist/{runtime-CZyFkpnB.js → runtime-B-cqLImu.js} +1 -1
- package/dist/runtime-api.js +1 -1
- package/dist/{sender-BrpzCcXA.js → sender-BeE_CBbN.js} +10 -5
- package/dist/setup-plugin-api.js +1 -1
- package/dist/{target-parser-C8HaD-ik.js → target-parser-ByU3srDK.js} +1 -1
- package/package.json +4 -4
- package/dist/approval-cg0SVahb.js +0 -94
- package/dist/config-BT8KP_H1.js +0 -94
- /package/dist/{narrowing-BoieBTIU.js → narrowing-Bj4eMufj.js} +0 -0
package/dist/api.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { C as recordMessageReply, E as setOutboundAudioPort, S as getMessageReplyStats, T as OUTBOUND_ERROR_CODES, _ as sendVoice, a as sendText, b as checkMessageReplyLimit, d as buildMediaTarget, f as parseTarget, g as sendVideoMsg, h as sendPhoto, i as sendProactiveMessage, m as sendDocument, n as sendCronMessage, p as resolveOutboundMediaPath, r as sendMedia, v as resolveUserFacingMediaError, w as DEFAULT_MEDIA_SEND_ERROR, x as getMessageReplyConfig, y as MESSAGE_REPLY_LIMIT } from "./outbound-
|
|
2
|
-
import { a as resolveQQBotAccount, i as resolveDefaultQQBotAccountId, n as applyQQBotAccountConfig, r as listQQBotAccountIds, t as DEFAULT_ACCOUNT_ID } from "./config-
|
|
3
|
-
import { t as qqbotPlugin } from "./channel-
|
|
4
|
-
import { L as formatErrorMessage, S as debugLog, o as getAccessToken, x as debugError } from "./sender-
|
|
5
|
-
import { t as qqbotSetupPlugin } from "./channel.setup-
|
|
6
|
-
import { r as getFrameworkCommands, t as getRequestContext } from "./request-context-
|
|
1
|
+
import { C as recordMessageReply, E as setOutboundAudioPort, S as getMessageReplyStats, T as OUTBOUND_ERROR_CODES, _ as sendVoice, a as sendText, b as checkMessageReplyLimit, d as buildMediaTarget, f as parseTarget, g as sendVideoMsg, h as sendPhoto, i as sendProactiveMessage, m as sendDocument, n as sendCronMessage, p as resolveOutboundMediaPath, r as sendMedia, v as resolveUserFacingMediaError, w as DEFAULT_MEDIA_SEND_ERROR, x as getMessageReplyConfig, y as MESSAGE_REPLY_LIMIT } from "./outbound-BdQEr78b.js";
|
|
2
|
+
import { a as resolveQQBotAccount, i as resolveDefaultQQBotAccountId, n as applyQQBotAccountConfig, r as listQQBotAccountIds, t as DEFAULT_ACCOUNT_ID } from "./config-DiBiPtf4.js";
|
|
3
|
+
import { t as qqbotPlugin } from "./channel-BYNY5Nwb.js";
|
|
4
|
+
import { L as formatErrorMessage, S as debugLog, o as getAccessToken, x as debugError } from "./sender-BeE_CBbN.js";
|
|
5
|
+
import { t as qqbotSetupPlugin } from "./channel.setup-DWWV_GAa.js";
|
|
6
|
+
import { r as getFrameworkCommands, t as getRequestContext } from "./request-context-Betw4nJr.js";
|
|
7
7
|
import { callGatewayTool } from "openclaw/plugin-sdk/agent-harness-runtime";
|
|
8
8
|
//#region extensions/qqbot/src/engine/tools/channel-api.ts
|
|
9
9
|
/**
|
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
import { t as asOptionalObjectRecord } from "./string-normalize-C46CS-F1.js";
|
|
2
|
-
import {
|
|
3
|
-
import { a as resolveApprovalTarget } from "./
|
|
4
|
-
import { a as
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import { n as
|
|
8
|
-
import { t as getQQBotRuntime } from "./runtime-CZyFkpnB.js";
|
|
9
|
-
import { n as normalizeTarget, s as getQQBotDataPath, t as looksLikeQQBotTarget } from "./target-parser-C8HaD-ik.js";
|
|
2
|
+
import { a as resolveQQBotAccount, f as ensurePlatformAdapter, n as applyQQBotAccountConfig, p as getBridgeLogger, t as DEFAULT_ACCOUNT_ID$1 } from "./config-DiBiPtf4.js";
|
|
3
|
+
import { a as shouldHandleQQBotExecApprovalRequest, i as resolveQQBotExecApprovalConfig, n as isQQBotExecApprovalClientEnabled, r as matchesQQBotApprovalAccount, t as authorizeQQBotApprovalAction, u as resolveApprovalTarget } from "./exec-approvals-Deww_EGt.js";
|
|
4
|
+
import { a as qqbotSetupAdapterShared, i as qqbotMeta, n as qqbotSetupWizard, r as qqbotConfigAdapter, t as qqbotChannelConfigSchema } from "./config-schema-BeJQUheK.js";
|
|
5
|
+
import { n as writeOpenClawConfigThroughRuntime, t as toGatewayAccount } from "./narrowing-Bj4eMufj.js";
|
|
6
|
+
import { t as getQQBotRuntime } from "./runtime-B-cqLImu.js";
|
|
7
|
+
import { n as normalizeTarget, s as getQQBotDataPath, t as looksLikeQQBotTarget } from "./target-parser-ByU3srDK.js";
|
|
10
8
|
import { getExecApprovalReplyMetadata } from "openclaw/plugin-sdk/approval-runtime";
|
|
11
9
|
import { createMessageReceiptFromOutboundResults, defineChannelMessageAdapter } from "openclaw/plugin-sdk/channel-message";
|
|
12
10
|
import { createChannelApprovalCapability } from "openclaw/plugin-sdk/approval-delivery-runtime";
|
|
@@ -21,10 +19,9 @@ import { loadJsonFile } from "openclaw/plugin-sdk/json-store";
|
|
|
21
19
|
/**
|
|
22
20
|
* QQ Bot Approval Capability — entry point.
|
|
23
21
|
*
|
|
24
|
-
* QQBot uses a simpler approval model than Telegram/Slack:
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
* originating conversation and whoever clicks the button resolves it.
|
|
22
|
+
* QQBot uses a simpler approval model than Telegram/Slack: when no
|
|
23
|
+
* approver list is configured, the bot sends the approval message to the
|
|
24
|
+
* originating conversation and any participant can approve from there.
|
|
28
25
|
*
|
|
29
26
|
* When `execApprovals` IS configured, it gates which requests are
|
|
30
27
|
* handled natively and who is authorized. When it is NOT configured,
|
|
@@ -65,24 +62,12 @@ function canResolveTarget(request) {
|
|
|
65
62
|
}
|
|
66
63
|
function createQQBotApprovalCapability() {
|
|
67
64
|
return createChannelApprovalCapability({
|
|
68
|
-
authorizeActorAction: ({ cfg, accountId, senderId, approvalKind }) => {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
accountId,
|
|
75
|
-
senderId
|
|
76
|
-
}) : isQQBotExecApprovalAuthorizedSender({
|
|
77
|
-
cfg,
|
|
78
|
-
accountId,
|
|
79
|
-
senderId
|
|
80
|
-
})) ? { authorized: true } : {
|
|
81
|
-
authorized: false,
|
|
82
|
-
reason: "You are not authorized to approve this request."
|
|
83
|
-
};
|
|
84
|
-
return { authorized: true };
|
|
85
|
-
},
|
|
65
|
+
authorizeActorAction: ({ cfg, accountId, senderId, approvalKind }) => authorizeQQBotApprovalAction({
|
|
66
|
+
cfg,
|
|
67
|
+
accountId,
|
|
68
|
+
senderId,
|
|
69
|
+
approvalKind
|
|
70
|
+
}),
|
|
86
71
|
getActionAvailabilityState: ({ cfg, accountId }) => {
|
|
87
72
|
return isNativeDeliveryEnabled({
|
|
88
73
|
cfg,
|
|
@@ -156,7 +141,7 @@ function createQQBotApprovalCapability() {
|
|
|
156
141
|
},
|
|
157
142
|
load: async () => {
|
|
158
143
|
ensurePlatformAdapter();
|
|
159
|
-
return (await import("./handler-runtime-
|
|
144
|
+
return (await import("./handler-runtime-COWL4RMq.js")).qqbotApprovalNativeRuntime;
|
|
160
145
|
}
|
|
161
146
|
})
|
|
162
147
|
});
|
|
@@ -345,7 +330,7 @@ function clearAccountCredentials(cfg, accountId) {
|
|
|
345
330
|
//#region extensions/qqbot/src/channel.ts
|
|
346
331
|
let gatewayModulePromise;
|
|
347
332
|
function loadGatewayModule() {
|
|
348
|
-
gatewayModulePromise ??= import("./gateway-
|
|
333
|
+
gatewayModulePromise ??= import("./gateway-DEJhmN-p.js");
|
|
349
334
|
return gatewayModulePromise;
|
|
350
335
|
}
|
|
351
336
|
function createQQBotSendReceipt(params) {
|
|
@@ -363,7 +348,7 @@ function createQQBotSendReceipt(params) {
|
|
|
363
348
|
async function sendQQBotText(params) {
|
|
364
349
|
await loadGatewayModule();
|
|
365
350
|
const account = resolveQQBotAccount(params.cfg, params.accountId);
|
|
366
|
-
const { sendText } = await import("./outbound-
|
|
351
|
+
const { sendText } = await import("./outbound-BdQEr78b.js").then((n) => n.t);
|
|
367
352
|
const result = await sendText({
|
|
368
353
|
to: params.to,
|
|
369
354
|
text: params.text,
|
|
@@ -385,7 +370,7 @@ async function sendQQBotText(params) {
|
|
|
385
370
|
async function sendQQBotMedia(params) {
|
|
386
371
|
await loadGatewayModule();
|
|
387
372
|
const account = resolveQQBotAccount(params.cfg, params.accountId);
|
|
388
|
-
const { sendMedia } = await import("./outbound-
|
|
373
|
+
const { sendMedia } = await import("./outbound-BdQEr78b.js").then((n) => n.t);
|
|
389
374
|
const result = await sendMedia({
|
|
390
375
|
to: params.to,
|
|
391
376
|
text: params.text ?? "",
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as qqbotPlugin } from "./channel-
|
|
1
|
+
import { t as qqbotPlugin } from "./channel-BYNY5Nwb.js";
|
|
2
2
|
export { qqbotPlugin };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import "./
|
|
2
|
-
import { a as qqbotSetupAdapterShared, i as qqbotMeta, n as qqbotSetupWizard, r as qqbotConfigAdapter, t as qqbotChannelConfigSchema } from "./config-schema-
|
|
1
|
+
import "./config-DiBiPtf4.js";
|
|
2
|
+
import { a as qqbotSetupAdapterShared, i as qqbotMeta, n as qqbotSetupWizard, r as qqbotConfigAdapter, t as qqbotChannelConfigSchema } from "./config-schema-BeJQUheK.js";
|
|
3
3
|
//#region extensions/qqbot/src/channel.setup.ts
|
|
4
4
|
/**
|
|
5
5
|
* Setup-only QQBot plugin — lightweight subset used during `openclaw onboard`
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { a as normalizeStringifiedOptionalString, c as getPlatformAdapter, d as registerPlatformAdapterFactory, l as hasPlatformAdapter, o as readStringField, r as normalizeOptionalLowercaseString, t as asOptionalObjectRecord, u as registerPlatformAdapter } from "./string-normalize-C46CS-F1.js";
|
|
2
|
-
import { hasConfiguredSecretInput, normalizeResolvedSecretInputString, normalizeSecretInputString } from "openclaw/plugin-sdk/secret-input";
|
|
2
|
+
import { coerceSecretRef, hasConfiguredSecretInput, normalizeResolvedSecretInputString, normalizeSecretInputString } from "openclaw/plugin-sdk/secret-input";
|
|
3
3
|
import { resolvePreferredOpenClawTmpDir } from "openclaw/plugin-sdk/temp-path";
|
|
4
|
+
import fs from "node:fs";
|
|
5
|
+
import { resolveDefaultSecretProviderAlias } from "openclaw/plugin-sdk/provider-auth";
|
|
4
6
|
//#region extensions/qqbot/src/bridge/logger.ts
|
|
5
7
|
let _logger = null;
|
|
6
8
|
/** Register the framework logger. Called once in startGateway(). */
|
|
@@ -48,8 +50,8 @@ function createBuiltinAdapter() {
|
|
|
48
50
|
if (typeof value === "string") return value || void 0;
|
|
49
51
|
},
|
|
50
52
|
async downloadFile(url, destDir, filename) {
|
|
51
|
-
const {
|
|
52
|
-
const result = await
|
|
53
|
+
const { readRemoteMediaBuffer } = await import("openclaw/plugin-sdk/media-runtime");
|
|
54
|
+
const result = await readRemoteMediaBuffer({
|
|
53
55
|
url,
|
|
54
56
|
filePathHint: filename
|
|
55
57
|
});
|
|
@@ -61,8 +63,8 @@ function createBuiltinAdapter() {
|
|
|
61
63
|
return destPath;
|
|
62
64
|
},
|
|
63
65
|
async fetchMedia(options) {
|
|
64
|
-
const {
|
|
65
|
-
const result = await
|
|
66
|
+
const { readRemoteMediaBuffer } = await import("openclaw/plugin-sdk/media-runtime");
|
|
67
|
+
const result = await readRemoteMediaBuffer({
|
|
66
68
|
url: options.url,
|
|
67
69
|
filePathHint: options.filePathHint,
|
|
68
70
|
maxBytes: options.maxBytes,
|
|
@@ -131,7 +133,7 @@ ensurePlatformAdapter();
|
|
|
131
133
|
* Default account ID, used for the unnamed top-level account.
|
|
132
134
|
* 默认账号 ID,用于顶层配置中未命名的账号。
|
|
133
135
|
*/
|
|
134
|
-
const DEFAULT_ACCOUNT_ID = "default";
|
|
136
|
+
const DEFAULT_ACCOUNT_ID$1 = "default";
|
|
135
137
|
function normalizeAppId(raw) {
|
|
136
138
|
if (typeof raw === "string") return raw.trim();
|
|
137
139
|
if (typeof raw === "number") return String(raw);
|
|
@@ -155,7 +157,7 @@ function readQQBotSection(cfg) {
|
|
|
155
157
|
function listAccountIds(cfg) {
|
|
156
158
|
const ids = /* @__PURE__ */ new Set();
|
|
157
159
|
const qqbot = readQQBotSection(cfg);
|
|
158
|
-
if (qqbot?.appId || process.env.QQBOT_APP_ID) ids.add(DEFAULT_ACCOUNT_ID);
|
|
160
|
+
if (qqbot?.appId || process.env.QQBOT_APP_ID) ids.add(DEFAULT_ACCOUNT_ID$1);
|
|
159
161
|
if (qqbot?.accounts) {
|
|
160
162
|
for (const accountId of Object.keys(qqbot.accounts)) if (qqbot.accounts[accountId]?.appId) ids.add(accountId);
|
|
161
163
|
}
|
|
@@ -169,12 +171,12 @@ function resolveDefaultAccountId(cfg) {
|
|
|
169
171
|
const qqbot = readQQBotSection(cfg);
|
|
170
172
|
const configuredDefaultAccountId = normalizeOptionalLowercaseString(qqbot?.defaultAccount);
|
|
171
173
|
if (configuredDefaultAccountId && (configuredDefaultAccountId === "default" || Boolean(qqbot?.accounts?.[configuredDefaultAccountId]?.appId))) return configuredDefaultAccountId;
|
|
172
|
-
if (qqbot?.appId || process.env.QQBOT_APP_ID) return DEFAULT_ACCOUNT_ID;
|
|
174
|
+
if (qqbot?.appId || process.env.QQBOT_APP_ID) return DEFAULT_ACCOUNT_ID$1;
|
|
173
175
|
if (qqbot?.accounts) {
|
|
174
176
|
const ids = Object.keys(qqbot.accounts);
|
|
175
177
|
if (ids.length > 0) return ids[0];
|
|
176
178
|
}
|
|
177
|
-
return DEFAULT_ACCOUNT_ID;
|
|
179
|
+
return DEFAULT_ACCOUNT_ID$1;
|
|
178
180
|
}
|
|
179
181
|
/**
|
|
180
182
|
* Resolve base account info (without credentials).
|
|
@@ -281,4 +283,92 @@ function formatAllowFrom(allowFrom) {
|
|
|
281
283
|
return (allowFrom ?? []).map((entry) => normalizeStringifiedOptionalString(entry)).filter((entry) => Boolean(entry)).map((entry) => entry.replace(/^qqbot:/i, "")).map((entry) => entry.toUpperCase());
|
|
282
284
|
}
|
|
283
285
|
//#endregion
|
|
284
|
-
|
|
286
|
+
//#region extensions/qqbot/src/bridge/config.ts
|
|
287
|
+
const DEFAULT_ACCOUNT_ID = DEFAULT_ACCOUNT_ID$1;
|
|
288
|
+
function assertNotLegacySecretRefMarker(value, path) {
|
|
289
|
+
const normalized = normalizeSecretInputString(value);
|
|
290
|
+
if (!normalized || !/^secretref(?:-env)?:/i.test(normalized)) return;
|
|
291
|
+
throw new Error(`${path}: legacy SecretRef marker strings are not valid QQ Bot clientSecret values; use a structured SecretRef object instead.`);
|
|
292
|
+
}
|
|
293
|
+
function resolveEnvSecretRefValue(params) {
|
|
294
|
+
const ref = coerceSecretRef(params.value, params.cfg.secrets?.defaults);
|
|
295
|
+
if (!ref || ref.source !== "env") return;
|
|
296
|
+
const providerConfig = params.cfg.secrets?.providers?.[ref.provider];
|
|
297
|
+
if (providerConfig) {
|
|
298
|
+
if (providerConfig.source !== "env") throw new Error(`Secret provider "${ref.provider}" has source "${providerConfig.source}" but ref requests "env".`);
|
|
299
|
+
if (providerConfig.allowlist && !providerConfig.allowlist.includes(ref.id)) throw new Error(`Environment variable "${ref.id}" is not allowlisted in secrets.providers.${ref.provider}.allowlist.`);
|
|
300
|
+
} else if (ref.provider !== resolveDefaultSecretProviderAlias(params.cfg, "env")) throw new Error(`Secret provider "${ref.provider}" is not configured (ref: env:${ref.provider}:${ref.id}).`);
|
|
301
|
+
return normalizeSecretInputString((params.env ?? process.env)[ref.id]);
|
|
302
|
+
}
|
|
303
|
+
function resolveQQBotClientSecretInput(params) {
|
|
304
|
+
assertNotLegacySecretRefMarker(params.value, params.path);
|
|
305
|
+
const envSecret = resolveEnvSecretRefValue({
|
|
306
|
+
cfg: params.cfg,
|
|
307
|
+
value: params.value
|
|
308
|
+
});
|
|
309
|
+
if (envSecret) return envSecret;
|
|
310
|
+
return getPlatformAdapter().resolveSecretInputString({
|
|
311
|
+
value: params.value,
|
|
312
|
+
path: params.path
|
|
313
|
+
});
|
|
314
|
+
}
|
|
315
|
+
/** List all configured QQBot account IDs. */
|
|
316
|
+
function listQQBotAccountIds(cfg) {
|
|
317
|
+
return listAccountIds(cfg);
|
|
318
|
+
}
|
|
319
|
+
/** Resolve the default QQBot account ID. */
|
|
320
|
+
function resolveDefaultQQBotAccountId(cfg) {
|
|
321
|
+
return resolveDefaultAccountId(cfg);
|
|
322
|
+
}
|
|
323
|
+
/** Resolve QQBot account config for runtime or setup flows. */
|
|
324
|
+
function resolveQQBotAccount(cfg, accountId, opts) {
|
|
325
|
+
const base = resolveAccountBase(cfg, accountId);
|
|
326
|
+
const qqbot = cfg.channels?.qqbot;
|
|
327
|
+
/**
|
|
328
|
+
* Legacy top-level account uses `channels.qqbot` as the base, but per-account
|
|
329
|
+
* fields (allowFrom, streaming, …) often live under `accounts.default`.
|
|
330
|
+
* Merge that slice so runtime sees `config.streaming` etc.
|
|
331
|
+
*/
|
|
332
|
+
const accountConfig = base.accountId === DEFAULT_ACCOUNT_ID ? {
|
|
333
|
+
...qqbot,
|
|
334
|
+
...qqbot?.accounts?.[DEFAULT_ACCOUNT_ID]
|
|
335
|
+
} : qqbot?.accounts?.[base.accountId] ?? {};
|
|
336
|
+
let clientSecret = "";
|
|
337
|
+
let secretSource = "none";
|
|
338
|
+
const clientSecretPath = base.accountId === DEFAULT_ACCOUNT_ID ? "channels.qqbot.clientSecret" : `channels.qqbot.accounts.${base.accountId}.clientSecret`;
|
|
339
|
+
const adapter = getPlatformAdapter();
|
|
340
|
+
if (adapter.hasConfiguredSecret(accountConfig.clientSecret)) {
|
|
341
|
+
clientSecret = opts?.allowUnresolvedSecretRef ? adapter.normalizeSecretInputString(accountConfig.clientSecret) ?? "" : resolveQQBotClientSecretInput({
|
|
342
|
+
cfg,
|
|
343
|
+
value: accountConfig.clientSecret,
|
|
344
|
+
path: clientSecretPath
|
|
345
|
+
}) ?? "";
|
|
346
|
+
secretSource = "config";
|
|
347
|
+
} else if (accountConfig.clientSecretFile) try {
|
|
348
|
+
clientSecret = fs.readFileSync(accountConfig.clientSecretFile, "utf8").trim();
|
|
349
|
+
secretSource = "file";
|
|
350
|
+
} catch {
|
|
351
|
+
secretSource = "none";
|
|
352
|
+
}
|
|
353
|
+
else if (process.env.QQBOT_CLIENT_SECRET && base.accountId === DEFAULT_ACCOUNT_ID) {
|
|
354
|
+
clientSecret = process.env.QQBOT_CLIENT_SECRET;
|
|
355
|
+
secretSource = "env";
|
|
356
|
+
}
|
|
357
|
+
return {
|
|
358
|
+
accountId: base.accountId,
|
|
359
|
+
name: accountConfig.name,
|
|
360
|
+
enabled: base.enabled,
|
|
361
|
+
appId: base.appId,
|
|
362
|
+
clientSecret,
|
|
363
|
+
secretSource,
|
|
364
|
+
systemPrompt: base.systemPrompt,
|
|
365
|
+
markdownSupport: base.markdownSupport,
|
|
366
|
+
config: accountConfig
|
|
367
|
+
};
|
|
368
|
+
}
|
|
369
|
+
/** Apply account config updates back into the OpenClaw config object. */
|
|
370
|
+
function applyQQBotAccountConfig(cfg, accountId, input) {
|
|
371
|
+
return applyAccountConfig(cfg, accountId, input);
|
|
372
|
+
}
|
|
373
|
+
//#endregion
|
|
374
|
+
export { resolveQQBotAccount as a, describeAccount as c, resolveAccountBase as d, ensurePlatformAdapter as f, resolveDefaultQQBotAccountId as i, formatAllowFrom as l, setBridgeLogger as m, applyQQBotAccountConfig as n, DEFAULT_ACCOUNT_ID$1 as o, getBridgeLogger as p, listQQBotAccountIds as r, applyAccountConfig as s, DEFAULT_ACCOUNT_ID as t, isAccountConfigured as u };
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { n as normalizeLowercaseStringOrEmpty } from "./string-normalize-C46CS-F1.js";
|
|
2
|
-
import { a as
|
|
3
|
-
import { a as resolveQQBotAccount, i as resolveDefaultQQBotAccountId, n as applyQQBotAccountConfig, r as listQQBotAccountIds } from "./config-BT8KP_H1.js";
|
|
2
|
+
import { a as resolveQQBotAccount, c as describeAccount, i as resolveDefaultQQBotAccountId, l as formatAllowFrom, n as applyQQBotAccountConfig, r as listQQBotAccountIds, s as applyAccountConfig, u as isAccountConfigured } from "./config-DiBiPtf4.js";
|
|
4
3
|
import { buildSecretInputSchema } from "openclaw/plugin-sdk/secret-input";
|
|
5
4
|
import { applyAccountNameToChannelSection, deleteAccountFromConfigSection, setAccountEnabledInConfigSection } from "openclaw/plugin-sdk/core";
|
|
6
5
|
import { DEFAULT_ACCOUNT_ID, createStandardChannelSetupStatus, setSetupChannelEnabled } from "openclaw/plugin-sdk/setup";
|
|
@@ -1,9 +1,102 @@
|
|
|
1
|
-
import { a as resolveQQBotAccount, r as listQQBotAccountIds } from "./config-
|
|
1
|
+
import { a as resolveQQBotAccount, r as listQQBotAccountIds } from "./config-DiBiPtf4.js";
|
|
2
2
|
import { resolveApprovalRequestChannelAccountId } from "openclaw/plugin-sdk/approval-native-runtime";
|
|
3
3
|
import { normalizeLowercaseStringOrEmpty, normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
4
4
|
import { resolveApprovalApprovers } from "openclaw/plugin-sdk/approval-auth-runtime";
|
|
5
5
|
import { createChannelExecApprovalProfile, isChannelExecApprovalClientEnabledFromConfig, matchesApprovalRequestFilters } from "openclaw/plugin-sdk/approval-client-runtime";
|
|
6
6
|
import { normalizeAccountId } from "openclaw/plugin-sdk/routing";
|
|
7
|
+
//#region extensions/qqbot/src/engine/approval/index.ts
|
|
8
|
+
function buildExecApprovalText(request) {
|
|
9
|
+
const expiresIn = Math.max(0, Math.round((request.expiresAtMs - Date.now()) / 1e3));
|
|
10
|
+
const lines = ["🔐 命令执行审批", ""];
|
|
11
|
+
const cmd = request.request.commandPreview ?? request.request.command ?? "";
|
|
12
|
+
if (cmd) lines.push(`\`\`\`\n${cmd.slice(0, 300)}\n\`\`\``);
|
|
13
|
+
if (request.request.cwd) lines.push(`\u{1f4c1} \u76ee\u5f55: ${request.request.cwd}`);
|
|
14
|
+
if (request.request.agentId) lines.push(`\u{1f916} Agent: ${request.request.agentId}`);
|
|
15
|
+
lines.push("", `\u23f1\ufe0f \u8d85\u65f6: ${expiresIn} \u79d2`);
|
|
16
|
+
return lines.join("\n");
|
|
17
|
+
}
|
|
18
|
+
function buildPluginApprovalText(request) {
|
|
19
|
+
const timeoutSec = Math.round((request.request.timeoutMs ?? 12e4) / 1e3);
|
|
20
|
+
const lines = [`${request.request.severity === "critical" ? "🔴" : request.request.severity === "info" ? "🔵" : "🟡"} \u5ba1\u6279\u8bf7\u6c42`, ""];
|
|
21
|
+
lines.push(`\u{1f4cb} ${request.request.title}`);
|
|
22
|
+
if (request.request.description) lines.push(`\u{1f4dd} ${request.request.description}`);
|
|
23
|
+
if (request.request.toolName) lines.push(`\u{1f527} \u5de5\u5177: ${request.request.toolName}`);
|
|
24
|
+
if (request.request.pluginId) lines.push(`\u{1f50c} \u63d2\u4ef6: ${request.request.pluginId}`);
|
|
25
|
+
if (request.request.agentId) lines.push(`\u{1f916} Agent: ${request.request.agentId}`);
|
|
26
|
+
lines.push("", `\u23f1\ufe0f \u8d85\u65f6: ${timeoutSec} \u79d2`);
|
|
27
|
+
return lines.join("\n");
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Build the three-button inline keyboard for approval messages.
|
|
31
|
+
*
|
|
32
|
+
* type=1 (Callback): click triggers INTERACTION_CREATE, button_data = data field.
|
|
33
|
+
* group_id "approval": clicking one button grays out the others (mutual exclusion).
|
|
34
|
+
* click_limit=1: each user can only click once.
|
|
35
|
+
* permission.type=2: all users can interact.
|
|
36
|
+
*/
|
|
37
|
+
function buildApprovalKeyboard(approvalId, allowedDecisions = [
|
|
38
|
+
"allow-once",
|
|
39
|
+
"allow-always",
|
|
40
|
+
"deny"
|
|
41
|
+
]) {
|
|
42
|
+
const makeBtn = (id, label, visitedLabel, data, style) => ({
|
|
43
|
+
id,
|
|
44
|
+
render_data: {
|
|
45
|
+
label,
|
|
46
|
+
visited_label: visitedLabel,
|
|
47
|
+
style
|
|
48
|
+
},
|
|
49
|
+
action: {
|
|
50
|
+
type: 1,
|
|
51
|
+
data,
|
|
52
|
+
permission: { type: 2 },
|
|
53
|
+
click_limit: 1
|
|
54
|
+
},
|
|
55
|
+
group_id: "approval"
|
|
56
|
+
});
|
|
57
|
+
const buttons = [];
|
|
58
|
+
if (allowedDecisions.includes("allow-once")) buttons.push(makeBtn("allow", "✅ 允许一次", "已允许", `approve:${approvalId}:allow-once`, 1));
|
|
59
|
+
if (allowedDecisions.includes("allow-always")) buttons.push(makeBtn("always", "⭐ 始终允许", "已始终允许", `approve:${approvalId}:allow-always`, 1));
|
|
60
|
+
if (allowedDecisions.includes("deny")) buttons.push(makeBtn("deny", "❌ 拒绝", "已拒绝", `approve:${approvalId}:deny`, 0));
|
|
61
|
+
return { content: { rows: [{ buttons }] } };
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Extract the delivery target from a sessionKey or turnSourceTo string.
|
|
65
|
+
*
|
|
66
|
+
* Expected formats:
|
|
67
|
+
* agent:main:qqbot:direct:OPENID -> { type: "c2c", id: "OPENID" }
|
|
68
|
+
* agent:main:qqbot:c2c:OPENID -> { type: "c2c", id: "OPENID" }
|
|
69
|
+
* agent:main:qqbot:group:GROUPID -> { type: "group", id: "GROUPID" }
|
|
70
|
+
*
|
|
71
|
+
* Returns null if neither field matches the expected pattern.
|
|
72
|
+
*/
|
|
73
|
+
function resolveApprovalTarget(sessionKey, turnSourceTo) {
|
|
74
|
+
const sk = sessionKey ?? turnSourceTo;
|
|
75
|
+
if (!sk) return null;
|
|
76
|
+
const m = sk.match(/qqbot:(c2c|direct|group):([A-F0-9]+)/i);
|
|
77
|
+
if (!m) return null;
|
|
78
|
+
return {
|
|
79
|
+
type: m[1].toLowerCase() === "group" ? "group" : "c2c",
|
|
80
|
+
id: m[2]
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Parse the button_data string from an INTERACTION_CREATE event.
|
|
85
|
+
*
|
|
86
|
+
* Expected format: `approve:<approvalId>:<decision>`
|
|
87
|
+
* where approvalId may be prefixed with "exec:" or "plugin:".
|
|
88
|
+
*
|
|
89
|
+
* Returns null if the data does not match the approval button format.
|
|
90
|
+
*/
|
|
91
|
+
function parseApprovalButtonData(buttonData) {
|
|
92
|
+
const m = buttonData.match(/^approve:((?:(?:exec|plugin):)?[0-9a-f-]+):(allow-once|allow-always|deny)$/i);
|
|
93
|
+
if (!m) return null;
|
|
94
|
+
return {
|
|
95
|
+
approvalId: m[1],
|
|
96
|
+
decision: m[2]
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
//#endregion
|
|
7
100
|
//#region extensions/qqbot/src/exec-approvals.ts
|
|
8
101
|
function normalizeApproverId(value) {
|
|
9
102
|
return normalizeOptionalString(String(value)) || void 0;
|
|
@@ -134,5 +227,12 @@ const isQQBotExecApprovalClientEnabled = qqbotExecApprovalProfile.isClientEnable
|
|
|
134
227
|
const isQQBotExecApprovalApprover = qqbotExecApprovalProfile.isApprover;
|
|
135
228
|
const isQQBotExecApprovalAuthorizedSender = qqbotExecApprovalProfile.isAuthorizedSender;
|
|
136
229
|
const shouldHandleQQBotExecApprovalRequest = qqbotExecApprovalProfile.shouldHandleRequest;
|
|
230
|
+
function authorizeQQBotApprovalAction(params) {
|
|
231
|
+
if (resolveQQBotExecApprovalConfig(params) === void 0) return { authorized: true };
|
|
232
|
+
return (params.approvalKind === "plugin" ? isQQBotExecApprovalApprover(params) : isQQBotExecApprovalAuthorizedSender(params)) ? { authorized: true } : {
|
|
233
|
+
authorized: false,
|
|
234
|
+
reason: "You are not authorized to approve this request."
|
|
235
|
+
};
|
|
236
|
+
}
|
|
137
237
|
//#endregion
|
|
138
|
-
export {
|
|
238
|
+
export { shouldHandleQQBotExecApprovalRequest as a, buildPluginApprovalText as c, resolveQQBotExecApprovalConfig as i, parseApprovalButtonData as l, isQQBotExecApprovalClientEnabled as n, buildApprovalKeyboard as o, matchesQQBotApprovalAccount as r, buildExecApprovalText as s, authorizeQQBotApprovalAction as t, resolveApprovalTarget as u };
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import { E as setOutboundAudioPort, _ as sendVoice, c as isMediaPayload, g as sendVideoMsg, h as sendPhoto, l as parseQQBotPayload, m as sendDocument, o as encodePayloadForCron, r as sendMedia, s as isCronReminderPayload, u as normalizeMediaTags, v as resolveUserFacingMediaError, w as DEFAULT_MEDIA_SEND_ERROR } from "./outbound-
|
|
1
|
+
import { E as setOutboundAudioPort, _ as sendVoice, c as isMediaPayload, g as sendVideoMsg, h as sendPhoto, l as parseQQBotPayload, m as sendDocument, o as encodePayloadForCron, r as sendMedia, s as isCronReminderPayload, u as normalizeMediaTags, v as resolveUserFacingMediaError, w as DEFAULT_MEDIA_SEND_ERROR } from "./outbound-BdQEr78b.js";
|
|
2
2
|
import { c as getPlatformAdapter, i as normalizeOptionalString, n as normalizeLowercaseStringOrEmpty, o as readStringField, s as sanitizeFileName, t as asOptionalObjectRecord } from "./string-normalize-C46CS-F1.js";
|
|
3
|
-
import { d as
|
|
4
|
-
import {
|
|
5
|
-
import { t as toGatewayAccount } from "./narrowing-
|
|
6
|
-
import { B as StreamInputState, C as debugWarn, D as openLocalFile, I as formatDuration, L as formatErrorMessage, N as getImageMimeType, P as getMaxUploadSize, R as StreamContentType, S as debugLog, T as getNextMsgSeq, a as createRawInputNotifyFn, b as withTokenRetry, c as getMessageApi, d as initSender, f as onMessageSent, g as sendText, h as sendMedia$1, i as clearTokenCache, j as formatFileSize, k as downloadFile, l as getPluginUserAgent, m as sendInputNotify, n as acknowledgeInteraction, o as getAccessToken, p as registerAccount, r as buildDeliveryTarget, s as getGatewayUrl, t as accountToCreds, u as initApiConfig, v as startBackgroundTokenRefresh, x as debugError, y as stopBackgroundTokenRefresh, z as StreamInputMode } from "./sender-
|
|
7
|
-
import { n as getQQBotRuntimeForEngine, t as getQQBotRuntime } from "./runtime-
|
|
8
|
-
import { a as getHomeDir, c as getQQBotMediaDir, d as isLocalPath, f as isWindows, i as checkSilkWasmAvailable, m as resolveQQBotPayloadLocalFilePath, o as getQQBotDataDir, p as normalizePath$1, s as getQQBotDataPath, u as getTempDir } from "./target-parser-
|
|
9
|
-
import { a as getPluginVersion, i as getFrameworkVersion, n as runWithRequestContext, o as initCommands, s as matchSlashCommand } from "./request-context-
|
|
3
|
+
import { d as resolveAccountBase, f as ensurePlatformAdapter, m as setBridgeLogger } from "./config-DiBiPtf4.js";
|
|
4
|
+
import { l as parseApprovalButtonData, t as authorizeQQBotApprovalAction } from "./exec-approvals-Deww_EGt.js";
|
|
5
|
+
import { t as toGatewayAccount } from "./narrowing-Bj4eMufj.js";
|
|
6
|
+
import { B as StreamInputState, C as debugWarn, D as openLocalFile, I as formatDuration, L as formatErrorMessage, N as getImageMimeType, P as getMaxUploadSize, R as StreamContentType, S as debugLog, T as getNextMsgSeq, a as createRawInputNotifyFn, b as withTokenRetry, c as getMessageApi, d as initSender, f as onMessageSent, g as sendText, h as sendMedia$1, i as clearTokenCache, j as formatFileSize, k as downloadFile, l as getPluginUserAgent, m as sendInputNotify, n as acknowledgeInteraction, o as getAccessToken, p as registerAccount, r as buildDeliveryTarget, s as getGatewayUrl, t as accountToCreds, u as initApiConfig, v as startBackgroundTokenRefresh, x as debugError, y as stopBackgroundTokenRefresh, z as StreamInputMode } from "./sender-BeE_CBbN.js";
|
|
7
|
+
import { n as getQQBotRuntimeForEngine, t as getQQBotRuntime } from "./runtime-B-cqLImu.js";
|
|
8
|
+
import { a as getHomeDir, c as getQQBotMediaDir, d as isLocalPath, f as isWindows, i as checkSilkWasmAvailable, m as resolveQQBotPayloadLocalFilePath, o as getQQBotDataDir, p as normalizePath$1, s as getQQBotDataPath, u as getTempDir } from "./target-parser-ByU3srDK.js";
|
|
9
|
+
import { a as getPluginVersion, i as getFrameworkVersion, n as runWithRequestContext, o as initCommands, s as matchSlashCommand } from "./request-context-Betw4nJr.js";
|
|
10
10
|
import * as fs$1 from "node:fs";
|
|
11
11
|
import fs from "node:fs";
|
|
12
12
|
import * as os$1 from "node:os";
|
|
@@ -3026,18 +3026,6 @@ function resolveQQBotEffectivePolicies(input) {
|
|
|
3026
3026
|
//#endregion
|
|
3027
3027
|
//#region extensions/qqbot/src/engine/gateway/interaction-handler.ts
|
|
3028
3028
|
/**
|
|
3029
|
-
* INTERACTION_CREATE event handler.
|
|
3030
|
-
*
|
|
3031
|
-
* Handles three interaction branches:
|
|
3032
|
-
*
|
|
3033
|
-
* 1. **Config query** (type=2001) — reads config, ACKs with `claw_cfg`.
|
|
3034
|
-
* 2. **Config update** (type=2002) — writes config, ACKs with updated snapshot.
|
|
3035
|
-
* 3. **Approval button** (other) — ACKs, resolves approval via PlatformAdapter.
|
|
3036
|
-
*
|
|
3037
|
-
* Config query/update require `runtime.config`. When unavailable, those
|
|
3038
|
-
* branches fall through to a bare ACK (backward-compatible).
|
|
3039
|
-
*/
|
|
3040
|
-
/**
|
|
3041
3029
|
* Build the canonical `claw_cfg` snapshot returned in interaction ACKs.
|
|
3042
3030
|
*
|
|
3043
3031
|
* Pure function — all resolution helpers live in engine/config/.
|
|
@@ -3123,7 +3111,7 @@ function applyRequireMentionUpdate(cfg, accountId, groupOpenid, update) {
|
|
|
3123
3111
|
* Returns a fire-and-forget callback that `GatewayConnection` calls
|
|
3124
3112
|
* on every `action: "interaction"` dispatch result.
|
|
3125
3113
|
*/
|
|
3126
|
-
function createInteractionHandler(account, runtime, log) {
|
|
3114
|
+
function createInteractionHandler(account, runtime, log, options) {
|
|
3127
3115
|
return (event) => {
|
|
3128
3116
|
const creds = accountToCreds(account);
|
|
3129
3117
|
const type = event.data?.type;
|
|
@@ -3137,22 +3125,102 @@ function createInteractionHandler(account, runtime, log) {
|
|
|
3137
3125
|
handleWithAck(creds, event, log, "CONFIG_UPDATE", () => applyConfigUpdate(event, account.accountId, runtime, log));
|
|
3138
3126
|
return;
|
|
3139
3127
|
}
|
|
3140
|
-
acknowledgeInteraction(creds, event.id).catch((err) => {
|
|
3141
|
-
log?.error(`Interaction ACK failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
3142
|
-
});
|
|
3143
3128
|
const parsed = parseApprovalButtonData(event.data?.resolved?.button_data ?? "");
|
|
3144
|
-
if (!parsed)
|
|
3145
|
-
|
|
3146
|
-
|
|
3147
|
-
|
|
3129
|
+
if (!parsed) {
|
|
3130
|
+
acknowledgeInteraction(creds, event.id).catch((err) => {
|
|
3131
|
+
log?.error(`Interaction ACK failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
3132
|
+
});
|
|
3148
3133
|
return;
|
|
3149
3134
|
}
|
|
3150
|
-
|
|
3151
|
-
|
|
3152
|
-
|
|
3135
|
+
handleApprovalButtonInteraction({
|
|
3136
|
+
accountId: account.accountId,
|
|
3137
|
+
creds,
|
|
3138
|
+
event,
|
|
3139
|
+
getActiveCfg: options?.getActiveCfg ?? runtime.config?.current,
|
|
3140
|
+
log,
|
|
3141
|
+
parsed
|
|
3153
3142
|
});
|
|
3154
3143
|
};
|
|
3155
3144
|
}
|
|
3145
|
+
async function handleApprovalButtonInteraction(params) {
|
|
3146
|
+
if (!params.getActiveCfg) {
|
|
3147
|
+
await acknowledgeApprovalInteraction(params.creds, params.event, params.log, { content: "Approval is unavailable." });
|
|
3148
|
+
params.log?.error("Approval button rejected: active config is unavailable");
|
|
3149
|
+
return;
|
|
3150
|
+
}
|
|
3151
|
+
let cfg;
|
|
3152
|
+
try {
|
|
3153
|
+
cfg = params.getActiveCfg();
|
|
3154
|
+
} catch (err) {
|
|
3155
|
+
await acknowledgeApprovalInteraction(params.creds, params.event, params.log, { content: "Approval is unavailable." });
|
|
3156
|
+
params.log?.error(`Approval button rejected: active config failed to load: ${err instanceof Error ? err.message : String(err)}`);
|
|
3157
|
+
return;
|
|
3158
|
+
}
|
|
3159
|
+
const authorization = authorizeApprovalButtonActor({
|
|
3160
|
+
cfg,
|
|
3161
|
+
accountId: params.accountId,
|
|
3162
|
+
event: params.event,
|
|
3163
|
+
approvalKind: resolveApprovalKind(params.parsed.approvalId)
|
|
3164
|
+
});
|
|
3165
|
+
if (!authorization.authorized) {
|
|
3166
|
+
await acknowledgeApprovalInteraction(params.creds, params.event, params.log, { content: authorization.reason ?? "You are not authorized to approve this request." });
|
|
3167
|
+
params.log?.info(`Approval button rejected: id=${params.parsed.approvalId}`);
|
|
3168
|
+
return;
|
|
3169
|
+
}
|
|
3170
|
+
await acknowledgeApprovalInteraction(params.creds, params.event, params.log);
|
|
3171
|
+
const adapter = getPlatformAdapter();
|
|
3172
|
+
if (!adapter.resolveApproval) {
|
|
3173
|
+
params.log?.error("resolveApproval not available on PlatformAdapter");
|
|
3174
|
+
return;
|
|
3175
|
+
}
|
|
3176
|
+
try {
|
|
3177
|
+
if (await adapter.resolveApproval(params.parsed.approvalId, params.parsed.decision)) params.log?.info(`Approval resolved: id=${params.parsed.approvalId}, decision=${params.parsed.decision}`);
|
|
3178
|
+
else params.log?.error(`Approval resolve failed: id=${params.parsed.approvalId}`);
|
|
3179
|
+
} catch (err) {
|
|
3180
|
+
params.log?.error(`Approval resolve failed: id=${params.parsed.approvalId}: ${err instanceof Error ? err.message : String(err)}`);
|
|
3181
|
+
}
|
|
3182
|
+
}
|
|
3183
|
+
async function acknowledgeApprovalInteraction(creds, event, log, data) {
|
|
3184
|
+
try {
|
|
3185
|
+
await acknowledgeInteraction(creds, event.id, 0, data);
|
|
3186
|
+
} catch (err) {
|
|
3187
|
+
log?.error(`Interaction ACK failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
3188
|
+
}
|
|
3189
|
+
}
|
|
3190
|
+
function authorizeApprovalButtonActor(params) {
|
|
3191
|
+
const senderIds = resolveApprovalActorSenderIds(params.event);
|
|
3192
|
+
if (senderIds.length === 0) return authorizeQQBotApprovalAction({
|
|
3193
|
+
cfg: params.cfg,
|
|
3194
|
+
accountId: params.accountId,
|
|
3195
|
+
senderId: null,
|
|
3196
|
+
approvalKind: params.approvalKind
|
|
3197
|
+
});
|
|
3198
|
+
let denial;
|
|
3199
|
+
for (const senderId of senderIds) {
|
|
3200
|
+
const result = authorizeQQBotApprovalAction({
|
|
3201
|
+
cfg: params.cfg,
|
|
3202
|
+
accountId: params.accountId,
|
|
3203
|
+
senderId,
|
|
3204
|
+
approvalKind: params.approvalKind
|
|
3205
|
+
});
|
|
3206
|
+
if (result.authorized) return result;
|
|
3207
|
+
denial ??= result;
|
|
3208
|
+
}
|
|
3209
|
+
return denial ?? {
|
|
3210
|
+
authorized: false,
|
|
3211
|
+
reason: "You are not authorized to approve this request."
|
|
3212
|
+
};
|
|
3213
|
+
}
|
|
3214
|
+
function resolveApprovalActorSenderIds(event) {
|
|
3215
|
+
const ids = [event.group_member_openid, event.user_openid].flatMap((value) => {
|
|
3216
|
+
const normalized = typeof value === "string" ? value.trim() : "";
|
|
3217
|
+
return normalized ? [normalized] : [];
|
|
3218
|
+
});
|
|
3219
|
+
return Array.from(new Set(ids));
|
|
3220
|
+
}
|
|
3221
|
+
function resolveApprovalKind(approvalId) {
|
|
3222
|
+
return approvalId.toLowerCase().startsWith("plugin:") ? "plugin" : "exec";
|
|
3223
|
+
}
|
|
3156
3224
|
/** Execute an async handler, ACK with the result, and handle errors. */
|
|
3157
3225
|
async function handleWithAck(creds, event, log, label, handler) {
|
|
3158
3226
|
try {
|
|
@@ -3267,7 +3335,7 @@ const IMAGE_PROBE_SSRF_POLICY = {};
|
|
|
3267
3335
|
/**
|
|
3268
3336
|
* Fetch image dimensions from a public URL using only the first 64 KB.
|
|
3269
3337
|
*
|
|
3270
|
-
* Uses {@link
|
|
3338
|
+
* Uses {@link readRemoteMediaBuffer} with SSRF guard to block probes against
|
|
3271
3339
|
* private/reserved/loopback/link-local/metadata destinations.
|
|
3272
3340
|
*/
|
|
3273
3341
|
async function getImageSizeFromUrl(url, timeoutMs = 5e3) {
|
|
@@ -6069,7 +6137,7 @@ async function startGateway$1(ctx) {
|
|
|
6069
6137
|
});
|
|
6070
6138
|
}
|
|
6071
6139
|
};
|
|
6072
|
-
const handleInteraction = createInteractionHandler(account, ctx.runtime, log);
|
|
6140
|
+
const handleInteraction = createInteractionHandler(account, ctx.runtime, log, { getActiveCfg: () => activeCfgProvider.getActiveCfg() });
|
|
6073
6141
|
await new GatewayConnection({
|
|
6074
6142
|
account,
|
|
6075
6143
|
abortSignal: ctx.abortSignal,
|
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { a as
|
|
3
|
-
import {
|
|
4
|
-
import { a as resolveQQBotExecApprovalConfig, i as matchesQQBotApprovalAccount, o as shouldHandleQQBotExecApprovalRequest, r as isQQBotExecApprovalClientEnabled } from "./exec-approvals-W4oL9R6C.js";
|
|
5
|
-
import { c as getMessageApi, t as accountToCreds } from "./sender-BrpzCcXA.js";
|
|
1
|
+
import { a as resolveQQBotAccount, f as ensurePlatformAdapter, p as getBridgeLogger } from "./config-DiBiPtf4.js";
|
|
2
|
+
import { a as shouldHandleQQBotExecApprovalRequest, c as buildPluginApprovalText, i as resolveQQBotExecApprovalConfig, n as isQQBotExecApprovalClientEnabled, o as buildApprovalKeyboard, r as matchesQQBotApprovalAccount, s as buildExecApprovalText, u as resolveApprovalTarget } from "./exec-approvals-Deww_EGt.js";
|
|
3
|
+
import { c as getMessageApi, t as accountToCreds } from "./sender-BeE_CBbN.js";
|
|
6
4
|
import { resolveApprovalRequestSessionConversation } from "openclaw/plugin-sdk/approval-native-runtime";
|
|
7
5
|
import { createChannelApprovalNativeRuntimeAdapter } from "openclaw/plugin-sdk/approval-handler-runtime";
|
|
8
6
|
//#region extensions/qqbot/src/bridge/approval/handler-runtime.ts
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { i as normalizeOptionalString, n as normalizeLowercaseStringOrEmpty, s as sanitizeFileName } from "./string-normalize-C46CS-F1.js";
|
|
2
|
-
import { A as fileExistsAsync, C as debugWarn, E as UPLOAD_PREPARE_FALLBACK_CODE, F as readFileAsync, L as formatErrorMessage, M as getFileTypeName, N as getImageMimeType, O as checkFileSize, P as getMaxUploadSize, S as debugLog, g as sendText$1, h as sendMedia$1, j as formatFileSize, k as downloadFile, t as accountToCreds, u as initApiConfig, w as UploadDailyLimitExceededError, x as debugError } from "./sender-
|
|
3
|
-
import { c as getQQBotMediaDir, d as isLocalPath, m as resolveQQBotPayloadLocalFilePath, o as getQQBotDataDir, p as normalizePath, r as parseTarget$1 } from "./target-parser-
|
|
2
|
+
import { A as fileExistsAsync, C as debugWarn, E as UPLOAD_PREPARE_FALLBACK_CODE, F as readFileAsync, L as formatErrorMessage, M as getFileTypeName, N as getImageMimeType, O as checkFileSize, P as getMaxUploadSize, S as debugLog, g as sendText$1, h as sendMedia$1, j as formatFileSize, k as downloadFile, t as accountToCreds, u as initApiConfig, w as UploadDailyLimitExceededError, x as debugError } from "./sender-BeE_CBbN.js";
|
|
3
|
+
import { c as getQQBotMediaDir, d as isLocalPath, m as resolveQQBotPayloadLocalFilePath, o as getQQBotDataDir, p as normalizePath, r as parseTarget$1 } from "./target-parser-ByU3srDK.js";
|
|
4
4
|
import { pathExistsSync, resolveLocalPathFromRootsSync } from "openclaw/plugin-sdk/security-runtime";
|
|
5
5
|
import path from "node:path";
|
|
6
6
|
import { getFileExtension } from "openclaw/plugin-sdk/media-mime";
|
|
@@ -878,6 +878,14 @@ const CRON_PREFIX = "QQBOT_CRON:";
|
|
|
878
878
|
function formatErr(e) {
|
|
879
879
|
return e instanceof Error ? e.message : String(e);
|
|
880
880
|
}
|
|
881
|
+
function normalizeBase64ForCompare(value) {
|
|
882
|
+
return value.replace(/=+$/u, "").replace(/-/gu, "+").replace(/_/gu, "/");
|
|
883
|
+
}
|
|
884
|
+
function decodeStrictBase64Utf8(value) {
|
|
885
|
+
const buffer = Buffer.from(value, "base64");
|
|
886
|
+
if (normalizeBase64ForCompare(buffer.toString("base64")) !== normalizeBase64ForCompare(value)) throw new Error("Cron payload body is not valid base64");
|
|
887
|
+
return buffer.toString("utf-8");
|
|
888
|
+
}
|
|
881
889
|
/** Parse model output that may start with the QQ Bot structured payload prefix. */
|
|
882
890
|
function parseQQBotPayload(text) {
|
|
883
891
|
const trimmedText = text.trim();
|
|
@@ -933,7 +941,7 @@ function decodeCronPayload(message) {
|
|
|
933
941
|
error: "Cron payload body is empty"
|
|
934
942
|
};
|
|
935
943
|
try {
|
|
936
|
-
const jsonString =
|
|
944
|
+
const jsonString = decodeStrictBase64Utf8(base64Content);
|
|
937
945
|
const payload = JSON.parse(jsonString);
|
|
938
946
|
if (payload.type !== "cron_reminder") return {
|
|
939
947
|
isCronPayload: true,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { S as debugLog } from "./sender-
|
|
2
|
-
import { a as getHomeDir, f as isWindows, l as getQQBotMediaPath, o as getQQBotDataDir } from "./target-parser-
|
|
1
|
+
import { S as debugLog } from "./sender-BeE_CBbN.js";
|
|
2
|
+
import { a as getHomeDir, f as isWindows, l as getQQBotMediaPath, o as getQQBotDataDir } from "./target-parser-ByU3srDK.js";
|
|
3
3
|
import fs from "node:fs";
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import { loadJsonFile } from "openclaw/plugin-sdk/json-store";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { _ as setOpenClawVersion } from "./sender-
|
|
1
|
+
import { _ as setOpenClawVersion } from "./sender-BeE_CBbN.js";
|
|
2
2
|
import { createPluginRuntimeStore } from "openclaw/plugin-sdk/runtime-store";
|
|
3
3
|
//#region extensions/qqbot/src/bridge/runtime.ts
|
|
4
4
|
const { setRuntime: _setRuntime, getRuntime: getQQBotRuntime } = createPluginRuntimeStore({
|
package/dist/runtime-api.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { r as setQQBotRuntime, t as getQQBotRuntime } from "./runtime-
|
|
1
|
+
import { r as setQQBotRuntime, t as getQQBotRuntime } from "./runtime-B-cqLImu.js";
|
|
2
2
|
export { getQQBotRuntime, setQQBotRuntime };
|
|
@@ -1386,14 +1386,19 @@ var TokenManager = class {
|
|
|
1386
1386
|
}
|
|
1387
1387
|
const traceId = response.headers.get("x-tps-trace-id") ?? "";
|
|
1388
1388
|
this.logger?.debug?.(`[qqbot:token:${appId}] <<< ${response.status}${traceId ? ` | TraceId: ${traceId}` : ""}`);
|
|
1389
|
+
let rawBody;
|
|
1390
|
+
try {
|
|
1391
|
+
rawBody = await response.text();
|
|
1392
|
+
} catch (err) {
|
|
1393
|
+
throw new Error(`Failed to read access_token response: ${formatErrorMessage(err)}`, { cause: err });
|
|
1394
|
+
}
|
|
1395
|
+
const logBody = rawBody.replace(/"access_token"\s*:\s*"[^"]+"/g, "\"access_token\": \"***\"");
|
|
1396
|
+
this.logger?.debug?.(`[qqbot:token:${appId}] <<< Body: ${logBody}`);
|
|
1389
1397
|
let data;
|
|
1390
1398
|
try {
|
|
1391
|
-
const rawBody = await response.text();
|
|
1392
|
-
const logBody = rawBody.replace(/"access_token"\s*:\s*"[^"]+"/g, "\"access_token\": \"***\"");
|
|
1393
|
-
this.logger?.debug?.(`[qqbot:token:${appId}] <<< Body: ${logBody}`);
|
|
1394
1399
|
data = JSON.parse(rawBody);
|
|
1395
|
-
} catch
|
|
1396
|
-
throw new Error(
|
|
1400
|
+
} catch {
|
|
1401
|
+
throw new Error("QQBot access_token response was malformed JSON");
|
|
1397
1402
|
}
|
|
1398
1403
|
if (!data.access_token) throw new Error(`Failed to get access_token: ${JSON.stringify(data)}`);
|
|
1399
1404
|
const expiresAt = Date.now() + (data.expires_in ?? 7200) * 1e3;
|
package/dist/setup-plugin-api.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as qqbotSetupPlugin } from "./channel.setup-
|
|
1
|
+
import { t as qqbotSetupPlugin } from "./channel.setup-DWWV_GAa.js";
|
|
2
2
|
export { qqbotSetupPlugin };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { c as getPlatformAdapter } from "./string-normalize-C46CS-F1.js";
|
|
2
|
-
import { C as debugWarn, L as formatErrorMessage, S as debugLog } from "./sender-
|
|
2
|
+
import { C as debugWarn, L as formatErrorMessage, S as debugLog } from "./sender-BeE_CBbN.js";
|
|
3
3
|
import * as fs$1 from "node:fs";
|
|
4
4
|
import * as os$1 from "node:os";
|
|
5
5
|
import * as path$1 from "node:path";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openclaw/qqbot",
|
|
3
|
-
"version": "2026.5.
|
|
3
|
+
"version": "2026.5.14-beta.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "OpenClaw QQ Bot channel plugin",
|
|
6
6
|
"repository": {
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"openclaw": "workspace:*"
|
|
22
22
|
},
|
|
23
23
|
"peerDependencies": {
|
|
24
|
-
"openclaw": ">=2026.5.
|
|
24
|
+
"openclaw": ">=2026.5.14-beta.1"
|
|
25
25
|
},
|
|
26
26
|
"peerDependenciesMeta": {
|
|
27
27
|
"openclaw": {
|
|
@@ -50,10 +50,10 @@
|
|
|
50
50
|
"minHostVersion": ">=2026.4.10"
|
|
51
51
|
},
|
|
52
52
|
"compat": {
|
|
53
|
-
"pluginApi": ">=2026.5.
|
|
53
|
+
"pluginApi": ">=2026.5.14-beta.1"
|
|
54
54
|
},
|
|
55
55
|
"build": {
|
|
56
|
-
"openclawVersion": "2026.5.
|
|
56
|
+
"openclawVersion": "2026.5.14-beta.1"
|
|
57
57
|
},
|
|
58
58
|
"release": {
|
|
59
59
|
"publishToClawHub": true,
|
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
//#region extensions/qqbot/src/engine/approval/index.ts
|
|
2
|
-
function buildExecApprovalText(request) {
|
|
3
|
-
const expiresIn = Math.max(0, Math.round((request.expiresAtMs - Date.now()) / 1e3));
|
|
4
|
-
const lines = ["🔐 命令执行审批", ""];
|
|
5
|
-
const cmd = request.request.commandPreview ?? request.request.command ?? "";
|
|
6
|
-
if (cmd) lines.push(`\`\`\`\n${cmd.slice(0, 300)}\n\`\`\``);
|
|
7
|
-
if (request.request.cwd) lines.push(`\u{1f4c1} \u76ee\u5f55: ${request.request.cwd}`);
|
|
8
|
-
if (request.request.agentId) lines.push(`\u{1f916} Agent: ${request.request.agentId}`);
|
|
9
|
-
lines.push("", `\u23f1\ufe0f \u8d85\u65f6: ${expiresIn} \u79d2`);
|
|
10
|
-
return lines.join("\n");
|
|
11
|
-
}
|
|
12
|
-
function buildPluginApprovalText(request) {
|
|
13
|
-
const timeoutSec = Math.round((request.request.timeoutMs ?? 12e4) / 1e3);
|
|
14
|
-
const lines = [`${request.request.severity === "critical" ? "🔴" : request.request.severity === "info" ? "🔵" : "🟡"} \u5ba1\u6279\u8bf7\u6c42`, ""];
|
|
15
|
-
lines.push(`\u{1f4cb} ${request.request.title}`);
|
|
16
|
-
if (request.request.description) lines.push(`\u{1f4dd} ${request.request.description}`);
|
|
17
|
-
if (request.request.toolName) lines.push(`\u{1f527} \u5de5\u5177: ${request.request.toolName}`);
|
|
18
|
-
if (request.request.pluginId) lines.push(`\u{1f50c} \u63d2\u4ef6: ${request.request.pluginId}`);
|
|
19
|
-
if (request.request.agentId) lines.push(`\u{1f916} Agent: ${request.request.agentId}`);
|
|
20
|
-
lines.push("", `\u23f1\ufe0f \u8d85\u65f6: ${timeoutSec} \u79d2`);
|
|
21
|
-
return lines.join("\n");
|
|
22
|
-
}
|
|
23
|
-
/**
|
|
24
|
-
* Build the three-button inline keyboard for approval messages.
|
|
25
|
-
*
|
|
26
|
-
* type=1 (Callback): click triggers INTERACTION_CREATE, button_data = data field.
|
|
27
|
-
* group_id "approval": clicking one button grays out the others (mutual exclusion).
|
|
28
|
-
* click_limit=1: each user can only click once.
|
|
29
|
-
* permission.type=2: all users can interact.
|
|
30
|
-
*/
|
|
31
|
-
function buildApprovalKeyboard(approvalId, allowedDecisions = [
|
|
32
|
-
"allow-once",
|
|
33
|
-
"allow-always",
|
|
34
|
-
"deny"
|
|
35
|
-
]) {
|
|
36
|
-
const makeBtn = (id, label, visitedLabel, data, style) => ({
|
|
37
|
-
id,
|
|
38
|
-
render_data: {
|
|
39
|
-
label,
|
|
40
|
-
visited_label: visitedLabel,
|
|
41
|
-
style
|
|
42
|
-
},
|
|
43
|
-
action: {
|
|
44
|
-
type: 1,
|
|
45
|
-
data,
|
|
46
|
-
permission: { type: 2 },
|
|
47
|
-
click_limit: 1
|
|
48
|
-
},
|
|
49
|
-
group_id: "approval"
|
|
50
|
-
});
|
|
51
|
-
const buttons = [];
|
|
52
|
-
if (allowedDecisions.includes("allow-once")) buttons.push(makeBtn("allow", "✅ 允许一次", "已允许", `approve:${approvalId}:allow-once`, 1));
|
|
53
|
-
if (allowedDecisions.includes("allow-always")) buttons.push(makeBtn("always", "⭐ 始终允许", "已始终允许", `approve:${approvalId}:allow-always`, 1));
|
|
54
|
-
if (allowedDecisions.includes("deny")) buttons.push(makeBtn("deny", "❌ 拒绝", "已拒绝", `approve:${approvalId}:deny`, 0));
|
|
55
|
-
return { content: { rows: [{ buttons }] } };
|
|
56
|
-
}
|
|
57
|
-
/**
|
|
58
|
-
* Extract the delivery target from a sessionKey or turnSourceTo string.
|
|
59
|
-
*
|
|
60
|
-
* Expected formats:
|
|
61
|
-
* agent:main:qqbot:direct:OPENID -> { type: "c2c", id: "OPENID" }
|
|
62
|
-
* agent:main:qqbot:c2c:OPENID -> { type: "c2c", id: "OPENID" }
|
|
63
|
-
* agent:main:qqbot:group:GROUPID -> { type: "group", id: "GROUPID" }
|
|
64
|
-
*
|
|
65
|
-
* Returns null if neither field matches the expected pattern.
|
|
66
|
-
*/
|
|
67
|
-
function resolveApprovalTarget(sessionKey, turnSourceTo) {
|
|
68
|
-
const sk = sessionKey ?? turnSourceTo;
|
|
69
|
-
if (!sk) return null;
|
|
70
|
-
const m = sk.match(/qqbot:(c2c|direct|group):([A-F0-9]+)/i);
|
|
71
|
-
if (!m) return null;
|
|
72
|
-
return {
|
|
73
|
-
type: m[1].toLowerCase() === "group" ? "group" : "c2c",
|
|
74
|
-
id: m[2]
|
|
75
|
-
};
|
|
76
|
-
}
|
|
77
|
-
/**
|
|
78
|
-
* Parse the button_data string from an INTERACTION_CREATE event.
|
|
79
|
-
*
|
|
80
|
-
* Expected format: `approve:<approvalId>:<decision>`
|
|
81
|
-
* where approvalId may be prefixed with "exec:" or "plugin:".
|
|
82
|
-
*
|
|
83
|
-
* Returns null if the data does not match the approval button format.
|
|
84
|
-
*/
|
|
85
|
-
function parseApprovalButtonData(buttonData) {
|
|
86
|
-
const m = buttonData.match(/^approve:((?:(?:exec|plugin):)?[0-9a-f-]+):(allow-once|allow-always|deny)$/i);
|
|
87
|
-
if (!m) return null;
|
|
88
|
-
return {
|
|
89
|
-
approvalId: m[1],
|
|
90
|
-
decision: m[2]
|
|
91
|
-
};
|
|
92
|
-
}
|
|
93
|
-
//#endregion
|
|
94
|
-
export { resolveApprovalTarget as a, parseApprovalButtonData as i, buildExecApprovalText as n, buildPluginApprovalText as r, buildApprovalKeyboard as t };
|
package/dist/config-BT8KP_H1.js
DELETED
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
import { c as getPlatformAdapter } from "./string-normalize-C46CS-F1.js";
|
|
2
|
-
import { c as resolveDefaultAccountId, n as applyAccountConfig, o as listAccountIds, s as resolveAccountBase, t as DEFAULT_ACCOUNT_ID$1 } from "./resolve-D3lCbUze.js";
|
|
3
|
-
import { coerceSecretRef, normalizeSecretInputString } from "openclaw/plugin-sdk/secret-input";
|
|
4
|
-
import fs from "node:fs";
|
|
5
|
-
import { resolveDefaultSecretProviderAlias } from "openclaw/plugin-sdk/provider-auth";
|
|
6
|
-
//#region extensions/qqbot/src/bridge/config.ts
|
|
7
|
-
const DEFAULT_ACCOUNT_ID = DEFAULT_ACCOUNT_ID$1;
|
|
8
|
-
function assertNotLegacySecretRefMarker(value, path) {
|
|
9
|
-
const normalized = normalizeSecretInputString(value);
|
|
10
|
-
if (!normalized || !/^secretref(?:-env)?:/i.test(normalized)) return;
|
|
11
|
-
throw new Error(`${path}: legacy SecretRef marker strings are not valid QQ Bot clientSecret values; use a structured SecretRef object instead.`);
|
|
12
|
-
}
|
|
13
|
-
function resolveEnvSecretRefValue(params) {
|
|
14
|
-
const ref = coerceSecretRef(params.value, params.cfg.secrets?.defaults);
|
|
15
|
-
if (!ref || ref.source !== "env") return;
|
|
16
|
-
const providerConfig = params.cfg.secrets?.providers?.[ref.provider];
|
|
17
|
-
if (providerConfig) {
|
|
18
|
-
if (providerConfig.source !== "env") throw new Error(`Secret provider "${ref.provider}" has source "${providerConfig.source}" but ref requests "env".`);
|
|
19
|
-
if (providerConfig.allowlist && !providerConfig.allowlist.includes(ref.id)) throw new Error(`Environment variable "${ref.id}" is not allowlisted in secrets.providers.${ref.provider}.allowlist.`);
|
|
20
|
-
} else if (ref.provider !== resolveDefaultSecretProviderAlias(params.cfg, "env")) throw new Error(`Secret provider "${ref.provider}" is not configured (ref: env:${ref.provider}:${ref.id}).`);
|
|
21
|
-
return normalizeSecretInputString((params.env ?? process.env)[ref.id]);
|
|
22
|
-
}
|
|
23
|
-
function resolveQQBotClientSecretInput(params) {
|
|
24
|
-
assertNotLegacySecretRefMarker(params.value, params.path);
|
|
25
|
-
const envSecret = resolveEnvSecretRefValue({
|
|
26
|
-
cfg: params.cfg,
|
|
27
|
-
value: params.value
|
|
28
|
-
});
|
|
29
|
-
if (envSecret) return envSecret;
|
|
30
|
-
return getPlatformAdapter().resolveSecretInputString({
|
|
31
|
-
value: params.value,
|
|
32
|
-
path: params.path
|
|
33
|
-
});
|
|
34
|
-
}
|
|
35
|
-
/** List all configured QQBot account IDs. */
|
|
36
|
-
function listQQBotAccountIds(cfg) {
|
|
37
|
-
return listAccountIds(cfg);
|
|
38
|
-
}
|
|
39
|
-
/** Resolve the default QQBot account ID. */
|
|
40
|
-
function resolveDefaultQQBotAccountId(cfg) {
|
|
41
|
-
return resolveDefaultAccountId(cfg);
|
|
42
|
-
}
|
|
43
|
-
/** Resolve QQBot account config for runtime or setup flows. */
|
|
44
|
-
function resolveQQBotAccount(cfg, accountId, opts) {
|
|
45
|
-
const base = resolveAccountBase(cfg, accountId);
|
|
46
|
-
const qqbot = cfg.channels?.qqbot;
|
|
47
|
-
/**
|
|
48
|
-
* Legacy top-level account uses `channels.qqbot` as the base, but per-account
|
|
49
|
-
* fields (allowFrom, streaming, …) often live under `accounts.default`.
|
|
50
|
-
* Merge that slice so runtime sees `config.streaming` etc.
|
|
51
|
-
*/
|
|
52
|
-
const accountConfig = base.accountId === DEFAULT_ACCOUNT_ID ? {
|
|
53
|
-
...qqbot,
|
|
54
|
-
...qqbot?.accounts?.[DEFAULT_ACCOUNT_ID]
|
|
55
|
-
} : qqbot?.accounts?.[base.accountId] ?? {};
|
|
56
|
-
let clientSecret = "";
|
|
57
|
-
let secretSource = "none";
|
|
58
|
-
const clientSecretPath = base.accountId === DEFAULT_ACCOUNT_ID ? "channels.qqbot.clientSecret" : `channels.qqbot.accounts.${base.accountId}.clientSecret`;
|
|
59
|
-
const adapter = getPlatformAdapter();
|
|
60
|
-
if (adapter.hasConfiguredSecret(accountConfig.clientSecret)) {
|
|
61
|
-
clientSecret = opts?.allowUnresolvedSecretRef ? adapter.normalizeSecretInputString(accountConfig.clientSecret) ?? "" : resolveQQBotClientSecretInput({
|
|
62
|
-
cfg,
|
|
63
|
-
value: accountConfig.clientSecret,
|
|
64
|
-
path: clientSecretPath
|
|
65
|
-
}) ?? "";
|
|
66
|
-
secretSource = "config";
|
|
67
|
-
} else if (accountConfig.clientSecretFile) try {
|
|
68
|
-
clientSecret = fs.readFileSync(accountConfig.clientSecretFile, "utf8").trim();
|
|
69
|
-
secretSource = "file";
|
|
70
|
-
} catch {
|
|
71
|
-
secretSource = "none";
|
|
72
|
-
}
|
|
73
|
-
else if (process.env.QQBOT_CLIENT_SECRET && base.accountId === DEFAULT_ACCOUNT_ID) {
|
|
74
|
-
clientSecret = process.env.QQBOT_CLIENT_SECRET;
|
|
75
|
-
secretSource = "env";
|
|
76
|
-
}
|
|
77
|
-
return {
|
|
78
|
-
accountId: base.accountId,
|
|
79
|
-
name: accountConfig.name,
|
|
80
|
-
enabled: base.enabled,
|
|
81
|
-
appId: base.appId,
|
|
82
|
-
clientSecret,
|
|
83
|
-
secretSource,
|
|
84
|
-
systemPrompt: base.systemPrompt,
|
|
85
|
-
markdownSupport: base.markdownSupport,
|
|
86
|
-
config: accountConfig
|
|
87
|
-
};
|
|
88
|
-
}
|
|
89
|
-
/** Apply account config updates back into the OpenClaw config object. */
|
|
90
|
-
function applyQQBotAccountConfig(cfg, accountId, input) {
|
|
91
|
-
return applyAccountConfig(cfg, accountId, input);
|
|
92
|
-
}
|
|
93
|
-
//#endregion
|
|
94
|
-
export { resolveQQBotAccount as a, resolveDefaultQQBotAccountId as i, applyQQBotAccountConfig as n, listQQBotAccountIds as r, DEFAULT_ACCOUNT_ID as t };
|
|
File without changes
|