commonswarm 0.1.45 → 0.1.47

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/cswarm.cjs +1866 -348
  2. package/package.json +1 -1
package/cswarm.cjs CHANGED
@@ -163,11 +163,11 @@ function __metadata(metadataKey, metadataValue) {
163
163
  }
164
164
  function __awaiter(thisArg, _arguments, P, generator) {
165
165
  function adopt(value) {
166
- return value instanceof P ? value : new P(function(resolve2) {
167
- resolve2(value);
166
+ return value instanceof P ? value : new P(function(resolve3) {
167
+ resolve3(value);
168
168
  });
169
169
  }
170
- return new (P || (P = Promise))(function(resolve2, reject) {
170
+ return new (P || (P = Promise))(function(resolve3, reject) {
171
171
  function fulfilled(value) {
172
172
  try {
173
173
  step(generator.next(value));
@@ -183,7 +183,7 @@ function __awaiter(thisArg, _arguments, P, generator) {
183
183
  }
184
184
  }
185
185
  function step(result) {
186
- result.done ? resolve2(result.value) : adopt(result.value).then(fulfilled, rejected);
186
+ result.done ? resolve3(result.value) : adopt(result.value).then(fulfilled, rejected);
187
187
  }
188
188
  step((generator = generator.apply(thisArg, _arguments || [])).next());
189
189
  });
@@ -374,14 +374,14 @@ function __asyncValues(o) {
374
374
  }, i);
375
375
  function verb(n) {
376
376
  i[n] = o[n] && function(v) {
377
- return new Promise(function(resolve2, reject) {
378
- v = o[n](v), settle(resolve2, reject, v.done, v.value);
377
+ return new Promise(function(resolve3, reject) {
378
+ v = o[n](v), settle(resolve3, reject, v.done, v.value);
379
379
  });
380
380
  };
381
381
  }
382
- function settle(resolve2, reject, d, v) {
382
+ function settle(resolve3, reject, d, v) {
383
383
  Promise.resolve(v).then(function(v2) {
384
- resolve2({ value: v2, done: d });
384
+ resolve3({ value: v2, done: d });
385
385
  }, reject);
386
386
  }
387
387
  }
@@ -4262,15 +4262,15 @@ var require_RealtimeChannel = __commonJS({
4262
4262
  }
4263
4263
  }
4264
4264
  } else {
4265
- return new Promise((resolve2) => {
4265
+ return new Promise((resolve3) => {
4266
4266
  var _a2, _b2, _c;
4267
4267
  const push = this.channelAdapter.push(args.type, args, opts.timeout || this.timeout);
4268
4268
  if (args.type === "broadcast" && !((_c = (_b2 = (_a2 = this.params) === null || _a2 === void 0 ? void 0 : _a2.config) === null || _b2 === void 0 ? void 0 : _b2.broadcast) === null || _c === void 0 ? void 0 : _c.ack)) {
4269
- resolve2("ok");
4269
+ resolve3("ok");
4270
4270
  }
4271
- push.receive("ok", () => resolve2("ok"));
4272
- push.receive("error", () => resolve2("error"));
4273
- push.receive("timeout", () => resolve2("timed out"));
4271
+ push.receive("ok", () => resolve3("ok"));
4272
+ push.receive("error", () => resolve3("error"));
4273
+ push.receive("timeout", () => resolve3("timed out"));
4274
4274
  });
4275
4275
  }
4276
4276
  }
@@ -4295,8 +4295,8 @@ var require_RealtimeChannel = __commonJS({
4295
4295
  * @category Realtime
4296
4296
  */
4297
4297
  async unsubscribe(timeout = this.timeout) {
4298
- return new Promise((resolve2) => {
4299
- this.channelAdapter.unsubscribe(timeout).receive("ok", () => resolve2("ok")).receive("timeout", () => resolve2("timed out")).receive("error", () => resolve2("error"));
4298
+ return new Promise((resolve3) => {
4299
+ this.channelAdapter.unsubscribe(timeout).receive("ok", () => resolve3("ok")).receive("timeout", () => resolve3("timed out")).receive("error", () => resolve3("error"));
4300
4300
  });
4301
4301
  }
4302
4302
  /**
@@ -4504,11 +4504,11 @@ var require_socketAdapter = __commonJS({
4504
4504
  this.socket.connect();
4505
4505
  }
4506
4506
  disconnect(callback, code, reason, timeout = 1e4) {
4507
- return new Promise((resolve2) => {
4508
- setTimeout(() => resolve2("timeout"), timeout);
4507
+ return new Promise((resolve3) => {
4508
+ setTimeout(() => resolve3("timeout"), timeout);
4509
4509
  this.socket.disconnect(() => {
4510
4510
  callback();
4511
- resolve2("ok");
4511
+ resolve3("ok");
4512
4512
  }, code, reason);
4513
4513
  });
4514
4514
  }
@@ -13511,6 +13511,7 @@ __export(cli_exports, {
13511
13511
  listenerFailureMessage: () => listenerFailureMessage,
13512
13512
  listenerHostLimits: () => listenerHostLimits,
13513
13513
  listenerPermissionMode: () => listenerPermissionMode,
13514
+ listenerProviderInstallEvidence: () => listenerProviderInstallEvidence,
13514
13515
  listenerRouteConfiguration: () => listenerRouteConfiguration,
13515
13516
  listenerStatusJson: () => listenerStatusJson,
13516
13517
  renderListenerStatus: () => renderListenerStatus,
@@ -13521,7 +13522,7 @@ __export(cli_exports, {
13521
13522
  resolveTurnBudgetOrDefer: () => resolveTurnBudgetOrDefer
13522
13523
  });
13523
13524
  module.exports = __toCommonJS(cli_exports);
13524
- var import_node_crypto20 = require("node:crypto");
13525
+ var import_node_crypto22 = require("node:crypto");
13525
13526
  var import_node_child_process9 = require("node:child_process");
13526
13527
  var import_node_fs7 = require("node:fs");
13527
13528
  var import_promises12 = require("node:fs/promises");
@@ -13590,18 +13591,18 @@ var PostgrestError = class extends Error {
13590
13591
  }
13591
13592
  };
13592
13593
  function sleep(ms, signal) {
13593
- return new Promise((resolve2) => {
13594
+ return new Promise((resolve3) => {
13594
13595
  if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
13595
- resolve2();
13596
+ resolve3();
13596
13597
  return;
13597
13598
  }
13598
13599
  const id = setTimeout(() => {
13599
13600
  signal === null || signal === void 0 || signal.removeEventListener("abort", onAbort);
13600
- resolve2();
13601
+ resolve3();
13601
13602
  }, ms);
13602
13603
  function onAbort() {
13603
13604
  clearTimeout(id);
13604
- resolve2();
13605
+ resolve3();
13605
13606
  }
13606
13607
  signal === null || signal === void 0 || signal.addEventListener("abort", onAbort);
13607
13608
  });
@@ -18039,7 +18040,7 @@ var _getRequestParams = (method, options, parameters, body) => {
18039
18040
  return _objectSpread22(_objectSpread22({}, params), parameters);
18040
18041
  };
18041
18042
  async function _handleRequest(fetcher, method, url, options, parameters, body, namespace) {
18042
- return new Promise((resolve2, reject) => {
18043
+ return new Promise((resolve3, reject) => {
18043
18044
  fetcher(url, _getRequestParams(method, options, parameters, body)).then((result) => {
18044
18045
  if (!result.ok) throw result;
18045
18046
  if (options === null || options === void 0 ? void 0 : options.noResolveJson) return result;
@@ -18049,7 +18050,7 @@ async function _handleRequest(fetcher, method, url, options, parameters, body, n
18049
18050
  if (!contentType || !contentType.includes("application/json")) return {};
18050
18051
  }
18051
18052
  return result.json();
18052
- }).then((data) => resolve2(data)).catch((error) => handleError(error, reject, options, namespace));
18053
+ }).then((data) => resolve3(data)).catch((error) => handleError(error, reject, options, namespace));
18053
18054
  });
18054
18055
  }
18055
18056
  function createFetchApi(namespace = "storage") {
@@ -20692,11 +20693,11 @@ var DEFAULT_TRACE_PROPAGATION_OPTIONS = {
20692
20693
  };
20693
20694
  function __awaiter2(thisArg, _arguments, P, generator) {
20694
20695
  function adopt(value) {
20695
- return value instanceof P ? value : new P(function(resolve2) {
20696
- resolve2(value);
20696
+ return value instanceof P ? value : new P(function(resolve3) {
20697
+ resolve3(value);
20697
20698
  });
20698
20699
  }
20699
- return new (P || (P = Promise))(function(resolve2, reject) {
20700
+ return new (P || (P = Promise))(function(resolve3, reject) {
20700
20701
  function fulfilled(value) {
20701
20702
  try {
20702
20703
  step(generator.next(value));
@@ -20712,7 +20713,7 @@ function __awaiter2(thisArg, _arguments, P, generator) {
20712
20713
  }
20713
20714
  }
20714
20715
  function step(result) {
20715
- result.done ? resolve2(result.value) : adopt(result.value).then(fulfilled, rejected);
20716
+ result.done ? resolve3(result.value) : adopt(result.value).then(fulfilled, rejected);
20716
20717
  }
20717
20718
  step((generator = generator.apply(thisArg, _arguments || [])).next());
20718
20719
  });
@@ -21500,14 +21501,14 @@ function validateCallbackUrl(raw, expectedOrigin, expectedState) {
21500
21501
  return code;
21501
21502
  }
21502
21503
  function listen(server, port) {
21503
- return new Promise((resolve2, reject) => {
21504
+ return new Promise((resolve3, reject) => {
21504
21505
  const onError = (error) => {
21505
21506
  server.off("listening", onListening);
21506
21507
  reject(error);
21507
21508
  };
21508
21509
  const onListening = () => {
21509
21510
  server.off("error", onError);
21510
- resolve2();
21511
+ resolve3();
21511
21512
  };
21512
21513
  server.once("error", onError);
21513
21514
  server.once("listening", onListening);
@@ -21516,8 +21517,8 @@ function listen(server, port) {
21516
21517
  }
21517
21518
  function closeServer(server) {
21518
21519
  if (!server.listening) return Promise.resolve();
21519
- const closed = new Promise((resolve2, reject) => {
21520
- server.close((error) => error ? reject(error) : resolve2());
21520
+ const closed = new Promise((resolve3, reject) => {
21521
+ server.close((error) => error ? reject(error) : resolve3());
21521
21522
  });
21522
21523
  server.closeAllConnections();
21523
21524
  return closed;
@@ -21525,8 +21526,8 @@ function closeServer(server) {
21525
21526
  async function callbackReceiver(expectedState) {
21526
21527
  let resolveCode;
21527
21528
  let rejectCode;
21528
- const result = new Promise((resolve2, reject) => {
21529
- resolveCode = resolve2;
21529
+ const result = new Promise((resolve3, reject) => {
21530
+ resolveCode = resolve3;
21530
21531
  rejectCode = reject;
21531
21532
  });
21532
21533
  let origin = "";
@@ -21611,23 +21612,23 @@ function authClient(target2, storage) {
21611
21612
  async function openExternalBrowser(url) {
21612
21613
  const command2 = process.platform === "darwin" ? { executable: "open", args: [url] } : process.platform === "linux" ? { executable: "xdg-open", args: [url] } : null;
21613
21614
  if (!command2) return false;
21614
- return await new Promise((resolve2) => {
21615
+ return await new Promise((resolve3) => {
21615
21616
  const child = (0, import_node_child_process.spawn)(command2.executable, command2.args, {
21616
21617
  detached: true,
21617
21618
  stdio: "ignore"
21618
21619
  });
21619
- child.once("error", () => resolve2(false));
21620
+ child.once("error", () => resolve3(false));
21620
21621
  child.once("spawn", () => {
21621
21622
  child.unref();
21622
- resolve2(true);
21623
+ resolve3(true);
21623
21624
  });
21624
21625
  });
21625
21626
  }
21626
21627
  function pastedCallback(input, output, origin, state) {
21627
21628
  if (!input) return null;
21628
21629
  let resolveCode;
21629
- const promise = new Promise((resolve2) => {
21630
- resolveCode = resolve2;
21630
+ const promise = new Promise((resolve3) => {
21631
+ resolveCode = resolve3;
21631
21632
  });
21632
21633
  let pending = "";
21633
21634
  const onData = (chunk) => {
@@ -21658,14 +21659,14 @@ function pastedCallback(input, output, origin, state) {
21658
21659
  async function waitForCode(receiver, state, input, output, timeoutMs, pasteFallbackDelayMs) {
21659
21660
  const activePastes = [];
21660
21661
  let pasteTimer = null;
21661
- const paste = input ? new Promise((resolve2) => {
21662
+ const paste = input ? new Promise((resolve3) => {
21662
21663
  pasteTimer = setTimeout(() => {
21663
21664
  output.write(
21664
21665
  "If the browser cannot reach the loopback callback, paste the complete callback URL here:\n"
21665
21666
  );
21666
21667
  const pasted = pastedCallback(input, output, receiver.origin, state);
21667
21668
  if (pasted) activePastes.push(pasted);
21668
- pasted?.promise.then(resolve2);
21669
+ pasted?.promise.then(resolve3);
21669
21670
  }, pasteFallbackDelayMs);
21670
21671
  }) : null;
21671
21672
  let timer2 = null;
@@ -22393,8 +22394,8 @@ function signalRetryDelayMs(retry, baseMs, random) {
22393
22394
  async function waitForSignalRetry(delayMs, deadline, callerAbort) {
22394
22395
  if (delayMs === 0) return "elapsed";
22395
22396
  let timer2;
22396
- const elapsed = new Promise((resolve2) => {
22397
- timer2 = setTimeout(() => resolve2("elapsed"), delayMs);
22397
+ const elapsed = new Promise((resolve3) => {
22398
+ timer2 = setTimeout(() => resolve3("elapsed"), delayMs);
22398
22399
  });
22399
22400
  try {
22400
22401
  const outcome = await raceSignalDeadline(elapsed, deadline, callerAbort);
@@ -22703,12 +22704,12 @@ var ThinCommandClient = class {
22703
22704
  }
22704
22705
  const controller = new AbortController();
22705
22706
  let releaseDeadline;
22706
- const deadline = new Promise((resolve2) => {
22707
- releaseDeadline = resolve2;
22707
+ const deadline = new Promise((resolve3) => {
22708
+ releaseDeadline = resolve3;
22708
22709
  });
22709
22710
  let releaseCallerAbort;
22710
- const callerAbort = new Promise((resolve2) => {
22711
- releaseCallerAbort = resolve2;
22711
+ const callerAbort = new Promise((resolve3) => {
22712
+ releaseCallerAbort = resolve3;
22712
22713
  });
22713
22714
  let deadlineReached = false;
22714
22715
  const timer2 = setTimeout(() => {
@@ -23581,7 +23582,7 @@ async function deleteSecureJsonFile(path) {
23581
23582
  }
23582
23583
  }
23583
23584
  async function run(executable, args, input, detached = false) {
23584
- return await new Promise((resolve2, reject) => {
23585
+ return await new Promise((resolve3, reject) => {
23585
23586
  const child = (0, import_node_child_process2.spawn)(executable, args, {
23586
23587
  stdio: ["pipe", "pipe", "pipe"],
23587
23588
  env: process.env,
@@ -23598,7 +23599,7 @@ async function run(executable, args, input, detached = false) {
23598
23599
  stderr += chunk;
23599
23600
  });
23600
23601
  child.on("error", reject);
23601
- child.on("close", (code) => resolve2({ code: code ?? 1, stdout, stderr }));
23602
+ child.on("close", (code) => resolve3({ code: code ?? 1, stdout, stderr }));
23602
23603
  if (input !== void 0) child.stdin.end(`${input}
23603
23604
  `);
23604
23605
  else child.stdin.end();
@@ -23848,8 +23849,7 @@ function parseStoredCurrentTarget(raw) {
23848
23849
  throw new Error("stored current target is malformed");
23849
23850
  }
23850
23851
  const record = value;
23851
- const keys = Object.keys(record).sort();
23852
- if (keys.length !== 3 || keys[0] !== "anonKey" || keys[1] !== "url" || keys[2] !== "version" || record.version !== 1 || typeof record.url !== "string" || typeof record.anonKey !== "string") {
23852
+ if (record.version !== 1 || typeof record.url !== "string" || typeof record.anonKey !== "string") {
23853
23853
  throw new Error("stored current target is malformed");
23854
23854
  }
23855
23855
  try {
@@ -24028,9 +24028,9 @@ var originError = /* @__PURE__ */ Symbol("OriginError");
24028
24028
  var CLOSE = {};
24029
24029
  var Query = class extends Promise {
24030
24030
  constructor(strings, args, handler, canceller, options = {}) {
24031
- let resolve2, reject;
24031
+ let resolve3, reject;
24032
24032
  super((a, b2) => {
24033
- resolve2 = a;
24033
+ resolve3 = a;
24034
24034
  reject = b2;
24035
24035
  });
24036
24036
  this.tagged = Array.isArray(strings.raw);
@@ -24041,7 +24041,7 @@ var Query = class extends Promise {
24041
24041
  this.options = options;
24042
24042
  this.state = null;
24043
24043
  this.statement = null;
24044
- this.resolve = (x) => (this.active = false, resolve2(x));
24044
+ this.resolve = (x) => (this.active = false, resolve3(x));
24045
24045
  this.reject = (x) => (this.active = false, reject(x));
24046
24046
  this.active = false;
24047
24047
  this.cancelled = null;
@@ -24089,12 +24089,12 @@ var Query = class extends Promise {
24089
24089
  if (this.executed && !this.active)
24090
24090
  return { done: true };
24091
24091
  prev && prev();
24092
- const promise = new Promise((resolve2, reject) => {
24092
+ const promise = new Promise((resolve3, reject) => {
24093
24093
  this.cursorFn = (value) => {
24094
- resolve2({ value, done: false });
24094
+ resolve3({ value, done: false });
24095
24095
  return new Promise((r) => prev = r);
24096
24096
  };
24097
- this.resolve = () => (this.active = false, resolve2({ done: true }));
24097
+ this.resolve = () => (this.active = false, resolve3({ done: true }));
24098
24098
  this.reject = (x) => (this.active = false, reject(x));
24099
24099
  });
24100
24100
  this.execute();
@@ -24721,12 +24721,12 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
24721
24721
  x.on("drain", drain);
24722
24722
  return x;
24723
24723
  }
24724
- async function cancel({ pid, secret }, resolve2, reject) {
24724
+ async function cancel({ pid, secret }, resolve3, reject) {
24725
24725
  try {
24726
24726
  cancelMessage = bytes_default().i32(16).i32(80877102).i32(pid).i32(secret).end(16);
24727
24727
  await connect();
24728
24728
  socket.once("error", reject);
24729
- socket.once("close", resolve2);
24729
+ socket.once("close", resolve3);
24730
24730
  } catch (error2) {
24731
24731
  reject(error2);
24732
24732
  }
@@ -25673,7 +25673,7 @@ function parseEvent(x) {
25673
25673
  // node_modules/postgres/src/large.js
25674
25674
  var import_stream2 = __toESM(require("stream"), 1);
25675
25675
  function largeObject(sql, oid, mode3 = 131072 | 262144) {
25676
- return new Promise(async (resolve2, reject) => {
25676
+ return new Promise(async (resolve3, reject) => {
25677
25677
  await sql.begin(async (sql2) => {
25678
25678
  let finish;
25679
25679
  !oid && ([{ oid }] = await sql2`select lo_creat(-1) as oid`);
@@ -25699,7 +25699,7 @@ function largeObject(sql, oid, mode3 = 131072 | 262144) {
25699
25699
  ) seek
25700
25700
  `
25701
25701
  };
25702
- resolve2(lo);
25702
+ resolve3(lo);
25703
25703
  return new Promise(async (r) => finish = r);
25704
25704
  async function readable({
25705
25705
  highWaterMark = 2048 * 8,
@@ -25873,8 +25873,8 @@ function Postgres(a, b2) {
25873
25873
  }
25874
25874
  async function reserve() {
25875
25875
  const queue = queue_default();
25876
- const c = open6.length ? open6.shift() : await new Promise((resolve2, reject) => {
25877
- const query = { reserve: resolve2, reject };
25876
+ const c = open6.length ? open6.shift() : await new Promise((resolve3, reject) => {
25877
+ const query = { reserve: resolve3, reject };
25878
25878
  queries.push(query);
25879
25879
  closed.length && connect(closed.shift(), query);
25880
25880
  });
@@ -25911,9 +25911,9 @@ function Postgres(a, b2) {
25911
25911
  let uncaughtError, result;
25912
25912
  name && await sql2`savepoint ${sql2(name)}`;
25913
25913
  try {
25914
- result = await new Promise((resolve2, reject) => {
25914
+ result = await new Promise((resolve3, reject) => {
25915
25915
  const x = fn2(sql2);
25916
- Promise.resolve(Array.isArray(x) ? Promise.all(x) : x).then(resolve2, reject);
25916
+ Promise.resolve(Array.isArray(x) ? Promise.all(x) : x).then(resolve3, reject);
25917
25917
  });
25918
25918
  if (uncaughtError)
25919
25919
  throw uncaughtError;
@@ -25970,8 +25970,8 @@ function Postgres(a, b2) {
25970
25970
  return c.execute(query) ? move(c, busy) : move(c, full);
25971
25971
  }
25972
25972
  function cancel(query) {
25973
- return new Promise((resolve2, reject) => {
25974
- query.state ? query.active ? connection_default(options).cancel(query.state, resolve2, reject) : query.cancelled = { resolve: resolve2, reject } : (queries.remove(query), query.cancelled = true, query.reject(Errors.generic("57014", "canceling statement due to user request")), resolve2());
25973
+ return new Promise((resolve3, reject) => {
25974
+ query.state ? query.active ? connection_default(options).cancel(query.state, resolve3, reject) : query.cancelled = { resolve: resolve3, reject } : (queries.remove(query), query.cancelled = true, query.reject(Errors.generic("57014", "canceling statement due to user request")), resolve3());
25975
25975
  });
25976
25976
  }
25977
25977
  async function end({ timeout = null } = {}) {
@@ -25990,11 +25990,11 @@ function Postgres(a, b2) {
25990
25990
  async function close() {
25991
25991
  await Promise.all(connections.map((c) => c.end()));
25992
25992
  }
25993
- async function destroy(resolve2) {
25993
+ async function destroy(resolve3) {
25994
25994
  await Promise.all(connections.map((c) => c.terminate()));
25995
25995
  while (queries.length)
25996
25996
  queries.shift().reject(Errors.connection("CONNECTION_DESTROYED", options));
25997
- resolve2();
25997
+ resolve3();
25998
25998
  }
25999
25999
  function connect(c, query) {
26000
26000
  move(c, connecting);
@@ -28750,10 +28750,19 @@ var SIGNAL_BODY_DISPLAY_MAX = 8e3;
28750
28750
  var SIGNAL_ABOUT_DISPLAY_MAX = 500;
28751
28751
  var SIGNAL_READ_TIMEOUT_MS = 3e4;
28752
28752
  var SignalReadTimeoutError = class extends Error {
28753
- constructor(message = "signal read timed out") {
28753
+ constructor(message = "signal read timed out", phase = "response") {
28754
28754
  super(message);
28755
+ this.phase = phase;
28755
28756
  this.name = "SignalReadTimeoutError";
28756
28757
  }
28758
+ phase;
28759
+ };
28760
+ var SignalHostPortsExhaustedError = class extends Error {
28761
+ code = "EADDRNOTAVAIL";
28762
+ constructor() {
28763
+ super("the host could not allocate an outbound source port");
28764
+ this.name = "SignalHostPortsExhaustedError";
28765
+ }
28757
28766
  };
28758
28767
  var SIGNAL_WAIT_MIN_SECONDS = 1;
28759
28768
  var SIGNAL_WAIT_MAX_SECONDS = 300;
@@ -28792,9 +28801,17 @@ var plainHttpRetryAfterMs = /* @__PURE__ */ new WeakMap();
28792
28801
  var plainHttpStatus = /* @__PURE__ */ new WeakMap();
28793
28802
  var plainHttpEnvelope = /* @__PURE__ */ new WeakMap();
28794
28803
  var plainTransportErrors = /* @__PURE__ */ new WeakSet();
28795
- function plainTransportError() {
28804
+ var plainTransportFailureCodes = /* @__PURE__ */ new WeakMap();
28805
+ var plainMalformedErrors = /* @__PURE__ */ new WeakSet();
28806
+ function plainTransportError(failureCode2 = "no_response") {
28796
28807
  const error = new Error("signal read could not reach the cloud service");
28797
28808
  plainTransportErrors.add(error);
28809
+ plainTransportFailureCodes.set(error, failureCode2);
28810
+ return error;
28811
+ }
28812
+ function plainMalformedError(message) {
28813
+ const error = new Error(message);
28814
+ plainMalformedErrors.add(error);
28798
28815
  return error;
28799
28816
  }
28800
28817
  function checkedUuid2(value, field) {
@@ -28999,7 +29016,62 @@ function followErrorEnvelope(error) {
28999
29016
  return EMPTY_SERVER_ERROR_ENVELOPE;
29000
29017
  }
29001
29018
  function isTransportFollowMessage(error) {
29002
- return error instanceof SignalTransportError || error instanceof Error && plainTransportErrors.has(error);
29019
+ return error instanceof SignalTransportError || error instanceof SignalHostPortsExhaustedError || error instanceof Error && plainTransportErrors.has(error);
29020
+ }
29021
+ function safeConstructorName(error) {
29022
+ if (error === null || typeof error !== "object") return typeof error;
29023
+ const name = error.constructor?.name;
29024
+ if (typeof name !== "string" || name.length === 0) return "Unknown";
29025
+ return name.replace(/[^A-Za-z0-9_$-]+/g, "_").slice(0, 96) || "Unknown";
29026
+ }
29027
+ function classifySignalReadFailure(error) {
29028
+ if (error instanceof SignalHostPortsExhaustedError || error !== null && typeof error === "object" && error.code === "EADDRNOTAVAIL") {
29029
+ return {
29030
+ code: "host_ports_exhausted",
29031
+ httpStatus: null,
29032
+ errorConstructor: null
29033
+ };
29034
+ }
29035
+ const http = followHttpDetails(error);
29036
+ if (http !== null) {
29037
+ return {
29038
+ code: "http_status",
29039
+ httpStatus: http.status,
29040
+ errorConstructor: null
29041
+ };
29042
+ }
29043
+ if (error instanceof SignalReadTimeoutError) {
29044
+ return {
29045
+ code: error.phase === "body" ? "body_timeout" : "no_response",
29046
+ httpStatus: null,
29047
+ errorConstructor: null
29048
+ };
29049
+ }
29050
+ if (error instanceof Error && plainTransportErrors.has(error)) {
29051
+ return {
29052
+ code: plainTransportFailureCodes.get(error) ?? "no_response",
29053
+ httpStatus: null,
29054
+ errorConstructor: null
29055
+ };
29056
+ }
29057
+ if (error instanceof SignalTransportError) {
29058
+ return { code: "no_response", httpStatus: null, errorConstructor: null };
29059
+ }
29060
+ if (error instanceof SignalMalformedError || error instanceof Error && plainMalformedErrors.has(error)) {
29061
+ return {
29062
+ code: "malformed_response",
29063
+ httpStatus: null,
29064
+ errorConstructor: null
29065
+ };
29066
+ }
29067
+ if (error instanceof Error && error.name === "AbortError") {
29068
+ return { code: "aborted", httpStatus: null, errorConstructor: null };
29069
+ }
29070
+ return {
29071
+ code: "unclassified",
29072
+ httpStatus: null,
29073
+ errorConstructor: safeConstructorName(error)
29074
+ };
29003
29075
  }
29004
29076
  function isRestartableReadError(error) {
29005
29077
  if (error instanceof SignalReadTimeoutError) return true;
@@ -29051,11 +29123,12 @@ async function fetchSignalRead(fetcher, input, init, timeoutMs = SIGNAL_READ_TIM
29051
29123
  }
29052
29124
  const deadlineController = new AbortController();
29053
29125
  let timedOut = false;
29126
+ let responseReceived = false;
29054
29127
  const signal = init.signal ? AbortSignal.any([init.signal, deadlineController.signal]) : deadlineController.signal;
29055
29128
  let onAbort = () => {
29056
29129
  };
29057
- const aborted = new Promise((resolve2) => {
29058
- onAbort = () => resolve2("timeout");
29130
+ const aborted = new Promise((resolve3) => {
29131
+ onAbort = () => resolve3("timeout");
29059
29132
  if (signal.aborted) {
29060
29133
  onAbort();
29061
29134
  } else {
@@ -29078,22 +29151,31 @@ async function fetchSignalRead(fetcher, input, init, timeoutMs = SIGNAL_READ_TIM
29078
29151
  signal
29079
29152
  });
29080
29153
  } catch (error) {
29081
- if (signal.aborted || timedOut || error?.name === "AbortError") {
29154
+ if (signal.aborted || timedOut) {
29082
29155
  return "timeout";
29083
29156
  }
29157
+ if (error instanceof Error && error.name === "AbortError") throw error;
29158
+ if (error !== null && typeof error === "object" && error.code === "EADDRNOTAVAIL") {
29159
+ throw new SignalHostPortsExhaustedError();
29160
+ }
29084
29161
  return null;
29085
29162
  }
29163
+ responseReceived = true;
29086
29164
  if (signal.aborted || timedOut) return "timeout";
29087
29165
  try {
29088
29166
  return { response, body: await response.json() };
29089
- } catch {
29167
+ } catch (error) {
29090
29168
  if (signal.aborted || timedOut) return "timeout";
29169
+ if (error instanceof Error && error.name === "AbortError") throw error;
29091
29170
  return { response, body: null };
29092
29171
  }
29093
29172
  })();
29094
29173
  const raced = await Promise.race([read, aborted]);
29095
29174
  if (raced === "timeout") {
29096
- throw new SignalReadTimeoutError();
29175
+ throw new SignalReadTimeoutError(
29176
+ "signal read timed out",
29177
+ responseReceived ? "body" : "response"
29178
+ );
29097
29179
  }
29098
29180
  return raced;
29099
29181
  } finally {
@@ -29103,7 +29185,7 @@ async function fetchSignalRead(fetcher, input, init, timeoutMs = SIGNAL_READ_TIM
29103
29185
  }
29104
29186
  var READ_RETRY_ATTEMPTS = 2;
29105
29187
  var READ_RETRY_BASE_MS = 250;
29106
- async function fetchSignalReadRetrying(fetcher, input, init, timeoutMs = SIGNAL_READ_TIMEOUT_MS, sleep2 = (ms) => new Promise((resolve2) => setTimeout(resolve2, ms))) {
29188
+ async function fetchSignalReadRetrying(fetcher, input, init, timeoutMs = SIGNAL_READ_TIMEOUT_MS, sleep2 = (ms) => new Promise((resolve3) => setTimeout(resolve3, ms))) {
29107
29189
  let result = await fetchSignalRead(fetcher, input, init, timeoutMs);
29108
29190
  for (let attempt = 1; attempt <= READ_RETRY_ATTEMPTS; attempt += 1) {
29109
29191
  if (result === null || result.response.ok) return result;
@@ -29122,7 +29204,9 @@ async function fetchSignalReadRetrying(fetcher, input, init, timeoutMs = SIGNAL_
29122
29204
  function mapReadFailure(error, waitBound) {
29123
29205
  if (error instanceof SignalReadTimeoutError) {
29124
29206
  if (waitBound) throw error;
29125
- throw plainTransportError();
29207
+ throw plainTransportError(
29208
+ error.phase === "body" ? "body_timeout" : "no_response"
29209
+ );
29126
29210
  }
29127
29211
  throw error;
29128
29212
  }
@@ -29178,7 +29262,7 @@ async function humanSignals(target2, credential, query, options) {
29178
29262
  throwSignalHttp(response, body);
29179
29263
  }
29180
29264
  if (!Array.isArray(body)) {
29181
- throw new Error("signal read returned malformed JSON");
29265
+ throw plainMalformedError("signal read returned malformed JSON");
29182
29266
  }
29183
29267
  const parsed = body.map((value) => parseSignalRecord(value));
29184
29268
  return sortSignals(rowsAfterCursor(parsed, query.after), ascending);
@@ -29246,7 +29330,7 @@ async function agentSignalPage(target2, credential, query, options, allowLegacyC
29246
29330
  const { response, body } = result;
29247
29331
  if (!response.ok) throwSignalHttp(response, body);
29248
29332
  if (!body || typeof body !== "object" || Array.isArray(body) || !Array.isArray(body.signals)) {
29249
- throw new Error("signal read returned malformed JSON");
29333
+ throw plainMalformedError("signal read returned malformed JSON");
29250
29334
  }
29251
29335
  const capabilities = signalReadCapabilities(
29252
29336
  body.capabilities
@@ -29423,7 +29507,7 @@ function nextWaitSleepMs(nowMs, deadlineMs, pollMs = SIGNAL_WAIT_POLL_MS) {
29423
29507
  }
29424
29508
  async function pollForSignals(options) {
29425
29509
  const now = options.now ?? Date.now;
29426
- const sleep2 = options.sleep ?? ((ms) => new Promise((resolve2) => setTimeout(resolve2, ms)));
29510
+ const sleep2 = options.sleep ?? ((ms) => new Promise((resolve3) => setTimeout(resolve3, ms)));
29427
29511
  const pollMs = options.pollMs ?? SIGNAL_WAIT_POLL_MS;
29428
29512
  const probe = async () => {
29429
29513
  try {
@@ -29736,6 +29820,7 @@ function resolveRefusalToleranceMs(raw, warn = () => {
29736
29820
  }
29737
29821
  function isRetryableFollowError(error) {
29738
29822
  if (serverRefusedRetry(followErrorEnvelope(error))) return false;
29823
+ if (error instanceof SignalHostPortsExhaustedError) return true;
29739
29824
  if (error instanceof SignalReadTimeoutError) return true;
29740
29825
  if (isTransportFollowMessage(error)) return true;
29741
29826
  const http = followHttpDetails(error);
@@ -29800,14 +29885,14 @@ async function runInboxFollow(options) {
29800
29885
  let timer2;
29801
29886
  let onAbort;
29802
29887
  try {
29803
- await new Promise((resolve2) => {
29888
+ await new Promise((resolve3) => {
29804
29889
  let settled = false;
29805
29890
  const finish = () => {
29806
29891
  if (settled) return;
29807
29892
  settled = true;
29808
29893
  if (timer2 !== void 0) clearTimeout(timer2);
29809
29894
  if (onAbort && abort) abort.removeEventListener("abort", onAbort);
29810
- resolve2();
29895
+ resolve3();
29811
29896
  };
29812
29897
  if (abort) {
29813
29898
  if (abort.aborted) {
@@ -30026,9 +30111,8 @@ function parseCursor(raw, workspaceId2, principalId) {
30026
30111
  throw new Error("stored arrival cursor is malformed");
30027
30112
  }
30028
30113
  const row = value;
30029
- const keys = Object.keys(row).sort();
30030
30114
  const cursor = row.cursor;
30031
- if (keys.join(",") !== "cursor,principal_id,version,workspace_id" || row.version !== 1 || row.workspace_id !== workspaceId2.toLowerCase() || row.principal_id !== principalId.toLowerCase() || !(cursor === null || typeof cursor === "object" && !Array.isArray(cursor) && Object.keys(cursor).sort().join(",") === "created_at,id" && typeof cursor.created_at === "string" && Number.isFinite(Date.parse(cursor.created_at)) && typeof cursor.id === "string" && UUID_RE10.test(cursor.id))) {
30115
+ if (row.version !== 1 || row.workspace_id !== workspaceId2.toLowerCase() || row.principal_id !== principalId.toLowerCase() || !(cursor === null || typeof cursor === "object" && !Array.isArray(cursor) && typeof cursor.created_at === "string" && Number.isFinite(Date.parse(cursor.created_at)) && typeof cursor.id === "string" && UUID_RE10.test(cursor.id))) {
30032
30116
  throw new Error("stored arrival cursor is malformed");
30033
30117
  }
30034
30118
  if (cursor === null) return null;
@@ -30095,7 +30179,7 @@ function notifyWriteError(error) {
30095
30179
  return error.code === "EPIPE" ? new NotifyStdoutClosedError() : error;
30096
30180
  }
30097
30181
  async function writeArrivalMonitorLine(line, stream2 = process.stdout) {
30098
- await new Promise((resolve2, reject) => {
30182
+ await new Promise((resolve3, reject) => {
30099
30183
  let settled = false;
30100
30184
  const finish = (error) => {
30101
30185
  if (settled) return;
@@ -30105,7 +30189,7 @@ async function writeArrivalMonitorLine(line, stream2 = process.stdout) {
30105
30189
  reject(notifyWriteError(error));
30106
30190
  } else {
30107
30191
  stream2.off("error", onError);
30108
- resolve2();
30192
+ resolve3();
30109
30193
  }
30110
30194
  };
30111
30195
  const onError = (error) => finish(error);
@@ -30140,15 +30224,15 @@ async function runArrivalWatch(options) {
30140
30224
  await options.sleep(ms);
30141
30225
  return;
30142
30226
  }
30143
- await new Promise((resolve2) => {
30227
+ await new Promise((resolve3) => {
30144
30228
  let timer2;
30145
30229
  const finish = () => {
30146
30230
  if (timer2 !== void 0) clearTimeout(timer2);
30147
30231
  options.signal?.removeEventListener("abort", finish);
30148
- resolve2();
30232
+ resolve3();
30149
30233
  };
30150
30234
  if (cancelled() || ms <= 0) {
30151
- resolve2();
30235
+ resolve3();
30152
30236
  return;
30153
30237
  }
30154
30238
  options.signal?.addEventListener("abort", finish, { once: true });
@@ -30755,11 +30839,7 @@ function signalReceiptJsonPayload(report, nowMs = Date.now()) {
30755
30839
  var import_node_child_process3 = require("node:child_process");
30756
30840
  var import_node_crypto12 = require("node:crypto");
30757
30841
 
30758
- // src/host/stderr-tail.ts
30759
- var RING_CAPACITY_BYTES = 4096;
30760
- var TAIL_MAX_CHARS = 2048;
30761
- var STDERR_EXIT_GRACE_MS = 100;
30762
- var STDERR_READABLE_END_GRACE_MS = STDERR_EXIT_GRACE_MS + 50;
30842
+ // src/host/credential-redaction.ts
30763
30843
  var EXOTIC_SEPARATORS = "\\u00a0\\u1680\\u2000-\\u200d\\u2028\\u2029\\u202a-\\u202e\\u2060\\u2066-\\u2069\\u202f\\u205f\\u3000\\ufeff";
30764
30844
  var SEPARATOR_CLASS_SOURCE = "\\t\\n\\x0b\\f\\r " + EXOTIC_SEPARATORS;
30765
30845
  var ANSI_ESCAPE_GLOBAL_RE2 = new RegExp("\\u001b\\[[0-?]*[ -\\/]*[@-~]", "g");
@@ -30771,8 +30851,17 @@ var CREDENTIAL_PREFIX_RE = new RegExp(
30771
30851
  `swm_(?:agt|inv|cap)_[^${SEPARATOR_CLASS_SOURCE}]*`,
30772
30852
  "gi"
30773
30853
  );
30854
+ function redactCredentialText(value) {
30855
+ return value.replace(ANSI_ESCAPE_GLOBAL_RE2, "").replace(CONTROL_AND_SEPARATOR_STRIP_RE, "").replace(CREDENTIAL_PREFIX_RE, "[redacted-credential]");
30856
+ }
30857
+
30858
+ // src/host/stderr-tail.ts
30859
+ var RING_CAPACITY_BYTES = 4096;
30860
+ var TAIL_MAX_CHARS = 2048;
30861
+ var STDERR_EXIT_GRACE_MS = 100;
30862
+ var STDERR_READABLE_END_GRACE_MS = STDERR_EXIT_GRACE_MS + 50;
30774
30863
  function sanitizeStderrTail(raw) {
30775
- return raw.replace(ANSI_ESCAPE_GLOBAL_RE2, "").replace(CONTROL_AND_SEPARATOR_STRIP_RE, "").replace(CREDENTIAL_PREFIX_RE, "[redacted-credential]").slice(-TAIL_MAX_CHARS).trim();
30864
+ return redactCredentialText(raw).slice(-TAIL_MAX_CHARS).trim();
30776
30865
  }
30777
30866
  function attachStderrTailRing(stderr) {
30778
30867
  const chunks = [];
@@ -30984,7 +31073,7 @@ function permissionDecisionToResult(decision) {
30984
31073
  var SECRET_VALUE_RE = /(?:(?:api[_-]?key|token|secret|password|authorization|bearer)\s*[:=]\s*)(["']?)([^\s"'\\]{8,})\1/gi;
30985
31074
  var JWT_RE = /\beyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\b/g;
30986
31075
  function redactString(value) {
30987
- return value.replace(SECRET_VALUE_RE, (_m, q) => `redacted=${q}***${q}`).replace(JWT_RE, "[redacted-jwt]");
31076
+ return redactCredentialText(value).replace(SECRET_VALUE_RE, (_m, q) => `redacted=${q}***${q}`).replace(JWT_RE, "[redacted-jwt]");
30988
31077
  }
30989
31078
  function redactUnknown(value, depth = 0) {
30990
31079
  if (depth > 6) return "[truncated]";
@@ -31100,12 +31189,14 @@ var AcpVersionBelowFloorError = class extends AcpVersionError {
31100
31189
  actual;
31101
31190
  };
31102
31191
  var AcpPermissionCanaryError = class extends AcpHostError {
31103
- constructor(message, reasonCode = null) {
31192
+ constructor(message, reasonCode = null, minimumRequiredVersion = null) {
31104
31193
  super("permission_canary_failed", message);
31105
31194
  this.reasonCode = reasonCode;
31195
+ this.minimumRequiredVersion = minimumRequiredVersion;
31106
31196
  this.name = "AcpPermissionCanaryError";
31107
31197
  }
31108
31198
  reasonCode;
31199
+ minimumRequiredVersion;
31109
31200
  };
31110
31201
  var AcpPromptsBlockedError = class extends AcpHostError {
31111
31202
  constructor() {
@@ -31205,12 +31296,12 @@ var AcpTransport = class extends import_node_events.EventEmitter {
31205
31296
  method,
31206
31297
  ...params !== void 0 ? { params } : {}
31207
31298
  };
31208
- return new Promise((resolve2, reject) => {
31299
+ return new Promise((resolve3, reject) => {
31209
31300
  const timer2 = setTimeout(() => {
31210
31301
  this.pending.delete(key2);
31211
31302
  reject(new AcpTimeoutError(`ACP request timed out: ${method}`));
31212
31303
  }, timeoutMs ?? this.requestTimeoutMs);
31213
- this.pending.set(key2, { resolve: resolve2, reject, timer: timer2, method });
31304
+ this.pending.set(key2, { resolve: resolve3, reject, timer: timer2, method });
31214
31305
  try {
31215
31306
  this.writeFrame(frame);
31216
31307
  } catch (err) {
@@ -32215,7 +32306,7 @@ async function assertOpenCodeVersionFloor(executable, options) {
32215
32306
  const lastMeasuredVersion = options?.lastMeasuredVersion ?? OPENCODE_LAST_MEASURED_VERSION;
32216
32307
  const timeoutMs = options?.timeoutMs ?? ACP_VERSION_CHECK_TIMEOUT_MS;
32217
32308
  const env = sanitizeChildEnv(options?.env ?? process.env);
32218
- const stdout = await new Promise((resolve2, reject) => {
32309
+ const stdout = await new Promise((resolve3, reject) => {
32219
32310
  (0, import_node_child_process3.execFile)(
32220
32311
  executable,
32221
32312
  ["--version"],
@@ -32229,7 +32320,7 @@ async function assertOpenCodeVersionFloor(executable, options) {
32229
32320
  );
32230
32321
  return;
32231
32322
  }
32232
- resolve2(out);
32323
+ resolve3(out);
32233
32324
  }
32234
32325
  );
32235
32326
  });
@@ -32414,7 +32505,7 @@ async function assertOpenCodeEffectiveConfig(options) {
32414
32505
  `,
32415
32506
  { mode: 384 }
32416
32507
  );
32417
- const stdout = await new Promise((resolve2, reject) => {
32508
+ const stdout = await new Promise((resolve3, reject) => {
32418
32509
  (0, import_node_child_process3.execFile)(
32419
32510
  options.executable,
32420
32511
  ["debug", "config", "--pure"],
@@ -32434,7 +32525,7 @@ async function assertOpenCodeEffectiveConfig(options) {
32434
32525
  );
32435
32526
  return;
32436
32527
  }
32437
- resolve2(out);
32528
+ resolve3(out);
32438
32529
  }
32439
32530
  );
32440
32531
  });
@@ -32553,11 +32644,11 @@ function waitForChildExit(child, timeoutMs) {
32553
32644
  if (child.exitCode !== null || child.signalCode !== null) {
32554
32645
  return Promise.resolve();
32555
32646
  }
32556
- return new Promise((resolve2) => {
32557
- const timer2 = setTimeout(() => resolve2(), timeoutMs);
32647
+ return new Promise((resolve3) => {
32648
+ const timer2 = setTimeout(() => resolve3(), timeoutMs);
32558
32649
  child.once("exit", () => {
32559
32650
  clearTimeout(timer2);
32560
- resolve2();
32651
+ resolve3();
32561
32652
  });
32562
32653
  });
32563
32654
  }
@@ -32698,6 +32789,7 @@ async function openOpenCodeAcpSession(options) {
32698
32789
 
32699
32790
  // src/host/claude.ts
32700
32791
  var import_node_child_process4 = require("node:child_process");
32792
+ var import_node_module = require("node:module");
32701
32793
  var import_node_fs4 = require("node:fs");
32702
32794
  var import_node_path7 = require("node:path");
32703
32795
  var CHILD_EXIT_WAIT_MS2 = 3e3;
@@ -32808,11 +32900,56 @@ function parseClaudeVersionOutput(stdout) {
32808
32900
  function parseClaudeCodeVersionOutput(stdout) {
32809
32901
  return parseProviderVersionOutput(stdout, /\bClaude Code\b/i, false);
32810
32902
  }
32903
+ function semanticVersion(value) {
32904
+ if (typeof value !== "string") return null;
32905
+ return parseProviderVersionOutput(`${value}
32906
+ `, /\bnever-a-product-name\b/i);
32907
+ }
32908
+ function readPackageAtOrAbove(entrypoint, expectedName) {
32909
+ let directory = (0, import_node_path7.dirname)(entrypoint);
32910
+ for (let depth = 0; depth < 5; depth += 1) {
32911
+ const path = (0, import_node_path7.join)(directory, "package.json");
32912
+ try {
32913
+ const row = JSON.parse((0, import_node_fs4.readFileSync)(path, "utf8"));
32914
+ if (row && typeof row === "object" && !Array.isArray(row) && row.name === expectedName) {
32915
+ return { path, row };
32916
+ }
32917
+ } catch {
32918
+ }
32919
+ const parent = (0, import_node_path7.dirname)(directory);
32920
+ if (parent === directory) break;
32921
+ directory = parent;
32922
+ }
32923
+ return null;
32924
+ }
32925
+ function measureClaudeBundleVersions(executable) {
32926
+ const adapter = readPackageAtOrAbove(
32927
+ executable,
32928
+ "@agentclientprotocol/claude-agent-acp"
32929
+ );
32930
+ if (!adapter) return { agentSdkVersion: null, claudeCodeVersion: null };
32931
+ try {
32932
+ const sdkEntrypoint = (0, import_node_module.createRequire)(adapter.path).resolve(
32933
+ "@anthropic-ai/claude-agent-sdk"
32934
+ );
32935
+ const sdk = readPackageAtOrAbove(
32936
+ sdkEntrypoint,
32937
+ "@anthropic-ai/claude-agent-sdk"
32938
+ );
32939
+ if (!sdk) return { agentSdkVersion: null, claudeCodeVersion: null };
32940
+ return {
32941
+ agentSdkVersion: semanticVersion(sdk.row.version),
32942
+ claudeCodeVersion: semanticVersion(sdk.row.claudeCodeVersion)
32943
+ };
32944
+ } catch {
32945
+ return { agentSdkVersion: null, claudeCodeVersion: null };
32946
+ }
32947
+ }
32811
32948
  async function readClaudeVersionOutput(executable, options) {
32812
32949
  const timeoutMs = options?.timeoutMs ?? ACP_VERSION_CHECK_TIMEOUT_MS;
32813
32950
  const env = options?.env ?? sanitizeChildEnv(process.env);
32814
32951
  const launch = buildClaudeLaunch(executable, ["--version"], options?.platform);
32815
- return await new Promise((resolve2, reject) => {
32952
+ return await new Promise((resolve3, reject) => {
32816
32953
  (0, import_node_child_process4.execFile)(
32817
32954
  launch.command,
32818
32955
  launch.args,
@@ -32826,29 +32963,26 @@ async function readClaudeVersionOutput(executable, options) {
32826
32963
  );
32827
32964
  return;
32828
32965
  }
32829
- resolve2(out);
32966
+ resolve3(out);
32830
32967
  }
32831
32968
  );
32832
32969
  });
32833
32970
  }
32834
- async function assertClaudeVersionFloor(executable, options) {
32835
- const minimumVersion = options?.minimumVersion ?? CLAUDE_ACP_MIN_VERSION;
32836
- const lastMeasuredVersion = options?.lastMeasuredVersion ?? CLAUDE_ACP_LAST_MEASURED_VERSION;
32837
- const stdout = await readClaudeVersionOutput(executable, options);
32838
- const version3 = parseClaudeVersionOutput(stdout);
32839
- if (!version3) {
32840
- throw new AcpVersionParseError(
32841
- `could not parse claude-agent-acp version from: ${stdout.trim().slice(0, 200)}`
32842
- );
32843
- }
32844
- assertProviderVersionFloor({
32845
- provider: "claude-agent-acp",
32846
- version: version3,
32847
- minimumVersion,
32848
- lastMeasuredVersion,
32849
- ...options?.onNewerVersion ? { onNewerVersion: options.onNewerVersion } : {}
32850
- });
32851
- return version3;
32971
+ async function inspectClaudeBridgeExecutable(executable = "claude-agent-acp", options) {
32972
+ const resolved = resolveClaudeExecutable(
32973
+ executable,
32974
+ options?.pathEnv,
32975
+ options?.platform
32976
+ );
32977
+ const output = await readClaudeVersionOutput(resolved, options);
32978
+ const bundle = measureClaudeBundleVersions(resolved);
32979
+ return {
32980
+ executable: resolved,
32981
+ providerVersion: parseClaudeVersionOutput(output),
32982
+ lastMeasuredVersion: CLAUDE_ACP_LAST_MEASURED_VERSION,
32983
+ bundledAgentSdkVersion: bundle.agentSdkVersion,
32984
+ bundledClaudeCodeVersion: bundle.claudeCodeVersion
32985
+ };
32852
32986
  }
32853
32987
  function buildClaudeAcpArgs() {
32854
32988
  return [];
@@ -32864,11 +32998,11 @@ function waitForChildExit2(child, timeoutMs) {
32864
32998
  if (child.exitCode !== null || child.signalCode !== null) {
32865
32999
  return Promise.resolve();
32866
33000
  }
32867
- return new Promise((resolve2) => {
32868
- const timer2 = setTimeout(resolve2, timeoutMs);
33001
+ return new Promise((resolve3) => {
33002
+ const timer2 = setTimeout(resolve3, timeoutMs);
32869
33003
  child.once("exit", () => {
32870
33004
  clearTimeout(timer2);
32871
- resolve2();
33005
+ resolve3();
32872
33006
  });
32873
33007
  });
32874
33008
  }
@@ -32913,29 +33047,57 @@ async function openClaudeAcpSession(options) {
32913
33047
  let executable;
32914
33048
  let env = baseEnv;
32915
33049
  let claudeCodeExecutable;
33050
+ let providerVersion;
33051
+ let bundleVersions = {
33052
+ agentSdkVersion: null,
33053
+ claudeCodeVersion: null
33054
+ };
33055
+ const reportRuntime = (resolved, version3) => {
33056
+ bundleVersions = measureClaudeBundleVersions(resolved);
33057
+ options.onRuntimeNotice?.({
33058
+ executable: resolved,
33059
+ providerVersion: version3,
33060
+ lastMeasuredVersion: CLAUDE_ACP_LAST_MEASURED_VERSION,
33061
+ bundledAgentSdkVersion: bundleVersions.agentSdkVersion,
33062
+ bundledClaudeCodeVersion: bundleVersions.claudeCodeVersion
33063
+ });
33064
+ };
33065
+ const admitBridgeVersion = (resolved, version3) => {
33066
+ providerVersion = version3;
33067
+ reportRuntime(resolved, version3);
33068
+ assertProviderVersionFloor({
33069
+ provider: "claude-agent-acp",
33070
+ version: version3,
33071
+ minimumVersion: CLAUDE_ACP_MIN_VERSION,
33072
+ lastMeasuredVersion: CLAUDE_ACP_LAST_MEASURED_VERSION,
33073
+ ...options.onVersionNotice ? { onNewerVersion: options.onVersionNotice } : {}
33074
+ });
33075
+ };
32916
33076
  if (requestedExecutable) {
32917
33077
  const output = await readClaudeVersionOutput(requestedExecutable, {
32918
33078
  env: baseEnv
32919
33079
  });
32920
33080
  const bridgeVersion = parseClaudeVersionOutput(output);
32921
33081
  if (bridgeVersion) {
32922
- assertProviderVersionFloor({
32923
- provider: "claude-agent-acp",
32924
- version: bridgeVersion,
32925
- minimumVersion: CLAUDE_ACP_MIN_VERSION,
32926
- lastMeasuredVersion: CLAUDE_ACP_LAST_MEASURED_VERSION,
32927
- ...options.onVersionNotice ? { onNewerVersion: options.onVersionNotice } : {}
32928
- });
32929
33082
  executable = requestedExecutable;
33083
+ admitBridgeVersion(executable, bridgeVersion);
32930
33084
  } else if (parseClaudeCodeVersionOutput(output)) {
32931
33085
  claudeCodeExecutable = requestedExecutable;
32932
33086
  executable = resolvePackagedClaudeBridge(resolvedPathEnv);
32933
33087
  env = buildClaudeChildEnv(parentEnv, claudeCodeExecutable);
32934
- await assertClaudeVersionFloor(executable, {
32935
- env,
32936
- ...options.onVersionNotice ? { onNewerVersion: options.onVersionNotice } : {}
33088
+ const bridgeOutput = await readClaudeVersionOutput(executable, {
33089
+ env
32937
33090
  });
33091
+ const packagedVersion = parseClaudeVersionOutput(bridgeOutput);
33092
+ if (!packagedVersion) {
33093
+ reportRuntime(executable, null);
33094
+ throw new AcpVersionParseError(
33095
+ `could not parse claude-agent-acp version from: ${bridgeOutput.trim().slice(0, 200)}`
33096
+ );
33097
+ }
33098
+ admitBridgeVersion(executable, packagedVersion);
32938
33099
  } else {
33100
+ reportRuntime(requestedExecutable, null);
32939
33101
  throw new AcpVersionError(
32940
33102
  `could not identify Claude executable from: ${output.trim().slice(0, 200)}`
32941
33103
  );
@@ -32946,10 +33108,19 @@ async function openClaudeAcpSession(options) {
32946
33108
  resolvedPathEnv
32947
33109
  );
32948
33110
  if (!options.skipVersionCheck) {
32949
- await assertClaudeVersionFloor(executable, {
32950
- env: baseEnv,
32951
- ...options.onVersionNotice ? { onNewerVersion: options.onVersionNotice } : {}
33111
+ const output = await readClaudeVersionOutput(executable, {
33112
+ env: baseEnv
32952
33113
  });
33114
+ const version3 = parseClaudeVersionOutput(output);
33115
+ if (!version3) {
33116
+ reportRuntime(executable, null);
33117
+ throw new AcpVersionParseError(
33118
+ `could not parse claude-agent-acp version from: ${output.trim().slice(0, 200)}`
33119
+ );
33120
+ }
33121
+ admitBridgeVersion(executable, version3);
33122
+ } else {
33123
+ reportRuntime(executable, null);
32953
33124
  }
32954
33125
  }
32955
33126
  if (options.signal?.aborted) {
@@ -33041,7 +33212,17 @@ async function openClaudeAcpSession(options) {
33041
33212
  })();
33042
33213
  return closePromise;
33043
33214
  };
33044
- return { session, child, executable, args, env, close };
33215
+ return {
33216
+ session,
33217
+ child,
33218
+ executable,
33219
+ args,
33220
+ env,
33221
+ ...providerVersion ? { providerVersion } : {},
33222
+ ...bundleVersions.agentSdkVersion ? { bundledAgentSdkVersion: bundleVersions.agentSdkVersion } : {},
33223
+ ...bundleVersions.claudeCodeVersion ? { bundledClaudeCodeVersion: bundleVersions.claudeCodeVersion } : {},
33224
+ close
33225
+ };
33045
33226
  } catch (error) {
33046
33227
  removeAbortListener();
33047
33228
  transport.close();
@@ -33141,7 +33322,7 @@ async function assertCodexVersionFloor(executable, options) {
33141
33322
  const timeoutMs = options?.timeoutMs ?? ACP_VERSION_CHECK_TIMEOUT_MS;
33142
33323
  const env = options?.env ?? sanitizeChildEnv(process.env);
33143
33324
  const launch = buildCodexLaunch(executable, ["--version"], options?.platform);
33144
- const stdout = await new Promise((resolve2, reject) => {
33325
+ const stdout = await new Promise((resolve3, reject) => {
33145
33326
  (0, import_node_child_process5.execFile)(
33146
33327
  launch.command,
33147
33328
  launch.args,
@@ -33155,7 +33336,7 @@ async function assertCodexVersionFloor(executable, options) {
33155
33336
  );
33156
33337
  return;
33157
33338
  }
33158
- resolve2(out);
33339
+ resolve3(out);
33159
33340
  }
33160
33341
  );
33161
33342
  });
@@ -33195,11 +33376,11 @@ function waitForChildExit3(child, timeoutMs) {
33195
33376
  if (child.exitCode !== null || child.signalCode !== null) {
33196
33377
  return Promise.resolve();
33197
33378
  }
33198
- return new Promise((resolve2) => {
33199
- const timer2 = setTimeout(resolve2, timeoutMs);
33379
+ return new Promise((resolve3) => {
33380
+ const timer2 = setTimeout(resolve3, timeoutMs);
33200
33381
  child.once("exit", () => {
33201
33382
  clearTimeout(timer2);
33202
- resolve2();
33383
+ resolve3();
33203
33384
  });
33204
33385
  });
33205
33386
  }
@@ -33893,6 +34074,18 @@ var V1_EFFECT_KEYS = /* @__PURE__ */ new Set([
33893
34074
  "updatedAt"
33894
34075
  ]);
33895
34076
  var V2_EFFECT_KEYS = /* @__PURE__ */ new Set([...V1_EFFECT_KEYS, "signalKind"]);
34077
+ var EFFECT_SENSITIVE_KEYS = /* @__PURE__ */ new Set([
34078
+ "lease_id",
34079
+ "leaseId",
34080
+ "listenerBearer",
34081
+ "bearer",
34082
+ "token",
34083
+ "prompt",
34084
+ "ackCommandId",
34085
+ "ack_command_id",
34086
+ "claimCommandId",
34087
+ "claim_command_id"
34088
+ ]);
33896
34089
  function defaultListenerStateDirectory() {
33897
34090
  return process.env.XDG_STATE_HOME ? (0, import_node_path9.join)(process.env.XDG_STATE_HOME, "cswarm", "listeners") : (0, import_node_path9.join)((0, import_node_os6.homedir)(), ".cswarm", "listeners");
33898
34091
  }
@@ -33911,9 +34104,9 @@ function integer(value) {
33911
34104
  function nullableString2(value, max) {
33912
34105
  return value === null || typeof value === "string" && value.length <= max;
33913
34106
  }
33914
- function rejectUnknownKeys(row, allowed) {
34107
+ function rejectSensitiveKeys(row) {
33915
34108
  for (const key2 of Object.keys(row)) {
33916
- if (!allowed.has(key2)) {
34109
+ if (EFFECT_SENSITIVE_KEYS.has(key2)) {
33917
34110
  throw new Error("stored listener effect is malformed");
33918
34111
  }
33919
34112
  }
@@ -33929,17 +34122,16 @@ function parseListenerEffectRecord(raw, expectedId) {
33929
34122
  throw new Error("stored listener effect is malformed");
33930
34123
  }
33931
34124
  const row = value;
34125
+ rejectSensitiveKeys(row);
33932
34126
  if (typeof row.version !== "number" || row.version !== 1 && row.version !== 2 || typeof row.signalId !== "string" || row.signalId.toLowerCase() !== expectedId || !UUID_RE13.test(row.signalId)) {
33933
34127
  throw new Error("stored listener effect is malformed");
33934
34128
  }
33935
34129
  if (row.version === 1) {
33936
- rejectUnknownKeys(row, V1_EFFECT_KEYS);
33937
34130
  if ("signalKind" in row || row.state === "observed" || row.state === "routed_main") {
33938
34131
  throw new Error("stored listener effect is malformed");
33939
34132
  }
33940
34133
  return upcastV1Ask(row);
33941
34134
  }
33942
- rejectUnknownKeys(row, V2_EFFECT_KEYS);
33943
34135
  return parseV2Record(row);
33944
34136
  }
33945
34137
  function upcastV1Ask(row) {
@@ -34181,7 +34373,7 @@ async function assertGrokVersionFloor(executable, options) {
34181
34373
  const minimumVersion = options?.minimumVersion ?? GROK_MIN_VERSION;
34182
34374
  const lastMeasuredVersion = options?.lastMeasuredVersion ?? GROK_LAST_MEASURED_VERSION;
34183
34375
  const timeoutMs = options?.timeoutMs ?? ACP_VERSION_CHECK_TIMEOUT_MS;
34184
- const stdout = await new Promise((resolve2, reject) => {
34376
+ const stdout = await new Promise((resolve3, reject) => {
34185
34377
  (0, import_node_child_process6.execFile)(
34186
34378
  executable,
34187
34379
  ["--version"],
@@ -34195,7 +34387,7 @@ async function assertGrokVersionFloor(executable, options) {
34195
34387
  );
34196
34388
  return;
34197
34389
  }
34198
- resolve2(out);
34390
+ resolve3(out);
34199
34391
  }
34200
34392
  );
34201
34393
  });
@@ -34238,11 +34430,11 @@ function waitForChildExit4(child, timeoutMs) {
34238
34430
  if (child.exitCode !== null || child.signalCode !== null) {
34239
34431
  return Promise.resolve();
34240
34432
  }
34241
- return new Promise((resolve2) => {
34242
- const timer2 = setTimeout(resolve2, timeoutMs);
34433
+ return new Promise((resolve3) => {
34434
+ const timer2 = setTimeout(resolve3, timeoutMs);
34243
34435
  child.once("exit", () => {
34244
34436
  clearTimeout(timer2);
34245
- resolve2();
34437
+ resolve3();
34246
34438
  });
34247
34439
  });
34248
34440
  }
@@ -34392,6 +34584,7 @@ var GrokListenerModel = class {
34392
34584
  ...this.options.effort ? { effort: this.options.effort } : {},
34393
34585
  ...this.options.env ? { env: this.options.env } : {},
34394
34586
  ...this.options.onVersionNotice ? { onVersionNotice: this.options.onVersionNotice } : {},
34587
+ ...this.options.events ? { events: this.options.events } : {},
34395
34588
  ...this.options.onWorkerStderrTail ? { onStderrTail: this.options.onWorkerStderrTail } : {},
34396
34589
  clientName: "cswarm-listener"
34397
34590
  });
@@ -34652,10 +34845,10 @@ var OpenCodeListenerModel = class {
34652
34845
  try {
34653
34846
  await Promise.race([
34654
34847
  entry.settlePromise,
34655
- new Promise((resolve2) => {
34848
+ new Promise((resolve3) => {
34656
34849
  entry.timer = setTimeout(() => {
34657
34850
  timedOut = true;
34658
- resolve2();
34851
+ resolve3();
34659
34852
  }, this.pendingOpenWaitMs);
34660
34853
  })
34661
34854
  ]);
@@ -34763,10 +34956,10 @@ var OpenCodeListenerModel = class {
34763
34956
  });
34764
34957
  this.workerHome = home;
34765
34958
  let markSettled;
34766
- const settlePromise = new Promise((resolve2, reject) => {
34959
+ const settlePromise = new Promise((resolve3, reject) => {
34767
34960
  markSettled = (err) => {
34768
34961
  if (err) reject(err);
34769
- else resolve2();
34962
+ else resolve3();
34770
34963
  };
34771
34964
  });
34772
34965
  void settlePromise.catch(() => void 0);
@@ -34832,6 +35025,7 @@ var OpenCodeListenerModel = class {
34832
35025
  ...this.options.model ? { model: this.options.model } : {},
34833
35026
  ...this.options.env ? { env: this.options.env } : {},
34834
35027
  ...this.options.onVersionNotice ? { onVersionNotice: this.options.onVersionNotice } : {},
35028
+ ...this.options.events ? { events: this.options.events } : {},
34835
35029
  ...this.options.allowMissingAuth === true ? { allowMissingAuth: true } : {},
34836
35030
  ...this.options.onWorkerStderrTail ? { onStderrTail: this.options.onWorkerStderrTail } : {},
34837
35031
  clientName: "cswarm-listener"
@@ -34935,6 +35129,35 @@ var import_node_crypto16 = require("node:crypto");
34935
35129
  var import_promises7 = require("node:fs/promises");
34936
35130
  var import_node_os8 = require("node:os");
34937
35131
  var import_node_path13 = require("node:path");
35132
+ var CLAUDE_CODE_VERSION_REQUIRED_RE = /\bClaude Code (\d+\.\d+\.\d+) does not support this model; version (\d+\.\d+\.\d+) or newer is required\b/;
35133
+ var CLAUDE_AUTH_FAILURE_RE = /\b(?:authentication failed|authentication required|not authenticated|OAuth (?:sign-in|login|token)|keychain\/OAuth|please (?:log|sign) in)\b/i;
35134
+ var CLAUDE_CANARY_TIMEOUT_RE = /^ACP request timed out: session\/prompt(?: \(failed \d+ attempts\))?$/;
35135
+ function classifyClaudeCanaryFailure(detail, typedReasonCode) {
35136
+ const recorded = detail?.trim() ?? "";
35137
+ const demanded = CLAUDE_CODE_VERSION_REQUIRED_RE.exec(recorded);
35138
+ if (demanded?.[2]) {
35139
+ return {
35140
+ code: "claude_bridge_version_required",
35141
+ minimumRequiredVersion: demanded[2]
35142
+ };
35143
+ }
35144
+ if (typedReasonCode === "claude_canary_timeout" || typedReasonCode === "timeout" || (typedReasonCode === null || typedReasonCode === void 0) && CLAUDE_CANARY_TIMEOUT_RE.test(recorded)) {
35145
+ return { code: "claude_canary_timeout", minimumRequiredVersion: null };
35146
+ }
35147
+ if (typedReasonCode === "claude_canary_auth_failed") {
35148
+ return { code: "claude_canary_auth_failed", minimumRequiredVersion: null };
35149
+ }
35150
+ if (typedReasonCode === "claude_bridge_version_required") {
35151
+ return {
35152
+ code: "claude_bridge_version_required",
35153
+ minimumRequiredVersion: demanded?.[2] ?? null
35154
+ };
35155
+ }
35156
+ if ((typedReasonCode === "rpc_error" || typedReasonCode === null || typedReasonCode === void 0) && CLAUDE_AUTH_FAILURE_RE.test(recorded)) {
35157
+ return { code: "claude_canary_auth_failed", minimumRequiredVersion: null };
35158
+ }
35159
+ return { code: "claude_canary_unknown", minimumRequiredVersion: null };
35160
+ }
34938
35161
  var ClaudeListenerClosedDuringOpen = class extends Error {
34939
35162
  constructor() {
34940
35163
  super("listener model closed while the Claude worker was opening");
@@ -35048,6 +35271,8 @@ var ClaudeListenerModel = class {
35048
35271
  ...this.options.executable ? { executable: this.options.executable } : {},
35049
35272
  ...this.options.env ? { env: this.options.env } : {},
35050
35273
  ...this.options.onVersionNotice ? { onVersionNotice: this.options.onVersionNotice } : {},
35274
+ ...this.options.onRuntimeNotice ? { onRuntimeNotice: this.options.onRuntimeNotice } : {},
35275
+ ...this.options.events ? { events: this.options.events } : {},
35051
35276
  signal: controller.signal,
35052
35277
  ...this.options.onWorkerStderrTail ? { onStderrTail: this.options.onWorkerStderrTail } : {},
35053
35278
  clientName: "cswarm-listener"
@@ -35076,6 +35301,7 @@ var ClaudeListenerModel = class {
35076
35301
  (0, import_node_os8.tmpdir)(),
35077
35302
  `cswarm-claude-permission-canary-${process.pid}-${(0, import_node_crypto16.randomUUID)()}`
35078
35303
  );
35304
+ let canaryError;
35079
35305
  let sentinelCreated = false;
35080
35306
  try {
35081
35307
  await handle.session.enablePromptsAfterCanary({
@@ -35083,6 +35309,8 @@ var ClaudeListenerModel = class {
35083
35309
  probeText: `Create the file ${sentinelPath} using the Write tool with content CSWARM_CANARY_NOOP. You must use the Write tool. Do nothing else.`,
35084
35310
  ...this.options.onCanaryAttempt ? { onAttempt: this.options.onCanaryAttempt } : {}
35085
35311
  });
35312
+ } catch (error) {
35313
+ canaryError = error;
35086
35314
  } finally {
35087
35315
  try {
35088
35316
  await (0, import_promises7.lstat)(sentinelPath);
@@ -35094,9 +35322,22 @@ var ClaudeListenerModel = class {
35094
35322
  }
35095
35323
  if (sentinelCreated) {
35096
35324
  throw new AcpPermissionCanaryError(
35097
- "Claude bridge wrote the permission canary sentinel before denial"
35325
+ "Claude bridge wrote the permission canary sentinel before denial",
35326
+ "claude_canary_write_not_blocked"
35098
35327
  );
35099
35328
  }
35329
+ if (canaryError instanceof AcpPermissionCanaryError) {
35330
+ const shape = classifyClaudeCanaryFailure(
35331
+ canaryError.message,
35332
+ canaryError.reasonCode
35333
+ );
35334
+ throw new AcpPermissionCanaryError(
35335
+ canaryError.message,
35336
+ shape.code,
35337
+ shape.minimumRequiredVersion
35338
+ );
35339
+ }
35340
+ if (canaryError !== void 0) throw canaryError;
35100
35341
  }
35101
35342
  };
35102
35343
 
@@ -35222,6 +35463,7 @@ var CodexListenerModel = class {
35222
35463
  ...this.options.executable ? { executable: this.options.executable } : {},
35223
35464
  ...this.options.env ? { env: this.options.env } : {},
35224
35465
  ...this.options.onVersionNotice ? { onVersionNotice: this.options.onVersionNotice } : {},
35466
+ ...this.options.events ? { events: this.options.events } : {},
35225
35467
  signal: controller.signal,
35226
35468
  ...this.options.onWorkerStderrTail ? { onStderrTail: this.options.onWorkerStderrTail } : {},
35227
35469
  clientName: "cswarm-listener"
@@ -35753,8 +35995,8 @@ var DeliveryCommandClient = class {
35753
35995
  const signal = deadlineController.signal;
35754
35996
  let onAbort = () => {
35755
35997
  };
35756
- const aborted = new Promise((resolve2) => {
35757
- onAbort = () => resolve2("timeout");
35998
+ const aborted = new Promise((resolve3) => {
35999
+ onAbort = () => resolve3("timeout");
35758
36000
  if (signal.aborted) {
35759
36001
  onAbort();
35760
36002
  } else {
@@ -35909,6 +36151,21 @@ var UUID_RE15 = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-
35909
36151
  var MAX_QUEUE_BYTES = 1024 * 1024;
35910
36152
  var QUEUE_FILE = "pending-for-main.json";
35911
36153
  var QUEUE_LOCK = "pending-for-main";
36154
+ var QUEUE_KEYS = /* @__PURE__ */ new Set(["version", "entries", "droppedCount"]);
36155
+ var ENTRY_KEYS = /* @__PURE__ */ new Set([
36156
+ "signalId",
36157
+ "workspaceId",
36158
+ "principalId",
36159
+ "fromId",
36160
+ "fromKind",
36161
+ "kind",
36162
+ "senderName",
36163
+ "body",
36164
+ "attachmentCount",
36165
+ "createdAt",
36166
+ "queuedAt",
36167
+ "observationPending"
36168
+ ]);
35912
36169
  var LISTENER_MAIN_QUEUE_MAX = 200;
35913
36170
  var LISTENER_DEFER_OVER_MIN = 1;
35914
36171
  var LISTENER_DEFER_OVER_MAX = 1e4;
@@ -35939,26 +36196,12 @@ function decideListenerRoute(route, threshold, bodyLength) {
35939
36196
  function checkedTimestamp2(value) {
35940
36197
  return typeof value === "string" && Number.isFinite(Date.parse(value));
35941
36198
  }
35942
- function parseEntry(value) {
36199
+ function parseEntry(value, rejectUnknownKeys) {
35943
36200
  if (!value || typeof value !== "object" || Array.isArray(value)) {
35944
36201
  throw new Error("stored pending-for-main entry is malformed");
35945
36202
  }
35946
36203
  const row = value;
35947
- const allowed = /* @__PURE__ */ new Set([
35948
- "signalId",
35949
- "workspaceId",
35950
- "principalId",
35951
- "fromId",
35952
- "fromKind",
35953
- "kind",
35954
- "senderName",
35955
- "body",
35956
- "attachmentCount",
35957
- "createdAt",
35958
- "queuedAt",
35959
- "observationPending"
35960
- ]);
35961
- if (Object.keys(row).some((key2) => !allowed.has(key2))) {
36204
+ if (rejectUnknownKeys && Object.keys(row).some((key2) => !ENTRY_KEYS.has(key2))) {
35962
36205
  throw new Error("stored pending-for-main entry is malformed");
35963
36206
  }
35964
36207
  if (typeof row.signalId !== "string" || !UUID_RE15.test(row.signalId) || typeof row.workspaceId !== "string" || !UUID_RE15.test(row.workspaceId) || typeof row.principalId !== "string" || !UUID_RE15.test(row.principalId) || typeof row.fromId !== "string" || !UUID_RE15.test(row.fromId) || row.fromKind !== "user" && row.fromKind !== "agent" || !(row.kind === void 0 || row.kind === "ask" || row.kind === "note") || !(row.senderName === null || typeof row.senderName === "string" && row.senderName.length <= 200) || typeof row.body !== "string" || row.body.length < 1 || !(row.attachmentCount === void 0 || typeof row.attachmentCount === "number" && Number.isSafeInteger(row.attachmentCount) && row.attachmentCount >= 1 && row.attachmentCount <= 8) || !checkedTimestamp2(row.createdAt) || !checkedTimestamp2(row.queuedAt) || !(row.observationPending === void 0 || row.observationPending === true)) {
@@ -35979,7 +36222,7 @@ function parseEntry(value) {
35979
36222
  ...row.observationPending === true ? { observationPending: true } : {}
35980
36223
  };
35981
36224
  }
35982
- function parseFile(raw) {
36225
+ function parseFile(raw, rejectUnknownKeys = false) {
35983
36226
  let value;
35984
36227
  try {
35985
36228
  value = JSON.parse(raw);
@@ -35990,12 +36233,10 @@ function parseFile(raw) {
35990
36233
  throw new Error("stored pending-for-main queue is malformed");
35991
36234
  }
35992
36235
  const row = value;
35993
- if (Object.keys(row).some(
35994
- (key2) => key2 !== "version" && key2 !== "entries" && key2 !== "droppedCount"
35995
- ) || row.version !== 1 || !Array.isArray(row.entries) || row.entries.length > LISTENER_MAIN_QUEUE_MAX || !(row.droppedCount === void 0 || typeof row.droppedCount === "number" && Number.isSafeInteger(row.droppedCount) && row.droppedCount >= 0)) {
36236
+ if (rejectUnknownKeys && Object.keys(row).some((key2) => !QUEUE_KEYS.has(key2)) || row.version !== 1 || !Array.isArray(row.entries) || row.entries.length > LISTENER_MAIN_QUEUE_MAX || !(row.droppedCount === void 0 || typeof row.droppedCount === "number" && Number.isSafeInteger(row.droppedCount) && row.droppedCount >= 0)) {
35996
36237
  throw new Error("stored pending-for-main queue is malformed");
35997
36238
  }
35998
- const entries = row.entries.map(parseEntry);
36239
+ const entries = row.entries.map((entry) => parseEntry(entry, rejectUnknownKeys));
35999
36240
  if (new Set(entries.map((entry) => entry.signalId)).size !== entries.length) {
36000
36241
  throw new Error("stored pending-for-main queue repeats a signal");
36001
36242
  }
@@ -36016,7 +36257,7 @@ var FilePendingMainQueue = class {
36016
36257
  return raw === null ? { version: 1, entries: [], droppedCount: 0 } : parseFile(raw);
36017
36258
  }
36018
36259
  async writeUnlocked(file) {
36019
- const canonical = parseFile(JSON.stringify(file));
36260
+ const canonical = parseFile(JSON.stringify(file), true);
36020
36261
  await writeSecureJsonFile(this.path, JSON.stringify(canonical));
36021
36262
  }
36022
36263
  async read() {
@@ -36030,7 +36271,7 @@ var FilePendingMainQueue = class {
36030
36271
  return { count: file.entries.length, droppedCount: file.droppedCount };
36031
36272
  }
36032
36273
  async enqueue(entry) {
36033
- const checked = parseEntry(entry);
36274
+ const checked = parseEntry(entry, true);
36034
36275
  return await withFileLock(this.directory, QUEUE_LOCK, async () => {
36035
36276
  const file = await this.readUnlocked();
36036
36277
  if (file.entries.some((item) => item.signalId === checked.signalId)) {
@@ -36089,7 +36330,7 @@ function pendingMainEntry(signal, principalId, provenance, now, options = {}) {
36089
36330
  createdAt: signal.created_at,
36090
36331
  queuedAt: new Date(now).toISOString(),
36091
36332
  ...options.observationPending ? { observationPending: true } : {}
36092
- });
36333
+ }, true);
36093
36334
  }
36094
36335
 
36095
36336
  // src/listener/runtime.ts
@@ -36102,6 +36343,7 @@ var LISTENER_REPLY_ONLY_MINIMUM_MS = SIGNAL_REQUEST_TIMEOUT_MS + LISTENER_ACK_ON
36102
36343
  var LISTENER_PROMPT_START_MINIMUM_MS = SIGNAL_READ_TIMEOUT_MS + ACP_DEFAULT_REQUEST_TIMEOUT_MS + LISTENER_REPLY_ONLY_MINIMUM_MS;
36103
36344
  var LISTENER_DELIVERY_RETRY_INITIAL_MS = 500;
36104
36345
  var LISTENER_DELIVERY_RETRY_MAX_MS = 3e4;
36346
+ var LISTENER_HOST_PORTS_PROBE_MS = 6e4;
36105
36347
  var UUID_RE16 = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
36106
36348
  var ListenerCapabilityError = class extends Error {
36107
36349
  code;
@@ -36234,12 +36476,12 @@ function eventTime(now) {
36234
36476
  }
36235
36477
  async function defaultSleep(ms, signal) {
36236
36478
  if (signal?.aborted) return;
36237
- await new Promise((resolve2) => {
36479
+ await new Promise((resolve3) => {
36238
36480
  let timer2;
36239
36481
  const finish = () => {
36240
36482
  if (timer2 !== void 0) clearTimeout(timer2);
36241
36483
  signal?.removeEventListener("abort", finish);
36242
- resolve2();
36484
+ resolve3();
36243
36485
  };
36244
36486
  signal?.addEventListener("abort", finish, { once: true });
36245
36487
  timer2 = setTimeout(finish, ms);
@@ -36536,6 +36778,8 @@ async function runListenerRuntime(options) {
36536
36778
  let ready = false;
36537
36779
  let deliveryMode = null;
36538
36780
  let readAttempt = 0;
36781
+ let readEpisodeStartedAtMs = null;
36782
+ let readEpisodeAttempts = 0;
36539
36783
  const onAbort = () => {
36540
36784
  options.model.cancel();
36541
36785
  };
@@ -36633,6 +36877,18 @@ async function runListenerRuntime(options) {
36633
36877
  }
36634
36878
  });
36635
36879
  requireCapabilities(page);
36880
+ if (ready && readEpisodeStartedAtMs !== null) {
36881
+ const recoveredAtMs = now();
36882
+ options.onEvent?.({
36883
+ type: "read_recovered",
36884
+ attempts: readEpisodeAttempts,
36885
+ durationMs: Math.max(0, recoveredAtMs - readEpisodeStartedAtMs),
36886
+ startedAt: new Date(readEpisodeStartedAtMs).toISOString(),
36887
+ ts: new Date(recoveredAtMs).toISOString()
36888
+ });
36889
+ readEpisodeStartedAtMs = null;
36890
+ readEpisodeAttempts = 0;
36891
+ }
36636
36892
  const nextMode = classifyDeliveryMode(page, durableConfigured);
36637
36893
  if (nextMode !== deliveryMode) {
36638
36894
  deliveryMode = nextMode;
@@ -36653,19 +36909,25 @@ async function runListenerRuntime(options) {
36653
36909
  stop = { reason: "credential", error: asError2(error) };
36654
36910
  break;
36655
36911
  }
36656
- if (isAbort2(error)) {
36657
- stop = { reason: "cancelled" };
36658
- break;
36659
- }
36660
- if (isRetryableFollowError(error)) {
36912
+ const failure = classifySignalReadFailure(error);
36913
+ if (isRetryableFollowError(error) || failure.code === "aborted" || failure.code === "host_ports_exhausted") {
36661
36914
  readAttempt += 1;
36662
- const delayMs = nextFollowBackoffMs(readAttempt, null, random);
36915
+ const delayMs = failure.code === "host_ports_exhausted" ? LISTENER_HOST_PORTS_PROBE_MS : nextFollowBackoffMs(readAttempt, null, random);
36663
36916
  if (ready) {
36917
+ const failedAtMs = now();
36918
+ if (readEpisodeStartedAtMs === null) {
36919
+ readEpisodeStartedAtMs = failedAtMs;
36920
+ readEpisodeAttempts = 0;
36921
+ }
36922
+ readEpisodeAttempts += 1;
36664
36923
  options.onEvent?.({
36665
36924
  type: "read_retry",
36666
36925
  attempt: readAttempt,
36926
+ episodeAttempt: readEpisodeAttempts,
36927
+ episodeStartedAt: new Date(readEpisodeStartedAtMs).toISOString(),
36928
+ failure,
36667
36929
  delayMs,
36668
- ts: eventTime(now)
36930
+ ts: new Date(failedAtMs).toISOString()
36669
36931
  });
36670
36932
  }
36671
36933
  await sleep2(delayMs, abort);
@@ -36688,6 +36950,7 @@ async function runListenerRuntime(options) {
36688
36950
  type: "ready",
36689
36951
  workspaceId: options.workspaceId,
36690
36952
  principalId: options.principalId,
36953
+ cadenceMs: pollMs,
36691
36954
  ts: eventTime(now)
36692
36955
  });
36693
36956
  if (options.declareModel !== void 0) {
@@ -37217,13 +37480,262 @@ async function runListenerRuntime(options) {
37217
37480
  return stop ?? { reason: "cancelled" };
37218
37481
  }
37219
37482
 
37483
+ // src/listener/read-health.ts
37484
+ var HOUR_MS = 60 * 6e4;
37485
+ var MINUTE_MS = 6e4;
37486
+ var HEALTH_WINDOW_MS = 24 * HOUR_MS;
37487
+ var LISTENER_READ_RETRY_HOUR_CAP = 25;
37488
+ var LISTENER_READ_RETRY_MINUTE_CAP = 61;
37489
+ var LISTENER_CLAIM_HOUR_CAP = 25;
37490
+ var LISTENER_THROUGHPUT_LAPSE_RATIO = 0.5;
37491
+ var FAILURE_CODES = /* @__PURE__ */ new Set([
37492
+ "http_status",
37493
+ "no_response",
37494
+ "body_timeout",
37495
+ "malformed_response",
37496
+ "aborted",
37497
+ "host_ports_exhausted",
37498
+ "unclassified"
37499
+ ]);
37500
+ function emptyListenerReadHealth() {
37501
+ return {
37502
+ currentEpisodeStartedAt: null,
37503
+ currentEpisodeAttempts: 0,
37504
+ currentReasonCode: null,
37505
+ currentHttpStatus: null,
37506
+ currentErrorConstructor: null,
37507
+ retryHours: [],
37508
+ retryMinutes: [],
37509
+ claimCadenceMs: null,
37510
+ claimHours: []
37511
+ };
37512
+ }
37513
+ function bucketStart(ts, sizeMs) {
37514
+ const time = Date.parse(ts);
37515
+ return new Date(Math.floor(time / sizeMs) * sizeMs).toISOString();
37516
+ }
37517
+ function trimNewest(rows3, cap) {
37518
+ return rows3.sort((left, right) => Date.parse(left.hourStart) - Date.parse(right.hourStart)).slice(-cap);
37519
+ }
37520
+ function recordRetryHour(rows3, ts, episodeStarted) {
37521
+ const hourStart = bucketStart(ts, HOUR_MS);
37522
+ const next = rows3.map((row) => ({ ...row }));
37523
+ const existing = next.find((row) => row.hourStart === hourStart);
37524
+ if (existing) {
37525
+ existing.retries += 1;
37526
+ if (episodeStarted) existing.episodes += 1;
37527
+ } else {
37528
+ next.push({
37529
+ hourStart,
37530
+ retries: 1,
37531
+ episodes: episodeStarted ? 1 : 0,
37532
+ longestEpisodeAttempts: 0,
37533
+ longestEpisodeDurationMs: 0
37534
+ });
37535
+ }
37536
+ return trimNewest(next, LISTENER_READ_RETRY_HOUR_CAP);
37537
+ }
37538
+ function recordRetryMinute(rows3, ts) {
37539
+ const minuteStart = bucketStart(ts, MINUTE_MS);
37540
+ const next = rows3.map((row) => ({ ...row }));
37541
+ const existing = next.find((row) => row.minuteStart === minuteStart);
37542
+ if (existing) {
37543
+ existing.retries += 1;
37544
+ } else {
37545
+ next.push({ minuteStart, retries: 1 });
37546
+ }
37547
+ return next.sort(
37548
+ (left, right) => Date.parse(left.minuteStart) - Date.parse(right.minuteStart)
37549
+ ).slice(-LISTENER_READ_RETRY_MINUTE_CAP);
37550
+ }
37551
+ function recordListenerReadRetry(health, input) {
37552
+ return {
37553
+ ...health,
37554
+ currentEpisodeStartedAt: input.episodeStartedAt,
37555
+ currentEpisodeAttempts: input.episodeAttempt,
37556
+ currentReasonCode: input.failure.code,
37557
+ currentHttpStatus: input.failure.httpStatus,
37558
+ currentErrorConstructor: input.failure.errorConstructor,
37559
+ retryHours: recordRetryHour(
37560
+ health.retryHours,
37561
+ input.ts,
37562
+ input.episodeAttempt === 1
37563
+ ),
37564
+ retryMinutes: recordRetryMinute(health.retryMinutes, input.ts)
37565
+ };
37566
+ }
37567
+ function recordListenerReadRecovery(health, input) {
37568
+ const hourStart = bucketStart(input.startedAt, HOUR_MS);
37569
+ const retryHours = health.retryHours.map((row) => ({ ...row }));
37570
+ const hour = retryHours.find((row) => row.hourStart === hourStart);
37571
+ if (hour) {
37572
+ if (input.durationMs > hour.longestEpisodeDurationMs || input.durationMs === hour.longestEpisodeDurationMs && input.attempts > hour.longestEpisodeAttempts) {
37573
+ hour.longestEpisodeAttempts = input.attempts;
37574
+ hour.longestEpisodeDurationMs = input.durationMs;
37575
+ }
37576
+ }
37577
+ return {
37578
+ ...health,
37579
+ currentEpisodeStartedAt: null,
37580
+ currentEpisodeAttempts: 0,
37581
+ currentReasonCode: null,
37582
+ currentHttpStatus: null,
37583
+ currentErrorConstructor: null,
37584
+ retryHours: trimNewest(retryHours, LISTENER_READ_RETRY_HOUR_CAP)
37585
+ };
37586
+ }
37587
+ function recordListenerClaimCadence(health, cadenceMs) {
37588
+ return { ...health, claimCadenceMs: cadenceMs };
37589
+ }
37590
+ function recordListenerClaim(health, ts) {
37591
+ const hourStart = bucketStart(ts, HOUR_MS);
37592
+ const claimHours = health.claimHours.map((row) => ({ ...row }));
37593
+ const hour = claimHours.find((row) => row.hourStart === hourStart);
37594
+ if (hour) hour.claims += 1;
37595
+ else claimHours.push({ hourStart, claims: 1 });
37596
+ return {
37597
+ ...health,
37598
+ claimHours: trimNewest(claimHours, LISTENER_CLAIM_HOUR_CAP)
37599
+ };
37600
+ }
37601
+ function hasExpectedKeys(value, expected, rejectUnknownKeys) {
37602
+ const actual = Object.keys(value);
37603
+ const allowed = new Set(expected);
37604
+ return expected.every((key2) => actual.includes(key2)) && (!rejectUnknownKeys || actual.every((key2) => allowed.has(key2)));
37605
+ }
37606
+ function validTimestamp(value) {
37607
+ return typeof value === "string" && Number.isFinite(Date.parse(value));
37608
+ }
37609
+ function validCount(value) {
37610
+ return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
37611
+ }
37612
+ function parseListenerReadHealth(value, rejectUnknownKeys = false) {
37613
+ if (!value || typeof value !== "object" || Array.isArray(value)) return null;
37614
+ const row = value;
37615
+ if (!hasExpectedKeys(row, [
37616
+ "currentEpisodeStartedAt",
37617
+ "currentEpisodeAttempts",
37618
+ "currentReasonCode",
37619
+ "currentHttpStatus",
37620
+ "currentErrorConstructor",
37621
+ "retryHours",
37622
+ "retryMinutes",
37623
+ "claimCadenceMs",
37624
+ "claimHours"
37625
+ ], rejectUnknownKeys)) return null;
37626
+ if (!(row.currentEpisodeStartedAt === null || validTimestamp(row.currentEpisodeStartedAt)) || !validCount(row.currentEpisodeAttempts) || !(row.currentReasonCode === null || typeof row.currentReasonCode === "string" && FAILURE_CODES.has(row.currentReasonCode)) || !(row.currentHttpStatus === null || typeof row.currentHttpStatus === "number" && Number.isSafeInteger(row.currentHttpStatus) && row.currentHttpStatus >= 100 && row.currentHttpStatus <= 599) || !(row.currentErrorConstructor === null || typeof row.currentErrorConstructor === "string" && /^[A-Za-z0-9_$-]{1,96}$/.test(row.currentErrorConstructor)) || !(row.claimCadenceMs === null || typeof row.claimCadenceMs === "number" && Number.isSafeInteger(row.claimCadenceMs) && row.claimCadenceMs >= 1) || !Array.isArray(row.retryHours) || row.retryHours.length > LISTENER_READ_RETRY_HOUR_CAP || !Array.isArray(row.retryMinutes) || row.retryMinutes.length > LISTENER_READ_RETRY_MINUTE_CAP || !Array.isArray(row.claimHours) || row.claimHours.length > LISTENER_CLAIM_HOUR_CAP) return null;
37627
+ if (row.currentEpisodeStartedAt === null !== (row.currentEpisodeAttempts === 0) || row.currentEpisodeStartedAt === null !== (row.currentReasonCode === null) || row.currentReasonCode === "http_status" !== (row.currentHttpStatus !== null) || row.currentReasonCode === "unclassified" !== (row.currentErrorConstructor !== null)) return null;
37628
+ for (const value2 of row.retryHours) {
37629
+ if (!value2 || typeof value2 !== "object" || Array.isArray(value2)) return null;
37630
+ const hour = value2;
37631
+ if (!hasExpectedKeys(hour, [
37632
+ "hourStart",
37633
+ "retries",
37634
+ "episodes",
37635
+ "longestEpisodeAttempts",
37636
+ "longestEpisodeDurationMs"
37637
+ ], rejectUnknownKeys) || !validTimestamp(hour.hourStart) || !validCount(hour.retries) || !validCount(hour.episodes) || !validCount(hour.longestEpisodeAttempts) || !validCount(hour.longestEpisodeDurationMs)) return null;
37638
+ }
37639
+ for (const value2 of row.retryMinutes) {
37640
+ if (!value2 || typeof value2 !== "object" || Array.isArray(value2)) return null;
37641
+ const minute = value2;
37642
+ if (!hasExpectedKeys(minute, ["minuteStart", "retries"], rejectUnknownKeys) || !validTimestamp(minute.minuteStart) || !validCount(minute.retries)) return null;
37643
+ }
37644
+ for (const value2 of row.claimHours) {
37645
+ if (!value2 || typeof value2 !== "object" || Array.isArray(value2)) return null;
37646
+ const hour = value2;
37647
+ if (!hasExpectedKeys(hour, ["hourStart", "claims"], rejectUnknownKeys) || !validTimestamp(hour.hourStart) || !validCount(hour.claims)) return null;
37648
+ }
37649
+ return {
37650
+ currentEpisodeStartedAt: row.currentEpisodeStartedAt,
37651
+ currentEpisodeAttempts: row.currentEpisodeAttempts,
37652
+ currentReasonCode: row.currentReasonCode,
37653
+ currentHttpStatus: row.currentHttpStatus,
37654
+ currentErrorConstructor: row.currentErrorConstructor,
37655
+ retryHours: row.retryHours.map((hour) => ({
37656
+ hourStart: hour.hourStart,
37657
+ retries: hour.retries,
37658
+ episodes: hour.episodes,
37659
+ longestEpisodeAttempts: hour.longestEpisodeAttempts,
37660
+ longestEpisodeDurationMs: hour.longestEpisodeDurationMs
37661
+ })),
37662
+ retryMinutes: row.retryMinutes.map((minute) => ({
37663
+ minuteStart: minute.minuteStart,
37664
+ retries: minute.retries
37665
+ })),
37666
+ claimCadenceMs: row.claimCadenceMs,
37667
+ claimHours: row.claimHours.map((hour) => ({
37668
+ hourStart: hour.hourStart,
37669
+ claims: hour.claims
37670
+ }))
37671
+ };
37672
+ }
37673
+ function summarizeListenerReadHealth(health, readyAt, nowMs) {
37674
+ const windowStart = nowMs - HEALTH_WINDOW_MS;
37675
+ const retryHours = health.retryHours.filter(
37676
+ (row) => Date.parse(row.hourStart) + HOUR_MS > windowStart && Date.parse(row.hourStart) <= nowMs
37677
+ );
37678
+ let episodesLast24h = retryHours.reduce((sum, row) => sum + row.episodes, 0);
37679
+ let longestEpisodeAttemptsLast24h = 0;
37680
+ let longestEpisodeDurationMsLast24h = 0;
37681
+ for (const row of retryHours) {
37682
+ if (row.longestEpisodeDurationMs > longestEpisodeDurationMsLast24h || row.longestEpisodeDurationMs === longestEpisodeDurationMsLast24h && row.longestEpisodeAttempts > longestEpisodeAttemptsLast24h) {
37683
+ longestEpisodeAttemptsLast24h = row.longestEpisodeAttempts;
37684
+ longestEpisodeDurationMsLast24h = row.longestEpisodeDurationMs;
37685
+ }
37686
+ }
37687
+ const currentStartedMs = health.currentEpisodeStartedAt === null ? null : Date.parse(health.currentEpisodeStartedAt);
37688
+ const currentEpisodeDurationMs = currentStartedMs === null ? null : Math.max(0, nowMs - currentStartedMs);
37689
+ if (currentStartedMs !== null && currentStartedMs >= windowStart && currentEpisodeDurationMs !== null && (currentEpisodeDurationMs > longestEpisodeDurationMsLast24h || currentEpisodeDurationMs === longestEpisodeDurationMsLast24h && health.currentEpisodeAttempts > longestEpisodeAttemptsLast24h)) {
37690
+ longestEpisodeAttemptsLast24h = health.currentEpisodeAttempts;
37691
+ longestEpisodeDurationMsLast24h = currentEpisodeDurationMs;
37692
+ }
37693
+ const rollingMinuteStart = Math.floor((nowMs - HOUR_MS) / MINUTE_MS) * MINUTE_MS;
37694
+ const retriesLastHour = health.retryMinutes.reduce((sum, row) => Date.parse(row.minuteStart) >= rollingMinuteStart && Date.parse(row.minuteStart) <= nowMs ? sum + row.retries : sum, 0);
37695
+ const claimThroughputHours = [];
37696
+ if (health.claimCadenceMs !== null && readyAt !== null) {
37697
+ const readyMs = Date.parse(readyAt);
37698
+ const firstFullHour = Math.ceil(readyMs / HOUR_MS) * HOUR_MS;
37699
+ const currentHour = Math.floor(nowMs / HOUR_MS) * HOUR_MS;
37700
+ const first = Math.max(firstFullHour, currentHour - HEALTH_WINDOW_MS);
37701
+ const claimsByHour = new Map(
37702
+ health.claimHours.map((row) => [row.hourStart, row.claims])
37703
+ );
37704
+ const expectedClaims = HOUR_MS / health.claimCadenceMs;
37705
+ for (let hour = first; hour < currentHour; hour += HOUR_MS) {
37706
+ const hourStart = new Date(hour).toISOString();
37707
+ const claims = claimsByHour.get(hourStart) ?? 0;
37708
+ claimThroughputHours.push({
37709
+ hourStart,
37710
+ claims,
37711
+ expectedClaims,
37712
+ ratio: claims / expectedClaims
37713
+ });
37714
+ }
37715
+ }
37716
+ const throughputLapseHours = claimThroughputHours.filter(
37717
+ (hour) => hour.ratio < LISTENER_THROUGHPUT_LAPSE_RATIO
37718
+ );
37719
+ return {
37720
+ currentEpisodeDurationMs,
37721
+ episodesLast24h,
37722
+ longestEpisodeAttemptsLast24h,
37723
+ longestEpisodeDurationMsLast24h,
37724
+ retriesLastHour,
37725
+ retryHours,
37726
+ claimThroughputHours,
37727
+ throughputLapseHours
37728
+ };
37729
+ }
37730
+
37220
37731
  // src/listener/control.ts
37732
+ var import_node_crypto19 = require("node:crypto");
37221
37733
  var import_node_net = require("node:net");
37222
37734
  var import_promises9 = require("node:fs/promises");
37223
37735
  var import_node_path16 = require("node:path");
37224
37736
  var UUID_RE17 = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
37225
37737
  var SEMVER_RE2 = /^(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)(?:-(?:0|[1-9]\d*|[A-Za-z-][0-9A-Za-z-]*)(?:\.(?:0|[1-9]\d*|[A-Za-z-][0-9A-Za-z-]*))*)?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/;
37226
- var MAX_STATUS_BYTES = 16 * 1024;
37738
+ var MAX_STATUS_BYTES = 32 * 1024;
37227
37739
  var MAX_CONTROL_BYTES = 8 * 1024;
37228
37740
  var CONTROL_TIMEOUT_MS = 2e3;
37229
37741
  var START_LOCK_WAIT_MS = 2e3;
@@ -37235,15 +37747,19 @@ var ListenerAlreadyRunningError = class extends Error {
37235
37747
  }
37236
37748
  };
37237
37749
  function listenerPaths(options) {
37238
- const root = options.stateDirectory ?? defaultListenerStateDirectory();
37750
+ const defaultRoot = defaultListenerStateDirectory();
37751
+ const root = options.stateDirectory ?? defaultRoot;
37239
37752
  if (!(0, import_node_path16.isAbsolute)(root)) {
37240
37753
  throw new Error("listener state directory must be absolute");
37241
37754
  }
37242
37755
  const key2 = listenerInstanceKey(options);
37243
37756
  const instanceDirectory = (0, import_node_path16.join)(root, key2);
37244
37757
  const uid2 = typeof process.getuid === "function" ? process.getuid() : process.pid;
37245
- const controlDirectory = process.platform === "win32" ? "" : (0, import_node_path16.join)("/tmp", `cswarm-control-${uid2}`);
37246
- const socketPath = process.platform === "win32" ? `\\\\.\\pipe\\cswarm-${key2}` : (0, import_node_path16.join)(controlDirectory, `${key2.slice(0, 32)}.sock`);
37758
+ const stateNamespace = (0, import_node_path16.resolve)(root) === (0, import_node_path16.resolve)(defaultRoot) ? "" : `-${(0, import_node_crypto19.createHash)("sha256").update((0, import_node_path16.resolve)(root)).digest("hex").slice(0, 16)}`;
37759
+ const platform = options.platform ?? process.platform;
37760
+ const socketKey = stateNamespace.length === 0 ? platform === "win32" ? key2 : key2.slice(0, 32) : `${key2.slice(0, 32)}${stateNamespace}`;
37761
+ const controlDirectory = platform === "win32" ? "" : (0, import_node_path16.join)("/tmp", `cswarm-control-${uid2}`);
37762
+ const socketPath = platform === "win32" ? `\\\\.\\pipe\\cswarm-${socketKey}` : (0, import_node_path16.join)(controlDirectory, `${socketKey}.sock`);
37247
37763
  return {
37248
37764
  key: key2,
37249
37765
  instanceDirectory,
@@ -37270,8 +37786,13 @@ var STATUS_ALLOWED_KEYS = /* @__PURE__ */ new Set([
37270
37786
  "lastSignalId",
37271
37787
  "lastErrorCode",
37272
37788
  "lastErrorDetail",
37789
+ "lastErrorReasonCode",
37790
+ "providerExecutable",
37273
37791
  "providerVersion",
37274
37792
  "providerLastMeasuredVersion",
37793
+ "providerBundledAgentSdkVersion",
37794
+ "providerBundledClaudeCodeVersion",
37795
+ "providerMinimumRequiredVersion",
37275
37796
  "cswarmVersion",
37276
37797
  "lastWorkerStderrTail",
37277
37798
  "logPath",
@@ -37284,7 +37805,19 @@ var STATUS_ALLOWED_KEYS = /* @__PURE__ */ new Set([
37284
37805
  "routeMode",
37285
37806
  "deferOverChars",
37286
37807
  "pendingForMainCount",
37287
- "droppedForMainCount"
37808
+ "droppedForMainCount",
37809
+ "readHealth",
37810
+ "connectionsOpened",
37811
+ "connectionReuseRatio",
37812
+ "activityPublishFailures",
37813
+ "activityLastErrorCode"
37814
+ ]);
37815
+ var STATUS_ACTIVITY_ERROR_CODES = /* @__PURE__ */ new Set([
37816
+ "activity_credential_failed",
37817
+ "activity_request_timeout",
37818
+ "activity_transport_failed",
37819
+ "activity_http_rejected",
37820
+ "activity_publish_unknown"
37288
37821
  ]);
37289
37822
  var STATUS_SENSITIVE_KEYS = /* @__PURE__ */ new Set([
37290
37823
  "leaseId",
@@ -37310,7 +37843,7 @@ var STATUS_DELIVERY_KEYS = [
37310
37843
  "lastClaimAt",
37311
37844
  "lastAckAt"
37312
37845
  ];
37313
- function parseStatus(raw) {
37846
+ function parseStatus(raw, rejectUnknownKeys = false) {
37314
37847
  let value;
37315
37848
  try {
37316
37849
  value = JSON.parse(raw);
@@ -37325,14 +37858,17 @@ function parseStatus(raw) {
37325
37858
  if (STATUS_SENSITIVE_KEYS.has(key2)) {
37326
37859
  throw new Error("stored listener status contains a forbidden field");
37327
37860
  }
37328
- if (!STATUS_ALLOWED_KEYS.has(key2)) {
37861
+ if (rejectUnknownKeys && !STATUS_ALLOWED_KEYS.has(key2)) {
37329
37862
  throw new Error("stored listener status is malformed");
37330
37863
  }
37331
37864
  }
37332
37865
  const nullableUuid3 = (candidate) => candidate === null || typeof candidate === "string" && UUID_RE17.test(candidate);
37333
37866
  const nullableCount = (candidate) => candidate === null || typeof candidate === "number" && Number.isSafeInteger(candidate) && candidate >= 0;
37334
37867
  const nullableTimestamp3 = (candidate) => candidate === null || typeof candidate === "string" && Number.isFinite(Date.parse(candidate));
37335
- if (row.version !== 1 || typeof row.instanceId !== "string" || !UUID_RE17.test(row.instanceId) || row.provider !== "grok" && row.provider !== "opencode" && row.provider !== "claude" && row.provider !== "codex" || typeof row.profileId !== "string" || typeof row.workspaceId !== "string" || !UUID_RE17.test(row.workspaceId) || typeof row.principalId !== "string" || !UUID_RE17.test(row.principalId) || !Number.isSafeInteger(row.pid) || row.pid < 1 || typeof row.state !== "string" || !["starting", "ready", "stopping", "stopped", "failed"].includes(row.state) || typeof row.startedAt !== "string" || !Number.isFinite(Date.parse(row.startedAt)) || !(row.readyAt === null || typeof row.readyAt === "string" && Number.isFinite(Date.parse(row.readyAt))) || typeof row.updatedAt !== "string" || !Number.isFinite(Date.parse(row.updatedAt)) || !(row.stoppedAt === null || typeof row.stoppedAt === "string" && Number.isFinite(Date.parse(row.stoppedAt))) || !nullableUuid3(row.lastSignalId) || !(row.lastErrorCode === null || typeof row.lastErrorCode === "string" && /^[a-z0-9_-]{1,96}$/.test(row.lastErrorCode)) || !(row.lastErrorDetail === void 0 || row.lastErrorDetail === null || typeof row.lastErrorDetail === "string" && row.lastErrorDetail.length > 0 && row.lastErrorDetail.length <= 2048 && !/swm_(?:agt|inv|cap)_/i.test(row.lastErrorDetail)) || !(row.providerVersion === void 0 || row.providerVersion === null || typeof row.providerVersion === "string" && SEMVER_RE2.test(row.providerVersion)) || !(row.providerLastMeasuredVersion === void 0 || row.providerLastMeasuredVersion === null || typeof row.providerLastMeasuredVersion === "string" && SEMVER_RE2.test(row.providerLastMeasuredVersion)) || !(row.cswarmVersion === void 0 || row.cswarmVersion === null || typeof row.cswarmVersion === "string" && SEMVER_RE2.test(row.cswarmVersion)) || (row.providerVersion === null || row.providerVersion === void 0) !== (row.providerLastMeasuredVersion === null || row.providerLastMeasuredVersion === void 0) || !(row.lastWorkerStderrTail === void 0 || row.lastWorkerStderrTail === null || typeof row.lastWorkerStderrTail === "string" && row.lastWorkerStderrTail.length > 0 && row.lastWorkerStderrTail.length <= 2048 && !/swm_(?:agt|inv|cap)_/i.test(row.lastWorkerStderrTail)) || typeof row.logPath !== "string" || !(0, import_node_path16.isAbsolute)(row.logPath) || !(row.deliveryMode === void 0 || row.deliveryMode === null || typeof row.deliveryMode === "string" && STATUS_DELIVERY_MODES.has(row.deliveryMode)) || !(row.pendingDeliveryCount === void 0 || nullableCount(row.pendingDeliveryCount)) || !(row.lastTerminalDeliveryFailureCount === void 0 || nullableCount(row.lastTerminalDeliveryFailureCount)) || !(row.lastTerminalDeliveryFailureAt === void 0 || nullableTimestamp3(row.lastTerminalDeliveryFailureAt)) || !(row.lastClaimAt === void 0 || nullableTimestamp3(row.lastClaimAt)) || !(row.lastAckAt === void 0 || nullableTimestamp3(row.lastAckAt)) || !(row.routeMode === void 0 || row.routeMode === "worker" || row.routeMode === "main" || row.routeMode === "split") || !(row.deferOverChars === void 0 || row.deferOverChars === null || typeof row.deferOverChars === "number" && Number.isSafeInteger(row.deferOverChars) && row.deferOverChars >= 1 && row.deferOverChars <= 1e4) || !(row.pendingForMainCount === void 0 || typeof row.pendingForMainCount === "number" && Number.isSafeInteger(row.pendingForMainCount) && row.pendingForMainCount >= 0) || !(row.droppedForMainCount === void 0 || typeof row.droppedForMainCount === "number" && Number.isSafeInteger(row.droppedForMainCount) && row.droppedForMainCount >= 0)) {
37868
+ const readHealth = row.readHealth === void 0 ? void 0 : parseListenerReadHealth(row.readHealth, rejectUnknownKeys);
37869
+ if (row.version !== 1 || typeof row.instanceId !== "string" || !UUID_RE17.test(row.instanceId) || row.provider !== "grok" && row.provider !== "opencode" && row.provider !== "claude" && row.provider !== "codex" || typeof row.profileId !== "string" || typeof row.workspaceId !== "string" || !UUID_RE17.test(row.workspaceId) || typeof row.principalId !== "string" || !UUID_RE17.test(row.principalId) || !Number.isSafeInteger(row.pid) || row.pid < 1 || typeof row.state !== "string" || !["starting", "ready", "stopping", "stopped", "failed"].includes(row.state) || typeof row.startedAt !== "string" || !Number.isFinite(Date.parse(row.startedAt)) || !(row.readyAt === null || typeof row.readyAt === "string" && Number.isFinite(Date.parse(row.readyAt))) || typeof row.updatedAt !== "string" || !Number.isFinite(Date.parse(row.updatedAt)) || !(row.stoppedAt === null || typeof row.stoppedAt === "string" && Number.isFinite(Date.parse(row.stoppedAt))) || !nullableUuid3(row.lastSignalId) || !(row.lastErrorCode === null || typeof row.lastErrorCode === "string" && /^[a-z0-9_-]{1,96}$/.test(row.lastErrorCode)) || !(row.lastErrorDetail === void 0 || row.lastErrorDetail === null || typeof row.lastErrorDetail === "string" && row.lastErrorDetail.length > 0 && row.lastErrorDetail.length <= 2048 && !/swm_(?:agt|inv|cap)_/i.test(row.lastErrorDetail)) || !(row.lastErrorReasonCode === void 0 || row.lastErrorReasonCode === null || typeof row.lastErrorReasonCode === "string" && /^[a-z0-9_-]{1,96}$/.test(row.lastErrorReasonCode)) || !(row.providerExecutable === void 0 || row.providerExecutable === null || typeof row.providerExecutable === "string" && (0, import_node_path16.isAbsolute)(row.providerExecutable)) || !(row.providerVersion === void 0 || row.providerVersion === null || typeof row.providerVersion === "string" && SEMVER_RE2.test(row.providerVersion)) || !(row.providerLastMeasuredVersion === void 0 || row.providerLastMeasuredVersion === null || typeof row.providerLastMeasuredVersion === "string" && SEMVER_RE2.test(row.providerLastMeasuredVersion)) || !(row.providerBundledAgentSdkVersion === void 0 || row.providerBundledAgentSdkVersion === null || typeof row.providerBundledAgentSdkVersion === "string" && SEMVER_RE2.test(row.providerBundledAgentSdkVersion)) || !(row.providerBundledClaudeCodeVersion === void 0 || row.providerBundledClaudeCodeVersion === null || typeof row.providerBundledClaudeCodeVersion === "string" && SEMVER_RE2.test(row.providerBundledClaudeCodeVersion)) || !(row.providerMinimumRequiredVersion === void 0 || row.providerMinimumRequiredVersion === null || typeof row.providerMinimumRequiredVersion === "string" && SEMVER_RE2.test(row.providerMinimumRequiredVersion)) || !(row.cswarmVersion === void 0 || row.cswarmVersion === null || typeof row.cswarmVersion === "string" && SEMVER_RE2.test(row.cswarmVersion)) || (row.providerVersion === null || row.providerVersion === void 0) !== (row.providerLastMeasuredVersion === null || row.providerLastMeasuredVersion === void 0) || !(row.lastWorkerStderrTail === void 0 || row.lastWorkerStderrTail === null || typeof row.lastWorkerStderrTail === "string" && row.lastWorkerStderrTail.length > 0 && row.lastWorkerStderrTail.length <= 2048 && !/swm_(?:agt|inv|cap)_/i.test(row.lastWorkerStderrTail)) || typeof row.logPath !== "string" || !(0, import_node_path16.isAbsolute)(row.logPath) || !(row.deliveryMode === void 0 || row.deliveryMode === null || typeof row.deliveryMode === "string" && STATUS_DELIVERY_MODES.has(row.deliveryMode)) || !(row.pendingDeliveryCount === void 0 || nullableCount(row.pendingDeliveryCount)) || !(row.lastTerminalDeliveryFailureCount === void 0 || nullableCount(row.lastTerminalDeliveryFailureCount)) || !(row.lastTerminalDeliveryFailureAt === void 0 || nullableTimestamp3(row.lastTerminalDeliveryFailureAt)) || !(row.lastClaimAt === void 0 || nullableTimestamp3(row.lastClaimAt)) || !(row.lastAckAt === void 0 || nullableTimestamp3(row.lastAckAt)) || !(row.routeMode === void 0 || row.routeMode === "worker" || row.routeMode === "main" || row.routeMode === "split") || !(row.deferOverChars === void 0 || row.deferOverChars === null || typeof row.deferOverChars === "number" && Number.isSafeInteger(row.deferOverChars) && row.deferOverChars >= 1 && row.deferOverChars <= 1e4) || !(row.pendingForMainCount === void 0 || typeof row.pendingForMainCount === "number" && Number.isSafeInteger(row.pendingForMainCount) && row.pendingForMainCount >= 0) || !(row.droppedForMainCount === void 0 || typeof row.droppedForMainCount === "number" && Number.isSafeInteger(row.droppedForMainCount) && row.droppedForMainCount >= 0) || readHealth === null || !(row.connectionsOpened === void 0 || typeof row.connectionsOpened === "number" && Number.isSafeInteger(row.connectionsOpened) && row.connectionsOpened >= 0) || !(row.connectionReuseRatio === void 0 || typeof row.connectionReuseRatio === "number" && Number.isFinite(row.connectionReuseRatio) && row.connectionReuseRatio >= 0) || !(row.activityPublishFailures === void 0 || typeof row.activityPublishFailures === "number" && Number.isSafeInteger(row.activityPublishFailures) && row.activityPublishFailures >= 0) || !(row.activityLastErrorCode === void 0 || row.activityLastErrorCode === null || typeof row.activityLastErrorCode === "string" && STATUS_ACTIVITY_ERROR_CODES.has(
37870
+ row.activityLastErrorCode
37871
+ ))) {
37336
37872
  throw new Error("stored listener status is malformed");
37337
37873
  }
37338
37874
  const routeMode = row.routeMode ?? "worker";
@@ -37340,8 +37876,11 @@ function parseStatus(raw) {
37340
37876
  if (routeMode === "split" && deferOverChars === null || routeMode !== "split" && deferOverChars !== null) {
37341
37877
  throw new Error("stored listener status routing fields are malformed");
37342
37878
  }
37879
+ const knownRow = Object.fromEntries(
37880
+ Object.entries(row).filter(([key2]) => STATUS_ALLOWED_KEYS.has(key2))
37881
+ );
37343
37882
  return {
37344
- ...row,
37883
+ ...knownRow,
37345
37884
  deliveryMode: row.deliveryMode ?? null,
37346
37885
  pendingDeliveryCount: row.pendingDeliveryCount ?? null,
37347
37886
  lastTerminalDeliveryFailureCount: row.lastTerminalDeliveryFailureCount ?? null,
@@ -37356,11 +37895,15 @@ function parseStatus(raw) {
37356
37895
  routeMode,
37357
37896
  deferOverChars,
37358
37897
  pendingForMainCount: row.pendingForMainCount ?? 0,
37359
- droppedForMainCount: row.droppedForMainCount ?? 0
37898
+ droppedForMainCount: row.droppedForMainCount ?? 0,
37899
+ ...readHealth === void 0 ? {} : { readHealth }
37360
37900
  };
37361
37901
  }
37362
37902
  async function writeListenerStatus(paths, status) {
37363
37903
  const serialized = JSON.stringify(status);
37904
+ if (Buffer.byteLength(serialized, "utf8") > MAX_STATUS_BYTES) {
37905
+ throw new Error("listener status is too large");
37906
+ }
37364
37907
  const parsed = JSON.parse(serialized);
37365
37908
  for (const key2 of STATUS_DELIVERY_KEYS) {
37366
37909
  if (!(key2 in parsed)) {
@@ -37370,7 +37913,7 @@ async function writeListenerStatus(paths, status) {
37370
37913
  if (!("lastErrorDetail" in parsed)) {
37371
37914
  throw new Error("listener status is missing local error detail metadata");
37372
37915
  }
37373
- parseStatus(serialized);
37916
+ parseStatus(serialized, true);
37374
37917
  await writeSecureJsonFile(paths.statusPath, serialized);
37375
37918
  }
37376
37919
  async function readListenerStatus(paths) {
@@ -37395,6 +37938,12 @@ async function appendListenerEvent(paths, event) {
37395
37938
  "passed",
37396
37939
  "reason",
37397
37940
  "delay_ms",
37941
+ "reason_code",
37942
+ "http_status",
37943
+ "error_constructor",
37944
+ "episode_attempt",
37945
+ "attempts",
37946
+ "duration_ms",
37398
37947
  "index",
37399
37948
  "delivery_mode",
37400
37949
  "pending_delivery_count",
@@ -37433,6 +37982,29 @@ async function appendListenerEvent(paths, event) {
37433
37982
  if ((key2 === "attempt" || key2 === "total") && !(typeof value === "number" && Number.isSafeInteger(value) && value >= 1)) {
37434
37983
  throw new Error("listener event attempt count is not allowed");
37435
37984
  }
37985
+ if ((key2 === "episode_attempt" || key2 === "attempts") && !(typeof value === "number" && Number.isSafeInteger(value) && value >= 1)) {
37986
+ throw new Error("listener event episode count is not allowed");
37987
+ }
37988
+ if (key2 === "duration_ms" && !(typeof value === "number" && Number.isSafeInteger(value) && value >= 0)) {
37989
+ throw new Error("listener event episode duration is not allowed");
37990
+ }
37991
+ if (key2 === "http_status" && !(typeof value === "number" && Number.isSafeInteger(value) && value >= 100 && value <= 599)) {
37992
+ throw new Error("listener event HTTP status is not allowed");
37993
+ }
37994
+ if (key2 === "reason_code" && !(typeof value === "string" && [
37995
+ "http_status",
37996
+ "no_response",
37997
+ "body_timeout",
37998
+ "malformed_response",
37999
+ "aborted",
38000
+ "host_ports_exhausted",
38001
+ "unclassified"
38002
+ ].includes(value))) {
38003
+ throw new Error("listener event read reason code is not allowed");
38004
+ }
38005
+ if (key2 === "error_constructor" && !(typeof value === "string" && /^[A-Za-z0-9_$-]{1,96}$/.test(value))) {
38006
+ throw new Error("listener event error constructor is not allowed");
38007
+ }
37436
38008
  if (key2 === "passed" && typeof value !== "boolean") {
37437
38009
  throw new Error("listener event canary result is not allowed");
37438
38010
  }
@@ -37476,6 +38048,12 @@ async function appendListenerEvent(paths, event) {
37476
38048
  if (event.event === "listener_canary_attempt" && (typeof event.attempt !== "number" || typeof event.total !== "number" || event.attempt > event.total || typeof event.passed !== "boolean" || !(event.reason === null || typeof event.reason === "string"))) {
37477
38049
  throw new Error("listener canary attempt event is incomplete");
37478
38050
  }
38051
+ if (event.event === "listener_read_retry" && (typeof event.reason_code !== "string" || typeof event.episode_attempt !== "number" || event.reason_code === "http_status" !== (typeof event.http_status === "number") || event.reason_code === "unclassified" !== (typeof event.error_constructor === "string"))) {
38052
+ throw new Error("listener read retry event is incomplete");
38053
+ }
38054
+ if (event.event === "listener_read_recovered" && (typeof event.attempts !== "number" || typeof event.duration_ms !== "number")) {
38055
+ throw new Error("listener read recovery event is incomplete");
38056
+ }
37479
38057
  await ensureSecureStateDirectory(paths.instanceDirectory);
37480
38058
  const serialized = `${JSON.stringify(event)}
37481
38059
  `;
@@ -37549,7 +38127,7 @@ async function startupLock(paths) {
37549
38127
  await (0, import_promises9.unlink)(lockPath).catch(() => void 0);
37550
38128
  continue;
37551
38129
  }
37552
- await new Promise((resolve2) => setTimeout(resolve2, 25));
38130
+ await new Promise((resolve3) => setTimeout(resolve3, 25));
37553
38131
  continue;
37554
38132
  }
37555
38133
  try {
@@ -37623,14 +38201,14 @@ async function startListenerControlServer(options) {
37623
38201
  if (options.initialize) {
37624
38202
  await options.initialize();
37625
38203
  }
37626
- await new Promise((resolve2, reject) => {
38204
+ await new Promise((resolve3, reject) => {
37627
38205
  const onError = (error) => {
37628
38206
  server.off("listening", onListening);
37629
38207
  reject(error);
37630
38208
  };
37631
38209
  const onListening = () => {
37632
38210
  server.off("error", onError);
37633
- resolve2();
38211
+ resolve3();
37634
38212
  };
37635
38213
  server.once("error", onError);
37636
38214
  server.once("listening", onListening);
@@ -37641,7 +38219,7 @@ async function startListenerControlServer(options) {
37641
38219
  }
37642
38220
  } catch (error) {
37643
38221
  if (server.listening) {
37644
- await new Promise((resolve2) => server.close(() => resolve2()));
38222
+ await new Promise((resolve3) => server.close(() => resolve3()));
37645
38223
  if (process.platform !== "win32") {
37646
38224
  await (0, import_promises9.unlink)(options.paths.socketPath).catch(() => void 0);
37647
38225
  }
@@ -37652,7 +38230,7 @@ async function startListenerControlServer(options) {
37652
38230
  }
37653
38231
  return {
37654
38232
  close: async () => {
37655
- await new Promise((resolve2) => server.close(() => resolve2()));
38233
+ await new Promise((resolve3) => server.close(() => resolve3()));
37656
38234
  if (process.platform !== "win32") {
37657
38235
  await (0, import_promises9.unlink)(options.paths.socketPath).catch(() => void 0);
37658
38236
  }
@@ -37660,7 +38238,7 @@ async function startListenerControlServer(options) {
37660
38238
  };
37661
38239
  }
37662
38240
  async function queryListenerControl(paths, command2, timeoutMs = CONTROL_TIMEOUT_MS) {
37663
- return await new Promise((resolve2, reject) => {
38241
+ return await new Promise((resolve3, reject) => {
37664
38242
  const socket = (0, import_node_net.createConnection)(paths.socketPath);
37665
38243
  let input = "";
37666
38244
  let settled = false;
@@ -37674,7 +38252,7 @@ async function queryListenerControl(paths, command2, timeoutMs = CONTROL_TIMEOUT
37674
38252
  clearTimeout(timer2);
37675
38253
  socket.destroy();
37676
38254
  if (error) reject(error);
37677
- else resolve2(status);
38255
+ else resolve3(status);
37678
38256
  };
37679
38257
  socket.setEncoding("utf8");
37680
38258
  socket.once("error", (error) => finish(error));
@@ -37705,7 +38283,7 @@ async function queryListenerControl(paths, command2, timeoutMs = CONTROL_TIMEOUT
37705
38283
  }
37706
38284
 
37707
38285
  // src/listener/supervisor.ts
37708
- var import_node_crypto19 = require("node:crypto");
38286
+ var import_node_crypto20 = require("node:crypto");
37709
38287
  var UUID_RE18 = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
37710
38288
  var LISTENER_RESTART_MAX_ATTEMPTS = 5;
37711
38289
  var LISTENER_RESTART_INITIAL_MS = 1e3;
@@ -37719,11 +38297,11 @@ function nextListenerRestartMs(attempt, policy = {}, random = Math.random) {
37719
38297
  }
37720
38298
  async function defaultRestartSleep(ms, signal) {
37721
38299
  if (ms <= 0 || signal.aborted) return;
37722
- await new Promise((resolve2) => {
38300
+ await new Promise((resolve3) => {
37723
38301
  const finish = () => {
37724
38302
  clearTimeout(timer2);
37725
38303
  signal.removeEventListener("abort", finish);
37726
- resolve2();
38304
+ resolve3();
37727
38305
  };
37728
38306
  const timer2 = setTimeout(finish, ms);
37729
38307
  signal.addEventListener("abort", finish, { once: true });
@@ -37760,6 +38338,28 @@ function localDiagnostic(message, maxChars) {
37760
38338
  function safeErrorDetail(error) {
37761
38339
  return localDiagnostic(error.message, 2048);
37762
38340
  }
38341
+ function providerStatusFields(notice) {
38342
+ if (!notice) return {};
38343
+ return {
38344
+ providerExecutable: notice.executable ?? null,
38345
+ providerVersion: notice.runningVersion,
38346
+ providerLastMeasuredVersion: notice.runningVersion === null ? null : notice.lastMeasuredVersion,
38347
+ providerBundledAgentSdkVersion: notice.bundledAgentSdkVersion ?? null,
38348
+ providerBundledClaudeCodeVersion: notice.bundledClaudeCodeVersion ?? null
38349
+ };
38350
+ }
38351
+ function providerFailureFields(error) {
38352
+ if (!(error instanceof AcpPermissionCanaryError)) {
38353
+ return {
38354
+ lastErrorReasonCode: null,
38355
+ providerMinimumRequiredVersion: null
38356
+ };
38357
+ }
38358
+ return {
38359
+ lastErrorReasonCode: error.reasonCode,
38360
+ providerMinimumRequiredVersion: error.minimumRequiredVersion
38361
+ };
38362
+ }
37763
38363
  var TAIL_SERIALIZED_BUDGET_BYTES = 3e3;
37764
38364
  function fitWorkerStderrTailForLog(tail) {
37765
38365
  let fitted = tail.trim();
@@ -37781,7 +38381,7 @@ async function runListenerSupervisor(options) {
37781
38381
  const now = options.now ?? Date.now;
37782
38382
  const startedAt = iso2(now);
37783
38383
  const controller = new AbortController();
37784
- const proposedInstanceId = (0, import_node_crypto19.randomUUID)();
38384
+ const proposedInstanceId = (0, import_node_crypto20.randomUUID)();
37785
38385
  let status = {
37786
38386
  version: 1,
37787
38387
  instanceId: proposedInstanceId,
@@ -37800,8 +38400,13 @@ async function runListenerSupervisor(options) {
37800
38400
  lastSignalId: null,
37801
38401
  lastErrorCode: null,
37802
38402
  lastErrorDetail: null,
38403
+ lastErrorReasonCode: null,
38404
+ providerExecutable: null,
37803
38405
  providerVersion: null,
37804
38406
  providerLastMeasuredVersion: null,
38407
+ providerBundledAgentSdkVersion: null,
38408
+ providerBundledClaudeCodeVersion: null,
38409
+ providerMinimumRequiredVersion: null,
37805
38410
  lastWorkerStderrTail: null,
37806
38411
  deliveryMode: null,
37807
38412
  pendingDeliveryCount: null,
@@ -37813,14 +38418,29 @@ async function runListenerSupervisor(options) {
37813
38418
  deferOverChars: options.deferOverChars ?? null,
37814
38419
  pendingForMainCount: 0,
37815
38420
  droppedForMainCount: 0,
38421
+ readHealth: emptyListenerReadHealth(),
38422
+ connectionsOpened: 0,
38423
+ connectionReuseRatio: 0,
38424
+ activityPublishFailures: 0,
38425
+ activityLastErrorCode: null,
37816
38426
  logPath: options.paths.logPath
37817
38427
  };
37818
38428
  let writes = Promise.resolve();
37819
38429
  const chain = (work) => {
37820
38430
  writes = writes.then(work).catch(() => void 0);
37821
38431
  };
38432
+ const statusSnapshot = () => {
38433
+ const metrics = options.getConnectionMetrics?.();
38434
+ return {
38435
+ ...structuredClone(status),
38436
+ ...metrics ? {
38437
+ connectionsOpened: metrics.connectionsOpened,
38438
+ connectionReuseRatio: metrics.connectionReuseRatio
38439
+ } : {}
38440
+ };
38441
+ };
37822
38442
  const persist = () => {
37823
- const snapshot = structuredClone(status);
38443
+ const snapshot = statusSnapshot();
37824
38444
  chain(() => writeListenerStatus(options.paths, snapshot));
37825
38445
  };
37826
38446
  const log = (event) => {
@@ -37838,7 +38458,7 @@ async function runListenerSupervisor(options) {
37838
38458
  const prepare = options.prepare;
37839
38459
  const control = await startListenerControlServer({
37840
38460
  paths: options.paths,
37841
- status: () => structuredClone(status),
38461
+ status: statusSnapshot,
37842
38462
  stop: () => {
37843
38463
  if (status.state === "stopped" || status.state === "failed") return;
37844
38464
  transition("stopping");
@@ -37876,9 +38496,16 @@ async function runListenerSupervisor(options) {
37876
38496
  readyAt: event.ts,
37877
38497
  lastErrorCode: null,
37878
38498
  lastErrorDetail: null,
38499
+ lastErrorReasonCode: null,
37879
38500
  lastWorkerStderrTail: null,
37880
- providerVersion: versionNotice?.runningVersion ?? null,
37881
- providerLastMeasuredVersion: versionNotice?.lastMeasuredVersion ?? null
38501
+ providerMinimumRequiredVersion: null,
38502
+ ...providerStatusFields(versionNotice),
38503
+ ...event.cadenceMs === void 0 ? {} : {
38504
+ readHealth: recordListenerClaimCadence(
38505
+ status.readHealth ?? emptyListenerReadHealth(),
38506
+ event.cadenceMs
38507
+ )
38508
+ }
37882
38509
  });
37883
38510
  log({ ts: event.ts, event: "listener_ready" });
37884
38511
  return;
@@ -37920,14 +38547,54 @@ async function runListenerSupervisor(options) {
37920
38547
  return;
37921
38548
  }
37922
38549
  if (event.type === "read_retry") {
38550
+ status = {
38551
+ ...status,
38552
+ readHealth: recordListenerReadRetry(
38553
+ status.readHealth ?? emptyListenerReadHealth(),
38554
+ {
38555
+ ts: event.ts,
38556
+ episodeStartedAt: event.episodeStartedAt,
38557
+ episodeAttempt: event.episodeAttempt,
38558
+ failure: event.failure
38559
+ }
38560
+ ),
38561
+ updatedAt: event.ts
38562
+ };
38563
+ persist();
37923
38564
  log({
37924
38565
  ts: event.ts,
37925
38566
  event: "listener_read_retry",
37926
38567
  attempt: event.attempt,
38568
+ episode_attempt: event.episodeAttempt,
38569
+ reason_code: event.failure.code,
38570
+ ...event.failure.httpStatus === null ? {} : { http_status: event.failure.httpStatus },
38571
+ ...event.failure.errorConstructor === null ? {} : { error_constructor: event.failure.errorConstructor },
37927
38572
  delay_ms: event.delayMs
37928
38573
  });
37929
38574
  return;
37930
38575
  }
38576
+ if (event.type === "read_recovered") {
38577
+ status = {
38578
+ ...status,
38579
+ readHealth: recordListenerReadRecovery(
38580
+ status.readHealth ?? emptyListenerReadHealth(),
38581
+ {
38582
+ startedAt: event.startedAt,
38583
+ attempts: event.attempts,
38584
+ durationMs: event.durationMs
38585
+ }
38586
+ ),
38587
+ updatedAt: event.ts
38588
+ };
38589
+ persist();
38590
+ log({
38591
+ ts: event.ts,
38592
+ event: "listener_read_recovered",
38593
+ attempts: event.attempts,
38594
+ duration_ms: event.durationMs
38595
+ });
38596
+ return;
38597
+ }
37931
38598
  if (event.type === "malformed_row") {
37932
38599
  log({
37933
38600
  ts: event.ts,
@@ -37936,6 +38603,16 @@ async function runListenerSupervisor(options) {
37936
38603
  });
37937
38604
  return;
37938
38605
  }
38606
+ if (event.type === "activity_publish_failure") {
38607
+ status = {
38608
+ ...status,
38609
+ activityPublishFailures: (status.activityPublishFailures ?? 0) + 1,
38610
+ activityLastErrorCode: event.code,
38611
+ updatedAt: event.ts
38612
+ };
38613
+ persist();
38614
+ return;
38615
+ }
37939
38616
  if (event.type === "model_declared") {
37940
38617
  log({
37941
38618
  ts: event.ts,
@@ -37964,6 +38641,10 @@ async function runListenerSupervisor(options) {
37964
38641
  if (event.type === "delivery_claim") {
37965
38642
  status = {
37966
38643
  ...status,
38644
+ readHealth: recordListenerClaim(
38645
+ status.readHealth ?? emptyListenerReadHealth(),
38646
+ event.ts
38647
+ ),
37967
38648
  pendingDeliveryCount: event.pendingDeliveryCount,
37968
38649
  lastClaimAt: event.ts,
37969
38650
  updatedAt: event.ts
@@ -38088,9 +38769,9 @@ async function runListenerSupervisor(options) {
38088
38769
  readyAt: null,
38089
38770
  lastErrorCode: restartCode,
38090
38771
  lastErrorDetail: safeErrorDetail(stop.error),
38772
+ ...providerFailureFields(stop.error),
38091
38773
  lastWorkerStderrTail: restartStderrTail,
38092
- providerVersion: null,
38093
- providerLastMeasuredVersion: null
38774
+ ...providerStatusFields(options.getProviderVersionNotice?.() ?? null)
38094
38775
  });
38095
38776
  await restartSleep(delayMs, controller.signal);
38096
38777
  if (controller.signal.aborted) {
@@ -38104,7 +38785,9 @@ async function runListenerSupervisor(options) {
38104
38785
  stoppedAt,
38105
38786
  lastErrorCode: null,
38106
38787
  lastErrorDetail: null,
38107
- lastWorkerStderrTail: null
38788
+ lastErrorReasonCode: null,
38789
+ lastWorkerStderrTail: null,
38790
+ providerMinimumRequiredVersion: null
38108
38791
  });
38109
38792
  log({ ts: stoppedAt, event: "listener_stopped" });
38110
38793
  } else {
@@ -38114,6 +38797,8 @@ async function runListenerSupervisor(options) {
38114
38797
  stoppedAt,
38115
38798
  lastErrorCode: code,
38116
38799
  lastErrorDetail: safeErrorDetail(stop.error),
38800
+ ...providerFailureFields(stop.error),
38801
+ ...providerStatusFields(options.getProviderVersionNotice?.() ?? null),
38117
38802
  lastWorkerStderrTail: failedStderrTail
38118
38803
  });
38119
38804
  log({
@@ -38138,6 +38823,10 @@ async function runListenerSupervisor(options) {
38138
38823
  lastErrorDetail: safeErrorDetail(
38139
38824
  error instanceof Error ? error : new Error(String(error))
38140
38825
  ),
38826
+ ...providerFailureFields(
38827
+ error instanceof Error ? error : new Error(String(error))
38828
+ ),
38829
+ ...providerStatusFields(options.getProviderVersionNotice?.() ?? null),
38141
38830
  lastWorkerStderrTail: failedStderrTail
38142
38831
  });
38143
38832
  log({
@@ -38150,7 +38839,7 @@ async function runListenerSupervisor(options) {
38150
38839
  await writes.catch(() => void 0);
38151
38840
  await control.close().catch(() => void 0);
38152
38841
  }
38153
- return status;
38842
+ return statusSnapshot();
38154
38843
  }
38155
38844
  async function effectiveListenerStatus(paths) {
38156
38845
  try {
@@ -38182,7 +38871,7 @@ async function waitForListenerReady(paths, options = {}) {
38182
38871
  const timeoutMs = options.timeoutMs ?? 12e4;
38183
38872
  const pollMs = options.pollMs ?? 100;
38184
38873
  const now = options.now ?? Date.now;
38185
- const sleep2 = options.sleep ?? ((ms) => new Promise((resolve2) => setTimeout(resolve2, ms)));
38874
+ const sleep2 = options.sleep ?? ((ms) => new Promise((resolve3) => setTimeout(resolve3, ms)));
38186
38875
  const deadline = now() + timeoutMs;
38187
38876
  let last = null;
38188
38877
  let processExitObservedAt = null;
@@ -38383,7 +39072,7 @@ function assertPlainObject(input, allowedKeys, requiredKeys, errMessage = "deliv
38383
39072
  throw new Error(errMessage);
38384
39073
  }
38385
39074
  }
38386
- function parseJournalRecord(raw, expectedWorkspaceId, expectedPrincipalId) {
39075
+ function parseJournalRecord(raw, expectedWorkspaceId, expectedPrincipalId, rejectUnknownKeys = false) {
38387
39076
  if (Buffer.byteLength(raw, "utf8") > MAX_JOURNAL_BYTES) {
38388
39077
  throw new Error("stored delivery journal is malformed");
38389
39078
  }
@@ -38404,7 +39093,7 @@ function parseJournalRecord(raw, expectedWorkspaceId, expectedPrincipalId) {
38404
39093
  throw new Error("stored delivery journal is malformed");
38405
39094
  }
38406
39095
  const ownProps = Object.getOwnPropertyNames(value);
38407
- if (ownProps.length !== ALLOWED_TOP_KEYS.size || !ownProps.every((p) => ALLOWED_TOP_KEYS.has(p))) {
39096
+ if ([...ALLOWED_TOP_KEYS].some((key2) => !ownProps.includes(key2)) || rejectUnknownKeys && !ownProps.every((key2) => ALLOWED_TOP_KEYS.has(key2))) {
38408
39097
  throw new Error("stored delivery journal is malformed");
38409
39098
  }
38410
39099
  for (const prop of ownProps) {
@@ -38438,8 +39127,16 @@ function parseJournalRecord(raw, expectedWorkspaceId, expectedPrincipalId) {
38438
39127
  if (!isValidIsoTimestamp(row.updatedAt)) {
38439
39128
  throw new Error("stored delivery journal is malformed");
38440
39129
  }
39130
+ const base = {
39131
+ version: 1,
39132
+ workspaceId: row.workspaceId,
39133
+ principalId: row.principalId,
39134
+ listenerInstanceId: row.listenerInstanceId,
39135
+ nextClaimOrdinal: row.nextClaimOrdinal,
39136
+ updatedAt: row.updatedAt
39137
+ };
38441
39138
  if (row.active === null) {
38442
- return row;
39139
+ return { ...base, active: null };
38443
39140
  }
38444
39141
  if (typeof row.active !== "object" || row.active === null || Array.isArray(row.active)) {
38445
39142
  throw new Error("stored delivery journal is malformed");
@@ -38452,8 +39149,10 @@ function parseJournalRecord(raw, expectedWorkspaceId, expectedPrincipalId) {
38452
39149
  throw new Error("stored delivery journal is malformed");
38453
39150
  }
38454
39151
  const activeProps = Object.getOwnPropertyNames(row.active);
38455
- const legacyWithoutFingerprint = activeProps.length === ALLOWED_ACTIVE_KEYS.size - 1 && !activeProps.includes("signalFingerprint");
38456
- if (!legacyWithoutFingerprint && activeProps.length !== ALLOWED_ACTIVE_KEYS.size || !activeProps.every((p) => ALLOWED_ACTIVE_KEYS.has(p))) {
39152
+ const requiredActiveKeys = [...ALLOWED_ACTIVE_KEYS].filter(
39153
+ (key2) => key2 !== "signalFingerprint"
39154
+ );
39155
+ if (requiredActiveKeys.some((key2) => !activeProps.includes(key2)) || rejectUnknownKeys && !activeProps.every((key2) => ALLOWED_ACTIVE_KEYS.has(key2))) {
38457
39156
  throw new Error("stored delivery journal is malformed");
38458
39157
  }
38459
39158
  for (const prop of activeProps) {
@@ -38521,7 +39220,7 @@ function parseJournalRecord(raw, expectedWorkspaceId, expectedPrincipalId) {
38521
39220
  throw new Error("stored delivery journal is malformed");
38522
39221
  }
38523
39222
  const ackProps = Object.getOwnPropertyNames(active.ack);
38524
- if (ackProps.length !== ALLOWED_ACK_KEYS.size || !ackProps.every((p) => ALLOWED_ACK_KEYS.has(p))) {
39223
+ if ([...ALLOWED_ACK_KEYS].some((key2) => !ackProps.includes(key2)) || rejectUnknownKeys && !ackProps.every((key2) => ALLOWED_ACK_KEYS.has(key2))) {
38525
39224
  throw new Error("stored delivery journal is malformed");
38526
39225
  }
38527
39226
  for (const prop of ackProps) {
@@ -38530,32 +39229,52 @@ function parseJournalRecord(raw, expectedWorkspaceId, expectedPrincipalId) {
38530
39229
  throw new Error("stored delivery journal is malformed");
38531
39230
  }
38532
39231
  }
38533
- const ack = active.ack;
38534
- if (typeof ack.commandId !== "string" || !COMMAND_ID_RE3.test(ack.commandId)) {
39232
+ const ack2 = active.ack;
39233
+ if (typeof ack2.commandId !== "string" || !COMMAND_ID_RE3.test(ack2.commandId)) {
38535
39234
  throw new Error("stored delivery journal is malformed");
38536
39235
  }
38537
39236
  const expectedAckCmdId = ackCommandId(active.leaseId);
38538
- if (ack.commandId !== expectedAckCmdId) {
39237
+ if (ack2.commandId !== expectedAckCmdId) {
38539
39238
  throw new Error("stored delivery journal is malformed");
38540
39239
  }
38541
- if (typeof ack.outcome !== "string" || !ALLOWED_OUTCOMES.has(ack.outcome)) {
39240
+ if (typeof ack2.outcome !== "string" || !ALLOWED_OUTCOMES.has(ack2.outcome)) {
38542
39241
  throw new Error("stored delivery journal is malformed");
38543
39242
  }
38544
- if (ack.outcome === "failed_terminal") {
38545
- if (typeof ack.lastErrorCode !== "string" || !ALLOWED_ERROR_CODES.has(ack.lastErrorCode)) {
39243
+ if (ack2.outcome === "failed_terminal") {
39244
+ if (typeof ack2.lastErrorCode !== "string" || !ALLOWED_ERROR_CODES.has(ack2.lastErrorCode)) {
38546
39245
  throw new Error("stored delivery journal is malformed");
38547
39246
  }
38548
39247
  } else {
38549
- if (ack.lastErrorCode !== null) {
39248
+ if (ack2.lastErrorCode !== null) {
38550
39249
  throw new Error("stored delivery journal is malformed");
38551
39250
  }
38552
39251
  }
38553
- if (!isValidIsoTimestamp(ack.preparedAt)) {
39252
+ if (!isValidIsoTimestamp(ack2.preparedAt)) {
38554
39253
  throw new Error("stored delivery journal is malformed");
38555
39254
  }
38556
39255
  }
38557
39256
  }
38558
- return row;
39257
+ const ack = active.ack;
39258
+ return {
39259
+ ...base,
39260
+ active: {
39261
+ phase: active.phase,
39262
+ claimOrdinal: active.claimOrdinal,
39263
+ claimCommandId: active.claimCommandId,
39264
+ claimCreatedAt: active.claimCreatedAt,
39265
+ claimLastAttemptAt: active.claimLastAttemptAt,
39266
+ signalId: active.signalId,
39267
+ leaseId: active.leaseId,
39268
+ leasedUntil: active.leasedUntil,
39269
+ ...active.signalFingerprint === void 0 ? {} : { signalFingerprint: active.signalFingerprint },
39270
+ ack: ack === null ? null : {
39271
+ commandId: ack.commandId,
39272
+ outcome: ack.outcome,
39273
+ lastErrorCode: ack.lastErrorCode,
39274
+ preparedAt: ack.preparedAt
39275
+ }
39276
+ }
39277
+ };
38559
39278
  }
38560
39279
  var FileListenerDeliveryJournal = class {
38561
39280
  instanceDirectory;
@@ -38619,7 +39338,8 @@ var FileListenerDeliveryJournal = class {
38619
39338
  parseJournalRecord(
38620
39339
  serialized,
38621
39340
  this.options.workspaceId,
38622
- this.options.principalId
39341
+ this.options.principalId,
39342
+ true
38623
39343
  );
38624
39344
  await writeSecureJsonFile(this.journalPath, serialized);
38625
39345
  }
@@ -38869,7 +39589,8 @@ async function openListenerDeliveryJournal(options) {
38869
39589
  parseJournalRecord(
38870
39590
  serialized2,
38871
39591
  workspaceIdSnapshot,
38872
- principalIdSnapshot
39592
+ principalIdSnapshot,
39593
+ true
38873
39594
  );
38874
39595
  await writeSecureJsonFile(journal.journalPath, serialized2);
38875
39596
  return {
@@ -38903,7 +39624,8 @@ async function openListenerDeliveryJournal(options) {
38903
39624
  parseJournalRecord(
38904
39625
  serialized,
38905
39626
  workspaceIdSnapshot,
38906
- principalIdSnapshot
39627
+ principalIdSnapshot,
39628
+ true
38907
39629
  );
38908
39630
  await writeSecureJsonFile(journal.journalPath, serialized);
38909
39631
  return {
@@ -39021,12 +39743,12 @@ async function spawnDetachedListener(options) {
39021
39743
  child.kill();
39022
39744
  throw new Error("detached listener child has no credential pipe");
39023
39745
  }
39024
- await new Promise((resolve2, reject) => {
39746
+ await new Promise((resolve3, reject) => {
39025
39747
  const onError = (error) => reject(error);
39026
39748
  child.once("error", onError);
39027
39749
  child.stdin.end(options.credentialArtifact, "utf8", () => {
39028
39750
  child.off("error", onError);
39029
- resolve2();
39751
+ resolve3();
39030
39752
  });
39031
39753
  });
39032
39754
  child.unref();
@@ -39059,7 +39781,7 @@ function parseState(raw) {
39059
39781
  }
39060
39782
  const row = value;
39061
39783
  const topicVersions = row.topicVersions;
39062
- if (Object.keys(row).sort().join(",") !== "principalId,topicVersions,version" || row.version !== 1 || typeof row.principalId !== "string" || !UUID_RE20.test(row.principalId) || !topicVersions || typeof topicVersions !== "object" || Array.isArray(topicVersions) || Object.keys(topicVersions).length > MAX_BRAIN_DIGEST_TOPICS) {
39784
+ if (row.version !== 1 || typeof row.principalId !== "string" || !UUID_RE20.test(row.principalId) || !topicVersions || typeof topicVersions !== "object" || Array.isArray(topicVersions) || Object.keys(topicVersions).length > MAX_BRAIN_DIGEST_TOPICS) {
39063
39785
  throw new Error("stored brain digest state is malformed");
39064
39786
  }
39065
39787
  for (const [topic, version3] of Object.entries(topicVersions)) {
@@ -39171,7 +39893,26 @@ function exactKeys2(row, keys) {
39171
39893
  const expected = new Set(keys);
39172
39894
  return Object.keys(row).length === expected.size && Object.keys(row).every((key2) => expected.has(key2));
39173
39895
  }
39174
- function parseListenerCredential(raw) {
39896
+ function hasRequiredKeys(row, keys) {
39897
+ return keys.every((key2) => Object.hasOwn(row, key2));
39898
+ }
39899
+ var LISTENER_CREDENTIAL_KEYS = [
39900
+ "version",
39901
+ "profileId",
39902
+ "targetUrl",
39903
+ "anonKey",
39904
+ "workspaceId",
39905
+ "principalId",
39906
+ "credential",
39907
+ "updatedAt"
39908
+ ];
39909
+ var HOOK_SURFACE_KEYS = /* @__PURE__ */ new Set([
39910
+ "version",
39911
+ "surfacedSignalIds",
39912
+ "reportedDroppedCount",
39913
+ "credentialFailureReported"
39914
+ ]);
39915
+ function parseListenerCredential(raw, rejectUnknownKeys = false) {
39175
39916
  let value;
39176
39917
  try {
39177
39918
  value = JSON.parse(raw);
@@ -39182,16 +39923,7 @@ function parseListenerCredential(raw) {
39182
39923
  throw new Error("stored listener hook credential is malformed");
39183
39924
  }
39184
39925
  const row = value;
39185
- if (!exactKeys2(row, [
39186
- "version",
39187
- "profileId",
39188
- "targetUrl",
39189
- "anonKey",
39190
- "workspaceId",
39191
- "principalId",
39192
- "credential",
39193
- "updatedAt"
39194
- ]) || row.version !== 1 || typeof row.profileId !== "string" || !/^[0-9a-f]{24}$/.test(row.profileId) || typeof row.targetUrl !== "string" || typeof row.anonKey !== "string" || row.anonKey.length < 1 || row.anonKey.length > 4096 || typeof row.workspaceId !== "string" || !UUID_RE21.test(row.workspaceId) || typeof row.principalId !== "string" || !UUID_RE21.test(row.principalId) || typeof row.credential !== "string" || !TOKEN_RE.test(row.credential) || typeof row.updatedAt !== "string" || !Number.isFinite(Date.parse(row.updatedAt))) {
39926
+ if (!(rejectUnknownKeys ? exactKeys2(row, LISTENER_CREDENTIAL_KEYS) : hasRequiredKeys(row, LISTENER_CREDENTIAL_KEYS)) || row.version !== 1 || typeof row.profileId !== "string" || !/^[0-9a-f]{24}$/.test(row.profileId) || typeof row.targetUrl !== "string" || typeof row.anonKey !== "string" || row.anonKey.length < 1 || row.anonKey.length > 4096 || typeof row.workspaceId !== "string" || !UUID_RE21.test(row.workspaceId) || typeof row.principalId !== "string" || !UUID_RE21.test(row.principalId) || typeof row.credential !== "string" || !TOKEN_RE.test(row.credential) || typeof row.updatedAt !== "string" || !Number.isFinite(Date.parse(row.updatedAt))) {
39195
39927
  throw new Error("stored listener hook credential is malformed");
39196
39928
  }
39197
39929
  const target2 = cloudTarget(row.targetUrl, row.anonKey);
@@ -39222,7 +39954,7 @@ async function writeListenerCredentialState(instanceDirectory, input) {
39222
39954
  principalId: input.principalId,
39223
39955
  credential: input.credential,
39224
39956
  updatedAt: new Date(input.now ?? Date.now()).toISOString()
39225
- }));
39957
+ }), true);
39226
39958
  await writeSecureJsonFile(
39227
39959
  (0, import_node_path20.join)(instanceDirectory, LISTENER_CREDENTIAL_FILE),
39228
39960
  JSON.stringify(record)
@@ -39238,7 +39970,7 @@ async function readListenerCredentialState(instanceDirectory) {
39238
39970
  );
39239
39971
  return raw === null ? null : parseListenerCredential(raw);
39240
39972
  }
39241
- function parseSurface(raw) {
39973
+ function parseSurface(raw, rejectUnknownKeys = false) {
39242
39974
  let value;
39243
39975
  try {
39244
39976
  value = JSON.parse(raw);
@@ -39249,9 +39981,7 @@ function parseSurface(raw) {
39249
39981
  throw new Error("stored listener hook surface state is malformed");
39250
39982
  }
39251
39983
  const row = value;
39252
- if (Object.keys(row).some(
39253
- (key2) => key2 !== "version" && key2 !== "surfacedSignalIds" && key2 !== "reportedDroppedCount" && key2 !== "credentialFailureReported"
39254
- ) || row.version !== 1 || !Array.isArray(row.surfacedSignalIds) || row.surfacedSignalIds.length > HOOK_SURFACED_IDS_MAX || row.surfacedSignalIds.some((id) => typeof id !== "string" || !UUID_RE21.test(id)) || !(row.reportedDroppedCount === void 0 || typeof row.reportedDroppedCount === "number" && Number.isSafeInteger(row.reportedDroppedCount) && row.reportedDroppedCount >= 0) || !(row.credentialFailureReported === void 0 || typeof row.credentialFailureReported === "boolean")) {
39984
+ if (rejectUnknownKeys && Object.keys(row).some((key2) => !HOOK_SURFACE_KEYS.has(key2)) || row.version !== 1 || !Array.isArray(row.surfacedSignalIds) || row.surfacedSignalIds.length > HOOK_SURFACED_IDS_MAX || row.surfacedSignalIds.some((id) => typeof id !== "string" || !UUID_RE21.test(id)) || !(row.reportedDroppedCount === void 0 || typeof row.reportedDroppedCount === "number" && Number.isSafeInteger(row.reportedDroppedCount) && row.reportedDroppedCount >= 0) || !(row.credentialFailureReported === void 0 || typeof row.credentialFailureReported === "boolean")) {
39255
39985
  throw new Error("stored listener hook surface state is malformed");
39256
39986
  }
39257
39987
  const ids = row.surfacedSignalIds.map((id) => String(id).toLowerCase());
@@ -39345,7 +40075,7 @@ var FileHookSurfaceStore = class {
39345
40075
  surfacedSignalIds: [...seen].slice(-HOOK_SURFACED_IDS_MAX),
39346
40076
  reportedDroppedCount: options.droppedCount ?? state.reportedDroppedCount,
39347
40077
  credentialFailureReported: options.credentialFailureReported ?? state.credentialFailureReported
39348
- })))
40078
+ }), true))
39349
40079
  );
39350
40080
  }, { timeoutMs: HOOK_LOCK_TIMEOUT_MS });
39351
40081
  }
@@ -39368,7 +40098,7 @@ function parseGlobalState(raw) {
39368
40098
  throw new Error("stored hook cooldown state is malformed");
39369
40099
  }
39370
40100
  const row = value;
39371
- if (!exactKeys2(row, ["version", "lastCheckAt"]) || row.version !== 1 || typeof row.lastCheckAt !== "number" || !Number.isSafeInteger(row.lastCheckAt) || row.lastCheckAt < 0) {
40101
+ if (!hasRequiredKeys(row, ["version", "lastCheckAt"]) || row.version !== 1 || typeof row.lastCheckAt !== "number" || !Number.isSafeInteger(row.lastCheckAt) || row.lastCheckAt < 0) {
39372
40102
  throw new Error("stored hook cooldown state is malformed");
39373
40103
  }
39374
40104
  return { version: 1, lastCheckAt: row.lastCheckAt };
@@ -39809,10 +40539,10 @@ async function runListenerHookCheck(options = {}) {
39809
40539
  signal: controller.signal,
39810
40540
  deadlineMs
39811
40541
  });
39812
- const timedOut = new Promise((resolve2) => {
40542
+ const timedOut = new Promise((resolve3) => {
39813
40543
  timer2 = setTimeout(() => {
39814
40544
  controller.abort();
39815
- resolve2("");
40545
+ resolve3("");
39816
40546
  }, HOOK_CHECK_TIMEOUT_MS);
39817
40547
  });
39818
40548
  return await Promise.race([checking, timedOut]);
@@ -39882,7 +40612,7 @@ async function logEvidence(path, signalId) {
39882
40612
  }
39883
40613
  async function runListenerAttendanceCanary(options) {
39884
40614
  const now = options.now ?? Date.now;
39885
- const sleep2 = options.sleep ?? ((milliseconds) => new Promise((resolve2) => setTimeout(resolve2, milliseconds)));
40615
+ const sleep2 = options.sleep ?? ((milliseconds) => new Promise((resolve3) => setTimeout(resolve3, milliseconds)));
39886
40616
  const startedAt = now();
39887
40617
  const deadlineMs = startedAt + options.waitMs;
39888
40618
  const client = new ThinCommandClient(options.target, options.fetcher, {
@@ -39995,16 +40725,508 @@ function renderListenerAttendanceCanary(result, workspaceId2, principalId) {
39995
40725
  return lines.join("\n");
39996
40726
  }
39997
40727
 
40728
+ // src/listener/activity.ts
40729
+ var import_node_crypto21 = require("node:crypto");
40730
+ var ACTIVITY_FRAME_INTERVAL_MS = 750;
40731
+ var ACTIVITY_HEARTBEAT_MS = 15e3;
40732
+ var ACTIVITY_TOOL_TITLE_MAX = 160;
40733
+ var ACTIVITY_REQUEST_TIMEOUT_MS = 5e3;
40734
+ var AgentActivityPublishError = class extends Error {
40735
+ constructor(code, cause) {
40736
+ super("activity frame publish failed", { cause });
40737
+ this.code = code;
40738
+ this.name = "AgentActivityPublishError";
40739
+ }
40740
+ code;
40741
+ };
40742
+ function activityPublishErrorCode(error) {
40743
+ return error instanceof AgentActivityPublishError ? error.code : "activity_publish_unknown";
40744
+ }
40745
+ var SYSTEM_CLOCK = {
40746
+ now: Date.now,
40747
+ setTimer: (callback, delayMs) => setTimeout(callback, delayMs),
40748
+ clearTimer: (timer2) => clearTimeout(timer2)
40749
+ };
40750
+ var TERMINAL_TOOL_STATUSES = /* @__PURE__ */ new Set([
40751
+ "cancelled",
40752
+ "completed",
40753
+ "done",
40754
+ "failed",
40755
+ "rejected"
40756
+ ]);
40757
+ var AgentActivityEndpointTransport = class {
40758
+ constructor(target2, credentialSession, fetcher, requestTimeoutMs = ACTIVITY_REQUEST_TIMEOUT_MS) {
40759
+ this.target = target2;
40760
+ this.credentialSession = credentialSession;
40761
+ this.requestTimeoutMs = requestTimeoutMs;
40762
+ this.fetcher = fetcher ?? fetch;
40763
+ }
40764
+ target;
40765
+ credentialSession;
40766
+ requestTimeoutMs;
40767
+ fetcher;
40768
+ async publish(frame) {
40769
+ let credential;
40770
+ try {
40771
+ credential = await this.credentialSession.bearer();
40772
+ } catch (error) {
40773
+ throw new AgentActivityPublishError("activity_credential_failed", error);
40774
+ }
40775
+ const timeoutSignal = AbortSignal.timeout(this.requestTimeoutMs);
40776
+ let response;
40777
+ try {
40778
+ response = await this.fetcher(
40779
+ `${this.target.url}/functions/v1/activity`,
40780
+ {
40781
+ method: "POST",
40782
+ headers: {
40783
+ authorization: `Bearer ${credential}`,
40784
+ apikey: this.target.anonKey,
40785
+ "content-type": "application/json"
40786
+ },
40787
+ body: JSON.stringify({
40788
+ version: frame.version,
40789
+ workspace_id: frame.workspaceId,
40790
+ stream_id: frame.streamId,
40791
+ sequence: frame.sequence,
40792
+ phase: frame.phase,
40793
+ signal_id: frame.signalId,
40794
+ tool_title: frame.toolTitle,
40795
+ elapsed_ms: frame.elapsedMs
40796
+ }),
40797
+ signal: timeoutSignal
40798
+ }
40799
+ );
40800
+ } catch (error) {
40801
+ throw new AgentActivityPublishError(
40802
+ timeoutSignal.aborted ? "activity_request_timeout" : "activity_transport_failed",
40803
+ error
40804
+ );
40805
+ }
40806
+ await response.body?.cancel().catch(() => void 0);
40807
+ if (!response.ok) {
40808
+ throw new AgentActivityPublishError("activity_http_rejected");
40809
+ }
40810
+ }
40811
+ };
40812
+ var ListenerActivityController = class {
40813
+ constructor(options) {
40814
+ this.options = options;
40815
+ this.clock = options.clock ?? SYSTEM_CLOCK;
40816
+ this.streamId = options.streamId ?? (0, import_node_crypto21.randomUUID)();
40817
+ this.events = { update: (update) => this.onSessionUpdate(update) };
40818
+ }
40819
+ options;
40820
+ events;
40821
+ clock;
40822
+ streamId;
40823
+ sequence = 0;
40824
+ phase = "idle";
40825
+ signalId = null;
40826
+ signalStartedAt = null;
40827
+ runningTools = /* @__PURE__ */ new Map();
40828
+ latestToolId = null;
40829
+ dirty = false;
40830
+ sending = false;
40831
+ closed = false;
40832
+ lastSentAt = Number.NEGATIVE_INFINITY;
40833
+ timer = null;
40834
+ heartbeatTimer = null;
40835
+ /** Observe the listener state machine without changing its durable effect path. */
40836
+ onRuntimeEvent(event) {
40837
+ if (event.type === "ready") {
40838
+ this.setIdle();
40839
+ } else if (event.type === "delivery_claim" && event.signalId !== null) {
40840
+ this.beginSignal(event.signalId);
40841
+ } else if (event.type === "routing_decision") {
40842
+ this.beginSignal(event.signalId);
40843
+ } else if (event.type === "effect") {
40844
+ this.setIdle();
40845
+ }
40846
+ }
40847
+ /** Wrap one provider model so prompt and reply phases are visible. */
40848
+ instrumentModel(model) {
40849
+ return {
40850
+ start: async () => await model.start(),
40851
+ prompt: async (signal, mode3, prompt, attempt) => {
40852
+ this.beginSignal(signal.id);
40853
+ this.setPhase("prompting");
40854
+ const result = await model.prompt(signal, mode3, prompt, attempt);
40855
+ this.runningTools.clear();
40856
+ this.latestToolId = null;
40857
+ this.setPhase("replying");
40858
+ return result;
40859
+ },
40860
+ cancel: () => model.cancel(),
40861
+ close: async () => await model.close()
40862
+ };
40863
+ }
40864
+ /** Stop pending local timers; a missing next frame becomes stale in the panel. */
40865
+ close() {
40866
+ this.closed = true;
40867
+ if (this.timer !== null) this.clock.clearTimer(this.timer);
40868
+ if (this.heartbeatTimer !== null) this.clock.clearTimer(this.heartbeatTimer);
40869
+ this.timer = null;
40870
+ this.heartbeatTimer = null;
40871
+ }
40872
+ onSessionUpdate(update) {
40873
+ if (this.signalId === null) return;
40874
+ if (update.kind !== "tool_call" && update.kind !== "tool_call_update") return;
40875
+ const id = update.toolCallId;
40876
+ if (!id) return;
40877
+ const status = update.status?.toLowerCase();
40878
+ if (status && TERMINAL_TOOL_STATUSES.has(status)) {
40879
+ this.runningTools.delete(id);
40880
+ if (this.latestToolId === id) {
40881
+ this.latestToolId = [...this.runningTools.keys()].at(-1) ?? null;
40882
+ }
40883
+ this.setPhase(this.runningTools.size > 0 ? "tool-running" : "prompting");
40884
+ return;
40885
+ }
40886
+ const sanitizedTitle = update.title === void 0 ? this.runningTools.get(id) : sanitizeText(update.title).slice(0, ACTIVITY_TOOL_TITLE_MAX);
40887
+ const title = sanitizedTitle && sanitizedTitle.length > 0 ? sanitizedTitle : "Tool";
40888
+ this.runningTools.set(id, title);
40889
+ this.latestToolId = id;
40890
+ this.setPhase("tool-running");
40891
+ }
40892
+ beginSignal(signalId) {
40893
+ if (this.signalId === signalId) return;
40894
+ this.signalId = signalId;
40895
+ this.signalStartedAt = this.clock.now();
40896
+ this.runningTools.clear();
40897
+ this.latestToolId = null;
40898
+ this.setPhase("claimed");
40899
+ }
40900
+ setIdle() {
40901
+ this.signalId = null;
40902
+ this.signalStartedAt = null;
40903
+ this.runningTools.clear();
40904
+ this.latestToolId = null;
40905
+ this.setPhase("idle");
40906
+ }
40907
+ setPhase(phase) {
40908
+ this.phase = phase;
40909
+ if (this.heartbeatTimer !== null) {
40910
+ this.clock.clearTimer(this.heartbeatTimer);
40911
+ this.heartbeatTimer = null;
40912
+ }
40913
+ this.dirty = true;
40914
+ this.schedule();
40915
+ }
40916
+ armHeartbeat() {
40917
+ if (this.closed || this.heartbeatTimer !== null) return;
40918
+ this.heartbeatTimer = this.clock.setTimer(() => {
40919
+ this.heartbeatTimer = null;
40920
+ this.dirty = true;
40921
+ this.schedule();
40922
+ }, ACTIVITY_HEARTBEAT_MS);
40923
+ }
40924
+ schedule() {
40925
+ if (this.closed || this.timer !== null || this.sending) return;
40926
+ const delay2 = Math.max(
40927
+ 0,
40928
+ this.lastSentAt + ACTIVITY_FRAME_INTERVAL_MS - this.clock.now()
40929
+ );
40930
+ if (delay2 === 0) {
40931
+ void this.flush();
40932
+ return;
40933
+ }
40934
+ this.timer = this.clock.setTimer(() => {
40935
+ this.timer = null;
40936
+ void this.flush();
40937
+ }, delay2);
40938
+ }
40939
+ async flush() {
40940
+ if (this.closed || this.sending || !this.dirty) return;
40941
+ this.dirty = false;
40942
+ this.sending = true;
40943
+ this.lastSentAt = this.clock.now();
40944
+ const toolTitle = this.latestToolId === null ? null : this.runningTools.get(this.latestToolId) ?? null;
40945
+ const frame = {
40946
+ version: 1,
40947
+ workspaceId: this.options.workspaceId,
40948
+ streamId: this.streamId,
40949
+ sequence: ++this.sequence,
40950
+ phase: this.phase,
40951
+ signalId: this.signalId,
40952
+ toolTitle,
40953
+ elapsedMs: this.signalStartedAt === null ? 0 : Math.max(0, Math.round(this.clock.now() - this.signalStartedAt))
40954
+ };
40955
+ try {
40956
+ await this.options.transport.publish(frame);
40957
+ } catch (error) {
40958
+ this.options.onPublishFailure?.(activityPublishErrorCode(error));
40959
+ } finally {
40960
+ this.sending = false;
40961
+ if (this.dirty) this.schedule();
40962
+ else this.armHeartbeat();
40963
+ }
40964
+ }
40965
+ };
40966
+
40967
+ // src/listener/http-client.ts
40968
+ var import_node_http2 = require("node:http");
40969
+ var import_node_https = require("node:https");
40970
+ var import_node_zlib = require("node:zlib");
40971
+ var LISTENER_HTTP_IDLE_TIMEOUT_MS = 6e4;
40972
+ function responseHeaders(message) {
40973
+ const headers = new Headers();
40974
+ for (let index = 0; index < message.rawHeaders.length; index += 2) {
40975
+ const name = message.rawHeaders[index];
40976
+ const value = message.rawHeaders[index + 1];
40977
+ if (name !== void 0 && value !== void 0) headers.append(name, value);
40978
+ }
40979
+ return headers;
40980
+ }
40981
+ function decodeResponseBody(bytes, headers) {
40982
+ const codings = (headers.get("content-encoding") ?? "").split(",").map((coding) => coding.trim().toLowerCase()).filter((coding) => coding !== "" && coding !== "identity");
40983
+ if (!codings.every((coding) => ["br", "deflate", "gzip", "x-gzip"].includes(coding))) {
40984
+ return Uint8Array.from(bytes).buffer;
40985
+ }
40986
+ let decoded = bytes;
40987
+ for (const coding of codings.reverse()) {
40988
+ if (coding === "br") decoded = (0, import_node_zlib.brotliDecompressSync)(decoded);
40989
+ else if (coding === "deflate") decoded = (0, import_node_zlib.inflateSync)(decoded);
40990
+ else decoded = (0, import_node_zlib.gunzipSync)(decoded);
40991
+ }
40992
+ return Uint8Array.from(decoded).buffer;
40993
+ }
40994
+ var ListenerHttpClient = class {
40995
+ fetch;
40996
+ httpAgent = new import_node_http2.Agent({
40997
+ keepAlive: true,
40998
+ maxSockets: 1,
40999
+ maxFreeSockets: 1,
41000
+ scheduling: "fifo"
41001
+ });
41002
+ httpsAgent = new import_node_https.Agent({
41003
+ keepAlive: true,
41004
+ maxSockets: 1,
41005
+ maxFreeSockets: 1,
41006
+ scheduling: "fifo"
41007
+ });
41008
+ idleTimeoutMs;
41009
+ sockets = /* @__PURE__ */ new WeakSet();
41010
+ requestCount = 0;
41011
+ openedCount = 0;
41012
+ activeRequests = 0;
41013
+ idleTimer = null;
41014
+ closed = false;
41015
+ constructor(options = {}) {
41016
+ const idleTimeoutMs = options.idleTimeoutMs ?? LISTENER_HTTP_IDLE_TIMEOUT_MS;
41017
+ if (!Number.isSafeInteger(idleTimeoutMs) || idleTimeoutMs <= 0) {
41018
+ throw new Error("listener HTTP idle timeout must be a positive integer");
41019
+ }
41020
+ this.idleTimeoutMs = idleTimeoutMs;
41021
+ this.fetch = this.request.bind(this);
41022
+ }
41023
+ /** Snapshot process-local counts without exposing the agents themselves. */
41024
+ metrics() {
41025
+ return {
41026
+ requests: this.requestCount,
41027
+ connectionsOpened: this.openedCount,
41028
+ connectionReuseRatio: this.openedCount === 0 ? 0 : this.requestCount / this.openedCount
41029
+ };
41030
+ }
41031
+ /** Close every idle or active socket when the listener process stops. */
41032
+ close() {
41033
+ if (this.closed) return;
41034
+ this.closed = true;
41035
+ this.clearIdleTimer();
41036
+ this.destroyAgents();
41037
+ }
41038
+ clearIdleTimer() {
41039
+ if (this.idleTimer === null) return;
41040
+ clearTimeout(this.idleTimer);
41041
+ this.idleTimer = null;
41042
+ }
41043
+ destroyAgents() {
41044
+ this.httpAgent.destroy();
41045
+ this.httpsAgent.destroy();
41046
+ }
41047
+ beginRequest() {
41048
+ if (this.closed) throw new Error("listener HTTP client is closed");
41049
+ this.clearIdleTimer();
41050
+ this.requestCount += 1;
41051
+ this.activeRequests += 1;
41052
+ }
41053
+ finishRequest() {
41054
+ this.activeRequests -= 1;
41055
+ if (this.activeRequests !== 0 || this.closed) return;
41056
+ this.idleTimer = setTimeout(() => {
41057
+ this.idleTimer = null;
41058
+ if (this.activeRequests === 0 && !this.closed) this.destroyAgents();
41059
+ }, this.idleTimeoutMs);
41060
+ this.idleTimer.unref?.();
41061
+ }
41062
+ trackSocket(request) {
41063
+ request.once("socket", (socket) => {
41064
+ if (this.sockets.has(socket)) return;
41065
+ this.sockets.add(socket);
41066
+ const opened = () => {
41067
+ this.openedCount += 1;
41068
+ };
41069
+ if (socket.connecting) socket.once("connect", opened);
41070
+ else opened();
41071
+ });
41072
+ }
41073
+ async request(input, init) {
41074
+ const webRequest = new Request(input, init);
41075
+ const body = webRequest.method === "GET" || webRequest.method === "HEAD" ? null : Buffer.from(await webRequest.arrayBuffer());
41076
+ let url = new URL(webRequest.url);
41077
+ let method = webRequest.method;
41078
+ let headers = new Headers(webRequest.headers);
41079
+ let redirected = false;
41080
+ for (let redirects = 0; ; redirects += 1) {
41081
+ const response = await this.sendOnce({
41082
+ url,
41083
+ method,
41084
+ headers,
41085
+ body: method === "GET" || method === "HEAD" ? null : body,
41086
+ signal: webRequest.signal,
41087
+ redirected
41088
+ });
41089
+ const location2 = response.headers.get("location");
41090
+ if (location2 === null || ![301, 302, 303, 307, 308].includes(response.status) || webRequest.redirect === "manual") {
41091
+ return response;
41092
+ }
41093
+ if (webRequest.redirect === "error" || redirects >= 20) {
41094
+ throw new TypeError("fetch failed while following a redirect");
41095
+ }
41096
+ const nextUrl = new URL(location2, url);
41097
+ if (nextUrl.protocol !== "http:" && nextUrl.protocol !== "https:") {
41098
+ throw new TypeError("listener HTTP client accepts only http and https URLs");
41099
+ }
41100
+ const rewriteToGet = response.status === 303 && method !== "HEAD" || (response.status === 301 || response.status === 302) && method === "POST";
41101
+ if (rewriteToGet) {
41102
+ method = "GET";
41103
+ for (const name of [
41104
+ "content-encoding",
41105
+ "content-language",
41106
+ "content-length",
41107
+ "content-location",
41108
+ "content-type",
41109
+ "transfer-encoding"
41110
+ ]) {
41111
+ headers.delete(name);
41112
+ }
41113
+ }
41114
+ if (nextUrl.origin !== url.origin) {
41115
+ for (const name of [
41116
+ "apikey",
41117
+ "authorization",
41118
+ "cookie",
41119
+ "host",
41120
+ "proxy-authorization"
41121
+ ]) {
41122
+ headers.delete(name);
41123
+ }
41124
+ }
41125
+ url = nextUrl;
41126
+ redirected = true;
41127
+ }
41128
+ }
41129
+ async sendOnce(options) {
41130
+ if (options.url.protocol !== "http:" && options.url.protocol !== "https:") {
41131
+ throw new TypeError("listener HTTP client accepts only http and https URLs");
41132
+ }
41133
+ const headers = Object.fromEntries(options.headers.entries());
41134
+ if (!("accept-encoding" in headers)) headers["accept-encoding"] = "gzip, deflate";
41135
+ if (options.body !== null && !("content-length" in headers) && !("transfer-encoding" in headers)) {
41136
+ headers["content-length"] = String(options.body.byteLength);
41137
+ }
41138
+ this.beginRequest();
41139
+ let finished = false;
41140
+ const finish = () => {
41141
+ if (finished) return;
41142
+ finished = true;
41143
+ this.finishRequest();
41144
+ };
41145
+ return await new Promise((resolve3, reject) => {
41146
+ const send = options.url.protocol === "https:" ? import_node_https.request : import_node_http2.request;
41147
+ const agent = options.url.protocol === "https:" ? this.httpsAgent : this.httpAgent;
41148
+ let request;
41149
+ try {
41150
+ request = send(options.url, {
41151
+ agent,
41152
+ method: options.method,
41153
+ headers,
41154
+ signal: options.signal
41155
+ });
41156
+ } catch (error) {
41157
+ finish();
41158
+ reject(error);
41159
+ return;
41160
+ }
41161
+ this.trackSocket(request);
41162
+ request.once("error", (error) => {
41163
+ finish();
41164
+ reject(error);
41165
+ });
41166
+ request.once("response", (message) => {
41167
+ const chunks = [];
41168
+ let settled = false;
41169
+ const rejectResponse = (error) => {
41170
+ if (settled) return;
41171
+ settled = true;
41172
+ finish();
41173
+ reject(error);
41174
+ };
41175
+ message.on("data", (chunk) => {
41176
+ chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
41177
+ });
41178
+ message.once("aborted", () => {
41179
+ rejectResponse(new TypeError("response body was aborted"));
41180
+ });
41181
+ message.once("error", rejectResponse);
41182
+ message.once("end", () => {
41183
+ if (settled) return;
41184
+ settled = true;
41185
+ finish();
41186
+ const status = message.statusCode ?? 0;
41187
+ const bytes = Buffer.concat(chunks);
41188
+ const webHeaders = responseHeaders(message);
41189
+ const responseBody2 = status === 204 || status === 205 || status === 304 ? null : decodeResponseBody(bytes, webHeaders);
41190
+ try {
41191
+ const response = new Response(responseBody2, {
41192
+ status,
41193
+ statusText: message.statusMessage,
41194
+ headers: webHeaders
41195
+ });
41196
+ Object.defineProperties(response, {
41197
+ redirected: { value: options.redirected },
41198
+ url: { value: options.url.href }
41199
+ });
41200
+ resolve3(response);
41201
+ } catch (error) {
41202
+ reject(error);
41203
+ }
41204
+ });
41205
+ });
41206
+ try {
41207
+ if (options.body !== null && options.body.byteLength > 0) {
41208
+ request.write(options.body);
41209
+ }
41210
+ request.end();
41211
+ } catch (error) {
41212
+ request.destroy();
41213
+ finish();
41214
+ reject(error);
41215
+ }
41216
+ });
41217
+ }
41218
+ };
41219
+
39998
41220
  // src/resume.ts
39999
41221
  var import_node_child_process8 = require("node:child_process");
40000
41222
  function execFileText(file, args) {
40001
- return new Promise((resolve2, reject) => {
41223
+ return new Promise((resolve3, reject) => {
40002
41224
  (0, import_node_child_process8.execFile)(file, [...args], {
40003
41225
  encoding: "utf8",
40004
41226
  maxBuffer: 4 * 1024 * 1024
40005
41227
  }, (error, stdout) => {
40006
41228
  if (error) reject(error);
40007
- else resolve2(stdout);
41229
+ else resolve3(stdout);
40008
41230
  });
40009
41231
  });
40010
41232
  }
@@ -40410,8 +41632,8 @@ var ACCEPTED_AGENT_CREDENTIAL_MESSAGES = [
40410
41632
  AGENT_CREDENTIAL_MESSAGE_D088
40411
41633
  ];
40412
41634
  function packageVersion() {
40413
- if ("0.1.45".length > 0) {
40414
- return "0.1.45";
41635
+ if ("0.1.47".length > 0) {
41636
+ return "0.1.47";
40415
41637
  }
40416
41638
  try {
40417
41639
  const value = JSON.parse(
@@ -41035,7 +42257,7 @@ async function runNew(args) {
41035
42257
  assertWorkspaceName(name);
41036
42258
  const cloud = await target(args);
41037
42259
  const human = await humanCredential(args, cloud);
41038
- const proposedId = (0, import_node_crypto20.randomUUID)();
42260
+ const proposedId = (0, import_node_crypto22.randomUUID)();
41039
42261
  let result;
41040
42262
  try {
41041
42263
  result = await new ThinCommandClient(cloud).sendConnect({
@@ -42058,7 +43280,7 @@ function accepted(label, result) {
42058
43280
  );
42059
43281
  }
42060
43282
  }
42061
- async function agentSession(cloud, workspaceId2, agent) {
43283
+ async function agentSession(cloud, workspaceId2, agent, fetcher) {
42062
43284
  let store2 = null;
42063
43285
  try {
42064
43286
  const candidate = await agentCredentialStore({
@@ -42084,7 +43306,8 @@ async function agentSession(cloud, workspaceId2, agent) {
42084
43306
  runId: agent.runId,
42085
43307
  expiresAt: agent.expiresAt
42086
43308
  },
42087
- store: store2
43309
+ store: store2,
43310
+ ...fetcher ? { fetcher } : {}
42088
43311
  });
42089
43312
  }
42090
43313
  async function commandWorkspaceAndCredential(args, cloud, options = {}) {
@@ -42366,8 +43589,8 @@ function prepareSignalAttachments(localPaths) {
42366
43589
  name,
42367
43590
  bytes,
42368
43591
  contentType,
42369
- fileId: (0, import_node_crypto20.randomUUID)(),
42370
- versionId: (0, import_node_crypto20.randomUUID)(),
43592
+ fileId: (0, import_node_crypto22.randomUUID)(),
43593
+ versionId: (0, import_node_crypto22.randomUUID)(),
42371
43594
  createCommandId: newCommandId(),
42372
43595
  commitCommandId: newCommandId()
42373
43596
  };
@@ -43052,6 +44275,7 @@ async function runInboxNotifyCommand(args) {
43052
44275
  );
43053
44276
  }
43054
44277
  const controller = new AbortController();
44278
+ const httpClient = new ListenerHttpClient();
43055
44279
  const stop = () => controller.abort();
43056
44280
  process.on("SIGINT", stop);
43057
44281
  process.on("SIGTERM", stop);
@@ -43082,7 +44306,7 @@ async function runInboxNotifyCommand(args) {
43082
44306
  ...after === null ? {} : { after }
43083
44307
  }
43084
44308
  },
43085
- { signal: controller.signal }
44309
+ { signal: controller.signal, fetcher: httpClient.fetch }
43086
44310
  );
43087
44311
  },
43088
44312
  emit: async (signal) => {
@@ -43116,6 +44340,7 @@ async function runInboxNotifyCommand(args) {
43116
44340
  } finally {
43117
44341
  process.off("SIGINT", stop);
43118
44342
  process.off("SIGTERM", stop);
44343
+ httpClient.close();
43119
44344
  }
43120
44345
  }
43121
44346
  async function runReceipt(args) {
@@ -43188,6 +44413,7 @@ async function runInboxFollowCommand(args) {
43188
44413
  includeStale: args.has("include-stale")
43189
44414
  };
43190
44415
  const controller = new AbortController();
44416
+ const httpClient = new ListenerHttpClient();
43191
44417
  let legacyCursorWarned = false;
43192
44418
  let malformedRowWarnings = 0;
43193
44419
  const onAbortSignal = () => controller.abort();
@@ -43219,7 +44445,7 @@ async function runInboxFollowCommand(args) {
43219
44445
  cloud,
43220
44446
  credential,
43221
44447
  query,
43222
- { signal: controller.signal },
44448
+ { signal: controller.signal, fetcher: httpClient.fetch },
43223
44449
  {
43224
44450
  allowLegacyCursorFallback: true,
43225
44451
  tolerateMalformedRows: true,
@@ -43251,7 +44477,7 @@ async function runInboxFollowCommand(args) {
43251
44477
  cloud,
43252
44478
  credential,
43253
44479
  query,
43254
- { signal: controller.signal }
44480
+ { signal: controller.signal, fetcher: httpClient.fetch }
43255
44481
  );
43256
44482
  },
43257
44483
  emit: (frame) => {
@@ -43269,6 +44495,7 @@ async function runInboxFollowCommand(args) {
43269
44495
  } finally {
43270
44496
  process.off("SIGINT", onAbortSignal);
43271
44497
  process.off("SIGTERM", onAbortSignal);
44498
+ httpClient.close();
43272
44499
  }
43273
44500
  }
43274
44501
  function listenerUuid(value, flag) {
@@ -43453,16 +44680,107 @@ function listenerAttendanceState(status, evidence) {
43453
44680
  function listenerAttendanceRemedy(principalId) {
43454
44681
  return `cswarm hook install claude --principal-id ${principalId} --write, then start a fresh session. Or restart the listener with --route worker.`;
43455
44682
  }
44683
+ function listenerReadHealthSummary(status, nowMs) {
44684
+ return summarizeListenerReadHealth(
44685
+ status.readHealth ?? emptyListenerReadHealth(),
44686
+ status.readyAt,
44687
+ nowMs
44688
+ );
44689
+ }
44690
+ function listenerLapseNotices(status, summary) {
44691
+ const health = status.readHealth ?? emptyListenerReadHealth();
44692
+ const notices = [];
44693
+ if (health.currentReasonCode === "host_ports_exhausted") {
44694
+ notices.push({
44695
+ code: "listener_host_ports_exhausted",
44696
+ message: "This host has run out of outbound ports. The listener is probing only once per minute so it does not amplify the outage.",
44697
+ nextStep: "Find the consumer: lsof -nP -iTCP | awk '{print $1}' | sort | uniq -c | sort -rn"
44698
+ });
44699
+ } else if (
44700
+ // Reuse arrival-watch.ts's 60s loud-lapse transition. The listener keeps
44701
+ // the episode in durable status instead of the monitor's process-local machine.
44702
+ summary.currentEpisodeDurationMs !== null && summary.currentEpisodeDurationMs >= ARRIVAL_RETRY_NOTICE_THRESHOLD_MS
44703
+ ) {
44704
+ notices.push({
44705
+ code: "listener_read_retry_persisting",
44706
+ message: `Listener reads have failed continuously for ${Math.floor(summary.currentEpisodeDurationMs / 1e3)}s. This is still in progress.`,
44707
+ nextStep: "Check cswarm status and the CommonSwarm service. If both are healthy, restart the listener."
44708
+ });
44709
+ }
44710
+ if (summary.throughputLapseHours.length > 0) {
44711
+ const latest = summary.throughputLapseHours.at(-1);
44712
+ notices.push({
44713
+ code: "listener_claim_throughput_lapse",
44714
+ message: `Claim throughput fell below 0.50 for the full hour at ${latest.hourStart}: ${latest.claims}/${Math.round(latest.expectedClaims)} expected (${latest.ratio.toFixed(3)}).`,
44715
+ nextStep: "This host is starving the listener \u2014 check load/memory pressure (sysctl kern.memorystatus_vm_pressure_level), or move the listener."
44716
+ });
44717
+ }
44718
+ return notices;
44719
+ }
44720
+ async function listenerProviderInstallEvidence(status) {
44721
+ if (status.provider !== "claude") return null;
44722
+ try {
44723
+ const notice = await inspectClaudeBridgeExecutable(
44724
+ status.providerExecutable ?? "claude-agent-acp",
44725
+ { pathEnv: process.env.PATH, env: process.env }
44726
+ );
44727
+ return {
44728
+ executable: notice.executable,
44729
+ providerVersion: notice.providerVersion,
44730
+ bundledAgentSdkVersion: notice.bundledAgentSdkVersion,
44731
+ bundledClaudeCodeVersion: notice.bundledClaudeCodeVersion
44732
+ };
44733
+ } catch {
44734
+ return {
44735
+ executable: null,
44736
+ providerVersion: null,
44737
+ bundledAgentSdkVersion: null,
44738
+ bundledClaudeCodeVersion: null
44739
+ };
44740
+ }
44741
+ }
44742
+ function versionIsBelow(left, right) {
44743
+ if (!left || !right) return false;
44744
+ try {
44745
+ return compareSemVer(left, right) < 0;
44746
+ } catch {
44747
+ return false;
44748
+ }
44749
+ }
44750
+ function providerRestartRequired(status, installed) {
44751
+ if (!installed) return false;
44752
+ return status.providerVersion !== null && status.providerVersion !== void 0 && installed.providerVersion !== null && status.providerVersion !== installed.providerVersion || status.providerBundledClaudeCodeVersion !== null && status.providerBundledClaudeCodeVersion !== void 0 && installed.bundledClaudeCodeVersion !== null && status.providerBundledClaudeCodeVersion !== installed.bundledClaudeCodeVersion;
44753
+ }
43456
44754
  function listenerStatusJson(status, permissionMode, evidence = {
43457
44755
  pendingForMainOldestAt: null,
43458
44756
  hookSurfaceExists: false,
43459
44757
  hookSurfaceAdvanced: false
43460
- }, nowMs = Date.now()) {
44758
+ }, nowMs = Date.now(), installed = null) {
43461
44759
  const mode3 = permissionMode ?? status.permissionMode;
43462
44760
  const attendance = listenerAttendanceState(status, evidence);
43463
44761
  const pending = status.pendingForMainCount ?? 0;
44762
+ const readHealth = status.readHealth ?? emptyListenerReadHealth();
44763
+ const readSummary = listenerReadHealthSummary(status, nowMs);
44764
+ const lapseNotices = listenerLapseNotices(status, readSummary);
43464
44765
  return {
43465
44766
  ...status,
44767
+ providerExecutable: status.providerExecutable ?? null,
44768
+ providerExecutableMeasured: typeof status.providerExecutable === "string",
44769
+ providerVersion: status.providerVersion ?? null,
44770
+ providerVersionMeasured: typeof status.providerVersion === "string",
44771
+ providerBundledAgentSdkVersion: status.providerBundledAgentSdkVersion ?? null,
44772
+ providerBundledClaudeCodeVersion: status.providerBundledClaudeCodeVersion ?? null,
44773
+ providerMinimumRequiredVersion: status.providerMinimumRequiredVersion ?? null,
44774
+ lastErrorReasonCode: status.lastErrorReasonCode ?? null,
44775
+ providerBelowDemandedMinimum: versionIsBelow(
44776
+ status.providerBundledClaudeCodeVersion,
44777
+ status.providerMinimumRequiredVersion
44778
+ ),
44779
+ providerOnDiskExecutable: installed?.executable ?? null,
44780
+ providerOnDiskVersion: installed?.providerVersion ?? null,
44781
+ providerOnDiskBundledAgentSdkVersion: installed?.bundledAgentSdkVersion ?? null,
44782
+ providerOnDiskBundledClaudeCodeVersion: installed?.bundledClaudeCodeVersion ?? null,
44783
+ providerRestartRequired: providerRestartRequired(status, installed),
43466
44784
  ...attendance,
43467
44785
  hookSurfaceExists: evidence.hookSurfaceExists,
43468
44786
  hookSurfaceAdvanced: evidence.hookSurfaceAdvanced,
@@ -43470,6 +44788,22 @@ function listenerStatusJson(status, permissionMode, evidence = {
43470
44788
  pendingForMainOldestAgeMs: evidence.pendingForMainOldestAt === null ? null : Math.max(0, nowMs - Date.parse(evidence.pendingForMainOldestAt)),
43471
44789
  attendanceWarningCode: pending > 0 ? "listener_unattended_main_queue" : null,
43472
44790
  attendanceNextStep: pending > 0 ? listenerAttendanceRemedy(status.principalId) : null,
44791
+ readRetryCurrentEpisodeStartedAt: readHealth.currentEpisodeStartedAt,
44792
+ readRetryCurrentEpisodeAttempts: readHealth.currentEpisodeAttempts,
44793
+ readRetryCurrentReasonCode: readHealth.currentReasonCode,
44794
+ readRetryCurrentHttpStatus: readHealth.currentHttpStatus,
44795
+ readRetryCurrentErrorConstructor: readHealth.currentErrorConstructor,
44796
+ readRetryCurrentEpisodeDurationMs: readSummary.currentEpisodeDurationMs,
44797
+ readRetryEpisodesLast24h: readSummary.episodesLast24h,
44798
+ readRetryLongestEpisodeAttemptsLast24h: readSummary.longestEpisodeAttemptsLast24h,
44799
+ readRetryLongestEpisodeDurationMsLast24h: readSummary.longestEpisodeDurationMsLast24h,
44800
+ readRetriesLastHour: readSummary.retriesLastHour,
44801
+ readRetryHours: readSummary.retryHours,
44802
+ claimCadenceMs: readHealth.claimCadenceMs,
44803
+ claimThroughputHours: readSummary.claimThroughputHours,
44804
+ listenerLapse: lapseNotices.length > 0,
44805
+ listenerLapseCodes: lapseNotices.map((notice) => notice.code),
44806
+ listenerLapseNextSteps: lapseNotices.map((notice) => notice.nextStep),
43473
44807
  deliveryMode: status.deliveryMode ?? null,
43474
44808
  pendingDeliveryCount: status.pendingDeliveryCount ?? null,
43475
44809
  lastTerminalDeliveryFailureCount: status.lastTerminalDeliveryFailureCount ?? null,
@@ -43480,6 +44814,10 @@ function listenerStatusJson(status, permissionMode, evidence = {
43480
44814
  deferOverChars: status.deferOverChars ?? null,
43481
44815
  pendingForMainCount: status.pendingForMainCount ?? 0,
43482
44816
  droppedForMainCount: status.droppedForMainCount ?? 0,
44817
+ connectionsOpened: status.connectionsOpened ?? null,
44818
+ connectionReuseRatio: status.connectionReuseRatio ?? null,
44819
+ activityPublishFailures: status.activityPublishFailures ?? null,
44820
+ activityLastErrorCode: status.activityLastErrorCode ?? null,
43483
44821
  ...mode3 ? {
43484
44822
  permission_mode: mode3,
43485
44823
  /* "allowed once" alone overstates it: allowOnceOrDeny selects allow_once only when the
@@ -43495,27 +44833,58 @@ function renderListenerStatus(status, evidence = {
43495
44833
  pendingForMainOldestAt: null,
43496
44834
  hookSurfaceExists: false,
43497
44835
  hookSurfaceAdvanced: false
43498
- }, nowMs = Date.now()) {
44836
+ }, nowMs = Date.now(), installed = null) {
43499
44837
  const routeMode = status.routeMode ?? "worker";
43500
44838
  const pendingForMainCount = status.pendingForMainCount ?? 0;
43501
44839
  const droppedForMainCount = status.droppedForMainCount ?? 0;
43502
44840
  const unattendedCount = `${pendingForMainCount} ${pendingForMainCount === 1 ? "message is" : "messages are"} unattended`;
43503
44841
  const attendance = listenerAttendanceState(status, evidence);
44842
+ const readHealth = status.readHealth ?? emptyListenerReadHealth();
44843
+ const readSummary = listenerReadHealthSummary(status, nowMs);
44844
+ const lapseNotices = listenerLapseNotices(status, readSummary);
43504
44845
  const lines = [
43505
- pendingForMainCount > 0 ? `Listener WARNING for agent ${status.principalId}: ${unattendedCount}.` : `Listener ${status.state} for agent ${status.principalId}.`,
44846
+ lapseNotices.length > 0 ? `Listener LAPSE for agent ${status.principalId}: ${lapseNotices.map((notice) => notice.code).join(", ")}.` : pendingForMainCount > 0 ? `Listener WARNING for agent ${status.principalId}: ${unattendedCount}.` : `Listener ${status.state} for agent ${status.principalId}.`,
43506
44847
  `CONNECTED: ${attendance.connected ? "yes" : "no"}. Transport state is ${status.state}.`,
43507
44848
  `ATTENDED: ${attendance.attendanceState === "attended" ? "yes. The session hook has surfaced messages on this host" : attendance.attendanceState === "unattended" ? "no. The main-session queue is not draining" : attendance.attendanceState === "not_required" ? "not required for the worker route" : "not yet proven on this host"}.`,
43508
44849
  `HANDLED: ${attendance.handledState === "handled" ? "yes. A delivery acknowledgement is recorded" : attendance.handledState === "not_handled" ? "no. Queued messages have not reached the session hook" : "not yet measured"}.`,
43509
44850
  `Provider: ${status.provider}; process: ${status.pid}; started: ${status.startedAt}.`,
44851
+ `Provider executable: ${status.providerExecutable ?? "not measured"}.`,
44852
+ `Connections opened: ${status.connectionsOpened ?? "not measured"}.`,
44853
+ `Connection reuse ratio: ${status.connectionReuseRatio ?? "not measured"}.`,
44854
+ ...status.activityPublishFailures !== void 0 && status.activityPublishFailures > 0 ? [`Activity publish failures: ${status.activityPublishFailures}.`] : [],
44855
+ ...status.activityLastErrorCode ? [`Last activity publish error code: ${status.activityLastErrorCode}.`] : [],
43510
44856
  status.readyAt ? `Ready since: ${status.readyAt}.` : "Not ready yet.",
43511
44857
  status.lastSignalId ? pendingForMainCount > 0 ? `Last claimed and queued signal: ${status.lastSignalId}. It is not handled yet.` : routeMode === "worker" ? `Last handled signal: ${status.lastSignalId}.` : `Last listener signal: ${status.lastSignalId}. Local status does not prove its final observed receipt.` : "No signal has been handled yet.",
43512
- status.lastErrorCode ? `Last status code: ${status.lastErrorCode}.` : "No listener process error is recorded."
44858
+ status.lastErrorCode ? `Last status code: ${status.lastErrorCode}.` : "No listener process error is recorded.",
44859
+ readHealth.currentEpisodeStartedAt === null ? "Current read retry episode: none." : `Current read retry episode: ${readHealth.currentEpisodeAttempts} attempt${readHealth.currentEpisodeAttempts === 1 ? "" : "s"} since ${readHealth.currentEpisodeStartedAt}; reason ${readHealth.currentReasonCode}${readHealth.currentHttpStatus === null ? "" : ` (HTTP ${readHealth.currentHttpStatus})`}${readHealth.currentErrorConstructor === null ? "" : ` (${readHealth.currentErrorConstructor})`}.`,
44860
+ `Read retry episodes in the last 24h: ${readSummary.episodesLast24h}; retries in the rolling hour: ${readSummary.retriesLastHour}.`,
44861
+ readSummary.longestEpisodeAttemptsLast24h === 0 ? "Longest read retry episode in the last 24h: none recorded." : `Longest read retry episode in the last 24h: ${readSummary.longestEpisodeAttemptsLast24h} attempts over ${Math.floor(readSummary.longestEpisodeDurationMsLast24h / 1e3)}s.`,
44862
+ readSummary.retryHours.length === 0 ? "Read retries by hour in the last 24h: none." : `Read retries by hour in the last 24h: ${readSummary.retryHours.map((hour) => `${hour.hourStart}=${hour.retries}`).join("; ")}.`,
44863
+ readSummary.claimThroughputHours.length === 0 ? "Claim throughput by full hour: no complete listener hour is available yet." : `Claim throughput by full hour: ${readSummary.claimThroughputHours.map((hour) => `${hour.hourStart} ${hour.claims}/${Math.round(hour.expectedClaims)} (${hour.ratio.toFixed(3)})`).join("; ")}.`
43513
44864
  ];
44865
+ for (const notice of lapseNotices) {
44866
+ lines.push(`WARNING [${notice.code}]: ${notice.message}`);
44867
+ lines.push(`Next: ${notice.nextStep}`);
44868
+ }
43514
44869
  if (status.lastErrorDetail) {
43515
44870
  const [first, ...rest] = status.lastErrorDetail.split("\n");
43516
44871
  lines.push(`Last error detail (local only): ${first}`);
43517
44872
  for (const line of rest) lines.push(` ${line}`);
43518
44873
  }
44874
+ if (status.lastErrorReasonCode) {
44875
+ lines.push(`Last provider reason code: ${status.lastErrorReasonCode}.`);
44876
+ }
44877
+ if (status.provider === "claude" && status.lastErrorCode === "permission_canary_failed") {
44878
+ lines.push(
44879
+ `Canary diagnosis: ${listenerFailureMessage(
44880
+ status.lastErrorCode,
44881
+ status.provider,
44882
+ status.lastErrorDetail,
44883
+ status.lastErrorReasonCode,
44884
+ status.providerMinimumRequiredVersion
44885
+ )}.`
44886
+ );
44887
+ }
43519
44888
  if (status.lastWorkerStderrTail) {
43520
44889
  const tailLines = status.lastWorkerStderrTail.split("\n").filter((line) => line.trim().length > 0);
43521
44890
  lines.push("Worker stderr (local log only):");
@@ -43525,8 +44894,34 @@ function renderListenerStatus(status, evidence = {
43525
44894
  }
43526
44895
  if (status.providerVersion && status.providerLastMeasuredVersion) {
43527
44896
  lines.push(
43528
- status.providerVersion === status.providerLastMeasuredVersion ? `Provider version: ${status.providerVersion} (last measured: ${status.providerLastMeasuredVersion}).` : `Provider version ${status.providerVersion} is newer than the last measured version ${status.providerLastMeasuredVersion}. It is unverified but allowed because the startup permission canary passed. Next: verify this provider release with CommonSwarm and update the last-measured version.`
44897
+ status.providerVersion === status.providerLastMeasuredVersion ? `Provider version: ${status.providerVersion} (last measured: ${status.providerLastMeasuredVersion}).` : status.state === "ready" ? `Provider version ${status.providerVersion} is newer than the last measured version ${status.providerLastMeasuredVersion}. It is unverified but allowed because the startup permission canary passed. Next: verify this provider release with CommonSwarm and update the last-measured version.` : `Provider version ${status.providerVersion} is newer than the last measured version ${status.providerLastMeasuredVersion}. It was measured before startup failed; compatibility was not established. Next: resolve the startup failure before verifying this provider release.`
44898
+ );
44899
+ } else {
44900
+ lines.push("Provider version: not measured.");
44901
+ }
44902
+ if (status.provider === "claude") {
44903
+ lines.push(
44904
+ `Bundled Claude Code version: ${status.providerBundledClaudeCodeVersion ?? "not measured"}.`,
44905
+ `Bundled Claude agent SDK version: ${status.providerBundledAgentSdkVersion ?? "not measured"}.`
43529
44906
  );
44907
+ if (status.providerMinimumRequiredVersion) {
44908
+ lines.push(
44909
+ `Last API minimum demanded: Claude Code ${status.providerMinimumRequiredVersion}.`
44910
+ );
44911
+ }
44912
+ if (versionIsBelow(
44913
+ status.providerBundledClaudeCodeVersion,
44914
+ status.providerMinimumRequiredVersion
44915
+ )) {
44916
+ lines.push(
44917
+ `WARNING [claude_bridge_below_api_minimum]: this listener has bundled Claude Code ${status.providerBundledClaudeCodeVersion}, below the API minimum ${status.providerMinimumRequiredVersion}. Install the current bridge (npm i -g @agentclientprotocol/claude-agent-acp@latest), restart the listener, then run cswarm listen status and confirm that the bundled Claude Code version meets the API minimum ${status.providerMinimumRequiredVersion}.`
44918
+ );
44919
+ }
44920
+ if (providerRestartRequired(status, installed)) {
44921
+ lines.push(
44922
+ `A different Claude bridge is on disk: ${installed?.providerVersion ?? "version not measured"}${installed?.bundledClaudeCodeVersion ? ` (bundled Claude Code ${installed.bundledClaudeCodeVersion})` : ""}. Restart to pick up ${installed?.providerVersion ?? "the on-disk bridge"}.`
44923
+ );
44924
+ }
43530
44925
  }
43531
44926
  if (status.deliveryMode === "durable_claim") {
43532
44927
  lines.push("Delivery mode: durable claim and acknowledgement.");
@@ -43603,7 +44998,26 @@ async function unsurfacedPendingMainStats(instanceDirectory, fallback) {
43603
44998
  };
43604
44999
  }
43605
45000
  }
43606
- function listenerFailureMessage(code, provider, detail) {
45001
+ function quotedListenerFailureDetail(detail) {
45002
+ const recorded = detail?.trim();
45003
+ if (!recorded) return "not recorded";
45004
+ const bounded = recorded.length > 600 ? `${recorded.slice(0, 599)}\u2026` : recorded;
45005
+ return JSON.stringify(bounded);
45006
+ }
45007
+ function listenerProviderIdentitySummary(status) {
45008
+ const parts = [
45009
+ `Provider executable: ${status.providerExecutable ?? "not measured"}`,
45010
+ `provider version: ${status.providerVersion ?? "not measured"}`
45011
+ ];
45012
+ if (status.provider === "claude") {
45013
+ parts.push(
45014
+ `bundled Claude Code: ${status.providerBundledClaudeCodeVersion ?? "not measured"}`,
45015
+ `bundled Claude agent SDK: ${status.providerBundledAgentSdkVersion ?? "not measured"}`
45016
+ );
45017
+ }
45018
+ return parts.join("; ");
45019
+ }
45020
+ function listenerFailureMessage(code, provider, detail, reasonCode, minimumRequiredVersion) {
43607
45021
  if (code === "version_below_floor") {
43608
45022
  if (provider === "codex") {
43609
45023
  return "the Codex listener requires codex-acp 1.1.9 or newer; update the bridge, then retry";
@@ -43663,11 +45077,25 @@ function listenerFailureMessage(code, provider, detail) {
43663
45077
  }
43664
45078
  if (code === "permission_canary_failed") {
43665
45079
  if (provider === "claude") {
43666
- return "the Claude bridge did not complete the ACP permission canary; the startup canary ran, but no workspace signal prompt was delivered. Confirm Claude Code keychain/OAuth sign-in, then retry";
45080
+ const shape = classifyClaudeCanaryFailure(detail, reasonCode);
45081
+ const ran = "the Claude ACP permission canary ran, but no workspace signal prompt was delivered";
45082
+ const response = `bridge response [${shape.code}]: ${quotedListenerFailureDetail(detail)}`;
45083
+ if (shape.code === "claude_bridge_version_required") {
45084
+ const minimum = minimumRequiredVersion ?? shape.minimumRequiredVersion;
45085
+ return `${ran}. ${response}. Next: install the current bridge (npm i -g @agentclientprotocol/claude-agent-acp@latest), restart the listener, then run cswarm listen status and confirm that the bundled Claude Code version meets the API minimum ${minimum ?? "reported there"}`;
45086
+ }
45087
+ if (shape.code === "claude_canary_timeout") {
45088
+ return `${ran}. ${response}. Next: run claude -p and check for session-limit text, check host load, then retry`;
45089
+ }
45090
+ if (shape.code === "claude_canary_auth_failed") {
45091
+ return `${ran}. ${response}. Next: confirm Claude Code keychain/OAuth sign-in, then retry`;
45092
+ }
45093
+ return `${ran}. ${response}. The cause was not determined. Next: inspect the quoted bridge response and local worker stderr, then retry only after the cause is known or the failure appears transient`;
43667
45094
  }
43668
45095
  if (provider === "codex") {
43669
45096
  const recorded = detail?.trim();
43670
- return recorded ? `the Codex bridge did not complete the read-only ACP permission canary; no workspace signal prompt was delivered. Recorded reason: ${JSON.stringify(recorded)}` : "the Codex bridge did not complete the read-only ACP permission canary; no workspace signal prompt was delivered. The recorded reason was unavailable. Next: run cswarm listen status, then retry";
45097
+ const gate = "the Codex listener did not pass the read-only ACP permission safety gate; no workspace signal prompt was delivered";
45098
+ return recorded ? `${gate}. Recorded reason: ${JSON.stringify(recorded)}` : `${gate}. The recorded reason was unavailable. Next: run cswarm listen status, then retry`;
43671
45099
  }
43672
45100
  if (provider === "grok") {
43673
45101
  return "the Grok bridge did not complete the ACP permission canary; no workspace signal prompt was delivered. The local cswarm listen status output includes the final error detail; read it, then retry";
@@ -43750,11 +45178,19 @@ async function runConfiguredListener(options) {
43750
45178
  principalId: options.principalId,
43751
45179
  ...options.stateDirectory ? { stateDirectory: options.stateDirectory } : {}
43752
45180
  });
43753
- const liveCredentialSession = await agentSession(
43754
- options.cloud,
43755
- options.workspaceId,
43756
- options.agent
43757
- );
45181
+ const httpClient = new ListenerHttpClient();
45182
+ let liveCredentialSession;
45183
+ try {
45184
+ liveCredentialSession = await agentSession(
45185
+ options.cloud,
45186
+ options.workspaceId,
45187
+ options.agent,
45188
+ httpClient.fetch
45189
+ );
45190
+ } catch (error) {
45191
+ httpClient.close();
45192
+ throw error;
45193
+ }
43758
45194
  let storedCredential = null;
43759
45195
  const credentialSession = {
43760
45196
  bearer: async () => {
@@ -43782,7 +45218,7 @@ async function runConfiguredListener(options) {
43782
45218
  options.cloud,
43783
45219
  credential,
43784
45220
  options.workspaceId,
43785
- context
45221
+ { ...context, fetcher: httpClient.fetch }
43786
45222
  );
43787
45223
  const provenance = listenerSenderProvenance(signal, senderDirectory);
43788
45224
  if (context.includeBrainDigest !== true) return provenance;
@@ -43793,7 +45229,8 @@ async function runConfiguredListener(options) {
43793
45229
  options.workspaceId,
43794
45230
  {
43795
45231
  ...context.signal ? { signal: context.signal } : {},
43796
- deadlineMs: context.deadlineMs
45232
+ deadlineMs: context.deadlineMs,
45233
+ fetcher: httpClient.fetch
43797
45234
  }
43798
45235
  );
43799
45236
  const brainDigest = await new FileBrainDigestStore(
@@ -43833,7 +45270,20 @@ async function runConfiguredListener(options) {
43833
45270
  let workerStderrGeneration = 0;
43834
45271
  let providerVersionNotice = null;
43835
45272
  const onVersionNotice = (notice) => {
43836
- providerVersionNotice = notice;
45273
+ providerVersionNotice = {
45274
+ ...providerVersionNotice ?? {},
45275
+ runningVersion: notice.runningVersion,
45276
+ lastMeasuredVersion: notice.lastMeasuredVersion
45277
+ };
45278
+ };
45279
+ const onClaudeRuntimeNotice = (notice) => {
45280
+ providerVersionNotice = {
45281
+ runningVersion: notice.providerVersion,
45282
+ lastMeasuredVersion: notice.lastMeasuredVersion,
45283
+ executable: notice.executable,
45284
+ bundledAgentSdkVersion: notice.bundledAgentSdkVersion,
45285
+ bundledClaudeCodeVersion: notice.bundledClaudeCodeVersion
45286
+ };
43837
45287
  };
43838
45288
  const newWorkerStderrTailSink = () => {
43839
45289
  const generation = ++workerStderrGeneration;
@@ -43843,7 +45293,7 @@ async function runConfiguredListener(options) {
43843
45293
  lastWorkerStderrTail = tail.length > 0 ? tail : null;
43844
45294
  };
43845
45295
  };
43846
- const newModel = (onCanaryAttempt) => {
45296
+ const newModel = (onCanaryAttempt, events) => {
43847
45297
  providerVersionNotice = null;
43848
45298
  return options.provider === "opencode" ? new OpenCodeListenerModel({
43849
45299
  cwd: options.cwd,
@@ -43852,6 +45302,7 @@ async function runConfiguredListener(options) {
43852
45302
  onWorkerStderrTail: newWorkerStderrTailSink(),
43853
45303
  onCanaryAttempt,
43854
45304
  onVersionNotice,
45305
+ events,
43855
45306
  ...options.model ? { model: options.model } : {},
43856
45307
  ...options.opencodeExecutable ? { executable: options.opencodeExecutable } : options.executable ? { executable: options.executable } : {}
43857
45308
  }) : options.provider === "claude" ? new ClaudeListenerModel({
@@ -43860,7 +45311,9 @@ async function runConfiguredListener(options) {
43860
45311
  promptTimeoutMs: resolveTurnBudgetMs,
43861
45312
  onWorkerStderrTail: newWorkerStderrTailSink(),
43862
45313
  onCanaryAttempt,
45314
+ onRuntimeNotice: onClaudeRuntimeNotice,
43863
45315
  onVersionNotice,
45316
+ events,
43864
45317
  ...options.claudeExecutable ? { executable: options.claudeExecutable } : options.executable ? { executable: options.executable } : {}
43865
45318
  }) : options.provider === "codex" ? new CodexListenerModel({
43866
45319
  cwd: options.cwd,
@@ -43869,6 +45322,7 @@ async function runConfiguredListener(options) {
43869
45322
  onWorkerStderrTail: newWorkerStderrTailSink(),
43870
45323
  onCanaryAttempt,
43871
45324
  onVersionNotice,
45325
+ events,
43872
45326
  ...options.codexExecutable ? { executable: options.codexExecutable } : options.executable ? { executable: options.executable } : {}
43873
45327
  }) : new GrokListenerModel({
43874
45328
  cwd: options.cwd,
@@ -43877,6 +45331,7 @@ async function runConfiguredListener(options) {
43877
45331
  onWorkerStderrTail: newWorkerStderrTailSink(),
43878
45332
  onCanaryAttempt,
43879
45333
  onVersionNotice,
45334
+ events,
43880
45335
  ...options.model ? { model: options.model } : {},
43881
45336
  ...options.effort ? { effort: options.effort } : {},
43882
45337
  ...options.executable ? { executable: options.executable } : {}
@@ -43907,6 +45362,7 @@ async function runConfiguredListener(options) {
43907
45362
  // one has run, else the configured cap.
43908
45363
  getTurnBudgetMs: () => lastAppliedTurnBudgetMs ?? turnBudgetMs,
43909
45364
  getProviderVersionNotice: () => providerVersionNotice,
45365
+ getConnectionMetrics: () => httpClient.metrics(),
43910
45366
  takeWorkerStderrTail: () => {
43911
45367
  const tail = lastWorkerStderrTail;
43912
45368
  lastWorkerStderrTail = null;
@@ -43940,28 +45396,53 @@ async function runConfiguredListener(options) {
43940
45396
  ts: (/* @__PURE__ */ new Date()).toISOString()
43941
45397
  });
43942
45398
  };
43943
- return await runListenerRuntime({
43944
- target: options.cloud,
45399
+ const activity = new ListenerActivityController({
43945
45400
  workspaceId: options.workspaceId,
43946
- principalId: options.principalId,
43947
- credentialSession,
43948
- store: effectStore,
43949
- model: newModel(onCanaryAttempt),
43950
- signal,
43951
- onEvent,
43952
- declareModel: listenerModelLabel(options.provider),
43953
- listenerInstanceId,
43954
- deliveryJournal: selectedJournal,
43955
- resolveSenderProvenance,
43956
- routeMode,
43957
- deferOverChars,
43958
- pendingMainQueue
45401
+ transport: new AgentActivityEndpointTransport(
45402
+ options.cloud,
45403
+ credentialSession,
45404
+ httpClient.fetch
45405
+ ),
45406
+ onPublishFailure: (code) => onEvent({
45407
+ type: "activity_publish_failure",
45408
+ code,
45409
+ ts: (/* @__PURE__ */ new Date()).toISOString()
45410
+ })
43959
45411
  });
45412
+ const instrumentedModel = activity.instrumentModel(
45413
+ newModel(onCanaryAttempt, activity.events)
45414
+ );
45415
+ try {
45416
+ return await runListenerRuntime({
45417
+ target: options.cloud,
45418
+ workspaceId: options.workspaceId,
45419
+ principalId: options.principalId,
45420
+ credentialSession,
45421
+ store: effectStore,
45422
+ model: instrumentedModel,
45423
+ signal,
45424
+ onEvent: (event) => {
45425
+ activity.onRuntimeEvent(event);
45426
+ onEvent(event);
45427
+ },
45428
+ declareModel: listenerModelLabel(options.provider),
45429
+ listenerInstanceId,
45430
+ deliveryJournal: selectedJournal,
45431
+ resolveSenderProvenance,
45432
+ routeMode,
45433
+ deferOverChars,
45434
+ pendingMainQueue,
45435
+ fetcher: httpClient.fetch
45436
+ });
45437
+ } finally {
45438
+ activity.close();
45439
+ }
43960
45440
  }
43961
45441
  });
43962
45442
  } finally {
43963
45443
  process.off("SIGINT", onProcessSignal);
43964
45444
  process.off("SIGTERM", onProcessSignal);
45445
+ httpClient.close();
43965
45446
  }
43966
45447
  }
43967
45448
  async function runListenStart(args) {
@@ -44111,18 +45592,30 @@ async function runListenStart(args) {
44111
45592
  if (error instanceof ListenerStartupError) {
44112
45593
  const failedStatus = await effectiveListenerStatus(paths).catch(() => null);
44113
45594
  const detail = failedStatus?.lastErrorCode === error.code ? failedStatus.lastErrorDetail : null;
44114
- throw new Error(listenerFailureMessage(error.code, provider, detail));
45595
+ const reasonCode = failedStatus?.lastErrorCode === error.code ? failedStatus.lastErrorReasonCode : null;
45596
+ const message = listenerFailureMessage(
45597
+ error.code,
45598
+ provider,
45599
+ detail,
45600
+ reasonCode,
45601
+ failedStatus?.providerMinimumRequiredVersion
45602
+ );
45603
+ throw new Error(
45604
+ failedStatus === null ? message : `${message}. ${listenerProviderIdentitySummary(failedStatus)}`
45605
+ );
44115
45606
  }
44116
45607
  throw error;
44117
45608
  }
44118
45609
  }
44119
45610
  if (status.state === "failed") {
44120
45611
  throw new Error(
44121
- listenerFailureMessage(
45612
+ `${listenerFailureMessage(
44122
45613
  status.lastErrorCode ?? "unknown_error",
44123
45614
  provider,
44124
- status.lastErrorDetail
44125
- )
45615
+ status.lastErrorDetail,
45616
+ status.lastErrorReasonCode,
45617
+ status.providerMinimumRequiredVersion
45618
+ )}. ${listenerProviderIdentitySummary(status)}`
44126
45619
  );
44127
45620
  }
44128
45621
  let attendanceEvidence = {
@@ -44304,11 +45797,22 @@ async function runListenStatusOrStop(args, command2) {
44304
45797
  hookSurfaceAdvanced: queueStats.hookSurfaceAdvanced
44305
45798
  };
44306
45799
  }
45800
+ const installed = command2 === "status" ? await listenerProviderInstallEvidence(status) : null;
44307
45801
  if (args.has("json")) {
44308
- printJson(listenerStatusJson(status, void 0, attendanceEvidence));
45802
+ printJson(
45803
+ listenerStatusJson(
45804
+ status,
45805
+ void 0,
45806
+ attendanceEvidence,
45807
+ Date.now(),
45808
+ installed
45809
+ )
45810
+ );
44309
45811
  } else {
44310
- process.stdout.write(`${renderListenerStatus(status, attendanceEvidence)}
44311
- `);
45812
+ process.stdout.write(
45813
+ `${renderListenerStatus(status, attendanceEvidence, Date.now(), installed)}
45814
+ `
45815
+ );
44312
45816
  }
44313
45817
  }
44314
45818
  async function runListenCanary(args) {
@@ -44345,16 +45849,23 @@ async function runListenCanary(args) {
44345
45849
  ...stateDirectory2 ? { stateDirectory: stateDirectory2 } : {}
44346
45850
  });
44347
45851
  const waitMs = parseWaitSeconds(args.optional("wait") ?? "10") * 1e3;
44348
- const result = await runListenerAttendanceCanary({
44349
- target: cloud,
44350
- workspaceId: workspaceId2,
44351
- principalId,
44352
- paths,
44353
- waitMs,
44354
- // Canary must remain read-only apart from its one self-note. It therefore
44355
- // uses the presented token and never enters the renewal/mint path.
44356
- credential: async () => agent.token
44357
- });
45852
+ const httpClient = new ListenerHttpClient();
45853
+ let result;
45854
+ try {
45855
+ result = await runListenerAttendanceCanary({
45856
+ target: cloud,
45857
+ workspaceId: workspaceId2,
45858
+ principalId,
45859
+ paths,
45860
+ waitMs,
45861
+ fetcher: httpClient.fetch,
45862
+ // Canary must remain read-only apart from its one self-note. It therefore
45863
+ // uses the presented token and never enters the renewal/mint path.
45864
+ credential: async () => agent.token
45865
+ });
45866
+ } finally {
45867
+ httpClient.close();
45868
+ }
44358
45869
  if (args.has("json")) {
44359
45870
  printJson({
44360
45871
  workspaceId: workspaceId2,
@@ -44620,19 +46131,25 @@ async function runHook(args) {
44620
46131
  process.exit(0);
44621
46132
  }, 3e3);
44622
46133
  hardExit.unref();
44623
- await runListenerHookCheck({
44624
- ...cooldownSeconds === void 0 ? {} : { cooldownSeconds },
44625
- ...principalIds.length === 0 ? {} : { principalIds },
44626
- write: async (output) => {
44627
- await new Promise((resolve2, reject) => {
44628
- process.stdout.write(`${output}
46134
+ const httpClient = new ListenerHttpClient();
46135
+ try {
46136
+ await runListenerHookCheck({
46137
+ ...cooldownSeconds === void 0 ? {} : { cooldownSeconds },
46138
+ ...principalIds.length === 0 ? {} : { principalIds },
46139
+ fetcher: httpClient.fetch,
46140
+ write: async (output) => {
46141
+ await new Promise((resolve3, reject) => {
46142
+ process.stdout.write(`${output}
44629
46143
  `, (error) => {
44630
- if (error) reject(error);
44631
- else resolve2();
46144
+ if (error) reject(error);
46145
+ else resolve3();
46146
+ });
44632
46147
  });
44633
- });
44634
- }
44635
- });
46148
+ }
46149
+ });
46150
+ } finally {
46151
+ httpClient.close();
46152
+ }
44636
46153
  return;
44637
46154
  }
44638
46155
  if (command2 !== "install" && command2 !== "uninstall") {
@@ -44758,8 +46275,8 @@ async function uploadNamedFile(context, name, bytes) {
44758
46275
  workspaceId: context.selected.selectedWorkspace,
44759
46276
  credential: context.selected.bearer
44760
46277
  };
44761
- const fileId = (0, import_node_crypto20.randomUUID)();
44762
- const versionId = (0, import_node_crypto20.randomUUID)();
46278
+ const fileId = (0, import_node_crypto22.randomUUID)();
46279
+ const versionId = (0, import_node_crypto22.randomUUID)();
44763
46280
  const createCommandId = newCommandId();
44764
46281
  const commitCommandId = newCommandId();
44765
46282
  const created = await onceRetried(
@@ -45170,7 +46687,7 @@ async function runDogfood(args) {
45170
46687
  const { selectedWorkspace, bearer } = await commandWorkspaceAndCredential(args, cloud);
45171
46688
  const client = new ThinCommandClient(cloud);
45172
46689
  const route = stream(args);
45173
- const taskId = args.optional("task-id") ?? (0, import_node_crypto20.randomUUID)();
46690
+ const taskId = args.optional("task-id") ?? (0, import_node_crypto22.randomUUID)();
45174
46691
  const ttl = Number(args.optional("ttl-ms") ?? "3600000");
45175
46692
  if (!Number.isSafeInteger(ttl) || ttl <= 0 || ttl > 144e5) {
45176
46693
  throw new Error("--ttl-ms must be an integer in 1..14400000");
@@ -45543,6 +47060,7 @@ ${usage()}
45543
47060
  listenerFailureMessage,
45544
47061
  listenerHostLimits,
45545
47062
  listenerPermissionMode,
47063
+ listenerProviderInstallEvidence,
45546
47064
  listenerRouteConfiguration,
45547
47065
  listenerStatusJson,
45548
47066
  renderListenerStatus,