episoda 0.2.61 → 0.2.63

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.61",
2729
+ version: "0.2.63",
2730
2730
  description: "CLI tool for Episoda local development workflow orchestration",
2731
2731
  main: "dist/index.js",
2732
2732
  types: "dist/index.d.ts",
@@ -7091,23 +7091,40 @@ var WorktreeManager = class _WorktreeManager {
7091
7091
  /**
7092
7092
  * Initialize worktree manager from existing project root
7093
7093
  * EP971: All projects use worktree architecture
7094
+ * EP1093: Added debug logging for cloud container diagnostics
7094
7095
  * @returns true if valid project, false otherwise
7095
7096
  */
7096
7097
  async initialize() {
7098
+ const debug = process.env.EPISODA_DEBUG === "1" || process.env.GIT_CREDENTIAL_EPISODA_DEBUG === "1";
7097
7099
  if (!fs15.existsSync(this.bareRepoPath)) {
7100
+ if (debug) {
7101
+ console.log(`[WorktreeManager] initialize: .bare not found at ${this.bareRepoPath}`);
7102
+ }
7098
7103
  return false;
7099
7104
  }
7100
7105
  if (!fs15.existsSync(this.configPath)) {
7106
+ if (debug) {
7107
+ console.log(`[WorktreeManager] initialize: config not found at ${this.configPath}`);
7108
+ }
7101
7109
  return false;
7102
7110
  }
7103
7111
  try {
7104
7112
  const config = this.readConfig();
7105
7113
  if (config === null) {
7114
+ if (debug) {
7115
+ console.log(`[WorktreeManager] initialize: readConfig returned null`);
7116
+ }
7106
7117
  return false;
7107
7118
  }
7119
+ if (debug) {
7120
+ console.log(`[WorktreeManager] initialize: config loaded, projectId=${config.projectId}`);
7121
+ }
7108
7122
  await this.ensureFetchRefspecConfigured();
7109
7123
  return true;
7110
- } catch {
7124
+ } catch (error) {
7125
+ if (debug) {
7126
+ console.log(`[WorktreeManager] initialize: exception - ${error.message}`);
7127
+ }
7111
7128
  return false;
7112
7129
  }
7113
7130
  }
@@ -7242,6 +7259,7 @@ var WorktreeManager = class _WorktreeManager {
7242
7259
  /**
7243
7260
  * Remove a worktree for a module
7244
7261
  * P1-2: Wrapped entire operation in lock to prevent race with createWorktree
7262
+ * EP1070: Clean build caches before git worktree remove to prevent orphaned directories
7245
7263
  */
7246
7264
  async removeWorktree(moduleUid, force = false) {
7247
7265
  if (!validateModuleUid(moduleUid)) {
@@ -7265,6 +7283,7 @@ var WorktreeManager = class _WorktreeManager {
7265
7283
  error: `No worktree found for module ${moduleUid}`
7266
7284
  };
7267
7285
  }
7286
+ await this.cleanBuildCaches(existing.worktreePath);
7268
7287
  const result = await this.gitExecutor.execute({
7269
7288
  action: "worktree_remove",
7270
7289
  path: existing.worktreePath,
@@ -7489,6 +7508,37 @@ var WorktreeManager = class _WorktreeManager {
7489
7508
  } catch {
7490
7509
  }
7491
7510
  }
7511
+ /**
7512
+ * EP1070: Clean build caches before worktree removal
7513
+ *
7514
+ * Removes common build cache directories that can cause:
7515
+ * 1. git worktree remove to fail (locked files on Windows)
7516
+ * 2. Orphaned directories if removal partially fails
7517
+ * 3. Disk space waste from abandoned build artifacts
7518
+ *
7519
+ * @param worktreePath - Absolute path to the worktree directory
7520
+ */
7521
+ async cleanBuildCaches(worktreePath) {
7522
+ const cacheDirs = [
7523
+ ".next",
7524
+ // Next.js build cache
7525
+ "node_modules/.cache",
7526
+ // Various build tool caches (babel, eslint, etc.)
7527
+ ".turbo"
7528
+ // Turborepo cache
7529
+ ];
7530
+ for (const cacheDir of cacheDirs) {
7531
+ const cachePath = path16.join(worktreePath, cacheDir);
7532
+ try {
7533
+ if (fs15.existsSync(cachePath)) {
7534
+ console.log(`[WorktreeManager] EP1070: Cleaning build cache: ${cacheDir}`);
7535
+ fs15.rmSync(cachePath, { recursive: true, force: true });
7536
+ }
7537
+ } catch (error) {
7538
+ console.warn(`[WorktreeManager] EP1070: Failed to clean ${cacheDir} (non-blocking):`, error.message);
7539
+ }
7540
+ }
7541
+ }
7492
7542
  readConfig() {
7493
7543
  try {
7494
7544
  if (!fs15.existsSync(this.configPath)) {
@@ -7686,20 +7736,43 @@ function getEpisodaRoot() {
7686
7736
  return process.env.EPISODA_ROOT || path16.join(require("os").homedir(), "episoda");
7687
7737
  }
7688
7738
  async function isWorktreeProject(projectRoot) {
7739
+ const debug = process.env.EPISODA_DEBUG === "1" || process.env.GIT_CREDENTIAL_EPISODA_DEBUG === "1";
7740
+ if (debug) {
7741
+ console.log(`[WorktreeManager] isWorktreeProject: checking ${projectRoot}`);
7742
+ }
7689
7743
  const manager = new WorktreeManager(projectRoot);
7690
- return manager.initialize();
7744
+ const result = await manager.initialize();
7745
+ if (debug) {
7746
+ console.log(`[WorktreeManager] isWorktreeProject: ${projectRoot} -> ${result}`);
7747
+ }
7748
+ return result;
7691
7749
  }
7692
7750
  async function findProjectRoot(startPath) {
7693
7751
  let current = path16.resolve(startPath);
7694
7752
  const episodaRoot = getEpisodaRoot();
7753
+ const debug = process.env.EPISODA_DEBUG === "1" || process.env.GIT_CREDENTIAL_EPISODA_DEBUG === "1";
7754
+ if (debug) {
7755
+ console.log(`[WorktreeManager] findProjectRoot: start=${startPath}, episodaRoot=${episodaRoot}`);
7756
+ }
7695
7757
  if (!current.startsWith(episodaRoot)) {
7758
+ if (debug) {
7759
+ console.log(`[WorktreeManager] findProjectRoot: ${current} is not under ${episodaRoot}`);
7760
+ }
7696
7761
  return null;
7697
7762
  }
7698
7763
  for (let i = 0; i < 10; i++) {
7699
7764
  const bareDir = path16.join(current, ".bare");
7700
7765
  const episodaDir = path16.join(current, ".episoda");
7766
+ if (debug) {
7767
+ const bareExists = fs15.existsSync(bareDir);
7768
+ const episodaExists = fs15.existsSync(episodaDir);
7769
+ console.log(`[WorktreeManager] findProjectRoot: checking ${current} (.bare=${bareExists}, .episoda=${episodaExists})`);
7770
+ }
7701
7771
  if (fs15.existsSync(bareDir) && fs15.existsSync(episodaDir)) {
7702
7772
  if (await isWorktreeProject(current)) {
7773
+ if (debug) {
7774
+ console.log(`[WorktreeManager] findProjectRoot: found valid project at ${current}`);
7775
+ }
7703
7776
  return current;
7704
7777
  }
7705
7778
  }
@@ -7709,6 +7782,9 @@ async function findProjectRoot(startPath) {
7709
7782
  }
7710
7783
  current = parent;
7711
7784
  }
7785
+ if (debug) {
7786
+ console.log(`[WorktreeManager] findProjectRoot: no project found`);
7787
+ }
7712
7788
  return null;
7713
7789
  }
7714
7790