commonswarm 0.1.53 → 0.1.54

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 +194 -26
  2. package/package.json +1 -1
package/cswarm.cjs CHANGED
@@ -13519,7 +13519,8 @@ __export(cli_exports, {
13519
13519
  replyRefusalHint: () => replyRefusalHint,
13520
13520
  resolveDetachedClaudeExecutable: () => resolveDetachedClaudeExecutable,
13521
13521
  resolveDetachedCodexExecutable: () => resolveDetachedCodexExecutable,
13522
- resolveTurnBudgetOrDefer: () => resolveTurnBudgetOrDefer
13522
+ resolveTurnBudgetOrDefer: () => resolveTurnBudgetOrDefer,
13523
+ usage: () => usage
13523
13524
  });
13524
13525
  module.exports = __toCommonJS(cli_exports);
13525
13526
  var import_node_crypto22 = require("node:crypto");
@@ -34518,6 +34519,25 @@ async function resolveBudgetAndPrompt(session, prompt, budget) {
34518
34519
  const timeoutMs = typeof budget === "number" ? budget : await budget();
34519
34520
  return await session.prompt(prompt, { timeoutMs });
34520
34521
  }
34522
+ var LISTENER_DELIVERY_MAX_LEASE_MS = 9e5;
34523
+ var LISTENER_DELIVERY_HOLD_RELEASE_REASONS = [
34524
+ "hold_budget",
34525
+ "lease_budget"
34526
+ ];
34527
+ var LISTENER_DELIVERY_HOLD_RELEASE_CLAUSES = {
34528
+ hold_budget: "it used the turn budget for one delivery",
34529
+ lease_budget: "what was left of its lease could not cover the next step"
34530
+ };
34531
+ var LISTENER_DELIVERY_HOLD_RELEASE_REMEDIES = {
34532
+ hold_budget: `a larger --turn-budget gives one delivery more of the seat. Past the ${LISTENER_DELIVERY_MAX_LEASE_MS / 6e4} minutes the service leases a delivery for it stops helping, because the turn then outlives its lease and the reply can no longer be acknowledged. The bound is read when the listener starts, so stop this listener and start it again to change it`,
34533
+ /* NOT a cap: nothing clamps the turn budget to the lease, and leaseSpent
34534
+ refuses to START a phase rather than interrupting one, so a 60m budget
34535
+ really does hold the worker for 60m. The sentence says raising past the
34536
+ lease stops helping, and why, which is what the code supports. An earlier
34537
+ version read "up to the 15 minutes the service leases it for", which a
34538
+ review arm read as a cap the code does not enforce. */
34539
+ lease_budget: "nothing needs raising: the row comes back under a new lease of full length, so the next attempt starts with the room this one ran out of. If it keeps being handed back, the service stops retrying it in the end, so look at the delivery rather than at the bound"
34540
+ };
34521
34541
 
34522
34542
  // src/listener/engine.ts
34523
34543
  var UUID_RE14 = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
