@cxyhhhhh/openclaw-qqbot 2.0.0-dev.202607081648 → 2.0.0-dev.202607082155

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.
Files changed (36) hide show
  1. package/dist/index.cjs +560 -381
  2. package/dist/index.cjs.map +1 -1
  3. package/index.ts +1 -1
  4. package/package.json +1 -1
  5. package/skills/qqbot-channel/SKILL.md +33 -11
  6. package/src/{runtime-adapter/contract-check.ts → adapter/contract.ts} +4 -7
  7. package/src/{runtime-adapter/gateway-runtime.ts → adapter/gateway.ts} +2 -3
  8. package/src/{runtime-adapter → adapter}/index.ts +3 -3
  9. package/src/{runtime-adapter/lint-runtime-access.ts → adapter/lint.ts} +7 -7
  10. package/src/adapter/media.ts +112 -0
  11. package/src/adapter/setup.ts +55 -0
  12. package/src/adapter/workspace.ts +29 -0
  13. package/src/bot-instance.ts +1 -1
  14. package/src/channel.ts +1 -1
  15. package/src/commands/bot-approve.ts +1 -1
  16. package/src/commands/bot-logs.ts +1 -1
  17. package/src/commands/bot-pairing.ts +1 -1
  18. package/src/commands/config-util.ts +1 -1
  19. package/src/dispatch/body-assembler.ts +1 -1
  20. package/src/dispatch/dispatch.ts +75 -45
  21. package/src/features/approval-handler.ts +1 -1
  22. package/src/gateway/event-handlers.ts +1 -1
  23. package/src/gateway/lifecycle.ts +1 -1
  24. package/src/gateway/qqbot-gateway.ts +1 -1
  25. package/src/middleware/access-control.ts +1 -1
  26. package/src/middleware/attachment.ts +4 -4
  27. package/src/openclaw-plugin-sdk.d.ts +41 -0
  28. package/src/outbound/media-send.ts +4 -6
  29. package/src/runtime.ts +3 -1
  30. package/src/setup/finalize.ts +1 -2
  31. package/src/setup/surface.ts +5 -6
  32. package/src/utils/pkg-version.ts +100 -49
  33. package/tsup.config.ts +1 -1
  34. /package/src/{runtime-adapter/pairing-runtime.ts → adapter/pairing.ts} +0 -0
  35. /package/src/{runtime-adapter → adapter}/resolve.ts +0 -0
  36. /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 = randomBytes(16).toString("base64");
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 req;
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
- req = websocket._req = request2(opts);
2850
+ req4 = websocket._req = request2(opts);
2851
2851
  if (websocket._redirects) {
2852
- websocket.emit("redirect", websocket.url, req);
2852
+ websocket.emit("redirect", websocket.url, req4);
2853
2853
  }
2854
2854
  } else {
2855
- req = websocket._req = request2(opts);
2855
+ req4 = websocket._req = request2(opts);
2856
2856
  }
