@openclaw/qqbot 2026.6.5-beta.1 → 2026.6.5-beta.3
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 +7 -657
- package/dist/{channel-BLMrGYfg.js → channel-CcN43bPL.js} +32 -287
- package/dist/channel-entry-api.js +2 -0
- package/dist/channel-entry-fUBLXKPr.js +143 -0
- package/dist/channel-plugin-api.js +1 -1
- package/dist/{channel.setup-xBlmSU4X.js → channel.setup-CQ_DFfPx.js} +1 -1
- package/dist/config-ZEfgeoL4.js +257 -0
- package/dist/{config-schema-BI7AYP6Q.js → config-schema-BFLNZ8Nf.js} +17 -259
- package/dist/doctor-contract-BYTS8-ia.js +135 -0
- package/dist/doctor-contract-api.js +2 -0
- package/dist/{gateway-iL9SWAED.js → gateway-DdM2k3ss.js} +23 -26
- package/dist/{handler-runtime-CjXwuNlq.js → handler-runtime-JKYDlRdq.js} +4 -3
- package/dist/index.js +8 -1
- package/dist/log-SDfMMBWe.js +107 -0
- package/dist/{outbound-CEqyriPT.js → outbound-C9wV892v.js} +3 -14
- package/dist/request-context-Bm7PTBD1.js +43 -0
- package/dist/runtime-B9UoQ5NI.js +18 -0
- package/dist/runtime-api.js +1 -1
- package/dist/{runtime-BSgtMZ6G.js → sender-DIMG7jHz.js} +36 -123
- package/dist/setup-plugin-api.js +1 -1
- package/dist/{request-context-DsuA124s.js → slash-commands-impl-FRw-Dl44.js} +3 -45
- package/dist/target-parser-BdCUmxK7.js +285 -0
- package/dist/tools-2d9t-N1b.js +518 -0
- package/dist/tools-api.js +2 -0
- package/npm-shrinkwrap.json +3 -3
- package/openclaw.plugin.json +162 -0
- package/package.json +4 -4
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { asObjectRecord } from "openclaw/plugin-sdk/runtime-doctor";
|
|
2
|
+
//#region extensions/qqbot/src/doctor-contract.ts
|
|
3
|
+
const RESTRICTED_GROUP_TOOLS = { deny: [
|
|
4
|
+
"exec",
|
|
5
|
+
"read",
|
|
6
|
+
"write"
|
|
7
|
+
] };
|
|
8
|
+
function hasLegacyGroupToolPolicy(value) {
|
|
9
|
+
const groups = asObjectRecord(value);
|
|
10
|
+
if (!groups) return false;
|
|
11
|
+
return Object.values(groups).some((group) => asObjectRecord(group)?.toolPolicy !== void 0);
|
|
12
|
+
}
|
|
13
|
+
function hasLegacyAccountGroupToolPolicy(value) {
|
|
14
|
+
const accounts = asObjectRecord(value);
|
|
15
|
+
if (!accounts) return false;
|
|
16
|
+
return Object.values(accounts).some((account) => hasLegacyGroupToolPolicy(asObjectRecord(account)?.groups));
|
|
17
|
+
}
|
|
18
|
+
function migrateToolPolicy(value) {
|
|
19
|
+
if (value === "none") return { deny: ["*"] };
|
|
20
|
+
if (value === "full") return { allow: [] };
|
|
21
|
+
if (value === "restricted") return { ...RESTRICTED_GROUP_TOOLS };
|
|
22
|
+
}
|
|
23
|
+
function describeToolPolicy(value) {
|
|
24
|
+
return typeof value === "string" ? value : String(value);
|
|
25
|
+
}
|
|
26
|
+
function migrateGroups(params) {
|
|
27
|
+
let changed = false;
|
|
28
|
+
const nextGroups = { ...params.groups };
|
|
29
|
+
for (const [groupId, rawGroup] of Object.entries(params.groups)) {
|
|
30
|
+
const group = asObjectRecord(rawGroup);
|
|
31
|
+
if (!group || group.toolPolicy === void 0) continue;
|
|
32
|
+
const { toolPolicy, ...rest } = group;
|
|
33
|
+
const nextGroup = { ...rest };
|
|
34
|
+
const policy = migrateToolPolicy(toolPolicy);
|
|
35
|
+
const path = `${params.pathPrefix}.${groupId}`;
|
|
36
|
+
if (nextGroup.tools !== void 0) params.changes.push(`Removed ${path}.toolPolicy (${path}.tools already exists).`);
|
|
37
|
+
else if (policy) {
|
|
38
|
+
nextGroup.tools = policy;
|
|
39
|
+
params.changes.push(`Moved ${path}.toolPolicy=${describeToolPolicy(toolPolicy)} to ${path}.tools.`);
|
|
40
|
+
} else params.changes.push(`Removed unsupported ${path}.toolPolicy=${describeToolPolicy(toolPolicy)}.`);
|
|
41
|
+
nextGroups[groupId] = nextGroup;
|
|
42
|
+
changed = true;
|
|
43
|
+
}
|
|
44
|
+
return {
|
|
45
|
+
groups: nextGroups,
|
|
46
|
+
changed
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
const legacyConfigRules = [{
|
|
50
|
+
path: [
|
|
51
|
+
"channels",
|
|
52
|
+
"qqbot",
|
|
53
|
+
"groups"
|
|
54
|
+
],
|
|
55
|
+
message: "channels.qqbot.groups.<id>.toolPolicy is legacy and was ignored by QQBot group tool enforcement; use channels.qqbot.groups.<id>.tools instead. Run \"openclaw doctor --fix\".",
|
|
56
|
+
match: hasLegacyGroupToolPolicy
|
|
57
|
+
}, {
|
|
58
|
+
path: [
|
|
59
|
+
"channels",
|
|
60
|
+
"qqbot",
|
|
61
|
+
"accounts"
|
|
62
|
+
],
|
|
63
|
+
message: "channels.qqbot.accounts.<id>.groups.<groupId>.toolPolicy is legacy and was ignored by QQBot group tool enforcement; use channels.qqbot.accounts.<id>.groups.<groupId>.tools instead. Run \"openclaw doctor --fix\".",
|
|
64
|
+
match: hasLegacyAccountGroupToolPolicy
|
|
65
|
+
}];
|
|
66
|
+
function normalizeCompatibilityConfig({ cfg }) {
|
|
67
|
+
const rawEntry = asObjectRecord(cfg.channels?.qqbot);
|
|
68
|
+
if (!rawEntry) return {
|
|
69
|
+
config: cfg,
|
|
70
|
+
changes: []
|
|
71
|
+
};
|
|
72
|
+
const changes = [];
|
|
73
|
+
let updated = rawEntry;
|
|
74
|
+
let changed = false;
|
|
75
|
+
const groups = asObjectRecord(updated.groups);
|
|
76
|
+
if (groups) {
|
|
77
|
+
const migrated = migrateGroups({
|
|
78
|
+
groups,
|
|
79
|
+
pathPrefix: "channels.qqbot.groups",
|
|
80
|
+
changes
|
|
81
|
+
});
|
|
82
|
+
if (migrated.changed) {
|
|
83
|
+
updated = {
|
|
84
|
+
...updated,
|
|
85
|
+
groups: migrated.groups
|
|
86
|
+
};
|
|
87
|
+
changed = true;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
const accounts = asObjectRecord(updated.accounts);
|
|
91
|
+
if (accounts) {
|
|
92
|
+
let accountsChanged = false;
|
|
93
|
+
const nextAccounts = { ...accounts };
|
|
94
|
+
for (const [accountId, rawAccount] of Object.entries(accounts)) {
|
|
95
|
+
const account = asObjectRecord(rawAccount);
|
|
96
|
+
const accountGroups = asObjectRecord(account?.groups);
|
|
97
|
+
if (!account || !accountGroups) continue;
|
|
98
|
+
const migrated = migrateGroups({
|
|
99
|
+
groups: accountGroups,
|
|
100
|
+
pathPrefix: `channels.qqbot.accounts.${accountId}.groups`,
|
|
101
|
+
changes
|
|
102
|
+
});
|
|
103
|
+
if (migrated.changed) {
|
|
104
|
+
nextAccounts[accountId] = {
|
|
105
|
+
...account,
|
|
106
|
+
groups: migrated.groups
|
|
107
|
+
};
|
|
108
|
+
accountsChanged = true;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
if (accountsChanged) {
|
|
112
|
+
updated = {
|
|
113
|
+
...updated,
|
|
114
|
+
accounts: nextAccounts
|
|
115
|
+
};
|
|
116
|
+
changed = true;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
if (!changed) return {
|
|
120
|
+
config: cfg,
|
|
121
|
+
changes: []
|
|
122
|
+
};
|
|
123
|
+
return {
|
|
124
|
+
config: {
|
|
125
|
+
...cfg,
|
|
126
|
+
channels: {
|
|
127
|
+
...cfg.channels,
|
|
128
|
+
qqbot: updated
|
|
129
|
+
}
|
|
130
|
+
},
|
|
131
|
+
changes
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
//#endregion
|
|
135
|
+
export { normalizeCompatibilityConfig as n, legacyConfigRules as t };
|
|
@@ -1,9 +1,14 @@
|
|
|
1
|
-
import { D as
|
|
1
|
+
import { C as getNextMsgSeq, D as downloadFile, F as StreamInputMode, I as StreamInputState, M as getMaxUploadSize, P as StreamContentType, T as openLocalFile, a as createRawInputNotifyFn, b as stopBackgroundTokenRefresh, c as getMessageApi, d as initSender, f as onMessageSent, g as sendText, h as sendMedia, i as clearTokenCache, j as getImageMimeType, k as formatFileSize, 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, x as withTokenRetry, y as startBackgroundTokenRefresh } from "./sender-DIMG7jHz.js";
|
|
2
2
|
import { c as getPlatformAdapter, i as normalizeOptionalString$1, n as normalizeLowercaseStringOrEmpty$1, o as readStringField, s as sanitizeFileName, t as asOptionalObjectRecord } from "./string-normalize-R_0cKO7Q.js";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import { a as
|
|
3
|
+
import { c as setBridgeLogger, o as ensurePlatformAdapter } from "./config-schema-BFLNZ8Nf.js";
|
|
4
|
+
import { a as authorizeQQBotApprovalAction, i as toGatewayAccount, n as buildQQBotStateKey, p as parseApprovalButtonData, r as openQQBotSyncKeyedStore } from "./channel-CcN43bPL.js";
|
|
5
|
+
import { d as resolveAccountBase } from "./config-ZEfgeoL4.js";
|
|
6
|
+
import { a as formatErrorMessage, i as formatDuration, n as debugLog, r as debugWarn, t as debugError } from "./log-SDfMMBWe.js";
|
|
7
|
+
import { n as getQQBotRuntimeForEngine, t as getQQBotRuntime } from "./runtime-B9UoQ5NI.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, s as getQQBotDataPath, u as getTempDir } from "./target-parser-BdCUmxK7.js";
|
|
9
|
+
import { a as matchSlashCommand, i as initCommands, n as getFrameworkVersion, r as getPluginVersion } from "./slash-commands-impl-FRw-Dl44.js";
|
|
10
|
+
import { n as runWithRequestContext } from "./request-context-Bm7PTBD1.js";
|
|
11
|
+
import { D as setOutboundAudioPort, T as DEFAULT_MEDIA_SEND_ERROR, _ as sendVideoMsg, c as isCronReminderPayload, d as normalizeMediaTags, g as sendPhoto, h as sendDocument, l as isMediaPayload, o as decodeMediaPath, r as sendMedia$1, s as encodePayloadForCron, u as parseQQBotPayload, v as sendVoice, y as resolveUserFacingMediaError } from "./outbound-C9wV892v.js";
|
|
7
12
|
import { asBoolean, uniqueStrings } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
8
13
|
import { isImplicitSameChatApprovalAuthorization } from "openclaw/plugin-sdk/approval-auth-runtime";
|
|
9
14
|
import * as fs$1 from "node:fs";
|
|
@@ -17,6 +22,7 @@ import path from "node:path";
|
|
|
17
22
|
import { mimeTypeFromFilePath } from "openclaw/plugin-sdk/media-mime";
|
|
18
23
|
import { MAX_TIMER_TIMEOUT_MS, finiteSecondsToTimerSafeMilliseconds } from "openclaw/plugin-sdk/number-runtime";
|
|
19
24
|
import { resolveRuntimeServiceVersion } from "openclaw/plugin-sdk/cli-runtime";
|
|
25
|
+
import { loadSessionStore } from "openclaw/plugin-sdk/session-store-runtime";
|
|
20
26
|
import { getRuntimeConfig } from "openclaw/plugin-sdk/runtime-config-snapshot";
|
|
21
27
|
import WebSocket from "ws";
|
|
22
28
|
import { resolveAmbientNodeProxyAgent } from "openclaw/plugin-sdk/extension-shared";
|
|
@@ -60,10 +66,7 @@ function resolveSessionStorePath(cfg, agentId) {
|
|
|
60
66
|
function createNodeSessionStoreReader() {
|
|
61
67
|
return { read: ({ cfg, agentId }) => {
|
|
62
68
|
try {
|
|
63
|
-
|
|
64
|
-
if (!fs.existsSync(storePath)) return null;
|
|
65
|
-
const raw = fs.readFileSync(storePath, "utf-8");
|
|
66
|
-
return JSON.parse(raw);
|
|
69
|
+
return loadSessionStore(resolveSessionStorePath(cfg, agentId), { skipCache: true });
|
|
67
70
|
} catch {
|
|
68
71
|
return null;
|
|
69
72
|
}
|
|
@@ -2564,7 +2567,6 @@ function classifyMedia(processed) {
|
|
|
2564
2567
|
const DEFAULT_GROUP_CONFIG = {
|
|
2565
2568
|
requireMention: true,
|
|
2566
2569
|
ignoreOtherMentions: false,
|
|
2567
|
-
toolPolicy: "restricted",
|
|
2568
2570
|
name: "",
|
|
2569
2571
|
historyLimit: 50
|
|
2570
2572
|
};
|
|
@@ -2585,10 +2587,6 @@ function readString(obj, key) {
|
|
|
2585
2587
|
const v = obj[key];
|
|
2586
2588
|
return typeof v === "string" && v.length > 0 ? v : void 0;
|
|
2587
2589
|
}
|
|
2588
|
-
function readToolPolicy(obj, key) {
|
|
2589
|
-
const v = obj[key];
|
|
2590
|
-
return v === "full" || v === "restricted" || v === "none" ? v : void 0;
|
|
2591
|
-
}
|
|
2592
2590
|
function readHistoryLimit(obj, key) {
|
|
2593
2591
|
const v = obj[key];
|
|
2594
2592
|
if (typeof v !== "number" || !Number.isFinite(v)) return;
|
|
@@ -2601,7 +2599,6 @@ function resolveGroupConfig(cfg, groupOpenid, accountId) {
|
|
|
2601
2599
|
return {
|
|
2602
2600
|
requireMention: readBoolean(specific, "requireMention") ?? readBoolean(wildcard, "requireMention") ?? DEFAULT_GROUP_CONFIG.requireMention,
|
|
2603
2601
|
ignoreOtherMentions: readBoolean(specific, "ignoreOtherMentions") ?? readBoolean(wildcard, "ignoreOtherMentions") ?? DEFAULT_GROUP_CONFIG.ignoreOtherMentions,
|
|
2604
|
-
toolPolicy: readToolPolicy(specific, "toolPolicy") ?? readToolPolicy(wildcard, "toolPolicy") ?? DEFAULT_GROUP_CONFIG.toolPolicy,
|
|
2605
2602
|
name: readString(specific, "name") ?? readString(wildcard, "name") ?? DEFAULT_GROUP_CONFIG.name,
|
|
2606
2603
|
prompt: readString(specific, "prompt") ?? readString(wildcard, "prompt"),
|
|
2607
2604
|
historyLimit: readHistoryLimit(specific, "historyLimit") ?? readHistoryLimit(wildcard, "historyLimit") ?? DEFAULT_GROUP_CONFIG.historyLimit
|
|
@@ -3828,7 +3825,7 @@ async function sendMarkdownReply(textWithoutImages, imageUrls, mdMatches, bareUr
|
|
|
3828
3825
|
const target = buildDeliveryTarget(event);
|
|
3829
3826
|
const creds = accountToCreds(account);
|
|
3830
3827
|
if (target.type === "c2c" || target.type === "group") await withTokenRetry(creds, async () => {
|
|
3831
|
-
await sendMedia
|
|
3828
|
+
await sendMedia({
|
|
3832
3829
|
target,
|
|
3833
3830
|
creds,
|
|
3834
3831
|
kind: "image",
|
|
@@ -4099,7 +4096,7 @@ async function handleImagePayload(ctx, payload) {
|
|
|
4099
4096
|
const deliveryTarget = buildDeliveryTarget(target);
|
|
4100
4097
|
const creds = accountToCreds(account);
|
|
4101
4098
|
await withTokenRetry(creds, async () => {
|
|
4102
|
-
if (deliveryTarget.type === "c2c" || deliveryTarget.type === "group") await sendMedia
|
|
4099
|
+
if (deliveryTarget.type === "c2c" || deliveryTarget.type === "group") await sendMedia({
|
|
4103
4100
|
target: deliveryTarget,
|
|
4104
4101
|
creds,
|
|
4105
4102
|
kind: "image",
|
|
@@ -4154,7 +4151,7 @@ async function sendTextAsVoiceReply(ctx, text, deps) {
|
|
|
4154
4151
|
const deliveryTarget = buildDeliveryTarget(target);
|
|
4155
4152
|
const creds = accountToCreds(account);
|
|
4156
4153
|
await withTokenRetry(creds, async () => {
|
|
4157
|
-
if (deliveryTarget.type === "c2c" || deliveryTarget.type === "group") await sendMedia
|
|
4154
|
+
if (deliveryTarget.type === "c2c" || deliveryTarget.type === "group") await sendMedia({
|
|
4158
4155
|
target: deliveryTarget,
|
|
4159
4156
|
creds,
|
|
4160
4157
|
kind: "voice",
|
|
@@ -4190,7 +4187,7 @@ async function handleVideoPayload(ctx, payload) {
|
|
|
4190
4187
|
return;
|
|
4191
4188
|
}
|
|
4192
4189
|
await withTokenRetry(creds, async () => {
|
|
4193
|
-
if (isHttpUrl) await sendMedia
|
|
4190
|
+
if (isHttpUrl) await sendMedia({
|
|
4194
4191
|
target: deliveryTarget,
|
|
4195
4192
|
creds,
|
|
4196
4193
|
kind: "video",
|
|
@@ -4200,7 +4197,7 @@ async function handleVideoPayload(ctx, payload) {
|
|
|
4200
4197
|
else {
|
|
4201
4198
|
const size = await assertLocalFileWithinTypeLimit(videoPath, 2);
|
|
4202
4199
|
log?.debug?.(`Video local (${formatFileSize(size)}): ${describeMediaTargetForLog(videoPath, false)}`);
|
|
4203
|
-
await sendMedia
|
|
4200
|
+
await sendMedia({
|
|
4204
4201
|
target: deliveryTarget,
|
|
4205
4202
|
creds,
|
|
4206
4203
|
kind: "video",
|
|
@@ -4232,7 +4229,7 @@ async function handleFilePayload(ctx, payload) {
|
|
|
4232
4229
|
return;
|
|
4233
4230
|
}
|
|
4234
4231
|
await withTokenRetry(creds, async () => {
|
|
4235
|
-
if (isHttpUrl) await sendMedia
|
|
4232
|
+
if (isHttpUrl) await sendMedia({
|
|
4236
4233
|
target: deliveryTarget,
|
|
4237
4234
|
creds,
|
|
4238
4235
|
kind: "file",
|
|
@@ -4243,7 +4240,7 @@ async function handleFilePayload(ctx, payload) {
|
|
|
4243
4240
|
else {
|
|
4244
4241
|
const size = await assertLocalFileWithinTypeLimit(filePath, 4);
|
|
4245
4242
|
log?.debug?.(`File local (${formatFileSize(size)}): ${describeMediaTargetForLog(filePath, false)}`);
|
|
4246
|
-
await sendMedia
|
|
4243
|
+
await sendMedia({
|
|
4247
4244
|
target: deliveryTarget,
|
|
4248
4245
|
creds,
|
|
4249
4246
|
kind: "file",
|
|
@@ -4446,7 +4443,7 @@ async function executeSendQueue(queue, ctx, options = {}) {
|
|
|
4446
4443
|
await sendFallbackText(resolveUserFacingMediaError(result));
|
|
4447
4444
|
}
|
|
4448
4445
|
} else if (item.type === "media") {
|
|
4449
|
-
const result = await sendMedia({
|
|
4446
|
+
const result = await sendMedia$1({
|
|
4450
4447
|
to: qualifiedTarget,
|
|
4451
4448
|
text: "",
|
|
4452
4449
|
mediaUrl: item.content,
|
|
@@ -5774,7 +5771,7 @@ async function dispatchOutbound(inbound, deps) {
|
|
|
5774
5771
|
for (const mediaUrl of toolMediaUrls) {
|
|
5775
5772
|
const ac = new AbortController();
|
|
5776
5773
|
try {
|
|
5777
|
-
const result = await Promise.race([sendMedia({
|
|
5774
|
+
const result = await Promise.race([sendMedia$1({
|
|
5778
5775
|
to: qualifiedTarget,
|
|
5779
5776
|
text: "",
|
|
5780
5777
|
mediaUrl,
|
|
@@ -5833,7 +5830,7 @@ async function dispatchOutbound(inbound, deps) {
|
|
|
5833
5830
|
sendVoice: (target, voicePath, uploadFormats, transcodeEnabled) => sendVoice(target, voicePath, uploadFormats, transcodeEnabled),
|
|
5834
5831
|
sendVideoMsg: (target, videoPath) => sendVideoMsg(target, videoPath),
|
|
5835
5832
|
sendDocument: (target, filePath) => sendDocument(target, filePath),
|
|
5836
|
-
sendMedia: (opts) => sendMedia(opts)
|
|
5833
|
+
sendMedia: (opts) => sendMedia$1(opts)
|
|
5837
5834
|
},
|
|
5838
5835
|
chunkText: (text, limit) => runtime.channel.text.chunkMarkdownText(text, limit)
|
|
5839
5836
|
};
|
|
@@ -5929,7 +5926,7 @@ async function dispatchOutbound(inbound, deps) {
|
|
|
5929
5926
|
const urlsToSend = [...toolMediaUrls];
|
|
5930
5927
|
toolMediaUrls.length = 0;
|
|
5931
5928
|
for (const mediaUrl of urlsToSend) try {
|
|
5932
|
-
await sendMedia({
|
|
5929
|
+
await sendMedia$1({
|
|
5933
5930
|
to: qualifiedTarget,
|
|
5934
5931
|
text: "",
|
|
5935
5932
|
mediaUrl,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { d as
|
|
1
|
+
import { c as getMessageApi, t as accountToCreds } from "./sender-DIMG7jHz.js";
|
|
2
|
+
import { o as ensurePlatformAdapter, s as getBridgeLogger } from "./config-schema-BFLNZ8Nf.js";
|
|
3
|
+
import { c as resolveQQBotExecApprovalConfig, d as buildExecApprovalText, f as buildPluginApprovalText, l as shouldHandleQQBotExecApprovalRequest, m as resolveApprovalTarget, o as isQQBotExecApprovalClientEnabled, s as matchesQQBotApprovalAccount, u as buildApprovalKeyboard } from "./channel-CcN43bPL.js";
|
|
4
|
+
import { a as resolveQQBotAccount } from "./config-ZEfgeoL4.js";
|
|
4
5
|
import { resolveApprovalRequestSessionConversation } from "openclaw/plugin-sdk/approval-native-runtime";
|
|
5
6
|
import { createChannelApprovalNativeRuntimeAdapter } from "openclaw/plugin-sdk/approval-handler-runtime";
|
|
6
7
|
//#region extensions/qqbot/src/bridge/approval/handler-runtime.ts
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,15 @@
|
|
|
1
1
|
import { defineBundledChannelEntry, loadBundledEntryExportSync } from "openclaw/plugin-sdk/channel-entry-contract";
|
|
2
2
|
//#region extensions/qqbot/index.ts
|
|
3
3
|
function registerQQBotFull(api) {
|
|
4
|
+
if (api.registrationMode === "tool-discovery") {
|
|
5
|
+
loadBundledEntryExportSync(import.meta.url, {
|
|
6
|
+
specifier: "./tools-api.js",
|
|
7
|
+
exportName: "registerQQBotTools"
|
|
8
|
+
})(api);
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
4
11
|
loadBundledEntryExportSync(import.meta.url, {
|
|
5
|
-
specifier: "./api.js",
|
|
12
|
+
specifier: "./channel-entry-api.js",
|
|
6
13
|
exportName: "registerQQBotFull"
|
|
7
14
|
})(api);
|
|
8
15
|
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
//#region extensions/qqbot/src/engine/utils/format.ts
|
|
2
|
+
/**
|
|
3
|
+
* General formatting and string utilities.
|
|
4
|
+
* 通用格式化与字符串工具。
|
|
5
|
+
*
|
|
6
|
+
* Pure utility functions with zero external dependencies.
|
|
7
|
+
* Replaces `openclaw/plugin-sdk/error-runtime` and `text-runtime`
|
|
8
|
+
* helpers for use inside engine/.
|
|
9
|
+
*
|
|
10
|
+
* NOTE: The framework `formatErrorMessage` also applies `redactSensitiveText()`
|
|
11
|
+
* for token masking. We intentionally omit that here — the framework's log
|
|
12
|
+
* pipeline handles redaction at a higher level.
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* Format any error object into a readable string.
|
|
16
|
+
* 将任意错误对象格式化为可读字符串。
|
|
17
|
+
*
|
|
18
|
+
* Traverses the `.cause` chain for nested Error objects to include
|
|
19
|
+
* the full error context (e.g. network errors wrapped inside HTTP errors).
|
|
20
|
+
*/
|
|
21
|
+
function formatErrorMessage(err) {
|
|
22
|
+
if (err instanceof Error) {
|
|
23
|
+
let formatted = err.message || err.name || "Error";
|
|
24
|
+
let cause = err.cause;
|
|
25
|
+
const seen = new Set([err]);
|
|
26
|
+
while (cause && !seen.has(cause)) {
|
|
27
|
+
seen.add(cause);
|
|
28
|
+
if (cause instanceof Error) {
|
|
29
|
+
if (cause.message) formatted += ` | ${cause.message}`;
|
|
30
|
+
cause = cause.cause;
|
|
31
|
+
} else if (typeof cause === "string") {
|
|
32
|
+
formatted += ` | ${cause}`;
|
|
33
|
+
break;
|
|
34
|
+
} else break;
|
|
35
|
+
}
|
|
36
|
+
return formatted;
|
|
37
|
+
}
|
|
38
|
+
if (typeof err === "string") return err;
|
|
39
|
+
if (err === null || err === void 0 || typeof err === "number" || typeof err === "boolean" || typeof err === "bigint") return String(err);
|
|
40
|
+
try {
|
|
41
|
+
return JSON.stringify(err);
|
|
42
|
+
} catch {
|
|
43
|
+
return Object.prototype.toString.call(err);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/** Format a millisecond duration into a human-readable string (e.g. "5m 30s"). */
|
|
47
|
+
function formatDuration(durationMs) {
|
|
48
|
+
const seconds = Math.round(durationMs / 1e3);
|
|
49
|
+
if (seconds < 60) return `${seconds}s`;
|
|
50
|
+
const minutes = Math.floor(seconds / 60);
|
|
51
|
+
const remainSeconds = seconds % 60;
|
|
52
|
+
return remainSeconds > 0 ? `${minutes}m ${remainSeconds}s` : `${minutes}m`;
|
|
53
|
+
}
|
|
54
|
+
//#endregion
|
|
55
|
+
//#region extensions/qqbot/src/engine/utils/log.ts
|
|
56
|
+
/**
|
|
57
|
+
* QQBot debug logging utilities.
|
|
58
|
+
* QQBot 调试日志工具。
|
|
59
|
+
*
|
|
60
|
+
* Only outputs when the QQBOT_DEBUG environment variable is set,
|
|
61
|
+
* preventing user message content from leaking in production logs.
|
|
62
|
+
*
|
|
63
|
+
* Self-contained within engine/ — no framework SDK dependency.
|
|
64
|
+
*/
|
|
65
|
+
function isQqbotDebugEnabled() {
|
|
66
|
+
const value = process.env.QQBOT_DEBUG;
|
|
67
|
+
if (typeof value !== "string") return false;
|
|
68
|
+
switch (value.trim().toLowerCase()) {
|
|
69
|
+
case "1":
|
|
70
|
+
case "on":
|
|
71
|
+
case "true":
|
|
72
|
+
case "yes": return true;
|
|
73
|
+
default: return false;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
const isDebug = () => isQqbotDebugEnabled();
|
|
77
|
+
const MAX_LOG_VALUE_CHARS = 4096;
|
|
78
|
+
function sanitizeDebugLogValue(value) {
|
|
79
|
+
let text;
|
|
80
|
+
if (typeof value === "string") text = value;
|
|
81
|
+
else if (value instanceof Error) text = value.stack || value.message;
|
|
82
|
+
else try {
|
|
83
|
+
text = JSON.stringify(value) ?? String(value);
|
|
84
|
+
} catch {
|
|
85
|
+
text = String(value);
|
|
86
|
+
}
|
|
87
|
+
const sanitized = text.replace(/\p{Cc}/gu, " ").replace(/\s+/g, " ").trim();
|
|
88
|
+
if (sanitized.length <= MAX_LOG_VALUE_CHARS) return sanitized;
|
|
89
|
+
return `${sanitized.slice(0, MAX_LOG_VALUE_CHARS)}...`;
|
|
90
|
+
}
|
|
91
|
+
function formatDebugLogArgs(args) {
|
|
92
|
+
return args.map(sanitizeDebugLogValue).join(" ");
|
|
93
|
+
}
|
|
94
|
+
/** Debug-level log; only outputs when QQBOT_DEBUG is enabled. */
|
|
95
|
+
function debugLog(...args) {
|
|
96
|
+
if (isDebug()) console.log(formatDebugLogArgs(args).replace(/\n|\r/g, ""));
|
|
97
|
+
}
|
|
98
|
+
/** Debug-level warning; only outputs when QQBOT_DEBUG is enabled. */
|
|
99
|
+
function debugWarn(...args) {
|
|
100
|
+
if (isDebug()) console.warn(formatDebugLogArgs(args).replace(/\n|\r/g, ""));
|
|
101
|
+
}
|
|
102
|
+
/** Debug-level error; only outputs when QQBOT_DEBUG is enabled. */
|
|
103
|
+
function debugError(...args) {
|
|
104
|
+
if (isDebug()) console.error(formatDebugLogArgs(args).replace(/\n|\r/g, ""));
|
|
105
|
+
}
|
|
106
|
+
//#endregion
|
|
107
|
+
export { formatErrorMessage as a, formatDuration as i, debugLog as n, debugWarn as r, debugError as t };
|
|
@@ -1,21 +1,10 @@
|
|
|
1
|
+
import { A as getFileTypeName, D as downloadFile, E as checkFileSize, L as __exportAll, M as getMaxUploadSize, N as readFileAsync, O as fileExistsAsync, S as UploadDailyLimitExceededError, g as sendText$1, h as sendMedia$1, j as getImageMimeType, k as formatFileSize, t as accountToCreds, u as initApiConfig, w as UPLOAD_PREPARE_FALLBACK_CODE } from "./sender-DIMG7jHz.js";
|
|
1
2
|
import { i as normalizeOptionalString, n as normalizeLowercaseStringOrEmpty, s as sanitizeFileName } from "./string-normalize-R_0cKO7Q.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
3
|
+
import { a as formatErrorMessage, n as debugLog, r as debugWarn, t as debugError } from "./log-SDfMMBWe.js";
|
|
4
|
+
import { c as getQQBotMediaDir, d as isLocalPath, m as resolveQQBotPayloadLocalFilePath, o as getQQBotDataDir, p as normalizePath$1, r as parseTarget$1 } from "./target-parser-BdCUmxK7.js";
|
|
4
5
|
import { pathExistsSync, resolveLocalPathFromRootsSync } from "openclaw/plugin-sdk/security-runtime";
|
|
5
6
|
import path from "node:path";
|
|
6
7
|
import { getFileExtension } from "openclaw/plugin-sdk/media-mime";
|
|
7
|
-
//#region \0rolldown/runtime.js
|
|
8
|
-
var __defProp = Object.defineProperty;
|
|
9
|
-
var __exportAll = (all, no_symbols) => {
|
|
10
|
-
let target = {};
|
|
11
|
-
for (var name in all) __defProp(target, name, {
|
|
12
|
-
get: all[name],
|
|
13
|
-
enumerable: true
|
|
14
|
-
});
|
|
15
|
-
if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
|
|
16
|
-
return target;
|
|
17
|
-
};
|
|
18
|
-
//#endregion
|
|
19
8
|
//#region extensions/qqbot/src/engine/messaging/outbound-audio-port.ts
|
|
20
9
|
let outboundAudioPort = null;
|
|
21
10
|
/**
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2
|
+
//#region extensions/qqbot/src/engine/utils/request-context.ts
|
|
3
|
+
/**
|
|
4
|
+
* Request-level context using AsyncLocalStorage.
|
|
5
|
+
*
|
|
6
|
+
* Provides ambient context (accountId, target openid, chat type, etc.)
|
|
7
|
+
* throughout the request lifecycle without explicit parameter threading.
|
|
8
|
+
*
|
|
9
|
+
* Gateway establishes the scope around each inbound message via
|
|
10
|
+
* `runWithRequestContext()`; any async code within that scope (including
|
|
11
|
+
* AI agent calls and tool `execute` callbacks) can retrieve the current
|
|
12
|
+
* request via `getRequestContext()` without racing with concurrent
|
|
13
|
+
* inbound messages.
|
|
14
|
+
*
|
|
15
|
+
* This is a pure Node.js module with zero framework dependencies,
|
|
16
|
+
* making it trivially portable between the built-in and standalone
|
|
17
|
+
* versions of QQBot.
|
|
18
|
+
*/
|
|
19
|
+
const store = new AsyncLocalStorage();
|
|
20
|
+
/**
|
|
21
|
+
* Execute an async function with request-scoped context.
|
|
22
|
+
*
|
|
23
|
+
* All code running within `fn` (including nested async calls) can
|
|
24
|
+
* retrieve the context via `getRequestContext()`.
|
|
25
|
+
*
|
|
26
|
+
* @param ctx - The context to attach to this request.
|
|
27
|
+
* @param fn - The async function to run within the context.
|
|
28
|
+
* @returns The return value of `fn`.
|
|
29
|
+
*/
|
|
30
|
+
function runWithRequestContext(ctx, fn) {
|
|
31
|
+
return store.run(ctx, fn);
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Retrieve the current request context.
|
|
35
|
+
*
|
|
36
|
+
* Returns `undefined` when called outside of a `runWithRequestContext`
|
|
37
|
+
* scope.
|
|
38
|
+
*/
|
|
39
|
+
function getRequestContext() {
|
|
40
|
+
return store.getStore();
|
|
41
|
+
}
|
|
42
|
+
//#endregion
|
|
43
|
+
export { runWithRequestContext as n, getRequestContext as t };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { v as setOpenClawVersion } from "./sender-DIMG7jHz.js";
|
|
2
|
+
import { createPluginRuntimeStore } from "openclaw/plugin-sdk/runtime-store";
|
|
3
|
+
//#region extensions/qqbot/src/bridge/runtime.ts
|
|
4
|
+
const { setRuntime: _setRuntime, clearRuntime: resetQQBotRuntimeForTest, getRuntime: getQQBotRuntime } = createPluginRuntimeStore({
|
|
5
|
+
pluginId: "qqbot",
|
|
6
|
+
errorMessage: "QQBot runtime not initialized"
|
|
7
|
+
});
|
|
8
|
+
/** Set the QQBot runtime and inject the framework version into the User-Agent. */
|
|
9
|
+
function setQQBotRuntime(runtime) {
|
|
10
|
+
_setRuntime(runtime);
|
|
11
|
+
setOpenClawVersion(runtime.version);
|
|
12
|
+
}
|
|
13
|
+
/** Type-narrowed getter for engine/ modules that need GatewayPluginRuntime. */
|
|
14
|
+
function getQQBotRuntimeForEngine() {
|
|
15
|
+
return getQQBotRuntime();
|
|
16
|
+
}
|
|
17
|
+
//#endregion
|
|
18
|
+
export { getQQBotRuntimeForEngine as n, setQQBotRuntime as r, getQQBotRuntime as t };
|
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-B9UoQ5NI.js";
|
|
2
2
|
export { getQQBotRuntime, setQQBotRuntime };
|