@cxyhhhhh/openclaw-qqbot 2.0.0-dev.202607091556 → 2.0.0-dev.202607092101

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 CHANGED
@@ -31,9 +31,9 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
31
31
  ));
32
32
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
33
33
 
34
- // node_modules/.pnpm/ws@8.20.1/node_modules/ws/lib/constants.js
34
+ // node_modules/.pnpm/ws@8.21.0/node_modules/ws/lib/constants.js
35
35
  var require_constants = __commonJS({
36
- "node_modules/.pnpm/ws@8.20.1/node_modules/ws/lib/constants.js"(exports2, module2) {
36
+ "node_modules/.pnpm/ws@8.21.0/node_modules/ws/lib/constants.js"(exports2, module2) {
37
37
  "use strict";
38
38
  var BINARY_TYPES = ["nodebuffer", "arraybuffer", "fragments"];
39
39
  var hasBlob = typeof Blob !== "undefined";
@@ -54,9 +54,9 @@ var require_constants = __commonJS({
54
54
  }
55
55
  });
56
56
 
57
- // node_modules/.pnpm/ws@8.20.1/node_modules/ws/lib/buffer-util.js
57
+ // node_modules/.pnpm/ws@8.21.0/node_modules/ws/lib/buffer-util.js
58
58
  var require_buffer_util = __commonJS({
59
- "node_modules/.pnpm/ws@8.20.1/node_modules/ws/lib/buffer-util.js"(exports2, module2) {
59
+ "node_modules/.pnpm/ws@8.21.0/node_modules/ws/lib/buffer-util.js"(exports2, module2) {
60
60
  "use strict";
61
61
  var { EMPTY_BUFFER } = require_constants();
62
62
  var FastBuffer = Buffer[Symbol.species];
@@ -129,9 +129,9 @@ var require_buffer_util = __commonJS({
129
129
  }
130
130
  });
131
131
 
132
- // node_modules/.pnpm/ws@8.20.1/node_modules/ws/lib/limiter.js
132
+ // node_modules/.pnpm/ws@8.21.0/node_modules/ws/lib/limiter.js
133
133
  var require_limiter = __commonJS({
134
- "node_modules/.pnpm/ws@8.20.1/node_modules/ws/lib/limiter.js"(exports2, module2) {
134
+ "node_modules/.pnpm/ws@8.21.0/node_modules/ws/lib/limiter.js"(exports2, module2) {
135
135
  "use strict";
136
136
  var kDone = /* @__PURE__ */ Symbol("kDone");
137
137
  var kRun = /* @__PURE__ */ Symbol("kRun");
@@ -179,9 +179,9 @@ var require_limiter = __commonJS({
179
179
  }
180
180
  });
181
181
 
182
- // node_modules/.pnpm/ws@8.20.1/node_modules/ws/lib/permessage-deflate.js
182
+ // node_modules/.pnpm/ws@8.21.0/node_modules/ws/lib/permessage-deflate.js
183
183
  var require_permessage_deflate = __commonJS({
184
- "node_modules/.pnpm/ws@8.20.1/node_modules/ws/lib/permessage-deflate.js"(exports2, module2) {
184
+ "node_modules/.pnpm/ws@8.21.0/node_modules/ws/lib/permessage-deflate.js"(exports2, module2) {
185
185
  "use strict";
186
186
  var zlib = require("zlib");
187
187
  var bufferUtil = require_buffer_util();
@@ -562,9 +562,9 @@ var require_permessage_deflate = __commonJS({
562
562
  }
563
563
  });
564
564
 
565
- // node_modules/.pnpm/ws@8.20.1/node_modules/ws/lib/validation.js
565
+ // node_modules/.pnpm/ws@8.21.0/node_modules/ws/lib/validation.js
566
566
  var require_validation = __commonJS({
567
- "node_modules/.pnpm/ws@8.20.1/node_modules/ws/lib/validation.js"(exports2, module2) {
567
+ "node_modules/.pnpm/ws@8.21.0/node_modules/ws/lib/validation.js"(exports2, module2) {
568
568
  "use strict";
569
569
  var { isUtf8 } = require("buffer");
570
570
  var { hasBlob } = require_constants();
@@ -763,9 +763,9 @@ var require_validation = __commonJS({
763
763
  }
764
764
  });
765
765
 
766
- // node_modules/.pnpm/ws@8.20.1/node_modules/ws/lib/receiver.js
766
+ // node_modules/.pnpm/ws@8.21.0/node_modules/ws/lib/receiver.js
767
767
  var require_receiver = __commonJS({
768
- "node_modules/.pnpm/ws@8.20.1/node_modules/ws/lib/receiver.js"(exports2, module2) {
768
+ "node_modules/.pnpm/ws@8.21.0/node_modules/ws/lib/receiver.js"(exports2, module2) {
769
769
  "use strict";
770
770
  var { Writable } = require("stream");
771
771
  var PerMessageDeflate2 = require_permessage_deflate();
@@ -798,6 +798,10 @@ var require_receiver = __commonJS({
798
798
  * extensions
799
799
  * @param {Boolean} [options.isServer=false] Specifies whether to operate in
800
800
  * client or server mode
801
+ * @param {Number} [options.maxBufferedChunks=0] The maximum number of
802
+ * buffered data chunks
803
+ * @param {Number} [options.maxFragments=0] The maximum number of message
804
+ * fragments
801
805
  * @param {Number} [options.maxPayload=0] The maximum allowed message length
802
806
  * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or
803
807
  * not to skip UTF-8 validation for text and close messages
@@ -808,6 +812,8 @@ var require_receiver = __commonJS({
808
812
  this._binaryType = options.binaryType || BINARY_TYPES[0];
809
813
  this._extensions = options.extensions || {};
810
814
  this._isServer = !!options.isServer;
815
+ this._maxBufferedChunks = options.maxBufferedChunks | 0;
816
+ this._maxFragments = options.maxFragments | 0;
811
817
  this._maxPayload = options.maxPayload | 0;
812
818
  this._skipUTF8Validation = !!options.skipUTF8Validation;
813
819
  this[kWebSocket] = void 0;
@@ -837,6 +843,18 @@ var require_receiver = __commonJS({
837
843
  */
838
844
  _write(chunk, encoding, cb) {
839
845
  if (this._opcode === 8 && this._state == GET_INFO) return cb();
846
+ if (this._maxBufferedChunks > 0 && this._buffers.length >= this._maxBufferedChunks) {
847
+ cb(
848
+ this.createError(
849
+ RangeError,
850
+ "Too many buffered chunks",
851
+ false,
852
+ 1008,
853
+ "WS_ERR_TOO_MANY_BUFFERED_PARTS"
854
+ )
855
+ );
856
+ return;
857
+ }
840
858
  this._bufferedBytes += chunk.length;
841
859
  this._buffers.push(chunk);
842
860
  this.startLoop(cb);
@@ -1166,6 +1184,17 @@ var require_receiver = __commonJS({
1166
1184
  return;
1167
1185
  }
1168
1186
  if (data.length) {
1187
+ if (this._maxFragments > 0 && this._fragments.length >= this._maxFragments) {
1188
+ const error = this.createError(
1189
+ RangeError,
1190
+ "Too many message fragments",
1191
+ false,
1192
+ 1008,
1193
+ "WS_ERR_TOO_MANY_BUFFERED_PARTS"
1194
+ );
1195
+ cb(error);
1196
+ return;
1197
+ }
1169
1198
  this._messageLength = this._totalPayloadLength;
1170
1199
  this._fragments.push(data);
1171
1200
  }
@@ -1195,6 +1224,17 @@ var require_receiver = __commonJS({
1195
1224
  cb(error);
1196
1225
  return;
1197
1226
  }
1227
+ if (this._maxFragments > 0 && this._fragments.length >= this._maxFragments) {
1228
+ const error = this.createError(
1229
+ RangeError,
1230
+ "Too many message fragments",
1231
+ false,
1232
+ 1008,
1233
+ "WS_ERR_TOO_MANY_BUFFERED_PARTS"
1234
+ );
1235
+ cb(error);
1236
+ return;
1237
+ }
1198
1238
  this._fragments.push(buf);
1199
1239
  }
1200
1240
  this.dataMessage(cb);
@@ -1355,9 +1395,9 @@ var require_receiver = __commonJS({
1355
1395
  }
1356
1396
  });
1357
1397
 
1358
- // node_modules/.pnpm/ws@8.20.1/node_modules/ws/lib/sender.js
1398
+ // node_modules/.pnpm/ws@8.21.0/node_modules/ws/lib/sender.js
1359
1399
  var require_sender = __commonJS({
1360
- "node_modules/.pnpm/ws@8.20.1/node_modules/ws/lib/sender.js"(exports2, module2) {
1400
+ "node_modules/.pnpm/ws@8.21.0/node_modules/ws/lib/sender.js"(exports2, module2) {
1361
1401
  "use strict";
1362
1402
  var { Duplex } = require("stream");
1363
1403
  var { randomFillSync } = require("crypto");
@@ -1848,9 +1888,9 @@ var require_sender = __commonJS({
1848
1888
  }
1849
1889
  });
1850
1890
 
1851
- // node_modules/.pnpm/ws@8.20.1/node_modules/ws/lib/event-target.js
1891
+ // node_modules/.pnpm/ws@8.21.0/node_modules/ws/lib/event-target.js
1852
1892
  var require_event_target = __commonJS({
1853
- "node_modules/.pnpm/ws@8.20.1/node_modules/ws/lib/event-target.js"(exports2, module2) {
1893
+ "node_modules/.pnpm/ws@8.21.0/node_modules/ws/lib/event-target.js"(exports2, module2) {
1854
1894
  "use strict";
1855
1895
  var { kForOnEventAttribute, kListener } = require_constants();
1856
1896
  var kCode = /* @__PURE__ */ Symbol("kCode");
@@ -2077,9 +2117,9 @@ var require_event_target = __commonJS({
2077
2117
  }
2078
2118
  });
2079
2119
 
2080
- // node_modules/.pnpm/ws@8.20.1/node_modules/ws/lib/extension.js
2120
+ // node_modules/.pnpm/ws@8.21.0/node_modules/ws/lib/extension.js
2081
2121
  var require_extension = __commonJS({
2082
- "node_modules/.pnpm/ws@8.20.1/node_modules/ws/lib/extension.js"(exports2, module2) {
2122
+ "node_modules/.pnpm/ws@8.21.0/node_modules/ws/lib/extension.js"(exports2, module2) {
2083
2123
  "use strict";
2084
2124
  var { tokenChars } = require_validation();
2085
2125
  function push(dest, name, elem) {
@@ -2230,14 +2270,14 @@ var require_extension = __commonJS({
2230
2270
  }
2231
2271
  });
2232
2272
 
2233
- // node_modules/.pnpm/ws@8.20.1/node_modules/ws/lib/websocket.js
2273
+ // node_modules/.pnpm/ws@8.21.0/node_modules/ws/lib/websocket.js
2234
2274
  var require_websocket = __commonJS({
2235
- "node_modules/.pnpm/ws@8.20.1/node_modules/ws/lib/websocket.js"(exports2, module2) {
2275
+ "node_modules/.pnpm/ws@8.21.0/node_modules/ws/lib/websocket.js"(exports2, module2) {
2236
2276
  "use strict";
2237
2277
  var EventEmitter = require("events");
2238
2278
  var https3 = require("https");
2239
2279
  var http2 = require("http");
2240
- var net = require("net");
2280
+ var net2 = require("net");
2241
2281
  var tls = require("tls");
2242
2282
  var { randomBytes: randomBytes2, createHash: createHash3 } = require("crypto");
2243
2283
  var { Duplex, Readable } = require("stream");
@@ -2401,6 +2441,10 @@ var require_websocket = __commonJS({
2401
2441
  * multiple times in the same tick
2402
2442
  * @param {Function} [options.generateMask] The function used to generate the
2403
2443
  * masking key
2444
+ * @param {Number} [options.maxBufferedChunks=0] The maximum number of
2445
+ * buffered data chunks
2446
+ * @param {Number} [options.maxFragments=0] The maximum number of message
2447
+ * fragments
2404
2448
  * @param {Number} [options.maxPayload=0] The maximum allowed message size
2405
2449
  * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or
2406
2450
  * not to skip UTF-8 validation for text and close messages
@@ -2412,6 +2456,8 @@ var require_websocket = __commonJS({
2412
2456
  binaryType: this.binaryType,
2413
2457
  extensions: this._extensions,
2414
2458
  isServer: this._isServer,
2459
+ maxBufferedChunks: options.maxBufferedChunks,
2460
+ maxFragments: options.maxFragments,
2415
2461
  maxPayload: options.maxPayload,
2416
2462
  skipUTF8Validation: options.skipUTF8Validation
2417
2463
  });
@@ -2711,6 +2757,8 @@ var require_websocket = __commonJS({
2711
2757
  autoPong: true,
2712
2758
  closeTimeout: CLOSE_TIMEOUT,
2713
2759
  protocolVersion: protocolVersions[1],
2760
+ maxBufferedChunks: 1024 * 1024,
2761
+ maxFragments: 128 * 1024,
2714
2762
  maxPayload: 100 * 1024 * 1024,
2715
2763
  skipUTF8Validation: false,
2716
2764
  perMessageDeflate: true,
@@ -2953,6 +3001,8 @@ var require_websocket = __commonJS({
2953
3001
  websocket.setSocket(socket, head, {
2954
3002
  allowSynchronousEvents: opts.allowSynchronousEvents,
2955
3003
  generateMask: opts.generateMask,
3004
+ maxBufferedChunks: opts.maxBufferedChunks,
3005
+ maxFragments: opts.maxFragments,
2956
3006
  maxPayload: opts.maxPayload,
2957
3007
  skipUTF8Validation: opts.skipUTF8Validation
2958
3008
  });
@@ -2971,12 +3021,12 @@ var require_websocket = __commonJS({
2971
3021
  }
2972
3022
  function netConnect(options) {
2973
3023
  options.path = options.socketPath;
2974
- return net.connect(options);
3024
+ return net2.connect(options);
2975
3025
  }
2976
3026
  function tlsConnect(options) {
2977
3027
  options.path = void 0;
2978
3028
  if (!options.servername && options.servername !== "") {
2979
- options.servername = net.isIP(options.host) ? "" : options.host;
3029
+ options.servername = net2.isIP(options.host) ? "" : options.host;
2980
3030
  }
2981
3031
  return tls.connect(options);
2982
3032
  }
@@ -3116,9 +3166,9 @@ var require_websocket = __commonJS({
3116
3166
  }
3117
3167
  });
3118
3168
 
3119
- // node_modules/.pnpm/ws@8.20.1/node_modules/ws/lib/stream.js
3169
+ // node_modules/.pnpm/ws@8.21.0/node_modules/ws/lib/stream.js
3120
3170
  var require_stream = __commonJS({
3121
- "node_modules/.pnpm/ws@8.20.1/node_modules/ws/lib/stream.js"(exports2, module2) {
3171
+ "node_modules/.pnpm/ws@8.21.0/node_modules/ws/lib/stream.js"(exports2, module2) {
3122
3172
  "use strict";
3123
3173
  var WebSocket2 = require_websocket();
3124
3174
  var { Duplex } = require("stream");
@@ -3214,9 +3264,9 @@ var require_stream = __commonJS({
3214
3264
  }
3215
3265
  });
3216
3266
 
3217
- // node_modules/.pnpm/ws@8.20.1/node_modules/ws/lib/subprotocol.js
3267
+ // node_modules/.pnpm/ws@8.21.0/node_modules/ws/lib/subprotocol.js
3218
3268
  var require_subprotocol = __commonJS({
3219
- "node_modules/.pnpm/ws@8.20.1/node_modules/ws/lib/subprotocol.js"(exports2, module2) {
3269
+ "node_modules/.pnpm/ws@8.21.0/node_modules/ws/lib/subprotocol.js"(exports2, module2) {
3220
3270
  "use strict";
3221
3271
  var { tokenChars } = require_validation();
3222
3272
  function parse(header) {
@@ -3259,9 +3309,9 @@ var require_subprotocol = __commonJS({
3259
3309
  }
3260
3310
  });
3261
3311
 
3262
- // node_modules/.pnpm/ws@8.20.1/node_modules/ws/lib/websocket-server.js
3312
+ // node_modules/.pnpm/ws@8.21.0/node_modules/ws/lib/websocket-server.js
3263
3313
  var require_websocket_server = __commonJS({
3264
- "node_modules/.pnpm/ws@8.20.1/node_modules/ws/lib/websocket-server.js"(exports2, module2) {
3314
+ "node_modules/.pnpm/ws@8.21.0/node_modules/ws/lib/websocket-server.js"(exports2, module2) {
3265
3315
  "use strict";
3266
3316
  var EventEmitter = require("events");
3267
3317
  var http2 = require("http");
@@ -3295,6 +3345,10 @@ var require_websocket_server = __commonJS({
3295
3345
  * called
3296
3346
  * @param {Function} [options.handleProtocols] A hook to handle protocols
3297
3347
  * @param {String} [options.host] The hostname where to bind the server
3348
+ * @param {Number} [options.maxBufferedChunks=1048576] The maximum number of
3349
+ * buffered data chunks
3350
+ * @param {Number} [options.maxFragments=131072] The maximum number of message
3351
+ * fragments
3298
3352
  * @param {Number} [options.maxPayload=104857600] The maximum allowed message
3299
3353
  * size
3300
3354
  * @param {Boolean} [options.noServer=false] Enable no server mode
@@ -3316,6 +3370,8 @@ var require_websocket_server = __commonJS({
3316
3370
  options = {
3317
3371
  allowSynchronousEvents: true,
3318
3372
  autoPong: true,
3373
+ maxBufferedChunks: 1024 * 1024,
3374
+ maxFragments: 128 * 1024,
3319
3375
  maxPayload: 100 * 1024 * 1024,
3320
3376
  skipUTF8Validation: false,
3321
3377
  perMessageDeflate: false,
@@ -3595,6 +3651,8 @@ var require_websocket_server = __commonJS({
3595
3651
  socket.removeListener("error", socketOnError);
3596
3652
  ws.setSocket(socket, head, {
3597
3653
  allowSynchronousEvents: this.options.allowSynchronousEvents,
3654
+ maxBufferedChunks: this.options.maxBufferedChunks,
3655
+ maxFragments: this.options.maxFragments,
3598
3656
  maxPayload: this.options.maxPayload,
3599
3657
  skipUTF8Validation: this.options.skipUTF8Validation
3600
3658
  });
@@ -5015,16 +5073,16 @@ var import_node_os = __toESM(require("os"), 1);
5015
5073
  // src/outbound/outbound-service.ts
5016
5074
  var path3 = __toESM(require("path"), 1);
5017
5075
 
5018
- // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607081646/node_modules/@cxyhhhhh/qqbot-nodejs/dist/QQBot.js
5076
+ // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/QQBot.js
5019
5077
  var fs3 = __toESM(require("fs"), 1);
5020
5078
  var path = __toESM(require("path"), 1);
5021
5079
 
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, path21, explicit, defaultValue) {
5080
+ // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/middleware/types.js
5081
+ function resolvePolicy(ctx, path22, explicit, defaultValue) {
5024
5082
  if (explicit !== void 0 && explicit !== null) {
5025
5083
  return explicit;
5026
5084
  }
5027
- const keys = path21.split(".");
5085
+ const keys = path22.split(".");
5028
5086
  let value = ctx.state.policy;
5029
5087
  for (const key of keys) {
5030
5088
  if (value === null || value === void 0)
@@ -5095,17 +5153,17 @@ function createMiddlewareContext(params) {
5095
5153
  return ctx;
5096
5154
  }
5097
5155
 
5098
- // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607081646/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/types.js
5156
+ // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/types.js
5099
5157
  var ApiError = class extends Error {
5100
5158
  httpStatus;
5101
5159
  path;
5102
5160
  bizCode;
5103
5161
  bizMessage;
5104
5162
  name = "ApiError";
5105
- constructor(message, httpStatus, path21, bizCode, bizMessage) {
5163
+ constructor(message, httpStatus, path22, bizCode, bizMessage) {
5106
5164
  super(message);
5107
5165
  this.httpStatus = httpStatus;
5108
- this.path = path21;
5166
+ this.path = path22;
5109
5167
  this.bizCode = bizCode;
5110
5168
  this.bizMessage = bizMessage;
5111
5169
  }
@@ -5128,7 +5186,7 @@ var StreamContentType = {
5128
5186
  MARKDOWN: "markdown"
5129
5187
  };
5130
5188
 
5131
- // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607081646/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/utils/format.js
5189
+ // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/utils/format.js
5132
5190
  function formatErrorMessage(err) {
5133
5191
  if (err instanceof Error) {
5134
5192
  let formatted = err.message || err.name || "Error";
@@ -5175,7 +5233,7 @@ function formatFileSize(bytes) {
5175
5233
  return `${(bytes / 1024 / 1024 / 1024).toFixed(2)} GB`;
5176
5234
  }
5177
5235
 
5178
- // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607081646/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/api/api-client.js
5236
+ // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/api/api-client.js
5179
5237
  var DEFAULT_BASE_URL = "https://api.sgroup.qq.com";
5180
5238
  var DEFAULT_TIMEOUT_MS = 3e4;
5181
5239
  var FILE_UPLOAD_TIMEOUT_MS = 12e4;
@@ -5193,14 +5251,14 @@ var ApiClient = class {
5193
5251
  const ua = config.userAgent ?? "qqbot-nodejs/unknown";
5194
5252
  this.resolveUserAgent = typeof ua === "function" ? ua : () => ua;
5195
5253
  }
5196
- async request(accessToken, method, path21, body, options) {
5197
- const url = `${this.baseUrl}${path21}`;
5254
+ async request(accessToken, method, path22, body, options) {
5255
+ const url = `${this.baseUrl}${path22}`;
5198
5256
  const headers = {
5199
5257
  Authorization: `QQBot ${accessToken}`,
5200
5258
  "Content-Type": "application/json",
5201
5259
  "User-Agent": this.resolveUserAgent()
5202
5260
  };
5203
- const isFileUpload = options?.uploadRequest === true || path21.includes("/files") || path21.includes("/upload_prepare") || path21.includes("/upload_part_finish");
5261
+ const isFileUpload = options?.uploadRequest === true || path22.includes("/files") || path22.includes("/upload_prepare") || path22.includes("/upload_part_finish");
5204
5262
  const timeout = options?.timeoutMs ?? (isFileUpload ? this.fileUploadTimeoutMs : this.defaultTimeoutMs);
5205
5263
  const controller = new AbortController();
5206
5264
  const timeoutId = setTimeout(() => controller.abort(), timeout);
@@ -5225,10 +5283,10 @@ var ApiClient = class {
5225
5283
  clearTimeout(timeoutId);
5226
5284
  if (err instanceof Error && err.name === "AbortError") {
5227
5285
  this.logger?.error?.(`[qqbot:api] <<< Timeout after ${timeout}ms`);
5228
- throw new ApiError(`Request timeout [${path21}]: exceeded ${timeout}ms`, 0, path21);
5286
+ throw new ApiError(`Request timeout [${path22}]: exceeded ${timeout}ms`, 0, path22);
5229
5287
  }
5230
5288
  this.logger?.error?.(`[qqbot:api] <<< Network error: ${formatErrorMessage(err)}`);
5231
- throw new ApiError(`Network error [${path21}]: ${formatErrorMessage(err)}`, 0, path21);
5289
+ throw new ApiError(`Network error [${path22}]: ${formatErrorMessage(err)}`, 0, path22);
5232
5290
  } finally {
5233
5291
  clearTimeout(timeoutId);
5234
5292
  }
@@ -5238,7 +5296,7 @@ var ApiClient = class {
5238
5296
  try {
5239
5297
  rawBody = await res.text();
5240
5298
  } catch (err) {
5241
- throw new ApiError(`Failed to read response [${path21}]: ${formatErrorMessage(err)}`, res.status, path21);
5299
+ throw new ApiError(`Failed to read response [${path22}]: ${formatErrorMessage(err)}`, res.status, path22);
5242
5300
  }
5243
5301
  this.logger?.debug?.(`[qqbot:api] <<< Body: ${rawBody}`);
5244
5302
  const contentType = res.headers.get("content-type") ?? "";
@@ -5246,36 +5304,36 @@ var ApiClient = class {
5246
5304
  if (!res.ok) {
5247
5305
  if (isHtmlResponse) {
5248
5306
  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${path21}\uFF09\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5`, res.status, path21);
5307
+ throw new ApiError(`${statusHint}\uFF08${path22}\uFF09\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5`, res.status, path22);
5250
5308
  }
5251
5309
  try {
5252
5310
  const error = JSON.parse(rawBody);
5253
5311
  const bizCode = error.code ?? error.err_code;
5254
- throw new ApiError(`API Error [${path21}]: ${error.message ?? rawBody}`, res.status, path21, bizCode, error.message);
5312
+ throw new ApiError(`API Error [${path22}]: ${error.message ?? rawBody}`, res.status, path22, bizCode, error.message);
5255
5313
  } catch (parseErr) {
5256
5314
  if (parseErr instanceof ApiError) {
5257
5315
  throw parseErr;
5258
5316
  }
5259
- throw new ApiError(`API Error [${path21}] HTTP ${res.status}: ${rawBody.slice(0, 200)}`, res.status, path21);
5317
+ throw new ApiError(`API Error [${path22}] HTTP ${res.status}: ${rawBody.slice(0, 200)}`, res.status, path22);
5260
5318
  }
5261
5319
  }
5262
5320
  if (isHtmlResponse) {
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);
5321
+ throw new ApiError(`QQ \u670D\u52A1\u7AEF\u8FD4\u56DE\u4E86\u975E JSON \u54CD\u5E94\uFF08${path22}\uFF09\uFF0C\u53EF\u80FD\u662F\u4E34\u65F6\u6545\u969C\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5`, res.status, path22);
5264
5322
  }
5265
5323
  try {
5266
5324
  return JSON.parse(rawBody);
5267
5325
  } catch {
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);
5326
+ throw new ApiError(`\u5F00\u653E\u5E73\u53F0\u54CD\u5E94\u683C\u5F0F\u5F02\u5E38\uFF08${path22}\uFF09\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5`, res.status, path22);
5269
5327
  }
5270
5328
  }
5271
5329
  };
5272
5330
 
5273
- // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607081646/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/api/media-chunked.js
5331
+ // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/api/media-chunked.js
5274
5332
  var crypto = __toESM(require("crypto"), 1);
5275
5333
  var fs = __toESM(require("fs"), 1);
5276
5334
  var https = __toESM(require("https"), 1);
5277
5335
 
5278
- // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607081646/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/api/retry.js
5336
+ // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/api/retry.js
5279
5337
  async function withRetry(fn, policy, persistentPolicy, logger) {
5280
5338
  let lastError = null;
5281
5339
  for (let attempt = 0; attempt <= policy.maxRetries; attempt++) {
@@ -5367,7 +5425,7 @@ function buildPartFinishPersistentPolicy(retryTimeoutMs, retryableCodes = PART_F
5367
5425
  var PART_FINISH_RETRYABLE_CODES = /* @__PURE__ */ new Set([40093001]);
5368
5426
  var UPLOAD_PREPARE_FALLBACK_CODE = 40093002;
5369
5427
 
5370
- // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607081646/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/api/routes.js
5428
+ // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/api/routes.js
5371
5429
  function messagePath(scope, targetId) {
5372
5430
  return scope === "c2c" ? `/v2/users/${targetId}/messages` : `/v2/groups/${targetId}/messages`;
5373
5431
  }
@@ -5404,7 +5462,7 @@ function getNextMsgSeq(_msgId) {
5404
5462
  return (timePart ^ random) % 65536;
5405
5463
  }
5406
5464
 
5407
- // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607081646/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/api/media-chunked.js
5465
+ // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/api/media-chunked.js
5408
5466
  var UploadDailyLimitExceededError = class extends Error {
5409
5467
  filePath;
5410
5468
  fileSize;
@@ -5488,9 +5546,9 @@ var ChunkedMediaApi = class {
5488
5546
  }
5489
5547
  async callUploadPrepare(opts, fileName, fileSize, hashes, pathLabel) {
5490
5548
  const token = await this.tokenManager.getAccessToken(opts.creds.appId, opts.creds.clientSecret);
5491
- const path21 = uploadPreparePath(opts.scope, opts.targetId);
5549
+ const path22 = uploadPreparePath(opts.scope, opts.targetId);
5492
5550
  try {
5493
- return await this.client.request(token, "POST", path21, {
5551
+ return await this.client.request(token, "POST", path22, {
5494
5552
  file_type: opts.fileType,
5495
5553
  file_name: fileName,
5496
5554
  file_size: fileSize,
@@ -5507,10 +5565,10 @@ var ChunkedMediaApi = class {
5507
5565
  }
5508
5566
  async callUploadPartFinish(opts, uploadId, partIndex, blockSize, md5, retryTimeoutMs) {
5509
5567
  const persistentPolicy = buildPartFinishPersistentPolicy(retryTimeoutMs);
5510
- const path21 = uploadPartFinishPath(opts.scope, opts.targetId);
5568
+ const path22 = uploadPartFinishPath(opts.scope, opts.targetId);
5511
5569
  await withRetry(async () => {
5512
5570
  const token = await this.tokenManager.getAccessToken(opts.creds.appId, opts.creds.clientSecret);
5513
- return this.client.request(token, "POST", path21, {
5571
+ return this.client.request(token, "POST", path22, {
5514
5572
  upload_id: uploadId,
5515
5573
  part_index: partIndex,
5516
5574
  block_size: blockSize,
@@ -5519,10 +5577,10 @@ var ChunkedMediaApi = class {
5519
5577
  }, PART_FINISH_RETRY_POLICY, persistentPolicy, this.logger);
5520
5578
  }
5521
5579
  async callCompleteUpload(opts, uploadId) {
5522
- const path21 = uploadCompletePath(opts.scope, opts.targetId);
5580
+ const path22 = uploadCompletePath(opts.scope, opts.targetId);
5523
5581
  return withRetry(async () => {
5524
5582
  const token = await this.tokenManager.getAccessToken(opts.creds.appId, opts.creds.clientSecret);
5525
- return this.client.request(token, "POST", path21, { upload_id: uploadId }, { uploadRequest: true });
5583
+ return this.client.request(token, "POST", path22, { upload_id: uploadId }, { uploadRequest: true });
5526
5584
  }, COMPLETE_UPLOAD_RETRY_POLICY, void 0, this.logger);
5527
5585
  }
5528
5586
  };
@@ -5663,7 +5721,7 @@ function sleep2(ms) {
5663
5721
  return new Promise((resolve2) => setTimeout(resolve2, ms));
5664
5722
  }
5665
5723
 
5666
- // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607081646/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/api/media.js
5724
+ // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/api/media.js
5667
5725
  var fs2 = __toESM(require("fs"), 1);
5668
5726
  var MediaApi = class {
5669
5727
  client;
@@ -5716,8 +5774,8 @@ var MediaApi = class {
5716
5774
  body.file_name = this.sanitize(opts.fileName);
5717
5775
  }
5718
5776
  const token = await this.tokenManager.getAccessToken(creds.appId, creds.clientSecret);
5719
- const path21 = mediaUploadPath(scope, targetId);
5720
- const result = await withRetry(() => this.client.request(token, "POST", path21, body, {
5777
+ const path22 = mediaUploadPath(scope, targetId);
5778
+ const result = await withRetry(() => this.client.request(token, "POST", path22, body, {
5721
5779
  redactBodyKeys: ["file_data"],
5722
5780
  uploadRequest: true
5723
5781
  }), UPLOAD_RETRY_POLICY, void 0, this.logger);
@@ -5733,8 +5791,8 @@ var MediaApi = class {
5733
5791
  async sendMediaMessage(scope, targetId, fileInfo, creds, opts) {
5734
5792
  const token = await this.tokenManager.getAccessToken(creds.appId, creds.clientSecret);
5735
5793
  const msgSeq = opts?.msgId ? getNextMsgSeq(opts.msgId) : 1;
5736
- const path21 = messagePath(scope, targetId);
5737
- return this.client.request(token, "POST", path21, {
5794
+ const path22 = messagePath(scope, targetId);
5795
+ return this.client.request(token, "POST", path22, {
5738
5796
  msg_type: 7,
5739
5797
  media: { file_info: fileInfo },
5740
5798
  msg_seq: msgSeq,
@@ -5744,7 +5802,7 @@ var MediaApi = class {
5744
5802
  }
5745
5803
  };
5746
5804
 
5747
- // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607081646/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/api/messages.js
5805
+ // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/api/messages.js
5748
5806
  var MessageApi = class {
5749
5807
  client;
5750
5808
  tokenManager;
@@ -5773,8 +5831,8 @@ var MessageApi = class {
5773
5831
  const token = await this.tokenManager.getAccessToken(creds.appId, creds.clientSecret);
5774
5832
  const msgSeq = opts?.msgId ? getNextMsgSeq(opts.msgId) : 1;
5775
5833
  const body = this.buildMessageBody(content, opts?.msgId, msgSeq, opts?.messageReference, opts?.inlineKeyboard);
5776
- const path21 = messagePath(scope, targetId);
5777
- return this.sendAndNotify(creds.appId, token, "POST", path21, body, { text: content });
5834
+ const path22 = messagePath(scope, targetId);
5835
+ return this.sendAndNotify(creds.appId, token, "POST", path22, body, { text: content });
5778
5836
  }
5779
5837
  async sendProactiveMessage(scope, targetId, content, creds) {
5780
5838
  if (!content?.trim()) {
@@ -5782,8 +5840,8 @@ var MessageApi = class {
5782
5840
  }
5783
5841
  const token = await this.tokenManager.getAccessToken(creds.appId, creds.clientSecret);
5784
5842
  const body = this.buildProactiveBody(content);
5785
- const path21 = messagePath(scope, targetId);
5786
- return this.sendAndNotify(creds.appId, token, "POST", path21, body, { text: content });
5843
+ const path22 = messagePath(scope, targetId);
5844
+ return this.sendAndNotify(creds.appId, token, "POST", path22, body, { text: content });
5787
5845
  }
5788
5846
  async sendChannelMessage(opts) {
5789
5847
  const token = await this.tokenManager.getAccessToken(opts.creds.appId, opts.creds.clientSecret);
@@ -5831,7 +5889,7 @@ var MessageApi = class {
5831
5889
  */
5832
5890
  async sendC2CStreamMessage(creds, openid, req4) {
5833
5891
  const token = await this.tokenManager.getAccessToken(creds.appId, creds.clientSecret);
5834
- const path21 = streamMessagePath(openid);
5892
+ const path22 = streamMessagePath(openid);
5835
5893
  const body = {
5836
5894
  input_mode: req4.input_mode,
5837
5895
  input_state: req4.input_state,
@@ -5845,7 +5903,7 @@ var MessageApi = class {
5845
5903
  if (req4.stream_msg_id) {
5846
5904
  body.stream_msg_id = req4.stream_msg_id;
5847
5905
  }
5848
- return this.client.request(token, "POST", path21, body);
5906
+ return this.client.request(token, "POST", path22, body);
5849
5907
  }
5850
5908
  /**
5851
5909
  * Raw message send — transparently forwards all fields to the QQ Open Platform API.
@@ -5859,7 +5917,7 @@ var MessageApi = class {
5859
5917
  */
5860
5918
  async sendRaw(scope, targetId, creds, body) {
5861
5919
  const token = await this.tokenManager.getAccessToken(creds.appId, creds.clientSecret);
5862
- const path21 = messagePath(scope, targetId);
5920
+ const path22 = messagePath(scope, targetId);
5863
5921
  if (body.msg_seq === void 0) {
5864
5922
  body.msg_seq = body.msg_id ? getNextMsgSeq(body.msg_id) : 1;
5865
5923
  }
@@ -5876,7 +5934,7 @@ var MessageApi = class {
5876
5934
  body.msg_type = 0;
5877
5935
  }
5878
5936
  const cleaned = Object.fromEntries(Object.entries(body).filter(([, v]) => v !== void 0));
5879
- return this.sendAndNotify(creds.appId, token, "POST", path21, cleaned, { text: cleaned.content ?? cleaned.markdown?.content });
5937
+ return this.sendAndNotify(creds.appId, token, "POST", path22, cleaned, { text: cleaned.content ?? cleaned.markdown?.content });
5880
5938
  }
5881
5939
  /**
5882
5940
  * Send a message to a guild text channel.
@@ -5900,11 +5958,11 @@ var MessageApi = class {
5900
5958
  */
5901
5959
  async recallMessage(scope, targetId, messageId, creds) {
5902
5960
  const token = await this.tokenManager.getAccessToken(creds.appId, creds.clientSecret);
5903
- const path21 = `${messagePath(scope, targetId)}/${messageId}`;
5904
- await this.client.request(token, "DELETE", path21);
5961
+ const path22 = `${messagePath(scope, targetId)}/${messageId}`;
5962
+ await this.client.request(token, "DELETE", path22);
5905
5963
  }
5906
- async sendAndNotify(_appId, accessToken, method, path21, body, meta) {
5907
- const result = await this.client.request(accessToken, method, path21, body);
5964
+ async sendAndNotify(_appId, accessToken, method, path22, body, meta) {
5965
+ const result = await this.client.request(accessToken, method, path22, body);
5908
5966
  if (result.ext_info?.ref_idx && this.messageSentHook) {
5909
5967
  try {
5910
5968
  this.messageSentHook(result.ext_info.ref_idx, meta);
@@ -5932,7 +5990,7 @@ var MessageApi = class {
5932
5990
  }
5933
5991
  };
5934
5992
 
5935
- // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607081646/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/api/token.js
5993
+ // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/api/token.js
5936
5994
  var DEFAULT_TOKEN_BASE_URL = "https://bots.qq.com";
5937
5995
  var TOKEN_PATH = "/app/getAppAccessToken";
5938
5996
  var TokenManager = class {
@@ -6108,7 +6166,7 @@ var TokenManager = class {
6108
6166
  }
6109
6167
  };
6110
6168
 
6111
- // node_modules/.pnpm/ws@8.20.1/node_modules/ws/wrapper.mjs
6169
+ // node_modules/.pnpm/ws@8.21.0/node_modules/ws/wrapper.mjs
6112
6170
  var import_stream = __toESM(require_stream(), 1);
6113
6171
  var import_extension = __toESM(require_extension(), 1);
6114
6172
  var import_permessage_deflate = __toESM(require_permessage_deflate(), 1);
@@ -6119,7 +6177,7 @@ var import_websocket = __toESM(require_websocket(), 1);
6119
6177
  var import_websocket_server = __toESM(require_websocket_server(), 1);
6120
6178
  var wrapper_default = import_websocket.default;
6121
6179
 
6122
- // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607081646/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/gateway/codec.js
6180
+ // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/gateway/codec.js
6123
6181
  function decodeGatewayMessageData(data) {
6124
6182
  if (typeof data === "string") {
6125
6183
  return data;
@@ -6146,7 +6204,7 @@ function readOptionalMessageSceneExt(event) {
6146
6204
  return scene?.ext;
6147
6205
  }
6148
6206
 
6149
- // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607081646/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/gateway/constants.js
6207
+ // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/gateway/constants.js
6150
6208
  var INTENTS = {
6151
6209
  GUILDS: 1 << 0,
6152
6210
  GUILD_MEMBERS: 1 << 1,
@@ -6219,7 +6277,7 @@ var GatewayEvent = {
6219
6277
  MESSAGE_REACTION_REMOVE: "MESSAGE_REACTION_REMOVE"
6220
6278
  };
6221
6279
 
6222
- // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607081646/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/gateway/event-dispatcher.js
6280
+ // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/gateway/event-dispatcher.js
6223
6281
  var REF_INDEX_KEY = "msg_idx";
6224
6282
  function parseRefIndices(ext, msgType, msgElements) {
6225
6283
  let refMsgIdx;
@@ -6360,7 +6418,7 @@ function dispatchEvent(eventType, data, _accountId, _log) {
6360
6418
  return { action: "raw", type: eventType, data };
6361
6419
  }
6362
6420
 
6363
- // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607081646/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/gateway/reconnect.js
6421
+ // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/gateway/reconnect.js
6364
6422
  var ReconnectState = class {
6365
6423
  accountId;
6366
6424
  log;
@@ -6471,7 +6529,7 @@ var ReconnectState = class {
6471
6529
  }
6472
6530
  };
6473
6531
 
6474
- // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607081646/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/gateway/gateway-connection.js
6532
+ // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/gateway/gateway-connection.js
6475
6533
  var GatewayConnection = class {
6476
6534
  isAborted = false;
6477
6535
  currentWs = null;
@@ -6729,7 +6787,7 @@ function previewPayload(data) {
6729
6787
  }
6730
6788
  }
6731
6789
 
6732
- // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607081646/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/transport/webhook-verify.js
6790
+ // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/transport/webhook-verify.js
6733
6791
  var crypto2 = __toESM(require("crypto"), 1);
6734
6792
  function deriveSeed(botSecret) {
6735
6793
  let seed = botSecret;
@@ -6781,14 +6839,14 @@ function signValidationResponse(params) {
6781
6839
  };
6782
6840
  }
6783
6841
 
6784
- // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607081646/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/transport/webhook-server-node.js
6842
+ // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/transport/webhook-server-node.js
6785
6843
  var http = __toESM(require("http"), 1);
6786
6844
  var NodeHttpWebhookServer = class {
6787
6845
  server = null;
6788
- async listen(port, path21, handler) {
6846
+ async listen(port, path22, handler) {
6789
6847
  return new Promise((resolve2, reject) => {
6790
6848
  const server = http.createServer(async (req4, res) => {
6791
- if (req4.method !== "POST" || req4.url !== path21) {
6849
+ if (req4.method !== "POST" || req4.url !== path22) {
6792
6850
  res.writeHead(404, { "Content-Type": "text/plain" });
6793
6851
  res.end("Not Found");
6794
6852
  return;
@@ -6829,7 +6887,7 @@ var NodeHttpWebhookServer = class {
6829
6887
  }
6830
6888
  };
6831
6889
 
6832
- // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607081646/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/transport/webhook.js
6890
+ // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/transport/webhook.js
6833
6891
  var OP_DISPATCH = 0;
6834
6892
  var OP_HTTP_CALLBACK_ACK = 12;
6835
6893
  var OP_VALIDATION = 13;
@@ -6850,11 +6908,11 @@ var WebhookTransport = class {
6850
6908
  }
6851
6909
  async start() {
6852
6910
  const port = this.opts.port ?? 8080;
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 });
6911
+ const path22 = this.opts.path ?? "/";
6912
+ this.log?.info?.(`[webhook] starting on port ${port}, path ${path22}`);
6913
+ await this.server.listen(port, path22, (req4) => this.handleRequest(req4));
6914
+ this.log?.info?.(`[webhook] listening on :${port}${path22}`);
6915
+ this.callbacks.onReady?.({ transport: "webhook", port, path: path22 });
6858
6916
  if (this.opts.abortSignal) {
6859
6917
  await new Promise((resolve2) => {
6860
6918
  if (this.opts.abortSignal.aborted) {
@@ -6973,7 +7031,7 @@ function getHeader(headers, key) {
6973
7031
  return val;
6974
7032
  }
6975
7033
 
6976
- // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607081646/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/utils/file-utils.js
7034
+ // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/utils/file-utils.js
6977
7035
  var MAX_UPLOAD_SIZE = 20 * 1024 * 1024;
6978
7036
  var CHUNKED_UPLOAD_MAX_SIZE = 100 * 1024 * 1024;
6979
7037
  var LARGE_FILE_THRESHOLD = 5 * 1024 * 1024;
@@ -6991,7 +7049,7 @@ function sanitizeFileName(name) {
6991
7049
  return cleaned || "file";
6992
7050
  }
6993
7051
 
6994
- // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607081646/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/utils/upload-cache.js
7052
+ // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/utils/upload-cache.js
6995
7053
  var crypto3 = __toESM(require("crypto"), 1);
6996
7054
  var MAX_CACHE_SIZE = 500;
6997
7055
  function computeFileHash(data) {
@@ -7056,7 +7114,7 @@ var UploadCache = class {
7056
7114
  }
7057
7115
  };
7058
7116
 
7059
- // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607081646/node_modules/@cxyhhhhh/qqbot-nodejs/dist/streaming.js
7117
+ // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/streaming.js
7060
7118
  var DEFAULT_THROTTLE_MS = 500;
7061
7119
  var MIN_THROTTLE_MS = 300;
7062
7120
  var MAX_FLUSH_RETRIES = 3;
@@ -7224,7 +7282,7 @@ var StreamSession = class {
7224
7282
  }
7225
7283
  };
7226
7284
 
7227
- // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607081646/node_modules/@cxyhhhhh/qqbot-nodejs/dist/QQBot.js
7285
+ // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/QQBot.js
7228
7286
  var MsgType = {
7229
7287
  /** Plain text. */
7230
7288
  TEXT: 0,
@@ -7744,25 +7802,25 @@ var QQBot = class {
7744
7802
  if (this._apiGateway)
7745
7803
  return this._apiGateway;
7746
7804
  this._apiGateway = {
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),
7805
+ get: (path22, query) => this.apiRequest("GET", path22, void 0, query),
7806
+ post: (path22, body) => this.apiRequest("POST", path22, body),
7807
+ put: (path22, body) => this.apiRequest("PUT", path22, body),
7808
+ patch: (path22, body) => this.apiRequest("PATCH", path22, body),
7809
+ delete: (path22) => this.apiRequest("DELETE", path22),
7752
7810
  getToken: () => this.tokenManager.getAccessToken(this.creds.appId, this.creds.clientSecret)
7753
7811
  };
7754
7812
  return this._apiGateway;
7755
7813
  }
7756
- async apiRequest(method, path21, body, query) {
7814
+ async apiRequest(method, path22, body, query) {
7757
7815
  const token = await this.tokenManager.getAccessToken(this.creds.appId, this.creds.clientSecret);
7758
- let fullPath = path21;
7816
+ let fullPath = path22;
7759
7817
  if (query && Object.keys(query).length > 0) {
7760
7818
  const params = new URLSearchParams();
7761
7819
  for (const [k, v] of Object.entries(query)) {
7762
7820
  if (v !== void 0 && v !== null)
7763
7821
  params.set(k, String(v));
7764
7822
  }
7765
- fullPath = `${path21}?${params.toString()}`;
7823
+ fullPath = `${path22}?${params.toString()}`;
7766
7824
  }
7767
7825
  return this.apiClient.request(token, method, fullPath, body ?? void 0);
7768
7826
  }
@@ -7912,7 +7970,7 @@ var QQBot = class {
7912
7970
  }
7913
7971
  };
7914
7972
 
7915
- // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607081646/node_modules/@cxyhhhhh/qqbot-nodejs/dist/middleware/message-filter.js
7973
+ // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/middleware/message-filter.js
7916
7974
  function messageFilter(options = {}) {
7917
7975
  const skipSelfEcho = options.skipSelfEcho ?? true;
7918
7976
  const dedupOpts = options.dedup !== false ? { windowMs: 5e3, maxSize: 1e3, ...options.dedup ?? {} } : null;
@@ -7950,7 +8008,7 @@ function messageFilter(options = {}) {
7950
8008
  };
7951
8009
  }
7952
8010
 
7953
- // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607081646/node_modules/@cxyhhhhh/qqbot-nodejs/dist/middleware/content-sanitizer.js
8011
+ // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/middleware/content-sanitizer.js
7954
8012
  function contentSanitizer(options = {}) {
7955
8013
  const { stripBotMention = true, stripAllMentions = false, collapseWhitespace = false, parseFaceTags: parseFaceTags2 = false, transform } = options;
7956
8014
  return async (ctx, next) => {
@@ -8045,7 +8103,7 @@ function faceToEmoji(id) {
8045
8103
  return map[id];
8046
8104
  }
8047
8105
 
8048
- // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607081646/node_modules/@cxyhhhhh/qqbot-nodejs/dist/middleware/rate-limiter.js
8106
+ // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/middleware/rate-limiter.js
8049
8107
  var SlidingWindow = class {
8050
8108
  buckets = /* @__PURE__ */ new Map();
8051
8109
  max;
@@ -8099,11 +8157,11 @@ function rateLimiter(options = {}) {
8099
8157
  };
8100
8158
  }
8101
8159
 
8102
- // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607081646/node_modules/@cxyhhhhh/qqbot-nodejs/dist/middleware/concurrency-guard.js
8160
+ // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/middleware/concurrency-guard.js
8103
8161
  function concurrencyGuard(options = {}) {
8104
8162
  const strategy = options.strategy ?? "queue";
8105
8163
  const maxQueue = options.maxQueue ?? 3;
8106
- const { onDrop, onMerge, onDispatch } = options;
8164
+ const { onDrop, onMerge, onDispatch, urgentPredicate } = options;
8107
8165
  const locks = /* @__PURE__ */ new Map();
8108
8166
  function getState(key) {
8109
8167
  let s = locks.get(key);
@@ -8156,6 +8214,15 @@ function concurrencyGuard(options = {}) {
8156
8214
  state.mergeBuffer = [];
8157
8215
  state.mergeWaiters = [];
8158
8216
  }
8217
+ if (urgentPredicate?.(ctx)) {
8218
+ ctx.log.debug?.(`[concurrency:merge] urgent for ${key}`);
8219
+ for (const w2 of state.mergeWaiters)
8220
+ w2.resolve();
8221
+ state.mergeBuffer.length = 0;
8222
+ state.mergeWaiters.length = 0;
8223
+ await next();
8224
+ return;
8225
+ }
8159
8226
  if (state.mergeBuffer.length >= maxQueue) {
8160
8227
  ctx.log.debug?.(`[concurrency:merge] buffer full (${maxQueue}), drop for ${key}`);
8161
8228
  await onDrop?.(ctx);
@@ -8303,7 +8370,7 @@ function concurrencyGuard(options = {}) {
8303
8370
  return guard;
8304
8371
  }
8305
8372
 
8306
- // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607081646/node_modules/@cxyhhhhh/qqbot-nodejs/dist/middleware/mention-gate.js
8373
+ // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/middleware/mention-gate.js
8307
8374
  function detectMentionInContent(content, appId) {
8308
8375
  if (!content || !appId)
8309
8376
  return false;
@@ -8359,7 +8426,7 @@ function mentionGate(options = {}) {
8359
8426
  };
8360
8427
  }
8361
8428
 
8362
- // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607081646/node_modules/@cxyhhhhh/qqbot-nodejs/dist/middleware/quote-ref.js
8429
+ // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/middleware/quote-ref.js
8363
8430
  var MemoryRefIndexStore = class {
8364
8431
  map = /* @__PURE__ */ new Map();
8365
8432
  maxSize;
@@ -8477,7 +8544,7 @@ function buildText(content, attachments) {
8477
8544
  return parts.join("\n") || "[empty message]";
8478
8545
  }
8479
8546
 
8480
- // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607081646/node_modules/@cxyhhhhh/qqbot-nodejs/dist/middleware/envelope-formatter.js
8547
+ // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/middleware/envelope-formatter.js
8481
8548
  function envelopeFormatter(options = {}) {
8482
8549
  const { historyLimit = 5, includeQuote = true, includeSender = true, format } = options;
8483
8550
  return async (ctx, next) => {
@@ -8549,7 +8616,7 @@ ${parts.join("\n")}
8549
8616
  return sections.join("\n\n");
8550
8617
  }
8551
8618
 
8552
- // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607081646/node_modules/@cxyhhhhh/qqbot-nodejs/dist/middleware/slash-command.js
8619
+ // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/middleware/slash-command.js
8553
8620
  function slashCommand(options = {}) {
8554
8621
  const prefixes = options.prefixes ?? ["/"];
8555
8622
  const catchErrors = options.catchErrors ?? true;
@@ -8701,7 +8768,7 @@ async function sendCommandResult(ctx, result) {
8701
8768
  }
8702
8769
  }
8703
8770
 
8704
- // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607081646/node_modules/@cxyhhhhh/qqbot-nodejs/dist/middleware/history-buffer.js
8771
+ // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/middleware/history-buffer.js
8705
8772
  var MemoryHistoryStore = class {
8706
8773
  buffers = /* @__PURE__ */ new Map();
8707
8774
  append(groupKey, entry, limit) {
@@ -8766,7 +8833,7 @@ function historyBuffer(options = {}) {
8766
8833
  return m3;
8767
8834
  }
8768
8835
 
8769
- // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607081646/node_modules/@cxyhhhhh/qqbot-nodejs/dist/middleware/typing-indicator.js
8836
+ // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/middleware/typing-indicator.js
8770
8837
  var DEFAULT_DURATION_SEC = 60;
8771
8838
  var DEFAULT_KEEPALIVE_INTERVAL_MS = 5e4;
8772
8839
  function typingIndicator(options = {}) {
@@ -8803,7 +8870,7 @@ function typingIndicator(options = {}) {
8803
8870
  };
8804
8871
  }
8805
8872
 
8806
- // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607081646/node_modules/@cxyhhhhh/qqbot-nodejs/dist/middleware/error-handler.js
8873
+ // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/middleware/error-handler.js
8807
8874
  var DEFAULT_FORMAT = (err) => {
8808
8875
  if (err instanceof ApiError) {
8809
8876
  if (err.bizMessage)
@@ -8841,7 +8908,7 @@ function errorHandler(options = {}) {
8841
8908
  };
8842
8909
  }
8843
8910
 
8844
- // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607081646/node_modules/@cxyhhhhh/qqbot-nodejs/dist/storage/kv-store.js
8911
+ // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/storage/kv-store.js
8845
8912
  var import_node_fs = __toESM(require("fs"), 1);
8846
8913
  var import_node_path = __toESM(require("path"), 1);
8847
8914
  var FileKVStore = class {
@@ -8951,7 +9018,7 @@ var FileKVStore = class {
8951
9018
  }
8952
9019
  };
8953
9020
 
8954
- // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607081646/node_modules/@cxyhhhhh/qqbot-nodejs/dist/storage/session-adapter.js
9021
+ // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/storage/session-adapter.js
8955
9022
  function kvSessionPersistence(opts) {
8956
9023
  const prefix = opts.prefix ?? "qqbot:session:";
8957
9024
  const key = `${prefix}${opts.accountId}`;
@@ -9004,13 +9071,105 @@ function parseTarget(to) {
9004
9071
  return { scope: "c2c", targetId: id };
9005
9072
  }
9006
9073
 
9074
+ // src/outbound/reply-limiter.ts
9075
+ var ReplyLimiter = class {
9076
+ limit;
9077
+ ttlMs;
9078
+ maxTracked;
9079
+ messages = /* @__PURE__ */ new Map();
9080
+ constructor(config) {
9081
+ this.limit = config?.limit ?? 4;
9082
+ this.ttlMs = config?.ttlMs ?? 36e5;
9083
+ this.maxTracked = config?.maxTrackedMessages ?? 1e4;
9084
+ }
9085
+ /**
9086
+ * 检查是否允许对指定消息继续被动回复
9087
+ */
9088
+ checkLimit(messageId) {
9089
+ const now = Date.now();
9090
+ const tracked = this.messages.get(messageId);
9091
+ if (!tracked) {
9092
+ return { allowed: true, remaining: this.limit, shouldFallbackToProactive: false };
9093
+ }
9094
+ if (now - tracked.firstSeenAt > this.ttlMs) {
9095
+ this.messages.delete(messageId);
9096
+ return {
9097
+ allowed: false,
9098
+ remaining: 0,
9099
+ shouldFallbackToProactive: true,
9100
+ fallbackReason: "expired"
9101
+ };
9102
+ }
9103
+ const remaining = Math.max(0, this.limit - tracked.count);
9104
+ if (remaining <= 0) {
9105
+ return {
9106
+ allowed: false,
9107
+ remaining: 0,
9108
+ shouldFallbackToProactive: true,
9109
+ fallbackReason: "limit_exceeded"
9110
+ };
9111
+ }
9112
+ return { allowed: true, remaining, shouldFallbackToProactive: false };
9113
+ }
9114
+ /**
9115
+ * 记录一次被动回复
9116
+ */
9117
+ record(messageId) {
9118
+ const now = Date.now();
9119
+ const tracked = this.messages.get(messageId);
9120
+ if (tracked) {
9121
+ tracked.count++;
9122
+ } else {
9123
+ if (this.messages.size >= this.maxTracked) {
9124
+ const firstKey = this.messages.keys().next().value;
9125
+ if (firstKey) this.messages.delete(firstKey);
9126
+ }
9127
+ this.messages.set(messageId, { count: 1, firstSeenAt: now });
9128
+ }
9129
+ }
9130
+ /**
9131
+ * 获取统计信息
9132
+ */
9133
+ getStats() {
9134
+ let totalReplies = 0;
9135
+ for (const [, v] of this.messages) {
9136
+ totalReplies += v.count;
9137
+ }
9138
+ return { trackedMessages: this.messages.size, totalReplies };
9139
+ }
9140
+ /**
9141
+ * 清除所有跟踪数据
9142
+ */
9143
+ clear() {
9144
+ this.messages.clear();
9145
+ }
9146
+ };
9147
+
9007
9148
  // src/outbound/outbound-service.ts
9008
9149
  var gateways = /* @__PURE__ */ new Map();
9150
+ var limiters = /* @__PURE__ */ new Map();
9151
+ function getLimiter(accountId) {
9152
+ let l3 = limiters.get(accountId);
9153
+ if (!l3) {
9154
+ l3 = new ReplyLimiter();
9155
+ limiters.set(accountId, l3);
9156
+ }
9157
+ return l3;
9158
+ }
9159
+ function resolveMsgId(replyToId, accountId) {
9160
+ if (!replyToId) return void 0;
9161
+ const limiter = getLimiter(accountId);
9162
+ const result = limiter.checkLimit(replyToId);
9163
+ if (!result.allowed) return void 0;
9164
+ limiter.record(replyToId);
9165
+ return replyToId;
9166
+ }
9009
9167
  function registerGateway(accountId, gw) {
9010
9168
  gateways.set(accountId, gw);
9011
9169
  }
9012
9170
  function unregisterGateway(accountId) {
9013
9171
  gateways.delete(accountId);
9172
+ limiters.delete(accountId);
9014
9173
  }
9015
9174
  function getGateway(accountId) {
9016
9175
  return gateways.get(accountId);
@@ -9022,62 +9181,55 @@ var MEDIA_KIND_TO_FILE_TYPE = {
9022
9181
  file: MediaFileType.FILE
9023
9182
  };
9024
9183
  async function sendText(params) {
9025
- const gw = gateways.get(params.account.accountId);
9026
- if (!gw) {
9027
- return { error: `Bot "${params.account.accountId}" not running` };
9028
- }
9184
+ const accountId = params.account.accountId;
9185
+ const gw = gateways.get(accountId);
9186
+ if (!gw) return { error: `Bot "${accountId}" not running` };
9029
9187
  try {
9030
9188
  const target = parseTarget(params.to);
9031
- const result = await gw.sendText(target, params.text, { msgId: params.replyToId });
9189
+ const msgId = resolveMsgId(params.replyToId, accountId);
9190
+ const result = await gw.sendText(target, params.text, { msgId });
9032
9191
  return { messageId: result.id };
9033
9192
  } catch (err) {
9034
9193
  return formatError(err);
9035
9194
  }
9036
9195
  }
9037
9196
  async function sendMedia(params) {
9038
- const gw = gateways.get(params.account.accountId);
9039
- if (!gw) {
9040
- return { error: `Bot "${params.account.accountId}" not running` };
9041
- }
9197
+ const accountId = params.account.accountId;
9198
+ const gw = gateways.get(accountId);
9199
+ if (!gw) return { error: `Bot "${accountId}" not running` };
9042
9200
  try {
9043
9201
  const target = parseTarget(params.to);
9044
9202
  const kind = params.mediaKind ?? "image";
9203
+ const msgId = resolveMsgId(params.replyToId, accountId);
9045
9204
  if (kind === "voice") {
9046
- const isLocalPath = params.mediaUrl.startsWith("/") || params.mediaUrl.startsWith("./") || params.mediaUrl.startsWith("../");
9047
- const isUrl = params.mediaUrl.startsWith("http://") || params.mediaUrl.startsWith("https://");
9048
- const source = isLocalPath ? { localPath: params.mediaUrl } : isUrl ? { url: params.mediaUrl } : { base64: params.mediaUrl };
9049
- const result2 = await gw.sendVoice(
9050
- target,
9051
- source,
9052
- { text: params.text, msgId: params.replyToId }
9053
- );
9205
+ const source = resolveVoiceSource(params.mediaUrl);
9206
+ const result2 = await gw.sendVoice(target, source, { text: params.text, msgId });
9054
9207
  return { messageId: result2.id };
9055
9208
  }
9056
9209
  if (kind === "video") {
9057
- const result2 = await gw.sendVideo(target, params.mediaUrl, {
9058
- text: params.text,
9059
- msgId: params.replyToId
9060
- });
9210
+ const result2 = await gw.sendVideo(target, params.mediaUrl, { text: params.text, msgId });
9061
9211
  return { messageId: result2.id };
9062
9212
  }
9063
9213
  if (kind === "file") {
9064
- const result2 = await gw.sendFile(target, params.mediaUrl, {
9065
- text: params.text,
9066
- msgId: params.replyToId
9067
- });
9214
+ const result2 = await gw.sendFile(target, params.mediaUrl, { text: params.text, msgId });
9068
9215
  return { messageId: result2.id };
9069
9216
  }
9070
9217
  const fileType = MEDIA_KIND_TO_FILE_TYPE[kind];
9071
- const result = await gw.sendMedia(target, params.mediaUrl, {
9072
- text: params.text,
9073
- msgId: params.replyToId,
9074
- fileType
9075
- });
9218
+ const result = await gw.sendMedia(target, params.mediaUrl, { text: params.text, msgId, fileType });
9076
9219
  return { messageId: result.id };
9077
9220
  } catch (err) {
9078
9221
  return formatError(err);
9079
9222
  }
9080
9223
  }
9224
+ function resolveVoiceSource(source) {
9225
+ if (source.startsWith("http://") || source.startsWith("https://")) return { url: source };
9226
+ if (source.startsWith("/") || source.startsWith("./") || source.startsWith("../")) return { localPath: source };
9227
+ if (source.startsWith("data:")) {
9228
+ const i = source.indexOf(",");
9229
+ return { base64: i > 0 ? source.slice(i + 1) : source };
9230
+ }
9231
+ return { base64: source };
9232
+ }
9081
9233
  function formatError(err) {
9082
9234
  if (err instanceof Error) {
9083
9235
  const result = { error: err.message };
@@ -9093,7 +9245,7 @@ var import_node_path2 = __toESM(require("path"), 1);
9093
9245
  var import_node_fs2 = __toESM(require("fs"), 1);
9094
9246
  var _cachedOpenclawVersion;
9095
9247
  function getPackageVersion() {
9096
- return true ? "2.0.0-dev.202607091556" : "unknown";
9248
+ return true ? "2.0.0-dev.202607092101" : "unknown";
9097
9249
  }
9098
9250
  function getOpenclawVersion(runtimeVersion) {
9099
9251
  if (_cachedOpenclawVersion) return _cachedOpenclawVersion;
@@ -9508,12 +9660,12 @@ function tryGetQQBotRuntime() {
9508
9660
 
9509
9661
  // src/adapter/resolve.ts
9510
9662
  function probeFunction(rt, paths) {
9511
- for (const path21 of paths) {
9663
+ for (const path22 of paths) {
9512
9664
  let target = rt;
9513
9665
  let parent = rt;
9514
- for (let i = 0; i < path21.length; i++) {
9666
+ for (let i = 0; i < path22.length; i++) {
9515
9667
  parent = target;
9516
- target = target?.[path21[i]];
9668
+ target = target?.[path22[i]];
9517
9669
  if (target === void 0 || target === null) break;
9518
9670
  }
9519
9671
  if (typeof target === "function") {
@@ -9675,6 +9827,63 @@ function resolveAgentWorkspace(cfg, agentId) {
9675
9827
  return getQQBotMediaDir();
9676
9828
  }
9677
9829
 
9830
+ // src/utils/ssrf-guard.ts
9831
+ var import_node_net = __toESM(require("net"), 1);
9832
+ var import_promises = __toESM(require("dns/promises"), 1);
9833
+ var RESERVED_V4_PREFIXES = [
9834
+ "127.",
9835
+ // loopback
9836
+ "10.",
9837
+ // class-A private
9838
+ "192.168.",
9839
+ // class-C private
9840
+ "169.254."
9841
+ // link-local / cloud metadata
9842
+ ];
9843
+ var PRIVATE_172_RE = /^172\.(1[6-9]|2\d|3[01])\./;
9844
+ function isReservedAddr(ip) {
9845
+ if (ip === "0.0.0.0") return true;
9846
+ for (const pfx of RESERVED_V4_PREFIXES) {
9847
+ if (ip.startsWith(pfx)) return true;
9848
+ }
9849
+ if (PRIVATE_172_RE.test(ip)) return true;
9850
+ const lower = ip.toLowerCase();
9851
+ if (lower === "::1" || lower === "::") return true;
9852
+ if (lower.startsWith("fe80:")) return true;
9853
+ if (lower.startsWith("fc") || lower.startsWith("fd")) return true;
9854
+ return false;
9855
+ }
9856
+ var ALLOWED_SCHEMES = /* @__PURE__ */ new Set(["http:", "https:"]);
9857
+ async function validateRemoteUrl(raw) {
9858
+ const url = new URL(raw);
9859
+ if (!ALLOWED_SCHEMES.has(url.protocol)) {
9860
+ throw new Error(
9861
+ `\u4E0D\u652F\u6301\u7684\u534F\u8BAE "${url.protocol}"\uFF0C\u4EC5\u5141\u8BB8 http/https\uFF08URL: ${raw}\uFF09`
9862
+ );
9863
+ }
9864
+ const host = url.hostname.replace(/^\[|\]$/g, "");
9865
+ if (import_node_net.default.isIP(host)) {
9866
+ assertPublicAddr(host, raw);
9867
+ return;
9868
+ }
9869
+ try {
9870
+ const ips = await import_promises.default.resolve(host);
9871
+ for (const ip of ips) {
9872
+ assertPublicAddr(ip, raw, host);
9873
+ }
9874
+ } catch (err) {
9875
+ if (err instanceof Error && err.message.includes("\u5185\u7F51")) throw err;
9876
+ console.warn(`[url-check] DNS \u89E3\u6790 "${host}" \u5931\u8D25: ${err}`);
9877
+ }
9878
+ }
9879
+ function assertPublicAddr(ip, originalUrl, domain) {
9880
+ if (!isReservedAddr(ip)) return;
9881
+ const target = domain ? `\u57DF\u540D "${domain}" \u89E3\u6790\u5230\u5185\u7F51\u5730\u5740 "${ip}"` : `\u5185\u7F51\u5730\u5740 "${ip}"`;
9882
+ throw new Error(
9883
+ `\u7981\u6B62\u8BBF\u95EE${target}\uFF0C\u5DF2\u62E6\u622A\u6F5C\u5728\u7684 SSRF \u8BF7\u6C42\uFF08URL: ${originalUrl}\uFF09`
9884
+ );
9885
+ }
9886
+
9678
9887
  // src/outbound/local-file-router.ts
9679
9888
  var path7 = __toESM(require("path"), 1);
9680
9889
  var fs8 = __toESM(require("fs"), 1);
@@ -9709,6 +9918,9 @@ function isLocalFilePath(source) {
9709
9918
  if (source.startsWith(".\\") || source.startsWith("..\\")) return true;
9710
9919
  return false;
9711
9920
  }
9921
+ function isDataUrl(source) {
9922
+ return source.startsWith("data:");
9923
+ }
9712
9924
  var IMAGE_EXTS = /* @__PURE__ */ new Set([".jpg", ".jpeg", ".png", ".gif", ".webp", ".bmp", ".svg", ".ico"]);
9713
9925
  var VOICE_EXTS = /* @__PURE__ */ new Set([".wav", ".mp3", ".silk", ".amr", ".ogg", ".flac", ".aac", ".m4a"]);
9714
9926
  var VIDEO_EXTS = /* @__PURE__ */ new Set([".mp4", ".avi", ".mov", ".mkv", ".webm", ".flv", ".wmv"]);
@@ -9726,14 +9938,48 @@ function inferMediaKindFromMime(mime) {
9726
9938
  if (lower.startsWith("video/")) return "video";
9727
9939
  return "file";
9728
9940
  }
9941
+ function isPathInAllowedRoots(absPath, allowedRoots) {
9942
+ if (!allowedRoots.length) return false;
9943
+ try {
9944
+ const real = fs8.realpathSync(absPath);
9945
+ return allowedRoots.some((root) => {
9946
+ try {
9947
+ const rootReal = fs8.existsSync(root) ? fs8.realpathSync(root) : root;
9948
+ return real.startsWith(rootReal + path7.sep) || real === rootReal;
9949
+ } catch {
9950
+ return false;
9951
+ }
9952
+ });
9953
+ } catch {
9954
+ return false;
9955
+ }
9956
+ }
9729
9957
 
9730
9958
  // src/outbound/media-send.ts
9959
+ function resolveTempRoots() {
9960
+ const roots = /* @__PURE__ */ new Set();
9961
+ try {
9962
+ const tmp = os4.tmpdir();
9963
+ roots.add(fs9.existsSync(tmp) ? fs9.realpathSync(tmp) : tmp);
9964
+ } catch {
9965
+ }
9966
+ if (process.platform !== "win32") {
9967
+ try {
9968
+ roots.add(fs9.realpathSync("/tmp"));
9969
+ } catch {
9970
+ }
9971
+ }
9972
+ return [...roots];
9973
+ }
9731
9974
  var ALLOWED_MEDIA_ROOTS = [
9732
9975
  path8.join(os4.homedir(), ".openclaw", "media"),
9733
9976
  path8.join(os4.homedir(), ".openclaw", "workspace"),
9734
9977
  // 框架 outbound 目录(saveMediaBuffer 写入)
9735
- path8.join(os4.homedir(), ".openclaw", "outbound")
9978
+ path8.join(os4.homedir(), ".openclaw", "outbound"),
9979
+ // TTS 语音临时目录(deliver-pipeline 已通过 isTtsPathSafe 预检)
9980
+ ...resolveTempRoots()
9736
9981
  ];
9982
+ var MAX_DATA_URL_BYTES = 10 * 1024 * 1024;
9737
9983
  async function sendMedia2(params) {
9738
9984
  const { source, accountId, log: log4 } = params;
9739
9985
  const mlog = log4?.child("media");
@@ -9743,7 +9989,7 @@ async function sendMedia2(params) {
9743
9989
  }
9744
9990
  const wsDir = resolveWorkspaceFromAgent(params.agentId);
9745
9991
  mlog?.debug(`resolveMediaPath source=${source} agentId=${params.agentId ?? "none"} workspaceDir=${wsDir ?? "none"}`);
9746
- const resolved = resolveMediaPath(source, mlog, wsDir);
9992
+ const resolved = await resolveMediaPath(source, mlog, wsDir);
9747
9993
  if (!resolved.ok) {
9748
9994
  mlog?.error(`resolveMediaPath failed: ${resolved.error}`);
9749
9995
  return { error: resolved.error };
@@ -9766,8 +10012,24 @@ async function sendMedia2(params) {
9766
10012
  return sendImageMedia(gw, target, resolved.path, params);
9767
10013
  }
9768
10014
  }
9769
- function resolveMediaPath(source, log4, workspaceDir) {
10015
+ async function resolveMediaPath(source, log4, workspaceDir) {
9770
10016
  const normalized = normalizePath(source);
10017
+ if (isDataUrl(normalized)) {
10018
+ if (normalized.length > MAX_DATA_URL_BYTES) {
10019
+ const sizeMB = (normalized.length / (1024 * 1024)).toFixed(1);
10020
+ return { ok: false, error: `Data URL \u8FC7\u5927\uFF08${sizeMB}MB\uFF0C\u6700\u5927 10MB\uFF09` };
10021
+ }
10022
+ return { ok: true, path: normalized, isLocal: false };
10023
+ }
10024
+ if (normalized.startsWith("http://") || normalized.startsWith("https://")) {
10025
+ try {
10026
+ await validateRemoteUrl(normalized);
10027
+ } catch (err) {
10028
+ log4?.warn(`SSRF blocked for media URL: ${normalized}`);
10029
+ return { ok: false, error: `\u5A92\u4F53 URL \u88AB SSRF \u9632\u62A4\u62E6\u622A: ${err instanceof Error ? err.message : String(err)}` };
10030
+ }
10031
+ return { ok: true, path: normalized, isLocal: false };
10032
+ }
9771
10033
  if (!isLocalFilePath(normalized)) {
9772
10034
  const resolved2 = resolveWorkingFile(normalized, workspaceDir);
9773
10035
  if (resolved2) {
@@ -9785,16 +10047,10 @@ function resolveMediaPath(source, log4, workspaceDir) {
9785
10047
  } catch {
9786
10048
  return { ok: false, error: `Cannot resolve path: ${resolved}` };
9787
10049
  }
9788
- const allowed = ALLOWED_MEDIA_ROOTS.some((root) => {
9789
- try {
9790
- const resolvedRoot = fs9.existsSync(root) ? fs9.realpathSync(root) : root;
9791
- return real.startsWith(resolvedRoot + path8.sep) || real === resolvedRoot;
9792
- } catch {
9793
- return false;
9794
- }
9795
- });
10050
+ const allowed = isPathInAllowedRoots(real, ALLOWED_MEDIA_ROOTS);
9796
10051
  if (!allowed) {
9797
- log4?.warn(`path not in allowed directory: ${real}`);
10052
+ log4?.warn(`path blocked \u2014 not in allowed directory: ${real}`);
10053
+ return { ok: false, error: `\u6587\u4EF6\u8DEF\u5F84\u4E0D\u5728\u5141\u8BB8\u7684\u76EE\u5F55\u4E2D` };
9798
10054
  }
9799
10055
  return { ok: true, path: real, isLocal: true };
9800
10056
  }
@@ -9830,7 +10086,7 @@ async function sendImageMedia(gw, target, source, params) {
9830
10086
  }
9831
10087
  }
9832
10088
  async function sendVoiceMedia(gw, target, source, params) {
9833
- const voiceSource = resolveVoiceSource(source);
10089
+ const voiceSource = resolveVoiceSource2(source);
9834
10090
  try {
9835
10091
  const result = await gw.sendVoice(target, voiceSource, {
9836
10092
  msgId: params.replyToId
@@ -9875,7 +10131,7 @@ async function sendFileMedia(gw, target, source, params) {
9875
10131
  return { error: formatErr(err) };
9876
10132
  }
9877
10133
  }
9878
- function resolveVoiceSource(source) {
10134
+ function resolveVoiceSource2(source) {
9879
10135
  if (source.startsWith("http://") || source.startsWith("https://")) {
9880
10136
  return { url: source };
9881
10137
  }
@@ -10173,6 +10429,31 @@ var qqbotSetupWizard = {
10173
10429
  }
10174
10430
  };
10175
10431
 
10432
+ // src/outbound/sanitize.ts
10433
+ var INTERNAL_TAGS = [
10434
+ // 框架脚手架标签
10435
+ /<system-reminder\b[^>]*>[\s\S]*?<\/system-reminder>/gi,
10436
+ /<previous_response\b[^>]*>[\s\S]*?<\/previous_response>/gi,
10437
+ /<\s*\/?\s*(?:system-reminder|previous_response)\b[^>]*\/?\s*>/gi,
10438
+ // 模型推理/思考内容
10439
+ // deepseek: `think`...`/think` — 匹配完整标签块,标签名 think 必须完整
10440
+ // 格式说明:deepseek 用 `` ` `` (反引号) 替代 XML 的 `<` `>` 作为标签定界符
10441
+ // `think` ≡ <think> 开标签
10442
+ // `/think` ≡ </think> 闭标签
10443
+ /`think`[\s\S]*?`\/think`/gi,
10444
+ /<\s*\/?\s*think\b[^>]*\/?\s*>/gi,
10445
+ // claude: <thinking>...</thinking>
10446
+ /<thinking\b[^>]*>[\s\S]*?<\/thinking>/gi,
10447
+ /<\s*\/?\s*thinking\b[^>]*\/?\s*>/gi
10448
+ ];
10449
+ function sanitizeQQBotText(text) {
10450
+ let result = text;
10451
+ for (const re of INTERNAL_TAGS) {
10452
+ result = result.replace(re, "");
10453
+ }
10454
+ return result.trim();
10455
+ }
10456
+
10176
10457
  // src/gateway/qqbot-gateway.ts
10177
10458
  var import_node_os4 = __toESM(require("os"), 1);
10178
10459
 
@@ -10655,6 +10936,7 @@ function botClearStorage(_account) {
10655
10936
  var import_node_fs5 = __toESM(require("fs"), 1);
10656
10937
  var import_node_path5 = __toESM(require("path"), 1);
10657
10938
  var import_node_os3 = __toESM(require("os"), 1);
10939
+ var import_node_crypto2 = __toESM(require("crypto"), 1);
10658
10940
  var MAX_LINES_PER_FILE = 1e3;
10659
10941
  var MAX_FILES = 4;
10660
10942
  var LOG_KEYWORDS = ["gateway", "openclaw", "clawdbot", "moltbot"];
@@ -10834,7 +11116,8 @@ function botLogs(runtime2) {
10834
11116
  const tmpDir = getQQBotMediaDir("exports");
10835
11117
  if (!import_node_fs5.default.existsSync(tmpDir)) import_node_fs5.default.mkdirSync(tmpDir, { recursive: true });
10836
11118
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, 19);
10837
- const tmpFile = import_node_path5.default.join(tmpDir, `bot-logs-${timestamp}.txt`);
11119
+ const suffix = import_node_crypto2.default.randomBytes(4).toString("hex");
11120
+ const tmpFile = import_node_path5.default.join(tmpDir, `bot-logs-${timestamp}-${suffix}.txt`);
10838
11121
  import_node_fs5.default.writeFileSync(tmpFile, lines.join("\n"), "utf8");
10839
11122
  let summary = `${recentFiles.length} \u4E2A\u65E5\u5FD7\u6587\u4EF6\uFF0C\u5171 ${totalIncluded} \u884C`;
10840
11123
  if (truncatedCount > 0) summary += `\uFF08${truncatedCount} \u4E2A\u622A\u65AD\uFF0C\u539F\u59CB ${totalOriginal} \u884C\uFF09`;
@@ -10844,7 +11127,7 @@ function botLogs(runtime2) {
10844
11127
  await ctx.bot.sendFile(
10845
11128
  { scope: "c2c", targetId: senderId, msgId: ctx.message.messageId },
10846
11129
  { localPath: tmpFile },
10847
- { fileName: `bot-logs-${timestamp}.txt` }
11130
+ { fileName: `bot-logs-${timestamp}-${suffix}.txt` }
10848
11131
  );
10849
11132
  }
10850
11133
  } catch (err) {
@@ -11161,10 +11444,10 @@ function buildCommandList(account, opts) {
11161
11444
  // src/middleware/attachment.ts
11162
11445
  var path17 = __toESM(require("path"), 1);
11163
11446
 
11164
- // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607081646/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/utils/reply-limiter.js
11447
+ // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/utils/reply-limiter.js
11165
11448
  var DEFAULT_TTL_MS = 60 * 60 * 1e3;
11166
11449
 
11167
- // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607081646/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/utils/media-tags.js
11450
+ // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/utils/media-tags.js
11168
11451
  var VALID_TAGS = ["qqimg", "qqvoice", "qqvideo", "qqfile", "qqmedia"];
11169
11452
  var TAG_ALIASES = {
11170
11453
  qq_img: "qqimg",
@@ -11213,30 +11496,30 @@ var SELF_CLOSING_TAG_REGEX = new RegExp("`?" + LEFT_BRACKET + "\\s*(" + TAG_NAME
11213
11496
  var FUZZY_MEDIA_TAG_REGEX = new RegExp("`?" + LEFT_BRACKET + "\\s*(" + TAG_NAME_PATTERN + ")\\s*" + RIGHT_BRACKET + `["']?\\s*([^<\uFF1C<\uFF1E>"'\`]+?)\\s*["']?` + LEFT_BRACKET + "\\s*/?\\s*(?:" + TAG_NAME_PATTERN + ")\\s*" + RIGHT_BRACKET + "`?", "gi");
11214
11497
  var MULTILINE_TAG_CLEANUP = new RegExp("(" + LEFT_BRACKET + "\\s*(?:" + TAG_NAME_PATTERN + ")\\s*" + RIGHT_BRACKET + ")([\\s\\S]*?)(" + LEFT_BRACKET + "\\s*/?\\s*(?:" + TAG_NAME_PATTERN + ")\\s*" + RIGHT_BRACKET + ")", "gi");
11215
11498
 
11216
- // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607081646/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/utils/ref-index-store.js
11499
+ // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/utils/ref-index-store.js
11217
11500
  var import_node_fs6 = __toESM(require("fs"), 1);
11218
11501
  var DEFAULT_TTL_MS2 = 7 * 24 * 60 * 60 * 1e3;
11219
11502
 
11220
- // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607081646/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/utils/session-store.js
11503
+ // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/utils/session-store.js
11221
11504
  var import_node_fs7 = __toESM(require("fs"), 1);
11222
11505
  var import_node_path7 = __toESM(require("path"), 1);
11223
11506
  var DEFAULT_EXPIRE_MS = 5 * 60 * 1e3;
11224
11507
 
11225
- // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607081646/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/utils/text-parsing.js
11508
+ // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/utils/text-parsing.js
11226
11509
  var MAX_FACE_EXT_BYTES = 64 * 1024;
11227
11510
 
11228
- // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607081646/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/utils/media-source.js
11511
+ // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/utils/media-source.js
11229
11512
  var fs14 = __toESM(require("fs"), 1);
11230
11513
 
11231
- // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607081646/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/utils/image-size.js
11514
+ // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/utils/image-size.js
11232
11515
  var import_node_buffer = require("buffer");
11233
11516
 
11234
- // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607081646/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/utils/ffmpeg.js
11517
+ // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/utils/ffmpeg.js
11235
11518
  var import_node_child_process = require("child_process");
11236
11519
  var fs15 = __toESM(require("fs"), 1);
11237
11520
  var path13 = __toESM(require("path"), 1);
11238
11521
 
11239
- // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607081646/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/utils/audio.js
11522
+ // node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/utils/audio.js
11240
11523
  var import_node_child_process2 = require("child_process");
11241
11524
  var fs16 = __toESM(require("fs"), 1);
11242
11525
  var path14 = __toESM(require("path"), 1);
@@ -11439,10 +11722,10 @@ function formatDuration2(seconds) {
11439
11722
 
11440
11723
  // src/adapter/media.ts
11441
11724
  var import_node_module4 = require("module");
11442
- var dns = __toESM(require("dns"), 1);
11725
+ var dns2 = __toESM(require("dns"), 1);
11443
11726
  var path16 = __toESM(require("path"), 1);
11444
11727
  var fs18 = __toESM(require("fs"), 1);
11445
- var crypto4 = __toESM(require("crypto"), 1);
11728
+ var crypto5 = __toESM(require("crypto"), 1);
11446
11729
  var req3 = (0, import_node_module4.createRequire)(__filename);
11447
11730
  var _save;
11448
11731
  function downloadRemoteMedia(opts) {
@@ -11478,7 +11761,7 @@ function isPrivateIP(ip) {
11478
11761
  return PRIVATE_RANGES.some(([mask, prefix]) => val >> 32n - BigInt(prefix) === mask >> 32n - BigInt(prefix));
11479
11762
  }
11480
11763
  async function assertSafeHostname(hostname) {
11481
- const addresses = await dns.promises.resolve4(hostname).catch(() => []);
11764
+ const addresses = await dns2.promises.resolve4(hostname).catch(() => []);
11482
11765
  if (addresses.length === 0) throw new Error(`DNS resolution failed: ${hostname}`);
11483
11766
  for (const addr of addresses) {
11484
11767
  if (isPrivateIP(addr)) {
@@ -11503,7 +11786,7 @@ async function downloadViaFetch(opts) {
11503
11786
  if (buf.length > maxBytes) throw new Error(`Download exceeds ${(maxBytes / 1024 / 1024).toFixed(0)}MB`);
11504
11787
  const ext = opts.originalFilename ? path16.extname(opts.originalFilename) || ".bin" : ".bin";
11505
11788
  const name = opts.originalFilename ? path16.basename(opts.originalFilename, path16.extname(opts.originalFilename)) : "download";
11506
- const rand = crypto4.randomBytes(4).toString("hex");
11789
+ const rand = crypto5.randomBytes(4).toString("hex");
11507
11790
  const filePath = path16.join(dir, `${name}_${Date.now()}_${rand}${ext}`);
11508
11791
  fs18.writeFileSync(filePath, buf);
11509
11792
  return { path: filePath };
@@ -12065,6 +12348,10 @@ function setupMiddlewares(bot, account, opts) {
12065
12348
  bot.use(concurrencyGuard({
12066
12349
  strategy: "merge",
12067
12350
  maxQueue: 50,
12351
+ /** 紧急指令(/stop)跳过排队,立即处理 */
12352
+ urgentPredicate: (ctx) => {
12353
+ return (ctx.message.content ?? "").trim() === "/stop";
12354
+ },
12068
12355
  onMerge: (buffered) => {
12069
12356
  const last = buffered[buffered.length - 1];
12070
12357
  if (buffered.length === 1) return last;
@@ -12149,6 +12436,8 @@ function buildEnvelope2(ctx, msg, account) {
12149
12436
  }
12150
12437
 
12151
12438
  // src/outbound/deliver-pipeline.ts
12439
+ var path18 = __toESM(require("path"), 1);
12440
+ var os7 = __toESM(require("os"), 1);
12152
12441
  function resolveMediaUrls(payload) {
12153
12442
  if (payload.mediaUrls?.length) {
12154
12443
  return payload.mediaUrls.filter(Boolean);
@@ -12197,6 +12486,7 @@ async function deliverReply(payload, _info, ctx) {
12197
12486
  }
12198
12487
  }
12199
12488
  async function sendMediaUrls(ctx, urls) {
12489
+ const failedUrls = [];
12200
12490
  for (const url of urls) {
12201
12491
  const result = await sendMedia2({
12202
12492
  to: ctx.qualifiedTarget,
@@ -12208,6 +12498,16 @@ async function sendMediaUrls(ctx, urls) {
12208
12498
  });
12209
12499
  if (result.error) {
12210
12500
  ctx.log?.error(`[media] ${result.error}`);
12501
+ failedUrls.push(url);
12502
+ }
12503
+ }
12504
+ if (failedUrls.length > 0) {
12505
+ const count = failedUrls.length;
12506
+ const total = urls.length;
12507
+ const failMsg = count === total ? `\u26A0\uFE0F \u5A92\u4F53\u53D1\u9001\u5931\u8D25\uFF08${count} \u4E2A\uFF09\uFF0C\u8BF7\u91CD\u8BD5` : `\u26A0\uFE0F ${count}/${total} \u4E2A\u5A92\u4F53\u53D1\u9001\u5931\u8D25`;
12508
+ const textResult = await ctx.sendText(ctx.qualifiedTarget, failMsg);
12509
+ if (textResult.error) {
12510
+ ctx.log?.error(`[media] failed to send failure notification: ${textResult.error}`);
12211
12511
  }
12212
12512
  }
12213
12513
  }
@@ -12227,6 +12527,10 @@ async function handleVoiceIntent(text, ctx) {
12227
12527
  ctx.log?.error(`[tts] TTS failed: ${ttsResult.error ?? "no audio path returned"}`);
12228
12528
  return false;
12229
12529
  }
12530
+ if (!isTtsPathSafe(ttsResult.audioPath)) {
12531
+ ctx.log?.error(`[tts] TTS audio path blocked: ${ttsResult.audioPath}`);
12532
+ return false;
12533
+ }
12230
12534
  if (ctx.audioFileToSilkBase64) {
12231
12535
  const silkBase64 = await ctx.audioFileToSilkBase64(ttsResult.audioPath);
12232
12536
  if (silkBase64) {
@@ -12247,6 +12551,15 @@ async function handleVoiceIntent(text, ctx) {
12247
12551
  return false;
12248
12552
  }
12249
12553
  }
12554
+ var TTS_ALLOWED_ROOTS = [
12555
+ path18.join(os7.homedir(), ".openclaw"),
12556
+ os7.tmpdir(),
12557
+ "/tmp"
12558
+ ];
12559
+ function isTtsPathSafe(audioPath) {
12560
+ if (!path18.isAbsolute(audioPath)) return false;
12561
+ return isPathInAllowedRoots(audioPath, TTS_ALLOWED_ROOTS);
12562
+ }
12250
12563
 
12251
12564
  // src/dispatch/ctx-builder.ts
12252
12565
  function buildCtxPayload(params) {
@@ -13091,10 +13404,10 @@ function getApprovalHandler(accountId) {
13091
13404
 
13092
13405
  // src/features/proactive.ts
13093
13406
  var fs19 = __toESM(require("fs"), 1);
13094
- var path19 = __toESM(require("path"), 1);
13407
+ var path20 = __toESM(require("path"), 1);
13095
13408
  var log2 = createPluginLogger({ prefix: "[proactive]" });
13096
13409
  var STORAGE_DIR = getQQBotDataDir("data");
13097
- var KNOWN_USERS_FILE = path19.join(STORAGE_DIR, "known-users.json");
13410
+ var KNOWN_USERS_FILE = path20.join(STORAGE_DIR, "known-users.json");
13098
13411
  var knownUsersCache = null;
13099
13412
  var cacheLastModified = 0;
13100
13413
  function ensureStorageDir() {
@@ -13298,6 +13611,11 @@ async function handleApproval(event, account, log4, ack) {
13298
13611
  }
13299
13612
  const buttonData = event.data?.resolved?.button_data;
13300
13613
  if (!buttonData?.startsWith("approve:")) return;
13614
+ const operatorId = resolveOperatorId(event);
13615
+ if (!isApprovalAuthorized(account, operatorId)) {
13616
+ log4.warn(`[approval] unauthorized operator=${operatorId ?? "unknown"} account=${account.accountId}`);
13617
+ return;
13618
+ }
13301
13619
  const parts = buttonData.split(":");
13302
13620
  if (parts.length < 3) return;
13303
13621
  const handler = getApprovalHandler(account.accountId);
@@ -13307,10 +13625,20 @@ async function handleApproval(event, account, log4, ack) {
13307
13625
  try {
13308
13626
  await handler.resolveApproval(approvalId, decision);
13309
13627
  } catch (err) {
13310
- log4.error(`interaction approve error: ${err}`);
13628
+ log4.error(`interaction approve error: ${err instanceof Error ? err.message : String(err)}`);
13311
13629
  }
13312
13630
  }
13313
13631
  var CHANNEL_VER = getPackageVersion();
13632
+ function resolveOperatorId(event) {
13633
+ const evt = event;
13634
+ return evt.user_openid ?? evt.data?.resolved?.user_id ?? evt.data?.resolved?.user_openid ?? evt.openid;
13635
+ }
13636
+ function isApprovalAuthorized(account, operatorId) {
13637
+ if (!operatorId) return false;
13638
+ const allowFrom = account.config?.allowFrom ?? [];
13639
+ if (!allowFrom.length || allowFrom.includes("*")) return true;
13640
+ return allowFrom.includes(operatorId);
13641
+ }
13314
13642
  function buildClawCfg(requireMention, mentionPatterns, groupPolicy) {
13315
13643
  return {
13316
13644
  channel_type: "qqbot",
@@ -13340,13 +13668,13 @@ function createPluginWebhookAdapter(params) {
13340
13668
  let storedPath = "";
13341
13669
  const accountId = params.account.accountId;
13342
13670
  return {
13343
- async listen(_port, path21, handler) {
13671
+ async listen(_port, path22, handler) {
13344
13672
  const ingress = await import("openclaw/plugin-sdk/webhook-ingress").catch(() => null);
13345
13673
  if (!ingress?.registerWebhookTargetWithPluginRoute) {
13346
13674
  params.log.error("Webhook ingress not available");
13347
13675
  return;
13348
13676
  }
13349
- const webhookPath = storedPath = path21 && path21 !== "/" ? path21 : params.account.config.webhook?.path ?? "/qqbot/webhook";
13677
+ const webhookPath = storedPath = path22 && path22 !== "/" ? path22 : params.account.config.webhook?.path ?? "/qqbot/webhook";
13350
13678
  const existing = sharedTargets.get(webhookPath);
13351
13679
  if (existing) {
13352
13680
  const dupIdx = existing.findIndex((t) => t.accountId === accountId);
@@ -13393,12 +13721,12 @@ function createPluginWebhookAdapter(params) {
13393
13721
  }
13394
13722
  };
13395
13723
  }
13396
- function createSharedHandler(path21, log4) {
13724
+ function createSharedHandler(path22, log4) {
13397
13725
  return async (req4, res) => {
13398
13726
  try {
13399
13727
  const ingress = await import("openclaw/plugin-sdk/webhook-ingress").catch(() => null);
13400
13728
  if (!ingress?.withResolvedWebhookRequestPipeline) {
13401
- await handleSimple(req4, res, path21, log4);
13729
+ await handleSimple(req4, res, path22, log4);
13402
13730
  return;
13403
13731
  }
13404
13732
  await ingress.withResolvedWebhookRequestPipeline({
@@ -13439,12 +13767,12 @@ function createSharedHandler(path21, log4) {
13439
13767
  if (payload.op === 13) {
13440
13768
  const t = targets[0];
13441
13769
  if (!t) {
13442
- log4.warn?.(`[webhook] op:13 no target on ${path21}`);
13770
+ log4.warn?.(`[webhook] op:13 no target on ${path22}`);
13443
13771
  res.statusCode = 500;
13444
13772
  res.end(JSON.stringify({ error: "no target" }));
13445
13773
  return;
13446
13774
  }
13447
- const h3 = resolveTargetHandler(path21, t.accountId);
13775
+ const h3 = resolveTargetHandler(path22, t.accountId);
13448
13776
  if (!h3) {
13449
13777
  log4.warn?.(`[webhook] op:13 no handler for ${t.accountId}`);
13450
13778
  res.statusCode = 500;
@@ -13475,10 +13803,10 @@ function createSharedHandler(path21, log4) {
13475
13803
  unauthorizedMessage: JSON.stringify({ error: "invalid signature" })
13476
13804
  });
13477
13805
  if (!matched) {
13478
- log4.warn?.(`[webhook] signature mismatch on ${path21} (${targets.length} target(s))`);
13806
+ log4.warn?.(`[webhook] signature mismatch on ${path22} (${targets.length} target(s))`);
13479
13807
  return;
13480
13808
  }
13481
- const h2 = resolveTargetHandler(path21, matched.accountId);
13809
+ const h2 = resolveTargetHandler(path22, matched.accountId);
13482
13810
  if (!h2) {
13483
13811
  log4.error?.(`[webhook] no handler for matched target ${matched.accountId}`);
13484
13812
  res.statusCode = 500;
@@ -13498,8 +13826,8 @@ function createSharedHandler(path21, log4) {
13498
13826
  }
13499
13827
  };
13500
13828
  }
13501
- function resolveTargetHandler(path21, accountId) {
13502
- return sharedTargets.get(path21)?.find((t) => t.accountId === accountId)?.handler;
13829
+ function resolveTargetHandler(path22, accountId) {
13830
+ return sharedTargets.get(path22)?.find((t) => t.accountId === accountId)?.handler;
13503
13831
  }
13504
13832
  async function delegateToHandler(handler, req4, res, rawBody) {
13505
13833
  const headers = {};
@@ -13513,7 +13841,7 @@ async function delegateToHandler(handler, req4, res, rawBody) {
13513
13841
  }
13514
13842
  res.end(resp.body);
13515
13843
  }
13516
- async function handleSimple(req4, res, path21, log4) {
13844
+ async function handleSimple(req4, res, path22, log4) {
13517
13845
  try {
13518
13846
  const ct = String(req4.headers["content-type"] ?? "");
13519
13847
  if (!ct.includes("application/json")) {
@@ -13534,7 +13862,7 @@ async function handleSimple(req4, res, path21, log4) {
13534
13862
  chunks.push(buf);
13535
13863
  }
13536
13864
  const rawBody = Buffer.concat(chunks);
13537
- const entries = sharedTargets.get(path21) ?? [];
13865
+ const entries = sharedTargets.get(path22) ?? [];
13538
13866
  for (const entry of entries) {
13539
13867
  const resp = await entry.handler({ body: rawBody, headers: mapHeaders(req4) });
13540
13868
  if (resp.status < 400) {
@@ -13565,12 +13893,35 @@ function getHeader2(req4, key) {
13565
13893
  }
13566
13894
 
13567
13895
  // src/gateway/qqbot-gateway.ts
13896
+ var TEXT_TIMEOUT_MS = 3e4;
13897
+ var MEDIA_TIMEOUT_MS = 3e5;
13898
+ function resolveMs(envKey, defaultMs) {
13899
+ const env = process.env[envKey];
13900
+ if (env) {
13901
+ const v = Number(env);
13902
+ if (!Number.isNaN(v) && v > 0) return v;
13903
+ }
13904
+ return defaultMs;
13905
+ }
13906
+ function withTimeout(promise, ms, label) {
13907
+ if (ms <= 0) return promise;
13908
+ return Promise.race([
13909
+ promise,
13910
+ new Promise(
13911
+ (_2, reject) => setTimeout(() => reject(new Error(`\u51FA\u7AD9\u8D85\u65F6: ${label} (${ms}ms)`)), ms)
13912
+ )
13913
+ ]);
13914
+ }
13568
13915
  var QQBotGateway = class {
13569
13916
  bot;
13570
13917
  account;
13571
13918
  runtime;
13572
13919
  log;
13920
+ textTimeout;
13921
+ mediaTimeout;
13573
13922
  constructor(account, runtime2, log4) {
13923
+ this.textTimeout = resolveMs("OPENCLAW_OUTBOUND_TIMEOUT_MS", TEXT_TIMEOUT_MS);
13924
+ this.mediaTimeout = resolveMs("OPENCLAW_OUTBOUND_MEDIA_TIMEOUT_MS", MEDIA_TIMEOUT_MS);
13574
13925
  this.account = account;
13575
13926
  this.runtime = runtime2;
13576
13927
  this.log = log4 ?? createPluginLogger({ prefix: `[qqbot:${account.accountId}]` });
@@ -13635,69 +13986,66 @@ var QQBotGateway = class {
13635
13986
  await this.bot.stop();
13636
13987
  }
13637
13988
  async sendText(target, text, opts) {
13638
- return this.bot.sendText(attachMsgId(target, opts), text);
13989
+ return withTimeout(
13990
+ this.bot.sendText(attachMsgId(target, opts), text),
13991
+ this.textTimeout,
13992
+ "sendText"
13993
+ );
13639
13994
  }
13640
13995
  async sendMedia(target, source, opts) {
13641
13996
  const resolvedTarget = attachMsgId(target, opts);
13642
13997
  const fileType = opts?.fileType ?? MediaFileType.IMAGE;
13643
13998
  const sourceOpts = resolveMediaSource(source);
13644
- const result = await this.bot.sendMedia({
13645
- target: resolvedTarget,
13646
- fileType,
13647
- ...sourceOpts,
13648
- content: opts?.text
13649
- });
13999
+ const result = await withTimeout(
14000
+ this.bot.sendMedia({ target: resolvedTarget, fileType, ...sourceOpts, content: opts?.text }),
14001
+ this.mediaTimeout,
14002
+ "sendMedia"
14003
+ );
13650
14004
  return result.message ?? { id: "", timestamp: Date.now() };
13651
14005
  }
13652
14006
  async sendVoice(target, source, opts) {
13653
14007
  const resolvedTarget = attachMsgId(target, opts);
13654
14008
  if (source.base64) {
13655
- const result2 = await this.bot.sendMedia({
13656
- target: resolvedTarget,
13657
- fileType: MediaFileType.VOICE,
13658
- fileData: source.base64,
13659
- content: opts?.text
13660
- });
14009
+ const result2 = await withTimeout(
14010
+ this.bot.sendMedia({ target: resolvedTarget, fileType: MediaFileType.VOICE, fileData: source.base64, content: opts?.text }),
14011
+ this.mediaTimeout,
14012
+ "sendVoice(base64)"
14013
+ );
13661
14014
  return result2.message ?? { id: "", timestamp: Date.now() };
13662
14015
  }
13663
14016
  if (source.localPath) {
13664
- const result2 = await this.bot.sendMedia({
13665
- target: resolvedTarget,
13666
- fileType: MediaFileType.VOICE,
13667
- localPath: source.localPath,
13668
- content: opts?.text
13669
- });
14017
+ const result2 = await withTimeout(
14018
+ this.bot.sendMedia({ target: resolvedTarget, fileType: MediaFileType.VOICE, localPath: source.localPath, content: opts?.text }),
14019
+ this.mediaTimeout,
14020
+ "sendVoice(path)"
14021
+ );
13670
14022
  return result2.message ?? { id: "", timestamp: Date.now() };
13671
14023
  }
13672
- const result = await this.bot.sendMedia({
13673
- target: resolvedTarget,
13674
- fileType: MediaFileType.VOICE,
13675
- url: source.url,
13676
- content: opts?.text
13677
- });
14024
+ const result = await withTimeout(
14025
+ this.bot.sendMedia({ target: resolvedTarget, fileType: MediaFileType.VOICE, url: source.url, content: opts?.text }),
14026
+ this.mediaTimeout,
14027
+ "sendVoice(url)"
14028
+ );
13678
14029
  return result.message ?? { id: "", timestamp: Date.now() };
13679
14030
  }
13680
14031
  async sendVideo(target, source, opts) {
13681
14032
  const resolvedTarget = attachMsgId(target, opts);
13682
14033
  const sourceOpts = resolveMediaSource(source);
13683
- const result = await this.bot.sendMedia({
13684
- target: resolvedTarget,
13685
- fileType: MediaFileType.VIDEO,
13686
- ...sourceOpts,
13687
- content: opts?.text
13688
- });
14034
+ const result = await withTimeout(
14035
+ this.bot.sendMedia({ target: resolvedTarget, fileType: MediaFileType.VIDEO, ...sourceOpts, content: opts?.text }),
14036
+ this.mediaTimeout,
14037
+ "sendVideo"
14038
+ );
13689
14039
  return result.message ?? { id: "", timestamp: Date.now() };
13690
14040
  }
13691
14041
  async sendFile(target, source, opts) {
13692
14042
  const resolvedTarget = attachMsgId(target, opts);
13693
14043
  const sourceOpts = resolveMediaSource(source);
13694
- const result = await this.bot.sendMedia({
13695
- target: resolvedTarget,
13696
- fileType: MediaFileType.FILE,
13697
- ...sourceOpts,
13698
- fileName: opts?.fileName,
13699
- content: opts?.text
13700
- });
14044
+ const result = await withTimeout(
14045
+ this.bot.sendMedia({ target: resolvedTarget, fileType: MediaFileType.FILE, ...sourceOpts, fileName: opts?.fileName, content: opts?.text }),
14046
+ this.mediaTimeout,
14047
+ "sendFile"
14048
+ );
13701
14049
  return result.message ?? { id: "", timestamp: Date.now() };
13702
14050
  }
13703
14051
  openStream(target, msgId) {
@@ -14064,6 +14412,11 @@ function stripMentionText(text, mentions) {
14064
14412
 
14065
14413
  // src/channel.ts
14066
14414
  var TEXT_CHUNK_LIMIT2 = 5e3;
14415
+ var GFM_TABLE_DATA_RE = /^\|.+\|.*\|/;
14416
+ var GFM_TABLE_SEP_RE = /^\|[\s:-]+\|/;
14417
+ function isGfmTableLine(line) {
14418
+ return GFM_TABLE_DATA_RE.test(line) || GFM_TABLE_SEP_RE.test(line);
14419
+ }
14067
14420
  var qqbotPlugin = {
14068
14421
  id: "qqbot",
14069
14422
  meta: {
@@ -14179,13 +14532,33 @@ var qqbotPlugin = {
14179
14532
  // ── 出站 ──
14180
14533
  outbound: {
14181
14534
  deliveryMode: "direct",
14535
+ sanitizeText: ({ text }) => sanitizeQQBotText(text),
14182
14536
  chunker: (text, limit) => {
14183
14537
  const adapters = getAdapters(getQQBotRuntime());
14184
14538
  if (adapters.chunkMarkdownText) return adapters.chunkMarkdownText(text, limit);
14185
14539
  const lines = text.split("\n");
14186
14540
  const chunks = [];
14187
14541
  let current = "";
14542
+ let tableBuffer = [];
14543
+ const flushTable = () => {
14544
+ if (tableBuffer.length === 0) return;
14545
+ const tableBlock = tableBuffer.join("\n");
14546
+ const candidate = current ? `${current}
14547
+ ${tableBlock}` : tableBlock;
14548
+ if (candidate.length > limit && current) {
14549
+ chunks.push(current);
14550
+ current = tableBlock;
14551
+ } else {
14552
+ current = candidate;
14553
+ }
14554
+ tableBuffer = [];
14555
+ };
14188
14556
  for (const line of lines) {
14557
+ if (isGfmTableLine(line)) {
14558
+ tableBuffer.push(line);
14559
+ continue;
14560
+ }
14561
+ flushTable();
14189
14562
  const candidate = current ? `${current}
14190
14563
  ${line}` : line;
14191
14564
  if (candidate.length > limit && current) {
@@ -14195,6 +14568,7 @@ ${line}` : line;
14195
14568
  current = candidate;
14196
14569
  }
14197
14570
  }
14571
+ flushTable();
14198
14572
  if (current) chunks.push(current);
14199
14573
  return chunks.length > 0 ? chunks : [text];
14200
14574
  },
@@ -14332,10 +14706,10 @@ function json(data) {
14332
14706
  details: data
14333
14707
  };
14334
14708
  }
14335
- function validatePath(path21) {
14336
- if (!path21.startsWith("/")) return "path \u5FC5\u987B\u4EE5 / \u5F00\u5934";
14337
- if (path21.includes("..") || path21.includes("//")) return "path \u4E0D\u5141\u8BB8\u5305\u542B .. \u6216 //";
14338
- if (!/^\/[a-zA-Z0-9\-._~:@!$&'()*+,;=/%]+$/.test(path21) && path21 !== "/") {
14709
+ function validatePath(path22) {
14710
+ if (!path22.startsWith("/")) return "path \u5FC5\u987B\u4EE5 / \u5F00\u5934";
14711
+ if (path22.includes("..") || path22.includes("//")) return "path \u4E0D\u5141\u8BB8\u5305\u542B .. \u6216 //";
14712
+ if (!/^\/[a-zA-Z0-9\-._~:@!$&'()*+,;=/%]+$/.test(path22) && path22 !== "/") {
14339
14713
  return "path \u5305\u542B\u975E\u6CD5\u5B57\u7B26";
14340
14714
  }
14341
14715
  return null;
@@ -14643,7 +15017,7 @@ function verifyRuntimeContract(rt) {
14643
15017
  for (const r of OPTIONAL) {
14644
15018
  if (!r.probe(rt)) degraded.push(r.name);
14645
15019
  }
14646
- log3.info(`openclaw=${version} required=${REQUIRED.length - missing.length}/${REQUIRED.length} degraded=${degraded.length}/${OPTIONAL.length}`);
15020
+ log3.debug(`openclaw=${version} required=${REQUIRED.length - missing.length}/${REQUIRED.length} degraded=${degraded.length}/${OPTIONAL.length}`);
14647
15021
  if (missing.length) {
14648
15022
  log3.error(`BROKEN \u2014 missing: ${missing.join(", ")}`);
14649
15023
  }