@perkos/perkos-a2a 0.8.12 → 0.8.13

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.js CHANGED
@@ -5368,9 +5368,9 @@ var require_read = __commonJS({
5368
5368
  }
5369
5369
  });
5370
5370
 
5371
- // node_modules/type-is/node_modules/media-typer/index.js
5371
+ // node_modules/media-typer/index.js
5372
5372
  var require_media_typer = __commonJS({
5373
- "node_modules/type-is/node_modules/media-typer/index.js"(exports) {
5373
+ "node_modules/media-typer/index.js"(exports) {
5374
5374
  var paramRegExp = /; *([!#$%&'\*\+\-\.0-9A-Z\^_`a-z\|~]+) *= *("(?:[ !\u0023-\u005b\u005d-\u007e\u0080-\u00ff]|\\[\u0020-\u007e])*"|[!#$%&'\*\+\-\.0-9A-Z\^_`a-z\|~]+) */g;
5375
5375
  var textRegExp = /^[\u0020-\u007e\u0080-\u00ff]+$/;
5376
5376
  var tokenRegExp = /^[!#$%&'\*\+\-\.0-9A-Z\^_`a-z\|~]+$/;
@@ -14035,7 +14035,7 @@ var require_mime_types = __commonJS({
14035
14035
  exports.charset = charset;
14036
14036
  exports.charsets = { lookup: charset };
14037
14037
  exports.contentType = contentType;
14038
- exports.extension = extension;
14038
+ exports.extension = extension2;
14039
14039
  exports.extensions = /* @__PURE__ */ Object.create(null);
14040
14040
  exports.lookup = lookup;
14041
14041
  exports.types = /* @__PURE__ */ Object.create(null);
@@ -14068,7 +14068,7 @@ var require_mime_types = __commonJS({
14068
14068
  }
14069
14069
  return mime;
14070
14070
  }
14071
- function extension(type) {
14071
+ function extension2(type) {
14072
14072
  if (!type || typeof type !== "string") {
14073
14073
  return false;
14074
14074
  }
@@ -14083,11 +14083,11 @@ var require_mime_types = __commonJS({
14083
14083
  if (!path || typeof path !== "string") {
14084
14084
  return false;
14085
14085
  }
14086
- var extension2 = extname("x." + path).toLowerCase().substr(1);
14087
- if (!extension2) {
14086
+ var extension3 = extname("x." + path).toLowerCase().substr(1);
14087
+ if (!extension3) {
14088
14088
  return false;
14089
14089
  }
14090
- return exports.types[extension2] || false;
14090
+ return exports.types[extension3] || false;
14091
14091
  }
14092
14092
  function populateMaps(extensions, types) {
14093
14093
  var preference = ["nginx", "apache", void 0, "iana"];
@@ -14099,15 +14099,15 @@ var require_mime_types = __commonJS({
14099
14099
  }
14100
14100
  extensions[type] = exts;
14101
14101
  for (var i = 0; i < exts.length; i++) {
14102
- var extension2 = exts[i];
14103
- if (types[extension2]) {
14104
- var from = preference.indexOf(db[types[extension2]].source);
14102
+ var extension3 = exts[i];
14103
+ if (types[extension3]) {
14104
+ var from = preference.indexOf(db[types[extension3]].source);
14105
14105
  var to = preference.indexOf(mime.source);
14106
- if (types[extension2] !== "application/octet-stream" && (from > to || from === to && types[extension2].substr(0, 12) === "application/")) {
14106
+ if (types[extension3] !== "application/octet-stream" && (from > to || from === to && types[extension3].substr(0, 12) === "application/")) {
14107
14107
  continue;
14108
14108
  }
14109
14109
  }
14110
- types[extension2] = type;
14110
+ types[extension3] = type;
14111
14111
  }
14112
14112
  });
14113
14113
  }
@@ -14305,10 +14305,7 @@ var require_json = __commonJS({
14305
14305
  var index = str.indexOf(char);
14306
14306
  var partial = "";
14307
14307
  if (index !== -1) {
14308
- partial = str.substring(0, index) + JSON_SYNTAX_CHAR;
14309
- for (var i = index + 1; i < str.length; i++) {
14310
- partial += JSON_SYNTAX_CHAR;
14311
- }
14308
+ partial = str.substring(0, index) + new Array(str.length - index + 1).join(JSON_SYNTAX_CHAR);
14312
14309
  }
14313
14310
  try {
14314
14311
  JSON.parse(partial);
@@ -15083,9 +15080,8 @@ var require_side_channel_list = __commonJS({
15083
15080
  }
15084
15081
  },
15085
15082
  "delete": function(key) {
15086
- var root = $o && $o.next;
15087
15083
  var deletedNode = listDelete($o, key);
15088
- if (deletedNode && root && root === deletedNode) {
15084
+ if (deletedNode && $o && !$o.next) {
15089
15085
  $o = void 0;
15090
15086
  }
15091
15087
  return !!deletedNode;
@@ -16196,6 +16192,8 @@ var require_utils = __commonJS({
16196
16192
  var newIndex = getMaxIndex(target) + 1;
16197
16193
  target[newIndex] = source;
16198
16194
  setMaxIndex(target, newIndex);
16195
+ } else if (options && options.strictMerge) {
16196
+ return [target, source];
16199
16197
  } else if (options && (options.plainObjects || options.allowPrototypes) || !has.call(Object.prototype, source)) {
16200
16198
  target[source] = true;
16201
16199
  }
@@ -16699,6 +16697,7 @@ var require_parse = __commonJS({
16699
16697
  parseArrays: true,
16700
16698
  plainObjects: false,
16701
16699
  strictDepth: false,
16700
+ strictMerge: true,
16702
16701
  strictNullHandling: false,
16703
16702
  throwOnLimitExceeded: false
16704
16703
  };
@@ -16725,9 +16724,9 @@ var require_parse = __commonJS({
16725
16724
  var limit = options.parameterLimit === Infinity ? void 0 : options.parameterLimit;
16726
16725
  var parts = cleanStr.split(
16727
16726
  options.delimiter,
16728
- options.throwOnLimitExceeded ? limit + 1 : limit
16727
+ options.throwOnLimitExceeded && typeof limit !== "undefined" ? limit + 1 : limit
16729
16728
  );
16730
- if (options.throwOnLimitExceeded && parts.length > limit) {
16729
+ if (options.throwOnLimitExceeded && typeof limit !== "undefined" && parts.length > limit) {
16731
16730
  throw new RangeError("Parameter limit exceeded. Only " + limit + " parameter" + (limit === 1 ? "" : "s") + " allowed.");
16732
16731
  }
16733
16732
  var skipIndex = -1;
@@ -16787,7 +16786,7 @@ var require_parse = __commonJS({
16787
16786
  }
16788
16787
  if (key !== null) {
16789
16788
  var existing = has.call(obj, key);
16790
- if (existing && options.duplicates === "combine") {
16789
+ if (existing && (options.duplicates === "combine" || part.indexOf("[]=") > -1)) {
16791
16790
  obj[key] = utils.combine(
16792
16791
  obj[key],
16793
16792
  val,
@@ -16944,6 +16943,7 @@ var require_parse = __commonJS({
16944
16943
  parseArrays: opts.parseArrays !== false,
16945
16944
  plainObjects: typeof opts.plainObjects === "boolean" ? opts.plainObjects : defaults.plainObjects,
16946
16945
  strictDepth: typeof opts.strictDepth === "boolean" ? !!opts.strictDepth : defaults.strictDepth,
16946
+ strictMerge: typeof opts.strictMerge === "boolean" ? !!opts.strictMerge : defaults.strictMerge,
16947
16947
  strictNullHandling: typeof opts.strictNullHandling === "boolean" ? opts.strictNullHandling : defaults.strictNullHandling,
16948
16948
  throwOnLimitExceeded: typeof opts.throwOnLimitExceeded === "boolean" ? opts.throwOnLimitExceeded : false
16949
16949
  };
@@ -17102,14 +17102,14 @@ var require_urlencoded = __commonJS({
17102
17102
  }
17103
17103
  function parameterCount(body, limit) {
17104
17104
  var count = 0;
17105
- var index = 0;
17106
- while ((index = body.indexOf("&", index)) !== -1) {
17105
+ var index = -1;
17106
+ do {
17107
17107
  count++;
17108
- index++;
17109
- if (count === limit) {
17108
+ if (count > limit) {
17110
17109
  return void 0;
17111
17110
  }
17112
- }
17111
+ index = body.indexOf("&", index + 1);
17112
+ } while (index !== -1);
17113
17113
  return count;
17114
17114
  }
17115
17115
  function parser(name) {
@@ -17431,7 +17431,7 @@ var require_finalhandler = __commonJS({
17431
17431
  module.exports = finalhandler;
17432
17432
  function finalhandler(req, res, options) {
17433
17433
  var opts = options || {};
17434
- var env = opts.env || process.env.NODE_ENV || "development";
17434
+ var env2 = opts.env || process.env.NODE_ENV || "development";
17435
17435
  var onerror = opts.onerror;
17436
17436
  return function(err) {
17437
17437
  var headers;
@@ -17448,7 +17448,7 @@ var require_finalhandler = __commonJS({
17448
17448
  } else {
17449
17449
  headers = getErrorHeaders(err);
17450
17450
  }
17451
- msg = getErrorMessage(err, status, env);
17451
+ msg = getErrorMessage(err, status, env2);
17452
17452
  } else {
17453
17453
  status = 404;
17454
17454
  msg = "Cannot " + req.method + " " + encodeUrl(getResourceName(req));
@@ -17479,9 +17479,9 @@ var require_finalhandler = __commonJS({
17479
17479
  }
17480
17480
  return headers;
17481
17481
  }
17482
- function getErrorMessage(err, status, env) {
17482
+ function getErrorMessage(err, status, env2) {
17483
17483
  var msg;
17484
- if (env !== "production") {
17484
+ if (env2 !== "production") {
17485
17485
  msg = err.stack;
17486
17486
  if (!msg && typeof err.toString === "function") {
17487
17487
  msg = err.toString();
@@ -17653,6 +17653,7 @@ var require_path_to_regexp = __commonJS({
17653
17653
  }
17654
17654
  pos = offset + match.length;
17655
17655
  if (match === "*") {
17656
+ backtrack = "";
17656
17657
  extraOffset += 3;
17657
17658
  return "(.*)";
17658
17659
  }
@@ -17673,6 +17674,7 @@ var require_path_to_regexp = __commonJS({
17673
17674
  offset: offset + extraOffset
17674
17675
  });
17675
17676
  var result = "(?:" + format + slash + capture + (star ? "((?:[/" + format + "].+?)?)" : "") + ")" + optional;
17677
+ backtrack = "";
17676
17678
  extraOffset += result.length - match.length;
17677
17679
  return result;
17678
17680
  }
@@ -19662,9 +19664,9 @@ var require_forwarded = __commonJS({
19662
19664
  }
19663
19665
  });
19664
19666
 
19665
- // node_modules/proxy-addr/node_modules/ipaddr.js/lib/ipaddr.js
19667
+ // node_modules/ipaddr.js/lib/ipaddr.js
19666
19668
  var require_ipaddr = __commonJS({
19667
- "node_modules/proxy-addr/node_modules/ipaddr.js/lib/ipaddr.js"(exports, module) {
19669
+ "node_modules/ipaddr.js/lib/ipaddr.js"(exports, module) {
19668
19670
  (function() {
19669
19671
  var expandIPv6, ipaddr, ipv4Part, ipv4Regexes, ipv6Part, ipv6Regexes, matchCIDR, root, zoneIndex;
19670
19672
  ipaddr = {};
@@ -20571,7 +20573,8 @@ var require_utils2 = __commonJS({
20571
20573
  }
20572
20574
  function parseExtendedQueryString(str) {
20573
20575
  return qs.parse(str, {
20574
- allowPrototypes: true
20576
+ allowPrototypes: true,
20577
+ arrayLimit: 1e3
20575
20578
  });
20576
20579
  }
20577
20580
  function newObject() {
@@ -20611,10 +20614,10 @@ var require_application = __commonJS({
20611
20614
  this.defaultConfiguration();
20612
20615
  };
20613
20616
  app.defaultConfiguration = function defaultConfiguration() {
20614
- var env = process.env.NODE_ENV || "development";
20617
+ var env2 = process.env.NODE_ENV || "development";
20615
20618
  this.enable("x-powered-by");
20616
20619
  this.set("etag", "weak");
20617
- this.set("env", env);
20620
+ this.set("env", env2);
20618
20621
  this.set("query parser", "extended");
20619
20622
  this.set("subdomain offset", 2);
20620
20623
  this.set("trust proxy", false);
@@ -20622,7 +20625,7 @@ var require_application = __commonJS({
20622
20625
  configurable: true,
20623
20626
  value: true
20624
20627
  });
20625
- debug("booting in %s mode", env);
20628
+ debug("booting in %s mode", env2);
20626
20629
  this.on("mount", function onmount(parent) {
20627
20630
  if (this.settings[trustProxyDefaultSymbol] === true && typeof parent.settings["trust proxy fn"] === "function") {
20628
20631
  delete this.settings["trust proxy"];
@@ -20639,7 +20642,7 @@ var require_application = __commonJS({
20639
20642
  this.set("view", View);
20640
20643
  this.set("views", resolve("views"));
20641
20644
  this.set("jsonp callback name", "callback");
20642
- if (env === "production") {
20645
+ if (env2 === "production") {
20643
20646
  this.enable("view cache");
20644
20647
  }
20645
20648
  Object.defineProperty(this, "router", {
@@ -20717,8 +20720,8 @@ var require_application = __commonJS({
20717
20720
  if (typeof fn !== "function") {
20718
20721
  throw new Error("callback function required");
20719
20722
  }
20720
- var extension = ext[0] !== "." ? "." + ext : ext;
20721
- this.engines[extension] = fn;
20723
+ var extension2 = ext[0] !== "." ? "." + ext : ext;
20724
+ this.engines[extension2] = fn;
20722
20725
  return this;
20723
20726
  };
20724
20727
  app.param = function param(name, fn) {
@@ -22746,7 +22749,7 @@ var require_permessage_deflate = __commonJS({
22746
22749
  var kBuffers = /* @__PURE__ */ Symbol("buffers");
22747
22750
  var kError = /* @__PURE__ */ Symbol("error");
22748
22751
  var zlibLimiter;
22749
- var PerMessageDeflate = class {
22752
+ var PerMessageDeflate2 = class {
22750
22753
  /**
22751
22754
  * Creates a PerMessageDeflate instance.
22752
22755
  *
@@ -22757,6 +22760,9 @@ var require_permessage_deflate = __commonJS({
22757
22760
  * acknowledge disabling of client context takeover
22758
22761
  * @param {Number} [options.concurrencyLimit=10] The number of concurrent
22759
22762
  * calls to zlib
22763
+ * @param {Boolean} [options.isServer=false] Create the instance in either
22764
+ * server or client mode
22765
+ * @param {Number} [options.maxPayload=0] The maximum allowed message length
22760
22766
  * @param {(Boolean|Number)} [options.serverMaxWindowBits] Request/confirm the
22761
22767
  * use of a custom server window size
22762
22768
  * @param {Boolean} [options.serverNoContextTakeover=false] Request/accept
@@ -22767,15 +22773,12 @@ var require_permessage_deflate = __commonJS({
22767
22773
  * deflate
22768
22774
  * @param {Object} [options.zlibInflateOptions] Options to pass to zlib on
22769
22775
  * inflate
22770
- * @param {Boolean} [isServer=false] Create the instance in either server or
22771
- * client mode
22772
- * @param {Number} [maxPayload=0] The maximum allowed message length
22773
22776
  */
22774
- constructor(options, isServer, maxPayload) {
22775
- this._maxPayload = maxPayload | 0;
22777
+ constructor(options) {
22776
22778
  this._options = options || {};
22777
22779
  this._threshold = this._options.threshold !== void 0 ? this._options.threshold : 1024;
22778
- this._isServer = !!isServer;
22780
+ this._maxPayload = this._options.maxPayload | 0;
22781
+ this._isServer = !!this._options.isServer;
22779
22782
  this._deflate = null;
22780
22783
  this._inflate = null;
22781
22784
  this.params = null;
@@ -23084,7 +23087,7 @@ var require_permessage_deflate = __commonJS({
23084
23087
  });
23085
23088
  }
23086
23089
  };
23087
- module.exports = PerMessageDeflate;
23090
+ module.exports = PerMessageDeflate2;
23088
23091
  function deflateOnData(chunk) {
23089
23092
  this[kBuffers].push(chunk);
23090
23093
  this[kTotalLength] += chunk.length;
@@ -23319,7 +23322,7 @@ var require_receiver = __commonJS({
23319
23322
  "node_modules/ws/lib/receiver.js"(exports, module) {
23320
23323
  "use strict";
23321
23324
  var { Writable } = __require("stream");
23322
- var PerMessageDeflate = require_permessage_deflate();
23325
+ var PerMessageDeflate2 = require_permessage_deflate();
23323
23326
  var {
23324
23327
  BINARY_TYPES,
23325
23328
  EMPTY_BUFFER,
@@ -23486,7 +23489,7 @@ var require_receiver = __commonJS({
23486
23489
  return;
23487
23490
  }
23488
23491
  const compressed = (buf[0] & 64) === 64;
23489
- if (compressed && !this._extensions[PerMessageDeflate.extensionName]) {
23492
+ if (compressed && !this._extensions[PerMessageDeflate2.extensionName]) {
23490
23493
  const error = this.createError(
23491
23494
  RangeError,
23492
23495
  "RSV1 must be clear",
@@ -23730,7 +23733,7 @@ var require_receiver = __commonJS({
23730
23733
  * @private
23731
23734
  */
23732
23735
  decompress(data, cb) {
23733
- const perMessageDeflate = this._extensions[PerMessageDeflate.extensionName];
23736
+ const perMessageDeflate = this._extensions[PerMessageDeflate2.extensionName];
23734
23737
  perMessageDeflate.decompress(data, this._fin, (err, buf) => {
23735
23738
  if (err) return cb(err);
23736
23739
  if (buf.length) {
@@ -23912,7 +23915,10 @@ var require_sender = __commonJS({
23912
23915
  "use strict";
23913
23916
  var { Duplex } = __require("stream");
23914
23917
  var { randomFillSync } = __require("crypto");
23915
- var PerMessageDeflate = require_permessage_deflate();
23918
+ var {
23919
+ types: { isUint8Array }
23920
+ } = __require("util");
23921
+ var PerMessageDeflate2 = require_permessage_deflate();
23916
23922
  var { EMPTY_BUFFER, kWebSocket, NOOP } = require_constants();
23917
23923
  var { isBlob, isValidStatusCode } = require_validation();
23918
23924
  var { mask: applyMask, toBuffer } = require_buffer_util();
@@ -24065,8 +24071,10 @@ var require_sender = __commonJS({
24065
24071
  buf.writeUInt16BE(code, 0);
24066
24072
  if (typeof data === "string") {
24067
24073
  buf.write(data, 2);
24068
- } else {
24074
+ } else if (isUint8Array(data)) {
24069
24075
  buf.set(data, 2);
24076
+ } else {
24077
+ throw new TypeError("Second argument must be a string or a Uint8Array");
24070
24078
  }
24071
24079
  }
24072
24080
  const options = {
@@ -24196,7 +24204,7 @@ var require_sender = __commonJS({
24196
24204
  * @public
24197
24205
  */
24198
24206
  send(data, options, cb) {
24199
- const perMessageDeflate = this._extensions[PerMessageDeflate.extensionName];
24207
+ const perMessageDeflate = this._extensions[PerMessageDeflate2.extensionName];
24200
24208
  let opcode = options.binary ? 2 : 1;
24201
24209
  let rsv1 = options.compress;
24202
24210
  let byteLength;
@@ -24320,7 +24328,7 @@ var require_sender = __commonJS({
24320
24328
  this.sendFrame(_Sender.frame(data, options), cb);
24321
24329
  return;
24322
24330
  }
24323
- const perMessageDeflate = this._extensions[PerMessageDeflate.extensionName];
24331
+ const perMessageDeflate = this._extensions[PerMessageDeflate2.extensionName];
24324
24332
  this._bufferedBytes += options[kByteLength];
24325
24333
  this._state = DEFLATING;
24326
24334
  perMessageDeflate.compress(data, options.fin, (_, buf) => {
@@ -24758,11 +24766,11 @@ var require_extension = __commonJS({
24758
24766
  return offers;
24759
24767
  }
24760
24768
  function format(extensions) {
24761
- return Object.keys(extensions).map((extension) => {
24762
- let configurations = extensions[extension];
24769
+ return Object.keys(extensions).map((extension2) => {
24770
+ let configurations = extensions[extension2];
24763
24771
  if (!Array.isArray(configurations)) configurations = [configurations];
24764
24772
  return configurations.map((params) => {
24765
- return [extension].concat(
24773
+ return [extension2].concat(
24766
24774
  Object.keys(params).map((k) => {
24767
24775
  let values = params[k];
24768
24776
  if (!Array.isArray(values)) values = [values];
@@ -24788,7 +24796,7 @@ var require_websocket = __commonJS({
24788
24796
  var { randomBytes, createHash } = __require("crypto");
24789
24797
  var { Duplex, Readable } = __require("stream");
24790
24798
  var { URL } = __require("url");
24791
- var PerMessageDeflate = require_permessage_deflate();
24799
+ var PerMessageDeflate2 = require_permessage_deflate();
24792
24800
  var Receiver2 = require_receiver();
24793
24801
  var Sender2 = require_sender();
24794
24802
  var { isBlob } = require_validation();
@@ -24996,8 +25004,8 @@ var require_websocket = __commonJS({
24996
25004
  this.emit("close", this._closeCode, this._closeMessage);
24997
25005
  return;
24998
25006
  }
24999
- if (this._extensions[PerMessageDeflate.extensionName]) {
25000
- this._extensions[PerMessageDeflate.extensionName].cleanup();
25007
+ if (this._extensions[PerMessageDeflate2.extensionName]) {
25008
+ this._extensions[PerMessageDeflate2.extensionName].cleanup();
25001
25009
  }
25002
25010
  this._receiver.removeAllListeners();
25003
25011
  this._readyState = _WebSocket.CLOSED;
@@ -25159,7 +25167,7 @@ var require_websocket = __commonJS({
25159
25167
  fin: true,
25160
25168
  ...options
25161
25169
  };
25162
- if (!this._extensions[PerMessageDeflate.extensionName]) {
25170
+ if (!this._extensions[PerMessageDeflate2.extensionName]) {
25163
25171
  opts.compress = false;
25164
25172
  }
25165
25173
  this._sender.send(data || EMPTY_BUFFER, opts, cb);
@@ -25285,7 +25293,7 @@ var require_websocket = __commonJS({
25285
25293
  } else {
25286
25294
  try {
25287
25295
  parsedUrl = new URL(address);
25288
- } catch (e) {
25296
+ } catch {
25289
25297
  throw new SyntaxError(`Invalid URL: ${address}`);
25290
25298
  }
25291
25299
  }
@@ -25333,13 +25341,13 @@ var require_websocket = __commonJS({
25333
25341
  opts.path = parsedUrl.pathname + parsedUrl.search;
25334
25342
  opts.timeout = opts.handshakeTimeout;
25335
25343
  if (opts.perMessageDeflate) {
25336
- perMessageDeflate = new PerMessageDeflate(
25337
- opts.perMessageDeflate !== true ? opts.perMessageDeflate : {},
25338
- false,
25339
- opts.maxPayload
25340
- );
25344
+ perMessageDeflate = new PerMessageDeflate2({
25345
+ ...opts.perMessageDeflate,
25346
+ isServer: false,
25347
+ maxPayload: opts.maxPayload
25348
+ });
25341
25349
  opts.headers["Sec-WebSocket-Extensions"] = format({
25342
- [PerMessageDeflate.extensionName]: perMessageDeflate.offer()
25350
+ [PerMessageDeflate2.extensionName]: perMessageDeflate.offer()
25343
25351
  });
25344
25352
  }
25345
25353
  if (protocols.length) {
@@ -25482,19 +25490,19 @@ var require_websocket = __commonJS({
25482
25490
  return;
25483
25491
  }
25484
25492
  const extensionNames = Object.keys(extensions);
25485
- if (extensionNames.length !== 1 || extensionNames[0] !== PerMessageDeflate.extensionName) {
25493
+ if (extensionNames.length !== 1 || extensionNames[0] !== PerMessageDeflate2.extensionName) {
25486
25494
  const message = "Server indicated an extension that was not requested";
25487
25495
  abortHandshake(websocket, socket, message);
25488
25496
  return;
25489
25497
  }
25490
25498
  try {
25491
- perMessageDeflate.accept(extensions[PerMessageDeflate.extensionName]);
25499
+ perMessageDeflate.accept(extensions[PerMessageDeflate2.extensionName]);
25492
25500
  } catch (err) {
25493
25501
  const message = "Invalid Sec-WebSocket-Extensions header";
25494
25502
  abortHandshake(websocket, socket, message);
25495
25503
  return;
25496
25504
  }
25497
- websocket._extensions[PerMessageDeflate.extensionName] = perMessageDeflate;
25505
+ websocket._extensions[PerMessageDeflate2.extensionName] = perMessageDeflate;
25498
25506
  }
25499
25507
  websocket.setSocket(socket, head, {
25500
25508
  allowSynchronousEvents: opts.allowSynchronousEvents,
@@ -25813,9 +25821,9 @@ var require_websocket_server = __commonJS({
25813
25821
  var http = __require("http");
25814
25822
  var { Duplex } = __require("stream");
25815
25823
  var { createHash } = __require("crypto");
25816
- var extension = require_extension();
25817
- var PerMessageDeflate = require_permessage_deflate();
25818
- var subprotocol = require_subprotocol();
25824
+ var extension2 = require_extension();
25825
+ var PerMessageDeflate2 = require_permessage_deflate();
25826
+ var subprotocol2 = require_subprotocol();
25819
25827
  var WebSocket2 = require_websocket();
25820
25828
  var { CLOSE_TIMEOUT, GUID, kWebSocket } = require_constants();
25821
25829
  var keyRegex = /^[+/0-9A-Za-z]{22}==$/;
@@ -26038,7 +26046,7 @@ var require_websocket_server = __commonJS({
26038
26046
  let protocols = /* @__PURE__ */ new Set();
26039
26047
  if (secWebSocketProtocol !== void 0) {
26040
26048
  try {
26041
- protocols = subprotocol.parse(secWebSocketProtocol);
26049
+ protocols = subprotocol2.parse(secWebSocketProtocol);
26042
26050
  } catch (err) {
26043
26051
  const message = "Invalid Sec-WebSocket-Protocol header";
26044
26052
  abortHandshakeOrEmitwsClientError(this, req, socket, 400, message);
@@ -26048,16 +26056,16 @@ var require_websocket_server = __commonJS({
26048
26056
  const secWebSocketExtensions = req.headers["sec-websocket-extensions"];
26049
26057
  const extensions = {};
26050
26058
  if (this.options.perMessageDeflate && secWebSocketExtensions !== void 0) {
26051
- const perMessageDeflate = new PerMessageDeflate(
26052
- this.options.perMessageDeflate,
26053
- true,
26054
- this.options.maxPayload
26055
- );
26059
+ const perMessageDeflate = new PerMessageDeflate2({
26060
+ ...this.options.perMessageDeflate,
26061
+ isServer: true,
26062
+ maxPayload: this.options.maxPayload
26063
+ });
26056
26064
  try {
26057
- const offers = extension.parse(secWebSocketExtensions);
26058
- if (offers[PerMessageDeflate.extensionName]) {
26059
- perMessageDeflate.accept(offers[PerMessageDeflate.extensionName]);
26060
- extensions[PerMessageDeflate.extensionName] = perMessageDeflate;
26065
+ const offers = extension2.parse(secWebSocketExtensions);
26066
+ if (offers[PerMessageDeflate2.extensionName]) {
26067
+ perMessageDeflate.accept(offers[PerMessageDeflate2.extensionName]);
26068
+ extensions[PerMessageDeflate2.extensionName] = perMessageDeflate;
26061
26069
  }
26062
26070
  } catch (err) {
26063
26071
  const message = "Invalid or unacceptable Sec-WebSocket-Extensions header";
@@ -26128,10 +26136,10 @@ var require_websocket_server = __commonJS({
26128
26136
  ws._protocol = protocol;
26129
26137
  }
26130
26138
  }
26131
- if (extensions[PerMessageDeflate.extensionName]) {
26132
- const params = extensions[PerMessageDeflate.extensionName].params;
26133
- const value = extension.format({
26134
- [PerMessageDeflate.extensionName]: [params]
26139
+ if (extensions[PerMessageDeflate2.extensionName]) {
26140
+ const params = extensions[PerMessageDeflate2.extensionName].params;
26141
+ const value = extension2.format({
26142
+ [PerMessageDeflate2.extensionName]: [params]
26135
26143
  });
26136
26144
  headers.push(`Sec-WebSocket-Extensions: ${value}`);
26137
26145
  ws._extensions = extensions;
@@ -26200,13 +26208,16 @@ var require_websocket_server = __commonJS({
26200
26208
 
26201
26209
  // src/server.ts
26202
26210
  var import_express = __toESM(require_express2(), 1);
26203
- import { randomUUID as randomUUID3 } from "crypto";
26211
+ import { randomUUID as randomUUID4 } from "crypto";
26204
26212
  import { homedir, networkInterfaces } from "os";
26205
26213
 
26206
26214
  // node_modules/ws/wrapper.mjs
26207
26215
  var import_stream = __toESM(require_stream(), 1);
26216
+ var import_extension = __toESM(require_extension(), 1);
26217
+ var import_permessage_deflate = __toESM(require_permessage_deflate(), 1);
26208
26218
  var import_receiver = __toESM(require_receiver(), 1);
26209
26219
  var import_sender = __toESM(require_sender(), 1);
26220
+ var import_subprotocol = __toESM(require_subprotocol(), 1);
26210
26221
  var import_websocket = __toESM(require_websocket(), 1);
26211
26222
  var import_websocket_server = __toESM(require_websocket_server(), 1);
26212
26223
  var wrapper_default = import_websocket.default;
@@ -26255,7 +26266,7 @@ var RelayClient = class {
26255
26266
  from: this.options.agentName,
26256
26267
  payload,
26257
26268
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
26258
- }, "task_response", 3e4);
26269
+ }, "task_response", Number(process.env.A2A_RELAY_RESPONSE_WAIT_MS || 6e4));
26259
26270
  }
26260
26271
  /** Discover agents connected to the relay */
26261
26272
  async discover() {
@@ -26424,6 +26435,7 @@ import { randomUUID as randomUUID2 } from "crypto";
26424
26435
  var DEFAULT_CONFIG = {
26425
26436
  port: 6060,
26426
26437
  apiKeys: [],
26438
+ registeredAgents: {},
26427
26439
  maxQueuePerAgent: 200,
26428
26440
  rateLimitPerMinute: 60,
26429
26441
  heartbeatIntervalMs: 3e4,
@@ -26531,7 +26543,14 @@ var RelayHub = class {
26531
26543
  this.sendError(ws, "missing_name", "agentName is required for registration");
26532
26544
  return null;
26533
26545
  }
26534
- if (this.config.apiKeys.length > 0 && !this.config.apiKeys.includes(apiKey)) {
26546
+ const approvedKey = this.config.registeredAgents[name];
26547
+ if (Object.keys(this.config.registeredAgents).length > 0) {
26548
+ if (!approvedKey || approvedKey !== apiKey) {
26549
+ this.sendError(ws, "not_approved", "Agent is not approved for this relay or API key does not match");
26550
+ ws.close(4001, "Agent not approved");
26551
+ return null;
26552
+ }
26553
+ } else if (this.config.apiKeys.length > 0 && !this.config.apiKeys.includes(apiKey)) {
26535
26554
  this.sendError(ws, "auth_failed", "Invalid API key");
26536
26555
  ws.close(4001, "Authentication failed");
26537
26556
  return null;
@@ -26569,6 +26588,10 @@ var RelayHub = class {
26569
26588
  }
26570
26589
  msg.from = fromAgent;
26571
26590
  msg.timestamp = (/* @__PURE__ */ new Date()).toISOString();
26591
+ if (Object.keys(this.config.registeredAgents).length > 0 && !(target in this.config.registeredAgents)) {
26592
+ this.sendError(this.agents.get(fromAgent).ws, "target_not_approved", `Target agent ${target} is not approved on this relay`);
26593
+ return;
26594
+ }
26572
26595
  const targetAgent = this.agents.get(target);
26573
26596
  if (targetAgent && targetAgent.ws.readyState === import_websocket.default.OPEN) {
26574
26597
  targetAgent.ws.send(JSON.stringify(msg));
@@ -26664,11 +26687,114 @@ var RelayHub = class {
26664
26687
  }
26665
26688
  };
26666
26689
 
26690
+ // src/runtime-reply.ts
26691
+ import { randomUUID as randomUUID3 } from "crypto";
26692
+ function env(name) {
26693
+ const value = process.env[name];
26694
+ return value && value.trim() ? value.trim() : void 0;
26695
+ }
26696
+ function stripTaskMarker(text, marker) {
26697
+ const trimmed = text.trim();
26698
+ if (!trimmed.includes(marker)) return trimmed;
26699
+ return trimmed.slice(trimmed.indexOf(marker) + marker.length).trim();
26700
+ }
26701
+ function agentIdFor(config) {
26702
+ return env("A2A_AGENT_ID") || env("HERMES_AGENT_ID") || config.agentName || "perkos-a2a-agent";
26703
+ }
26704
+ function llmSystemPrompt(config) {
26705
+ const agentName = config.agentName || config.runtime?.kind || "PerkOS A2A agent";
26706
+ return [
26707
+ `You are ${agentName}, a PerkOS A2A agent.`,
26708
+ "Reply concisely and directly.",
26709
+ "If asked to confirm receipt, confirm that you received the task via PerkOS A2A and are using PerkOS LLM.",
26710
+ "Do not mention implementation details unless asked."
26711
+ ].join(" ");
26712
+ }
26713
+ async function generateRuntimeReply(config, text, marker) {
26714
+ const runtimeKind = config.runtime?.kind || "openclaw";
26715
+ const apiKey = env("PERKOS_LLM_API_KEY") || env("OPENAI_API_KEY") || env("OLLAMA_API_KEY");
26716
+ if (!apiKey) {
26717
+ throw new Error("No PerkOS LLM API key available in environment");
26718
+ }
26719
+ const headers = {
26720
+ "content-type": "application/json",
26721
+ authorization: `Bearer ${apiKey}`,
26722
+ "x-agent-id": agentIdFor(config)
26723
+ };
26724
+ const system = llmSystemPrompt(config);
26725
+ const user = [
26726
+ text,
26727
+ "",
26728
+ "Return only the useful final answer.",
26729
+ `Do not include ${marker}; the A2A bridge will attach the marker/task result.`
26730
+ ].join("\n");
26731
+ if (runtimeKind === "hermes") {
26732
+ const base2 = (env("OPENAI_BASE_URL") || "https://api.llm.perkos.xyz/v1").replace(/\/+$/, "");
26733
+ const model2 = env("HERMES_INFERENCE_MODEL") || env("OPENAI_MODEL") || "kimi-k2.6:cloud";
26734
+ const response2 = await fetch(`${base2}/chat/completions`, {
26735
+ method: "POST",
26736
+ headers,
26737
+ body: JSON.stringify({
26738
+ model: model2,
26739
+ messages: [
26740
+ { role: "system", content: system },
26741
+ { role: "user", content: user }
26742
+ ],
26743
+ temperature: 0.2
26744
+ })
26745
+ });
26746
+ if (!response2.ok) {
26747
+ const body = await response2.text().catch(() => "");
26748
+ throw new Error(`PerkOS LLM OpenAI-compatible call failed (${response2.status}): ${body || response2.statusText}`);
26749
+ }
26750
+ const data2 = await response2.json();
26751
+ return stripTaskMarker(data2.choices?.[0]?.message?.content || "Task completed.", marker);
26752
+ }
26753
+ const base = (env("OLLAMA_BASE_URL") || "https://api.llm.perkos.xyz").replace(/\/+$/, "");
26754
+ const model = env("OLLAMA_MODEL") || "kimi-k2.6:cloud";
26755
+ const response = await fetch(`${base}/api/chat`, {
26756
+ method: "POST",
26757
+ headers,
26758
+ body: JSON.stringify({
26759
+ model,
26760
+ stream: false,
26761
+ messages: [
26762
+ { role: "system", content: system },
26763
+ { role: "user", content: user }
26764
+ ]
26765
+ })
26766
+ });
26767
+ if (!response.ok) {
26768
+ const body = await response.text().catch(() => "");
26769
+ throw new Error(`PerkOS LLM Ollama-compatible call failed (${response.status}): ${body || response.statusText}`);
26770
+ }
26771
+ const data = await response.json();
26772
+ return stripTaskMarker(data.message?.content || data.response || "Task completed.", marker);
26773
+ }
26774
+ function completeTaskWithReply(task, finalText) {
26775
+ task.artifacts.push({
26776
+ kind: "artifact",
26777
+ artifactId: randomUUID3(),
26778
+ parts: [{ kind: "text", text: finalText }]
26779
+ });
26780
+ task.status = {
26781
+ state: "completed",
26782
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
26783
+ message: {
26784
+ role: "agent",
26785
+ parts: [{ kind: "text", text: finalText }]
26786
+ }
26787
+ };
26788
+ }
26789
+ function isTerminalTaskState(state) {
26790
+ return state === "completed" || state === "failed" || state === "canceled";
26791
+ }
26792
+
26667
26793
  // src/server.ts
26668
26794
  function appendArtifact(task, text) {
26669
26795
  task.artifacts.push({
26670
26796
  kind: "artifact",
26671
- artifactId: randomUUID3(),
26797
+ artifactId: randomUUID4(),
26672
26798
  parts: [{ kind: "text", text }]
26673
26799
  });
26674
26800
  }
@@ -26718,7 +26844,7 @@ var A2AServer = class {
26718
26844
  description: `PerkOS agent: ${config.agentName}`,
26719
26845
  protocolVersion: "0.3.0",
26720
26846
  version: "1.0.0",
26721
- url: `http://localhost:${config.port}/a2a/jsonrpc`,
26847
+ url: `${(config.publicUrl || `http://localhost:${config.port}`).replace(/\/+$/, "")}/a2a/jsonrpc`,
26722
26848
  skills: config.skills || [],
26723
26849
  capabilities: { pushNotifications: false },
26724
26850
  defaultInputModes: ["text"],
@@ -26822,9 +26948,8 @@ var A2AServer = class {
26822
26948
  }
26823
26949
  async handleSendMessage(params, rpcId) {
26824
26950
  const message = params.message;
26825
- const taskId = randomUUID3();
26826
- const contextId = message?.contextId || randomUUID3();
26827
- const meta = message?.metadata || {};
26951
+ const taskId = randomUUID4();
26952
+ const contextId = message?.contextId || randomUUID4();
26828
26953
  const task = {
26829
26954
  kind: "task",
26830
26955
  id: taskId,
@@ -26833,10 +26958,7 @@ var A2AServer = class {
26833
26958
  messages: [message],
26834
26959
  artifacts: [],
26835
26960
  metadata: {
26836
- fromAgent: meta.fromAgent || "unknown",
26837
- replyToTaskId: meta.replyToTaskId,
26838
- conversationId: meta.conversationId || contextId,
26839
- kind: meta.kind || "request"
26961
+ fromAgent: message?.metadata?.fromAgent || "unknown"
26840
26962
  },
26841
26963
  sessionKeyHint: "agent:main"
26842
26964
  };
@@ -26852,33 +26974,11 @@ var A2AServer = class {
26852
26974
  this.tasks.set(task.id, structuredClone(task));
26853
26975
  const textParts = task.messages.flatMap((m) => m.parts || []).filter((p) => p.kind === "text").map((p) => p.text).join("\n");
26854
26976
  try {
26855
- if (task.metadata?.kind === "response" && task.metadata?.replyToTaskId) {
26856
- const original = this.tasks.get(String(task.metadata.replyToTaskId));
26857
- if (original) {
26858
- appendArtifact(original, textParts || "(empty response)");
26859
- original.status = {
26860
- state: "completed",
26861
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
26862
- message: {
26863
- role: "agent",
26864
- parts: [{ kind: "text", text: textParts || "(empty response)" }]
26865
- }
26866
- };
26867
- this.tasks.set(original.id, structuredClone(original));
26868
- appendArtifact(task, `Response linked to original task ${original.id}`);
26869
- task.status = { state: "completed", timestamp: (/* @__PURE__ */ new Date()).toISOString() };
26870
- this.tasks.set(task.id, structuredClone(task));
26871
- this.logger.info(`[perkos-a2a] Response task ${task.id} linked to original task ${original.id}`);
26872
- return;
26873
- }
26874
- }
26875
26977
  if (this.messageInjector) {
26876
26978
  this.messageInjector(textParts, {
26877
26979
  source: "a2a",
26878
26980
  fromAgent: task.metadata?.fromAgent,
26879
- taskId: task.id,
26880
- conversationId: task.metadata?.conversationId,
26881
- kind: task.metadata?.kind
26981
+ taskId: task.id
26882
26982
  });
26883
26983
  appendArtifact(task, "Task accepted and dispatched for execution");
26884
26984
  this.tasks.set(task.id, structuredClone(task));
@@ -26954,11 +27054,11 @@ var A2AServer = class {
26954
27054
  return this.success(rpcId, task);
26955
27055
  }
26956
27056
  /** Send a task to a peer agent via A2A protocol (direct HTTP or relay) */
26957
- async sendTask(targetAgent, messageText, metadata) {
27057
+ async sendTask(targetAgent, messageText) {
26958
27058
  const targetUrl = this.config.peers[targetAgent];
26959
27059
  if (targetUrl) {
26960
27060
  try {
26961
- return await this.sendTaskDirect(targetAgent, targetUrl, messageText, metadata);
27061
+ return await this.sendTaskDirect(targetAgent, targetUrl, messageText);
26962
27062
  } catch (err) {
26963
27063
  if (!this.relayClient?.isConnected()) {
26964
27064
  throw err;
@@ -26969,13 +27069,13 @@ var A2AServer = class {
26969
27069
  }
26970
27070
  }
26971
27071
  if (this.relayClient?.isConnected()) {
26972
- return this.sendTaskViaRelay(targetAgent, messageText, metadata);
27072
+ return this.sendTaskViaRelay(targetAgent, messageText);
26973
27073
  }
26974
27074
  throw new Error(
26975
27075
  `Cannot reach ${targetAgent}: no direct URL configured and relay not connected. Known peers: ${Object.keys(this.config.peers).join(", ")}`
26976
27076
  );
26977
27077
  }
26978
- async sendTaskDirect(targetAgent, targetUrl, messageText, metadata) {
27078
+ async sendTaskDirect(targetAgent, targetUrl, messageText) {
26979
27079
  const headers = { "Content-Type": "application/json" };
26980
27080
  const peerAuth = this.config.peerAuth?.[targetAgent];
26981
27081
  if (peerAuth) {
@@ -26984,19 +27084,14 @@ var A2AServer = class {
26984
27084
  const payload = {
26985
27085
  jsonrpc: "2.0",
26986
27086
  method: "message/send",
26987
- id: randomUUID3(),
27087
+ id: randomUUID4(),
26988
27088
  params: {
26989
27089
  message: {
26990
27090
  kind: "message",
26991
- messageId: randomUUID3(),
27091
+ messageId: randomUUID4(),
26992
27092
  role: "user",
26993
27093
  parts: [{ kind: "text", text: messageText }],
26994
- metadata: {
26995
- fromAgent: this.config.agentName,
26996
- conversationId: metadata?.conversationId,
26997
- replyToTaskId: metadata?.replyToTaskId,
26998
- kind: metadata?.kind || "request"
26999
- }
27094
+ metadata: { fromAgent: this.config.agentName }
27000
27095
  }
27001
27096
  }
27002
27097
  };
@@ -27005,10 +27100,51 @@ var A2AServer = class {
27005
27100
  headers,
27006
27101
  body: JSON.stringify(payload)
27007
27102
  });
27008
- return await response.json();
27103
+ const initial = await response.json();
27104
+ const task = initial.result;
27105
+ if (task?.id && !isTerminalTaskState(task.status?.state)) {
27106
+ const terminal = await this.waitForRemoteTaskTerminal(targetUrl, headers, task.id).catch((err) => {
27107
+ const msg = err instanceof Error ? err.message : String(err);
27108
+ this.logger.info(`[perkos-a2a] Waiting for ${targetAgent} task ${task.id} terminal state failed: ${msg}`);
27109
+ return null;
27110
+ });
27111
+ if (terminal) return terminal;
27112
+ }
27113
+ return initial;
27114
+ }
27115
+ async waitForRemoteTaskTerminal(targetUrl, headers, taskId, timeoutMs = Number(process.env.A2A_SEND_WAIT_MS || 45e3), pollMs = Number(process.env.A2A_SEND_POLL_MS || 1e3)) {
27116
+ const deadline = Date.now() + timeoutMs;
27117
+ while (Date.now() < deadline) {
27118
+ await new Promise((resolve) => setTimeout(resolve, pollMs));
27119
+ const response = await fetch(`${targetUrl}/a2a/jsonrpc`, {
27120
+ method: "POST",
27121
+ headers,
27122
+ body: JSON.stringify({
27123
+ jsonrpc: "2.0",
27124
+ method: "tasks/get",
27125
+ id: randomUUID4(),
27126
+ params: { id: taskId }
27127
+ })
27128
+ });
27129
+ const json = await response.json();
27130
+ const task = json.result;
27131
+ if (task && isTerminalTaskState(task.status?.state)) return json;
27132
+ }
27133
+ return null;
27134
+ }
27135
+ async waitForLocalTaskTerminal(taskId, timeoutMs = Number(process.env.A2A_RELAY_WAIT_MS || 45e3), pollMs = Number(process.env.A2A_RELAY_POLL_MS || 1e3)) {
27136
+ const deadline = Date.now() + timeoutMs;
27137
+ while (Date.now() < deadline) {
27138
+ const task = this.tasks.get(taskId);
27139
+ if (task && isTerminalTaskState(task.status?.state)) {
27140
+ return this.success(randomUUID4(), structuredClone(task));
27141
+ }
27142
+ await new Promise((resolve) => setTimeout(resolve, pollMs));
27143
+ }
27144
+ return null;
27009
27145
  }
27010
- async sendTaskViaRelay(targetAgent, messageText, metadata) {
27011
- const rpcId = randomUUID3();
27146
+ async sendTaskViaRelay(targetAgent, messageText) {
27147
+ const rpcId = randomUUID4();
27012
27148
  const result = await this.relayClient.sendTask(targetAgent, {
27013
27149
  jsonrpc: "2.0",
27014
27150
  method: "message/send",
@@ -27016,15 +27152,10 @@ var A2AServer = class {
27016
27152
  params: {
27017
27153
  message: {
27018
27154
  kind: "message",
27019
- messageId: randomUUID3(),
27155
+ messageId: randomUUID4(),
27020
27156
  role: "user",
27021
27157
  parts: [{ kind: "text", text: messageText }],
27022
- metadata: {
27023
- fromAgent: this.config.agentName,
27024
- conversationId: metadata?.conversationId,
27025
- replyToTaskId: metadata?.replyToTaskId,
27026
- kind: metadata?.kind || "request"
27027
- }
27158
+ metadata: { fromAgent: this.config.agentName }
27028
27159
  }
27029
27160
  }
27030
27161
  });
@@ -27074,7 +27205,19 @@ var A2AServer = class {
27074
27205
  const payload = msg.payload;
27075
27206
  const params = payload.params || payload;
27076
27207
  const rpcId = payload.id || msg.id;
27077
- this.handleSendMessage(params, rpcId).then((response) => {
27208
+ this.handleSendMessage(params, rpcId).then(async (response) => {
27209
+ const task = response.result;
27210
+ if (task?.id && !isTerminalTaskState(task.status?.state)) {
27211
+ const terminal = await this.waitForLocalTaskTerminal(task.id).catch((err) => {
27212
+ const errMsg = err instanceof Error ? err.message : String(err);
27213
+ this.logger.info(`[perkos-a2a] Waiting for relay task ${task.id} terminal state failed: ${errMsg}`);
27214
+ return null;
27215
+ });
27216
+ if (terminal) {
27217
+ this.relayClient?.sendTaskResponse(msg, terminal);
27218
+ return;
27219
+ }
27220
+ }
27078
27221
  this.relayClient?.sendTaskResponse(msg, response);
27079
27222
  }).catch((err) => {
27080
27223
  const errMsg = err instanceof Error ? err.message : String(err);
@@ -27099,8 +27242,9 @@ var A2AServer = class {
27099
27242
  const relayConfig = this.config.relay;
27100
27243
  this.relayHub = new RelayHub(
27101
27244
  {
27102
- port: this.config.port,
27103
- apiKeys: this.config.auth?.apiKeys || [],
27245
+ port: this.config.relay?.hubPort || this.config.port,
27246
+ apiKeys: this.config.relay?.hubApiKeys || this.config.auth?.apiKeys || [],
27247
+ registeredAgents: this.config.relay?.registeredAgents || {},
27104
27248
  maxQueuePerAgent: 200,
27105
27249
  rateLimitPerMinute: 60,
27106
27250
  heartbeatIntervalMs: 3e4,
@@ -27162,11 +27306,12 @@ var A2AServer = class {
27162
27306
  tryListen(port, attempt = 1) {
27163
27307
  const maxAttempts = 3;
27164
27308
  try {
27165
- const srv = this.app.listen(port, "0.0.0.0", () => {
27309
+ const bindHost = this.config.bindHost || "0.0.0.0";
27310
+ const srv = this.app.listen(port, bindHost, () => {
27166
27311
  this.logger.info(
27167
- `[perkos-a2a] ${this.config.agentName} server on port ${port}`
27312
+ `[perkos-a2a] ${this.config.agentName} server on ${bindHost}:${port}`
27168
27313
  );
27169
- this.agentCard.url = `http://localhost:${port}/a2a/jsonrpc`;
27314
+ this.agentCard.url = `${(this.config.publicUrl || `http://localhost:${port}`).replace(/\/+$/, "")}/a2a/jsonrpc`;
27170
27315
  });
27171
27316
  srv.on("error", (err) => {
27172
27317
  if (err.code === "EADDRINUSE" && attempt < maxAttempts) {
@@ -27193,7 +27338,7 @@ var A2AServer = class {
27193
27338
  };
27194
27339
 
27195
27340
  // src/index.ts
27196
- import { randomUUID as randomUUID4 } from "crypto";
27341
+ import { randomUUID as randomUUID5 } from "crypto";
27197
27342
  function wakeGatewayAgent(requestHeartbeatNow, reason, logger, sessionKey = "agent:main") {
27198
27343
  if (typeof requestHeartbeatNow === "function") {
27199
27344
  try {
@@ -27207,6 +27352,34 @@ function wakeGatewayAgent(requestHeartbeatNow, reason, logger, sessionKey = "age
27207
27352
  logger.info("[perkos-a2a] runtime.system.requestHeartbeatNow unavailable \u2014 task will process on next agent turn");
27208
27353
  }
27209
27354
  }
27355
+ function openclawWakeSessionKey(config) {
27356
+ return config.runtime?.sessionKey || "agent:main";
27357
+ }
27358
+ function openclawEventSessionKey(config) {
27359
+ const key = config.runtime?.sessionKey;
27360
+ if (!key) return "agent:main:main";
27361
+ return key.endsWith(":main") ? key : `${key}:main`;
27362
+ }
27363
+ async function deliverToHermes(config, message, logger) {
27364
+ const runtime = config.runtime || {};
27365
+ const baseUrl = (runtime.hermesUrl || process.env.HERMES_WORKSPACE_URL || "http://127.0.0.1:3000").replace(/\/+$/, "");
27366
+ const endpoint = runtime.hermesEndpoint || "/api/session-send";
27367
+ const sessionKey = runtime.sessionKey || "main";
27368
+ const token = runtime.hermesToken || process.env.HERMES_WORKSPACE_TOKEN || process.env.HERMES_SESSION_TOKEN;
27369
+ const url = `${baseUrl}${endpoint.startsWith("/") ? endpoint : `/${endpoint}`}`;
27370
+ const headers = { "content-type": "application/json" };
27371
+ if (token) headers.cookie = `claude-auth=${token}`;
27372
+ const response = await fetch(url, {
27373
+ method: "POST",
27374
+ headers,
27375
+ body: JSON.stringify({ sessionKey, message })
27376
+ });
27377
+ if (!response.ok) {
27378
+ const body = await response.text().catch(() => "");
27379
+ throw new Error(`Hermes delivery failed (${response.status}): ${body || response.statusText}`);
27380
+ }
27381
+ logger.info(`[perkos-a2a] Delivered inbound A2A task to Hermes session ${sessionKey} via ${url}`);
27382
+ }
27210
27383
  function register(api) {
27211
27384
  const pluginConfig = api.config?.plugins?.entries?.["perkos-a2a"]?.config || {
27212
27385
  agentName: "agent",
@@ -27230,6 +27403,7 @@ function register(api) {
27230
27403
  logger.info("[perkos-a2a] runtime.system.requestHeartbeatNow unavailable \u2014 wake will rely on next agent turn");
27231
27404
  }
27232
27405
  server.setTaskResultHandler(async (task, text) => {
27406
+ const runtimeKind = pluginConfig.runtime?.kind || "openclaw";
27233
27407
  const from = task.metadata?.fromAgent || "unknown";
27234
27408
  const marker = `[A2A_RESULT:${task.id}]`;
27235
27409
  const eventText = [
@@ -27249,22 +27423,43 @@ function register(api) {
27249
27423
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
27250
27424
  message: {
27251
27425
  role: "agent",
27252
- parts: [{ kind: "text", text: "Task dispatched to supported system-event execution path." }]
27426
+ parts: [{ kind: "text", text: `Task dispatched to ${runtimeKind} runtime.` }]
27253
27427
  }
27254
27428
  };
27429
+ if (runtimeKind === "hermes") {
27430
+ await deliverToHermes(pluginConfig, eventText, logger);
27431
+ task.artifacts.push({
27432
+ kind: "artifact",
27433
+ artifactId: randomUUID5(),
27434
+ parts: [{ kind: "text", text: `debug: delivered task ${task.id} to Hermes Workspace` }]
27435
+ });
27436
+ const finalText2 = await generateRuntimeReply(pluginConfig, text, marker);
27437
+ completeTaskWithReply(task, finalText2);
27438
+ return;
27439
+ }
27440
+ if (runtimeKind === "none") {
27441
+ task.artifacts.push({
27442
+ kind: "artifact",
27443
+ artifactId: randomUUID5(),
27444
+ parts: [{ kind: "text", text: `debug: runtime delivery disabled for ${marker}` }]
27445
+ });
27446
+ return;
27447
+ }
27255
27448
  task.artifacts.push({
27256
27449
  kind: "artifact",
27257
- artifactId: randomUUID4(),
27450
+ artifactId: randomUUID5(),
27258
27451
  parts: [{ kind: "text", text: `debug: enqueued system event for ${marker}` }]
27259
27452
  });
27260
27453
  if (enqueueSystemEvent) {
27261
- enqueueSystemEvent(eventText, { sessionKey: "agent:main:main" });
27454
+ enqueueSystemEvent(eventText, { sessionKey: openclawEventSessionKey(pluginConfig) });
27262
27455
  }
27456
+ const finalText = await generateRuntimeReply(pluginConfig, text, marker);
27457
+ completeTaskWithReply(task, finalText);
27263
27458
  wakeGatewayAgent(
27264
27459
  requestHeartbeatNow,
27265
27460
  `[A2A] Process queued task ${task.id}`,
27266
27461
  logger,
27267
- "agent:main"
27462
+ openclawWakeSessionKey(pluginConfig)
27268
27463
  );
27269
27464
  });
27270
27465
  server.setTaskFailureHandler(async (task, errorText) => {
@@ -27283,7 +27478,8 @@ function register(api) {
27283
27478
  const time = (/* @__PURE__ */ new Date()).toISOString();
27284
27479
  pendingTasks.push({ from, text, taskId, time });
27285
27480
  logger.info(`[perkos-a2a] Task queued from ${from} (${taskId}), ${pendingTasks.length} pending`);
27286
- if (enqueueSystemEvent) {
27481
+ const runtimeKind = pluginConfig.runtime?.kind || "openclaw";
27482
+ if (runtimeKind === "openclaw" && enqueueSystemEvent) {
27287
27483
  const eventText = [
27288
27484
  `[A2A OBSERVABILITY EVENT]`,
27289
27485
  `From: ${from} | Task ID: ${taskId} | Time: ${time}`,
@@ -27291,19 +27487,21 @@ function register(api) {
27291
27487
  text
27292
27488
  ].join("\n");
27293
27489
  try {
27294
- enqueueSystemEvent(eventText, { sessionKey: "agent:main:main" });
27490
+ enqueueSystemEvent(eventText, { sessionKey: openclawEventSessionKey(pluginConfig) });
27295
27491
  logger.info(`[perkos-a2a] Observability system event enqueued for task ${taskId}`);
27296
27492
  } catch (err) {
27297
27493
  const msg = err instanceof Error ? err.message : String(err);
27298
27494
  logger.error(`[perkos-a2a] Failed to enqueue observability system event: ${msg}`);
27299
27495
  }
27300
27496
  }
27301
- wakeGatewayAgent(
27302
- requestHeartbeatNow,
27303
- `[A2A] Incoming task from ${from} (${taskId}).`,
27304
- logger,
27305
- "agent:main"
27306
- );
27497
+ if (runtimeKind === "openclaw") {
27498
+ wakeGatewayAgent(
27499
+ requestHeartbeatNow,
27500
+ `[A2A] Incoming task from ${from} (${taskId}).`,
27501
+ logger,
27502
+ openclawWakeSessionKey(pluginConfig)
27503
+ );
27504
+ }
27307
27505
  });
27308
27506
  api.registerHook("before_agent_start", async () => {
27309
27507
  if (pendingTasks.length === 0) return {};
@@ -27320,7 +27518,7 @@ function register(api) {
27320
27518
  }
27321
27519
  logger.info(`[perkos-a2a] Injecting ${tasks.length} observability note(s) into agent context via before_agent_start`);
27322
27520
  return { prependContext: lines.join("\n") };
27323
- });
27521
+ }, { name: "perkos-a2a-before-agent-start", description: "Inject pending A2A observability notes before agent starts." });
27324
27522
  api.runtime?.events?.onSessionTranscriptUpdate?.((update) => {
27325
27523
  const message = update?.message;
27326
27524
  const text = Array.isArray(message?.parts) ? message.parts.filter((p) => p?.kind === "text" && typeof p?.text === "string").map((p) => p.text).join("\n") : typeof message?.text === "string" ? message.text : "";
@@ -27328,11 +27526,12 @@ function register(api) {
27328
27526
  for (const task of server.getTasks()) {
27329
27527
  const marker = `[A2A_RESULT:${task.id}]`;
27330
27528
  if (!text.includes(marker)) continue;
27529
+ if (task.status.state === "completed") continue;
27331
27530
  const finalText = text.slice(text.indexOf(marker) + marker.length).trim();
27332
27531
  if (!finalText) continue;
27333
27532
  task.artifacts.push({
27334
27533
  kind: "artifact",
27335
- artifactId: randomUUID4(),
27534
+ artifactId: randomUUID5(),
27336
27535
  parts: [{ kind: "text", text: finalText }]
27337
27536
  });
27338
27537
  task.status = {