episoda 0.2.75 → 0.2.77

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.
@@ -2116,6 +2116,7 @@ var require_websocket_client = __commonJS({
2116
2116
  * @param token - OAuth access token
2117
2117
  * @param machineId - Optional machine identifier for multi-machine support
2118
2118
  * @param deviceInfo - Optional device information (hostname, OS, daemonPid)
2119
+ * EP1119: Added environment and containerId for cloud routing
2119
2120
  */
2120
2121
  async connect(url, token, machineId, deviceInfo) {
2121
2122
  this.url = url;
@@ -2125,6 +2126,8 @@ var require_websocket_client = __commonJS({
2125
2126
  this.osPlatform = deviceInfo?.osPlatform;
2126
2127
  this.osArch = deviceInfo?.osArch;
2127
2128
  this.daemonPid = deviceInfo?.daemonPid;
2129
+ this.environment = deviceInfo?.environment;
2130
+ this.containerId = deviceInfo?.containerId;
2128
2131
  this.isDisconnecting = false;
2129
2132
  this.isGracefulShutdown = false;
2130
2133
  this.isIntentionalDisconnect = false;
@@ -2162,7 +2165,9 @@ var require_websocket_client = __commonJS({
2162
2165
  type: "auth",
2163
2166
  token,
2164
2167
  version: version_1.VERSION,
2168
+ environment: this.environment,
2165
2169
  machineId,
2170
+ containerId: this.containerId,
2166
2171
  hostname: this.hostname,
2167
2172
  osPlatform: this.osPlatform,
2168
2173
  osArch: this.osArch,
@@ -2463,7 +2468,9 @@ var require_websocket_client = __commonJS({
2463
2468
  hostname: this.hostname,
2464
2469
  osPlatform: this.osPlatform,
2465
2470
  osArch: this.osArch,
2466
- daemonPid: this.daemonPid
2471
+ daemonPid: this.daemonPid,
2472
+ environment: this.environment,
2473
+ containerId: this.containerId
2467
2474
  }).then(() => {
2468
2475
  console.log("[EpisodaClient] Reconnection successful");
2469
2476
  this.reconnectAttempts = 0;
@@ -2741,7 +2748,7 @@ var require_package = __commonJS({
2741
2748
  "package.json"(exports2, module2) {
2742
2749
  module2.exports = {
2743
2750
  name: "episoda",
2744
- version: "0.2.75",
2751
+ version: "0.2.77",
2745
2752
  description: "CLI tool for Episoda local development workflow orchestration",
2746
2753
  main: "dist/index.js",
2747
2754
  types: "dist/index.d.ts",
@@ -4187,6 +4194,27 @@ async function clearTunnelUrl(moduleUid) {
4187
4194
  }
4188
4195
  }
4189
4196
 
4197
+ // src/daemon/mode-config.ts
4198
+ var CLOUD_CONFIG = {
4199
+ mode: "cloud",
4200
+ portAllocation: "fixed",
4201
+ fixedPort: 3e3,
4202
+ orphanTunnelCleanup: false,
4203
+ orphanWorktreeCleanup: false,
4204
+ maxConcurrentModules: 1
4205
+ };
4206
+ var LOCAL_CONFIG = {
4207
+ mode: "local",
4208
+ portAllocation: "dynamic",
4209
+ orphanTunnelCleanup: true,
4210
+ orphanWorktreeCleanup: true,
4211
+ maxConcurrentModules: Infinity
4212
+ };
4213
+ function getDaemonModeConfig() {
4214
+ const mode = process.env.EPISODA_MODE;
4215
+ return mode === "cloud" ? CLOUD_CONFIG : LOCAL_CONFIG;
4216
+ }
4217
+
4190
4218
  // src/tunnel/tunnel-manager.ts
4191
4219
  var TUNNEL_PID_DIR = path7.join(os2.homedir(), ".episoda", "tunnels");
4192
4220
  var TUNNEL_TIMEOUTS = {
@@ -4386,8 +4414,9 @@ var TunnelManager = class extends import_events.EventEmitter {
4386
4414
  */
4387
4415
  async cleanupOrphanedProcesses() {
4388
4416
  const cleaned = [];
4389
- if (process.env.EPISODA_MODE === "cloud") {
4390
- console.log("[Tunnel] EP1111: Skipping orphan cleanup in cloud mode (supervisord manages cloudflared)");
4417
+ const modeConfig = getDaemonModeConfig();
4418
+ if (!modeConfig.orphanTunnelCleanup) {
4419
+ console.log(`[Tunnel] EP1115: Skipping orphan cleanup (mode: ${modeConfig.mode}, orphanTunnelCleanup: false)`);
4391
4420
  return { cleaned: 0, pids: [] };
4392
4421
  }
4393
4422
  try {
@@ -6380,13 +6409,19 @@ var PreviewManager = class extends import_events3.EventEmitter {
6380
6409
  *
6381
6410
  * Must be called before starting any previews.
6382
6411
  * Initializes the tunnel manager (ensures cloudflared, cleans orphans).
6412
+ * EP1119: Skips tunnel initialization in cloud mode - supervisord manages cloudflared there.
6383
6413
  */
6384
6414
  async initialize() {
6385
6415
  if (this.initialized) {
6386
6416
  return;
6387
6417
  }
6388
6418
  console.log("[PreviewManager] Initializing...");
6389
- await this.tunnel.initialize();
6419
+ const modeConfig = getDaemonModeConfig();
6420
+ if (modeConfig.mode === "cloud") {
6421
+ console.log("[PreviewManager] EP1119: Skipping TunnelManager init in cloud mode");
6422
+ } else {
6423
+ await this.tunnel.initialize();
6424
+ }
6390
6425
  this.initialized = true;
6391
6426
  console.log("[PreviewManager] Initialized");
6392
6427
  }
@@ -6403,7 +6438,7 @@ var PreviewManager = class extends import_events3.EventEmitter {
6403
6438
  * @returns Result with success status and preview URL
6404
6439
  */
6405
6440
  async startPreview(config) {
6406
- const { moduleUid, worktreePath, port = DEFAULT_PORT, customCommand } = config;
6441
+ const { moduleUid, worktreePath, port = DEFAULT_PORT, customCommand, skipTunnel } = config;
6407
6442
  if (!worktreePath) {
6408
6443
  return { success: false, error: "Worktree path is required" };
6409
6444
  }
@@ -6467,6 +6502,17 @@ var PreviewManager = class extends import_events3.EventEmitter {
6467
6502
  state.state = "running";
6468
6503
  this.emitStateChange(moduleUid, "running");
6469
6504
  console.log(`[PreviewManager] Dev server running on port ${port}`);
6505
+ if (skipTunnel) {
6506
+ console.log(`[PreviewManager] EP1119: Skipping tunnel management for ${moduleUid} (cloud mode)`);
6507
+ state.state = "live";
6508
+ this.emitStateChange(moduleUid, "live");
6509
+ this.startingModules.delete(moduleUid);
6510
+ return {
6511
+ success: true,
6512
+ previewUrl: void 0
6513
+ // URL comes from Cloudflare Named Tunnel, not local
6514
+ };
6515
+ }
6470
6516
  console.log(`[PreviewManager] Starting Named Tunnel for ${moduleUid}...`);
6471
6517
  state.state = "tunneling";
6472
6518
  this.emitStateChange(moduleUid, "tunneling");
@@ -8103,6 +8149,15 @@ var Daemon = class _Daemon {
8103
8149
  this.startHealthCheckPolling();
8104
8150
  this.setupShutdownHandlers();
8105
8151
  console.log("[Daemon] Daemon started successfully");
8152
+ const modeConfig = getDaemonModeConfig();
8153
+ console.log("[Daemon] EP1115: Mode config:", {
8154
+ mode: modeConfig.mode,
8155
+ portAllocation: modeConfig.portAllocation,
8156
+ fixedPort: modeConfig.fixedPort,
8157
+ orphanTunnelCleanup: modeConfig.orphanTunnelCleanup,
8158
+ orphanWorktreeCleanup: modeConfig.orphanWorktreeCleanup,
8159
+ maxConcurrentModules: modeConfig.maxConcurrentModules
8160
+ });
8106
8161
  this.checkAndNotifyUpdates();
8107
8162
  }
8108
8163
  /**
@@ -8593,15 +8648,25 @@ var Daemon = class _Daemon {
8593
8648
  return;
8594
8649
  }
8595
8650
  console.log(`[Daemon] EP1024: Using worktree path ${worktree.path} for ${cmd.moduleUid}`);
8596
- const port = cmd.port || allocatePort(cmd.moduleUid);
8597
- console.log(`[Daemon] EP1038: Allocated port ${port} for ${cmd.moduleUid}`);
8651
+ const modeConfig = getDaemonModeConfig();
8652
+ let port;
8653
+ if (cmd.port) {
8654
+ port = cmd.port;
8655
+ } else if (modeConfig.portAllocation === "fixed" && modeConfig.fixedPort) {
8656
+ port = modeConfig.fixedPort;
8657
+ } else {
8658
+ port = allocatePort(cmd.moduleUid);
8659
+ }
8660
+ console.log(`[Daemon] EP1115: Using port ${port} for ${cmd.moduleUid} (mode: ${modeConfig.mode})`);
8598
8661
  const devConfig = await (0, import_core12.loadConfig)();
8599
8662
  const customCommand = devConfig?.project_settings?.worktree_dev_server_script;
8600
8663
  const startResult = await previewManager.startPreview({
8601
8664
  moduleUid: cmd.moduleUid,
8602
8665
  worktreePath: worktree.path,
8603
8666
  port,
8604
- customCommand
8667
+ customCommand,
8668
+ skipTunnel: modeConfig.mode === "cloud"
8669
+ // EP1119: Cloud mode - supervisord handles cloudflared
8605
8670
  });
8606
8671
  if (startResult.success) {
8607
8672
  console.log(`[Daemon] EP1024: Preview started for ${cmd.moduleUid}: ${startResult.previewUrl}`);
@@ -8978,11 +9043,16 @@ var Daemon = class _Daemon {
8978
9043
  };
8979
9044
  client.once("auth_error", errorHandler);
8980
9045
  });
9046
+ const modeConfig = getDaemonModeConfig();
9047
+ const environment = modeConfig.mode;
9048
+ const containerId = process.env.EPISODA_CONTAINER_ID;
8981
9049
  await client.connect(wsUrl, config.access_token, this.machineId, {
8982
9050
  hostname: os8.hostname(),
8983
9051
  osPlatform: os8.platform(),
8984
9052
  osArch: os8.arch(),
8985
- daemonPid
9053
+ daemonPid,
9054
+ environment,
9055
+ containerId
8986
9056
  });
8987
9057
  console.log(`[Daemon] Successfully connected to project ${projectId}`);
8988
9058
  await authSuccessPromise;