episoda 0.2.104 → 0.2.106

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -2117,6 +2117,7 @@ var require_websocket_client = __commonJS({
2117
2117
  this.lastCommandTime = Date.now();
2118
2118
  this.isIntentionalDisconnect = false;
2119
2119
  this.lastConnectAttemptTime = 0;
2120
+ this.consecutiveAuthFailures = 0;
2120
2121
  }
2121
2122
  /**
2122
2123
  * Connect to episoda.dev WebSocket gateway
@@ -2384,6 +2385,10 @@ var require_websocket_client = __commonJS({
2384
2385
  this.rateLimitBackoffUntil = Date.now() + retryAfterMs;
2385
2386
  console.log(`[EpisodaClient] ${errorMessage.code}: will retry after ${retryAfterMs / 1e3}s`);
2386
2387
  }
2388
+ if (errorMessage.code === "AUTH_FAILED" || errorMessage.code === "UNAUTHORIZED" || errorMessage.code === "INVALID_TOKEN") {
2389
+ this.consecutiveAuthFailures++;
2390
+ console.warn(`[EpisodaClient] Auth failure (${this.consecutiveAuthFailures}): ${errorMessage.code}`);
2391
+ }
2387
2392
  }
2388
2393
  const handlers = this.eventHandlers.get(message.type) || [];
2389
2394
  handlers.forEach((handler) => {
@@ -2442,7 +2447,19 @@ var require_websocket_client = __commonJS({
2442
2447
  }
2443
2448
  let delay;
2444
2449
  let shouldRetry = true;
2445
- if (this.isGracefulShutdown) {
2450
+ const isCloudMode = this.environment === "cloud";
2451
+ const MAX_CLOUD_AUTH_FAILURES = 3;
2452
+ const MAX_CLOUD_RECONNECT_DELAY = 3e5;
2453
+ if (isCloudMode) {
2454
+ if (this.consecutiveAuthFailures >= MAX_CLOUD_AUTH_FAILURES) {
2455
+ console.error(`[EpisodaClient] Cloud mode: ${MAX_CLOUD_AUTH_FAILURES} consecutive auth failures - token may be invalid. Giving up.`);
2456
+ shouldRetry = false;
2457
+ } else {
2458
+ delay = Math.min(1e3 * Math.pow(2, this.reconnectAttempts), MAX_CLOUD_RECONNECT_DELAY);
2459
+ const delayStr = delay >= 6e4 ? `${Math.round(delay / 6e4)}m` : `${Math.round(delay / 1e3)}s`;
2460
+ console.log(`[EpisodaClient] Cloud mode: reconnecting in ${delayStr}... (attempt ${this.reconnectAttempts + 1}, never giving up)`);
2461
+ }
2462
+ } else if (this.isGracefulShutdown) {
2446
2463
  if (this.reconnectAttempts >= 7) {
2447
2464
  console.error('[EpisodaClient] Server restart reconnection failed after 7 attempts. Run "episoda dev" to reconnect.');
2448
2465
  shouldRetry = false;
@@ -2485,6 +2502,7 @@ var require_websocket_client = __commonJS({
2485
2502
  this.isGracefulShutdown = false;
2486
2503
  this.firstDisconnectTime = void 0;
2487
2504
  this.rateLimitBackoffUntil = void 0;
2505
+ this.consecutiveAuthFailures = 0;
2488
2506
  }).catch((error) => {
2489
2507
  console.error("[EpisodaClient] Reconnection failed:", error.message);
2490
2508
  });
@@ -3772,7 +3790,13 @@ var WorktreeManager = class _WorktreeManager {
3772
3790
  }
3773
3791
  };
3774
3792
  function getEpisodaRoot() {
3775
- return process.env.EPISODA_ROOT || path3.join(require("os").homedir(), "episoda");
3793
+ if (process.env.EPISODA_ROOT) {
3794
+ return process.env.EPISODA_ROOT;
3795
+ }
3796
+ if (process.env.EPISODA_MODE === "cloud") {
3797
+ return process.env.HOME || "/home/episoda";
3798
+ }
3799
+ return path3.join(require("os").homedir(), "episoda");
3776
3800
  }
3777
3801
  function getProjectPath(workspaceSlug, projectSlug) {
3778
3802
  return path3.join(getEpisodaRoot(), workspaceSlug, projectSlug);