episoda 0.2.24 → 0.2.26

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.
@@ -1556,15 +1556,15 @@ var require_git_executor = __commonJS({
1556
1556
  try {
1557
1557
  const { stdout: gitDir } = await execAsync2("git rev-parse --git-dir", { cwd, timeout: 5e3 });
1558
1558
  const gitDirPath = gitDir.trim();
1559
- const fs14 = await Promise.resolve().then(() => __importStar(require("fs"))).then((m) => m.promises);
1559
+ const fs15 = await Promise.resolve().then(() => __importStar(require("fs"))).then((m) => m.promises);
1560
1560
  const rebaseMergePath = `${gitDirPath}/rebase-merge`;
1561
1561
  const rebaseApplyPath = `${gitDirPath}/rebase-apply`;
1562
1562
  try {
1563
- await fs14.access(rebaseMergePath);
1563
+ await fs15.access(rebaseMergePath);
1564
1564
  inRebase = true;
1565
1565
  } catch {
1566
1566
  try {
1567
- await fs14.access(rebaseApplyPath);
1567
+ await fs15.access(rebaseApplyPath);
1568
1568
  inRebase = true;
1569
1569
  } catch {
1570
1570
  inRebase = false;
@@ -1618,9 +1618,9 @@ var require_git_executor = __commonJS({
1618
1618
  error: validation.error || "UNKNOWN_ERROR"
1619
1619
  };
1620
1620
  }
1621
- const fs14 = await Promise.resolve().then(() => __importStar(require("fs"))).then((m) => m.promises);
1621
+ const fs15 = await Promise.resolve().then(() => __importStar(require("fs"))).then((m) => m.promises);
1622
1622
  try {
1623
- await fs14.access(command.path);
1623
+ await fs15.access(command.path);
1624
1624
  return {
1625
1625
  success: false,
1626
1626
  error: "WORKTREE_EXISTS",
@@ -1671,9 +1671,9 @@ var require_git_executor = __commonJS({
1671
1671
  */
1672
1672
  async executeWorktreeRemove(command, cwd, options) {
1673
1673
  try {
1674
- const fs14 = await Promise.resolve().then(() => __importStar(require("fs"))).then((m) => m.promises);
1674
+ const fs15 = await Promise.resolve().then(() => __importStar(require("fs"))).then((m) => m.promises);
1675
1675
  try {
1676
- await fs14.access(command.path);
1676
+ await fs15.access(command.path);
1677
1677
  } catch {
1678
1678
  return {
1679
1679
  success: false,
@@ -1826,10 +1826,10 @@ var require_git_executor = __commonJS({
1826
1826
  */
1827
1827
  async executeCloneBare(command, options) {
1828
1828
  try {
1829
- const fs14 = await Promise.resolve().then(() => __importStar(require("fs"))).then((m) => m.promises);
1830
- const path15 = await Promise.resolve().then(() => __importStar(require("path")));
1829
+ const fs15 = await Promise.resolve().then(() => __importStar(require("fs"))).then((m) => m.promises);
1830
+ const path16 = await Promise.resolve().then(() => __importStar(require("path")));
1831
1831
  try {
1832
- await fs14.access(command.path);
1832
+ await fs15.access(command.path);
1833
1833
  return {
1834
1834
  success: false,
1835
1835
  error: "BRANCH_ALREADY_EXISTS",
@@ -1838,9 +1838,9 @@ var require_git_executor = __commonJS({
1838
1838
  };
1839
1839
  } catch {
1840
1840
  }
1841
- const parentDir = path15.dirname(command.path);
1841
+ const parentDir = path16.dirname(command.path);
1842
1842
  try {
1843
- await fs14.mkdir(parentDir, { recursive: true });
1843
+ await fs15.mkdir(parentDir, { recursive: true });
1844
1844
  } catch {
1845
1845
  }
1846
1846
  const { stdout, stderr } = await execAsync2(
@@ -1883,22 +1883,22 @@ var require_git_executor = __commonJS({
1883
1883
  */
1884
1884
  async executeProjectInfo(cwd, options) {
1885
1885
  try {
1886
- const fs14 = await Promise.resolve().then(() => __importStar(require("fs"))).then((m) => m.promises);
1887
- const path15 = await Promise.resolve().then(() => __importStar(require("path")));
1886
+ const fs15 = await Promise.resolve().then(() => __importStar(require("fs"))).then((m) => m.promises);
1887
+ const path16 = await Promise.resolve().then(() => __importStar(require("path")));
1888
1888
  let currentPath = cwd;
1889
1889
  let projectPath = cwd;
1890
1890
  let bareRepoPath;
1891
1891
  for (let i = 0; i < 10; i++) {
1892
- const bareDir = path15.join(currentPath, ".bare");
1893
- const episodaDir = path15.join(currentPath, ".episoda");
1892
+ const bareDir = path16.join(currentPath, ".bare");
1893
+ const episodaDir = path16.join(currentPath, ".episoda");
1894
1894
  try {
1895
- await fs14.access(bareDir);
1896
- await fs14.access(episodaDir);
1895
+ await fs15.access(bareDir);
1896
+ await fs15.access(episodaDir);
1897
1897
  projectPath = currentPath;
1898
1898
  bareRepoPath = bareDir;
1899
1899
  break;
1900
1900
  } catch {
1901
- const parentPath = path15.dirname(currentPath);
1901
+ const parentPath = path16.dirname(currentPath);
1902
1902
  if (parentPath === currentPath) {
1903
1903
  break;
1904
1904
  }
@@ -2492,31 +2492,31 @@ var require_auth = __commonJS({
2492
2492
  exports2.loadConfig = loadConfig5;
2493
2493
  exports2.saveConfig = saveConfig2;
2494
2494
  exports2.validateToken = validateToken;
2495
- var fs14 = __importStar(require("fs"));
2496
- var path15 = __importStar(require("path"));
2495
+ var fs15 = __importStar(require("fs"));
2496
+ var path16 = __importStar(require("path"));
2497
2497
  var os6 = __importStar(require("os"));
2498
2498
  var child_process_1 = require("child_process");
2499
2499
  var DEFAULT_CONFIG_FILE = "config.json";
2500
2500
  function getConfigDir6() {
2501
- return process.env.EPISODA_CONFIG_DIR || path15.join(os6.homedir(), ".episoda");
2501
+ return process.env.EPISODA_CONFIG_DIR || path16.join(os6.homedir(), ".episoda");
2502
2502
  }
2503
2503
  function getConfigPath(configPath) {
2504
2504
  if (configPath) {
2505
2505
  return configPath;
2506
2506
  }
2507
- return path15.join(getConfigDir6(), DEFAULT_CONFIG_FILE);
2507
+ return path16.join(getConfigDir6(), DEFAULT_CONFIG_FILE);
2508
2508
  }
2509
2509
  function ensureConfigDir(configPath) {
2510
- const dir = path15.dirname(configPath);
2511
- const isNew = !fs14.existsSync(dir);
2510
+ const dir = path16.dirname(configPath);
2511
+ const isNew = !fs15.existsSync(dir);
2512
2512
  if (isNew) {
2513
- fs14.mkdirSync(dir, { recursive: true, mode: 448 });
2513
+ fs15.mkdirSync(dir, { recursive: true, mode: 448 });
2514
2514
  }
2515
2515
  if (process.platform === "darwin") {
2516
- const nosyncPath = path15.join(dir, ".nosync");
2517
- if (isNew || !fs14.existsSync(nosyncPath)) {
2516
+ const nosyncPath = path16.join(dir, ".nosync");
2517
+ if (isNew || !fs15.existsSync(nosyncPath)) {
2518
2518
  try {
2519
- fs14.writeFileSync(nosyncPath, "", { mode: 384 });
2519
+ fs15.writeFileSync(nosyncPath, "", { mode: 384 });
2520
2520
  (0, child_process_1.execSync)(`xattr -w com.apple.fileprovider.ignore 1 "${dir}"`, {
2521
2521
  stdio: "ignore",
2522
2522
  timeout: 5e3
@@ -2528,11 +2528,11 @@ var require_auth = __commonJS({
2528
2528
  }
2529
2529
  async function loadConfig5(configPath) {
2530
2530
  const fullPath = getConfigPath(configPath);
2531
- if (!fs14.existsSync(fullPath)) {
2531
+ if (!fs15.existsSync(fullPath)) {
2532
2532
  return null;
2533
2533
  }
2534
2534
  try {
2535
- const content = fs14.readFileSync(fullPath, "utf8");
2535
+ const content = fs15.readFileSync(fullPath, "utf8");
2536
2536
  const config = JSON.parse(content);
2537
2537
  return config;
2538
2538
  } catch (error) {
@@ -2545,7 +2545,7 @@ var require_auth = __commonJS({
2545
2545
  ensureConfigDir(fullPath);
2546
2546
  try {
2547
2547
  const content = JSON.stringify(config, null, 2);
2548
- fs14.writeFileSync(fullPath, content, { mode: 384 });
2548
+ fs15.writeFileSync(fullPath, content, { mode: 384 });
2549
2549
  } catch (error) {
2550
2550
  throw new Error(`Failed to save config: ${error instanceof Error ? error.message : String(error)}`);
2551
2551
  }
@@ -2696,7 +2696,7 @@ var require_package = __commonJS({
2696
2696
  "package.json"(exports2, module2) {
2697
2697
  module2.exports = {
2698
2698
  name: "episoda",
2699
- version: "0.2.23",
2699
+ version: "0.2.25",
2700
2700
  description: "CLI tool for Episoda local development workflow orchestration",
2701
2701
  main: "dist/index.js",
2702
2702
  types: "dist/index.d.ts",
@@ -6102,10 +6102,105 @@ function clearAllPorts() {
6102
6102
  }
6103
6103
  }
6104
6104
 
6105
- // src/daemon/daemon-process.ts
6105
+ // src/framework-detector.ts
6106
6106
  var fs13 = __toESM(require("fs"));
6107
- var os5 = __toESM(require("os"));
6108
6107
  var path14 = __toESM(require("path"));
6108
+ function getInstallCommand(cwd) {
6109
+ if (fs13.existsSync(path14.join(cwd, "bun.lockb"))) {
6110
+ return {
6111
+ command: ["bun", "install"],
6112
+ description: "Installing dependencies with bun",
6113
+ detectedFrom: "bun.lockb"
6114
+ };
6115
+ }
6116
+ if (fs13.existsSync(path14.join(cwd, "pnpm-lock.yaml"))) {
6117
+ return {
6118
+ command: ["pnpm", "install"],
6119
+ description: "Installing dependencies with pnpm",
6120
+ detectedFrom: "pnpm-lock.yaml"
6121
+ };
6122
+ }
6123
+ if (fs13.existsSync(path14.join(cwd, "yarn.lock"))) {
6124
+ return {
6125
+ command: ["yarn", "install"],
6126
+ description: "Installing dependencies with yarn",
6127
+ detectedFrom: "yarn.lock"
6128
+ };
6129
+ }
6130
+ if (fs13.existsSync(path14.join(cwd, "package-lock.json"))) {
6131
+ return {
6132
+ command: ["npm", "ci"],
6133
+ description: "Installing dependencies with npm ci",
6134
+ detectedFrom: "package-lock.json"
6135
+ };
6136
+ }
6137
+ if (fs13.existsSync(path14.join(cwd, "package.json"))) {
6138
+ return {
6139
+ command: ["npm", "install"],
6140
+ description: "Installing dependencies with npm",
6141
+ detectedFrom: "package.json"
6142
+ };
6143
+ }
6144
+ if (fs13.existsSync(path14.join(cwd, "Pipfile.lock")) || fs13.existsSync(path14.join(cwd, "Pipfile"))) {
6145
+ return {
6146
+ command: ["pipenv", "install"],
6147
+ description: "Installing dependencies with pipenv",
6148
+ detectedFrom: fs13.existsSync(path14.join(cwd, "Pipfile.lock")) ? "Pipfile.lock" : "Pipfile"
6149
+ };
6150
+ }
6151
+ if (fs13.existsSync(path14.join(cwd, "poetry.lock"))) {
6152
+ return {
6153
+ command: ["poetry", "install"],
6154
+ description: "Installing dependencies with poetry",
6155
+ detectedFrom: "poetry.lock"
6156
+ };
6157
+ }
6158
+ if (fs13.existsSync(path14.join(cwd, "pyproject.toml"))) {
6159
+ const pyprojectPath = path14.join(cwd, "pyproject.toml");
6160
+ const content = fs13.readFileSync(pyprojectPath, "utf-8");
6161
+ if (content.includes("[tool.poetry]")) {
6162
+ return {
6163
+ command: ["poetry", "install"],
6164
+ description: "Installing dependencies with poetry",
6165
+ detectedFrom: "pyproject.toml"
6166
+ };
6167
+ }
6168
+ }
6169
+ if (fs13.existsSync(path14.join(cwd, "requirements.txt"))) {
6170
+ return {
6171
+ command: ["pip", "install", "-r", "requirements.txt"],
6172
+ description: "Installing dependencies with pip",
6173
+ detectedFrom: "requirements.txt"
6174
+ };
6175
+ }
6176
+ if (fs13.existsSync(path14.join(cwd, "Gemfile.lock")) || fs13.existsSync(path14.join(cwd, "Gemfile"))) {
6177
+ return {
6178
+ command: ["bundle", "install"],
6179
+ description: "Installing dependencies with bundler",
6180
+ detectedFrom: fs13.existsSync(path14.join(cwd, "Gemfile.lock")) ? "Gemfile.lock" : "Gemfile"
6181
+ };
6182
+ }
6183
+ if (fs13.existsSync(path14.join(cwd, "go.sum")) || fs13.existsSync(path14.join(cwd, "go.mod"))) {
6184
+ return {
6185
+ command: ["go", "mod", "download"],
6186
+ description: "Downloading Go modules",
6187
+ detectedFrom: fs13.existsSync(path14.join(cwd, "go.sum")) ? "go.sum" : "go.mod"
6188
+ };
6189
+ }
6190
+ if (fs13.existsSync(path14.join(cwd, "Cargo.lock")) || fs13.existsSync(path14.join(cwd, "Cargo.toml"))) {
6191
+ return {
6192
+ command: ["cargo", "build"],
6193
+ description: "Building Rust project (downloads dependencies)",
6194
+ detectedFrom: fs13.existsSync(path14.join(cwd, "Cargo.lock")) ? "Cargo.lock" : "Cargo.toml"
6195
+ };
6196
+ }
6197
+ return null;
6198
+ }
6199
+
6200
+ // src/daemon/daemon-process.ts
6201
+ var fs14 = __toESM(require("fs"));
6202
+ var os5 = __toESM(require("os"));
6203
+ var path15 = __toESM(require("path"));
6109
6204
  var packageJson = require_package();
6110
6205
  async function ensureValidToken(config, bufferMs = 5 * 60 * 1e3) {
6111
6206
  const now = Date.now();
@@ -6602,7 +6697,7 @@ var Daemon = class _Daemon {
6602
6697
  client.updateActivity();
6603
6698
  try {
6604
6699
  const gitCmd = message.command;
6605
- const bareRepoPath = path14.join(projectPath, ".bare");
6700
+ const bareRepoPath = path15.join(projectPath, ".bare");
6606
6701
  const cwd = gitCmd.worktreePath || bareRepoPath;
6607
6702
  if (gitCmd.worktreePath) {
6608
6703
  console.log(`[Daemon] Routing command to worktree: ${gitCmd.worktreePath}`);
@@ -7101,8 +7196,9 @@ var Daemon = class _Daemon {
7101
7196
  const setupConfig = worktreeConfig?.project_settings;
7102
7197
  const envVars = await fetchEnvVars();
7103
7198
  const hasEnvVars = Object.keys(envVars).length > 0;
7104
- if (setupConfig?.worktree_copy_files?.length || setupConfig?.worktree_setup_script || hasEnvVars) {
7105
- console.log(`[Daemon] EP959: Starting async worktree setup for ${moduleUid}`);
7199
+ const hasSetupConfig = setupConfig?.worktree_copy_files?.length || setupConfig?.worktree_setup_script || hasEnvVars;
7200
+ {
7201
+ console.log(`[Daemon] EP986: Starting async worktree setup for ${moduleUid}${hasSetupConfig ? " (with config)" : " (for dependency installation)"}`);
7106
7202
  await worktreeManager.updateWorktreeStatus(moduleUid, "pending");
7107
7203
  this.runWorktreeSetupAsync(
7108
7204
  moduleUid,
@@ -7111,6 +7207,7 @@ var Daemon = class _Daemon {
7111
7207
  setupConfig?.worktree_setup_script,
7112
7208
  worktree.path,
7113
7209
  envVars
7210
+ // EP973: Use server-fetched env vars
7114
7211
  ).then(() => {
7115
7212
  console.log(`[Daemon] EP959: Setup complete for ${moduleUid}, starting tunnel`);
7116
7213
  this.startTunnelForModule(moduleUid, worktree.path);
@@ -7119,7 +7216,8 @@ var Daemon = class _Daemon {
7119
7216
  });
7120
7217
  return;
7121
7218
  }
7122
- } else if (!worktree.exists) {
7219
+ }
7220
+ if (!worktree.exists) {
7123
7221
  console.log(`[Daemon] EP956: No worktree for ${moduleUid} at ${worktree.path}, skipping tunnel`);
7124
7222
  return;
7125
7223
  }
@@ -7209,8 +7307,8 @@ var Daemon = class _Daemon {
7209
7307
  let daemonPid;
7210
7308
  try {
7211
7309
  const pidPath = getPidFilePath();
7212
- if (fs13.existsSync(pidPath)) {
7213
- const pidStr = fs13.readFileSync(pidPath, "utf-8").trim();
7310
+ if (fs14.existsSync(pidPath)) {
7311
+ const pidStr = fs14.readFileSync(pidPath, "utf-8").trim();
7214
7312
  daemonPid = parseInt(pidStr, 10);
7215
7313
  }
7216
7314
  } catch (pidError) {
@@ -7331,27 +7429,27 @@ var Daemon = class _Daemon {
7331
7429
  */
7332
7430
  async installGitHooks(projectPath) {
7333
7431
  const hooks = ["post-checkout", "pre-commit", "post-commit"];
7334
- const hooksDir = path14.join(projectPath, ".git", "hooks");
7335
- if (!fs13.existsSync(hooksDir)) {
7432
+ const hooksDir = path15.join(projectPath, ".git", "hooks");
7433
+ if (!fs14.existsSync(hooksDir)) {
7336
7434
  console.warn(`[Daemon] Hooks directory not found: ${hooksDir}`);
7337
7435
  return;
7338
7436
  }
7339
7437
  for (const hookName of hooks) {
7340
7438
  try {
7341
- const hookPath = path14.join(hooksDir, hookName);
7342
- const bundledHookPath = path14.join(__dirname, "..", "hooks", hookName);
7343
- if (!fs13.existsSync(bundledHookPath)) {
7439
+ const hookPath = path15.join(hooksDir, hookName);
7440
+ const bundledHookPath = path15.join(__dirname, "..", "hooks", hookName);
7441
+ if (!fs14.existsSync(bundledHookPath)) {
7344
7442
  console.warn(`[Daemon] Bundled hook not found: ${bundledHookPath}`);
7345
7443
  continue;
7346
7444
  }
7347
- const hookContent = fs13.readFileSync(bundledHookPath, "utf-8");
7348
- if (fs13.existsSync(hookPath)) {
7349
- const existingContent = fs13.readFileSync(hookPath, "utf-8");
7445
+ const hookContent = fs14.readFileSync(bundledHookPath, "utf-8");
7446
+ if (fs14.existsSync(hookPath)) {
7447
+ const existingContent = fs14.readFileSync(hookPath, "utf-8");
7350
7448
  if (existingContent === hookContent) {
7351
7449
  continue;
7352
7450
  }
7353
7451
  }
7354
- fs13.writeFileSync(hookPath, hookContent, { mode: 493 });
7452
+ fs14.writeFileSync(hookPath, hookContent, { mode: 493 });
7355
7453
  console.log(`[Daemon] Installed git hook: ${hookName}`);
7356
7454
  } catch (error) {
7357
7455
  console.warn(`[Daemon] Failed to install ${hookName} hook:`, error instanceof Error ? error.message : error);
@@ -7479,8 +7577,8 @@ var Daemon = class _Daemon {
7479
7577
  }
7480
7578
  return `${key}=${value}`;
7481
7579
  }).join("\n") + "\n";
7482
- const envPath = path14.join(worktreePath, ".env");
7483
- fs13.writeFileSync(envPath, envContent, { mode: 384 });
7580
+ const envPath = path15.join(worktreePath, ".env");
7581
+ fs14.writeFileSync(envPath, envContent, { mode: 384 });
7484
7582
  console.log(`[Daemon] EP964: .env written to ${envPath}`);
7485
7583
  }
7486
7584
  if (copyFiles.length > 0) {
@@ -7491,6 +7589,29 @@ var Daemon = class _Daemon {
7491
7589
  console.warn(`[Daemon] EP964: File copy failed (non-fatal): ${copyResult.error}`);
7492
7590
  }
7493
7591
  }
7592
+ const installCmd = getInstallCommand(worktreePath);
7593
+ if (installCmd) {
7594
+ console.log(`[Daemon] EP986: ${installCmd.description} (detected from ${installCmd.detectedFrom})`);
7595
+ console.log(`[Daemon] EP986: Running: ${installCmd.command.join(" ")}`);
7596
+ try {
7597
+ const { execSync: execSync6 } = await import("child_process");
7598
+ execSync6(installCmd.command.join(" "), {
7599
+ cwd: worktreePath,
7600
+ stdio: "inherit",
7601
+ timeout: 10 * 60 * 1e3,
7602
+ // 10 minute timeout
7603
+ env: { ...process.env, CI: "true" }
7604
+ // CI=true for cleaner output
7605
+ });
7606
+ console.log(`[Daemon] EP986: Dependencies installed successfully for ${moduleUid}`);
7607
+ } catch (installError) {
7608
+ const errorMsg = installError instanceof Error ? installError.message : String(installError);
7609
+ console.warn(`[Daemon] EP986: Dependency installation failed (non-fatal): ${errorMsg}`);
7610
+ console.warn(`[Daemon] EP986: You may need to run '${installCmd.command.join(" ")}' manually`);
7611
+ }
7612
+ } else {
7613
+ console.log(`[Daemon] EP986: No package manager detected for ${moduleUid}, skipping dependency installation`);
7614
+ }
7494
7615
  if (setupScript) {
7495
7616
  console.log(`[Daemon] EP959: Running setup script for ${moduleUid}`);
7496
7617
  const scriptResult = await worktreeManager.runSetupScript(moduleUid, setupScript);
@@ -8233,8 +8354,8 @@ var Daemon = class _Daemon {
8233
8354
  await this.shutdown();
8234
8355
  try {
8235
8356
  const pidPath = getPidFilePath();
8236
- if (fs13.existsSync(pidPath)) {
8237
- fs13.unlinkSync(pidPath);
8357
+ if (fs14.existsSync(pidPath)) {
8358
+ fs14.unlinkSync(pidPath);
8238
8359
  console.log("[Daemon] PID file cleaned up");
8239
8360
  }
8240
8361
  } catch (error) {