@cxyhhhhh/openclaw-qqbot 2.0.0-dev.202607081648 → 2.0.0-dev.202607082219
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 +543 -393
- package/dist/index.cjs.map +1 -1
- package/index.ts +1 -1
- package/package.json +1 -1
- package/skills/qqbot-channel/SKILL.md +33 -11
- package/src/{runtime-adapter/contract-check.ts → adapter/contract.ts} +4 -7
- package/src/{runtime-adapter/gateway-runtime.ts → adapter/gateway.ts} +2 -3
- package/src/{runtime-adapter → adapter}/index.ts +3 -3
- package/src/{runtime-adapter/lint-runtime-access.ts → adapter/lint.ts} +7 -7
- package/src/adapter/media.ts +112 -0
- package/src/adapter/setup.ts +55 -0
- package/src/adapter/workspace.ts +29 -0
- package/src/bot-instance.ts +1 -1
- package/src/channel.ts +1 -1
- package/src/commands/bot-approve.ts +1 -1
- package/src/commands/bot-logs.ts +1 -1
- package/src/commands/bot-pairing.ts +1 -1
- package/src/commands/config-util.ts +1 -1
- package/src/dispatch/body-assembler.ts +1 -1
- package/src/dispatch/dispatch.ts +75 -45
- package/src/features/approval-handler.ts +1 -1
- package/src/gateway/event-handlers.ts +1 -1
- package/src/gateway/lifecycle.ts +1 -1
- package/src/gateway/qqbot-gateway.ts +1 -1
- package/src/middleware/access-control.ts +1 -1
- package/src/middleware/attachment.ts +4 -4
- package/src/openclaw-plugin-sdk.d.ts +41 -0
- package/src/outbound/media-send.ts +4 -6
- package/src/runtime.ts +3 -1
- package/src/setup/finalize.ts +1 -2
- package/src/setup/surface.ts +5 -6
- package/src/utils/pkg-version.ts +78 -58
- package/tsup.config.ts +6 -1
- /package/src/{runtime-adapter/pairing-runtime.ts → adapter/pairing.ts} +0 -0
- /package/src/{runtime-adapter → adapter}/resolve.ts +0 -0
- /package/src/{runtime-adapter/webhook-adapter.ts → adapter/webhook.ts} +0 -0
package/dist/index.cjs
CHANGED
|
@@ -2239,7 +2239,7 @@ var require_websocket = __commonJS({
|
|
|
2239
2239
|
var http2 = require("http");
|
|
2240
2240
|
var net = require("net");
|
|
2241
2241
|
var tls = require("tls");
|
|
2242
|
-
var { randomBytes, createHash: createHash3 } = require("crypto");
|
|
2242
|
+
var { randomBytes: randomBytes2, createHash: createHash3 } = require("crypto");
|
|
2243
2243
|
var { Duplex, Readable } = require("stream");
|
|
2244
2244
|
var { URL: URL2 } = require("url");
|
|
2245
2245
|
var PerMessageDeflate2 = require_permessage_deflate();
|
|
@@ -2769,7 +2769,7 @@ var require_websocket = __commonJS({
|
|
|
2769
2769
|
}
|
|
2770
2770
|
}
|
|
2771
2771
|
const defaultPort = isSecure ? 443 : 80;
|
|
2772
|
-
const key =
|
|
2772
|
+
const key = randomBytes2(16).toString("base64");
|
|
2773
2773
|
const request2 = isSecure ? https3.request : http2.request;
|
|
2774
2774
|
const protocolSet = /* @__PURE__ */ new Set();
|
|
2775
2775
|
let perMessageDeflate;
|
|
@@ -2822,7 +2822,7 @@ var require_websocket = __commonJS({
|
|
|
2822
2822
|
opts.socketPath = parts[0];
|
|
2823
2823
|
opts.path = parts[1];
|
|
2824
2824
|
}
|
|
2825
|
-
let
|
|
2825
|
+
let req4;
|
|
2826
2826
|
if (opts.followRedirects) {
|
|
2827
2827
|
if (websocket._redirects === 0) {
|
|
2828
2828
|
websocket._originalIpc = isIpcUrl;
|
|
@@ -2847,32 +2847,32 @@ var require_websocket = __commonJS({
|
|
|
2847
2847
|
if (opts.auth && !options.headers.authorization) {
|
|
2848
2848
|
options.headers.authorization = "Basic " + Buffer.from(opts.auth).toString("base64");
|
|
2849
2849
|
}
|
|
2850
|
-
|
|
2850
|
+
req4 = websocket._req = request2(opts);
|
|
2851
2851
|
if (websocket._redirects) {
|
|
2852
|
-
websocket.emit("redirect", websocket.url,
|
|
2852
|
+
websocket.emit("redirect", websocket.url, req4);
|
|
2853
2853
|
}
|
|
2854
2854
|
} else {
|
|
2855
|
-
|
|
2855
|
+
req4 = websocket._req = request2(opts);
|
|
2856
2856
|
}
|
|
2857
2857
|
if (opts.timeout) {
|
|
2858
|
-
|
|
2859
|
-
abortHandshake(websocket,
|
|
2858
|
+
req4.on("timeout", () => {
|
|
2859
|
+
abortHandshake(websocket, req4, "Opening handshake has timed out");
|
|
2860
2860
|
});
|
|
2861
2861
|
}
|
|
2862
|
-
|
|
2863
|
-
if (
|
|
2864
|
-
|
|
2862
|
+
req4.on("error", (err) => {
|
|
2863
|
+
if (req4 === null || req4[kAborted]) return;
|
|
2864
|
+
req4 = websocket._req = null;
|
|
2865
2865
|
emitErrorAndClose(websocket, err);
|
|
2866
2866
|
});
|
|
2867
|
-
|
|
2867
|
+
req4.on("response", (res) => {
|
|
2868
2868
|
const location = res.headers.location;
|
|
2869
2869
|
const statusCode = res.statusCode;
|
|
2870
2870
|
if (location && opts.followRedirects && statusCode >= 300 && statusCode < 400) {
|
|
2871
2871
|
if (++websocket._redirects > opts.maxRedirects) {
|
|
2872
|
-
abortHandshake(websocket,
|
|
2872
|
+
abortHandshake(websocket, req4, "Maximum redirects exceeded");
|
|
2873
2873
|
return;
|
|
2874
2874
|
}
|
|
2875
|
-
|
|
2875
|
+
req4.abort();
|
|
2876
2876
|
let addr;
|
|
2877
2877
|
try {
|
|
2878
2878
|
addr = new URL2(location, address);
|
|
@@ -2882,18 +2882,18 @@ var require_websocket = __commonJS({
|
|
|
2882
2882
|
return;
|
|
2883
2883
|
}
|
|
2884
2884
|
initAsClient(websocket, addr, protocols, options);
|
|
2885
|
-
} else if (!websocket.emit("unexpected-response",
|
|
2885
|
+
} else if (!websocket.emit("unexpected-response", req4, res)) {
|
|
2886
2886
|
abortHandshake(
|
|
2887
2887
|
websocket,
|
|
2888
|
-
|
|
2888
|
+
req4,
|
|
2889
2889
|
`Unexpected server response: ${res.statusCode}`
|
|
2890
2890
|
);
|
|
2891
2891
|
}
|
|
2892
2892
|
});
|
|
2893
|
-
|
|
2893
|
+
req4.on("upgrade", (res, socket, head) => {
|
|
2894
2894
|
websocket.emit("upgrade", res);
|
|
2895
2895
|
if (websocket.readyState !== WebSocket2.CONNECTING) return;
|
|
2896
|
-
|
|
2896
|
+
req4 = websocket._req = null;
|
|
2897
2897
|
const upgrade = res.headers.upgrade;
|
|
2898
2898
|
if (upgrade === void 0 || upgrade.toLowerCase() !== "websocket") {
|
|
2899
2899
|
abortHandshake(websocket, socket, "Invalid Upgrade header");
|
|
@@ -2958,9 +2958,9 @@ var require_websocket = __commonJS({
|
|
|
2958
2958
|
});
|
|
2959
2959
|
});
|
|
2960
2960
|
if (opts.finishRequest) {
|
|
2961
|
-
opts.finishRequest(
|
|
2961
|
+
opts.finishRequest(req4, websocket);
|
|
2962
2962
|
} else {
|
|
2963
|
-
|
|
2963
|
+
req4.end();
|
|
2964
2964
|
}
|
|
2965
2965
|
}
|
|
2966
2966
|
function emitErrorAndClose(websocket, err) {
|
|
@@ -3339,7 +3339,7 @@ var require_websocket_server = __commonJS({
|
|
|
3339
3339
|
);
|
|
3340
3340
|
}
|
|
3341
3341
|
if (options.port != null) {
|
|
3342
|
-
this._server = http2.createServer((
|
|
3342
|
+
this._server = http2.createServer((req4, res) => {
|
|
3343
3343
|
const body = http2.STATUS_CODES[426];
|
|
3344
3344
|
res.writeHead(426, {
|
|
3345
3345
|
"Content-Length": body.length,
|
|
@@ -3361,8 +3361,8 @@ var require_websocket_server = __commonJS({
|
|
|
3361
3361
|
this._removeListeners = addListeners(this._server, {
|
|
3362
3362
|
listening: this.emit.bind(this, "listening"),
|
|
3363
3363
|
error: this.emit.bind(this, "error"),
|
|
3364
|
-
upgrade: (
|
|
3365
|
-
this.handleUpgrade(
|
|
3364
|
+
upgrade: (req4, socket, head) => {
|
|
3365
|
+
this.handleUpgrade(req4, socket, head, emitConnection);
|
|
3366
3366
|
}
|
|
3367
3367
|
});
|
|
3368
3368
|
}
|
|
@@ -3440,10 +3440,10 @@ var require_websocket_server = __commonJS({
|
|
|
3440
3440
|
* @return {Boolean} `true` if the request is valid, else `false`
|
|
3441
3441
|
* @public
|
|
3442
3442
|
*/
|
|
3443
|
-
shouldHandle(
|
|
3443
|
+
shouldHandle(req4) {
|
|
3444
3444
|
if (this.options.path) {
|
|
3445
|
-
const index =
|
|
3446
|
-
const pathname = index !== -1 ?
|
|
3445
|
+
const index = req4.url.indexOf("?");
|
|
3446
|
+
const pathname = index !== -1 ? req4.url.slice(0, index) : req4.url;
|
|
3447
3447
|
if (pathname !== this.options.path) return false;
|
|
3448
3448
|
}
|
|
3449
3449
|
return true;
|
|
@@ -3457,49 +3457,49 @@ var require_websocket_server = __commonJS({
|
|
|
3457
3457
|
* @param {Function} cb Callback
|
|
3458
3458
|
* @public
|
|
3459
3459
|
*/
|
|
3460
|
-
handleUpgrade(
|
|
3460
|
+
handleUpgrade(req4, socket, head, cb) {
|
|
3461
3461
|
socket.on("error", socketOnError);
|
|
3462
|
-
const key =
|
|
3463
|
-
const upgrade =
|
|
3464
|
-
const version = +
|
|
3465
|
-
if (
|
|
3462
|
+
const key = req4.headers["sec-websocket-key"];
|
|
3463
|
+
const upgrade = req4.headers.upgrade;
|
|
3464
|
+
const version = +req4.headers["sec-websocket-version"];
|
|
3465
|
+
if (req4.method !== "GET") {
|
|
3466
3466
|
const message = "Invalid HTTP method";
|
|
3467
|
-
abortHandshakeOrEmitwsClientError(this,
|
|
3467
|
+
abortHandshakeOrEmitwsClientError(this, req4, socket, 405, message);
|
|
3468
3468
|
return;
|
|
3469
3469
|
}
|
|
3470
3470
|
if (upgrade === void 0 || upgrade.toLowerCase() !== "websocket") {
|
|
3471
3471
|
const message = "Invalid Upgrade header";
|
|
3472
|
-
abortHandshakeOrEmitwsClientError(this,
|
|
3472
|
+
abortHandshakeOrEmitwsClientError(this, req4, socket, 400, message);
|
|
3473
3473
|
return;
|
|
3474
3474
|
}
|
|
3475
3475
|
if (key === void 0 || !keyRegex.test(key)) {
|
|
3476
3476
|
const message = "Missing or invalid Sec-WebSocket-Key header";
|
|
3477
|
-
abortHandshakeOrEmitwsClientError(this,
|
|
3477
|
+
abortHandshakeOrEmitwsClientError(this, req4, socket, 400, message);
|
|
3478
3478
|
return;
|
|
3479
3479
|
}
|
|
3480
3480
|
if (version !== 13 && version !== 8) {
|
|
3481
3481
|
const message = "Missing or invalid Sec-WebSocket-Version header";
|
|
3482
|
-
abortHandshakeOrEmitwsClientError(this,
|
|
3482
|
+
abortHandshakeOrEmitwsClientError(this, req4, socket, 400, message, {
|
|
3483
3483
|
"Sec-WebSocket-Version": "13, 8"
|
|
3484
3484
|
});
|
|
3485
3485
|
return;
|
|
3486
3486
|
}
|
|
3487
|
-
if (!this.shouldHandle(
|
|
3487
|
+
if (!this.shouldHandle(req4)) {
|
|
3488
3488
|
abortHandshake(socket, 400);
|
|
3489
3489
|
return;
|
|
3490
3490
|
}
|
|
3491
|
-
const secWebSocketProtocol =
|
|
3491
|
+
const secWebSocketProtocol = req4.headers["sec-websocket-protocol"];
|
|
3492
3492
|
let protocols = /* @__PURE__ */ new Set();
|
|
3493
3493
|
if (secWebSocketProtocol !== void 0) {
|
|
3494
3494
|
try {
|
|
3495
3495
|
protocols = subprotocol2.parse(secWebSocketProtocol);
|
|
3496
3496
|
} catch (err) {
|
|
3497
3497
|
const message = "Invalid Sec-WebSocket-Protocol header";
|
|
3498
|
-
abortHandshakeOrEmitwsClientError(this,
|
|
3498
|
+
abortHandshakeOrEmitwsClientError(this, req4, socket, 400, message);
|
|
3499
3499
|
return;
|
|
3500
3500
|
}
|
|
3501
3501
|
}
|
|
3502
|
-
const secWebSocketExtensions =
|
|
3502
|
+
const secWebSocketExtensions = req4.headers["sec-websocket-extensions"];
|
|
3503
3503
|
const extensions = {};
|
|
3504
3504
|
if (this.options.perMessageDeflate && secWebSocketExtensions !== void 0) {
|
|
3505
3505
|
const perMessageDeflate = new PerMessageDeflate2({
|
|
@@ -3515,15 +3515,15 @@ var require_websocket_server = __commonJS({
|
|
|
3515
3515
|
}
|
|
3516
3516
|
} catch (err) {
|
|
3517
3517
|
const message = "Invalid or unacceptable Sec-WebSocket-Extensions header";
|
|
3518
|
-
abortHandshakeOrEmitwsClientError(this,
|
|
3518
|
+
abortHandshakeOrEmitwsClientError(this, req4, socket, 400, message);
|
|
3519
3519
|
return;
|
|
3520
3520
|
}
|
|
3521
3521
|
}
|
|
3522
3522
|
if (this.options.verifyClient) {
|
|
3523
3523
|
const info = {
|
|
3524
|
-
origin:
|
|
3525
|
-
secure: !!(
|
|
3526
|
-
req
|
|
3524
|
+
origin: req4.headers[`${version === 8 ? "sec-websocket-origin" : "origin"}`],
|
|
3525
|
+
secure: !!(req4.socket.authorized || req4.socket.encrypted),
|
|
3526
|
+
req: req4
|
|
3527
3527
|
};
|
|
3528
3528
|
if (this.options.verifyClient.length === 2) {
|
|
3529
3529
|
this.options.verifyClient(info, (verified, code, message, headers) => {
|
|
@@ -3534,7 +3534,7 @@ var require_websocket_server = __commonJS({
|
|
|
3534
3534
|
extensions,
|
|
3535
3535
|
key,
|
|
3536
3536
|
protocols,
|
|
3537
|
-
|
|
3537
|
+
req4,
|
|
3538
3538
|
socket,
|
|
3539
3539
|
head,
|
|
3540
3540
|
cb
|
|
@@ -3544,7 +3544,7 @@ var require_websocket_server = __commonJS({
|
|
|
3544
3544
|
}
|
|
3545
3545
|
if (!this.options.verifyClient(info)) return abortHandshake(socket, 401);
|
|
3546
3546
|
}
|
|
3547
|
-
this.completeUpgrade(extensions, key, protocols,
|
|
3547
|
+
this.completeUpgrade(extensions, key, protocols, req4, socket, head, cb);
|
|
3548
3548
|
}
|
|
3549
3549
|
/**
|
|
3550
3550
|
* Upgrade the connection to WebSocket.
|
|
@@ -3559,7 +3559,7 @@ var require_websocket_server = __commonJS({
|
|
|
3559
3559
|
* @throws {Error} If called more than once with the same socket
|
|
3560
3560
|
* @private
|
|
3561
3561
|
*/
|
|
3562
|
-
completeUpgrade(extensions, key, protocols,
|
|
3562
|
+
completeUpgrade(extensions, key, protocols, req4, socket, head, cb) {
|
|
3563
3563
|
if (!socket.readable || !socket.writable) return socket.destroy();
|
|
3564
3564
|
if (socket[kWebSocket]) {
|
|
3565
3565
|
throw new Error(
|
|
@@ -3576,7 +3576,7 @@ var require_websocket_server = __commonJS({
|
|
|
3576
3576
|
];
|
|
3577
3577
|
const ws = new this.options.WebSocket(null, void 0, this.options);
|
|
3578
3578
|
if (protocols.size) {
|
|
3579
|
-
const protocol = this.options.handleProtocols ? this.options.handleProtocols(protocols,
|
|
3579
|
+
const protocol = this.options.handleProtocols ? this.options.handleProtocols(protocols, req4) : protocols.values().next().value;
|
|
3580
3580
|
if (protocol) {
|
|
3581
3581
|
headers.push(`Sec-WebSocket-Protocol: ${protocol}`);
|
|
3582
3582
|
ws._protocol = protocol;
|
|
@@ -3590,7 +3590,7 @@ var require_websocket_server = __commonJS({
|
|
|
3590
3590
|
headers.push(`Sec-WebSocket-Extensions: ${value}`);
|
|
3591
3591
|
ws._extensions = extensions;
|
|
3592
3592
|
}
|
|
3593
|
-
this.emit("headers", headers,
|
|
3593
|
+
this.emit("headers", headers, req4);
|
|
3594
3594
|
socket.write(headers.concat("\r\n").join("\r\n"));
|
|
3595
3595
|
socket.removeListener("error", socketOnError);
|
|
3596
3596
|
ws.setSocket(socket, head, {
|
|
@@ -3607,7 +3607,7 @@ var require_websocket_server = __commonJS({
|
|
|
3607
3607
|
}
|
|
3608
3608
|
});
|
|
3609
3609
|
}
|
|
3610
|
-
cb(ws,
|
|
3610
|
+
cb(ws, req4);
|
|
3611
3611
|
}
|
|
3612
3612
|
};
|
|
3613
3613
|
module2.exports = WebSocketServer2;
|
|
@@ -3640,11 +3640,11 @@ var require_websocket_server = __commonJS({
|
|
|
3640
3640
|
` + Object.keys(headers).map((h2) => `${h2}: ${headers[h2]}`).join("\r\n") + "\r\n\r\n" + message
|
|
3641
3641
|
);
|
|
3642
3642
|
}
|
|
3643
|
-
function abortHandshakeOrEmitwsClientError(server,
|
|
3643
|
+
function abortHandshakeOrEmitwsClientError(server, req4, socket, code, message, headers) {
|
|
3644
3644
|
if (server.listenerCount("wsClientError")) {
|
|
3645
3645
|
const err = new Error(message);
|
|
3646
3646
|
Error.captureStackTrace(err, abortHandshakeOrEmitwsClientError);
|
|
3647
|
-
server.emit("wsClientError", err, socket,
|
|
3647
|
+
server.emit("wsClientError", err, socket, req4);
|
|
3648
3648
|
} else {
|
|
3649
3649
|
abortHandshake(socket, code, message, headers);
|
|
3650
3650
|
}
|
|
@@ -5020,11 +5020,11 @@ var fs3 = __toESM(require("fs"), 1);
|
|
|
5020
5020
|
var path = __toESM(require("path"), 1);
|
|
5021
5021
|
|
|
5022
5022
|
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607081646/node_modules/@cxyhhhhh/qqbot-nodejs/dist/middleware/types.js
|
|
5023
|
-
function resolvePolicy(ctx,
|
|
5023
|
+
function resolvePolicy(ctx, path21, explicit, defaultValue) {
|
|
5024
5024
|
if (explicit !== void 0 && explicit !== null) {
|
|
5025
5025
|
return explicit;
|
|
5026
5026
|
}
|
|
5027
|
-
const keys =
|
|
5027
|
+
const keys = path21.split(".");
|
|
5028
5028
|
let value = ctx.state.policy;
|
|
5029
5029
|
for (const key of keys) {
|
|
5030
5030
|
if (value === null || value === void 0)
|
|
@@ -5102,10 +5102,10 @@ var ApiError = class extends Error {
|
|
|
5102
5102
|
bizCode;
|
|
5103
5103
|
bizMessage;
|
|
5104
5104
|
name = "ApiError";
|
|
5105
|
-
constructor(message, httpStatus,
|
|
5105
|
+
constructor(message, httpStatus, path21, bizCode, bizMessage) {
|
|
5106
5106
|
super(message);
|
|
5107
5107
|
this.httpStatus = httpStatus;
|
|
5108
|
-
this.path =
|
|
5108
|
+
this.path = path21;
|
|
5109
5109
|
this.bizCode = bizCode;
|
|
5110
5110
|
this.bizMessage = bizMessage;
|
|
5111
5111
|
}
|
|
@@ -5193,14 +5193,14 @@ var ApiClient = class {
|
|
|
5193
5193
|
const ua = config.userAgent ?? "qqbot-nodejs/unknown";
|
|
5194
5194
|
this.resolveUserAgent = typeof ua === "function" ? ua : () => ua;
|
|
5195
5195
|
}
|
|
5196
|
-
async request(accessToken, method,
|
|
5197
|
-
const url = `${this.baseUrl}${
|
|
5196
|
+
async request(accessToken, method, path21, body, options) {
|
|
5197
|
+
const url = `${this.baseUrl}${path21}`;
|
|
5198
5198
|
const headers = {
|
|
5199
5199
|
Authorization: `QQBot ${accessToken}`,
|
|
5200
5200
|
"Content-Type": "application/json",
|
|
5201
5201
|
"User-Agent": this.resolveUserAgent()
|
|
5202
5202
|
};
|
|
5203
|
-
const isFileUpload = options?.uploadRequest === true ||
|
|
5203
|
+
const isFileUpload = options?.uploadRequest === true || path21.includes("/files") || path21.includes("/upload_prepare") || path21.includes("/upload_part_finish");
|
|
5204
5204
|
const timeout = options?.timeoutMs ?? (isFileUpload ? this.fileUploadTimeoutMs : this.defaultTimeoutMs);
|
|
5205
5205
|
const controller = new AbortController();
|
|
5206
5206
|
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
@@ -5225,10 +5225,10 @@ var ApiClient = class {
|
|
|
5225
5225
|
clearTimeout(timeoutId);
|
|
5226
5226
|
if (err instanceof Error && err.name === "AbortError") {
|
|
5227
5227
|
this.logger?.error?.(`[qqbot:api] <<< Timeout after ${timeout}ms`);
|
|
5228
|
-
throw new ApiError(`Request timeout [${
|
|
5228
|
+
throw new ApiError(`Request timeout [${path21}]: exceeded ${timeout}ms`, 0, path21);
|
|
5229
5229
|
}
|
|
5230
5230
|
this.logger?.error?.(`[qqbot:api] <<< Network error: ${formatErrorMessage(err)}`);
|
|
5231
|
-
throw new ApiError(`Network error [${
|
|
5231
|
+
throw new ApiError(`Network error [${path21}]: ${formatErrorMessage(err)}`, 0, path21);
|
|
5232
5232
|
} finally {
|
|
5233
5233
|
clearTimeout(timeoutId);
|
|
5234
5234
|
}
|
|
@@ -5238,7 +5238,7 @@ var ApiClient = class {
|
|
|
5238
5238
|
try {
|
|
5239
5239
|
rawBody = await res.text();
|
|
5240
5240
|
} catch (err) {
|
|
5241
|
-
throw new ApiError(`Failed to read response [${
|
|
5241
|
+
throw new ApiError(`Failed to read response [${path21}]: ${formatErrorMessage(err)}`, res.status, path21);
|
|
5242
5242
|
}
|
|
5243
5243
|
this.logger?.debug?.(`[qqbot:api] <<< Body: ${rawBody}`);
|
|
5244
5244
|
const contentType = res.headers.get("content-type") ?? "";
|
|
@@ -5246,26 +5246,26 @@ var ApiClient = class {
|
|
|
5246
5246
|
if (!res.ok) {
|
|
5247
5247
|
if (isHtmlResponse) {
|
|
5248
5248
|
const statusHint = res.status === 502 || res.status === 503 || res.status === 504 ? "\u8C03\u7528\u53D1\u751F\u5F02\u5E38\uFF0C\u8BF7\u7A0D\u5019\u91CD\u8BD5" : res.status === 429 ? "\u8BF7\u6C42\u8FC7\u4E8E\u9891\u7E41\uFF0C\u5DF2\u88AB\u9650\u6D41" : `\u5F00\u653E\u5E73\u53F0\u8FD4\u56DE HTTP ${res.status}`;
|
|
5249
|
-
throw new ApiError(`${statusHint}\uFF08${
|
|
5249
|
+
throw new ApiError(`${statusHint}\uFF08${path21}\uFF09\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5`, res.status, path21);
|
|
5250
5250
|
}
|
|
5251
5251
|
try {
|
|
5252
5252
|
const error = JSON.parse(rawBody);
|
|
5253
5253
|
const bizCode = error.code ?? error.err_code;
|
|
5254
|
-
throw new ApiError(`API Error [${
|
|
5254
|
+
throw new ApiError(`API Error [${path21}]: ${error.message ?? rawBody}`, res.status, path21, bizCode, error.message);
|
|
5255
5255
|
} catch (parseErr) {
|
|
5256
5256
|
if (parseErr instanceof ApiError) {
|
|
5257
5257
|
throw parseErr;
|
|
5258
5258
|
}
|
|
5259
|
-
throw new ApiError(`API Error [${
|
|
5259
|
+
throw new ApiError(`API Error [${path21}] HTTP ${res.status}: ${rawBody.slice(0, 200)}`, res.status, path21);
|
|
5260
5260
|
}
|
|
5261
5261
|
}
|
|
5262
5262
|
if (isHtmlResponse) {
|
|
5263
|
-
throw new ApiError(`QQ \u670D\u52A1\u7AEF\u8FD4\u56DE\u4E86\u975E JSON \u54CD\u5E94\uFF08${
|
|
5263
|
+
throw new ApiError(`QQ \u670D\u52A1\u7AEF\u8FD4\u56DE\u4E86\u975E JSON \u54CD\u5E94\uFF08${path21}\uFF09\uFF0C\u53EF\u80FD\u662F\u4E34\u65F6\u6545\u969C\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5`, res.status, path21);
|
|
5264
5264
|
}
|
|
5265
5265
|
try {
|
|
5266
5266
|
return JSON.parse(rawBody);
|
|
5267
5267
|
} catch {
|
|
5268
|
-
throw new ApiError(`\u5F00\u653E\u5E73\u53F0\u54CD\u5E94\u683C\u5F0F\u5F02\u5E38\uFF08${
|
|
5268
|
+
throw new ApiError(`\u5F00\u653E\u5E73\u53F0\u54CD\u5E94\u683C\u5F0F\u5F02\u5E38\uFF08${path21}\uFF09\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5`, res.status, path21);
|
|
5269
5269
|
}
|
|
5270
5270
|
}
|
|
5271
5271
|
};
|
|
@@ -5488,9 +5488,9 @@ var ChunkedMediaApi = class {
|
|
|
5488
5488
|
}
|
|
5489
5489
|
async callUploadPrepare(opts, fileName, fileSize, hashes, pathLabel) {
|
|
5490
5490
|
const token = await this.tokenManager.getAccessToken(opts.creds.appId, opts.creds.clientSecret);
|
|
5491
|
-
const
|
|
5491
|
+
const path21 = uploadPreparePath(opts.scope, opts.targetId);
|
|
5492
5492
|
try {
|
|
5493
|
-
return await this.client.request(token, "POST",
|
|
5493
|
+
return await this.client.request(token, "POST", path21, {
|
|
5494
5494
|
file_type: opts.fileType,
|
|
5495
5495
|
file_name: fileName,
|
|
5496
5496
|
file_size: fileSize,
|
|
@@ -5507,10 +5507,10 @@ var ChunkedMediaApi = class {
|
|
|
5507
5507
|
}
|
|
5508
5508
|
async callUploadPartFinish(opts, uploadId, partIndex, blockSize, md5, retryTimeoutMs) {
|
|
5509
5509
|
const persistentPolicy = buildPartFinishPersistentPolicy(retryTimeoutMs);
|
|
5510
|
-
const
|
|
5510
|
+
const path21 = uploadPartFinishPath(opts.scope, opts.targetId);
|
|
5511
5511
|
await withRetry(async () => {
|
|
5512
5512
|
const token = await this.tokenManager.getAccessToken(opts.creds.appId, opts.creds.clientSecret);
|
|
5513
|
-
return this.client.request(token, "POST",
|
|
5513
|
+
return this.client.request(token, "POST", path21, {
|
|
5514
5514
|
upload_id: uploadId,
|
|
5515
5515
|
part_index: partIndex,
|
|
5516
5516
|
block_size: blockSize,
|
|
@@ -5519,10 +5519,10 @@ var ChunkedMediaApi = class {
|
|
|
5519
5519
|
}, PART_FINISH_RETRY_POLICY, persistentPolicy, this.logger);
|
|
5520
5520
|
}
|
|
5521
5521
|
async callCompleteUpload(opts, uploadId) {
|
|
5522
|
-
const
|
|
5522
|
+
const path21 = uploadCompletePath(opts.scope, opts.targetId);
|
|
5523
5523
|
return withRetry(async () => {
|
|
5524
5524
|
const token = await this.tokenManager.getAccessToken(opts.creds.appId, opts.creds.clientSecret);
|
|
5525
|
-
return this.client.request(token, "POST",
|
|
5525
|
+
return this.client.request(token, "POST", path21, { upload_id: uploadId }, { uploadRequest: true });
|
|
5526
5526
|
}, COMPLETE_UPLOAD_RETRY_POLICY, void 0, this.logger);
|
|
5527
5527
|
}
|
|
5528
5528
|
};
|
|
@@ -5598,7 +5598,7 @@ var PART_UPLOAD_MAX_RETRIES = 2;
|
|
|
5598
5598
|
function putToCOS(presignedUrl, data, signal) {
|
|
5599
5599
|
return new Promise((resolve2, reject) => {
|
|
5600
5600
|
const parsed = new URL(presignedUrl);
|
|
5601
|
-
const
|
|
5601
|
+
const req4 = https.request(parsed, {
|
|
5602
5602
|
method: "PUT",
|
|
5603
5603
|
headers: { "Content-Length": String(data.length) },
|
|
5604
5604
|
signal
|
|
@@ -5616,10 +5616,10 @@ function putToCOS(presignedUrl, data, signal) {
|
|
|
5616
5616
|
});
|
|
5617
5617
|
res.on("error", reject);
|
|
5618
5618
|
});
|
|
5619
|
-
|
|
5619
|
+
req4.on("error", (err) => {
|
|
5620
5620
|
reject(err);
|
|
5621
5621
|
});
|
|
5622
|
-
|
|
5622
|
+
req4.end(data);
|
|
5623
5623
|
});
|
|
5624
5624
|
}
|
|
5625
5625
|
async function putToPresignedUrl(presignedUrl, data, partIndex, totalParts, logger, prefix) {
|
|
@@ -5716,8 +5716,8 @@ var MediaApi = class {
|
|
|
5716
5716
|
body.file_name = this.sanitize(opts.fileName);
|
|
5717
5717
|
}
|
|
5718
5718
|
const token = await this.tokenManager.getAccessToken(creds.appId, creds.clientSecret);
|
|
5719
|
-
const
|
|
5720
|
-
const result = await withRetry(() => this.client.request(token, "POST",
|
|
5719
|
+
const path21 = mediaUploadPath(scope, targetId);
|
|
5720
|
+
const result = await withRetry(() => this.client.request(token, "POST", path21, body, {
|
|
5721
5721
|
redactBodyKeys: ["file_data"],
|
|
5722
5722
|
uploadRequest: true
|
|
5723
5723
|
}), UPLOAD_RETRY_POLICY, void 0, this.logger);
|
|
@@ -5733,8 +5733,8 @@ var MediaApi = class {
|
|
|
5733
5733
|
async sendMediaMessage(scope, targetId, fileInfo, creds, opts) {
|
|
5734
5734
|
const token = await this.tokenManager.getAccessToken(creds.appId, creds.clientSecret);
|
|
5735
5735
|
const msgSeq = opts?.msgId ? getNextMsgSeq(opts.msgId) : 1;
|
|
5736
|
-
const
|
|
5737
|
-
return this.client.request(token, "POST",
|
|
5736
|
+
const path21 = messagePath(scope, targetId);
|
|
5737
|
+
return this.client.request(token, "POST", path21, {
|
|
5738
5738
|
msg_type: 7,
|
|
5739
5739
|
media: { file_info: fileInfo },
|
|
5740
5740
|
msg_seq: msgSeq,
|
|
@@ -5773,8 +5773,8 @@ var MessageApi = class {
|
|
|
5773
5773
|
const token = await this.tokenManager.getAccessToken(creds.appId, creds.clientSecret);
|
|
5774
5774
|
const msgSeq = opts?.msgId ? getNextMsgSeq(opts.msgId) : 1;
|
|
5775
5775
|
const body = this.buildMessageBody(content, opts?.msgId, msgSeq, opts?.messageReference, opts?.inlineKeyboard);
|
|
5776
|
-
const
|
|
5777
|
-
return this.sendAndNotify(creds.appId, token, "POST",
|
|
5776
|
+
const path21 = messagePath(scope, targetId);
|
|
5777
|
+
return this.sendAndNotify(creds.appId, token, "POST", path21, body, { text: content });
|
|
5778
5778
|
}
|
|
5779
5779
|
async sendProactiveMessage(scope, targetId, content, creds) {
|
|
5780
5780
|
if (!content?.trim()) {
|
|
@@ -5782,8 +5782,8 @@ var MessageApi = class {
|
|
|
5782
5782
|
}
|
|
5783
5783
|
const token = await this.tokenManager.getAccessToken(creds.appId, creds.clientSecret);
|
|
5784
5784
|
const body = this.buildProactiveBody(content);
|
|
5785
|
-
const
|
|
5786
|
-
return this.sendAndNotify(creds.appId, token, "POST",
|
|
5785
|
+
const path21 = messagePath(scope, targetId);
|
|
5786
|
+
return this.sendAndNotify(creds.appId, token, "POST", path21, body, { text: content });
|
|
5787
5787
|
}
|
|
5788
5788
|
async sendChannelMessage(opts) {
|
|
5789
5789
|
const token = await this.tokenManager.getAccessToken(opts.creds.appId, opts.creds.clientSecret);
|
|
@@ -5829,23 +5829,23 @@ var MessageApi = class {
|
|
|
5829
5829
|
* Send a C2C stream message chunk (`/v2/users/{openid}/stream_messages`).
|
|
5830
5830
|
* Only supported for one-to-one chats.
|
|
5831
5831
|
*/
|
|
5832
|
-
async sendC2CStreamMessage(creds, openid,
|
|
5832
|
+
async sendC2CStreamMessage(creds, openid, req4) {
|
|
5833
5833
|
const token = await this.tokenManager.getAccessToken(creds.appId, creds.clientSecret);
|
|
5834
|
-
const
|
|
5834
|
+
const path21 = streamMessagePath(openid);
|
|
5835
5835
|
const body = {
|
|
5836
|
-
input_mode:
|
|
5837
|
-
input_state:
|
|
5838
|
-
content_type:
|
|
5839
|
-
content_raw:
|
|
5840
|
-
event_id:
|
|
5841
|
-
msg_id:
|
|
5842
|
-
msg_seq:
|
|
5843
|
-
index:
|
|
5836
|
+
input_mode: req4.input_mode,
|
|
5837
|
+
input_state: req4.input_state,
|
|
5838
|
+
content_type: req4.content_type,
|
|
5839
|
+
content_raw: req4.content_raw,
|
|
5840
|
+
event_id: req4.event_id,
|
|
5841
|
+
msg_id: req4.msg_id,
|
|
5842
|
+
msg_seq: req4.msg_seq,
|
|
5843
|
+
index: req4.index
|
|
5844
5844
|
};
|
|
5845
|
-
if (
|
|
5846
|
-
body.stream_msg_id =
|
|
5845
|
+
if (req4.stream_msg_id) {
|
|
5846
|
+
body.stream_msg_id = req4.stream_msg_id;
|
|
5847
5847
|
}
|
|
5848
|
-
return this.client.request(token, "POST",
|
|
5848
|
+
return this.client.request(token, "POST", path21, body);
|
|
5849
5849
|
}
|
|
5850
5850
|
/**
|
|
5851
5851
|
* Raw message send — transparently forwards all fields to the QQ Open Platform API.
|
|
@@ -5859,7 +5859,7 @@ var MessageApi = class {
|
|
|
5859
5859
|
*/
|
|
5860
5860
|
async sendRaw(scope, targetId, creds, body) {
|
|
5861
5861
|
const token = await this.tokenManager.getAccessToken(creds.appId, creds.clientSecret);
|
|
5862
|
-
const
|
|
5862
|
+
const path21 = messagePath(scope, targetId);
|
|
5863
5863
|
if (body.msg_seq === void 0) {
|
|
5864
5864
|
body.msg_seq = body.msg_id ? getNextMsgSeq(body.msg_id) : 1;
|
|
5865
5865
|
}
|
|
@@ -5876,7 +5876,7 @@ var MessageApi = class {
|
|
|
5876
5876
|
body.msg_type = 0;
|
|
5877
5877
|
}
|
|
5878
5878
|
const cleaned = Object.fromEntries(Object.entries(body).filter(([, v]) => v !== void 0));
|
|
5879
|
-
return this.sendAndNotify(creds.appId, token, "POST",
|
|
5879
|
+
return this.sendAndNotify(creds.appId, token, "POST", path21, cleaned, { text: cleaned.content ?? cleaned.markdown?.content });
|
|
5880
5880
|
}
|
|
5881
5881
|
/**
|
|
5882
5882
|
* Send a message to a guild text channel.
|
|
@@ -5900,11 +5900,11 @@ var MessageApi = class {
|
|
|
5900
5900
|
*/
|
|
5901
5901
|
async recallMessage(scope, targetId, messageId, creds) {
|
|
5902
5902
|
const token = await this.tokenManager.getAccessToken(creds.appId, creds.clientSecret);
|
|
5903
|
-
const
|
|
5904
|
-
await this.client.request(token, "DELETE",
|
|
5903
|
+
const path21 = `${messagePath(scope, targetId)}/${messageId}`;
|
|
5904
|
+
await this.client.request(token, "DELETE", path21);
|
|
5905
5905
|
}
|
|
5906
|
-
async sendAndNotify(_appId, accessToken, method,
|
|
5907
|
-
const result = await this.client.request(accessToken, method,
|
|
5906
|
+
async sendAndNotify(_appId, accessToken, method, path21, body, meta) {
|
|
5907
|
+
const result = await this.client.request(accessToken, method, path21, body);
|
|
5908
5908
|
if (result.ext_info?.ref_idx && this.messageSentHook) {
|
|
5909
5909
|
try {
|
|
5910
5910
|
this.messageSentHook(result.ext_info.ref_idx, meta);
|
|
@@ -6785,21 +6785,21 @@ function signValidationResponse(params) {
|
|
|
6785
6785
|
var http = __toESM(require("http"), 1);
|
|
6786
6786
|
var NodeHttpWebhookServer = class {
|
|
6787
6787
|
server = null;
|
|
6788
|
-
async listen(port,
|
|
6788
|
+
async listen(port, path21, handler) {
|
|
6789
6789
|
return new Promise((resolve2, reject) => {
|
|
6790
|
-
const server = http.createServer(async (
|
|
6791
|
-
if (
|
|
6790
|
+
const server = http.createServer(async (req4, res) => {
|
|
6791
|
+
if (req4.method !== "POST" || req4.url !== path21) {
|
|
6792
6792
|
res.writeHead(404, { "Content-Type": "text/plain" });
|
|
6793
6793
|
res.end("Not Found");
|
|
6794
6794
|
return;
|
|
6795
6795
|
}
|
|
6796
6796
|
const chunks = [];
|
|
6797
|
-
|
|
6798
|
-
|
|
6797
|
+
req4.on("data", (chunk) => chunks.push(chunk));
|
|
6798
|
+
req4.on("end", async () => {
|
|
6799
6799
|
try {
|
|
6800
6800
|
const body = Buffer.concat(chunks);
|
|
6801
6801
|
const headers = {};
|
|
6802
|
-
for (const [key, value] of Object.entries(
|
|
6802
|
+
for (const [key, value] of Object.entries(req4.headers)) {
|
|
6803
6803
|
headers[key.toLowerCase()] = value;
|
|
6804
6804
|
}
|
|
6805
6805
|
const response = await handler({ body, headers });
|
|
@@ -6850,11 +6850,11 @@ var WebhookTransport = class {
|
|
|
6850
6850
|
}
|
|
6851
6851
|
async start() {
|
|
6852
6852
|
const port = this.opts.port ?? 8080;
|
|
6853
|
-
const
|
|
6854
|
-
this.log?.info?.(`[webhook] starting on port ${port}, path ${
|
|
6855
|
-
await this.server.listen(port,
|
|
6856
|
-
this.log?.info?.(`[webhook] listening on :${port}${
|
|
6857
|
-
this.callbacks.onReady?.({ transport: "webhook", port, path:
|
|
6853
|
+
const path21 = this.opts.path ?? "/";
|
|
6854
|
+
this.log?.info?.(`[webhook] starting on port ${port}, path ${path21}`);
|
|
6855
|
+
await this.server.listen(port, path21, (req4) => this.handleRequest(req4));
|
|
6856
|
+
this.log?.info?.(`[webhook] listening on :${port}${path21}`);
|
|
6857
|
+
this.callbacks.onReady?.({ transport: "webhook", port, path: path21 });
|
|
6858
6858
|
if (this.opts.abortSignal) {
|
|
6859
6859
|
await new Promise((resolve2) => {
|
|
6860
6860
|
if (this.opts.abortSignal.aborted) {
|
|
@@ -6879,10 +6879,10 @@ var WebhookTransport = class {
|
|
|
6879
6879
|
this.stopResolve?.();
|
|
6880
6880
|
}
|
|
6881
6881
|
// ============ Request handler ============
|
|
6882
|
-
async handleRequest(
|
|
6882
|
+
async handleRequest(req4) {
|
|
6883
6883
|
let payload;
|
|
6884
6884
|
try {
|
|
6885
|
-
payload = JSON.parse(
|
|
6885
|
+
payload = JSON.parse(req4.body.toString("utf-8"));
|
|
6886
6886
|
} catch {
|
|
6887
6887
|
this.log?.warn?.(`[webhook] invalid JSON body`);
|
|
6888
6888
|
return { status: 400, body: JSON.stringify({ error: "invalid json" }) };
|
|
@@ -6890,14 +6890,14 @@ var WebhookTransport = class {
|
|
|
6890
6890
|
if (payload.op === OP_VALIDATION) {
|
|
6891
6891
|
return this.handleValidation(payload);
|
|
6892
6892
|
}
|
|
6893
|
-
const timestamp = getHeader(
|
|
6894
|
-
const signature = getHeader(
|
|
6893
|
+
const timestamp = getHeader(req4.headers, "x-signature-timestamp") ?? "";
|
|
6894
|
+
const signature = getHeader(req4.headers, "x-signature-ed25519") ?? "";
|
|
6895
6895
|
if (!timestamp || !signature) {
|
|
6896
6896
|
this.log?.warn?.(`[webhook] missing signature headers`);
|
|
6897
6897
|
return { status: 401, body: JSON.stringify({ error: "missing signature" }) };
|
|
6898
6898
|
}
|
|
6899
6899
|
const valid = verifyWebhookSignature({
|
|
6900
|
-
body:
|
|
6900
|
+
body: req4.body,
|
|
6901
6901
|
timestamp,
|
|
6902
6902
|
signature,
|
|
6903
6903
|
botSecret: this.opts.appSecret
|
|
@@ -7161,7 +7161,7 @@ var StreamSession = class {
|
|
|
7161
7161
|
this.msgSeq = getNextMsgSeq(this.opts.msgId);
|
|
7162
7162
|
}
|
|
7163
7163
|
const currentIndex = this.index++;
|
|
7164
|
-
const
|
|
7164
|
+
const req4 = {
|
|
7165
7165
|
input_mode: StreamInputMode.REPLACE,
|
|
7166
7166
|
input_state: state,
|
|
7167
7167
|
content_type: StreamContentType.MARKDOWN,
|
|
@@ -7172,9 +7172,9 @@ var StreamSession = class {
|
|
|
7172
7172
|
index: currentIndex
|
|
7173
7173
|
};
|
|
7174
7174
|
if (this.streamMsgId) {
|
|
7175
|
-
|
|
7175
|
+
req4.stream_msg_id = this.streamMsgId;
|
|
7176
7176
|
}
|
|
7177
|
-
const resp = await this.sendWithRetry(
|
|
7177
|
+
const resp = await this.sendWithRetry(req4);
|
|
7178
7178
|
if (resp?.id && !this.streamMsgId) {
|
|
7179
7179
|
this.streamMsgId = resp.id;
|
|
7180
7180
|
}
|
|
@@ -7196,10 +7196,10 @@ var StreamSession = class {
|
|
|
7196
7196
|
* Send a stream message with exponential backoff on rate-limit errors.
|
|
7197
7197
|
* QQ returns err_code 50002 or HTTP 429 when rate-limited.
|
|
7198
7198
|
*/
|
|
7199
|
-
async sendWithRetry(
|
|
7199
|
+
async sendWithRetry(req4) {
|
|
7200
7200
|
for (let attempt = 0; attempt <= MAX_FLUSH_RETRIES; attempt++) {
|
|
7201
7201
|
try {
|
|
7202
|
-
return await this.api.sendC2CStreamMessage(this.opts.creds, this.opts.openid,
|
|
7202
|
+
return await this.api.sendC2CStreamMessage(this.opts.creds, this.opts.openid, req4);
|
|
7203
7203
|
} catch (err) {
|
|
7204
7204
|
if (!this.isRateLimitError(err) || attempt >= MAX_FLUSH_RETRIES) {
|
|
7205
7205
|
throw err;
|
|
@@ -7207,7 +7207,7 @@ var StreamSession = class {
|
|
|
7207
7207
|
const delay = RATE_LIMIT_BASE_DELAY_MS * Math.pow(2, attempt);
|
|
7208
7208
|
this.opts.logger?.debug?.(`[qqbot:stream] rate limited, retry ${attempt + 1}/${MAX_FLUSH_RETRIES} after ${delay}ms`);
|
|
7209
7209
|
await new Promise((r) => setTimeout(r, delay));
|
|
7210
|
-
|
|
7210
|
+
req4.index = this.index++;
|
|
7211
7211
|
}
|
|
7212
7212
|
}
|
|
7213
7213
|
return void 0;
|
|
@@ -7744,25 +7744,25 @@ var QQBot = class {
|
|
|
7744
7744
|
if (this._apiGateway)
|
|
7745
7745
|
return this._apiGateway;
|
|
7746
7746
|
this._apiGateway = {
|
|
7747
|
-
get: (
|
|
7748
|
-
post: (
|
|
7749
|
-
put: (
|
|
7750
|
-
patch: (
|
|
7751
|
-
delete: (
|
|
7747
|
+
get: (path21, query) => this.apiRequest("GET", path21, void 0, query),
|
|
7748
|
+
post: (path21, body) => this.apiRequest("POST", path21, body),
|
|
7749
|
+
put: (path21, body) => this.apiRequest("PUT", path21, body),
|
|
7750
|
+
patch: (path21, body) => this.apiRequest("PATCH", path21, body),
|
|
7751
|
+
delete: (path21) => this.apiRequest("DELETE", path21),
|
|
7752
7752
|
getToken: () => this.tokenManager.getAccessToken(this.creds.appId, this.creds.clientSecret)
|
|
7753
7753
|
};
|
|
7754
7754
|
return this._apiGateway;
|
|
7755
7755
|
}
|
|
7756
|
-
async apiRequest(method,
|
|
7756
|
+
async apiRequest(method, path21, body, query) {
|
|
7757
7757
|
const token = await this.tokenManager.getAccessToken(this.creds.appId, this.creds.clientSecret);
|
|
7758
|
-
let fullPath =
|
|
7758
|
+
let fullPath = path21;
|
|
7759
7759
|
if (query && Object.keys(query).length > 0) {
|
|
7760
7760
|
const params = new URLSearchParams();
|
|
7761
7761
|
for (const [k, v] of Object.entries(query)) {
|
|
7762
7762
|
if (v !== void 0 && v !== null)
|
|
7763
7763
|
params.set(k, String(v));
|
|
7764
7764
|
}
|
|
7765
|
-
fullPath = `${
|
|
7765
|
+
fullPath = `${path21}?${params.toString()}`;
|
|
7766
7766
|
}
|
|
7767
7767
|
return this.apiClient.request(token, method, fullPath, body ?? void 0);
|
|
7768
7768
|
}
|
|
@@ -9089,69 +9089,73 @@ function formatError(err) {
|
|
|
9089
9089
|
}
|
|
9090
9090
|
|
|
9091
9091
|
// src/utils/pkg-version.ts
|
|
9092
|
-
var import_node_url = require("url");
|
|
9093
|
-
var import_node_module = require("module");
|
|
9094
9092
|
var import_node_path2 = __toESM(require("path"), 1);
|
|
9095
9093
|
var import_node_fs2 = __toESM(require("fs"), 1);
|
|
9096
|
-
var
|
|
9097
|
-
function
|
|
9098
|
-
|
|
9099
|
-
return (0, import_node_url.fileURLToPath)(metaUrl);
|
|
9100
|
-
}
|
|
9101
|
-
if (typeof __filename !== "undefined") {
|
|
9102
|
-
return __filename;
|
|
9103
|
-
}
|
|
9104
|
-
return process.cwd();
|
|
9094
|
+
var _cachedOpenclawVersion;
|
|
9095
|
+
function getPackageVersion() {
|
|
9096
|
+
return true ? "2.0.0-dev.202607082219" : "unknown";
|
|
9105
9097
|
}
|
|
9106
|
-
function
|
|
9107
|
-
if (
|
|
9108
|
-
|
|
9109
|
-
|
|
9110
|
-
if (pkg.name === "@tencent-connect/openclaw-qqbot" && pkg.version) {
|
|
9111
|
-
return pkg.version;
|
|
9112
|
-
}
|
|
9113
|
-
} catch {
|
|
9114
|
-
_resolvedPkgPath = null;
|
|
9115
|
-
}
|
|
9098
|
+
function getOpenclawVersion(runtimeVersion) {
|
|
9099
|
+
if (_cachedOpenclawVersion) return _cachedOpenclawVersion;
|
|
9100
|
+
if (runtimeVersion && runtimeVersion !== "unknown") {
|
|
9101
|
+
return _cachedOpenclawVersion = runtimeVersion;
|
|
9116
9102
|
}
|
|
9117
|
-
|
|
9118
|
-
|
|
9119
|
-
|
|
9120
|
-
|
|
9121
|
-
|
|
9122
|
-
try {
|
|
9123
|
-
if (import_node_fs2.default.existsSync(candidate)) {
|
|
9124
|
-
const pkg = JSON.parse(import_node_fs2.default.readFileSync(candidate, "utf8"));
|
|
9125
|
-
if (pkg.name === "@tencent-connect/openclaw-qqbot" && pkg.version) {
|
|
9126
|
-
_resolvedPkgPath = candidate;
|
|
9127
|
-
return pkg.version;
|
|
9128
|
-
}
|
|
9129
|
-
}
|
|
9130
|
-
} catch {
|
|
9131
|
-
}
|
|
9132
|
-
dir = import_node_path2.default.dirname(dir);
|
|
9103
|
+
if (process.env.OPENCLAW_VERSION) {
|
|
9104
|
+
return _cachedOpenclawVersion = process.env.OPENCLAW_VERSION;
|
|
9105
|
+
}
|
|
9106
|
+
if (process.env.OPENCLAW_SERVICE_VERSION) {
|
|
9107
|
+
return _cachedOpenclawVersion = process.env.OPENCLAW_SERVICE_VERSION;
|
|
9133
9108
|
}
|
|
9109
|
+
const pkgVer = readOpenclawPackageVersion();
|
|
9110
|
+
if (pkgVer) return _cachedOpenclawVersion = pkgVer;
|
|
9111
|
+
return "unknown";
|
|
9112
|
+
}
|
|
9113
|
+
function readOpenclawPackageVersion() {
|
|
9134
9114
|
try {
|
|
9135
|
-
const
|
|
9136
|
-
for (const
|
|
9115
|
+
const dirs = searchRoots();
|
|
9116
|
+
for (const dir of dirs) {
|
|
9117
|
+
const pkgPath = import_node_path2.default.join(dir, "package.json");
|
|
9137
9118
|
try {
|
|
9138
|
-
const pkg =
|
|
9139
|
-
if (pkg
|
|
9140
|
-
return pkg.version;
|
|
9141
|
-
}
|
|
9119
|
+
const pkg = JSON.parse(import_node_fs2.default.readFileSync(pkgPath, "utf8"));
|
|
9120
|
+
if (pkg.name === "openclaw" && pkg.version) return pkg.version;
|
|
9142
9121
|
} catch {
|
|
9143
9122
|
}
|
|
9144
9123
|
}
|
|
9145
9124
|
} catch {
|
|
9146
9125
|
}
|
|
9147
|
-
return
|
|
9126
|
+
return void 0;
|
|
9127
|
+
}
|
|
9128
|
+
function searchRoots() {
|
|
9129
|
+
const roots = [];
|
|
9130
|
+
if (typeof __filename === "string") {
|
|
9131
|
+
let dir = import_node_path2.default.dirname(__filename);
|
|
9132
|
+
for (let i = 0; i < 10; i++) {
|
|
9133
|
+
roots.push(dir);
|
|
9134
|
+
const parent = import_node_path2.default.dirname(dir);
|
|
9135
|
+
if (parent === dir) break;
|
|
9136
|
+
dir = parent;
|
|
9137
|
+
}
|
|
9138
|
+
}
|
|
9139
|
+
for (const key of ["OPENCLAW_STATE_DIR", "CLAWDBOT_STATE_DIR", "MOLTBOT_STATE_DIR"]) {
|
|
9140
|
+
const v = process.env[key];
|
|
9141
|
+
if (v) {
|
|
9142
|
+
roots.push(import_node_path2.default.dirname(v));
|
|
9143
|
+
roots.push(import_node_path2.default.resolve(v, ".."));
|
|
9144
|
+
}
|
|
9145
|
+
}
|
|
9146
|
+
const home = process.env.HOME || process.env.USERPROFILE || "/tmp";
|
|
9147
|
+
for (const name of ["openclaw", "clawdbot", "moltbot"]) {
|
|
9148
|
+
roots.push(import_node_path2.default.join(home, `.${name}`));
|
|
9149
|
+
}
|
|
9150
|
+
roots.push(process.cwd());
|
|
9151
|
+
return [...new Set(roots.filter((r) => typeof r === "string" && r.length > 0))];
|
|
9148
9152
|
}
|
|
9149
9153
|
|
|
9150
9154
|
// src/bot-instance.ts
|
|
9151
9155
|
var PLUGIN_VERSION = getPackageVersion();
|
|
9152
9156
|
var _openclawVersion = "unknown";
|
|
9153
9157
|
function setOpenClawVersion(version) {
|
|
9154
|
-
_openclawVersion = version;
|
|
9158
|
+
if (version) _openclawVersion = version;
|
|
9155
9159
|
}
|
|
9156
9160
|
function getOpenClawVersion() {
|
|
9157
9161
|
return _openclawVersion;
|
|
@@ -9471,7 +9475,8 @@ var runtime = null;
|
|
|
9471
9475
|
var exitHooksInstalled = false;
|
|
9472
9476
|
function setQQBotRuntime(next) {
|
|
9473
9477
|
runtime = next;
|
|
9474
|
-
|
|
9478
|
+
const version = getOpenclawVersion(next.version);
|
|
9479
|
+
setOpenClawVersion(version);
|
|
9475
9480
|
installExitHooksOnce();
|
|
9476
9481
|
}
|
|
9477
9482
|
function installExitHooksOnce() {
|
|
@@ -9501,14 +9506,14 @@ function tryGetQQBotRuntime() {
|
|
|
9501
9506
|
return runtime;
|
|
9502
9507
|
}
|
|
9503
9508
|
|
|
9504
|
-
// src/
|
|
9509
|
+
// src/adapter/resolve.ts
|
|
9505
9510
|
function probeFunction(rt, paths) {
|
|
9506
|
-
for (const
|
|
9511
|
+
for (const path21 of paths) {
|
|
9507
9512
|
let target = rt;
|
|
9508
9513
|
let parent = rt;
|
|
9509
|
-
for (let i = 0; i <
|
|
9514
|
+
for (let i = 0; i < path21.length; i++) {
|
|
9510
9515
|
parent = target;
|
|
9511
|
-
target = target?.[
|
|
9516
|
+
target = target?.[path21[i]];
|
|
9512
9517
|
if (target === void 0 || target === null) break;
|
|
9513
9518
|
}
|
|
9514
9519
|
if (typeof target === "function") {
|
|
@@ -9578,7 +9583,7 @@ function resolveRuntimeAdapters(rt, log4) {
|
|
|
9578
9583
|
const chunkMarkdownText = probeFunction(rt, [
|
|
9579
9584
|
["channel", "text", "chunkMarkdownText"]
|
|
9580
9585
|
]);
|
|
9581
|
-
const
|
|
9586
|
+
const saveRemoteMedia = probeFunction(rt, [
|
|
9582
9587
|
["channel", "media", "saveRemoteMedia"]
|
|
9583
9588
|
]);
|
|
9584
9589
|
const getConfig = probeFunction(rt, [
|
|
@@ -9607,7 +9612,7 @@ function resolveRuntimeAdapters(rt, log4) {
|
|
|
9607
9612
|
recordInboundSession && "recordInboundSession",
|
|
9608
9613
|
formatEnvelope && "formatEnvelope",
|
|
9609
9614
|
chunkMarkdownText && "chunkMarkdownText",
|
|
9610
|
-
|
|
9615
|
+
saveRemoteMedia && "saveRemoteMedia",
|
|
9611
9616
|
getConfig && "getConfig",
|
|
9612
9617
|
persistConfig && `persistConfig(${rawMutateConfig ? "mutate" : "write"})`
|
|
9613
9618
|
].filter(Boolean);
|
|
@@ -9624,7 +9629,7 @@ function resolveRuntimeAdapters(rt, log4) {
|
|
|
9624
9629
|
formatEnvelope,
|
|
9625
9630
|
resolveEnvelopeFormatOptions,
|
|
9626
9631
|
chunkMarkdownText,
|
|
9627
|
-
saveRemoteMedia
|
|
9632
|
+
saveRemoteMedia,
|
|
9628
9633
|
getConfig,
|
|
9629
9634
|
persistConfig,
|
|
9630
9635
|
version
|
|
@@ -9646,7 +9651,24 @@ function getAdapters(rt, log4) {
|
|
|
9646
9651
|
var path8 = __toESM(require("path"), 1);
|
|
9647
9652
|
var fs9 = __toESM(require("fs"), 1);
|
|
9648
9653
|
var os4 = __toESM(require("os"), 1);
|
|
9649
|
-
|
|
9654
|
+
|
|
9655
|
+
// src/adapter/workspace.ts
|
|
9656
|
+
var import_node_module = require("module");
|
|
9657
|
+
var req = (0, import_node_module.createRequire)(__filename);
|
|
9658
|
+
var health = null;
|
|
9659
|
+
function resolveAgentWorkspace(cfg, agentId) {
|
|
9660
|
+
if (!health) {
|
|
9661
|
+
try {
|
|
9662
|
+
health = req("openclaw/plugin-sdk/health");
|
|
9663
|
+
} catch {
|
|
9664
|
+
health = null;
|
|
9665
|
+
}
|
|
9666
|
+
}
|
|
9667
|
+
if (health) {
|
|
9668
|
+
return health.resolveAgentWorkspaceDir(cfg, agentId ?? health.resolveDefaultAgentId(cfg));
|
|
9669
|
+
}
|
|
9670
|
+
return getQQBotMediaDir();
|
|
9671
|
+
}
|
|
9650
9672
|
|
|
9651
9673
|
// src/outbound/local-file-router.ts
|
|
9652
9674
|
var path7 = __toESM(require("path"), 1);
|
|
@@ -9774,11 +9796,7 @@ function resolveMediaPath(source, log4, workspaceDir) {
|
|
|
9774
9796
|
function resolveWorkspaceFromAgent(agentId) {
|
|
9775
9797
|
const cfg = resolveConfigViaAdapter();
|
|
9776
9798
|
if (!cfg) return void 0;
|
|
9777
|
-
|
|
9778
|
-
return (0, import_health.resolveAgentWorkspaceDir)(cfg, agentId ?? (0, import_health.resolveDefaultAgentId)(cfg));
|
|
9779
|
-
} catch {
|
|
9780
|
-
return void 0;
|
|
9781
|
-
}
|
|
9799
|
+
return resolveAgentWorkspace(cfg, agentId);
|
|
9782
9800
|
}
|
|
9783
9801
|
function resolveConfigViaAdapter() {
|
|
9784
9802
|
try {
|
|
@@ -9867,12 +9885,48 @@ function formatErr(err) {
|
|
|
9867
9885
|
return String(err);
|
|
9868
9886
|
}
|
|
9869
9887
|
|
|
9870
|
-
// src/setup
|
|
9871
|
-
var
|
|
9872
|
-
|
|
9873
|
-
|
|
9874
|
-
var
|
|
9875
|
-
|
|
9888
|
+
// src/adapter/setup.ts
|
|
9889
|
+
var import_node_module2 = require("module");
|
|
9890
|
+
var req2 = (0, import_node_module2.createRequire)(__filename);
|
|
9891
|
+
var _setup;
|
|
9892
|
+
var _tools;
|
|
9893
|
+
function loadSetup() {
|
|
9894
|
+
if (_setup !== void 0) return _setup;
|
|
9895
|
+
try {
|
|
9896
|
+
_setup = req2("openclaw/plugin-sdk/setup");
|
|
9897
|
+
} catch {
|
|
9898
|
+
_setup = null;
|
|
9899
|
+
}
|
|
9900
|
+
return _setup;
|
|
9901
|
+
}
|
|
9902
|
+
function loadTools() {
|
|
9903
|
+
if (_tools !== void 0) return _tools;
|
|
9904
|
+
try {
|
|
9905
|
+
_tools = req2("openclaw/plugin-sdk/setup-tools");
|
|
9906
|
+
} catch {
|
|
9907
|
+
_tools = null;
|
|
9908
|
+
}
|
|
9909
|
+
return _tools;
|
|
9910
|
+
}
|
|
9911
|
+
var DEFAULT_ACCOUNT_ID2 = "default";
|
|
9912
|
+
function createStandardChannelSetupStatus(...args) {
|
|
9913
|
+
const mod = loadSetup();
|
|
9914
|
+
if (mod) return mod.createStandardChannelSetupStatus(...args);
|
|
9915
|
+
return {
|
|
9916
|
+
channelLabel: args[0]?.channelLabel ?? "QQ Bot",
|
|
9917
|
+
configuredLabel: "Configured",
|
|
9918
|
+
unconfiguredLabel: "Not configured",
|
|
9919
|
+
resolveConfigured: () => false
|
|
9920
|
+
};
|
|
9921
|
+
}
|
|
9922
|
+
function setSetupChannelEnabled(...args) {
|
|
9923
|
+
loadSetup()?.setSetupChannelEnabled?.(...args);
|
|
9924
|
+
}
|
|
9925
|
+
function formatDocsLink(...args) {
|
|
9926
|
+
const mod = loadTools();
|
|
9927
|
+
if (mod) return mod.formatDocsLink(...args);
|
|
9928
|
+
return args[1] ? `${args[1]}: ${args[0]}` : args[0];
|
|
9929
|
+
}
|
|
9876
9930
|
|
|
9877
9931
|
// node_modules/.pnpm/@tencent-connect+qqbot-connector@1.2.0/node_modules/@tencent-connect/qqbot-connector/dist/esm/qr-connect.js
|
|
9878
9932
|
var import_qrcode_terminal = __toESM(require_main(), 1);
|
|
@@ -10039,7 +10093,7 @@ async function linkViaQrCode(cfg, accountId, prompter, rt) {
|
|
|
10039
10093
|
} catch (err) {
|
|
10040
10094
|
rt.error(`QQ Bot \u7ED1\u5B9A\u5931\u8D25: ${String(err)}`);
|
|
10041
10095
|
await prompter.note(`\u7ED1\u5B9A\u5931\u8D25\uFF0C\u60A8\u53EF\u4EE5\u7A0D\u540E\u624B\u52A8\u914D\u7F6E\u3002
|
|
10042
|
-
\u6587\u6863: ${
|
|
10096
|
+
\u6587\u6863: ${formatDocsLink("/channels/qqbot", "qqbot")}`, "QQ Bot");
|
|
10043
10097
|
return cfg;
|
|
10044
10098
|
}
|
|
10045
10099
|
}
|
|
@@ -10052,7 +10106,7 @@ async function linkViaManual(cfg, prompter) {
|
|
|
10052
10106
|
return next;
|
|
10053
10107
|
}
|
|
10054
10108
|
async function finalizeQQBotSetup(params) {
|
|
10055
|
-
const accountId = params.accountId.trim() ||
|
|
10109
|
+
const accountId = params.accountId.trim() || DEFAULT_ACCOUNT_ID2;
|
|
10056
10110
|
const configured = isConfigured(params.cfg, accountId);
|
|
10057
10111
|
const mode = await params.prompter.select({
|
|
10058
10112
|
message: configured ? "QQ \u5DF2\u7ED1\u5B9A\uFF0C\u9009\u62E9\u64CD\u4F5C" : "\u9009\u62E9 QQ \u7ED1\u5B9A\u65B9\u5F0F",
|
|
@@ -10077,7 +10131,7 @@ function applyAccountDefaults(cfg, accountId, userOpenid) {
|
|
|
10077
10131
|
const qqbot = { ...next.channels?.qqbot ?? {} };
|
|
10078
10132
|
const defaults = { streaming: true, dmPolicy: "allowlist" };
|
|
10079
10133
|
if (userOpenid) defaults.allowFrom = [userOpenid];
|
|
10080
|
-
if (accountId ===
|
|
10134
|
+
if (accountId === DEFAULT_ACCOUNT_ID2) {
|
|
10081
10135
|
Object.assign(qqbot, defaults);
|
|
10082
10136
|
} else {
|
|
10083
10137
|
const accounts = { ...qqbot.accounts ?? {} };
|
|
@@ -10089,11 +10143,10 @@ function applyAccountDefaults(cfg, accountId, userOpenid) {
|
|
|
10089
10143
|
}
|
|
10090
10144
|
|
|
10091
10145
|
// src/setup/surface.ts
|
|
10092
|
-
var import_setup3 = require("openclaw/plugin-sdk/setup");
|
|
10093
10146
|
var CHANNEL = "qqbot";
|
|
10094
10147
|
var qqbotSetupWizard = {
|
|
10095
10148
|
channel: CHANNEL,
|
|
10096
|
-
status:
|
|
10149
|
+
status: createStandardChannelSetupStatus({
|
|
10097
10150
|
channelLabel: "QQ Bot",
|
|
10098
10151
|
configuredLabel: "configured",
|
|
10099
10152
|
unconfiguredLabel: "needs AppID + AppSecret",
|
|
@@ -10109,7 +10162,10 @@ var qqbotSetupWizard = {
|
|
|
10109
10162
|
credentials: [],
|
|
10110
10163
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
10111
10164
|
finalize: (async ({ cfg, accountId, prompter, runtime: runtime2 }) => finalizeQQBotSetup({ cfg, accountId, prompter, runtime: runtime2 })),
|
|
10112
|
-
disable: (cfg) =>
|
|
10165
|
+
disable: (cfg) => {
|
|
10166
|
+
setSetupChannelEnabled(cfg, CHANNEL, false);
|
|
10167
|
+
return cfg;
|
|
10168
|
+
}
|
|
10113
10169
|
};
|
|
10114
10170
|
|
|
10115
10171
|
// src/gateway/qqbot-gateway.ts
|
|
@@ -10196,7 +10252,7 @@ var REGISTRIES = [
|
|
|
10196
10252
|
var CURRENT_VERSION = getPackageVersion();
|
|
10197
10253
|
function fetchJson(url, timeoutMs) {
|
|
10198
10254
|
return new Promise((resolve2, reject) => {
|
|
10199
|
-
const
|
|
10255
|
+
const req4 = import_node_https2.default.get(url, { timeout: timeoutMs, headers: { Accept: "application/json" } }, (res) => {
|
|
10200
10256
|
if (res.statusCode !== 200) {
|
|
10201
10257
|
res.resume();
|
|
10202
10258
|
reject(new Error(`HTTP ${res.statusCode} from ${url}`));
|
|
@@ -10214,9 +10270,9 @@ function fetchJson(url, timeoutMs) {
|
|
|
10214
10270
|
}
|
|
10215
10271
|
});
|
|
10216
10272
|
});
|
|
10217
|
-
|
|
10218
|
-
|
|
10219
|
-
|
|
10273
|
+
req4.on("error", reject);
|
|
10274
|
+
req4.on("timeout", () => {
|
|
10275
|
+
req4.destroy();
|
|
10220
10276
|
reject(new Error(`timeout fetching ${url}`));
|
|
10221
10277
|
});
|
|
10222
10278
|
});
|
|
@@ -10640,10 +10696,10 @@ function collectCandidateLogDirs(runtime2) {
|
|
|
10640
10696
|
pushDir(import_node_path5.default.join(homeDir, name));
|
|
10641
10697
|
pushDir(import_node_path5.default.join(homeDir, name, "logs"));
|
|
10642
10698
|
}
|
|
10643
|
-
const
|
|
10644
|
-
if (process.env.APPDATA)
|
|
10645
|
-
if (process.env.LOCALAPPDATA)
|
|
10646
|
-
for (const root of
|
|
10699
|
+
const searchRoots2 = /* @__PURE__ */ new Set([homeDir, process.cwd(), import_node_path5.default.dirname(process.cwd())]);
|
|
10700
|
+
if (process.env.APPDATA) searchRoots2.add(process.env.APPDATA);
|
|
10701
|
+
if (process.env.LOCALAPPDATA) searchRoots2.add(process.env.LOCALAPPDATA);
|
|
10702
|
+
for (const root of searchRoots2) {
|
|
10647
10703
|
try {
|
|
10648
10704
|
const entries = import_node_fs5.default.readdirSync(root, { withFileTypes: true });
|
|
10649
10705
|
for (const entry of entries) {
|
|
@@ -10955,8 +11011,8 @@ function botGroupAlways(account, getRuntime) {
|
|
|
10955
11011
|
};
|
|
10956
11012
|
}
|
|
10957
11013
|
|
|
10958
|
-
// src/
|
|
10959
|
-
var
|
|
11014
|
+
// src/adapter/pairing.ts
|
|
11015
|
+
var import_node_module3 = require("module");
|
|
10960
11016
|
var import_node_path6 = __toESM(require("path"), 1);
|
|
10961
11017
|
var _api;
|
|
10962
11018
|
function getPairingApi() {
|
|
@@ -10966,14 +11022,14 @@ function getPairingApi() {
|
|
|
10966
11022
|
}
|
|
10967
11023
|
function loadPairingApi() {
|
|
10968
11024
|
const currentFile = __filename;
|
|
10969
|
-
const
|
|
11025
|
+
const req4 = (0, import_node_module3.createRequire)(currentFile);
|
|
10970
11026
|
const pluginRoot = import_node_path6.default.resolve(import_node_path6.default.dirname(currentFile), "..", "..");
|
|
10971
|
-
const
|
|
11027
|
+
const fs21 = req4("node:fs");
|
|
10972
11028
|
const tryLoad = (root) => {
|
|
10973
11029
|
for (const rel of ["dist/plugin-sdk/conversation-runtime.js", "plugin-sdk/conversation-runtime.js"]) {
|
|
10974
11030
|
const p2 = import_node_path6.default.join(root, rel);
|
|
10975
11031
|
try {
|
|
10976
|
-
if (
|
|
11032
|
+
if (fs21.existsSync(p2)) return req4(p2);
|
|
10977
11033
|
} catch {
|
|
10978
11034
|
}
|
|
10979
11035
|
}
|
|
@@ -10981,7 +11037,7 @@ function loadPairingApi() {
|
|
|
10981
11037
|
};
|
|
10982
11038
|
let mod = null;
|
|
10983
11039
|
try {
|
|
10984
|
-
const { findOpenclawRoot } =
|
|
11040
|
+
const { findOpenclawRoot } = req4(import_node_path6.default.join(pluginRoot, "scripts", "link-sdk-core.cjs"));
|
|
10985
11041
|
const root = findOpenclawRoot(pluginRoot);
|
|
10986
11042
|
if (root) mod = tryLoad(root);
|
|
10987
11043
|
} catch {
|
|
@@ -10990,7 +11046,7 @@ function loadPairingApi() {
|
|
|
10990
11046
|
try {
|
|
10991
11047
|
const entry = process.argv[1];
|
|
10992
11048
|
if (entry) {
|
|
10993
|
-
const realEntry =
|
|
11049
|
+
const realEntry = fs21.realpathSync(entry);
|
|
10994
11050
|
let dir = import_node_path6.default.dirname(realEntry);
|
|
10995
11051
|
for (let i = 0; i < 6; i++) {
|
|
10996
11052
|
mod = tryLoad(dir);
|
|
@@ -11098,7 +11154,7 @@ function buildCommandList(account, opts) {
|
|
|
11098
11154
|
}
|
|
11099
11155
|
|
|
11100
11156
|
// src/middleware/attachment.ts
|
|
11101
|
-
var
|
|
11157
|
+
var path17 = __toESM(require("path"), 1);
|
|
11102
11158
|
|
|
11103
11159
|
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607081646/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/utils/reply-limiter.js
|
|
11104
11160
|
var DEFAULT_TTL_MS = 60 * 60 * 1e3;
|
|
@@ -11258,9 +11314,6 @@ function isVoiceAttachment(att) {
|
|
|
11258
11314
|
return [".amr", ".silk", ".slk", ".slac"].includes(ext);
|
|
11259
11315
|
}
|
|
11260
11316
|
|
|
11261
|
-
// src/middleware/attachment.ts
|
|
11262
|
-
var import_media_runtime = require("openclaw/plugin-sdk/media-runtime");
|
|
11263
|
-
|
|
11264
11317
|
// src/utils/stt.ts
|
|
11265
11318
|
var fs17 = __toESM(require("fs"), 1);
|
|
11266
11319
|
var path15 = __toESM(require("path"), 1);
|
|
@@ -11379,6 +11432,78 @@ function formatDuration2(seconds) {
|
|
|
11379
11432
|
return `${mins}:${secs.toString().padStart(2, "0")}`;
|
|
11380
11433
|
}
|
|
11381
11434
|
|
|
11435
|
+
// src/adapter/media.ts
|
|
11436
|
+
var import_node_module4 = require("module");
|
|
11437
|
+
var dns = __toESM(require("dns"), 1);
|
|
11438
|
+
var path16 = __toESM(require("path"), 1);
|
|
11439
|
+
var fs18 = __toESM(require("fs"), 1);
|
|
11440
|
+
var crypto4 = __toESM(require("crypto"), 1);
|
|
11441
|
+
var req3 = (0, import_node_module4.createRequire)(__filename);
|
|
11442
|
+
var _save;
|
|
11443
|
+
function downloadRemoteMedia(opts) {
|
|
11444
|
+
if (_save === void 0) {
|
|
11445
|
+
try {
|
|
11446
|
+
const mod = req3("openclaw/plugin-sdk/media-runtime");
|
|
11447
|
+
_save = mod.saveRemoteMedia;
|
|
11448
|
+
} catch {
|
|
11449
|
+
_save = null;
|
|
11450
|
+
}
|
|
11451
|
+
}
|
|
11452
|
+
return _save ? _save(opts) : downloadViaFetch(opts);
|
|
11453
|
+
}
|
|
11454
|
+
var PRIVATE_RANGES = [
|
|
11455
|
+
[0x0A000000n, 8],
|
|
11456
|
+
// 10.0.0.0/8
|
|
11457
|
+
[0xAC100000n, 12],
|
|
11458
|
+
// 172.16.0.0/12
|
|
11459
|
+
[0xC0A80000n, 16],
|
|
11460
|
+
// 192.168.0.0/16
|
|
11461
|
+
[0x7F000000n, 8],
|
|
11462
|
+
// 127.0.0.0/8
|
|
11463
|
+
[0xA9FE0000n, 16],
|
|
11464
|
+
// 169.254.0.0/16
|
|
11465
|
+
[0xE0000000n, 4]
|
|
11466
|
+
// 224.0.0.0/4 (multicast)
|
|
11467
|
+
];
|
|
11468
|
+
function ipToBigInt(ip) {
|
|
11469
|
+
return ip.split(".").reduce((acc, octet) => acc << 8n | BigInt(Number(octet)), 0n);
|
|
11470
|
+
}
|
|
11471
|
+
function isPrivateIP(ip) {
|
|
11472
|
+
const val = ipToBigInt(ip);
|
|
11473
|
+
return PRIVATE_RANGES.some(([mask, prefix]) => val >> 32n - BigInt(prefix) === mask >> 32n - BigInt(prefix));
|
|
11474
|
+
}
|
|
11475
|
+
async function assertSafeHostname(hostname) {
|
|
11476
|
+
const addresses = await dns.promises.resolve4(hostname).catch(() => []);
|
|
11477
|
+
if (addresses.length === 0) throw new Error(`DNS resolution failed: ${hostname}`);
|
|
11478
|
+
for (const addr of addresses) {
|
|
11479
|
+
if (isPrivateIP(addr)) {
|
|
11480
|
+
throw new Error(`SSRF blocked: ${hostname} resolves to private IP ${addr}`);
|
|
11481
|
+
}
|
|
11482
|
+
}
|
|
11483
|
+
}
|
|
11484
|
+
async function downloadViaFetch(opts) {
|
|
11485
|
+
const parsed = new URL(opts.url);
|
|
11486
|
+
if (parsed.protocol !== "https:") {
|
|
11487
|
+
throw new Error(`Only HTTPS allowed: ${parsed.protocol}`);
|
|
11488
|
+
}
|
|
11489
|
+
await assertSafeHostname(parsed.hostname);
|
|
11490
|
+
const dir = getQQBotMediaDir(opts.subdir ?? "downloads");
|
|
11491
|
+
if (!fs18.existsSync(dir)) fs18.mkdirSync(dir, { recursive: true });
|
|
11492
|
+
const resp = await fetch(opts.url, {
|
|
11493
|
+
signal: AbortSignal.timeout(opts.timeoutMs ?? 12e4)
|
|
11494
|
+
});
|
|
11495
|
+
if (!resp.ok) throw new Error(`Download HTTP ${resp.status}`);
|
|
11496
|
+
const maxBytes = opts.maxBytes ?? 500 * 1024 * 1024;
|
|
11497
|
+
const buf = Buffer.from(await resp.arrayBuffer());
|
|
11498
|
+
if (buf.length > maxBytes) throw new Error(`Download exceeds ${(maxBytes / 1024 / 1024).toFixed(0)}MB`);
|
|
11499
|
+
const ext = opts.originalFilename ? path16.extname(opts.originalFilename) || ".bin" : ".bin";
|
|
11500
|
+
const name = opts.originalFilename ? path16.basename(opts.originalFilename, path16.extname(opts.originalFilename)) : "download";
|
|
11501
|
+
const rand = crypto4.randomBytes(4).toString("hex");
|
|
11502
|
+
const filePath = path16.join(dir, `${name}_${Date.now()}_${rand}${ext}`);
|
|
11503
|
+
fs18.writeFileSync(filePath, buf);
|
|
11504
|
+
return { path: filePath };
|
|
11505
|
+
}
|
|
11506
|
+
|
|
11382
11507
|
// src/middleware/attachment.ts
|
|
11383
11508
|
function attachmentProcessor(opts) {
|
|
11384
11509
|
return async (ctx, next) => {
|
|
@@ -11494,7 +11619,7 @@ async function processVoiceAttachment(att, sttCfg, audioPolicy, log4) {
|
|
|
11494
11619
|
if (silkUrl) {
|
|
11495
11620
|
const silkPath = await downloadMediaFile(silkUrl, att.filename, log4);
|
|
11496
11621
|
if (silkPath) {
|
|
11497
|
-
const ext =
|
|
11622
|
+
const ext = path17.extname(silkPath).toLowerCase();
|
|
11498
11623
|
if (audioPolicy.sttDirectFormats.includes(ext)) {
|
|
11499
11624
|
localPath = silkPath;
|
|
11500
11625
|
} else {
|
|
@@ -11567,12 +11692,12 @@ async function downloadMediaFile(url, filename, log4) {
|
|
|
11567
11692
|
return null;
|
|
11568
11693
|
}
|
|
11569
11694
|
try {
|
|
11570
|
-
const result = await (
|
|
11695
|
+
const result = await downloadRemoteMedia({
|
|
11571
11696
|
url,
|
|
11572
11697
|
subdir: "qqbot/downloads",
|
|
11573
11698
|
originalFilename: filename,
|
|
11574
11699
|
maxBytes: 500 * 1024 * 1024,
|
|
11575
|
-
timeoutMs:
|
|
11700
|
+
timeoutMs: 12e4
|
|
11576
11701
|
});
|
|
11577
11702
|
log4?.debug?.(`Downloaded: ${result.path}`);
|
|
11578
11703
|
return result.path;
|
|
@@ -12301,10 +12426,6 @@ async function dispatchToOpenClaw(ctx, msg, account, runtime2, log4) {
|
|
|
12301
12426
|
const adapters = getAdapters(runtime2, dlog);
|
|
12302
12427
|
const envelope = buildEnvelope2(ctx, msg, account);
|
|
12303
12428
|
dlog?.debug(`received sender=${envelope.senderId} scope=${envelope.chatScope} msgId=${envelope.messageId}`);
|
|
12304
|
-
if (!adapters.inboundRun) {
|
|
12305
|
-
dlog?.error(`runtime adapter inboundRun not available (openclaw=${adapters.version})`);
|
|
12306
|
-
return;
|
|
12307
|
-
}
|
|
12308
12429
|
if (!adapters.dispatchReply) {
|
|
12309
12430
|
dlog?.error(`runtime adapter dispatchReply not available (openclaw=${adapters.version})`);
|
|
12310
12431
|
return;
|
|
@@ -12400,127 +12521,160 @@ async function dispatchToOpenClaw(ctx, msg, account, runtime2, log4) {
|
|
|
12400
12521
|
if (streamingController) {
|
|
12401
12522
|
dlog?.debug(`streaming enabled for ${envelope.senderId}`);
|
|
12402
12523
|
}
|
|
12403
|
-
|
|
12404
|
-
|
|
12405
|
-
|
|
12406
|
-
|
|
12407
|
-
|
|
12408
|
-
|
|
12409
|
-
|
|
12410
|
-
|
|
12411
|
-
|
|
12412
|
-
|
|
12413
|
-
|
|
12414
|
-
|
|
12415
|
-
|
|
12416
|
-
|
|
12417
|
-
|
|
12418
|
-
|
|
12419
|
-
|
|
12420
|
-
|
|
12421
|
-
|
|
12422
|
-
|
|
12423
|
-
|
|
12424
|
-
|
|
12524
|
+
if (!adapters.inboundRun) {
|
|
12525
|
+
if (adapters.recordInboundSession) {
|
|
12526
|
+
try {
|
|
12527
|
+
await adapters.recordInboundSession({
|
|
12528
|
+
storePath,
|
|
12529
|
+
sessionKey: route.sessionKey,
|
|
12530
|
+
ctx: ctxPayload
|
|
12531
|
+
});
|
|
12532
|
+
} catch {
|
|
12533
|
+
}
|
|
12534
|
+
}
|
|
12535
|
+
await adapters.dispatchReply({
|
|
12536
|
+
ctx: ctxPayload,
|
|
12537
|
+
cfg,
|
|
12538
|
+
dispatcherOptions: {
|
|
12539
|
+
deliver: async (payload, info) => {
|
|
12540
|
+
await deliverReply(payload, info, deliverCtx);
|
|
12541
|
+
}
|
|
12542
|
+
},
|
|
12543
|
+
...streamingController ? {
|
|
12544
|
+
replyOptions: {
|
|
12545
|
+
onPartialReply: async (p2) => {
|
|
12546
|
+
if (p2.text) await streamingController.onPartialReply(p2.text);
|
|
12425
12547
|
}
|
|
12426
|
-
}
|
|
12427
|
-
|
|
12428
|
-
|
|
12429
|
-
|
|
12430
|
-
|
|
12431
|
-
|
|
12432
|
-
|
|
12433
|
-
|
|
12434
|
-
|
|
12435
|
-
|
|
12436
|
-
|
|
12437
|
-
|
|
12438
|
-
|
|
12439
|
-
|
|
12440
|
-
|
|
12441
|
-
|
|
12442
|
-
|
|
12443
|
-
|
|
12548
|
+
}
|
|
12549
|
+
} : {}
|
|
12550
|
+
});
|
|
12551
|
+
if (streamingController && !streamingController.isTerminal) {
|
|
12552
|
+
await streamingController.finalize();
|
|
12553
|
+
}
|
|
12554
|
+
if (debouncer) await debouncer.flushAll();
|
|
12555
|
+
} else {
|
|
12556
|
+
await adapters.inboundRun({
|
|
12557
|
+
channel: "qqbot",
|
|
12558
|
+
accountId: route.accountId,
|
|
12559
|
+
raw: envelope,
|
|
12560
|
+
adapter: {
|
|
12561
|
+
ingest: (raw) => ({
|
|
12562
|
+
id: envelope.messageId,
|
|
12563
|
+
rawText: assembled.rawBody,
|
|
12564
|
+
textForAgent: assembled.agentBody,
|
|
12565
|
+
textForCommands: assembled.rawBody,
|
|
12566
|
+
raw
|
|
12567
|
+
}),
|
|
12568
|
+
resolveTurn: (_input, _eventClass, _preflight) => ({
|
|
12569
|
+
channel: "qqbot",
|
|
12570
|
+
accountId: route.accountId,
|
|
12571
|
+
routeSessionKey: route.sessionKey,
|
|
12572
|
+
storePath,
|
|
12573
|
+
ctxPayload,
|
|
12574
|
+
recordInboundSession: adapters.recordInboundSession,
|
|
12575
|
+
record: {
|
|
12576
|
+
onRecordError: (err) => {
|
|
12577
|
+
dlog?.error(`Session record error: ${err}`);
|
|
12578
|
+
}
|
|
12579
|
+
},
|
|
12580
|
+
runDispatch: () => {
|
|
12581
|
+
let blockDelivered = false;
|
|
12582
|
+
const deliveredMediaUrls = /* @__PURE__ */ new Set();
|
|
12583
|
+
return adapters.dispatchReply({
|
|
12584
|
+
ctx: ctxPayload,
|
|
12585
|
+
cfg,
|
|
12586
|
+
dispatcherOptions: {
|
|
12587
|
+
deliver: async (payload, info) => {
|
|
12588
|
+
try {
|
|
12589
|
+
const kind = info?.kind;
|
|
12590
|
+
dlog?.debug(`deliver kind=${kind ?? "none"} textLen=${payload.text?.length ?? 0} audioAsVoice=${payload.audioAsVoice ?? false} mediaUrl=${payload.mediaUrl?.slice(0, 60) ?? "none"} mediaUrls=${payload.mediaUrls?.length ?? 0}`);
|
|
12591
|
+
if (kind === "block") {
|
|
12592
|
+
if (payload.audioAsVoice) {
|
|
12593
|
+
await deliverReply(payload, info, deliverCtx);
|
|
12594
|
+
} else {
|
|
12595
|
+
const urls = payload.mediaUrls?.length ? payload.mediaUrls : payload.mediaUrl ? [payload.mediaUrl] : [];
|
|
12596
|
+
for (const url of urls) {
|
|
12597
|
+
try {
|
|
12598
|
+
await sendMedia2({
|
|
12599
|
+
to: deliverCtx.qualifiedTarget,
|
|
12600
|
+
source: url,
|
|
12601
|
+
text: "",
|
|
12602
|
+
replyToId: deliverCtx.replyToId,
|
|
12603
|
+
accountId: deliverCtx.accountId,
|
|
12604
|
+
log: deliverCtx.log,
|
|
12605
|
+
agentId: deliverCtx.agentId
|
|
12606
|
+
});
|
|
12607
|
+
deliveredMediaUrls.add(url);
|
|
12608
|
+
} catch (err) {
|
|
12609
|
+
dlog?.error(`block media failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
12610
|
+
}
|
|
12611
|
+
}
|
|
12612
|
+
}
|
|
12613
|
+
}
|
|
12614
|
+
if (streamingController && !streamingController.shouldFallbackToStatic) {
|
|
12615
|
+
if (kind !== "block") {
|
|
12616
|
+
await streamingController.finalize();
|
|
12617
|
+
}
|
|
12618
|
+
if (!streamingController.shouldFallbackToStatic) {
|
|
12619
|
+
if (kind === "block") return;
|
|
12620
|
+
return;
|
|
12621
|
+
}
|
|
12622
|
+
dlog?.warn(`streaming fallback to static`);
|
|
12623
|
+
}
|
|
12624
|
+
if (kind === "block") {
|
|
12625
|
+
blockDelivered = true;
|
|
12626
|
+
} else if (kind === "final" && blockDelivered) {
|
|
12627
|
+
return;
|
|
12628
|
+
}
|
|
12629
|
+
if (kind === "tool") {
|
|
12630
|
+
const toolMediaUrls = [];
|
|
12631
|
+
if (payload.mediaUrls?.length) toolMediaUrls.push(...payload.mediaUrls);
|
|
12632
|
+
if (payload.mediaUrl && !toolMediaUrls.includes(payload.mediaUrl)) toolMediaUrls.push(payload.mediaUrl);
|
|
12633
|
+
const newUrls = toolMediaUrls.filter((u2) => !deliveredMediaUrls.has(u2));
|
|
12634
|
+
for (const mediaUrl of newUrls) {
|
|
12444
12635
|
try {
|
|
12445
12636
|
await sendMedia2({
|
|
12446
12637
|
to: deliverCtx.qualifiedTarget,
|
|
12447
|
-
source:
|
|
12638
|
+
source: mediaUrl,
|
|
12448
12639
|
text: "",
|
|
12449
12640
|
replyToId: deliverCtx.replyToId,
|
|
12450
12641
|
accountId: deliverCtx.accountId,
|
|
12451
12642
|
log: deliverCtx.log,
|
|
12452
12643
|
agentId: deliverCtx.agentId
|
|
12453
12644
|
});
|
|
12454
|
-
deliveredMediaUrls.add(
|
|
12645
|
+
deliveredMediaUrls.add(mediaUrl);
|
|
12646
|
+
dlog?.info(`tool media forwarded url=${mediaUrl.slice(0, 60)}`);
|
|
12455
12647
|
} catch (err) {
|
|
12456
|
-
dlog?.error(`
|
|
12648
|
+
dlog?.error(`tool media forward failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
12457
12649
|
}
|
|
12458
12650
|
}
|
|
12459
|
-
}
|
|
12460
|
-
}
|
|
12461
|
-
if (streamingController && !streamingController.shouldFallbackToStatic) {
|
|
12462
|
-
if (kind !== "block") {
|
|
12463
|
-
await streamingController.finalize();
|
|
12464
|
-
}
|
|
12465
|
-
if (!streamingController.shouldFallbackToStatic) {
|
|
12466
|
-
if (kind === "block") return;
|
|
12467
12651
|
return;
|
|
12468
12652
|
}
|
|
12469
|
-
|
|
12470
|
-
|
|
12471
|
-
|
|
12472
|
-
|
|
12473
|
-
|
|
12474
|
-
|
|
12475
|
-
}
|
|
12476
|
-
|
|
12477
|
-
const toolMediaUrls = [];
|
|
12478
|
-
if (payload.mediaUrls?.length) toolMediaUrls.push(...payload.mediaUrls);
|
|
12479
|
-
if (payload.mediaUrl && !toolMediaUrls.includes(payload.mediaUrl)) toolMediaUrls.push(payload.mediaUrl);
|
|
12480
|
-
const newUrls = toolMediaUrls.filter((u2) => !deliveredMediaUrls.has(u2));
|
|
12481
|
-
for (const mediaUrl of newUrls) {
|
|
12482
|
-
try {
|
|
12483
|
-
await sendMedia2({
|
|
12484
|
-
to: deliverCtx.qualifiedTarget,
|
|
12485
|
-
source: mediaUrl,
|
|
12486
|
-
text: "",
|
|
12487
|
-
replyToId: deliverCtx.replyToId,
|
|
12488
|
-
accountId: deliverCtx.accountId,
|
|
12489
|
-
log: deliverCtx.log,
|
|
12490
|
-
agentId: deliverCtx.agentId
|
|
12491
|
-
});
|
|
12492
|
-
deliveredMediaUrls.add(mediaUrl);
|
|
12493
|
-
dlog?.info(`tool media forwarded url=${mediaUrl.slice(0, 60)}`);
|
|
12494
|
-
} catch (err) {
|
|
12495
|
-
dlog?.error(`tool media forward failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
12496
|
-
}
|
|
12497
|
-
}
|
|
12498
|
-
return;
|
|
12653
|
+
const filteredPayload = deliveredMediaUrls.size > 0 ? {
|
|
12654
|
+
...payload,
|
|
12655
|
+
mediaUrl: payload.mediaUrl && !deliveredMediaUrls.has(payload.mediaUrl) ? payload.mediaUrl : void 0,
|
|
12656
|
+
mediaUrls: payload.mediaUrls?.filter((u2) => !deliveredMediaUrls.has(u2))
|
|
12657
|
+
} : payload;
|
|
12658
|
+
await deliverReply(filteredPayload, info, deliverCtx);
|
|
12659
|
+
} catch (err) {
|
|
12660
|
+
dlog?.error(`error: ${err instanceof Error ? err.message : String(err)}`);
|
|
12499
12661
|
}
|
|
12500
|
-
const filteredPayload = deliveredMediaUrls.size > 0 ? {
|
|
12501
|
-
...payload,
|
|
12502
|
-
mediaUrl: payload.mediaUrl && !deliveredMediaUrls.has(payload.mediaUrl) ? payload.mediaUrl : void 0,
|
|
12503
|
-
mediaUrls: payload.mediaUrls?.filter((u2) => !deliveredMediaUrls.has(u2))
|
|
12504
|
-
} : payload;
|
|
12505
|
-
await deliverReply(filteredPayload, info, deliverCtx);
|
|
12506
|
-
} catch (err) {
|
|
12507
|
-
dlog?.error(`error: ${err instanceof Error ? err.message : String(err)}`);
|
|
12508
12662
|
}
|
|
12663
|
+
},
|
|
12664
|
+
replyOptions: {
|
|
12665
|
+
runId: envelope.messageId,
|
|
12666
|
+
...streamingController ? {
|
|
12667
|
+
onPartialReply: async (p2) => {
|
|
12668
|
+
if (p2.text) await streamingController.onPartialReply(p2.text);
|
|
12669
|
+
}
|
|
12670
|
+
} : {}
|
|
12509
12671
|
}
|
|
12510
|
-
}
|
|
12511
|
-
|
|
12512
|
-
|
|
12513
|
-
|
|
12514
|
-
|
|
12515
|
-
|
|
12516
|
-
}
|
|
12517
|
-
} : {}
|
|
12518
|
-
}
|
|
12519
|
-
});
|
|
12520
|
-
}
|
|
12521
|
-
})
|
|
12522
|
-
}
|
|
12523
|
-
});
|
|
12672
|
+
});
|
|
12673
|
+
}
|
|
12674
|
+
})
|
|
12675
|
+
}
|
|
12676
|
+
});
|
|
12677
|
+
}
|
|
12524
12678
|
dlog?.debug(`inboundRun completed sessionKey=${route.sessionKey}`);
|
|
12525
12679
|
if (envelope.chatScope === "group") {
|
|
12526
12680
|
clearGroupHistory(envelope.groupId ?? envelope.senderId);
|
|
@@ -12551,26 +12705,25 @@ function createStreamingController(envelope, account, log4) {
|
|
|
12551
12705
|
});
|
|
12552
12706
|
}
|
|
12553
12707
|
|
|
12554
|
-
// src/
|
|
12555
|
-
var
|
|
12708
|
+
// src/adapter/gateway.ts
|
|
12709
|
+
var import_node_module5 = require("module");
|
|
12556
12710
|
var import_node_path8 = __toESM(require("path"), 1);
|
|
12557
12711
|
function loadApprovalGatewayRuntime() {
|
|
12558
|
-
const
|
|
12559
|
-
const
|
|
12560
|
-
const
|
|
12561
|
-
const fs20 = req("node:fs");
|
|
12712
|
+
const req4 = (0, import_node_module5.createRequire)(__filename);
|
|
12713
|
+
const pluginRoot = import_node_path8.default.resolve(import_node_path8.default.dirname(__filename), "..", "..");
|
|
12714
|
+
const fs21 = req4("node:fs");
|
|
12562
12715
|
const tryLoadFromRoot = (root) => {
|
|
12563
12716
|
for (const rel of ["dist/plugin-sdk/gateway-runtime.js", "plugin-sdk/gateway-runtime.js"]) {
|
|
12564
12717
|
const p2 = import_node_path8.default.join(root, rel);
|
|
12565
12718
|
try {
|
|
12566
|
-
if (
|
|
12719
|
+
if (fs21.existsSync(p2)) return req4(p2);
|
|
12567
12720
|
} catch {
|
|
12568
12721
|
}
|
|
12569
12722
|
}
|
|
12570
12723
|
return null;
|
|
12571
12724
|
};
|
|
12572
12725
|
try {
|
|
12573
|
-
const { findOpenclawRoot } =
|
|
12726
|
+
const { findOpenclawRoot } = req4(import_node_path8.default.join(pluginRoot, "scripts", "link-sdk-core.cjs"));
|
|
12574
12727
|
const root = findOpenclawRoot(pluginRoot);
|
|
12575
12728
|
if (root) {
|
|
12576
12729
|
const mod = tryLoadFromRoot(root);
|
|
@@ -12581,7 +12734,7 @@ function loadApprovalGatewayRuntime() {
|
|
|
12581
12734
|
try {
|
|
12582
12735
|
const entry = process.argv[1];
|
|
12583
12736
|
if (entry) {
|
|
12584
|
-
const realEntry =
|
|
12737
|
+
const realEntry = fs21.realpathSync(entry);
|
|
12585
12738
|
let dir = import_node_path8.default.dirname(realEntry);
|
|
12586
12739
|
for (let i = 0; i < 6; i++) {
|
|
12587
12740
|
const mod = tryLoadFromRoot(dir);
|
|
@@ -12864,16 +13017,16 @@ function getApprovalHandler(accountId) {
|
|
|
12864
13017
|
}
|
|
12865
13018
|
|
|
12866
13019
|
// src/features/proactive.ts
|
|
12867
|
-
var
|
|
12868
|
-
var
|
|
13020
|
+
var fs19 = __toESM(require("fs"), 1);
|
|
13021
|
+
var path19 = __toESM(require("path"), 1);
|
|
12869
13022
|
var log2 = createPluginLogger({ prefix: "[proactive]" });
|
|
12870
13023
|
var STORAGE_DIR = getQQBotDataDir("data");
|
|
12871
|
-
var KNOWN_USERS_FILE =
|
|
13024
|
+
var KNOWN_USERS_FILE = path19.join(STORAGE_DIR, "known-users.json");
|
|
12872
13025
|
var knownUsersCache = null;
|
|
12873
13026
|
var cacheLastModified = 0;
|
|
12874
13027
|
function ensureStorageDir() {
|
|
12875
|
-
if (!
|
|
12876
|
-
|
|
13028
|
+
if (!fs19.existsSync(STORAGE_DIR)) {
|
|
13029
|
+
fs19.mkdirSync(STORAGE_DIR, { recursive: true });
|
|
12877
13030
|
}
|
|
12878
13031
|
}
|
|
12879
13032
|
function getUserKey(type, openid, accountId) {
|
|
@@ -12882,7 +13035,7 @@ function getUserKey(type, openid, accountId) {
|
|
|
12882
13035
|
function loadKnownUsers() {
|
|
12883
13036
|
if (knownUsersCache !== null) {
|
|
12884
13037
|
try {
|
|
12885
|
-
const stat =
|
|
13038
|
+
const stat = fs19.statSync(KNOWN_USERS_FILE);
|
|
12886
13039
|
if (stat.mtimeMs <= cacheLastModified) {
|
|
12887
13040
|
return knownUsersCache;
|
|
12888
13041
|
}
|
|
@@ -12892,14 +13045,14 @@ function loadKnownUsers() {
|
|
|
12892
13045
|
}
|
|
12893
13046
|
const users = /* @__PURE__ */ new Map();
|
|
12894
13047
|
try {
|
|
12895
|
-
if (
|
|
12896
|
-
const data =
|
|
13048
|
+
if (fs19.existsSync(KNOWN_USERS_FILE)) {
|
|
13049
|
+
const data = fs19.readFileSync(KNOWN_USERS_FILE, "utf-8");
|
|
12897
13050
|
const parsed = JSON.parse(data);
|
|
12898
13051
|
for (const user of parsed) {
|
|
12899
13052
|
const key = getUserKey(user.type, user.openid, user.accountId);
|
|
12900
13053
|
users.set(key, user);
|
|
12901
13054
|
}
|
|
12902
|
-
cacheLastModified =
|
|
13055
|
+
cacheLastModified = fs19.statSync(KNOWN_USERS_FILE).mtimeMs;
|
|
12903
13056
|
}
|
|
12904
13057
|
} catch (err) {
|
|
12905
13058
|
log2.error(`Failed to load known users: ${err}`);
|
|
@@ -12911,7 +13064,7 @@ function saveKnownUsers(users) {
|
|
|
12911
13064
|
try {
|
|
12912
13065
|
ensureStorageDir();
|
|
12913
13066
|
const data = Array.from(users.values());
|
|
12914
|
-
|
|
13067
|
+
fs19.writeFileSync(KNOWN_USERS_FILE, JSON.stringify(data, null, 2), "utf-8");
|
|
12915
13068
|
cacheLastModified = Date.now();
|
|
12916
13069
|
knownUsersCache = users;
|
|
12917
13070
|
} catch (err) {
|
|
@@ -13106,7 +13259,7 @@ function setGroupRequireMention(runtime2, accountId, groupOpenid, requireMention
|
|
|
13106
13259
|
}) ?? Promise.resolve();
|
|
13107
13260
|
}
|
|
13108
13261
|
|
|
13109
|
-
// src/
|
|
13262
|
+
// src/adapter/webhook.ts
|
|
13110
13263
|
var sharedTargets = /* @__PURE__ */ new Map();
|
|
13111
13264
|
var _routeUnregisters = /* @__PURE__ */ new Map();
|
|
13112
13265
|
function createPluginWebhookAdapter(params) {
|
|
@@ -13114,13 +13267,13 @@ function createPluginWebhookAdapter(params) {
|
|
|
13114
13267
|
let storedPath = "";
|
|
13115
13268
|
const accountId = params.account.accountId;
|
|
13116
13269
|
return {
|
|
13117
|
-
async listen(_port,
|
|
13270
|
+
async listen(_port, path21, handler) {
|
|
13118
13271
|
const ingress = await import("openclaw/plugin-sdk/webhook-ingress").catch(() => null);
|
|
13119
13272
|
if (!ingress?.registerWebhookTargetWithPluginRoute) {
|
|
13120
13273
|
params.log.error("Webhook ingress not available");
|
|
13121
13274
|
return;
|
|
13122
13275
|
}
|
|
13123
|
-
const webhookPath = storedPath =
|
|
13276
|
+
const webhookPath = storedPath = path21 && path21 !== "/" ? path21 : params.account.config.webhook?.path ?? "/qqbot/webhook";
|
|
13124
13277
|
const existing = sharedTargets.get(webhookPath);
|
|
13125
13278
|
if (existing) {
|
|
13126
13279
|
const dupIdx = existing.findIndex((t) => t.accountId === accountId);
|
|
@@ -13167,16 +13320,16 @@ function createPluginWebhookAdapter(params) {
|
|
|
13167
13320
|
}
|
|
13168
13321
|
};
|
|
13169
13322
|
}
|
|
13170
|
-
function createSharedHandler(
|
|
13171
|
-
return async (
|
|
13323
|
+
function createSharedHandler(path21, log4) {
|
|
13324
|
+
return async (req4, res) => {
|
|
13172
13325
|
try {
|
|
13173
13326
|
const ingress = await import("openclaw/plugin-sdk/webhook-ingress").catch(() => null);
|
|
13174
13327
|
if (!ingress?.withResolvedWebhookRequestPipeline) {
|
|
13175
|
-
await handleSimple(
|
|
13328
|
+
await handleSimple(req4, res, path21, log4);
|
|
13176
13329
|
return;
|
|
13177
13330
|
}
|
|
13178
13331
|
await ingress.withResolvedWebhookRequestPipeline({
|
|
13179
|
-
req,
|
|
13332
|
+
req: req4,
|
|
13180
13333
|
res,
|
|
13181
13334
|
targetsByPath: sharedTargets,
|
|
13182
13335
|
rateLimiter: ingress.createFixedWindowRateLimiter?.({
|
|
@@ -13191,7 +13344,7 @@ function createSharedHandler(path20, log4) {
|
|
|
13191
13344
|
requireJsonContentType: true,
|
|
13192
13345
|
handle: async ({ targets }) => {
|
|
13193
13346
|
const bodyResult = await ingress.readWebhookBodyOrReject({
|
|
13194
|
-
req,
|
|
13347
|
+
req: req4,
|
|
13195
13348
|
res,
|
|
13196
13349
|
maxBytes: 1048576,
|
|
13197
13350
|
timeoutMs: 3e4
|
|
@@ -13213,25 +13366,25 @@ function createSharedHandler(path20, log4) {
|
|
|
13213
13366
|
if (payload.op === 13) {
|
|
13214
13367
|
const t = targets[0];
|
|
13215
13368
|
if (!t) {
|
|
13216
|
-
log4.warn?.(`[webhook] op:13 no target on ${
|
|
13369
|
+
log4.warn?.(`[webhook] op:13 no target on ${path21}`);
|
|
13217
13370
|
res.statusCode = 500;
|
|
13218
13371
|
res.end(JSON.stringify({ error: "no target" }));
|
|
13219
13372
|
return;
|
|
13220
13373
|
}
|
|
13221
|
-
const h3 = resolveTargetHandler(
|
|
13374
|
+
const h3 = resolveTargetHandler(path21, t.accountId);
|
|
13222
13375
|
if (!h3) {
|
|
13223
13376
|
log4.warn?.(`[webhook] op:13 no handler for ${t.accountId}`);
|
|
13224
13377
|
res.statusCode = 500;
|
|
13225
13378
|
res.end(JSON.stringify({ error: "no handler" }));
|
|
13226
13379
|
return;
|
|
13227
13380
|
}
|
|
13228
|
-
await delegateToHandler(h3,
|
|
13381
|
+
await delegateToHandler(h3, req4, res, rawBody);
|
|
13229
13382
|
return;
|
|
13230
13383
|
}
|
|
13231
|
-
const timestamp = getHeader2(
|
|
13232
|
-
const signature = getHeader2(
|
|
13384
|
+
const timestamp = getHeader2(req4, "x-signature-timestamp") ?? "";
|
|
13385
|
+
const signature = getHeader2(req4, "x-signature-ed25519") ?? "";
|
|
13233
13386
|
if (!timestamp || !signature) {
|
|
13234
|
-
log4.warn?.(`[webhook] missing signature headers on ${
|
|
13387
|
+
log4.warn?.(`[webhook] missing signature headers on ${req4.url}`);
|
|
13235
13388
|
res.statusCode = 401;
|
|
13236
13389
|
res.end(JSON.stringify({ error: "missing signature" }));
|
|
13237
13390
|
return;
|
|
@@ -13249,17 +13402,17 @@ function createSharedHandler(path20, log4) {
|
|
|
13249
13402
|
unauthorizedMessage: JSON.stringify({ error: "invalid signature" })
|
|
13250
13403
|
});
|
|
13251
13404
|
if (!matched) {
|
|
13252
|
-
log4.warn?.(`[webhook] signature mismatch on ${
|
|
13405
|
+
log4.warn?.(`[webhook] signature mismatch on ${path21} (${targets.length} target(s))`);
|
|
13253
13406
|
return;
|
|
13254
13407
|
}
|
|
13255
|
-
const h2 = resolveTargetHandler(
|
|
13408
|
+
const h2 = resolveTargetHandler(path21, matched.accountId);
|
|
13256
13409
|
if (!h2) {
|
|
13257
13410
|
log4.error?.(`[webhook] no handler for matched target ${matched.accountId}`);
|
|
13258
13411
|
res.statusCode = 500;
|
|
13259
13412
|
res.end(JSON.stringify({ error: "no handler" }));
|
|
13260
13413
|
return;
|
|
13261
13414
|
}
|
|
13262
|
-
await delegateToHandler(h2,
|
|
13415
|
+
await delegateToHandler(h2, req4, res, rawBody);
|
|
13263
13416
|
}
|
|
13264
13417
|
});
|
|
13265
13418
|
} catch (err) {
|
|
@@ -13272,12 +13425,12 @@ function createSharedHandler(path20, log4) {
|
|
|
13272
13425
|
}
|
|
13273
13426
|
};
|
|
13274
13427
|
}
|
|
13275
|
-
function resolveTargetHandler(
|
|
13276
|
-
return sharedTargets.get(
|
|
13428
|
+
function resolveTargetHandler(path21, accountId) {
|
|
13429
|
+
return sharedTargets.get(path21)?.find((t) => t.accountId === accountId)?.handler;
|
|
13277
13430
|
}
|
|
13278
|
-
async function delegateToHandler(handler,
|
|
13431
|
+
async function delegateToHandler(handler, req4, res, rawBody) {
|
|
13279
13432
|
const headers = {};
|
|
13280
|
-
for (const [k, v] of Object.entries(
|
|
13433
|
+
for (const [k, v] of Object.entries(req4.headers)) {
|
|
13281
13434
|
headers[k.toLowerCase()] = v;
|
|
13282
13435
|
}
|
|
13283
13436
|
const resp = await handler({ body: rawBody, headers });
|
|
@@ -13287,9 +13440,9 @@ async function delegateToHandler(handler, req, res, rawBody) {
|
|
|
13287
13440
|
}
|
|
13288
13441
|
res.end(resp.body);
|
|
13289
13442
|
}
|
|
13290
|
-
async function handleSimple(
|
|
13443
|
+
async function handleSimple(req4, res, path21, log4) {
|
|
13291
13444
|
try {
|
|
13292
|
-
const ct = String(
|
|
13445
|
+
const ct = String(req4.headers["content-type"] ?? "");
|
|
13293
13446
|
if (!ct.includes("application/json")) {
|
|
13294
13447
|
res.statusCode = 400;
|
|
13295
13448
|
res.end(JSON.stringify({ error: "unsupported content type" }));
|
|
@@ -13297,7 +13450,7 @@ async function handleSimple(req, res, path20, log4) {
|
|
|
13297
13450
|
}
|
|
13298
13451
|
const chunks = [];
|
|
13299
13452
|
let total = 0;
|
|
13300
|
-
for await (const chunk of
|
|
13453
|
+
for await (const chunk of req4) {
|
|
13301
13454
|
const buf = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
|
|
13302
13455
|
total += buf.length;
|
|
13303
13456
|
if (total > 1048576) {
|
|
@@ -13308,9 +13461,9 @@ async function handleSimple(req, res, path20, log4) {
|
|
|
13308
13461
|
chunks.push(buf);
|
|
13309
13462
|
}
|
|
13310
13463
|
const rawBody = Buffer.concat(chunks);
|
|
13311
|
-
const entries = sharedTargets.get(
|
|
13464
|
+
const entries = sharedTargets.get(path21) ?? [];
|
|
13312
13465
|
for (const entry of entries) {
|
|
13313
|
-
const resp = await entry.handler({ body: rawBody, headers: mapHeaders(
|
|
13466
|
+
const resp = await entry.handler({ body: rawBody, headers: mapHeaders(req4) });
|
|
13314
13467
|
if (resp.status < 400) {
|
|
13315
13468
|
res.statusCode = resp.status;
|
|
13316
13469
|
if (resp.headers) for (const [k, v] of Object.entries(resp.headers)) res.setHeader(k, v);
|
|
@@ -13328,13 +13481,13 @@ async function handleSimple(req, res, path20, log4) {
|
|
|
13328
13481
|
}
|
|
13329
13482
|
}
|
|
13330
13483
|
}
|
|
13331
|
-
function mapHeaders(
|
|
13484
|
+
function mapHeaders(req4) {
|
|
13332
13485
|
const h2 = {};
|
|
13333
|
-
for (const [k, v] of Object.entries(
|
|
13486
|
+
for (const [k, v] of Object.entries(req4.headers ?? {})) h2[k.toLowerCase()] = v;
|
|
13334
13487
|
return h2;
|
|
13335
13488
|
}
|
|
13336
|
-
function getHeader2(
|
|
13337
|
-
const val =
|
|
13489
|
+
function getHeader2(req4, key) {
|
|
13490
|
+
const val = req4.headers[key];
|
|
13338
13491
|
return Array.isArray(val) ? val[0] : val;
|
|
13339
13492
|
}
|
|
13340
13493
|
|
|
@@ -14106,10 +14259,10 @@ function json(data) {
|
|
|
14106
14259
|
details: data
|
|
14107
14260
|
};
|
|
14108
14261
|
}
|
|
14109
|
-
function validatePath(
|
|
14110
|
-
if (!
|
|
14111
|
-
if (
|
|
14112
|
-
if (!/^\/[a-zA-Z0-9\-._~:@!$&'()*+,;=/%]+$/.test(
|
|
14262
|
+
function validatePath(path21) {
|
|
14263
|
+
if (!path21.startsWith("/")) return "path \u5FC5\u987B\u4EE5 / \u5F00\u5934";
|
|
14264
|
+
if (path21.includes("..") || path21.includes("//")) return "path \u4E0D\u5141\u8BB8\u5305\u542B .. \u6216 //";
|
|
14265
|
+
if (!/^\/[a-zA-Z0-9\-._~:@!$&'()*+,;=/%]+$/.test(path21) && path21 !== "/") {
|
|
14113
14266
|
return "path \u5305\u542B\u975E\u6CD5\u5B57\u7B26";
|
|
14114
14267
|
}
|
|
14115
14268
|
return null;
|
|
@@ -14384,22 +14537,19 @@ function registerRemindTool(api) {
|
|
|
14384
14537
|
);
|
|
14385
14538
|
}
|
|
14386
14539
|
|
|
14387
|
-
// src/
|
|
14540
|
+
// src/adapter/contract.ts
|
|
14388
14541
|
var log3 = createPluginLogger({ prefix: "[contract]", forceConsole: true });
|
|
14389
14542
|
var REQUIRED = [
|
|
14390
|
-
{
|
|
14391
|
-
name: "channel.inbound.run",
|
|
14392
|
-
probe: (rt) => {
|
|
14393
|
-
const c = rt.channel;
|
|
14394
|
-
return typeof c?.inbound?.run === "function" || typeof c?.turn?.run === "function";
|
|
14395
|
-
}
|
|
14396
|
-
},
|
|
14397
14543
|
{
|
|
14398
14544
|
name: "channel.reply.dispatchReplyWithBufferedBlockDispatcher",
|
|
14399
14545
|
probe: (rt) => typeof rt.channel?.reply?.dispatchReplyWithBufferedBlockDispatcher === "function"
|
|
14400
14546
|
}
|
|
14401
14547
|
];
|
|
14402
14548
|
var OPTIONAL = [
|
|
14549
|
+
{ name: "channel.inbound.run (degraded)", probe: (rt) => {
|
|
14550
|
+
const c = rt.channel;
|
|
14551
|
+
return typeof c?.inbound?.run === "function" || typeof c?.turn?.run === "function";
|
|
14552
|
+
} },
|
|
14403
14553
|
{ name: "channel.inbound.buildContext", probe: (rt) => typeof rt.channel?.inbound?.buildContext === "function" },
|
|
14404
14554
|
{ name: "channel.reply.formatAgentEnvelope", probe: (rt) => typeof rt.channel?.reply?.formatAgentEnvelope === "function" },
|
|
14405
14555
|
{ name: "channel.text.chunkMarkdownText", probe: (rt) => typeof rt.channel?.text?.chunkMarkdownText === "function" },
|