2857
2857
  if (opts.timeout) {
2858
- req.on("timeout", () => {
2859
- abortHandshake(websocket, req, "Opening handshake has timed out");
2858
+ req4.on("timeout", () => {
2859
+ abortHandshake(websocket, req4, "Opening handshake has timed out");
2860
2860
  });
2861
2861
  }
2862
- req.on("error", (err) => {
2863
- if (req === null || req[kAborted]) return;
2864
- req = websocket._req = null;
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
- req.on("response", (res) => {
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, req, "Maximum redirects exceeded");
2872
+ abortHandshake(websocket, req4, "Maximum redirects exceeded");
2873
2873
  return;
2874
2874
  }
2875
- req.abort();
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", req, res)) {
2885
+ } else if (!websocket.emit("unexpected-response", req4, res)) {
2886
2886
  abortHandshake(
2887
2887
  websocket,
2888
- req,
2888
+ req4,
2889
2889
  `Unexpected server response: ${res.statusCode}`
2890
2890
  );
2891
2891
  }
2892
2892
  });
2893
- req.on("upgrade", (res, socket, head) => {
2893
+ req4.on("upgrade", (res, socket, head) => {
2894
2894
  websocket.emit("upgrade", res);
2895
2895
  if (websocket.readyState !== WebSocket2.CONNECTING) return;
2896
- req = websocket._req = null;
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(req, websocket);
2961
+ opts.finishRequest(req4, websocket);
2962
2962
  } else {
2963
- req.end();
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((req, res) => {
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: (req, socket, head) => {
3365
- this.handleUpgrade(req, socket, head, emitConnection);
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(req) {
3443
+ shouldHandle(req4) {
3444
3444
  if (this.options.path) {
3445
- const index = req.url.indexOf("?");
3446
- const pathname = index !== -1 ? req.url.slice(0, index) : req.url;
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(req, socket, head, cb) {
3460
+ handleUpgrade(req4, socket, head, cb) {
3461
3461
  socket.on("error", socketOnError);
3462
- const key = req.headers["sec-websocket-key"];
3463
- const upgrade = req.headers.upgrade;
3464
- const version = +req.headers["sec-websocket-version"];
3465
- if (req.method !== "GET") {
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, req, socket, 405, message);
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, req, socket, 400, message);
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, req, socket, 400, message);
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, req, socket, 400, message, {
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(req)) {
3487
+ if (!this.shouldHandle(req4)) {
3488
3488
  abortHandshake(socket, 400);
3489
3489
  return;
3490
3490
  }
3491
- const secWebSocketProtocol = req.headers["sec-websocket-protocol"];
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, req, socket, 400, message);
3498
+ abortHandshakeOrEmitwsClientError(this, req4, socket, 400, message);
3499
3499
  return;
3500
3500
  }
3501
3501
  }
3502
- const secWebSocketExtensions = req.headers["sec-websocket-extensions"];
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, req, socket, 400, message);
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: req.headers[`${version === 8 ? "sec-websocket-origin" : "origin"}`],
3525
- secure: !!(req.socket.authorized || req.socket.encrypted),
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
- req,
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, req, socket, head, cb);
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, req, socket, head, cb) {
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, req) : protocols.values().next().value;
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, req);
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, req);
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, req, socket, code, message, headers) {
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, req);
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, path20, explicit, defaultValue) {
5023
+ function resolvePolicy(ctx, path21, explicit, defaultValue) {
5024
5024
  if (explicit !== void 0 && explicit !== null) {
5025
5025
  return explicit;
5026
5026
  }
5027
- const keys = path20.split(".");
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, path20, bizCode, bizMessage) {
5105
+ constructor(message, httpStatus, path21, bizCode, bizMessage) {
5106
5106
  super(message);
5107
5107
  this.httpStatus = httpStatus;
5108
- this.path = path20;
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, path20, body, options) {
5197
- const url = `${this.baseUrl}${path20}`;
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 || path20.includes("/files") || path20.includes("/upload_prepare") || path20.includes("/upload_part_finish");
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 [${path20}]: exceeded ${timeout}ms`, 0, path20);
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 [${path20}]: ${formatErrorMessage(err)}`, 0, path20);
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 [${path20}]: ${formatErrorMessage(err)}`, res.status, path20);
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${path20}\uFF09\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5`, res.status, path20);
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 [${path20}]: ${error.message ?? rawBody}`, res.status, path20, bizCode, error.message);
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 [${path20}] HTTP ${res.status}: ${rawBody.slice(0, 200)}`, res.status, path20);
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${path20}\uFF09\uFF0C\u53EF\u80FD\u662F\u4E34\u65F6\u6545\u969C\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5`, res.status, path20);
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${path20}\uFF09\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5`, res.status, path20);
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 path20 = uploadPreparePath(opts.scope, opts.targetId);
5491
+ const path21 = uploadPreparePath(opts.scope, opts.targetId);
5492
5492
  try {
5493
- return await this.client.request(token, "POST", path20, {
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 path20 = uploadPartFinishPath(opts.scope, opts.targetId);
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", path20, {
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 path20 = uploadCompletePath(opts.scope, opts.targetId);
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", path20, { upload_id: uploadId }, { uploadRequest: true });
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 req = https.request(parsed, {
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
- req.on("error", (err) => {
5619
+ req4.on("error", (err) => {
5620
5620
  reject(err);
5621
5621
  });
5622
- req.end(data);
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 path20 = mediaUploadPath(scope, targetId);
5720
- const result = await withRetry(() => this.client.request(token, "POST", path20, body, {
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 path20 = messagePath(scope, targetId);
5737
- return this.client.request(token, "POST", path20, {
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 path20 = messagePath(scope, targetId);
5777
- return this.sendAndNotify(creds.appId, token, "POST", path20, body, { text: content });
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 path20 = messagePath(scope, targetId);
5786
- return this.sendAndNotify(creds.appId, token, "POST", path20, body, { text: content });
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, req) {
5832
+ async sendC2CStreamMessage(creds, openid, req4) {
5833
5833
  const token = await this.tokenManager.getAccessToken(creds.appId, creds.clientSecret);
5834
- const path20 = streamMessagePath(openid);
5834
+ const path21 = streamMessagePath(openid);
5835
5835
  const body = {
5836
- input_mode: req.input_mode,
5837
- input_state: req.input_state,
5838
- content_type: req.content_type,
5839
- content_raw: req.content_raw,
5840
- event_id: req.event_id,
5841
- msg_id: req.msg_id,
5842
- msg_seq: req.msg_seq,
5843
- index: req.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 (req.stream_msg_id) {
5846
- body.stream_msg_id = req.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", path20, body);
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 path20 = messagePath(scope, targetId);
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", path20, cleaned, { text: cleaned.content ?? cleaned.markdown?.content });
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 path20 = `${messagePath(scope, targetId)}/${messageId}`;
5904
- await this.client.request(token, "DELETE", path20);
5903
+ const path21 = `${messagePath(scope, targetId)}/${messageId}`;
5904
+ await this.client.request(token, "DELETE", path21);
5905
5905
  }
5906
- async sendAndNotify(_appId, accessToken, method, path20, body, meta) {
5907
- const result = await this.client.request(accessToken, method, path20, body);
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, path20, handler) {
6788
+ async listen(port, path21, handler) {
6789
6789
  return new Promise((resolve2, reject) => {
6790
- const server = http.createServer(async (req, res) => {
6791
- if (req.method !== "POST" || req.url !== path20) {
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
- req.on("data", (chunk) => chunks.push(chunk));
6798
- req.on("end", async () => {
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(req.headers)) {
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 path20 = this.opts.path ?? "/";
6854
- this.log?.info?.(`[webhook] starting on port ${port}, path ${path20}`);
6855
- await this.server.listen(port, path20, (req) => this.handleRequest(req));
6856
- this.log?.info?.(`[webhook] listening on :${port}${path20}`);
6857
- this.callbacks.onReady?.({ transport: "webhook", port, path: path20 });
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(req) {
6882
+ async handleRequest(req4) {
6883
6883
  let payload;
6884
6884
  try {
6885
- payload = JSON.parse(req.body.toString("utf-8"));
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(req.headers, "x-signature-timestamp") ?? "";
6894
- const signature = getHeader(req.headers, "x-signature-ed25519") ?? "";
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: req.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 req = {
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
- req.stream_msg_id = this.streamMsgId;
7175
+ req4.stream_msg_id = this.streamMsgId;
7176
7176
  }
7177
- const resp = await this.sendWithRetry(req);
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(req) {
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, req);
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
- req.index = this.index++;
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: (path20, query) => this.apiRequest("GET", path20, void 0, query),
7748
- post: (path20, body) => this.apiRequest("POST", path20, body),
7749
- put: (path20, body) => this.apiRequest("PUT", path20, body),
7750
- patch: (path20, body) => this.apiRequest("PATCH", path20, body),
7751
- delete: (path20) => this.apiRequest("DELETE", path20),
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, path20, body, query) {
7756
+ async apiRequest(method, path21, body, query) {
7757
7757
  const token = await this.tokenManager.getAccessToken(this.creds.appId, this.creds.clientSecret);
7758
- let fullPath = path20;
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 = `${path20}?${params.toString()}`;
7765
+ fullPath = `${path21}?${params.toString()}`;
7766
7766
  }
7767
7767
  return this.apiClient.request(token, method, fullPath, body ?? void 0);
7768
7768
  }
@@ -9089,21 +9089,11 @@ 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
9094
  var _resolvedPkgPath = null;
9097
- function getCurrentFilename(metaUrl) {
9098
- if (metaUrl) {
9099
- return (0, import_node_url.fileURLToPath)(metaUrl);
9100
- }
9101
- if (typeof __filename !== "undefined") {
9102
- return __filename;
9103
- }
9104
- return process.cwd();
9105
- }
9106
- function getPackageVersion(metaUrl) {
9095
+ var _cachedOpenclawVersion;
9096
+ function getPackageVersion() {
9107
9097
  if (_resolvedPkgPath) {
9108
9098
  try {
9109
9099
  const pkg = JSON.parse(import_node_fs2.default.readFileSync(_resolvedPkgPath, "utf8"));
@@ -9114,44 +9104,87 @@ function getPackageVersion(metaUrl) {
9114
9104
  _resolvedPkgPath = null;
9115
9105
  }
9116
9106
  }
9117
- const startFile = getCurrentFilename(metaUrl);
9118
- let dir = import_node_path2.default.dirname(startFile);
9119
- const root = import_node_path2.default.parse(dir).root;
9120
- while (dir !== root) {
9121
- const candidate = import_node_path2.default.join(dir, "package.json");
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;
9107
+ if (typeof __filename === "string") {
9108
+ let dir = import_node_path2.default.dirname(__filename);
9109
+ const root = import_node_path2.default.parse(dir).root;
9110
+ while (dir !== root) {
9111
+ const candidate = import_node_path2.default.join(dir, "package.json");
9112
+ try {
9113
+ if (import_node_fs2.default.existsSync(candidate)) {
9114
+ const pkg = JSON.parse(import_node_fs2.default.readFileSync(candidate, "utf8"));
9115
+ if (pkg.name === "@tencent-connect/openclaw-qqbot" && pkg.version) {
9116
+ _resolvedPkgPath = candidate;
9117
+ return pkg.version;
9118
+ }
9128
9119
  }
9120
+ } catch {
9129
9121
  }
9130
- } catch {
9122
+ dir = import_node_path2.default.dirname(dir);
9131
9123
  }
9132
- dir = import_node_path2.default.dirname(dir);
9133
9124
  }
9125
+ return "unknown";
9126
+ }
9127
+ function getOpenclawVersion(runtimeVersion) {
9128
+ if (_cachedOpenclawVersion) return _cachedOpenclawVersion;
9129
+ if (runtimeVersion && runtimeVersion !== "unknown") {
9130
+ return _cachedOpenclawVersion = runtimeVersion;
9131
+ }
9132
+ if (process.env.OPENCLAW_VERSION) {
9133
+ return _cachedOpenclawVersion = process.env.OPENCLAW_VERSION;
9134
+ }
9135
+ if (process.env.OPENCLAW_SERVICE_VERSION) {
9136
+ return _cachedOpenclawVersion = process.env.OPENCLAW_SERVICE_VERSION;
9137
+ }
9138
+ const pkgVer = readOpenclawPackageVersion();
9139
+ if (pkgVer) return _cachedOpenclawVersion = pkgVer;
9140
+ return "unknown";
9141
+ }
9142
+ function readOpenclawPackageVersion() {
9134
9143
  try {
9135
- const req = (0, import_node_module.createRequire)(__filename);
9136
- for (const rel of ["../../package.json", "../package.json", "./package.json"]) {
9144
+ const dirs = searchRoots();
9145
+ for (const dir of dirs) {
9146
+ const pkgPath = import_node_path2.default.join(dir, "package.json");
9137
9147
  try {
9138
- const pkg = req(rel);
9139
- if (pkg?.version) {
9140
- return pkg.version;
9141
- }
9148
+ const pkg = JSON.parse(import_node_fs2.default.readFileSync(pkgPath, "utf8"));
9149
+ if (pkg.name === "openclaw" && pkg.version) return pkg.version;
9142
9150
  } catch {
9143
9151
  }
9144
9152
  }
9145
9153
  } catch {
9146
9154
  }
9147
- return "unknown";
9155
+ return void 0;
9156
+ }
9157
+ function searchRoots() {
9158
+ const roots = [];
9159
+ if (typeof __filename === "string") {
9160
+ let dir = import_node_path2.default.dirname(__filename);
9161
+ for (let i = 0; i < 10; i++) {
9162
+ roots.push(dir);
9163
+ const parent = import_node_path2.default.dirname(dir);
9164
+ if (parent === dir) break;
9165
+ dir = parent;
9166
+ }
9167
+ }
9168
+ for (const key of ["OPENCLAW_STATE_DIR", "CLAWDBOT_STATE_DIR", "MOLTBOT_STATE_DIR"]) {
9169
+ const v = process.env[key];
9170
+ if (v) {
9171
+ roots.push(import_node_path2.default.dirname(v));
9172
+ roots.push(import_node_path2.default.resolve(v, ".."));
9173
+ }
9174
+ }
9175
+ const home = process.env.HOME || process.env.USERPROFILE || "/tmp";
9176
+ for (const name of ["openclaw", "clawdbot", "moltbot"]) {
9177
+ roots.push(import_node_path2.default.join(home, `.${name}`));
9178
+ }
9179
+ roots.push(process.cwd());
9180
+ return [...new Set(roots.filter((r) => typeof r === "string" && r.length > 0))];
9148
9181
  }
9149
9182
 
9150
9183
  // src/bot-instance.ts
9151
9184
  var PLUGIN_VERSION = getPackageVersion();
9152
9185
  var _openclawVersion = "unknown";
9153
9186
  function setOpenClawVersion(version) {
9154
- _openclawVersion = version;
9187
+ if (version) _openclawVersion = version;
9155
9188
  }
9156
9189
  function getOpenClawVersion() {
9157
9190
  return _openclawVersion;
@@ -9471,7 +9504,8 @@ var runtime = null;
9471
9504
  var exitHooksInstalled = false;
9472
9505
  function setQQBotRuntime(next) {
9473
9506
  runtime = next;
9474
- setOpenClawVersion(next.version);
9507
+ const version = getOpenclawVersion(next.version);
9508
+ setOpenClawVersion(version);
9475
9509
  installExitHooksOnce();
9476
9510
  }
9477
9511
  function installExitHooksOnce() {
@@ -9501,14 +9535,14 @@ function tryGetQQBotRuntime() {
9501
9535
  return runtime;
9502
9536
  }
9503
9537
 
9504
- // src/runtime-adapter/resolve.ts
9538
+ // src/adapter/resolve.ts
9505
9539
  function probeFunction(rt, paths) {
9506
- for (const path20 of paths) {
9540
+ for (const path21 of paths) {
9507
9541
  let target = rt;
9508
9542
  let parent = rt;
9509
- for (let i = 0; i < path20.length; i++) {
9543
+ for (let i = 0; i < path21.length; i++) {
9510
9544
  parent = target;
9511
- target = target?.[path20[i]];
9545
+ target = target?.[path21[i]];
9512
9546
  if (target === void 0 || target === null) break;
9513
9547
  }
9514
9548
  if (typeof target === "function") {
@@ -9578,7 +9612,7 @@ function resolveRuntimeAdapters(rt, log4) {
9578
9612
  const chunkMarkdownText = probeFunction(rt, [
9579
9613
  ["channel", "text", "chunkMarkdownText"]
9580
9614
  ]);
9581
- const saveRemoteMedia2 = probeFunction(rt, [
9615
+ const saveRemoteMedia = probeFunction(rt, [
9582
9616
  ["channel", "media", "saveRemoteMedia"]
9583
9617
  ]);
9584
9618
  const getConfig = probeFunction(rt, [
@@ -9607,7 +9641,7 @@ function resolveRuntimeAdapters(rt, log4) {
9607
9641
  recordInboundSession && "recordInboundSession",
9608
9642
  formatEnvelope && "formatEnvelope",
9609
9643
  chunkMarkdownText && "chunkMarkdownText",
9610
- saveRemoteMedia2 && "saveRemoteMedia",
9644
+ saveRemoteMedia && "saveRemoteMedia",
9611
9645
  getConfig && "getConfig",
9612
9646
  persistConfig && `persistConfig(${rawMutateConfig ? "mutate" : "write"})`
9613
9647
  ].filter(Boolean);
@@ -9624,7 +9658,7 @@ function resolveRuntimeAdapters(rt, log4) {
9624
9658
  formatEnvelope,
9625
9659
  resolveEnvelopeFormatOptions,
9626
9660
  chunkMarkdownText,
9627
- saveRemoteMedia: saveRemoteMedia2,
9661
+ saveRemoteMedia,
9628
9662
  getConfig,
9629
9663
  persistConfig,
9630
9664
  version
@@ -9646,7 +9680,24 @@ function getAdapters(rt, log4) {
9646
9680
  var path8 = __toESM(require("path"), 1);
9647
9681
  var fs9 = __toESM(require("fs"), 1);
9648
9682
  var os4 = __toESM(require("os"), 1);
9649
- var import_health = require("openclaw/plugin-sdk/health");
9683
+
9684
+ // src/adapter/workspace.ts
9685
+ var import_node_module = require("module");
9686
+ var req = (0, import_node_module.createRequire)(__filename);
9687
+ var health = null;
9688
+ function resolveAgentWorkspace(cfg, agentId) {
9689
+ if (!health) {
9690
+ try {
9691
+ health = req("openclaw/plugin-sdk/health");
9692
+ } catch {
9693
+ health = null;
9694
+ }
9695
+ }
9696
+ if (health) {
9697
+ return health.resolveAgentWorkspaceDir(cfg, agentId ?? health.resolveDefaultAgentId(cfg));
9698
+ }
9699
+ return getQQBotMediaDir();
9700
+ }
9650
9701
 
9651
9702
  // src/outbound/local-file-router.ts
9652
9703
  var path7 = __toESM(require("path"), 1);
@@ -9774,11 +9825,7 @@ function resolveMediaPath(source, log4, workspaceDir) {
9774
9825
  function resolveWorkspaceFromAgent(agentId) {
9775
9826
  const cfg = resolveConfigViaAdapter();
9776
9827
  if (!cfg) return void 0;
9777
- try {
9778
- return (0, import_health.resolveAgentWorkspaceDir)(cfg, agentId ?? (0, import_health.resolveDefaultAgentId)(cfg));
9779
- } catch {
9780
- return void 0;
9781
- }
9828
+ return resolveAgentWorkspace(cfg, agentId);
9782
9829
  }
9783
9830
  function resolveConfigViaAdapter() {
9784
9831
  try {
@@ -9867,12 +9914,48 @@ function formatErr(err) {
9867
9914
  return String(err);
9868
9915
  }
9869
9916
 
9870
- // src/setup/surface.ts
9871
- var import_setup2 = require("openclaw/plugin-sdk/setup");
9872
-
9873
- // src/setup/finalize.ts
9874
- var import_setup = require("openclaw/plugin-sdk/setup");
9875
- var import_setup_tools = require("openclaw/plugin-sdk/setup-tools");
9917
+ // src/adapter/setup.ts
9918
+ var import_node_module2 = require("module");
9919
+ var req2 = (0, import_node_module2.createRequire)(__filename);
9920
+ var _setup;
9921
+ var _tools;
9922
+ function loadSetup() {
9923
+ if (_setup !== void 0) return _setup;
9924
+ try {
9925
+ _setup = req2("openclaw/plugin-sdk/setup");
9926
+ } catch {
9927
+ _setup = null;
9928
+ }
9929
+ return _setup;
9930
+ }
9931
+ function loadTools() {
9932
+ if (_tools !== void 0) return _tools;
9933
+ try {
9934
+ _tools = req2("openclaw/plugin-sdk/setup-tools");
9935
+ } catch {
9936
+ _tools = null;
9937
+ }
9938
+ return _tools;
9939
+ }
9940
+ var DEFAULT_ACCOUNT_ID2 = "default";
9941
+ function createStandardChannelSetupStatus(...args) {
9942
+ const mod = loadSetup();
9943
+ if (mod) return mod.createStandardChannelSetupStatus(...args);
9944
+ return {
9945
+ channelLabel: args[0]?.channelLabel ?? "QQ Bot",
9946
+ configuredLabel: "Configured",
9947
+ unconfiguredLabel: "Not configured",
9948
+ resolveConfigured: () => false
9949
+ };
9950
+ }
9951
+ function setSetupChannelEnabled(...args) {
9952
+ loadSetup()?.setSetupChannelEnabled?.(...args);
9953
+ }
9954
+ function formatDocsLink(...args) {
9955
+ const mod = loadTools();
9956
+ if (mod) return mod.formatDocsLink(...args);
9957
+ return args[1] ? `${args[1]}: ${args[0]}` : args[0];
9958
+ }
9876
9959
 
9877
9960
  // node_modules/.pnpm/@tencent-connect+qqbot-connector@1.2.0/node_modules/@tencent-connect/qqbot-connector/dist/esm/qr-connect.js
9878
9961
  var import_qrcode_terminal = __toESM(require_main(), 1);
@@ -10039,7 +10122,7 @@ async function linkViaQrCode(cfg, accountId, prompter, rt) {
10039
10122
  } catch (err) {
10040
10123
  rt.error(`QQ Bot \u7ED1\u5B9A\u5931\u8D25: ${String(err)}`);
10041
10124
  await prompter.note(`\u7ED1\u5B9A\u5931\u8D25\uFF0C\u60A8\u53EF\u4EE5\u7A0D\u540E\u624B\u52A8\u914D\u7F6E\u3002
10042
- \u6587\u6863: ${(0, import_setup_tools.formatDocsLink)("/channels/qqbot", "qqbot")}`, "QQ Bot");
10125
+ \u6587\u6863: ${formatDocsLink("/channels/qqbot", "qqbot")}`, "QQ Bot");
10043
10126
  return cfg;
10044
10127
  }
10045
10128
  }
@@ -10052,7 +10135,7 @@ async function linkViaManual(cfg, prompter) {
10052
10135
  return next;
10053
10136
  }
10054
10137
  async function finalizeQQBotSetup(params) {
10055
- const accountId = params.accountId.trim() || import_setup.DEFAULT_ACCOUNT_ID;
10138
+ const accountId = params.accountId.trim() || DEFAULT_ACCOUNT_ID2;
10056
10139
  const configured = isConfigured(params.cfg, accountId);
10057
10140
  const mode = await params.prompter.select({
10058
10141
  message: configured ? "QQ \u5DF2\u7ED1\u5B9A\uFF0C\u9009\u62E9\u64CD\u4F5C" : "\u9009\u62E9 QQ \u7ED1\u5B9A\u65B9\u5F0F",
@@ -10077,7 +10160,7 @@ function applyAccountDefaults(cfg, accountId, userOpenid) {
10077
10160
  const qqbot = { ...next.channels?.qqbot ?? {} };
10078
10161
  const defaults = { streaming: true, dmPolicy: "allowlist" };
10079
10162
  if (userOpenid) defaults.allowFrom = [userOpenid];
10080
- if (accountId === import_setup.DEFAULT_ACCOUNT_ID) {
10163
+ if (accountId === DEFAULT_ACCOUNT_ID2) {
10081
10164
  Object.assign(qqbot, defaults);
10082
10165
  } else {
10083
10166
  const accounts = { ...qqbot.accounts ?? {} };
@@ -10089,11 +10172,10 @@ function applyAccountDefaults(cfg, accountId, userOpenid) {
10089
10172
  }
10090
10173
 
10091
10174
  // src/setup/surface.ts
10092
- var import_setup3 = require("openclaw/plugin-sdk/setup");
10093
10175
  var CHANNEL = "qqbot";
10094
10176
  var qqbotSetupWizard = {
10095
10177
  channel: CHANNEL,
10096
- status: (0, import_setup2.createStandardChannelSetupStatus)({
10178
+ status: createStandardChannelSetupStatus({
10097
10179
  channelLabel: "QQ Bot",
10098
10180
  configuredLabel: "configured",
10099
10181
  unconfiguredLabel: "needs AppID + AppSecret",
@@ -10109,7 +10191,10 @@ var qqbotSetupWizard = {
10109
10191
  credentials: [],
10110
10192
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
10111
10193
  finalize: (async ({ cfg, accountId, prompter, runtime: runtime2 }) => finalizeQQBotSetup({ cfg, accountId, prompter, runtime: runtime2 })),
10112
- disable: (cfg) => (0, import_setup3.setSetupChannelEnabled)(cfg, CHANNEL, false)
10194
+ disable: (cfg) => {
10195
+ setSetupChannelEnabled(cfg, CHANNEL, false);
10196
+ return cfg;
10197
+ }
10113
10198
  };
10114
10199
 
10115
10200
  // src/gateway/qqbot-gateway.ts
@@ -10196,7 +10281,7 @@ var REGISTRIES = [
10196
10281
  var CURRENT_VERSION = getPackageVersion();
10197
10282
  function fetchJson(url, timeoutMs) {
10198
10283
  return new Promise((resolve2, reject) => {
10199
- const req = import_node_https2.default.get(url, { timeout: timeoutMs, headers: { Accept: "application/json" } }, (res) => {
10284
+ const req4 = import_node_https2.default.get(url, { timeout: timeoutMs, headers: { Accept: "application/json" } }, (res) => {
10200
10285
  if (res.statusCode !== 200) {
10201
10286
  res.resume();
10202
10287
  reject(new Error(`HTTP ${res.statusCode} from ${url}`));
@@ -10214,9 +10299,9 @@ function fetchJson(url, timeoutMs) {
10214
10299
  }
10215
10300
  });
10216
10301
  });
10217
- req.on("error", reject);
10218
- req.on("timeout", () => {
10219
- req.destroy();
10302
+ req4.on("error", reject);
10303
+ req4.on("timeout", () => {
10304
+ req4.destroy();
10220
10305
  reject(new Error(`timeout fetching ${url}`));
10221
10306
  });
10222
10307
  });
@@ -10640,10 +10725,10 @@ function collectCandidateLogDirs(runtime2) {
10640
10725
  pushDir(import_node_path5.default.join(homeDir, name));
10641
10726
  pushDir(import_node_path5.default.join(homeDir, name, "logs"));
10642
10727
  }
10643
- const searchRoots = /* @__PURE__ */ new Set([homeDir, process.cwd(), import_node_path5.default.dirname(process.cwd())]);
10644
- if (process.env.APPDATA) searchRoots.add(process.env.APPDATA);
10645
- if (process.env.LOCALAPPDATA) searchRoots.add(process.env.LOCALAPPDATA);
10646
- for (const root of searchRoots) {
10728
+ const searchRoots2 = /* @__PURE__ */ new Set([homeDir, process.cwd(), import_node_path5.default.dirname(process.cwd())]);
10729
+ if (process.env.APPDATA) searchRoots2.add(process.env.APPDATA);
10730
+ if (process.env.LOCALAPPDATA) searchRoots2.add(process.env.LOCALAPPDATA);
10731
+ for (const root of searchRoots2) {
10647
10732
  try {
10648
10733
  const entries = import_node_fs5.default.readdirSync(root, { withFileTypes: true });
10649
10734
  for (const entry of entries) {
@@ -10955,8 +11040,8 @@ function botGroupAlways(account, getRuntime) {
10955
11040
  };
10956
11041
  }
10957
11042
 
10958
- // src/runtime-adapter/pairing-runtime.ts
10959
- var import_node_module2 = require("module");
11043
+ // src/adapter/pairing.ts
11044
+ var import_node_module3 = require("module");
10960
11045
  var import_node_path6 = __toESM(require("path"), 1);
10961
11046
  var _api;
10962
11047
  function getPairingApi() {
@@ -10966,14 +11051,14 @@ function getPairingApi() {
10966
11051
  }
10967
11052
  function loadPairingApi() {
10968
11053
  const currentFile = __filename;
10969
- const req = (0, import_node_module2.createRequire)(currentFile);
11054
+ const req4 = (0, import_node_module3.createRequire)(currentFile);
10970
11055
  const pluginRoot = import_node_path6.default.resolve(import_node_path6.default.dirname(currentFile), "..", "..");
10971
- const fs20 = req("node:fs");
11056
+ const fs21 = req4("node:fs");
10972
11057
  const tryLoad = (root) => {
10973
11058
  for (const rel of ["dist/plugin-sdk/conversation-runtime.js", "plugin-sdk/conversation-runtime.js"]) {
10974
11059
  const p2 = import_node_path6.default.join(root, rel);
10975
11060
  try {
10976
- if (fs20.existsSync(p2)) return req(p2);
11061
+ if (fs21.existsSync(p2)) return req4(p2);
10977
11062
  } catch {
10978
11063
  }
10979
11064
  }
@@ -10981,7 +11066,7 @@ function loadPairingApi() {
10981
11066
  };
10982
11067
  let mod = null;
10983
11068
  try {
10984
- const { findOpenclawRoot } = req(import_node_path6.default.join(pluginRoot, "scripts", "link-sdk-core.cjs"));
11069
+ const { findOpenclawRoot } = req4(import_node_path6.default.join(pluginRoot, "scripts", "link-sdk-core.cjs"));
10985
11070
  const root = findOpenclawRoot(pluginRoot);
10986
11071
  if (root) mod = tryLoad(root);
10987
11072
  } catch {
@@ -10990,7 +11075,7 @@ function loadPairingApi() {
10990
11075
  try {
10991
11076
  const entry = process.argv[1];
10992
11077
  if (entry) {
10993
- const realEntry = fs20.realpathSync(entry);
11078
+ const realEntry = fs21.realpathSync(entry);
10994
11079
  let dir = import_node_path6.default.dirname(realEntry);
10995
11080
  for (let i = 0; i < 6; i++) {
10996
11081
  mod = tryLoad(dir);
@@ -11098,7 +11183,7 @@ function buildCommandList(account, opts) {
11098
11183
  }
11099
11184
 
11100
11185
  // src/middleware/attachment.ts
11101
- var path16 = __toESM(require("path"), 1);
11186
+ var path17 = __toESM(require("path"), 1);
11102
11187
 
11103
11188
  // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607081646/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/utils/reply-limiter.js
11104
11189
  var DEFAULT_TTL_MS = 60 * 60 * 1e3;
@@ -11258,9 +11343,6 @@ function isVoiceAttachment(att) {
11258
11343
  return [".amr", ".silk", ".slk", ".slac"].includes(ext);
11259
11344
  }
11260
11345
 
11261
- // src/middleware/attachment.ts
11262
- var import_media_runtime = require("openclaw/plugin-sdk/media-runtime");
11263
-
11264
11346
  // src/utils/stt.ts
11265
11347
  var fs17 = __toESM(require("fs"), 1);
11266
11348
  var path15 = __toESM(require("path"), 1);
@@ -11379,6 +11461,78 @@ function formatDuration2(seconds) {
11379
11461
  return `${mins}:${secs.toString().padStart(2, "0")}`;
11380
11462
  }
11381
11463
 
11464
+ // src/adapter/media.ts
11465
+ var import_node_module4 = require("module");
11466
+ var dns = __toESM(require("dns"), 1);
11467
+ var path16 = __toESM(require("path"), 1);
11468
+ var fs18 = __toESM(require("fs"), 1);
11469
+ var crypto4 = __toESM(require("crypto"), 1);
11470
+ var req3 = (0, import_node_module4.createRequire)(__filename);
11471
+ var _save;
11472
+ function downloadRemoteMedia(opts) {
11473
+ if (_save === void 0) {
11474
+ try {
11475
+ const mod = req3("openclaw/plugin-sdk/media-runtime");
11476
+ _save = mod.saveRemoteMedia;
11477
+ } catch {
11478
+ _save = null;
11479
+ }
11480
+ }
11481
+ return _save ? _save(opts) : downloadViaFetch(opts);
11482
+ }
11483
+ var PRIVATE_RANGES = [
11484
+ [0x0A000000n, 8],
11485
+ // 10.0.0.0/8
11486
+ [0xAC100000n, 12],
11487
+ // 172.16.0.0/12
11488
+ [0xC0A80000n, 16],
11489
+ // 192.168.0.0/16
11490
+ [0x7F000000n, 8],
11491
+ // 127.0.0.0/8
11492
+ [0xA9FE0000n, 16],
11493
+ // 169.254.0.0/16
11494
+ [0xE0000000n, 4]
11495
+ // 224.0.0.0/4 (multicast)
11496
+ ];
11497
+ function ipToBigInt(ip) {
11498
+ return ip.split(".").reduce((acc, octet) => acc << 8n | BigInt(Number(octet)), 0n);
11499
+ }
11500
+ function isPrivateIP(ip) {
11501
+ const val = ipToBigInt(ip);
11502
+ return PRIVATE_RANGES.some(([mask, prefix]) => val >> 32n - BigInt(prefix) === mask >> 32n - BigInt(prefix));
11503
+ }
11504
+ async function assertSafeHostname(hostname) {
11505
+ const addresses = await dns.promises.resolve4(hostname).catch(() => []);
11506
+ if (addresses.length === 0) throw new Error(`DNS resolution failed: ${hostname}`);
11507
+ for (const addr of addresses) {
11508
+ if (isPrivateIP(addr)) {
11509
+ throw new Error(`SSRF blocked: ${hostname} resolves to private IP ${addr}`);
11510
+ }
11511
+ }
11512
+ }
11513
+ async function downloadViaFetch(opts) {
11514
+ const parsed = new URL(opts.url);
11515
+ if (parsed.protocol !== "https:") {
11516
+ throw new Error(`Only HTTPS allowed: ${parsed.protocol}`);
11517
+ }
11518
+ await assertSafeHostname(parsed.hostname);
11519
+ const dir = getQQBotMediaDir(opts.subdir ?? "downloads");
11520
+ if (!fs18.existsSync(dir)) fs18.mkdirSync(dir, { recursive: true });
11521
+ const resp = await fetch(opts.url, {
11522
+ signal: AbortSignal.timeout(opts.timeoutMs ?? 12e4)
11523
+ });
11524
+ if (!resp.ok) throw new Error(`Download HTTP ${resp.status}`);
11525
+ const maxBytes = opts.maxBytes ?? 500 * 1024 * 1024;
11526
+ const buf = Buffer.from(await resp.arrayBuffer());
11527
+ if (buf.length > maxBytes) throw new Error(`Download exceeds ${(maxBytes / 1024 / 1024).toFixed(0)}MB`);
11528
+ const ext = opts.originalFilename ? path16.extname(opts.originalFilename) || ".bin" : ".bin";
11529
+ const name = opts.originalFilename ? path16.basename(opts.originalFilename, path16.extname(opts.originalFilename)) : "download";
11530
+ const rand = crypto4.randomBytes(4).toString("hex");
11531
+ const filePath = path16.join(dir, `${name}_${Date.now()}_${rand}${ext}`);
11532
+ fs18.writeFileSync(filePath, buf);
11533
+ return { path: filePath };
11534
+ }
11535
+
11382
11536
  // src/middleware/attachment.ts
11383
11537
  function attachmentProcessor(opts) {
11384
11538
  return async (ctx, next) => {
@@ -11494,7 +11648,7 @@ async function processVoiceAttachment(att, sttCfg, audioPolicy, log4) {
11494
11648
  if (silkUrl) {
11495
11649
  const silkPath = await downloadMediaFile(silkUrl, att.filename, log4);
11496
11650
  if (silkPath) {
11497
- const ext = path16.extname(silkPath).toLowerCase();
11651
+ const ext = path17.extname(silkPath).toLowerCase();
11498
11652
  if (audioPolicy.sttDirectFormats.includes(ext)) {
11499
11653
  localPath = silkPath;
11500
11654
  } else {
@@ -11567,12 +11721,12 @@ async function downloadMediaFile(url, filename, log4) {
11567
11721
  return null;
11568
11722
  }
11569
11723
  try {
11570
- const result = await (0, import_media_runtime.saveRemoteMedia)({
11724
+ const result = await downloadRemoteMedia({
11571
11725
  url,
11572
11726
  subdir: "qqbot/downloads",
11573
11727
  originalFilename: filename,
11574
11728
  maxBytes: 500 * 1024 * 1024,
11575
- timeoutMs: 6e4
11729
+ timeoutMs: 12e4
11576
11730
  });
11577
11731
  log4?.debug?.(`Downloaded: ${result.path}`);
11578
11732
  return result.path;
@@ -12301,10 +12455,6 @@ async function dispatchToOpenClaw(ctx, msg, account, runtime2, log4) {
12301
12455
  const adapters = getAdapters(runtime2, dlog);
12302
12456
  const envelope = buildEnvelope2(ctx, msg, account);
12303
12457
  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
12458
  if (!adapters.dispatchReply) {
12309
12459
  dlog?.error(`runtime adapter dispatchReply not available (openclaw=${adapters.version})`);
12310
12460
  return;
@@ -12400,127 +12550,160 @@ async function dispatchToOpenClaw(ctx, msg, account, runtime2, log4) {
12400
12550
  if (streamingController) {
12401
12551
  dlog?.debug(`streaming enabled for ${envelope.senderId}`);
12402
12552
  }
12403
- await adapters.inboundRun({
12404
- channel: "qqbot",
12405
- accountId: route.accountId,
12406
- raw: envelope,
12407
- adapter: {
12408
- ingest: (raw) => ({
12409
- id: envelope.messageId,
12410
- rawText: assembled.rawBody,
12411
- textForAgent: assembled.agentBody,
12412
- textForCommands: assembled.rawBody,
12413
- raw
12414
- }),
12415
- resolveTurn: (_input, _eventClass, _preflight) => ({
12416
- channel: "qqbot",
12417
- accountId: route.accountId,
12418
- routeSessionKey: route.sessionKey,
12419
- storePath,
12420
- ctxPayload,
12421
- recordInboundSession: adapters.recordInboundSession,
12422
- record: {
12423
- onRecordError: (err) => {
12424
- dlog?.error(`Session record error: ${err}`);
12553
+ if (!adapters.inboundRun) {
12554
+ if (adapters.recordInboundSession) {
12555
+ try {
12556
+ await adapters.recordInboundSession({
12557
+ storePath,
12558
+ sessionKey: route.sessionKey,
12559
+ ctx: ctxPayload
12560
+ });
12561
+ } catch {
12562
+ }
12563
+ }
12564
+ await adapters.dispatchReply({
12565
+ ctx: ctxPayload,
12566
+ cfg,
12567
+ dispatcherOptions: {
12568
+ deliver: async (payload, info) => {
12569
+ await deliverReply(payload, info, deliverCtx);
12570
+ }
12571
+ },
12572
+ ...streamingController ? {
12573
+ replyOptions: {
12574
+ onPartialReply: async (p2) => {
12575
+ if (p2.text) await streamingController.onPartialReply(p2.text);
12425
12576
  }
12426
- },
12427
- runDispatch: () => {
12428
- let blockDelivered = false;
12429
- const deliveredMediaUrls = /* @__PURE__ */ new Set();
12430
- return adapters.dispatchReply({
12431
- ctx: ctxPayload,
12432
- cfg,
12433
- dispatcherOptions: {
12434
- deliver: async (payload, info) => {
12435
- try {
12436
- const kind = info?.kind;
12437
- 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}`);
12438
- if (kind === "block") {
12439
- if (payload.audioAsVoice) {
12440
- await deliverReply(payload, info, deliverCtx);
12441
- } else {
12442
- const urls = payload.mediaUrls?.length ? payload.mediaUrls : payload.mediaUrl ? [payload.mediaUrl] : [];
12443
- for (const url of urls) {
12577
+ }
12578
+ } : {}
12579
+ });
12580
+ if (streamingController && !streamingController.isTerminal) {
12581
+ await streamingController.finalize();
12582
+ }
12583
+ if (debouncer) await debouncer.flushAll();
12584
+ } else {
12585
+ await adapters.inboundRun({
12586
+ channel: "qqbot",
12587
+ accountId: route.accountId,
12588
+ raw: envelope,
12589
+ adapter: {
12590
+ ingest: (raw) => ({
12591
+ id: envelope.messageId,
12592
+ rawText: assembled.rawBody,
12593
+ textForAgent: assembled.agentBody,
12594
+ textForCommands: assembled.rawBody,
12595
+ raw
12596
+ }),
12597
+ resolveTurn: (_input, _eventClass, _preflight) => ({
12598
+ channel: "qqbot",
12599
+ accountId: route.accountId,
12600
+ routeSessionKey: route.sessionKey,
12601
+ storePath,
12602
+ ctxPayload,
12603
+ recordInboundSession: adapters.recordInboundSession,
12604
+ record: {
12605
+ onRecordError: (err) => {
12606
+ dlog?.error(`Session record error: ${err}`);
12607
+ }
12608
+ },
12609
+ runDispatch: () => {
12610
+ let blockDelivered = false;
12611
+ const deliveredMediaUrls = /* @__PURE__ */ new Set();
12612
+ return adapters.dispatchReply({
12613
+ ctx: ctxPayload,
12614
+ cfg,
12615
+ dispatcherOptions: {
12616
+ deliver: async (payload, info) => {
12617
+ try {
12618
+ const kind = info?.kind;
12619
+ 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}`);
12620
+ if (kind === "block") {
12621
+ if (payload.audioAsVoice) {
12622
+ await deliverReply(payload, info, deliverCtx);
12623
+ } else {
12624
+ const urls = payload.mediaUrls?.length ? payload.mediaUrls : payload.mediaUrl ? [payload.mediaUrl] : [];
12625
+ for (const url of urls) {
12626
+ try {
12627
+ await sendMedia2({
12628
+ to: deliverCtx.qualifiedTarget,
12629
+ source: url,
12630
+ text: "",
12631
+ replyToId: deliverCtx.replyToId,
12632
+ accountId: deliverCtx.accountId,
12633
+ log: deliverCtx.log,
12634
+ agentId: deliverCtx.agentId
12635
+ });
12636
+ deliveredMediaUrls.add(url);
12637
+ } catch (err) {
12638
+ dlog?.error(`block media failed: ${err instanceof Error ? err.message : String(err)}`);
12639
+ }
12640
+ }
12641
+ }
12642
+ }
12643
+ if (streamingController && !streamingController.shouldFallbackToStatic) {
12644
+ if (kind !== "block") {
12645
+ await streamingController.finalize();
12646
+ }
12647
+ if (!streamingController.shouldFallbackToStatic) {
12648
+ if (kind === "block") return;
12649
+ return;
12650
+ }
12651
+ dlog?.warn(`streaming fallback to static`);
12652
+ }
12653
+ if (kind === "block") {
12654
+ blockDelivered = true;
12655
+ } else if (kind === "final" && blockDelivered) {
12656
+ return;
12657
+ }
12658
+ if (kind === "tool") {
12659
+ const toolMediaUrls = [];
12660
+ if (payload.mediaUrls?.length) toolMediaUrls.push(...payload.mediaUrls);
12661
+ if (payload.mediaUrl && !toolMediaUrls.includes(payload.mediaUrl)) toolMediaUrls.push(payload.mediaUrl);
12662
+ const newUrls = toolMediaUrls.filter((u2) => !deliveredMediaUrls.has(u2));
12663
+ for (const mediaUrl of newUrls) {
12444
12664
  try {
12445
12665
  await sendMedia2({
12446
12666
  to: deliverCtx.qualifiedTarget,
12447
- source: url,
12667
+ source: mediaUrl,
12448
12668
  text: "",
12449
12669
  replyToId: deliverCtx.replyToId,
12450
12670
  accountId: deliverCtx.accountId,
12451
12671
  log: deliverCtx.log,
12452
12672
  agentId: deliverCtx.agentId
12453
12673
  });
12454
- deliveredMediaUrls.add(url);
12674
+ deliveredMediaUrls.add(mediaUrl);
12675
+ dlog?.info(`tool media forwarded url=${mediaUrl.slice(0, 60)}`);
12455
12676
  } catch (err) {
12456
- dlog?.error(`block media failed: ${err instanceof Error ? err.message : String(err)}`);
12677
+ dlog?.error(`tool media forward failed: ${err instanceof Error ? err.message : String(err)}`);
12457
12678
  }
12458
12679
  }
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
12680
  return;
12468
12681
  }
12469
- dlog?.warn(`streaming fallback to static`);
12470
- }
12471
- if (kind === "block") {
12472
- blockDelivered = true;
12473
- } else if (kind === "final" && blockDelivered) {
12474
- return;
12475
- }
12476
- if (kind === "tool") {
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;
12682
+ const filteredPayload = deliveredMediaUrls.size > 0 ? {
12683
+ ...payload,
12684
+ mediaUrl: payload.mediaUrl && !deliveredMediaUrls.has(payload.mediaUrl) ? payload.mediaUrl : void 0,
12685
+ mediaUrls: payload.mediaUrls?.filter((u2) => !deliveredMediaUrls.has(u2))
12686
+ } : payload;
12687
+ await deliverReply(filteredPayload, info, deliverCtx);
12688
+ } catch (err) {
12689
+ dlog?.error(`error: ${err instanceof Error ? err.message : String(err)}`);
12499
12690
  }
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
12691
  }
12692
+ },
12693
+ replyOptions: {
12694
+ runId: envelope.messageId,
12695
+ ...streamingController ? {
12696
+ onPartialReply: async (p2) => {
12697
+ if (p2.text) await streamingController.onPartialReply(p2.text);
12698
+ }
12699
+ } : {}
12509
12700
  }
12510
- },
12511
- replyOptions: {
12512
- runId: envelope.messageId,
12513
- ...streamingController ? {
12514
- onPartialReply: async (p2) => {
12515
- if (p2.text) await streamingController.onPartialReply(p2.text);
12516
- }
12517
- } : {}
12518
- }
12519
- });
12520
- }
12521
- })
12522
- }
12523
- });
12701
+ });
12702
+ }
12703
+ })
12704
+ }
12705
+ });
12706
+ }
12524
12707
  dlog?.debug(`inboundRun completed sessionKey=${route.sessionKey}`);
12525
12708
  if (envelope.chatScope === "group") {
12526
12709
  clearGroupHistory(envelope.groupId ?? envelope.senderId);
@@ -12551,26 +12734,25 @@ function createStreamingController(envelope, account, log4) {
12551
12734
  });
12552
12735
  }
12553
12736
 
12554
- // src/runtime-adapter/gateway-runtime.ts
12555
- var import_node_module3 = require("module");
12737
+ // src/adapter/gateway.ts
12738
+ var import_node_module5 = require("module");
12556
12739
  var import_node_path8 = __toESM(require("path"), 1);
12557
12740
  function loadApprovalGatewayRuntime() {
12558
- const currentFile = __filename;
12559
- const req = (0, import_node_module3.createRequire)(currentFile);
12560
- const pluginRoot = import_node_path8.default.resolve(import_node_path8.default.dirname(currentFile), "..", "..");
12561
- const fs20 = req("node:fs");
12741
+ const req4 = (0, import_node_module5.createRequire)(__filename);
12742
+ const pluginRoot = import_node_path8.default.resolve(import_node_path8.default.dirname(__filename), "..", "..");
12743
+ const fs21 = req4("node:fs");
12562
12744
  const tryLoadFromRoot = (root) => {
12563
12745
  for (const rel of ["dist/plugin-sdk/gateway-runtime.js", "plugin-sdk/gateway-runtime.js"]) {
12564
12746
  const p2 = import_node_path8.default.join(root, rel);
12565
12747
  try {
12566
- if (fs20.existsSync(p2)) return req(p2);
12748
+ if (fs21.existsSync(p2)) return req4(p2);
12567
12749
  } catch {
12568
12750
  }
12569
12751
  }
12570
12752
  return null;
12571
12753
  };
12572
12754
  try {
12573
- const { findOpenclawRoot } = req(import_node_path8.default.join(pluginRoot, "scripts", "link-sdk-core.cjs"));
12755
+ const { findOpenclawRoot } = req4(import_node_path8.default.join(pluginRoot, "scripts", "link-sdk-core.cjs"));
12574
12756
  const root = findOpenclawRoot(pluginRoot);
12575
12757
  if (root) {
12576
12758
  const mod = tryLoadFromRoot(root);
@@ -12581,7 +12763,7 @@ function loadApprovalGatewayRuntime() {
12581
12763
  try {
12582
12764
  const entry = process.argv[1];
12583
12765
  if (entry) {
12584
- const realEntry = fs20.realpathSync(entry);
12766
+ const realEntry = fs21.realpathSync(entry);
12585
12767
  let dir = import_node_path8.default.dirname(realEntry);
12586
12768
  for (let i = 0; i < 6; i++) {
12587
12769
  const mod = tryLoadFromRoot(dir);
@@ -12864,16 +13046,16 @@ function getApprovalHandler(accountId) {
12864
13046
  }
12865
13047
 
12866
13048
  // src/features/proactive.ts
12867
- var fs18 = __toESM(require("fs"), 1);
12868
- var path18 = __toESM(require("path"), 1);
13049
+ var fs19 = __toESM(require("fs"), 1);
13050
+ var path19 = __toESM(require("path"), 1);
12869
13051
  var log2 = createPluginLogger({ prefix: "[proactive]" });
12870
13052
  var STORAGE_DIR = getQQBotDataDir("data");
12871
- var KNOWN_USERS_FILE = path18.join(STORAGE_DIR, "known-users.json");
13053
+ var KNOWN_USERS_FILE = path19.join(STORAGE_DIR, "known-users.json");
12872
13054
  var knownUsersCache = null;
12873
13055
  var cacheLastModified = 0;
12874
13056
  function ensureStorageDir() {
12875
- if (!fs18.existsSync(STORAGE_DIR)) {
12876
- fs18.mkdirSync(STORAGE_DIR, { recursive: true });
13057
+ if (!fs19.existsSync(STORAGE_DIR)) {
13058
+ fs19.mkdirSync(STORAGE_DIR, { recursive: true });
12877
13059
  }
12878
13060
  }
12879
13061
  function getUserKey(type, openid, accountId) {
@@ -12882,7 +13064,7 @@ function getUserKey(type, openid, accountId) {
12882
13064
  function loadKnownUsers() {
12883
13065
  if (knownUsersCache !== null) {
12884
13066
  try {
12885
- const stat = fs18.statSync(KNOWN_USERS_FILE);
13067
+ const stat = fs19.statSync(KNOWN_USERS_FILE);
12886
13068
  if (stat.mtimeMs <= cacheLastModified) {
12887
13069
  return knownUsersCache;
12888
13070
  }
@@ -12892,14 +13074,14 @@ function loadKnownUsers() {
12892
13074
  }
12893
13075
  const users = /* @__PURE__ */ new Map();
12894
13076
  try {
12895
- if (fs18.existsSync(KNOWN_USERS_FILE)) {
12896
- const data = fs18.readFileSync(KNOWN_USERS_FILE, "utf-8");
13077
+ if (fs19.existsSync(KNOWN_USERS_FILE)) {
13078
+ const data = fs19.readFileSync(KNOWN_USERS_FILE, "utf-8");
12897
13079
  const parsed = JSON.parse(data);
12898
13080
  for (const user of parsed) {
12899
13081
  const key = getUserKey(user.type, user.openid, user.accountId);
12900
13082
  users.set(key, user);
12901
13083
  }
12902
- cacheLastModified = fs18.statSync(KNOWN_USERS_FILE).mtimeMs;
13084
+ cacheLastModified = fs19.statSync(KNOWN_USERS_FILE).mtimeMs;
12903
13085
  }
12904
13086
  } catch (err) {
12905
13087
  log2.error(`Failed to load known users: ${err}`);
@@ -12911,7 +13093,7 @@ function saveKnownUsers(users) {
12911
13093
  try {
12912
13094
  ensureStorageDir();
12913
13095
  const data = Array.from(users.values());
12914
- fs18.writeFileSync(KNOWN_USERS_FILE, JSON.stringify(data, null, 2), "utf-8");
13096
+ fs19.writeFileSync(KNOWN_USERS_FILE, JSON.stringify(data, null, 2), "utf-8");
12915
13097
  cacheLastModified = Date.now();
12916
13098
  knownUsersCache = users;
12917
13099
  } catch (err) {
@@ -13106,7 +13288,7 @@ function setGroupRequireMention(runtime2, accountId, groupOpenid, requireMention
13106
13288
  }) ?? Promise.resolve();
13107
13289
  }
13108
13290
 
13109
- // src/runtime-adapter/webhook-adapter.ts
13291
+ // src/adapter/webhook.ts
13110
13292
  var sharedTargets = /* @__PURE__ */ new Map();
13111
13293
  var _routeUnregisters = /* @__PURE__ */ new Map();
13112
13294
  function createPluginWebhookAdapter(params) {
@@ -13114,13 +13296,13 @@ function createPluginWebhookAdapter(params) {
13114
13296
  let storedPath = "";
13115
13297
  const accountId = params.account.accountId;
13116
13298
  return {
13117
- async listen(_port, path20, handler) {
13299
+ async listen(_port, path21, handler) {
13118
13300
  const ingress = await import("openclaw/plugin-sdk/webhook-ingress").catch(() => null);
13119
13301
  if (!ingress?.registerWebhookTargetWithPluginRoute) {
13120
13302
  params.log.error("Webhook ingress not available");
13121
13303
  return;
13122
13304
  }
13123
- const webhookPath = storedPath = path20 && path20 !== "/" ? path20 : params.account.config.webhook?.path ?? "/qqbot/webhook";
13305
+ const webhookPath = storedPath = path21 && path21 !== "/" ? path21 : params.account.config.webhook?.path ?? "/qqbot/webhook";
13124
13306
  const existing = sharedTargets.get(webhookPath);
13125
13307
  if (existing) {
13126
13308
  const dupIdx = existing.findIndex((t) => t.accountId === accountId);
@@ -13167,16 +13349,16 @@ function createPluginWebhookAdapter(params) {
13167
13349
  }
13168
13350
  };
13169
13351
  }
13170
- function createSharedHandler(path20, log4) {
13171
- return async (req, res) => {
13352
+ function createSharedHandler(path21, log4) {
13353
+ return async (req4, res) => {
13172
13354
  try {
13173
13355
  const ingress = await import("openclaw/plugin-sdk/webhook-ingress").catch(() => null);
13174
13356
  if (!ingress?.withResolvedWebhookRequestPipeline) {
13175
- await handleSimple(req, res, path20, log4);
13357
+ await handleSimple(req4, res, path21, log4);
13176
13358
  return;
13177
13359
  }
13178
13360
  await ingress.withResolvedWebhookRequestPipeline({
13179
- req,
13361
+ req: req4,
13180
13362
  res,
13181
13363
  targetsByPath: sharedTargets,
13182
13364
  rateLimiter: ingress.createFixedWindowRateLimiter?.({
@@ -13191,7 +13373,7 @@ function createSharedHandler(path20, log4) {
13191
13373
  requireJsonContentType: true,
13192
13374
  handle: async ({ targets }) => {
13193
13375
  const bodyResult = await ingress.readWebhookBodyOrReject({
13194
- req,
13376
+ req: req4,
13195
13377
  res,
13196
13378
  maxBytes: 1048576,
13197
13379
  timeoutMs: 3e4
@@ -13213,25 +13395,25 @@ function createSharedHandler(path20, log4) {
13213
13395
  if (payload.op === 13) {
13214
13396
  const t = targets[0];
13215
13397
  if (!t) {
13216
- log4.warn?.(`[webhook] op:13 no target on ${path20}`);
13398
+ log4.warn?.(`[webhook] op:13 no target on ${path21}`);
13217
13399
  res.statusCode = 500;
13218
13400
  res.end(JSON.stringify({ error: "no target" }));
13219
13401
  return;
13220
13402
  }
13221
- const h3 = resolveTargetHandler(path20, t.accountId);
13403
+ const h3 = resolveTargetHandler(path21, t.accountId);
13222
13404
  if (!h3) {
13223
13405
  log4.warn?.(`[webhook] op:13 no handler for ${t.accountId}`);
13224
13406
  res.statusCode = 500;
13225
13407
  res.end(JSON.stringify({ error: "no handler" }));
13226
13408
  return;
13227
13409
  }
13228
- await delegateToHandler(h3, req, res, rawBody);
13410
+ await delegateToHandler(h3, req4, res, rawBody);
13229
13411
  return;
13230
13412
  }
13231
- const timestamp = getHeader2(req, "x-signature-timestamp") ?? "";
13232
- const signature = getHeader2(req, "x-signature-ed25519") ?? "";
13413
+ const timestamp = getHeader2(req4, "x-signature-timestamp") ?? "";
13414
+ const signature = getHeader2(req4, "x-signature-ed25519") ?? "";
13233
13415
  if (!timestamp || !signature) {
13234
- log4.warn?.(`[webhook] missing signature headers on ${req.url}`);
13416
+ log4.warn?.(`[webhook] missing signature headers on ${req4.url}`);
13235
13417
  res.statusCode = 401;
13236
13418
  res.end(JSON.stringify({ error: "missing signature" }));
13237
13419
  return;
@@ -13249,17 +13431,17 @@ function createSharedHandler(path20, log4) {
13249
13431
  unauthorizedMessage: JSON.stringify({ error: "invalid signature" })
13250
13432
  });
13251
13433
  if (!matched) {
13252
- log4.warn?.(`[webhook] signature mismatch on ${path20} (${targets.length} target(s))`);
13434
+ log4.warn?.(`[webhook] signature mismatch on ${path21} (${targets.length} target(s))`);
13253
13435
  return;
13254
13436
  }
13255
- const h2 = resolveTargetHandler(path20, matched.accountId);
13437
+ const h2 = resolveTargetHandler(path21, matched.accountId);
13256
13438
  if (!h2) {
13257
13439
  log4.error?.(`[webhook] no handler for matched target ${matched.accountId}`);
13258
13440
  res.statusCode = 500;
13259
13441
  res.end(JSON.stringify({ error: "no handler" }));
13260
13442
  return;
13261
13443
  }
13262
- await delegateToHandler(h2, req, res, rawBody);
13444
+ await delegateToHandler(h2, req4, res, rawBody);
13263
13445
  }
13264
13446
  });
13265
13447
  } catch (err) {
@@ -13272,12 +13454,12 @@ function createSharedHandler(path20, log4) {
13272
13454
  }
13273
13455
  };
13274
13456
  }
13275
- function resolveTargetHandler(path20, accountId) {
13276
- return sharedTargets.get(path20)?.find((t) => t.accountId === accountId)?.handler;
13457
+ function resolveTargetHandler(path21, accountId) {
13458
+ return sharedTargets.get(path21)?.find((t) => t.accountId === accountId)?.handler;
13277
13459
  }
13278
- async function delegateToHandler(handler, req, res, rawBody) {
13460
+ async function delegateToHandler(handler, req4, res, rawBody) {
13279
13461
  const headers = {};
13280
- for (const [k, v] of Object.entries(req.headers)) {
13462
+ for (const [k, v] of Object.entries(req4.headers)) {
13281
13463
  headers[k.toLowerCase()] = v;
13282
13464
  }
13283
13465
  const resp = await handler({ body: rawBody, headers });
@@ -13287,9 +13469,9 @@ async function delegateToHandler(handler, req, res, rawBody) {
13287
13469
  }
13288
13470
  res.end(resp.body);
13289
13471
  }
13290
- async function handleSimple(req, res, path20, log4) {
13472
+ async function handleSimple(req4, res, path21, log4) {
13291
13473
  try {
13292
- const ct = String(req.headers["content-type"] ?? "");
13474
+ const ct = String(req4.headers["content-type"] ?? "");
13293
13475
  if (!ct.includes("application/json")) {
13294
13476
  res.statusCode = 400;
13295
13477
  res.end(JSON.stringify({ error: "unsupported content type" }));
@@ -13297,7 +13479,7 @@ async function handleSimple(req, res, path20, log4) {
13297
13479
  }
13298
13480
  const chunks = [];
13299
13481
  let total = 0;
13300
- for await (const chunk of req) {
13482
+ for await (const chunk of req4) {
13301
13483
  const buf = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
13302
13484
  total += buf.length;
13303
13485
  if (total > 1048576) {
@@ -13308,9 +13490,9 @@ async function handleSimple(req, res, path20, log4) {
13308
13490
  chunks.push(buf);
13309
13491
  }
13310
13492
  const rawBody = Buffer.concat(chunks);
13311
- const entries = sharedTargets.get(path20) ?? [];
13493
+ const entries = sharedTargets.get(path21) ?? [];
13312
13494
  for (const entry of entries) {
13313
- const resp = await entry.handler({ body: rawBody, headers: mapHeaders(req) });
13495
+ const resp = await entry.handler({ body: rawBody, headers: mapHeaders(req4) });
13314
13496
  if (resp.status < 400) {
13315
13497
  res.statusCode = resp.status;
13316
13498
  if (resp.headers) for (const [k, v] of Object.entries(resp.headers)) res.setHeader(k, v);
@@ -13328,13 +13510,13 @@ async function handleSimple(req, res, path20, log4) {
13328
13510
  }
13329
13511
  }
13330
13512
  }
13331
- function mapHeaders(req) {
13513
+ function mapHeaders(req4) {
13332
13514
  const h2 = {};
13333
- for (const [k, v] of Object.entries(req.headers ?? {})) h2[k.toLowerCase()] = v;
13515
+ for (const [k, v] of Object.entries(req4.headers ?? {})) h2[k.toLowerCase()] = v;
13334
13516
  return h2;
13335
13517
  }
13336
- function getHeader2(req, key) {
13337
- const val = req.headers[key];
13518
+ function getHeader2(req4, key) {
13519
+ const val = req4.headers[key];
13338
13520
  return Array.isArray(val) ? val[0] : val;
13339
13521
  }
13340
13522
 
@@ -14106,10 +14288,10 @@ function json(data) {
14106
14288
  details: data
14107
14289
  };
14108
14290
  }
14109
- function validatePath(path20) {
14110
- if (!path20.startsWith("/")) return "path \u5FC5\u987B\u4EE5 / \u5F00\u5934";
14111
- if (path20.includes("..") || path20.includes("//")) return "path \u4E0D\u5141\u8BB8\u5305\u542B .. \u6216 //";
14112
- if (!/^\/[a-zA-Z0-9\-._~:@!$&'()*+,;=/%]+$/.test(path20) && path20 !== "/") {
14291
+ function validatePath(path21) {
14292
+ if (!path21.startsWith("/")) return "path \u5FC5\u987B\u4EE5 / \u5F00\u5934";
14293
+ if (path21.includes("..") || path21.includes("//")) return "path \u4E0D\u5141\u8BB8\u5305\u542B .. \u6216 //";
14294
+ if (!/^\/[a-zA-Z0-9\-._~:@!$&'()*+,;=/%]+$/.test(path21) && path21 !== "/") {
14113
14295
  return "path \u5305\u542B\u975E\u6CD5\u5B57\u7B26";
14114
14296
  }
14115
14297
  return null;
@@ -14384,22 +14566,19 @@ function registerRemindTool(api) {
14384
14566
  );
14385
14567
  }
14386
14568
 
14387
- // src/runtime-adapter/contract-check.ts
14569
+ // src/adapter/contract.ts
14388
14570
  var log3 = createPluginLogger({ prefix: "[contract]", forceConsole: true });
14389
14571
  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
14572
  {
14398
14573
  name: "channel.reply.dispatchReplyWithBufferedBlockDispatcher",
14399
14574
  probe: (rt) => typeof rt.channel?.reply?.dispatchReplyWithBufferedBlockDispatcher === "function"
14400
14575
  }
14401
14576
  ];
14402
14577
  var OPTIONAL = [
14578
+ { name: "channel.inbound.run (degraded)", probe: (rt) => {
14579
+ const c = rt.channel;
14580
+ return typeof c?.inbound?.run === "function" || typeof c?.turn?.run === "function";
14581
+ } },
14403
14582
  { name: "channel.inbound.buildContext", probe: (rt) => typeof rt.channel?.inbound?.buildContext === "function" },
14404
14583
  { name: "channel.reply.formatAgentEnvelope", probe: (rt) => typeof rt.channel?.reply?.formatAgentEnvelope === "function" },
14405
14584
  { name: "channel.text.chunkMarkdownText", probe: (rt) => typeof rt.channel?.text?.chunkMarkdownText === "function" },