@@ -36739,11 +36759,11 @@ function pendingMainEntry(signal, principalId, provenance, now, options = {}) {
36739
36759
  // src/listener/runtime.ts
36740
36760
  var LISTENER_PAGE_LIMIT = 100;
36741
36761
  var LISTENER_IDLE_POLL_MS = 2e3;
36742
- var LISTENER_DELIVERY_MAX_LEASE_MS = 9e5;
36743
36762
  var LISTENER_DELIVERY_SAFETY_MARGIN_MS = 3e4;
36744
36763
  var LISTENER_ACK_ONLY_MINIMUM_MS = DELIVERY_REQUEST_TIMEOUT_MS + LISTENER_DELIVERY_SAFETY_MARGIN_MS;
36745
36764
  var LISTENER_REPLY_ONLY_MINIMUM_MS = SIGNAL_REQUEST_TIMEOUT_MS + LISTENER_ACK_ONLY_MINIMUM_MS;
36746
36765
  var LISTENER_PROMPT_START_MINIMUM_MS = SIGNAL_READ_TIMEOUT_MS + ACP_DEFAULT_REQUEST_TIMEOUT_MS + LISTENER_REPLY_ONLY_MINIMUM_MS;
36766
+ var LISTENER_DELIVERY_HOLD_BUDGET_MS = LISTENER_PROMPT_TIMEOUT_MS;
36747
36767
  var LISTENER_DELIVERY_RETRY_INITIAL_MS = 500;
36748
36768
  var LISTENER_DELIVERY_RETRY_MAX_MS = 3e4;
36749
36769
  var LISTENER_HOST_PORTS_PROBE_MS = 6e4;
@@ -37016,6 +37036,7 @@ async function runListenerRuntime(options) {
37016
37036
  const pollMs = options.pollMs ?? LISTENER_IDLE_POLL_MS;
37017
37037
  const routeMode = options.routeMode ?? "worker";
37018
37038
  const deferOverChars = options.deferOverChars ?? null;
37039
+ const deliveryHoldBudgetMs = options.deliveryHoldBudgetMs ?? LISTENER_DELIVERY_HOLD_BUDGET_MS;
37019
37040
  const abort = options.signal;
37020
37041
  const hasInstanceId = options.listenerInstanceId !== void 0;
37021
37042
  const hasJournal = options.deliveryJournal !== void 0;
@@ -37037,6 +37058,12 @@ async function runListenerRuntime(options) {
37037
37058
  new Error("an injected delivery client requires durable delivery configuration")
37038
37059
  );
37039
37060
  }
37061
+ if (!Number.isSafeInteger(deliveryHoldBudgetMs) || deliveryHoldBudgetMs <= 0) {
37062
+ return await closeBeforeStart(
37063
+ options.model,
37064
+ new Error("listener delivery hold budget must be a positive number of milliseconds")
37065
+ );
37066
+ }
37040
37067
  try {
37041
37068
  decideListenerRoute(routeMode, deferOverChars, 0);
37042
37069
  if (routeMode !== "worker" && options.pendingMainQueue === void 0) {
@@ -37630,6 +37657,8 @@ async function runListenerRuntime(options) {
37630
37657
  stop = { reason: "cancelled" };
37631
37658
  break;
37632
37659
  }
37660
+ const claimedAtMs = Date.parse(active.claimCreatedAt);
37661
+ const holdStartedAtMs = Number.isFinite(claimedAtMs) ? Math.min(claimedAtMs, now()) : now();
37633
37662
  const signal = authoritativeSignal(claimed);
37634
37663
  let terminal = null;
37635
37664
  try {
@@ -37696,22 +37725,18 @@ async function runListenerRuntime(options) {
37696
37725
  throw new Error("stored listener effect does not match the authoritative delivery");
37697
37726
  }
37698
37727
  const requiredBudget = effectPhaseBudget(before);
37699
- if (leasedUntilMs <= now() + requiredBudget) {
37700
- await sleep2(
37701
- Math.max(
37702
- 0,
37703
- leasedUntilMs + LISTENER_DELIVERY_SAFETY_MARGIN_MS - now()
37704
- ),
37705
- abort
37706
- );
37707
- if (abort?.aborted) {
37708
- stop = { reason: "cancelled" };
37709
- break;
37710
- }
37711
- if (now() >= leasedUntilMs + LISTENER_DELIVERY_SAFETY_MARGIN_MS) {
37712
- await journal.clearActive(eventTime(now));
37713
- after = null;
37714
- }
37728
+ const holdSpent = processAttempt > 0 && now() - holdStartedAtMs >= deliveryHoldBudgetMs;
37729
+ const leaseSpent = leasedUntilMs <= now() + requiredBudget;
37730
+ if (holdSpent || leaseSpent) {
37731
+ await journal.clearActive(eventTime(now));
37732
+ after = null;
37733
+ options.onEvent?.({
37734
+ type: "delivery_hold_released",
37735
+ signalId: signal.id,
37736
+ reason: holdSpent ? "hold_budget" : "lease_budget",
37737
+ heldMs: Math.max(0, now() - holdStartedAtMs),
37738
+ ts: eventTime(now)
37739
+ });
37715
37740
  break;
37716
37741
  }
37717
37742
  const processed = await engine.process(signal);
@@ -38210,6 +38235,10 @@ var STATUS_ALLOWED_KEYS = /* @__PURE__ */ new Set([
38210
38235
  "lastAckOutcome",
38211
38236
  "consecutiveAckFailureCount",
38212
38237
  "lastAckSignalId",
38238
+ "currentDeliverySignalId",
38239
+ "currentDeliverySince",
38240
+ "heldBackDeliveries",
38241
+ "pendingDeliveryCountAt",
38213
38242
  "routeMode",
38214
38243
  "deferOverChars",
38215
38244
  "pendingForMainCount",
@@ -38254,6 +38283,30 @@ var STATUS_DELIVERY_KEYS = [
38254
38283
  "consecutiveAckFailureCount"
38255
38284
  ];
38256
38285
  var deliveryOutcomes = DELIVERY_ACK_OUTCOMES;
38286
+ var LISTENER_HELD_BACK_MAX = 16;
38287
+ function parseHeldBackDeliveries(value) {
38288
+ if (!Array.isArray(value) || value.length > LISTENER_HELD_BACK_MAX) return null;
38289
+ const parsed = [];
38290
+ for (const item of value) {
38291
+ if (!item || typeof item !== "object" || Array.isArray(item)) return null;
38292
+ const entry = item;
38293
+ for (const key2 of Object.keys(entry)) {
38294
+ if (key2 !== "signalId" && key2 !== "at" && key2 !== "reason") return null;
38295
+ }
38296
+ if (typeof entry.signalId !== "string" || !UUID_RE18.test(entry.signalId) || typeof entry.at !== "string" || !Number.isFinite(Date.parse(entry.at)) || typeof entry.reason !== "string" || !LISTENER_DELIVERY_HOLD_RELEASE_REASONS.includes(
38297
+ entry.reason
38298
+ )) {
38299
+ return null;
38300
+ }
38301
+ if (parsed.some((seen) => seen.signalId === entry.signalId)) return null;
38302
+ parsed.push({
38303
+ signalId: entry.signalId,
38304
+ at: entry.at,
38305
+ reason: entry.reason
38306
+ });
38307
+ }
38308
+ return parsed;
38309
+ }
38257
38310
  function parseStatus(raw, rejectUnknownKeys = false) {
38258
38311
  let value;
38259
38312
  try {
@@ -38277,7 +38330,8 @@ function parseStatus(raw, rejectUnknownKeys = false) {
38277
38330
  const nullableCount = (candidate) => candidate === null || typeof candidate === "number" && Number.isSafeInteger(candidate) && candidate >= 0;
38278
38331
  const nullableTimestamp3 = (candidate) => candidate === null || typeof candidate === "string" && Number.isFinite(Date.parse(candidate));
38279
38332
  const readHealth = row.readHealth === void 0 ? void 0 : parseListenerReadHealth(row.readHealth, rejectUnknownKeys);
38280
- if (row.version !== 1 || typeof row.instanceId !== "string" || !UUID_RE18.test(row.instanceId) || row.provider !== "grok" && row.provider !== "opencode" && row.provider !== "claude" && row.provider !== "codex" || typeof row.profileId !== "string" || typeof row.workspaceId !== "string" || !UUID_RE18.test(row.workspaceId) || typeof row.principalId !== "string" || !UUID_RE18.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.lastAckOutcome === void 0 || row.lastAckOutcome === null || typeof row.lastAckOutcome === "string" && deliveryOutcomes.has(row.lastAckOutcome)) || !(row.consecutiveAckFailureCount === void 0 || nullableCount(row.consecutiveAckFailureCount)) || !(row.lastAckSignalId === void 0 || row.lastAckSignalId === null || typeof row.lastAckSignalId === "string" && UUID_RE18.test(row.lastAckSignalId)) || !(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(
38333
+ const heldBackDeliveries = row.heldBackDeliveries === void 0 ? void 0 : parseHeldBackDeliveries(row.heldBackDeliveries);
38334
+ if (row.version !== 1 || typeof row.instanceId !== "string" || !UUID_RE18.test(row.instanceId) || row.provider !== "grok" && row.provider !== "opencode" && row.provider !== "claude" && row.provider !== "codex" || typeof row.profileId !== "string" || typeof row.workspaceId !== "string" || !UUID_RE18.test(row.workspaceId) || typeof row.principalId !== "string" || !UUID_RE18.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.lastAckOutcome === void 0 || row.lastAckOutcome === null || typeof row.lastAckOutcome === "string" && deliveryOutcomes.has(row.lastAckOutcome)) || !(row.consecutiveAckFailureCount === void 0 || nullableCount(row.consecutiveAckFailureCount)) || !(row.lastAckSignalId === void 0 || row.lastAckSignalId === null || typeof row.lastAckSignalId === "string" && UUID_RE18.test(row.lastAckSignalId)) || !(row.currentDeliverySignalId === void 0 || row.currentDeliverySignalId === null || typeof row.currentDeliverySignalId === "string" && UUID_RE18.test(row.currentDeliverySignalId)) || !(row.currentDeliverySince === void 0 || nullableTimestamp3(row.currentDeliverySince)) || heldBackDeliveries === null || !(row.pendingDeliveryCountAt === void 0 || nullableTimestamp3(row.pendingDeliveryCountAt)) || !(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(
38281
38335
  row.activityLastErrorCode
38282
38336
  ))) {
38283
38337
  throw new Error("stored listener status is malformed");
@@ -38303,6 +38357,16 @@ function parseStatus(raw, rejectUnknownKeys = false) {
38303
38357
  // Optional key: present only when the file carried it, so a status written
38304
38358
  // without it round-trips byte-for-byte (the routeMode pattern).
38305
38359
  ...row.lastAckSignalId === void 0 ? {} : { lastAckSignalId: row.lastAckSignalId ?? null },
38360
+ ...row.currentDeliverySignalId === void 0 ? {} : {
38361
+ currentDeliverySignalId: row.currentDeliverySignalId ?? null
38362
+ },
38363
+ ...row.currentDeliverySince === void 0 ? {} : {
38364
+ currentDeliverySince: row.currentDeliverySince ?? null
38365
+ },
38366
+ ...heldBackDeliveries === void 0 ? {} : { heldBackDeliveries },
38367
+ ...row.pendingDeliveryCountAt === void 0 ? {} : {
38368
+ pendingDeliveryCountAt: row.pendingDeliveryCountAt ?? null
38369
+ },
38306
38370
  lastErrorDetail: row.lastErrorDetail ?? null,
38307
38371
  lastWorkerStderrTail: row.lastWorkerStderrTail ?? null,
38308
38372
  providerVersion: row.providerVersion ?? null,
@@ -38379,7 +38443,10 @@ async function appendListenerEvent(paths, event) {
38379
38443
  "defer_over_chars",
38380
38444
  "body_length",
38381
38445
  "pending_main_count",
38382
- "dropped_count"
38446
+ "dropped_count",
38447
+ // How long one delivery held the worker seat, and why it gave it back.
38448
+ "held_ms",
38449
+ "release_reason"
38383
38450
  ]);
38384
38451
  const deliveryModes = /* @__PURE__ */ new Set(["durable_claim", "cursor_fallback"]);
38385
38452
  const routeModes = /* @__PURE__ */ new Set(["worker", "main", "split"]);
@@ -38441,6 +38508,14 @@ async function appendListenerEvent(paths, event) {
38441
38508
  if ((key2 === "body_length" || key2 === "pending_main_count" || key2 === "dropped_count") && !(typeof value === "number" && Number.isSafeInteger(value) && value >= 0)) {
38442
38509
  throw new Error("listener event main-route count is not allowed");
38443
38510
  }
38511
+ if (key2 === "held_ms" && !(typeof value === "number" && Number.isSafeInteger(value) && value >= 0)) {
38512
+ throw new Error("listener event hold duration is not allowed");
38513
+ }
38514
+ if (key2 === "release_reason" && !(typeof value === "string" && LISTENER_DELIVERY_HOLD_RELEASE_REASONS.includes(
38515
+ value
38516
+ ))) {
38517
+ throw new Error("listener event hold release reason is not allowed");
38518
+ }
38444
38519
  if (key2 === "worker_stderr_tail" && !(typeof value === "string" && value.length > 0 && value.length <= 2048)) {
38445
38520
  throw new Error("listener event stderr tail is not allowed");
38446
38521
  }
@@ -38820,6 +38895,7 @@ async function runListenerSupervisor(options) {
38820
38895
  lastWorkerStderrTail: null,
38821
38896
  deliveryMode: null,
38822
38897
  pendingDeliveryCount: null,
38898
+ pendingDeliveryCountAt: null,
38823
38899
  lastTerminalDeliveryFailureCount: null,
38824
38900
  lastTerminalDeliveryFailureAt: null,
38825
38901
  lastClaimAt: null,
@@ -38831,6 +38907,11 @@ async function runListenerSupervisor(options) {
38831
38907
  lastAckOutcome: carried?.lastAckOutcome ?? null,
38832
38908
  consecutiveAckFailureCount: carried?.consecutiveAckFailureCount ?? null,
38833
38909
  lastAckSignalId: carried?.lastAckSignalId ?? null,
38910
+ /* Never carried across a restart: a seat this process does not hold cannot
38911
+ be reported as held, and the queue age restarts with the observations. */
38912
+ currentDeliverySignalId: null,
38913
+ currentDeliverySince: null,
38914
+ heldBackDeliveries: [],
38834
38915
  routeMode: options.routeMode ?? "worker",
38835
38916
  deferOverChars: options.deferOverChars ?? null,
38836
38917
  pendingForMainCount: 0,
@@ -38864,9 +38945,15 @@ async function runListenerSupervisor(options) {
38864
38945
  chain(() => appendListenerEvent(options.paths, event));
38865
38946
  };
38866
38947
  const transition = (state, changes = {}) => {
38948
+ const notWatching = state === "starting" || state === "stopped" || state === "failed";
38867
38949
  status = {
38868
38950
  ...status,
38869
38951
  ...changes,
38952
+ ...notWatching ? {
38953
+ currentDeliverySignalId: null,
38954
+ currentDeliverySince: null,
38955
+ heldBackDeliveries: []
38956
+ } : {},
38870
38957
  state,
38871
38958
  updatedAt: iso2(now)
38872
38959
  };
@@ -39055,6 +39142,7 @@ async function runListenerSupervisor(options) {
39055
39142
  ...status,
39056
39143
  deliveryMode: event.mode,
39057
39144
  pendingDeliveryCount: event.pendingDeliveryCount,
39145
+ pendingDeliveryCountAt: event.pendingDeliveryCount === null ? null : event.ts,
39058
39146
  updatedAt: event.ts
39059
39147
  };
39060
39148
  persist();
@@ -39067,6 +39155,7 @@ async function runListenerSupervisor(options) {
39067
39155
  return;
39068
39156
  }
39069
39157
  if (event.type === "delivery_claim") {
39158
+ const heldBack = (status.heldBackDeliveries ?? []).filter((entry) => entry.signalId !== event.signalId);
39070
39159
  status = {
39071
39160
  ...status,
39072
39161
  readHealth: recordListenerClaim(
@@ -39074,6 +39163,10 @@ async function runListenerSupervisor(options) {
39074
39163
  event.ts
39075
39164
  ),
39076
39165
  pendingDeliveryCount: event.pendingDeliveryCount,
39166
+ pendingDeliveryCountAt: event.ts,
39167
+ currentDeliverySignalId: event.signalId,
39168
+ currentDeliverySince: event.signalId === null ? null : event.ts,
39169
+ heldBackDeliveries: heldBack,
39077
39170
  lastClaimAt: event.ts,
39078
39171
  updatedAt: event.ts
39079
39172
  };
@@ -39105,6 +39198,36 @@ async function runListenerSupervisor(options) {
39105
39198
  });
39106
39199
  return;
39107
39200
  }
39201
+ if (event.type === "delivery_hold_released") {
39202
+ status = {
39203
+ ...status,
39204
+ currentDeliverySignalId: null,
39205
+ currentDeliverySince: null,
39206
+ /* Held back, NOT waiting to be claimed: the row keeps its live lease,
39207
+ so the service cannot hand it to anyone until that lease expires.
39208
+ Both review arms on 33cd24b measured the earlier wording counting it
39209
+ among deliveries "waiting to be claimed". Newest first, deduplicated
39210
+ on the id (a row can be released, redelivered and released again),
39211
+ and bounded. */
39212
+ heldBackDeliveries: [
39213
+ { signalId: event.signalId, at: event.ts, reason: event.reason },
39214
+ ...(status.heldBackDeliveries ?? []).filter(
39215
+ (entry) => entry.signalId !== event.signalId
39216
+ )
39217
+ ].slice(0, LISTENER_HELD_BACK_MAX),
39218
+ lastSignalId: event.signalId,
39219
+ updatedAt: event.ts
39220
+ };
39221
+ persist();
39222
+ log({
39223
+ ts: event.ts,
39224
+ event: "listener_delivery_hold_released",
39225
+ signal_id: event.signalId,
39226
+ release_reason: event.reason,
39227
+ held_ms: Math.max(0, Math.trunc(event.heldMs))
39228
+ });
39229
+ return;
39230
+ }
39108
39231
  if (event.type === "delivery_ack") {
39109
39232
  const failed = event.outcome === "failed_terminal";
39110
39233
  const providerProven = DELIVERY_PROVIDER_PROVEN_OUTCOMES.has(event.outcome);
@@ -39115,6 +39238,13 @@ async function runListenerSupervisor(options) {
39115
39238
  lastAckSignalId: event.signalId,
39116
39239
  consecutiveAckFailureCount: failed ? (status.consecutiveAckFailureCount ?? 0) + 1 : providerProven ? 0 : status.consecutiveAckFailureCount,
39117
39240
  pendingDeliveryCount: null,
39241
+ pendingDeliveryCountAt: null,
39242
+ currentDeliverySignalId: null,
39243
+ currentDeliverySince: null,
39244
+ // An acknowledged row is answered and gone; drop just that one.
39245
+ heldBackDeliveries: (status.heldBackDeliveries ?? []).filter(
39246
+ (entry) => entry.signalId !== event.signalId
39247
+ ),
39118
39248
  lastSignalId: event.signalId,
39119
39249
  updatedAt: event.ts
39120
39250
  };
@@ -39285,7 +39415,14 @@ async function effectiveListenerStatus(paths) {
39285
39415
  state: "failed",
39286
39416
  updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
39287
39417
  stoppedAt: (/* @__PURE__ */ new Date()).toISOString(),
39288
- lastErrorCode: "unclean_exit"
39418
+ lastErrorCode: "unclean_exit",
39419
+ /* The process is gone: it holds nothing and observes nothing, so every
39420
+ field whose sentence is rendered in the present tense against read
39421
+ time is cleared. pendingDeliveryCount stays, because its line already
39422
+ says it is what the service reported. */
39423
+ currentDeliverySignalId: null,
39424
+ currentDeliverySince: null,
39425
+ heldBackDeliveries: []
39289
39426
  };
39290
39427
  await writeListenerStatus(paths, failed);
39291
39428
  return failed;
@@ -42142,8 +42279,8 @@ var BOOLEAN_FLAGS = /* @__PURE__ */ new Set([
42142
42279
  ]);
42143
42280
  var UUID_RE23 = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
42144
42281
  function packageVersion() {
42145
- if ("0.1.53".length > 0) {
42146
- return "0.1.53";
42282
+ if ("0.1.54".length > 0) {
42283
+ return "0.1.54";
42147
42284
  }
42148
42285
  try {
42149
42286
  const value = JSON.parse(
@@ -42368,7 +42505,10 @@ due \u2014 a turn never outlives its credential. Right after a rotation the full
42368
42505
  budget is available up to the token TTL minus 60s (about 59m on the default 1h
42369
42506
  TTL); a turn that lands just before a rotation can be clamped to the ~5m
42370
42507
  renewal lead, and if it times out there, durable delivery retries it on the
42371
- fresh credential.
42508
+ fresh credential. The same budget also bounds how long ONE delivery may hold the
42509
+ worker seat across its retries: when it is spent the listener hands the seat
42510
+ back and claims the next delivery. After the lease ends the service either
42511
+ delivers the released one again or terminates it.
42372
42512
 
42373
42513
  listen start --route worker|main|split chooses where directed messages go. worker
42374
42514
  is the unchanged default. main queues every ask or note for the interactive session.
@@ -45391,6 +45531,12 @@ function listenerStatusJson(status, permissionMode, evidence = {
45391
45531
  lastAckOutcome: status.lastAckOutcome ?? null,
45392
45532
  consecutiveAckFailureCount: status.consecutiveAckFailureCount ?? null,
45393
45533
  lastAckSignalId: status.lastAckSignalId ?? null,
45534
+ currentDeliverySignalId: status.currentDeliverySignalId ?? null,
45535
+ currentDeliverySince: status.currentDeliverySince ?? null,
45536
+ currentDeliveryElapsedMs: status.currentDeliverySince ? Math.max(0, nowMs - Date.parse(status.currentDeliverySince)) : null,
45537
+ pendingDeliveryCountAt: status.pendingDeliveryCountAt ?? null,
45538
+ heldBackDeliveries: status.heldBackDeliveries ?? [],
45539
+ heldBackDeliveryCount: (status.heldBackDeliveries ?? []).length,
45394
45540
  routeMode: status.routeMode ?? "worker",
45395
45541
  deferOverChars: status.deferOverChars ?? null,
45396
45542
  pendingForMainCount: status.pendingForMainCount ?? 0,
@@ -45513,8 +45659,26 @@ function renderListenerStatus(status, evidence = {
45513
45659
  lines.push("Delivery mode has not been reported yet.");
45514
45660
  }
45515
45661
  if (status.pendingDeliveryCount !== null) {
45662
+ const observedAt = status.pendingDeliveryCountAt ?? null;
45663
+ lines.push(
45664
+ `Pending deliveries reported by the service: ${status.pendingDeliveryCount}.` + (observedAt === null ? " When the service reported it was not recorded." : ` The service reported that ${relativeAge(observedAt, nowMs)}.`)
45665
+ );
45666
+ }
45667
+ const currentDeliveryId = status.currentDeliverySignalId ?? null;
45668
+ const currentDeliverySince = status.currentDeliverySince ?? null;
45669
+ if (currentDeliveryId !== null && currentDeliverySince !== null) {
45670
+ lines.push(
45671
+ `Working on delivery ${currentDeliveryId}, claimed ${relativeAge(currentDeliverySince, nowMs)}.`
45672
+ );
45673
+ } else {
45674
+ lines.push("No delivery is being worked on right now.");
45675
+ }
45676
+ const heldBack = status.heldBackDeliveries ?? [];
45677
+ const newestHeldBack = heldBack[0];
45678
+ if (newestHeldBack !== void 0) {
45679
+ const others = heldBack.length - 1;
45516
45680
  lines.push(
45517
- `Pending deliveries reported by the service: ${status.pendingDeliveryCount}.`
45681
+ `Delivery ${newestHeldBack.signalId} was handed back ${relativeAge(newestHeldBack.at, nowMs)} because ${LISTENER_DELIVERY_HOLD_RELEASE_CLAUSES[newestHeldBack.reason]}.` + (others > 0 ? ` This listener is still tracking ${others} other handed-back ${others === 1 ? "delivery" : "deliveries"}.` : "") + ` This listener has not answered it. After the lease ends the service either delivers it again or terminates it. If this repeats, ${LISTENER_DELIVERY_HOLD_RELEASE_REMEDIES[newestHeldBack.reason]}.`
45518
45682
  );
45519
45683
  }
45520
45684
  lines.push(
@@ -46055,6 +46219,9 @@ async function runConfiguredListener(options) {
46055
46219
  },
46056
46220
  routeMode,
46057
46221
  deferOverChars,
46222
+ /* One delivery may hold the seat for one turn budget, not for the
46223
+ whole 15-minute lease. Same lever, so the two cannot drift. */
46224
+ deliveryHoldBudgetMs: turnBudgetMs,
46058
46225
  pendingMainQueue,
46059
46226
  fetcher: httpClient.fetch
46060
46227
  });
@@ -47734,5 +47901,6 @@ ${usage()}
47734
47901
  replyRefusalHint,
47735
47902
  resolveDetachedClaudeExecutable,
47736
47903
  resolveDetachedCodexExecutable,
47737
- resolveTurnBudgetOrDefer
47904
+ resolveTurnBudgetOrDefer,
47905
+ usage
47738
47906
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "commonswarm",
3
- "version": "0.1.53",
3
+ "version": "0.1.54",
4
4
  "description": "CommonSwarm CLI — coordination for teams where people and AI agents work side by side.",
5
5
  "bin": {
6
6
  "cswarm": "cswarm.cjs"