clisbot 0.1.8 → 0.1.9

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/dist/main.js +55 -2
  2. package/package.json +1 -1
package/dist/main.js CHANGED
@@ -63257,6 +63257,41 @@ async function monitorTmuxRun(params) {
63257
63257
  }
63258
63258
 
63259
63259
  // src/agents/active-run-manager.ts
63260
+ var OBSERVER_RETRYABLE_FAILURE_LIMIT = 3;
63261
+ function formatObserverError(error) {
63262
+ return error instanceof Error ? error.stack ?? error.message : String(error);
63263
+ }
63264
+ function listObserverErrorCodes(error) {
63265
+ const codes = new Set;
63266
+ const visit = (value) => {
63267
+ if (!value || typeof value !== "object") {
63268
+ return;
63269
+ }
63270
+ const candidate = value;
63271
+ if (typeof candidate.code === "string" && candidate.code.trim()) {
63272
+ codes.add(candidate.code.trim().toUpperCase());
63273
+ }
63274
+ if (Array.isArray(candidate.errors)) {
63275
+ for (const nested of candidate.errors) {
63276
+ visit(nested);
63277
+ }
63278
+ }
63279
+ if (candidate.cause) {
63280
+ visit(candidate.cause);
63281
+ }
63282
+ };
63283
+ visit(error);
63284
+ return [...codes];
63285
+ }
63286
+ function isRetryableObserverDeliveryError(error) {
63287
+ const codes = listObserverErrorCodes(error);
63288
+ if (codes.some((code) => code === "ETIMEDOUT" || code === "ECONNRESET" || code === "ECONNREFUSED" || code === "EHOSTUNREACH" || code === "ENETUNREACH" || code === "UND_ERR_CONNECT_TIMEOUT" || code === "UND_ERR_HEADERS_TIMEOUT" || code === "UND_ERR_SOCKET")) {
63289
+ return true;
63290
+ }
63291
+ const message = error instanceof Error ? `${error.name} ${error.message}` : String(error);
63292
+ return /fetch failed|request timed out|network|socket hang up/i.test(message);
63293
+ }
63294
+
63260
63295
  class ActiveRunInProgressError extends Error {
63261
63296
  update;
63262
63297
  constructor(update) {
@@ -63332,6 +63367,7 @@ class ActiveRunManager {
63332
63367
  this.activeRuns.set(resolved.sessionKey, {
63333
63368
  resolved,
63334
63369
  observers: new Map,
63370
+ observerFailures: new Map,
63335
63371
  initialResult,
63336
63372
  latestUpdate: update
63337
63373
  });
@@ -63366,6 +63402,7 @@ class ActiveRunManager {
63366
63402
  this.activeRuns.set(provisionalResolved.sessionKey, {
63367
63403
  resolved: provisionalResolved,
63368
63404
  observers: new Map([[observer.id, { ...observer }]]),
63405
+ observerFailures: new Map,
63369
63406
  initialResult,
63370
63407
  latestUpdate: this.createRunUpdate({
63371
63408
  resolved: provisionalResolved,
@@ -63422,6 +63459,7 @@ class ActiveRunManager {
63422
63459
  existingRun.observers.set(observer.id, {
63423
63460
  ...observer
63424
63461
  });
63462
+ existingRun.observerFailures.delete(observer.id);
63425
63463
  return {
63426
63464
  active: !isTerminalRunStatus(existingRun.latestUpdate.status),
63427
63465
  update: existingRun.latestUpdate
@@ -63456,6 +63494,7 @@ class ActiveRunManager {
63456
63494
  };
63457
63495
  }
63458
63496
  observer.mode = "passive-final";
63497
+ run.observerFailures.delete(observerId);
63459
63498
  return {
63460
63499
  detached: true
63461
63500
  };
@@ -63482,7 +63521,7 @@ class ActiveRunManager {
63482
63521
  async notifyRunObservers(run, update) {
63483
63522
  run.latestUpdate = update;
63484
63523
  const now = Date.now();
63485
- for (const observer of run.observers.values()) {
63524
+ for (const [observerId, observer] of run.observers.entries()) {
63486
63525
  if (observer.expiresAt && now >= observer.expiresAt && observer.mode !== "passive-final") {
63487
63526
  observer.mode = "passive-final";
63488
63527
  }
@@ -63498,7 +63537,21 @@ class ActiveRunManager {
63498
63537
  continue;
63499
63538
  }
63500
63539
  observer.lastSentAt = now;
63501
- await observer.onUpdate(update);
63540
+ try {
63541
+ await observer.onUpdate(update);
63542
+ run.observerFailures.delete(observerId);
63543
+ } catch (error) {
63544
+ const retryable = isRetryableObserverDeliveryError(error);
63545
+ const nextFailures = retryable ? (run.observerFailures.get(observerId) ?? 0) + 1 : OBSERVER_RETRYABLE_FAILURE_LIMIT;
63546
+ const shouldDetach = !retryable || isTerminalRunStatus(update.status) || nextFailures >= OBSERVER_RETRYABLE_FAILURE_LIMIT;
63547
+ if (shouldDetach) {
63548
+ run.observers.delete(observerId);
63549
+ run.observerFailures.delete(observerId);
63550
+ } else {
63551
+ run.observerFailures.set(observerId, nextFailures);
63552
+ }
63553
+ console.error(shouldDetach ? `run observer '${observerId}' update failed for ${run.resolved.sessionKey}; detaching observer` : `run observer '${observerId}' update failed for ${run.resolved.sessionKey}; keeping observer for retry (${nextFailures}/${OBSERVER_RETRYABLE_FAILURE_LIMIT})`, formatObserverError(error));
63554
+ }
63502
63555
  }
63503
63556
  }
63504
63557
  async finishActiveRun(sessionKey, update) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clisbot",
3
- "version": "0.1.8",
3
+ "version": "0.1.9",
4
4
  "private": false,
5
5
  "description": "Chat surfaces for durable AI coding agents running in tmux",
6
6
  "license": "MIT",