episoda 0.2.63 → 0.2.64

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.
@@ -2726,7 +2726,7 @@ var require_package = __commonJS({
2726
2726
  "package.json"(exports2, module2) {
2727
2727
  module2.exports = {
2728
2728
  name: "episoda",
2729
- version: "0.2.63",
2729
+ version: "0.2.64",
2730
2730
  description: "CLI tool for Episoda local development workflow orchestration",
2731
2731
  main: "dist/index.js",
2732
2732
  types: "dist/index.d.ts",
@@ -8007,8 +8007,8 @@ var Daemon = class _Daemon {
8007
8007
  // 60 seconds
8008
8008
  constructor() {
8009
8009
  this.machineId = "";
8010
- this.deviceId = null;
8011
- // EP726: Cached device UUID from server
8010
+ this.machineUuid = null;
8011
+ // EP1091: Renamed from deviceId for platform terminology alignment
8012
8012
  this.deviceName = null;
8013
8013
  // EP661: Cached device name from server
8014
8014
  this.flyMachineId = null;
@@ -8067,9 +8067,9 @@ var Daemon = class _Daemon {
8067
8067
  this.machineId = await getMachineId();
8068
8068
  console.log(`[Daemon] Machine ID: ${this.machineId}`);
8069
8069
  const config = await (0, import_core12.loadConfig)();
8070
- if (config?.device_id) {
8071
- this.deviceId = config.device_id;
8072
- console.log(`[Daemon] Loaded cached Device ID (UUID): ${this.deviceId}`);
8070
+ if (config?.machine_uuid || config?.device_id) {
8071
+ this.machineUuid = config.machine_uuid || config.device_id || null;
8072
+ console.log(`[Daemon] Loaded cached Machine UUID: ${this.machineUuid}`);
8073
8073
  }
8074
8074
  await this.ipcServer.start();
8075
8075
  console.log("[Daemon] IPC server started");
@@ -8121,8 +8121,10 @@ var Daemon = class _Daemon {
8121
8121
  return {
8122
8122
  running: true,
8123
8123
  machineId: this.machineId,
8124
- deviceId: this.deviceId,
8125
- // EP726: UUID for unified device identification
8124
+ machineUuid: this.machineUuid,
8125
+ // EP1091: New preferred field name
8126
+ deviceId: this.machineUuid,
8127
+ // EP726: Kept for backward compatibility
8126
8128
  hostname: os8.hostname(),
8127
8129
  platform: os8.platform(),
8128
8130
  arch: os8.arch(),
@@ -8834,18 +8836,19 @@ var Daemon = class _Daemon {
8834
8836
  this.liveConnections.add(projectPath);
8835
8837
  this.pendingConnections.delete(projectPath);
8836
8838
  const authMessage = message;
8839
+ const effectiveMachineUuid = authMessage.machineUuid || authMessage.deviceId;
8837
8840
  if (authMessage.userId && authMessage.workspaceId) {
8838
- await this.configureGitUser(projectPath, authMessage.userId, authMessage.workspaceId, this.machineId, projectId, authMessage.deviceId);
8841
+ await this.configureGitUser(projectPath, authMessage.userId, authMessage.workspaceId, this.machineId, projectId, effectiveMachineUuid);
8839
8842
  await this.installGitHooks(projectPath);
8840
8843
  }
8841
8844
  if (authMessage.deviceName) {
8842
8845
  this.deviceName = authMessage.deviceName;
8843
8846
  console.log(`[Daemon] Device name: ${this.deviceName}`);
8844
8847
  }
8845
- if (authMessage.deviceId) {
8846
- this.deviceId = authMessage.deviceId;
8847
- console.log(`[Daemon] Device ID (UUID): ${this.deviceId}`);
8848
- await this.cacheDeviceId(authMessage.deviceId);
8848
+ if (effectiveMachineUuid) {
8849
+ this.machineUuid = effectiveMachineUuid;
8850
+ console.log(`[Daemon] Machine UUID: ${this.machineUuid}`);
8851
+ await this.cacheMachineUuid(effectiveMachineUuid);
8849
8852
  }
8850
8853
  if (authMessage.flyMachineId) {
8851
8854
  this.flyMachineId = authMessage.flyMachineId;
@@ -8867,9 +8870,6 @@ var Daemon = class _Daemon {
8867
8870
  this.reconcileWorktrees(projectId, projectPath, client).catch((err) => {
8868
8871
  console.warn("[Daemon] EP1003: Reconciliation report failed:", err.message);
8869
8872
  });
8870
- this.reconcilePendingCleanups(projectId, projectPath).catch((err) => {
8871
- console.warn("[Daemon] EP1047: Cleanup queue reconciliation failed:", err.message);
8872
- });
8873
8873
  });
8874
8874
  client.on("module_state_changed", async (message) => {
8875
8875
  if (message.type === "module_state_changed") {
@@ -8879,7 +8879,7 @@ var Daemon = class _Daemon {
8879
8879
  console.log(`[Daemon] EP1003: State change for non-local module ${moduleUid} (mode: ${devMode || "unknown"})`);
8880
8880
  return;
8881
8881
  }
8882
- if (checkoutMachineId && checkoutMachineId !== this.deviceId) {
8882
+ if (checkoutMachineId && checkoutMachineId !== this.machineUuid) {
8883
8883
  console.log(`[Daemon] EP1003: State change for ${moduleUid} handled by different machine: ${checkoutMachineId}`);
8884
8884
  return;
8885
8885
  }
@@ -8984,12 +8984,13 @@ var Daemon = class _Daemon {
8984
8984
  * EP595: Configure git with user and workspace ID for post-checkout hook
8985
8985
  * EP655: Added machineId for device isolation in multi-device environments
8986
8986
  * EP725: Added projectId for main branch badge tracking
8987
- * EP726: Added deviceId (UUID) for unified device identification
8987
+ * EP726: Added machineUuid (UUID) for unified device identification
8988
+ * EP1091: Renamed deviceId param to machineUuid for consistency
8988
8989
  *
8989
8990
  * This stores the IDs in .git/config so the post-checkout hook can
8990
8991
  * update module.checkout_* fields when git operations happen from terminal.
8991
8992
  */
8992
- async configureGitUser(projectPath, userId, workspaceId, machineId, projectId, deviceId) {
8993
+ async configureGitUser(projectPath, userId, workspaceId, machineId, projectId, machineUuid) {
8993
8994
  try {
8994
8995
  const { execSync: execSync9 } = await import("child_process");
8995
8996
  execSync9(`git config episoda.userId ${userId}`, {
@@ -9012,14 +9013,14 @@ var Daemon = class _Daemon {
9012
9013
  encoding: "utf8",
9013
9014
  stdio: "pipe"
9014
9015
  });
9015
- if (deviceId) {
9016
- execSync9(`git config episoda.deviceId ${deviceId}`, {
9016
+ if (machineUuid) {
9017
+ execSync9(`git config episoda.deviceId ${machineUuid}`, {
9017
9018
  cwd: projectPath,
9018
9019
  encoding: "utf8",
9019
9020
  stdio: "pipe"
9020
9021
  });
9021
9022
  }
9022
- console.log(`[Daemon] Configured git for project: episoda.userId=${userId}, machineId=${machineId}, projectId=${projectId}${deviceId ? `, deviceId=${deviceId}` : ""}`);
9023
+ console.log(`[Daemon] Configured git for project: episoda.userId=${userId}, machineId=${machineId}, projectId=${projectId}${machineUuid ? `, machineUuid=${machineUuid}` : ""}`);
9023
9024
  } catch (error) {
9024
9025
  console.warn(`[Daemon] Failed to configure git user for ${projectPath}:`, error instanceof Error ? error.message : error);
9025
9026
  }
@@ -9061,30 +9062,34 @@ var Daemon = class _Daemon {
9061
9062
  }
9062
9063
  }
9063
9064
  /**
9064
- * EP726: Cache device UUID to config file
9065
+ * EP726: Cache machine UUID to config file
9066
+ * EP1091: Renamed from cacheDeviceId, writes machine_uuid (new) and device_id (backward compat)
9065
9067
  *
9066
- * Persists the device_id (UUID) received from the server so it's available
9068
+ * Persists the machine UUID received from the server so it's available
9067
9069
  * on daemon restart without needing to re-register the device.
9068
9070
  */
9069
- async cacheDeviceId(deviceId) {
9071
+ async cacheMachineUuid(machineUuid) {
9070
9072
  try {
9071
9073
  const config = await (0, import_core12.loadConfig)();
9072
9074
  if (!config) {
9073
- console.warn("[Daemon] Cannot cache device ID - no config found");
9075
+ console.warn("[Daemon] Cannot cache machine UUID - no config found");
9074
9076
  return;
9075
9077
  }
9076
- if (config.device_id === deviceId) {
9078
+ if (config.machine_uuid === machineUuid) {
9077
9079
  return;
9078
9080
  }
9079
9081
  const updatedConfig = {
9080
9082
  ...config,
9081
- device_id: deviceId,
9083
+ machine_uuid: machineUuid,
9084
+ // EP1091: New preferred field
9085
+ device_id: machineUuid,
9086
+ // Backward compatibility
9082
9087
  machine_id: this.machineId
9083
9088
  };
9084
9089
  await (0, import_core12.saveConfig)(updatedConfig);
9085
- console.log(`[Daemon] Cached device ID to config: ${deviceId}`);
9090
+ console.log(`[Daemon] Cached machine UUID to config: ${machineUuid}`);
9086
9091
  } catch (error) {
9087
- console.warn("[Daemon] Failed to cache device ID:", error instanceof Error ? error.message : error);
9092
+ console.warn("[Daemon] Failed to cache machine UUID:", error instanceof Error ? error.message : error);
9088
9093
  }
9089
9094
  }
9090
9095
  /**
@@ -9145,14 +9150,14 @@ var Daemon = class _Daemon {
9145
9150
  */
9146
9151
  async syncMachineProjectPath(projectId, projectPath) {
9147
9152
  try {
9148
- if (!this.deviceId) {
9149
- console.warn("[Daemon] EP995: Cannot sync project path - deviceId not available");
9153
+ if (!this.machineUuid) {
9154
+ console.warn("[Daemon] EP995: Cannot sync project path - machineUuid not available");
9150
9155
  return;
9151
9156
  }
9152
9157
  const config = await (0, import_core12.loadConfig)();
9153
9158
  if (!config) return;
9154
9159
  const apiUrl = config.api_url || "https://episoda.dev";
9155
- const response = await fetchWithAuth(`${apiUrl}/api/account/machines/${this.deviceId}`, {
9160
+ const response = await fetchWithAuth(`${apiUrl}/api/account/machines/${this.machineUuid}`, {
9156
9161
  method: "PATCH",
9157
9162
  headers: {
9158
9163
  "Content-Type": "application/json"
@@ -9233,8 +9238,8 @@ var Daemon = class _Daemon {
9233
9238
  async reconcileWorktrees(projectId, projectPath, client) {
9234
9239
  console.log(`[Daemon] EP1003: Starting reconciliation report for project ${projectId}`);
9235
9240
  try {
9236
- if (!this.deviceId) {
9237
- console.log("[Daemon] EP1003: Cannot reconcile - deviceId not available yet");
9241
+ if (!this.machineUuid) {
9242
+ console.log("[Daemon] EP1003: Cannot reconcile - machineUuid not available yet");
9238
9243
  return;
9239
9244
  }
9240
9245
  const config = await (0, import_core12.loadConfig)();
@@ -9245,7 +9250,7 @@ var Daemon = class _Daemon {
9245
9250
  let modulesResponse;
9246
9251
  try {
9247
9252
  modulesResponse = await fetchWithAuth(
9248
- `${apiUrl}/api/modules?state=doing,review&dev_mode=local&checkout_machine_id=${this.deviceId}&project_id=${projectId}`,
9253
+ `${apiUrl}/api/modules?state=doing,review&dev_mode=local&checkout_machine_id=${this.machineUuid}&project_id=${projectId}`,
9249
9254
  { signal: controller.signal }
9250
9255
  );
9251
9256
  } finally {
@@ -9294,7 +9299,7 @@ var Daemon = class _Daemon {
9294
9299
  }
9295
9300
  const report = {
9296
9301
  projectId,
9297
- machineId: this.deviceId,
9302
+ machineId: this.machineUuid,
9298
9303
  modules: moduleStatuses,
9299
9304
  orphanTunnels: orphanTunnels.length > 0 ? orphanTunnels : void 0
9300
9305
  };
@@ -9315,8 +9320,11 @@ var Daemon = class _Daemon {
9315
9320
  /**
9316
9321
  * EP1047: Process pending cleanup queue entries for this machine
9317
9322
  *
9318
- * On daemon startup/reconnect, fetch pending worktree cleanup tasks from the queue
9319
- * and process them. This catches any cleanups missed while the daemon was offline.
9323
+ * @deprecated EP1091: No longer called on connect. Server-side cron now processes
9324
+ * the cleanup queue and sends WebSocket commands to connected daemons. This is
9325
+ * more reliable than daemon-side polling since it works even if daemon stays connected.
9326
+ *
9327
+ * Kept for potential manual invocation or debugging purposes.
9320
9328
  *
9321
9329
  * Flow:
9322
9330
  * 1. Query server for pending cleanup tasks for this machine
@@ -9324,11 +9332,11 @@ var Daemon = class _Daemon {
9324
9332
  * 3. Report success/failure back to server
9325
9333
  */
9326
9334
  async reconcilePendingCleanups(projectId, projectPath) {
9327
- if (!this.deviceId) {
9328
- console.log("[Daemon] EP1047: Cannot reconcile cleanups - deviceId not available yet");
9335
+ if (!this.machineUuid) {
9336
+ console.log("[Daemon] EP1047: Cannot reconcile cleanups - machineUuid not available yet");
9329
9337
  return;
9330
9338
  }
9331
- console.log(`[Daemon] EP1047: Checking for pending cleanup tasks for machine ${this.deviceId}`);
9339
+ console.log(`[Daemon] EP1047: Checking for pending cleanup tasks for machine ${this.machineUuid}`);
9332
9340
  try {
9333
9341
  const config = await (0, import_core12.loadConfig)();
9334
9342
  if (!config) {
@@ -9341,7 +9349,7 @@ var Daemon = class _Daemon {
9341
9349
  let response;
9342
9350
  try {
9343
9351
  response = await fetchWithAuth(
9344
- `${apiUrl}/api/cli/background-ops?machine_id=${this.deviceId}`,
9352
+ `${apiUrl}/api/cli/background-ops?machine_id=${this.machineUuid}`,
9345
9353
  { signal: controller.signal }
9346
9354
  );
9347
9355
  } finally {