episoda 0.2.52 → 0.2.53

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.
@@ -2718,7 +2718,7 @@ var require_package = __commonJS({
2718
2718
  "package.json"(exports2, module2) {
2719
2719
  module2.exports = {
2720
2720
  name: "episoda",
2721
- version: "0.2.52",
2721
+ version: "0.2.53",
2722
2722
  description: "CLI tool for Episoda local development workflow orchestration",
2723
2723
  main: "dist/index.js",
2724
2724
  types: "dist/index.d.ts",
@@ -6838,14 +6838,21 @@ var WorktreeManager = class _WorktreeManager {
6838
6838
  error: result.output || "Failed to remove worktree"
6839
6839
  };
6840
6840
  }
6841
- const config = this.readConfig();
6842
- if (config) {
6843
- config.worktrees = config.worktrees.filter((w) => w.moduleUid !== moduleUid);
6844
- this.writeConfig(config);
6841
+ let configUpdated = false;
6842
+ try {
6843
+ const config = this.readConfig();
6844
+ if (config) {
6845
+ config.worktrees = config.worktrees.filter((w) => w.moduleUid !== moduleUid);
6846
+ this.writeConfig(config);
6847
+ configUpdated = true;
6848
+ }
6849
+ } catch (configError) {
6850
+ console.warn(`[WorktreeManager] EP1035: Config update failed after removing ${moduleUid} (non-blocking):`, configError.message);
6845
6851
  }
6846
6852
  return {
6847
6853
  success: true,
6848
- worktreePath: existing.worktreePath
6854
+ worktreePath: existing.worktreePath,
6855
+ configUpdated
6849
6856
  };
6850
6857
  } finally {
6851
6858
  this.releaseLock();
@@ -7052,7 +7059,12 @@ var WorktreeManager = class _WorktreeManager {
7052
7059
  const content = fs13.readFileSync(this.configPath, "utf-8");
7053
7060
  return JSON.parse(content);
7054
7061
  } catch (error) {
7055
- console.error("[WorktreeManager] Failed to read config:", error);
7062
+ if (error instanceof SyntaxError) {
7063
+ console.warn(`[WorktreeManager] EP1035: Config file corrupted at ${this.configPath} - JSON parse error:`, error.message);
7064
+ console.warn("[WorktreeManager] EP1035: Config will be recovered on next pruneStaleWorktrees call");
7065
+ } else {
7066
+ console.error("[WorktreeManager] Failed to read config:", error.message);
7067
+ }
7056
7068
  return null;
7057
7069
  }
7058
7070
  }
@@ -8217,6 +8229,78 @@ var Daemon = class _Daemon {
8217
8229
  }
8218
8230
  }
8219
8231
  });
