@episoda/cli 0.2.220 → 0.2.222

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.
@@ -36,7 +36,8 @@ var require_command_protocol = __commonJS({
36
36
  "../core/dist/command-protocol.js"(exports2) {
37
37
  "use strict";
38
38
  Object.defineProperty(exports2, "__esModule", { value: true });
39
- exports2.WORKTREE_STATUS_VALUES = void 0;
39
+ exports2.WORKTREE_STATUS_VALUES = exports2.DAEMON_PROTOCOL_VERSION = void 0;
40
+ exports2.DAEMON_PROTOCOL_VERSION = 2;
40
41
  exports2.WORKTREE_STATUS_VALUES = [
41
42
  "pending",
42
43
  "provisioning",
@@ -2180,6 +2181,7 @@ var require_websocket_client = __commonJS({
2180
2181
  exports2.EpisodaClient = void 0;
2181
2182
  var ws_1 = __importDefault(require("ws"));
2182
2183
  var https_1 = __importDefault(require("https"));
2184
+ var command_protocol_1 = require_command_protocol();
2183
2185
  var version_1 = require_version();
2184
2186
  var ipv4Agent = new https_1.default.Agent({ family: 4 });
2185
2187
  var MAX_RETRY_DURATION = 6 * 60 * 60 * 1e3;
@@ -2196,6 +2198,7 @@ var require_websocket_client = __commonJS({
2196
2198
  this.autoReconnectEnabled = true;
2197
2199
  this.url = "";
2198
2200
  this.token = "";
2201
+ this.protocolVersion = command_protocol_1.DAEMON_PROTOCOL_VERSION;
2199
2202
  this.isConnected = false;
2200
2203
  this.isDisconnecting = false;
2201
2204
  this.isGracefulShutdown = false;
@@ -2221,11 +2224,15 @@ var require_websocket_client = __commonJS({
2221
2224
  this.osArch = deviceInfo?.osArch;
2222
2225
  this.daemonPid = deviceInfo?.daemonPid;
2223
2226
  this.cliVersion = deviceInfo?.cliVersion;
2227
+ this.protocolVersion = deviceInfo?.protocolVersion ?? command_protocol_1.DAEMON_PROTOCOL_VERSION;
2224
2228
  this.cliPackageName = deviceInfo?.cliPackageName;
2225
2229
  this.capabilities = deviceInfo?.capabilities;
2230
+ this.ptyProviderVersions = deviceInfo?.ptyProviderVersions;
2226
2231
  this.environment = deviceInfo?.environment;
2227
2232
  this.containerId = deviceInfo?.containerId;
2233
+ this.sessionGeneration = void 0;
2228
2234
  this.isDisconnecting = false;
2235
+ this.autoReconnectEnabled = true;
2229
2236
  this.isGracefulShutdown = false;
2230
2237
  this.isIntentionalDisconnect = false;
2231
2238
  this.lastConnectAttemptTime = Date.now();
@@ -2262,8 +2269,10 @@ var require_websocket_client = __commonJS({
2262
2269
  type: "auth",
2263
2270
  token,
2264
2271
  version: this.cliVersion || version_1.VERSION,
2272
+ protocolVersion: this.protocolVersion,
2265
2273
  cliPackageName: this.cliPackageName,
2266
2274
  capabilities: this.capabilities,
2275
+ ptyProviderVersions: this.ptyProviderVersions,
2267
2276
  environment: this.environment,
2268
2277
  machineId,
2269
2278
  containerId: this.containerId,
@@ -2295,6 +2304,7 @@ var require_websocket_client = __commonJS({
2295
2304
  this.ws.on("close", (code, reason) => {
2296
2305
  console.log(`[EpisodaClient] WebSocket closed: ${code} ${reason.toString()}`);
2297
2306
  this.isConnected = false;
2307
+ this.sessionGeneration = void 0;
2298
2308
  const willReconnect = !this.isDisconnecting && this.autoReconnectEnabled;
2299
2309
  this.emit({
2300
2310
  type: "disconnected",
@@ -2356,6 +2366,7 @@ var require_websocket_client = __commonJS({
2356
2366
  this.ws = void 0;
2357
2367
  }
2358
2368
  this.isConnected = false;
2369
+ this.sessionGeneration = void 0;
2359
2370
  }
2360
2371
  /**
2361
2372
  * Register an event handler
@@ -2433,7 +2444,8 @@ var require_websocket_client = __commonJS({
2433
2444
  */
2434
2445
  getStatus() {
2435
2446
  return {
2436
- connected: this.isConnected
2447
+ connected: this.isConnected,
2448
+ sessionGeneration: this.sessionGeneration
2437
2449
  };
2438
2450
  }
2439
2451
  /**
@@ -2475,6 +2487,9 @@ var require_websocket_client = __commonJS({
2475
2487
  * Handle incoming message from server
2476
2488
  */
2477
2489
  handleMessage(message) {
2490
+ if (message.type === "auth_success") {
2491
+ this.sessionGeneration = message.sessionGeneration;
2492
+ }
2478
2493
  if (message.type === "shutdown") {
2479
2494
  console.log("[EpisodaClient] Received graceful shutdown message from server");
2480
2495
  this.isGracefulShutdown = true;
@@ -2492,6 +2507,11 @@ var require_websocket_client = __commonJS({
2492
2507
  this.consecutiveAuthFailures++;
2493
2508
  console.warn(`[EpisodaClient] Auth failure (${this.consecutiveAuthFailures}): ${errorMessage.code}`);
2494
2509
  }
2510
+ if (errorMessage.code === "DAEMON_UPDATE_REQUIRED" || errorMessage.code === "PROTOCOL_MISMATCH") {
2511
+ this.autoReconnectEnabled = false;
2512
+ const errorText = "message" in errorMessage && typeof errorMessage.message === "string" ? errorMessage.message : "Daemon update required";
2513
+ console.error(`[EpisodaClient] ${errorMessage.code}: ${errorText}`);
2514
+ }
2495
2515
  }
2496
2516
  const handlers = this.eventHandlers.get(message.type) || [];
2497
2517
  handlers.forEach((handler) => {
@@ -2621,8 +2641,10 @@ var require_websocket_client = __commonJS({
2621
2641
  osArch: this.osArch,
2622
2642
  daemonPid: this.daemonPid,
2623
2643
  cliVersion: this.cliVersion,
2644
+ protocolVersion: this.protocolVersion,
2624
2645
  cliPackageName: this.cliPackageName,
2625
2646
  capabilities: this.capabilities,
2647
+ ptyProviderVersions: this.ptyProviderVersions,
2626
2648
  environment: this.environment,
2627
2649
  containerId: this.containerId
2628
2650
  }).then(() => {
@@ -3052,7 +3074,7 @@ var require_package = __commonJS({
3052
3074
  "package.json"(exports2, module2) {
3053
3075
  module2.exports = {
3054
3076
  name: "@episoda/cli",
3055
- version: "0.2.220",
3077
+ version: "0.2.222",
3056
3078
  description: "CLI tool for Episoda local development workflow orchestration",
3057
3079
  main: "dist/index.js",
3058
3080
  types: "dist/index.d.ts",
@@ -13262,7 +13284,8 @@ async function handlePtySpawn(payload, client) {
13262
13284
  moduleUid,
13263
13285
  agent_run_id,
13264
13286
  code: -1,
13265
- durationMs: 0
13287
+ durationMs: 0,
13288
+ sessionGeneration: client.getStatus().sessionGeneration
13266
13289
  });
13267
13290
  return {
13268
13291
  success: false,
@@ -13328,7 +13351,8 @@ async function handlePtySpawn(payload, client) {
13328
13351
  moduleUid,
13329
13352
  agent_run_id,
13330
13353
  code: exitCode,
13331
- durationMs
13354
+ durationMs,
13355
+ sessionGeneration: client.getStatus().sessionGeneration
13332
13356
  }).catch((err) => {
13333
13357
  console.error(`[PTY] Failed to send pty_exit for ${agent_run_id}:`, err.message);
13334
13358
  });
@@ -15496,7 +15520,8 @@ var ProjectMessageRouter = class {
15496
15520
  startupConfirmedAt: result.startupConfirmedAt,
15497
15521
  modelUsed: result.modelUsed,
15498
15522
  launchConfig: result.launchConfig,
15499
- authPath: result.authPath
15523
+ authPath: result.authPath,
15524
+ sessionGeneration: client.getStatus().sessionGeneration
15500
15525
  });
15501
15526
  }
15502
15527
  });
@@ -15524,7 +15549,8 @@ var ProjectMessageRouter = class {
15524
15549
  requestId: message.id,
15525
15550
  agent_run_id: payload.agent_run_id,
15526
15551
  success: result.success,
15527
- error: result.error
15552
+ error: result.error,
15553
+ sessionGeneration: client.getStatus().sessionGeneration
15528
15554
  });
15529
15555
  if (!result.success) {
15530
15556
  console.warn(`[Daemon] EP1476: pty_stdin failed for run ${payload.agent_run_id}: ${result.error}`);
@@ -15815,6 +15841,69 @@ function collectUnexpectedWorktrees(params) {
15815
15841
 
15816
15842
  // src/daemon/daemon-process.ts
15817
15843
  var packageJson = require_package();
15844
+ var DAEMON_PROTOCOL_VERSION = 2;
15845
+ function resolveBundledBinaryCandidates(binaryName) {
15846
+ return [
15847
+ path37.join(__dirname, "..", "..", "node_modules", ".bin", binaryName),
15848
+ path37.join(__dirname, "..", "..", "..", "..", "node_modules", ".bin", binaryName),
15849
+ path37.join(__dirname, "..", "..", "..", "..", "..", "node_modules", ".bin", binaryName)
15850
+ ];
15851
+ }
15852
+ function tryReadBinaryVersionAsync(binaryPath, versionPattern) {
15853
+ return new Promise((resolve10) => {
15854
+ (0, import_child_process18.execFile)(
15855
+ binaryPath,
15856
+ ["--version"],
15857
+ {
15858
+ encoding: "utf-8",
15859
+ timeout: 5e3,
15860
+ windowsHide: true
15861
+ },
15862
+ (error, stdout) => {
15863
+ if (error) {
15864
+ resolve10(void 0);
15865
+ return;
15866
+ }
15867
+ const output = String(stdout ?? "").trim();
15868
+ const match = output.match(versionPattern);
15869
+ resolve10(match?.[1]);
15870
+ }
15871
+ );
15872
+ });
15873
+ }
15874
+ async function detectPtyProviderVersions() {
15875
+ const providers = [
15876
+ { key: "claude", binaryName: "claude", versionPattern: /(\d+\.\d+(?:\.\d+)?)/ },
15877
+ { key: "codex", binaryName: "codex", versionPattern: /(\d+\.\d+(?:\.\d+)?)/i }
15878
+ ];
15879
+ const versions = {};
15880
+ for (const provider of providers) {
15881
+ const bundledCandidates = resolveBundledBinaryCandidates(provider.binaryName);
15882
+ const candidates = bundledCandidates.filter((candidate, index, arr) => fs35.existsSync(candidate) && arr.indexOf(candidate) === index);
15883
+ for (const candidate of candidates) {
15884
+ const version = await tryReadBinaryVersionAsync(candidate, provider.versionPattern);
15885
+ if (version) {
15886
+ versions[provider.key] = version;
15887
+ break;
15888
+ }
15889
+ }
15890
+ if (versions[provider.key]) {
15891
+ continue;
15892
+ }
15893
+ const globalVersion = await tryReadBinaryVersionAsync(provider.binaryName, provider.versionPattern);
15894
+ if (globalVersion) {
15895
+ versions[provider.key] = globalVersion;
15896
+ }
15897
+ }
15898
+ return versions;
15899
+ }
15900
+ var detectedPtyProviderVersionsPromise = null;
15901
+ function getDetectedPtyProviderVersions() {
15902
+ if (!detectedPtyProviderVersionsPromise) {
15903
+ detectedPtyProviderVersionsPromise = detectPtyProviderVersions().catch(() => ({}));
15904
+ }
15905
+ return detectedPtyProviderVersionsPromise;
15906
+ }
15818
15907
  var Daemon = class _Daemon {
15819
15908
  constructor() {
15820
15909
  this.machineId = "";
@@ -16787,17 +16876,21 @@ var Daemon = class _Daemon {
16787
16876
  const environment = modeConfig.mode;
16788
16877
  const containerId = process.env.EPISODA_CONTAINER_ID;
16789
16878
  const capabilities = ["worktree_create_v1", "pty_v1"];
16790
- await client.connect(wsEndpoint.wsUrl, config.access_token, this.machineId, {
16879
+ const ptyProviderVersions = await getDetectedPtyProviderVersions();
16880
+ const deviceInfo = {
16791
16881
  hostname: os16.hostname(),
16792
16882
  osPlatform: os16.platform(),
16793
16883
  osArch: os16.arch(),
16794
16884
  daemonPid,
16795
16885
  cliVersion: this.cliRuntimeVersion,
16886
+ protocolVersion: DAEMON_PROTOCOL_VERSION,
16796
16887
  cliPackageName: packageJson.name,
16797
16888
  capabilities,
16889
+ ptyProviderVersions,
16798
16890
  environment,
16799
16891
  containerId
16800
- });
16892
+ };
16893
+ await client.connect(wsEndpoint.wsUrl, config.access_token, this.machineId, deviceInfo);
16801
16894
  console.log(`[Daemon] Successfully connected to project ${projectId}`);
16802
16895
  this.connectionManager.setState(projectPath, "authenticating");
16803
16896
  await this.connectionManager.waitForAuthentication(client, 3e4);