episoda 0.2.35 → 0.2.36

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.
@@ -397,6 +397,9 @@ var require_git_executor = __commonJS({
397
397
  return await this.executeWorktreeList(cwd, options);
398
398
  case "worktree_prune":
399
399
  return await this.executeWorktreePrune(cwd, options);
400
+ // EP1002: Worktree setup command for unified orchestration
401
+ case "worktree_setup":
402
+ return await this.executeWorktreeSetup(command, cwd, options);
400
403
  case "clone_bare":
401
404
  return await this.executeCloneBare(command, options);
402
405
  case "project_info":
@@ -1710,6 +1713,10 @@ var require_git_executor = __commonJS({
1710
1713
  args.push(command.path);
1711
1714
  const result = await this.runGitCommand(args, cwd, options);
1712
1715
  if (result.success) {
1716
+ try {
1717
+ await fs17.rm(command.path, { recursive: true, force: true });
1718
+ } catch {
1719
+ }
1713
1720
  return {
1714
1721
  success: true,
1715
1722
  output: `Removed worktree at ${command.path}`,
@@ -1823,6 +1830,18 @@ var require_git_executor = __commonJS({
1823
1830
  };
1824
1831
  }
1825
1832
  }
1833
+ /**
1834
+ * EP1002: Worktree setup command stub
1835
+ * The actual implementation is in the daemon which intercepts this command.
1836
+ * This stub exists for type checking and as a fallback.
1837
+ */
1838
+ async executeWorktreeSetup(command, cwd, options) {
1839
+ return {
1840
+ success: false,
1841
+ error: "NOT_IMPLEMENTED",
1842
+ output: "worktree_setup must be handled by the daemon, not GitExecutor"
1843
+ };
1844
+ }
1826
1845
  /**
1827
1846
  * EP944: Clone a repository as a bare repository
1828
1847
  * Used for worktree-based development setup
@@ -2593,6 +2612,9 @@ var require_errors = __commonJS({
2593
2612
  "WORKTREE_NOT_FOUND": "Worktree not found at this path",
2594
2613
  "WORKTREE_LOCKED": "Worktree is locked",
2595
2614
  "BRANCH_IN_USE": "Branch is already checked out in another worktree",
2615
+ // EP1002: Worktree setup error messages
2616
+ "NOT_IMPLEMENTED": "Command not implemented in this context",
2617
+ "SETUP_FAILED": "Worktree setup failed",
2596
2618
  "UNKNOWN_ERROR": "Unknown error occurred"
2597
2619
  };
2598
2620
  let message = messages[code] || `Error: ${code}`;
@@ -2699,7 +2721,7 @@ var require_package = __commonJS({
2699
2721
  "package.json"(exports2, module2) {
2700
2722
  module2.exports = {
2701
2723
  name: "episoda",
2702
- version: "0.2.34",
2724
+ version: "0.2.35",
2703
2725
  description: "CLI tool for Episoda local development workflow orchestration",
2704
2726
  main: "dist/index.js",
2705
2727
  types: "dist/index.d.ts",
@@ -6242,17 +6264,6 @@ async function getWorktreeInfoForModule(moduleUid) {
6242
6264
  }
6243
6265
  return getWorktreeInfo(moduleUid, config.workspace_slug, config.project_slug);
6244
6266
  }
6245
- async function getProjectRootPath() {
6246
- const config = await (0, import_core9.loadConfig)();
6247
- if (!config?.workspace_slug || !config?.project_slug) {
6248
- return null;
6249
- }
6250
- return path15.join(
6251
- getEpisodaRoot2(),
6252
- config.workspace_slug,
6253
- config.project_slug
6254
- );
6255
- }
6256
6267
 
6257
6268
  // src/utils/port-allocator.ts
6258
6269
  var PORT_RANGE_START = 3100;
@@ -6898,6 +6909,32 @@ var Daemon = class _Daemon {
6898
6909
  } else {
6899
6910
  console.log(`[Daemon] Running git command in bare repo: ${bareRepoPath}`);
6900
6911
  }
6912
+ if (gitCmd.action === "worktree_setup") {
6913
+ const wtManager = new WorktreeManager(projectPath);
6914
+ await wtManager.initialize();
6915
+ const SETUP_TIMEOUT_MS = 15 * 60 * 1e3;
6916
+ const setupPromise = this.handleWorktreeSetup(gitCmd, projectPath, wtManager);
6917
+ const timeoutPromise = new Promise(
6918
+ (_, reject) => setTimeout(() => reject(new Error("Worktree setup timed out after 15 minutes")), SETUP_TIMEOUT_MS)
6919
+ );
6920
+ let setupResult;
6921
+ try {
6922
+ setupResult = await Promise.race([setupPromise, timeoutPromise]);
6923
+ } catch (timeoutError) {
6924
+ setupResult = {
6925
+ success: false,
6926
+ error: "COMMAND_TIMEOUT",
6927
+ output: timeoutError instanceof Error ? timeoutError.message : "Setup timed out"
6928
+ };
6929
+ }
6930
+ await client.send({
6931
+ type: "result",
6932
+ commandId: message.id,
6933
+ result: setupResult
6934
+ });
6935
+ console.log(`[Daemon] EP1002: Worktree setup completed for ${gitCmd.moduleUid}:`, setupResult.success ? "success" : "failed");
6936
+ return;
6937
+ }
6901
6938
  const result = await gitExecutor.execute(gitCmd, {
6902
6939
  cwd
6903
6940
  });
@@ -7367,74 +7404,6 @@ var Daemon = class _Daemon {
7367
7404
  console.error(`[Daemon] EP956: Cannot resolve worktree path for ${moduleUid} (missing config slugs)`);
7368
7405
  return;
7369
7406
  }
7370
- if (!worktree.exists && startingWork) {
7371
- console.log(`[Daemon] EP959: Creating worktree for ${moduleUid} at ${worktree.path}`);
7372
- const projectRoot = await getProjectRootPath();
7373
- if (!projectRoot) {
7374
- console.error(`[Daemon] EP959: Cannot determine project root for worktree creation`);
7375
- return;
7376
- }
7377
- const worktreeManager = new WorktreeManager(projectRoot);
7378
- const initialized = await worktreeManager.initialize();
7379
- if (!initialized) {
7380
- console.error(`[Daemon] EP959: Failed to initialize WorktreeManager at ${projectRoot}`);
7381
- return;
7382
- }
7383
- const moduleBranchName = branchName || moduleUid;
7384
- const createResult = await worktreeManager.createWorktree(moduleUid, moduleBranchName, true);
7385
- if (!createResult.success) {
7386
- console.error(`[Daemon] EP959: Failed to create worktree for ${moduleUid}: ${createResult.error}`);
7387
- return;
7388
- }
7389
- console.log(`[Daemon] EP959: Worktree created for ${moduleUid} at ${createResult.worktreePath}`);
7390
- if (this.deviceId) {
7391
- try {
7392
- const ownershipConfig = await (0, import_core10.loadConfig)();
7393
- const ownershipApiUrl = ownershipConfig?.api_url || "https://episoda.dev";
7394
- const ownershipResponse = await fetchWithAuth(`${ownershipApiUrl}/api/modules/${moduleUid}`, {
7395
- method: "PATCH",
7396
- body: JSON.stringify({ checkout_machine_id: this.deviceId })
7397
- });
7398
- if (ownershipResponse.ok) {
7399
- console.log(`[Daemon] EP990: Claimed ownership of ${moduleUid} for device ${this.deviceId}`);
7400
- } else {
7401
- console.warn(`[Daemon] EP990: Failed to claim ownership of ${moduleUid}: ${ownershipResponse.status}`);
7402
- }
7403
- } catch (ownershipError) {
7404
- console.warn(`[Daemon] EP990: Error claiming ownership of ${moduleUid}:`, ownershipError);
7405
- }
7406
- }
7407
- worktree = await getWorktreeInfoForModule(moduleUid);
7408
- if (!worktree || !worktree.exists) {
7409
- console.error(`[Daemon] EP959: Worktree still not found after creation for ${moduleUid}`);
7410
- return;
7411
- }
7412
- const worktreeConfig = await (0, import_core10.loadConfig)();
7413
- const setupConfig = worktreeConfig?.project_settings;
7414
- const envVars = await fetchEnvVars2();
7415
- const hasEnvVars = Object.keys(envVars).length > 0;
7416
- const hasSetupConfig = setupConfig?.worktree_copy_files?.length || setupConfig?.worktree_setup_script || hasEnvVars;
7417
- {
7418
- console.log(`[Daemon] EP986: Starting async worktree setup for ${moduleUid}${hasSetupConfig ? " (with config)" : " (for dependency installation)"}`);
7419
- await worktreeManager.updateWorktreeStatus(moduleUid, "pending");
7420
- await this.updateModuleWorktreeStatus(moduleUid, "pending", worktree.path);
7421
- this.runWorktreeSetupAsync(
7422
- moduleUid,
7423
- worktreeManager,
7424
- setupConfig?.worktree_copy_files || [],
7425
- setupConfig?.worktree_setup_script,
7426
- worktree.path,
7427
- envVars
7428
- // EP973: Use server-fetched env vars
7429
- ).then(() => {
7430
- console.log(`[Daemon] EP959: Setup complete for ${moduleUid}, starting tunnel`);
7431
- this.startTunnelForModule(moduleUid, worktree.path);
7432
- }).catch((err) => {
7433
- console.error(`[Daemon] EP959: Setup failed for ${moduleUid}:`, err);
7434
- });
7435
- return;
7436
- }
7437
- }
7438
7407
  if (!worktree.exists) {
7439
7408
  console.log(`[Daemon] EP956: No worktree for ${moduleUid} at ${worktree.path}, skipping tunnel`);
7440
7409
  return;
@@ -7996,6 +7965,90 @@ var Daemon = class _Daemon {
7996
7965
  throw error;
7997
7966
  }
7998
7967
  }
7968
+ /**
7969
+ * EP1002: Handle worktree_setup command from server
7970
+ * This provides a unified setup flow for both local and cloud environments.
7971
+ * Server orchestrates, daemon executes.
7972
+ */
7973
+ async handleWorktreeSetup(command, projectPath, worktreeManager) {
7974
+ const { path: worktreePath, moduleUid } = command;
7975
+ console.log(`[Daemon] EP1002: Handling worktree_setup for ${moduleUid} at ${worktreePath}`);
7976
+ try {
7977
+ const envVars = await fetchEnvVars2();
7978
+ console.log(`[Daemon] EP1002: Fetched ${Object.keys(envVars).length} env vars for ${moduleUid}`);
7979
+ const config = await (0, import_core10.loadConfig)();
7980
+ const setupConfig = config?.project_settings;
7981
+ await this.runWorktreeSetupSync(
7982
+ moduleUid,
7983
+ worktreeManager,
7984
+ setupConfig?.worktree_copy_files || [],
7985
+ setupConfig?.worktree_setup_script,
7986
+ worktreePath,
7987
+ envVars
7988
+ );
7989
+ return {
7990
+ success: true,
7991
+ output: `Worktree setup completed for ${moduleUid}`,
7992
+ details: {
7993
+ moduleUid,
7994
+ worktreePath,
7995
+ envVarsCount: Object.keys(envVars).length
7996
+ }
7997
+ };
7998
+ } catch (error) {
7999
+ const errorMessage = error instanceof Error ? error.message : String(error);
8000
+ console.error(`[Daemon] EP1002: Worktree setup failed for ${moduleUid}:`, errorMessage);
8001
+ return {
8002
+ success: false,
8003
+ error: "SETUP_FAILED",
8004
+ output: errorMessage
8005
+ };
8006
+ }
8007
+ }
8008
+ /**
8009
+ * EP1002: Synchronous worktree setup for command-driven flow
8010
+ * Similar to runWorktreeSetupAsync but runs synchronously for server orchestration
8011
+ */
8012
+ async runWorktreeSetupSync(moduleUid, worktreeManager, copyFiles, setupScript, worktreePath, envVars = {}) {
8013
+ console.log(`[Daemon] EP1002: Running worktree setup for ${moduleUid}`);
8014
+ await worktreeManager.updateWorktreeStatus(moduleUid, "running");
8015
+ await this.updateModuleWorktreeStatus(moduleUid, "setup", worktreePath);
8016
+ if (Object.keys(envVars).length > 0) {
8017
+ console.log(`[Daemon] EP1002: Writing .env with ${Object.keys(envVars).length} variables`);
8018
+ writeEnvFile(worktreePath, envVars);
8019
+ }
8020
+ const installCmd = getInstallCommand(worktreePath);
8021
+ if (installCmd) {
8022
+ console.log(`[Daemon] EP1002: ${installCmd.description} (detected from ${installCmd.detectedFrom})`);
8023
+ console.log(`[Daemon] EP1002: Running: ${installCmd.command.join(" ")}`);
8024
+ try {
8025
+ const { execSync: execSync7 } = await import("child_process");
8026
+ execSync7(installCmd.command.join(" "), {
8027
+ cwd: worktreePath,
8028
+ stdio: "inherit",
8029
+ timeout: 10 * 60 * 1e3,
8030
+ // 10 minute timeout
8031
+ env: { ...process.env, CI: "true" }
8032
+ });
8033
+ console.log(`[Daemon] EP1002: Dependencies installed successfully`);
8034
+ } catch (installError) {
8035
+ const errorMsg = installError instanceof Error ? installError.message : String(installError);
8036
+ console.warn(`[Daemon] EP1002: Dependency installation failed (non-fatal): ${errorMsg}`);
8037
+ }
8038
+ } else {
8039
+ console.log(`[Daemon] EP1002: No package manager detected, skipping dependency installation`);
8040
+ }
8041
+ if (setupScript) {
8042
+ console.log(`[Daemon] EP1002: Running setup script`);
8043
+ const scriptResult = await worktreeManager.runSetupScript(moduleUid, setupScript);
8044
+ if (!scriptResult.success) {
8045
+ throw new Error(`Setup script failed: ${scriptResult.error}`);
8046
+ }
8047
+ }
8048
+ await worktreeManager.updateWorktreeStatus(moduleUid, "ready");
8049
+ await this.updateModuleWorktreeStatus(moduleUid, "ready", worktreePath);
8050
+ console.log(`[Daemon] EP1002: Worktree setup complete for ${moduleUid}`);
8051
+ }
7999
8052
  /**
8000
8053
  * EP959-11: Run worktree setup asynchronously
8001
8054
  * EP964: Added envVars parameter to inject .env file