8232
+ client.on("worktree_cleanup_command", async (message) => {
8233
+ if (message.type === "worktree_cleanup_command" && message.command) {
8234
+ const cmd = message.command;
8235
+ console.log(`[Daemon] EP1035: Received worktree cleanup command for ${cmd.moduleUid}`);
8236
+ client.updateActivity();
8237
+ let result;
8238
+ try {
8239
+ const projectRootPath = await findProjectRoot(cmd.worktreePath);
8240
+ if (!projectRootPath) {
8241
+ console.warn(`[Daemon] EP1035: Cannot find project root for ${cmd.worktreePath}`);
8242
+ result = {
8243
+ success: false,
8244
+ error: `Cannot find project root for worktree path: ${cmd.worktreePath}`
8245
+ };
8246
+ } else {
8247
+ const manager = new WorktreeManager(projectRootPath);
8248
+ const initialized = await manager.initialize();
8249
+ if (!initialized) {
8250
+ console.warn(`[Daemon] EP1035: Failed to initialize WorktreeManager for ${projectRootPath}`);
8251
+ result = {
8252
+ success: false,
8253
+ error: `Failed to initialize WorktreeManager for project: ${projectRootPath}`
8254
+ };
8255
+ } else {
8256
+ const removeResult = await manager.removeWorktree(cmd.moduleUid, cmd.force || false);
8257
+ if (removeResult.success) {
8258
+ if (removeResult.configUpdated === false) {
8259
+ console.warn(`[Daemon] EP1035: Worktree ${cmd.moduleUid} removed but config update failed (will sync on next prune)`);
8260
+ } else {
8261
+ console.log(`[Daemon] EP1035: Successfully cleaned up worktree for ${cmd.moduleUid}`);
8262
+ }
8263
+ result = {
8264
+ success: true,
8265
+ worktreePath: removeResult.worktreePath
8266
+ };
8267
+ } else {
8268
+ if (removeResult.error?.includes("not found") || removeResult.error?.includes("No worktree found")) {
8269
+ console.log(`[Daemon] EP1035: Worktree for ${cmd.moduleUid} already removed, syncing config`);
8270
+ await manager.pruneStaleWorktrees();
8271
+ result = {
8272
+ success: true,
8273
+ worktreePath: cmd.worktreePath
8274
+ };
8275
+ } else {
8276
+ console.error(`[Daemon] EP1035: Failed to remove worktree for ${cmd.moduleUid}: ${removeResult.error}`);
8277
+ result = {
8278
+ success: false,
8279
+ error: removeResult.error
8280
+ };
8281
+ }
8282
+ }
8283
+ }
8284
+ }
8285
+ } catch (error) {
8286
+ console.error(`[Daemon] EP1035: Worktree cleanup error for ${cmd.moduleUid}:`, error);
8287
+ result = {
8288
+ success: false,
8289
+ error: error instanceof Error ? error.message : String(error)
8290
+ };
8291
+ }
8292
+ try {
8293
+ await client.send({
8294
+ type: "worktree_cleanup_result",
8295
+ commandId: message.id,
8296
+ result
8297
+ });
8298
+ } catch (sendError) {
8299
+ console.error(`[Daemon] EP1035: Failed to send cleanup result (WebSocket may be disconnected):`, sendError);
8300
+ }
8301
+ console.log(`[Daemon] EP1035: Worktree cleanup for ${cmd.moduleUid} completed:`, result.success ? "success" : "failed");
8302
+ }
8303
+ });
8220
8304
  client.on("shutdown", async (message) => {
8221
8305
  const shutdownMessage = message;
8222
8306
  const reason = shutdownMessage.reason || "unknown";
@@ -8997,14 +9081,36 @@ var Daemon = class _Daemon {
8997
9081
  }
8998
9082
  const { orphaned } = manager.auditWorktrees(activeModuleUids);
8999
9083
  if (orphaned.length > 0) {
9000
- console.log(`[Daemon] EP957: Found ${orphaned.length} orphaned worktree(s) in ${config.workspaceSlug}/${config.projectSlug}:`);
9084
+ console.log(`[Daemon] EP1035: Found ${orphaned.length} orphaned worktree(s) in ${config.workspaceSlug}/${config.projectSlug}:`);
9001
9085
  for (const w of orphaned) {
9002
9086
  console.log(` - ${w.moduleUid} (branch: ${w.branchName})`);
9003
9087
  }
9004
- console.log('[Daemon] EP957: Run "episoda release <module>" to clean up');
9088
+ console.log("[Daemon] EP1035: Auto-cleaning orphaned worktrees...");
9089
+ for (const w of orphaned) {
9090
+ try {
9091
+ const removeResult = await manager.removeWorktree(w.moduleUid, true);
9092
+ if (removeResult.success) {
9093
+ console.log(`[Daemon] EP1035: Cleaned up orphaned worktree ${w.moduleUid}`);
9094
+ } else {
9095
+ if (removeResult.error?.includes("not found") || removeResult.error?.includes("No worktree found")) {
9096
+ console.log(`[Daemon] EP1035: Worktree ${w.moduleUid} already removed, syncing config`);
9097
+ await manager.pruneStaleWorktrees();
9098
+ } else {
9099
+ console.warn(`[Daemon] EP1035: Failed to clean up ${w.moduleUid}: ${removeResult.error}`);
9100
+ }
9101
+ }
9102
+ } catch (cleanupError) {
9103
+ console.warn(`[Daemon] EP1035: Error cleaning up ${w.moduleUid}:`, cleanupError.message);
9104
+ }
9105
+ }
9106
+ try {
9107
+ await manager.pruneStaleWorktrees();
9108
+ } catch (pruneError) {
9109
+ console.warn("[Daemon] EP1035: Failed to prune stale worktrees:", pruneError.message);
9110
+ }
9005
9111
  }
9006
9112
  } catch (error) {
9007
- console.warn(`[Daemon] EP957: Failed to audit ${projectPath}:`, error);
9113
+ console.warn(`[Daemon] EP1035: Failed to audit ${projectPath}:`, error);
9008
9114
  }
9009
9115
  }
9010
9116
  /**