@episoda/cli 0.2.222 → 0.2.224

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.
@@ -3074,7 +3074,7 @@ var require_package = __commonJS({
3074
3074
  "package.json"(exports2, module2) {
3075
3075
  module2.exports = {
3076
3076
  name: "@episoda/cli",
3077
- version: "0.2.222",
3077
+ version: "0.2.224",
3078
3078
  description: "CLI tool for Episoda local development workflow orchestration",
3079
3079
  main: "dist/index.js",
3080
3080
  types: "dist/index.d.ts",
@@ -3336,6 +3336,10 @@ function removeProject(projectPath) {
3336
3336
  }
3337
3337
  return false;
3338
3338
  }
3339
+ function getProject(projectPath) {
3340
+ const data = readProjects();
3341
+ return data.projects.find((p) => p.path === projectPath) || null;
3342
+ }
3339
3343
  function getAllProjects() {
3340
3344
  const data = readProjects();
3341
3345
  return data.projects;
@@ -15946,6 +15950,9 @@ var Daemon = class _Daemon {
15946
15950
  static {
15947
15951
  this.AGENT_HEARTBEAT_INTERVAL_MS = 6e4;
15948
15952
  }
15953
+ static {
15954
+ this.DISCONNECTED_PROJECT_RECONNECT_DELAY_MS = 2e3;
15955
+ }
15949
15956
  static {
15950
15957
  this.HEALTH_PORT = 9999;
15951
15958
  }
@@ -16000,6 +16007,32 @@ var Daemon = class _Daemon {
16000
16007
  console.warn(`[Daemon] EP1429: Failed to stop session ${sessionId} after continue=false`, error);
16001
16008
  }
16002
16009
  }
16010
+ scheduleTrackedProjectReconnect(projectId, projectPath, reason) {
16011
+ const trackedProject = getProject(projectPath);
16012
+ const connection = this.connectionManager.getConnection(projectPath);
16013
+ if (!trackedProject || !connection) {
16014
+ return false;
16015
+ }
16016
+ if (connection.reconnectTimer) {
16017
+ clearTimeout(connection.reconnectTimer);
16018
+ }
16019
+ connection.reconnectTimer = setTimeout(() => {
16020
+ const latest = this.connectionManager.getConnection(projectPath);
16021
+ if (latest) {
16022
+ latest.reconnectTimer = void 0;
16023
+ }
16024
+ void this.connectProject(projectId, projectPath).catch((error) => {
16025
+ console.warn(
16026
+ `[Daemon] Automatic reconnect failed for ${projectPath}:`,
16027
+ error instanceof Error ? error.message : error
16028
+ );
16029
+ });
16030
+ }, _Daemon.DISCONNECTED_PROJECT_RECONNECT_DELAY_MS);
16031
+ console.log(
16032
+ `[Daemon] Scheduling reconnect for ${projectPath} in ${_Daemon.DISCONNECTED_PROJECT_RECONNECT_DELAY_MS}ms (${reason})`
16033
+ );
16034
+ return true;
16035
+ }
16003
16036
  startAgentHeartbeatLoop(sessionId, client) {
16004
16037
  if (this.agentHeartbeatLoops.has(sessionId)) return;
16005
16038
  let stopped = false;
@@ -16687,6 +16720,14 @@ var Daemon = class _Daemon {
16687
16720
  client.setAutoReconnect(true);
16688
16721
  console.log(`[Daemon] Authenticated for project ${projectId}`);
16689
16722
  touchProject(projectPath);
16723
+ const activeConnection = this.connectionManager.getConnection(projectPath);
16724
+ if (activeConnection?.reconnectTimer) {
16725
+ clearTimeout(activeConnection.reconnectTimer);
16726
+ activeConnection.reconnectTimer = void 0;
16727
+ }
16728
+ if (activeConnection) {
16729
+ activeConnection.manualDisconnectRequested = false;
16730
+ }
16690
16731
  this.connectionManager.addLiveConnection(projectPath);
16691
16732
  this.lastLiveConnectionAt = Date.now();
16692
16733
  this.lastDisconnectAt = null;
@@ -16843,6 +16884,8 @@ var Daemon = class _Daemon {
16843
16884
  });
16844
16885
  client.on("disconnected", (event) => {
16845
16886
  const disconnectEvent = event;
16887
+ const activeConnection = this.connectionManager.getConnection(projectPath);
16888
+ const manualDisconnectRequested = activeConnection?.manualDisconnectRequested === true;
16846
16889
  console.log(`[Daemon] Connection closed for ${projectId}: code=${disconnectEvent.code}, willReconnect=${disconnectEvent.willReconnect}`);
16847
16890
  this.logReliabilityMetric("ws_transport_disconnect", {
16848
16891
  projectId,
@@ -16856,7 +16899,12 @@ var Daemon = class _Daemon {
16856
16899
  this.lastDisconnectAt = this.lastDisconnectAt || Date.now();
16857
16900
  }
16858
16901
  this.updateManager.applyPendingUpdateIfIdle();
16859
- if (!disconnectEvent.willReconnect) {
16902
+ const daemonReconnectScheduled = !disconnectEvent.willReconnect && !manualDisconnectRequested ? this.scheduleTrackedProjectReconnect(
16903
+ projectId,
16904
+ projectPath,
16905
+ disconnectEvent.reason || "transport_disconnected"
16906
+ ) : false;
16907
+ if (!disconnectEvent.willReconnect && (manualDisconnectRequested || !daemonReconnectScheduled)) {
16860
16908
  this.connectionManager.deleteConnection(projectPath);
16861
16909
  console.log(`[Daemon] Removed connection for ${projectPath} from map`);
16862
16910
  }
@@ -16936,8 +16984,10 @@ var Daemon = class _Daemon {
16936
16984
  if (!connection) {
16937
16985
  return;
16938
16986
  }
16987
+ connection.manualDisconnectRequested = true;
16939
16988
  if (connection.reconnectTimer) {
16940
16989
  clearTimeout(connection.reconnectTimer);
16990
+ connection.reconnectTimer = void 0;
16941
16991
  }
16942
16992
  await connection.client.disconnect();
16943
16993
  this.connectionManager.deleteConnection(projectPath);