episoda 0.2.106 → 0.2.107

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.
@@ -1571,15 +1571,15 @@ var require_git_executor = __commonJS({
1571
1571
  try {
1572
1572
  const { stdout: gitDir } = await execAsync3("git rev-parse --git-dir", { cwd, timeout: 5e3 });
1573
1573
  const gitDirPath = gitDir.trim();
1574
- const fs23 = await Promise.resolve().then(() => __importStar(require("fs"))).then((m) => m.promises);
1574
+ const fs24 = await Promise.resolve().then(() => __importStar(require("fs"))).then((m) => m.promises);
1575
1575
  const rebaseMergePath = `${gitDirPath}/rebase-merge`;
1576
1576
  const rebaseApplyPath = `${gitDirPath}/rebase-apply`;
1577
1577
  try {
1578
- await fs23.access(rebaseMergePath);
1578
+ await fs24.access(rebaseMergePath);
1579
1579
  inRebase = true;
1580
1580
  } catch {
1581
1581
  try {
1582
- await fs23.access(rebaseApplyPath);
1582
+ await fs24.access(rebaseApplyPath);
1583
1583
  inRebase = true;
1584
1584
  } catch {
1585
1585
  inRebase = false;
@@ -1633,9 +1633,9 @@ var require_git_executor = __commonJS({
1633
1633
  error: validation.error || "UNKNOWN_ERROR"
1634
1634
  };
1635
1635
  }
1636
- const fs23 = await Promise.resolve().then(() => __importStar(require("fs"))).then((m) => m.promises);
1636
+ const fs24 = await Promise.resolve().then(() => __importStar(require("fs"))).then((m) => m.promises);
1637
1637
  try {
1638
- await fs23.access(command.path);
1638
+ await fs24.access(command.path);
1639
1639
  return {
1640
1640
  success: false,
1641
1641
  error: "WORKTREE_EXISTS",
@@ -1689,9 +1689,9 @@ var require_git_executor = __commonJS({
1689
1689
  */
1690
1690
  async executeWorktreeRemove(command, cwd, options) {
1691
1691
  try {
1692
- const fs23 = await Promise.resolve().then(() => __importStar(require("fs"))).then((m) => m.promises);
1692
+ const fs24 = await Promise.resolve().then(() => __importStar(require("fs"))).then((m) => m.promises);
1693
1693
  try {
1694
- await fs23.access(command.path);
1694
+ await fs24.access(command.path);
1695
1695
  } catch {
1696
1696
  return {
1697
1697
  success: false,
@@ -1726,7 +1726,7 @@ var require_git_executor = __commonJS({
1726
1726
  const result = await this.runGitCommand(args, cwd, options);
1727
1727
  if (result.success) {
1728
1728
  try {
1729
- await fs23.rm(command.path, { recursive: true, force: true });
1729
+ await fs24.rm(command.path, { recursive: true, force: true });
1730
1730
  } catch {
1731
1731
  }
1732
1732
  return {
@@ -1860,10 +1860,10 @@ var require_git_executor = __commonJS({
1860
1860
  */
1861
1861
  async executeCloneBare(command, options) {
1862
1862
  try {
1863
- const fs23 = await Promise.resolve().then(() => __importStar(require("fs"))).then((m) => m.promises);
1864
- const path24 = await Promise.resolve().then(() => __importStar(require("path")));
1863
+ const fs24 = await Promise.resolve().then(() => __importStar(require("fs"))).then((m) => m.promises);
1864
+ const path25 = await Promise.resolve().then(() => __importStar(require("path")));
1865
1865
  try {
1866
- await fs23.access(command.path);
1866
+ await fs24.access(command.path);
1867
1867
  return {
1868
1868
  success: false,
1869
1869
  error: "BRANCH_ALREADY_EXISTS",
@@ -1872,9 +1872,9 @@ var require_git_executor = __commonJS({
1872
1872
  };
1873
1873
  } catch {
1874
1874
  }
1875
- const parentDir = path24.dirname(command.path);
1875
+ const parentDir = path25.dirname(command.path);
1876
1876
  try {
1877
- await fs23.mkdir(parentDir, { recursive: true });
1877
+ await fs24.mkdir(parentDir, { recursive: true });
1878
1878
  } catch {
1879
1879
  }
1880
1880
  const { stdout, stderr } = await execAsync3(
@@ -1922,22 +1922,22 @@ var require_git_executor = __commonJS({
1922
1922
  */
1923
1923
  async executeProjectInfo(cwd, options) {
1924
1924
  try {
1925
- const fs23 = await Promise.resolve().then(() => __importStar(require("fs"))).then((m) => m.promises);
1926
- const path24 = await Promise.resolve().then(() => __importStar(require("path")));
1925
+ const fs24 = await Promise.resolve().then(() => __importStar(require("fs"))).then((m) => m.promises);
1926
+ const path25 = await Promise.resolve().then(() => __importStar(require("path")));
1927
1927
  let currentPath = cwd;
1928
1928
  let projectPath = cwd;
1929
1929
  let bareRepoPath;
1930
1930
  for (let i = 0; i < 10; i++) {
1931
- const bareDir = path24.join(currentPath, ".bare");
1932
- const episodaDir = path24.join(currentPath, ".episoda");
1931
+ const bareDir = path25.join(currentPath, ".bare");
1932
+ const episodaDir = path25.join(currentPath, ".episoda");
1933
1933
  try {
1934
- await fs23.access(bareDir);
1935
- await fs23.access(episodaDir);
1934
+ await fs24.access(bareDir);
1935
+ await fs24.access(episodaDir);
1936
1936
  projectPath = currentPath;
1937
1937
  bareRepoPath = bareDir;
1938
1938
  break;
1939
1939
  } catch {
1940
- const parentPath = path24.dirname(currentPath);
1940
+ const parentPath = path25.dirname(currentPath);
1941
1941
  if (parentPath === currentPath) {
1942
1942
  break;
1943
1943
  }
@@ -2590,31 +2590,31 @@ var require_auth = __commonJS({
2590
2590
  exports2.loadConfig = loadConfig8;
2591
2591
  exports2.saveConfig = saveConfig2;
2592
2592
  exports2.validateToken = validateToken;
2593
- var fs23 = __importStar(require("fs"));
2594
- var path24 = __importStar(require("path"));
2593
+ var fs24 = __importStar(require("fs"));
2594
+ var path25 = __importStar(require("path"));
2595
2595
  var os9 = __importStar(require("os"));
2596
2596
  var child_process_1 = require("child_process");
2597
2597
  var DEFAULT_CONFIG_FILE = "config.json";
2598
2598
  function getConfigDir8() {
2599
- return process.env.EPISODA_CONFIG_DIR || path24.join(os9.homedir(), ".episoda");
2599
+ return process.env.EPISODA_CONFIG_DIR || path25.join(os9.homedir(), ".episoda");
2600
2600
  }
2601
2601
  function getConfigPath(configPath) {
2602
2602
  if (configPath) {
2603
2603
  return configPath;
2604
2604
  }
2605
- return path24.join(getConfigDir8(), DEFAULT_CONFIG_FILE);
2605
+ return path25.join(getConfigDir8(), DEFAULT_CONFIG_FILE);
2606
2606
  }
2607
2607
  function ensureConfigDir(configPath) {
2608
- const dir = path24.dirname(configPath);
2609
- const isNew = !fs23.existsSync(dir);
2608
+ const dir = path25.dirname(configPath);
2609
+ const isNew = !fs24.existsSync(dir);
2610
2610
  if (isNew) {
2611
- fs23.mkdirSync(dir, { recursive: true, mode: 448 });
2611
+ fs24.mkdirSync(dir, { recursive: true, mode: 448 });
2612
2612
  }
2613
2613
  if (process.platform === "darwin") {
2614
- const nosyncPath = path24.join(dir, ".nosync");
2615
- if (isNew || !fs23.existsSync(nosyncPath)) {
2614
+ const nosyncPath = path25.join(dir, ".nosync");
2615
+ if (isNew || !fs24.existsSync(nosyncPath)) {
2616
2616
  try {
2617
- fs23.writeFileSync(nosyncPath, "", { mode: 384 });
2617
+ fs24.writeFileSync(nosyncPath, "", { mode: 384 });
2618
2618
  (0, child_process_1.execSync)(`xattr -w com.apple.fileprovider.ignore 1 "${dir}"`, {
2619
2619
  stdio: "ignore",
2620
2620
  timeout: 5e3
@@ -2626,9 +2626,9 @@ var require_auth = __commonJS({
2626
2626
  }
2627
2627
  async function loadConfig8(configPath) {
2628
2628
  const fullPath = getConfigPath(configPath);
2629
- if (fs23.existsSync(fullPath)) {
2629
+ if (fs24.existsSync(fullPath)) {
2630
2630
  try {
2631
- const content = fs23.readFileSync(fullPath, "utf8");
2631
+ const content = fs24.readFileSync(fullPath, "utf8");
2632
2632
  const config = JSON.parse(content);
2633
2633
  return config;
2634
2634
  } catch (error) {
@@ -2638,9 +2638,9 @@ var require_auth = __commonJS({
2638
2638
  if (process.env.EPISODA_MODE === "cloud" && process.env.EPISODA_WORKSPACE) {
2639
2639
  const homeDir = process.env.HOME || require("os").homedir();
2640
2640
  const workspaceConfigPath = require("path").join(homeDir, "episoda", process.env.EPISODA_WORKSPACE, ".episoda", "config.json");
2641
- if (fs23.existsSync(workspaceConfigPath)) {
2641
+ if (fs24.existsSync(workspaceConfigPath)) {
2642
2642
  try {
2643
- const content = fs23.readFileSync(workspaceConfigPath, "utf8");
2643
+ const content = fs24.readFileSync(workspaceConfigPath, "utf8");
2644
2644
  const workspaceConfig = JSON.parse(content);
2645
2645
  return {
2646
2646
  access_token: process.env.EPISODA_ACCESS_TOKEN || workspaceConfig.accessToken,
@@ -2687,7 +2687,7 @@ var require_auth = __commonJS({
2687
2687
  ensureConfigDir(fullPath);
2688
2688
  try {
2689
2689
  const content = JSON.stringify(config, null, 2);
2690
- fs23.writeFileSync(fullPath, content, { mode: 384 });
2690
+ fs24.writeFileSync(fullPath, content, { mode: 384 });
2691
2691
  } catch (error) {
2692
2692
  throw new Error(`Failed to save config: ${error instanceof Error ? error.message : String(error)}`);
2693
2693
  }
@@ -2843,7 +2843,7 @@ var require_package = __commonJS({
2843
2843
  "@modelcontextprotocol/server-github": "^0.6.0"
2844
2844
  },
2845
2845
  devDependencies: {
2846
- "@episoda/core": "*",
2846
+ "@episoda/core": "workspace:*",
2847
2847
  "@types/node": "^20.11.24",
2848
2848
  "@types/semver": "7.7.1",
2849
2849
  "@types/tar": "6.1.13",
@@ -4058,8 +4058,8 @@ async function handleExec(command, projectPath) {
4058
4058
  }
4059
4059
 
4060
4060
  // src/daemon/handlers/worktree-handlers.ts
4061
- var path15 = __toESM(require("path"));
4062
- var fs14 = __toESM(require("fs"));
4061
+ var path16 = __toESM(require("path"));
4062
+ var fs15 = __toESM(require("fs"));
4063
4063
  var import_child_process8 = require("child_process");
4064
4064
  var import_util = require("util");
4065
4065
 
@@ -7332,6 +7332,144 @@ async function deleteWorktree(config, moduleUid) {
7332
7332
  }
7333
7333
  }
7334
7334
 
7335
+ // src/daemon/package-manager.ts
7336
+ var fs14 = __toESM(require("fs"));
7337
+ var path15 = __toESM(require("path"));
7338
+ var PACKAGE_MANAGERS = {
7339
+ javascript: [
7340
+ {
7341
+ name: "pnpm",
7342
+ detector: (p) => {
7343
+ if (fs14.existsSync(path15.join(p, "pnpm-lock.yaml"))) {
7344
+ return "pnpm-lock.yaml";
7345
+ }
7346
+ const pkgJsonPath = path15.join(p, "package.json");
7347
+ if (fs14.existsSync(pkgJsonPath)) {
7348
+ try {
7349
+ const pkg = JSON.parse(fs14.readFileSync(pkgJsonPath, "utf-8"));
7350
+ if (pkg.packageManager?.startsWith("pnpm")) {
7351
+ return "package.json (packageManager field)";
7352
+ }
7353
+ } catch {
7354
+ }
7355
+ }
7356
+ return null;
7357
+ },
7358
+ config: {
7359
+ installCmd: "pnpm install --frozen-lockfile",
7360
+ cacheEnvVar: "PNPM_HOME"
7361
+ }
7362
+ },
7363
+ {
7364
+ name: "yarn",
7365
+ detector: (p) => fs14.existsSync(path15.join(p, "yarn.lock")) ? "yarn.lock" : null,
7366
+ config: {
7367
+ installCmd: "yarn install --frozen-lockfile",
7368
+ cacheEnvVar: "YARN_CACHE_FOLDER"
7369
+ }
7370
+ },
7371
+ {
7372
+ name: "bun",
7373
+ detector: (p) => fs14.existsSync(path15.join(p, "bun.lockb")) ? "bun.lockb" : null,
7374
+ config: {
7375
+ installCmd: "bun install --frozen-lockfile"
7376
+ }
7377
+ },
7378
+ {
7379
+ name: "npm",
7380
+ detector: (p) => fs14.existsSync(path15.join(p, "package-lock.json")) ? "package-lock.json" : null,
7381
+ config: {
7382
+ installCmd: "npm ci"
7383
+ }
7384
+ },
7385
+ {
7386
+ // EP1222: Default to pnpm for new projects without lockfile
7387
+ // This encourages standardization on pnpm across Episoda projects
7388
+ name: "pnpm",
7389
+ detector: (p) => fs14.existsSync(path15.join(p, "package.json")) ? "package.json (no lockfile - defaulting to pnpm)" : null,
7390
+ config: {
7391
+ installCmd: "pnpm install",
7392
+ cacheEnvVar: "PNPM_HOME"
7393
+ }
7394
+ }
7395
+ ],
7396
+ python: [
7397
+ {
7398
+ name: "uv",
7399
+ detector: (p) => {
7400
+ const pyprojectPath = path15.join(p, "pyproject.toml");
7401
+ if (fs14.existsSync(path15.join(p, "uv.lock"))) {
7402
+ return "uv.lock";
7403
+ }
7404
+ if (fs14.existsSync(pyprojectPath)) {
7405
+ try {
7406
+ const content = fs14.readFileSync(pyprojectPath, "utf-8");
7407
+ if (content.includes("[tool.uv]") || content.includes("[project]")) {
7408
+ return "pyproject.toml";
7409
+ }
7410
+ } catch {
7411
+ }
7412
+ }
7413
+ return null;
7414
+ },
7415
+ config: {
7416
+ installCmd: "uv sync",
7417
+ cacheEnvVar: "UV_CACHE_DIR"
7418
+ }
7419
+ },
7420
+ {
7421
+ name: "pip",
7422
+ detector: (p) => fs14.existsSync(path15.join(p, "requirements.txt")) ? "requirements.txt" : null,
7423
+ config: {
7424
+ installCmd: "pip install -r requirements.txt"
7425
+ }
7426
+ }
7427
+ ]
7428
+ // Future: Add more languages here
7429
+ // rust: [
7430
+ // {
7431
+ // name: 'cargo',
7432
+ // detector: (p) => fs.existsSync(path.join(p, 'Cargo.toml')) ? 'Cargo.toml' : null,
7433
+ // config: { installCmd: 'cargo build' }
7434
+ // }
7435
+ // ],
7436
+ // go: [
7437
+ // {
7438
+ // name: 'go',
7439
+ // detector: (p) => fs.existsSync(path.join(p, 'go.mod')) ? 'go.mod' : null,
7440
+ // config: { installCmd: 'go mod download' }
7441
+ // }
7442
+ // ],
7443
+ };
7444
+ function detectPackageManager(worktreePath, preferredLanguages) {
7445
+ const checkedFiles = [];
7446
+ const languages = preferredLanguages || Object.keys(PACKAGE_MANAGERS);
7447
+ for (const language of languages) {
7448
+ const managers = PACKAGE_MANAGERS[language];
7449
+ if (!managers) continue;
7450
+ for (const { name, detector, config } of managers) {
7451
+ const matchedFile = detector(worktreePath);
7452
+ if (matchedFile) {
7453
+ checkedFiles.push(matchedFile);
7454
+ return {
7455
+ detected: true,
7456
+ packageManager: {
7457
+ name,
7458
+ language,
7459
+ ...config
7460
+ },
7461
+ checkedFiles,
7462
+ matchedFile
7463
+ };
7464
+ }
7465
+ }
7466
+ }
7467
+ return {
7468
+ detected: false,
7469
+ checkedFiles
7470
+ };
7471
+ }
7472
+
7335
7473
  // src/daemon/handlers/worktree-handlers.ts
7336
7474
  async function getConfigForApi() {
7337
7475
  if (process.env.EPISODA_MODE === "cloud" && process.env.EPISODA_ACCESS_TOKEN) {
@@ -7350,6 +7488,16 @@ async function getConfigForApi() {
7350
7488
  return (0, import_core9.loadConfig)();
7351
7489
  }
7352
7490
  var execAsync = (0, import_util.promisify)(import_child_process8.exec);
7491
+ async function autoDetectSetupScript(worktreePath) {
7492
+ const detection = detectPackageManager(worktreePath);
7493
+ if (!detection.detected || !detection.packageManager) {
7494
+ console.log(`[Worktree] EP1222: No package manager detected in ${worktreePath}`);
7495
+ return null;
7496
+ }
7497
+ const { name, language, installCmd } = detection.packageManager;
7498
+ console.log(`[Worktree] EP1222: Detected ${name} (${language}) via ${detection.matchedFile}`);
7499
+ return installCmd;
7500
+ }
7353
7501
  async function handleWorktreeCreate(request2) {
7354
7502
  const {
7355
7503
  workspaceSlug,
@@ -7374,18 +7522,18 @@ async function handleWorktreeCreate(request2) {
7374
7522
  }
7375
7523
  try {
7376
7524
  const projectPath = getProjectPath(workspaceSlug, projectSlug);
7377
- const bareRepoPath = path15.join(projectPath, ".bare");
7378
- if (!fs14.existsSync(bareRepoPath)) {
7525
+ const bareRepoPath = path16.join(projectPath, ".bare");
7526
+ if (!fs15.existsSync(bareRepoPath)) {
7379
7527
  console.log(`[Worktree] K1273: Project not found, cloning lazily...`);
7380
7528
  console.log(`[Worktree] Repo URL: ${repoUrl.replace(/\/\/[^@]*@/, "//***@")}`);
7381
- const episodaDir = path15.join(projectPath, ".episoda");
7382
- fs14.mkdirSync(episodaDir, { recursive: true });
7529
+ const episodaDir = path16.join(projectPath, ".episoda");
7530
+ fs15.mkdirSync(episodaDir, { recursive: true });
7383
7531
  try {
7384
7532
  console.log(`[Worktree] K1273: Starting git clone...`);
7385
7533
  await execAsync(`git clone --bare "${repoUrl}" "${bareRepoPath}"`);
7386
7534
  console.log(`[Worktree] K1273: Clone successful`);
7387
7535
  await execAsync(`git -C "${bareRepoPath}" config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*"`);
7388
- const configPath = path15.join(episodaDir, "config.json");
7536
+ const configPath = path16.join(episodaDir, "config.json");
7389
7537
  const config2 = {
7390
7538
  projectId,
7391
7539
  workspaceSlug,
@@ -7394,7 +7542,7 @@ async function handleWorktreeCreate(request2) {
7394
7542
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
7395
7543
  worktrees: []
7396
7544
  };
7397
- fs14.writeFileSync(configPath, JSON.stringify(config2, null, 2), "utf-8");
7545
+ fs15.writeFileSync(configPath, JSON.stringify(config2, null, 2), "utf-8");
7398
7546
  console.log(`[Worktree] K1273: Project initialized at ${projectPath}`);
7399
7547
  } catch (cloneError) {
7400
7548
  console.error(`[Worktree] K1273: Git clone failed: ${cloneError.message}`);
@@ -7442,11 +7590,12 @@ async function handleWorktreeCreate(request2) {
7442
7590
  }
7443
7591
  if (envVars && Object.keys(envVars).length > 0) {
7444
7592
  const envContent = Object.entries(envVars).map(([key, value]) => `${key}=${value}`).join("\n");
7445
- const envPath = path15.join(worktreePath, ".env");
7446
- fs14.writeFileSync(envPath, envContent + "\n", "utf-8");
7593
+ const envPath = path16.join(worktreePath, ".env");
7594
+ fs15.writeFileSync(envPath, envContent + "\n", "utf-8");
7447
7595
  console.log(`[Worktree] EP1143: Wrote ${Object.keys(envVars).length} env vars to .env`);
7448
7596
  }
7449
- if (setupScript) {
7597
+ const effectiveSetupScript = setupScript || await autoDetectSetupScript(worktreePath);
7598
+ if (effectiveSetupScript) {
7450
7599
  await manager.updateWorktreeStatus(moduleUid, "setup");
7451
7600
  if (config?.access_token) {
7452
7601
  await updateWorktree(config, {
@@ -7458,7 +7607,7 @@ async function handleWorktreeCreate(request2) {
7458
7607
  });
7459
7608
  }
7460
7609
  console.log(`[Worktree] EP1143: Running setup script...`);
7461
- const scriptResult = await manager.runSetupScript(moduleUid, setupScript);
7610
+ const scriptResult = await manager.runSetupScript(moduleUid, effectiveSetupScript);
7462
7611
  if (!scriptResult.success) {
7463
7612
  console.error(`[Worktree] EP1143: Setup script failed: ${scriptResult.error}`);
7464
7613
  await manager.updateWorktreeStatus(moduleUid, "error", scriptResult.error);
@@ -7616,12 +7765,12 @@ async function handleProjectEject(request2) {
7616
7765
  console.log(`[Worktree] EP1144: Ejecting project ${projectSlug} from workspace ${workspaceSlug}`);
7617
7766
  try {
7618
7767
  const projectPath = getProjectPath(workspaceSlug, projectSlug);
7619
- const bareRepoPath = path15.join(projectPath, ".bare");
7620
- if (!fs14.existsSync(projectPath)) {
7768
+ const bareRepoPath = path16.join(projectPath, ".bare");
7769
+ if (!fs15.existsSync(projectPath)) {
7621
7770
  console.log(`[Worktree] EP1144: Project path not found, nothing to eject: ${projectPath}`);
7622
7771
  return { success: true };
7623
7772
  }
7624
- if (!fs14.existsSync(bareRepoPath)) {
7773
+ if (!fs15.existsSync(bareRepoPath)) {
7625
7774
  console.log(`[Worktree] EP1144: Bare repo not found, nothing to eject: ${bareRepoPath}`);
7626
7775
  return { success: true };
7627
7776
  }
@@ -7636,12 +7785,12 @@ async function handleProjectEject(request2) {
7636
7785
  };
7637
7786
  }
7638
7787
  }
7639
- const artifactsPath = path15.join(projectPath, "artifacts");
7640
- if (fs14.existsSync(artifactsPath)) {
7788
+ const artifactsPath = path16.join(projectPath, "artifacts");
7789
+ if (fs15.existsSync(artifactsPath)) {
7641
7790
  await persistArtifactsBeforeEject(artifactsPath, projectId, projectSlug);
7642
7791
  }
7643
7792
  console.log(`[Worktree] EP1144: Removing project directory: ${projectPath}`);
7644
- await fs14.promises.rm(projectPath, { recursive: true, force: true });
7793
+ await fs15.promises.rm(projectPath, { recursive: true, force: true });
7645
7794
  console.log(`[Worktree] EP1144: Successfully ejected project ${projectSlug}`);
7646
7795
  return { success: true };
7647
7796
  } catch (error) {
@@ -7655,7 +7804,7 @@ async function handleProjectEject(request2) {
7655
7804
  async function persistArtifactsBeforeEject(artifactsPath, projectId, projectSlug) {
7656
7805
  const MAX_ARTIFACT_SIZE = 10 * 1024 * 1024;
7657
7806
  try {
7658
- const files = await fs14.promises.readdir(artifactsPath);
7807
+ const files = await fs15.promises.readdir(artifactsPath);
7659
7808
  if (files.length === 0) {
7660
7809
  return;
7661
7810
  }
@@ -7669,8 +7818,8 @@ async function persistArtifactsBeforeEject(artifactsPath, projectId, projectSlug
7669
7818
  }
7670
7819
  const artifacts = [];
7671
7820
  for (const fileName of files) {
7672
- const filePath = path15.join(artifactsPath, fileName);
7673
- const stat = await fs14.promises.stat(filePath);
7821
+ const filePath = path16.join(artifactsPath, fileName);
7822
+ const stat = await fs15.promises.stat(filePath);
7674
7823
  if (stat.isDirectory()) {
7675
7824
  continue;
7676
7825
  }
@@ -7679,9 +7828,9 @@ async function persistArtifactsBeforeEject(artifactsPath, projectId, projectSlug
7679
7828
  continue;
7680
7829
  }
7681
7830
  try {
7682
- const content = await fs14.promises.readFile(filePath);
7831
+ const content = await fs15.promises.readFile(filePath);
7683
7832
  const base64Content = content.toString("base64");
7684
- const ext = path15.extname(fileName).toLowerCase();
7833
+ const ext = path16.extname(fileName).toLowerCase();
7685
7834
  const mimeTypes = {
7686
7835
  ".json": "application/json",
7687
7836
  ".txt": "text/plain",
@@ -7737,8 +7886,8 @@ async function persistArtifactsBeforeEject(artifactsPath, projectId, projectSlug
7737
7886
  }
7738
7887
 
7739
7888
  // src/daemon/handlers/project-handlers.ts
7740
- var path16 = __toESM(require("path"));
7741
- var fs15 = __toESM(require("fs"));
7889
+ var path17 = __toESM(require("path"));
7890
+ var fs16 = __toESM(require("fs"));
7742
7891
  function validateSlug(slug, fieldName) {
7743
7892
  if (!slug || typeof slug !== "string") {
7744
7893
  return `${fieldName} is required`;
@@ -7778,14 +7927,14 @@ async function handleProjectSetup(params) {
7778
7927
  console.log(`[ProjectSetup] EP1199: Setting up project ${workspaceSlug}/${projectSlug}`);
7779
7928
  try {
7780
7929
  const projectPath = getProjectPath(workspaceSlug, projectSlug);
7781
- const artifactsPath = path16.join(projectPath, "artifacts");
7782
- const configDir = path16.join(projectPath, ".episoda");
7783
- const configPath = path16.join(configDir, "config.json");
7784
- await fs15.promises.mkdir(artifactsPath, { recursive: true });
7785
- await fs15.promises.mkdir(configDir, { recursive: true });
7930
+ const artifactsPath = path17.join(projectPath, "artifacts");
7931
+ const configDir = path17.join(projectPath, ".episoda");
7932
+ const configPath = path17.join(configDir, "config.json");
7933
+ await fs16.promises.mkdir(artifactsPath, { recursive: true });
7934
+ await fs16.promises.mkdir(configDir, { recursive: true });
7786
7935
  let existingConfig = {};
7787
7936
  try {
7788
- const existing = await fs15.promises.readFile(configPath, "utf-8");
7937
+ const existing = await fs16.promises.readFile(configPath, "utf-8");
7789
7938
  existingConfig = JSON.parse(existing);
7790
7939
  } catch {
7791
7940
  }
@@ -7798,7 +7947,7 @@ async function handleProjectSetup(params) {
7798
7947
  // Only set created_at if not already present
7799
7948
  created_at: existingConfig.created_at || (/* @__PURE__ */ new Date()).toISOString()
7800
7949
  };
7801
- await fs15.promises.writeFile(configPath, JSON.stringify(config, null, 2));
7950
+ await fs16.promises.writeFile(configPath, JSON.stringify(config, null, 2));
7802
7951
  console.log(`[ProjectSetup] EP1199: Project setup complete at ${projectPath}`);
7803
7952
  return {
7804
7953
  success: true,
@@ -7912,12 +8061,12 @@ async function cleanupStaleCommits(projectPath) {
7912
8061
 
7913
8062
  // src/agent/claude-binary.ts
7914
8063
  var import_child_process10 = require("child_process");
7915
- var path17 = __toESM(require("path"));
7916
- var fs16 = __toESM(require("fs"));
8064
+ var path18 = __toESM(require("path"));
8065
+ var fs17 = __toESM(require("fs"));
7917
8066
  var cachedBinaryPath = null;
7918
8067
  function isValidClaudeBinary(binaryPath) {
7919
8068
  try {
7920
- fs16.accessSync(binaryPath, fs16.constants.X_OK);
8069
+ fs17.accessSync(binaryPath, fs17.constants.X_OK);
7921
8070
  const version = (0, import_child_process10.execSync)(`"${binaryPath}" --version`, {
7922
8071
  encoding: "utf-8",
7923
8072
  timeout: 5e3,
@@ -7950,14 +8099,14 @@ async function ensureClaudeBinary() {
7950
8099
  }
7951
8100
  const bundledPaths = [
7952
8101
  // In production: node_modules/.bin/claude
7953
- path17.join(__dirname, "..", "..", "node_modules", ".bin", "claude"),
8102
+ path18.join(__dirname, "..", "..", "node_modules", ".bin", "claude"),
7954
8103
  // In monorepo development: packages/episoda/node_modules/.bin/claude
7955
- path17.join(__dirname, "..", "..", "..", "..", "node_modules", ".bin", "claude"),
8104
+ path18.join(__dirname, "..", "..", "..", "..", "node_modules", ".bin", "claude"),
7956
8105
  // Root monorepo node_modules
7957
- path17.join(__dirname, "..", "..", "..", "..", "..", "node_modules", ".bin", "claude")
8106
+ path18.join(__dirname, "..", "..", "..", "..", "..", "node_modules", ".bin", "claude")
7958
8107
  ];
7959
8108
  for (const bundledPath of bundledPaths) {
7960
- if (fs16.existsSync(bundledPath) && isValidClaudeBinary(bundledPath)) {
8109
+ if (fs17.existsSync(bundledPath) && isValidClaudeBinary(bundledPath)) {
7961
8110
  cachedBinaryPath = bundledPath;
7962
8111
  return cachedBinaryPath;
7963
8112
  }
@@ -7983,12 +8132,12 @@ async function ensureClaudeBinary() {
7983
8132
 
7984
8133
  // src/agent/codex-binary.ts
7985
8134
  var import_child_process11 = require("child_process");
7986
- var path18 = __toESM(require("path"));
7987
- var fs17 = __toESM(require("fs"));
8135
+ var path19 = __toESM(require("path"));
8136
+ var fs18 = __toESM(require("fs"));
7988
8137
  var cachedBinaryPath2 = null;
7989
8138
  function isValidCodexBinary(binaryPath) {
7990
8139
  try {
7991
- fs17.accessSync(binaryPath, fs17.constants.X_OK);
8140
+ fs18.accessSync(binaryPath, fs18.constants.X_OK);
7992
8141
  const version = (0, import_child_process11.execSync)(`"${binaryPath}" --version`, {
7993
8142
  encoding: "utf-8",
7994
8143
  timeout: 5e3,
@@ -8021,14 +8170,14 @@ async function ensureCodexBinary() {
8021
8170
  }
8022
8171
  const bundledPaths = [
8023
8172
  // In production: node_modules/.bin/codex
8024
- path18.join(__dirname, "..", "..", "node_modules", ".bin", "codex"),
8173
+ path19.join(__dirname, "..", "..", "node_modules", ".bin", "codex"),
8025
8174
  // In monorepo development: packages/episoda/node_modules/.bin/codex
8026
- path18.join(__dirname, "..", "..", "..", "..", "node_modules", ".bin", "codex"),
8175
+ path19.join(__dirname, "..", "..", "..", "..", "node_modules", ".bin", "codex"),
8027
8176
  // Root monorepo node_modules
8028
- path18.join(__dirname, "..", "..", "..", "..", "..", "node_modules", ".bin", "codex")
8177
+ path19.join(__dirname, "..", "..", "..", "..", "..", "node_modules", ".bin", "codex")
8029
8178
  ];
8030
8179
  for (const bundledPath of bundledPaths) {
8031
- if (fs17.existsSync(bundledPath) && isValidCodexBinary(bundledPath)) {
8180
+ if (fs18.existsSync(bundledPath) && isValidCodexBinary(bundledPath)) {
8032
8181
  cachedBinaryPath2 = bundledPath;
8033
8182
  return cachedBinaryPath2;
8034
8183
  }
@@ -8095,8 +8244,8 @@ function generateCodexConfig(credentials, projectPath) {
8095
8244
 
8096
8245
  // src/agent/agent-manager.ts
8097
8246
  var import_child_process12 = require("child_process");
8098
- var path19 = __toESM(require("path"));
8099
- var fs18 = __toESM(require("fs"));
8247
+ var path20 = __toESM(require("path"));
8248
+ var fs19 = __toESM(require("fs"));
8100
8249
  var os6 = __toESM(require("os"));
8101
8250
 
8102
8251
  // src/agent/claude-config.ts
@@ -8419,7 +8568,7 @@ var AgentManager = class {
8419
8568
  this.initialized = false;
8420
8569
  // EP1133: Lock for config file writes to prevent race conditions
8421
8570
  this.configWriteLock = Promise.resolve();
8422
- this.pidDir = path19.join(os6.homedir(), ".episoda", "agent-pids");
8571
+ this.pidDir = path20.join(os6.homedir(), ".episoda", "agent-pids");
8423
8572
  }
8424
8573
  /**
8425
8574
  * EP1133: Acquire lock for config file writes
@@ -8448,8 +8597,8 @@ var AgentManager = class {
8448
8597
  return;
8449
8598
  }
8450
8599
  console.log("[AgentManager] Initializing...");
8451
- if (!fs18.existsSync(this.pidDir)) {
8452
- fs18.mkdirSync(this.pidDir, { recursive: true });
8600
+ if (!fs19.existsSync(this.pidDir)) {
8601
+ fs19.mkdirSync(this.pidDir, { recursive: true });
8453
8602
  }
8454
8603
  await this.cleanupOrphanedProcesses();
8455
8604
  try {
@@ -8696,9 +8845,9 @@ If changes are needed, explain what needs to be done.`;
8696
8845
  const useApiKey = !useOAuth && !!session.credentials.apiKey;
8697
8846
  if (provider === "codex") {
8698
8847
  await this.withConfigLock(async () => {
8699
- const codexDir = path19.join(os6.homedir(), ".codex");
8700
- if (!fs18.existsSync(codexDir)) {
8701
- fs18.mkdirSync(codexDir, { recursive: true });
8848
+ const codexDir = path20.join(os6.homedir(), ".codex");
8849
+ if (!fs19.existsSync(codexDir)) {
8850
+ fs19.mkdirSync(codexDir, { recursive: true });
8702
8851
  }
8703
8852
  if (useOAuth) {
8704
8853
  const codexConfig = generateCodexConfig({
@@ -8708,21 +8857,21 @@ If changes are needed, explain what needs to be done.`;
8708
8857
  accountId: session.credentials.accountId,
8709
8858
  expiresAt: session.credentials.expiresAt
8710
8859
  }, session.projectPath);
8711
- const authJsonPath = path19.join(codexDir, "auth.json");
8712
- fs18.writeFileSync(authJsonPath, codexConfig["auth.json"], { mode: 384 });
8860
+ const authJsonPath = path20.join(codexDir, "auth.json");
8861
+ fs19.writeFileSync(authJsonPath, codexConfig["auth.json"], { mode: 384 });
8713
8862
  console.log("[AgentManager] EP1133: Wrote Codex auth.json to ~/.codex/auth.json");
8714
8863
  if (codexConfig["config.toml"]) {
8715
- const configTomlPath = path19.join(codexDir, "config.toml");
8864
+ const configTomlPath = path20.join(codexDir, "config.toml");
8716
8865
  let existingConfig = "";
8717
8866
  try {
8718
- existingConfig = fs18.readFileSync(configTomlPath, "utf-8");
8867
+ existingConfig = fs19.readFileSync(configTomlPath, "utf-8");
8719
8868
  } catch {
8720
8869
  }
8721
8870
  const escapedPathForRegex = session.projectPath.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
8722
8871
  const projectKeyPattern = new RegExp(`\\[projects\\."${escapedPathForRegex}"\\]`);
8723
8872
  const projectAlreadyTrusted = projectKeyPattern.test(existingConfig);
8724
8873
  if (!projectAlreadyTrusted) {
8725
- fs18.writeFileSync(configTomlPath, existingConfig + "\n" + codexConfig["config.toml"], { mode: 420 });
8874
+ fs19.writeFileSync(configTomlPath, existingConfig + "\n" + codexConfig["config.toml"], { mode: 420 });
8726
8875
  console.log("[AgentManager] EP1133: Updated Codex config.toml with project trust");
8727
8876
  }
8728
8877
  }
@@ -8732,14 +8881,14 @@ If changes are needed, explain what needs to be done.`;
8732
8881
  });
8733
8882
  } else {
8734
8883
  await this.withConfigLock(async () => {
8735
- const claudeDir = path19.join(os6.homedir(), ".claude");
8736
- const credentialsPath = path19.join(claudeDir, ".credentials.json");
8737
- const statsigDir = path19.join(claudeDir, "statsig");
8738
- if (!fs18.existsSync(claudeDir)) {
8739
- fs18.mkdirSync(claudeDir, { recursive: true });
8884
+ const claudeDir = path20.join(os6.homedir(), ".claude");
8885
+ const credentialsPath = path20.join(claudeDir, ".credentials.json");
8886
+ const statsigDir = path20.join(claudeDir, "statsig");
8887
+ if (!fs19.existsSync(claudeDir)) {
8888
+ fs19.mkdirSync(claudeDir, { recursive: true });
8740
8889
  }
8741
- if (!fs18.existsSync(statsigDir)) {
8742
- fs18.mkdirSync(statsigDir, { recursive: true });
8890
+ if (!fs19.existsSync(statsigDir)) {
8891
+ fs19.mkdirSync(statsigDir, { recursive: true });
8743
8892
  }
8744
8893
  if (useOAuth) {
8745
8894
  const oauthCredentials = {
@@ -8757,7 +8906,7 @@ If changes are needed, explain what needs to be done.`;
8757
8906
  const credentialsContent = JSON.stringify({
8758
8907
  claudeAiOauth: oauthCredentials
8759
8908
  }, null, 2);
8760
- fs18.writeFileSync(credentialsPath, credentialsContent, { mode: 384 });
8909
+ fs19.writeFileSync(credentialsPath, credentialsContent, { mode: 384 });
8761
8910
  console.log("[AgentManager] Wrote OAuth credentials to ~/.claude/.credentials.json");
8762
8911
  try {
8763
8912
  const claudeConfig = generateClaudeConfig({
@@ -8769,11 +8918,11 @@ If changes are needed, explain what needs to be done.`;
8769
8918
  if (!hasEvaluations || !hasStableId) {
8770
8919
  throw new Error(`Invalid statsig config: missing required files`);
8771
8920
  }
8772
- const settingsPath = path19.join(claudeDir, "settings.json");
8773
- fs18.writeFileSync(settingsPath, claudeConfig["settings.json"], { mode: 384 });
8921
+ const settingsPath = path20.join(claudeDir, "settings.json");
8922
+ fs19.writeFileSync(settingsPath, claudeConfig["settings.json"], { mode: 384 });
8774
8923
  for (const [filename, content] of Object.entries(claudeConfig.statsig)) {
8775
- const filePath = path19.join(statsigDir, filename);
8776
- fs18.writeFileSync(filePath, content, { mode: 420 });
8924
+ const filePath = path20.join(statsigDir, filename);
8925
+ fs19.writeFileSync(filePath, content, { mode: 420 });
8777
8926
  }
8778
8927
  if (session.credentials.githubToken) {
8779
8928
  console.log("[AgentManager] EP1146: GitHub MCP server enabled with installation token");
@@ -9043,14 +9192,14 @@ If changes are needed, explain what needs to be done.`;
9043
9192
  */
9044
9193
  async cleanupOrphanedProcesses() {
9045
9194
  let cleaned = 0;
9046
- if (!fs18.existsSync(this.pidDir)) {
9195
+ if (!fs19.existsSync(this.pidDir)) {
9047
9196
  return { cleaned };
9048
9197
  }
9049
- const pidFiles = fs18.readdirSync(this.pidDir).filter((f) => f.endsWith(".pid"));
9198
+ const pidFiles = fs19.readdirSync(this.pidDir).filter((f) => f.endsWith(".pid"));
9050
9199
  for (const pidFile of pidFiles) {
9051
- const pidPath = path19.join(this.pidDir, pidFile);
9200
+ const pidPath = path20.join(this.pidDir, pidFile);
9052
9201
  try {
9053
- const pidStr = fs18.readFileSync(pidPath, "utf-8").trim();
9202
+ const pidStr = fs19.readFileSync(pidPath, "utf-8").trim();
9054
9203
  const pid = parseInt(pidStr, 10);
9055
9204
  if (!isNaN(pid)) {
9056
9205
  try {
@@ -9061,7 +9210,7 @@ If changes are needed, explain what needs to be done.`;
9061
9210
  } catch {
9062
9211
  }
9063
9212
  }
9064
- fs18.unlinkSync(pidPath);
9213
+ fs19.unlinkSync(pidPath);
9065
9214
  } catch (error) {
9066
9215
  console.warn(`[AgentManager] Error cleaning PID file ${pidFile}:`, error);
9067
9216
  }
@@ -9075,17 +9224,17 @@ If changes are needed, explain what needs to be done.`;
9075
9224
  * Write PID file for session tracking
9076
9225
  */
9077
9226
  writePidFile(sessionId, pid) {
9078
- const pidPath = path19.join(this.pidDir, `${sessionId}.pid`);
9079
- fs18.writeFileSync(pidPath, pid.toString());
9227
+ const pidPath = path20.join(this.pidDir, `${sessionId}.pid`);
9228
+ fs19.writeFileSync(pidPath, pid.toString());
9080
9229
  }
9081
9230
  /**
9082
9231
  * Remove PID file for session
9083
9232
  */
9084
9233
  removePidFile(sessionId) {
9085
- const pidPath = path19.join(this.pidDir, `${sessionId}.pid`);
9234
+ const pidPath = path20.join(this.pidDir, `${sessionId}.pid`);
9086
9235
  try {
9087
- if (fs18.existsSync(pidPath)) {
9088
- fs18.unlinkSync(pidPath);
9236
+ if (fs19.existsSync(pidPath)) {
9237
+ fs19.unlinkSync(pidPath);
9089
9238
  }
9090
9239
  } catch {
9091
9240
  }
@@ -9095,8 +9244,8 @@ If changes are needed, explain what needs to be done.`;
9095
9244
  // src/utils/dev-server.ts
9096
9245
  var import_child_process13 = require("child_process");
9097
9246
  var import_core11 = __toESM(require_dist());
9098
- var fs19 = __toESM(require("fs"));
9099
- var path20 = __toESM(require("path"));
9247
+ var fs20 = __toESM(require("fs"));
9248
+ var path21 = __toESM(require("path"));
9100
9249
  var MAX_RESTART_ATTEMPTS = 5;
9101
9250
  var INITIAL_RESTART_DELAY_MS = 2e3;
9102
9251
  var MAX_RESTART_DELAY_MS = 3e4;
@@ -9104,26 +9253,26 @@ var MAX_LOG_SIZE_BYTES = 5 * 1024 * 1024;
9104
9253
  var NODE_MEMORY_LIMIT_MB = 2048;
9105
9254
  var activeServers = /* @__PURE__ */ new Map();
9106
9255
  function getLogsDir() {
9107
- const logsDir = path20.join((0, import_core11.getConfigDir)(), "logs");
9108
- if (!fs19.existsSync(logsDir)) {
9109
- fs19.mkdirSync(logsDir, { recursive: true });
9256
+ const logsDir = path21.join((0, import_core11.getConfigDir)(), "logs");
9257
+ if (!fs20.existsSync(logsDir)) {
9258
+ fs20.mkdirSync(logsDir, { recursive: true });
9110
9259
  }
9111
9260
  return logsDir;
9112
9261
  }
9113
9262
  function getLogFilePath(moduleUid) {
9114
- return path20.join(getLogsDir(), `dev-${moduleUid}.log`);
9263
+ return path21.join(getLogsDir(), `dev-${moduleUid}.log`);
9115
9264
  }
9116
9265
  function rotateLogIfNeeded(logPath) {
9117
9266
  try {
9118
- if (fs19.existsSync(logPath)) {
9119
- const stats = fs19.statSync(logPath);
9267
+ if (fs20.existsSync(logPath)) {
9268
+ const stats = fs20.statSync(logPath);
9120
9269
  if (stats.size > MAX_LOG_SIZE_BYTES) {
9121
9270
  const backupPath = `${logPath}.1`;
9122
- if (fs19.existsSync(backupPath)) {
9123
- fs19.unlinkSync(backupPath);
9271
+ if (fs20.existsSync(backupPath)) {
9272
+ fs20.unlinkSync(backupPath);
9124
9273
  }
9125
- fs19.renameSync(logPath, backupPath);
9126
- console.log(`[DevServer] EP932: Rotated log file for ${path20.basename(logPath)}`);
9274
+ fs20.renameSync(logPath, backupPath);
9275
+ console.log(`[DevServer] EP932: Rotated log file for ${path21.basename(logPath)}`);
9127
9276
  }
9128
9277
  }
9129
9278
  } catch (error) {
@@ -9136,7 +9285,7 @@ function writeToLog(logPath, line, isError = false) {
9136
9285
  const prefix = isError ? "ERR" : "OUT";
9137
9286
  const logLine = `[${timestamp}] [${prefix}] ${line}
9138
9287
  `;
9139
- fs19.appendFileSync(logPath, logLine);
9288
+ fs20.appendFileSync(logPath, logLine);
9140
9289
  } catch {
9141
9290
  }
9142
9291
  }
@@ -9315,8 +9464,8 @@ async function startDevServer(projectPath, port = 3e3, moduleUid = "default", op
9315
9464
  });
9316
9465
  injectedEnvVars = result.envVars;
9317
9466
  console.log(`[DevServer] EP998: Loaded ${Object.keys(injectedEnvVars).length} env vars (from ${result.fromCache ? "cache" : "server"})`);
9318
- const envFilePath = path20.join(projectPath, ".env");
9319
- if (!fs19.existsSync(envFilePath) && Object.keys(injectedEnvVars).length > 0) {
9467
+ const envFilePath = path21.join(projectPath, ".env");
9468
+ if (!fs20.existsSync(envFilePath) && Object.keys(injectedEnvVars).length > 0) {
9320
9469
  console.log(`[DevServer] EP1004: .env file missing, writing ${Object.keys(injectedEnvVars).length} vars to ${envFilePath}`);
9321
9470
  writeEnvFile(projectPath, injectedEnvVars);
9322
9471
  }
@@ -9422,19 +9571,19 @@ function getDevServerStatus() {
9422
9571
  }
9423
9572
 
9424
9573
  // src/utils/worktree.ts
9425
- var path21 = __toESM(require("path"));
9426
- var fs20 = __toESM(require("fs"));
9574
+ var path22 = __toESM(require("path"));
9575
+ var fs21 = __toESM(require("fs"));
9427
9576
  var os7 = __toESM(require("os"));
9428
9577
  var import_core12 = __toESM(require_dist());
9429
9578
  function getEpisodaRoot2() {
9430
- return process.env.EPISODA_ROOT || path21.join(os7.homedir(), "episoda");
9579
+ return process.env.EPISODA_ROOT || path22.join(os7.homedir(), "episoda");
9431
9580
  }
9432
9581
  function getWorktreeInfo(moduleUid, workspaceSlug, projectSlug) {
9433
9582
  const root = getEpisodaRoot2();
9434
- const worktreePath = path21.join(root, workspaceSlug, projectSlug, moduleUid);
9583
+ const worktreePath = path22.join(root, workspaceSlug, projectSlug, moduleUid);
9435
9584
  return {
9436
9585
  path: worktreePath,
9437
- exists: fs20.existsSync(worktreePath),
9586
+ exists: fs21.existsSync(worktreePath),
9438
9587
  moduleUid
9439
9588
  };
9440
9589
  }
@@ -9448,15 +9597,15 @@ async function getWorktreeInfoForModule(moduleUid) {
9448
9597
  return null;
9449
9598
  }
9450
9599
  const root = getEpisodaRoot2();
9451
- const workspaceRoot = path21.join(root, config.workspace_slug);
9600
+ const workspaceRoot = path22.join(root, config.workspace_slug);
9452
9601
  try {
9453
- const entries = fs20.readdirSync(workspaceRoot, { withFileTypes: true });
9602
+ const entries = fs21.readdirSync(workspaceRoot, { withFileTypes: true });
9454
9603
  for (const entry of entries) {
9455
9604
  if (!entry.isDirectory()) {
9456
9605
  continue;
9457
9606
  }
9458
- const worktreePath = path21.join(workspaceRoot, entry.name, moduleUid);
9459
- if (fs20.existsSync(worktreePath)) {
9607
+ const worktreePath = path22.join(workspaceRoot, entry.name, moduleUid);
9608
+ if (fs21.existsSync(worktreePath)) {
9460
9609
  return {
9461
9610
  path: worktreePath,
9462
9611
  exists: true,
@@ -9473,61 +9622,61 @@ async function getWorktreeInfoForModule(moduleUid) {
9473
9622
  }
9474
9623
 
9475
9624
  // src/framework-detector.ts
9476
- var fs21 = __toESM(require("fs"));
9477
- var path22 = __toESM(require("path"));
9478
- function getInstallCommand(cwd) {
9479
- if (fs21.existsSync(path22.join(cwd, "bun.lockb"))) {
9625
+ var fs22 = __toESM(require("fs"));
9626
+ var path23 = __toESM(require("path"));
9627
+ function getInstallCommand2(cwd) {
9628
+ if (fs22.existsSync(path23.join(cwd, "bun.lockb"))) {
9480
9629
  return {
9481
9630
  command: ["bun", "install"],
9482
9631
  description: "Installing dependencies with bun",
9483
9632
  detectedFrom: "bun.lockb"
9484
9633
  };
9485
9634
  }
9486
- if (fs21.existsSync(path22.join(cwd, "pnpm-lock.yaml"))) {
9635
+ if (fs22.existsSync(path23.join(cwd, "pnpm-lock.yaml"))) {
9487
9636
  return {
9488
9637
  command: ["pnpm", "install"],
9489
9638
  description: "Installing dependencies with pnpm",
9490
9639
  detectedFrom: "pnpm-lock.yaml"
9491
9640
  };
9492
9641
  }
9493
- if (fs21.existsSync(path22.join(cwd, "yarn.lock"))) {
9642
+ if (fs22.existsSync(path23.join(cwd, "yarn.lock"))) {
9494
9643
  return {
9495
9644
  command: ["yarn", "install"],
9496
9645
  description: "Installing dependencies with yarn",
9497
9646
  detectedFrom: "yarn.lock"
9498
9647
  };
9499
9648
  }
9500
- if (fs21.existsSync(path22.join(cwd, "package-lock.json"))) {
9649
+ if (fs22.existsSync(path23.join(cwd, "package-lock.json"))) {
9501
9650
  return {
9502
9651
  command: ["npm", "ci"],
9503
9652
  description: "Installing dependencies with npm ci",
9504
9653
  detectedFrom: "package-lock.json"
9505
9654
  };
9506
9655
  }
9507
- if (fs21.existsSync(path22.join(cwd, "package.json"))) {
9656
+ if (fs22.existsSync(path23.join(cwd, "package.json"))) {
9508
9657
  return {
9509
9658
  command: ["npm", "install"],
9510
9659
  description: "Installing dependencies with npm",
9511
9660
  detectedFrom: "package.json"
9512
9661
  };
9513
9662
  }
9514
- if (fs21.existsSync(path22.join(cwd, "Pipfile.lock")) || fs21.existsSync(path22.join(cwd, "Pipfile"))) {
9663
+ if (fs22.existsSync(path23.join(cwd, "Pipfile.lock")) || fs22.existsSync(path23.join(cwd, "Pipfile"))) {
9515
9664
  return {
9516
9665
  command: ["pipenv", "install"],
9517
9666
  description: "Installing dependencies with pipenv",
9518
- detectedFrom: fs21.existsSync(path22.join(cwd, "Pipfile.lock")) ? "Pipfile.lock" : "Pipfile"
9667
+ detectedFrom: fs22.existsSync(path23.join(cwd, "Pipfile.lock")) ? "Pipfile.lock" : "Pipfile"
9519
9668
  };
9520
9669
  }
9521
- if (fs21.existsSync(path22.join(cwd, "poetry.lock"))) {
9670
+ if (fs22.existsSync(path23.join(cwd, "poetry.lock"))) {
9522
9671
  return {
9523
9672
  command: ["poetry", "install"],
9524
9673
  description: "Installing dependencies with poetry",
9525
9674
  detectedFrom: "poetry.lock"
9526
9675
  };
9527
9676
  }
9528
- if (fs21.existsSync(path22.join(cwd, "pyproject.toml"))) {
9529
- const pyprojectPath = path22.join(cwd, "pyproject.toml");
9530
- const content = fs21.readFileSync(pyprojectPath, "utf-8");
9677
+ if (fs22.existsSync(path23.join(cwd, "pyproject.toml"))) {
9678
+ const pyprojectPath = path23.join(cwd, "pyproject.toml");
9679
+ const content = fs22.readFileSync(pyprojectPath, "utf-8");
9531
9680
  if (content.includes("[tool.poetry]")) {
9532
9681
  return {
9533
9682
  command: ["poetry", "install"],
@@ -9536,42 +9685,42 @@ function getInstallCommand(cwd) {
9536
9685
  };
9537
9686
  }
9538
9687
  }
9539
- if (fs21.existsSync(path22.join(cwd, "requirements.txt"))) {
9688
+ if (fs22.existsSync(path23.join(cwd, "requirements.txt"))) {
9540
9689
  return {
9541
9690
  command: ["pip", "install", "-r", "requirements.txt"],
9542
9691
  description: "Installing dependencies with pip",
9543
9692
  detectedFrom: "requirements.txt"
9544
9693
  };
9545
9694
  }
9546
- if (fs21.existsSync(path22.join(cwd, "Gemfile.lock")) || fs21.existsSync(path22.join(cwd, "Gemfile"))) {
9695
+ if (fs22.existsSync(path23.join(cwd, "Gemfile.lock")) || fs22.existsSync(path23.join(cwd, "Gemfile"))) {
9547
9696
  return {
9548
9697
  command: ["bundle", "install"],
9549
9698
  description: "Installing dependencies with bundler",
9550
- detectedFrom: fs21.existsSync(path22.join(cwd, "Gemfile.lock")) ? "Gemfile.lock" : "Gemfile"
9699
+ detectedFrom: fs22.existsSync(path23.join(cwd, "Gemfile.lock")) ? "Gemfile.lock" : "Gemfile"
9551
9700
  };
9552
9701
  }
9553
- if (fs21.existsSync(path22.join(cwd, "go.sum")) || fs21.existsSync(path22.join(cwd, "go.mod"))) {
9702
+ if (fs22.existsSync(path23.join(cwd, "go.sum")) || fs22.existsSync(path23.join(cwd, "go.mod"))) {
9554
9703
  return {
9555
9704
  command: ["go", "mod", "download"],
9556
9705
  description: "Downloading Go modules",
9557
- detectedFrom: fs21.existsSync(path22.join(cwd, "go.sum")) ? "go.sum" : "go.mod"
9706
+ detectedFrom: fs22.existsSync(path23.join(cwd, "go.sum")) ? "go.sum" : "go.mod"
9558
9707
  };
9559
9708
  }
9560
- if (fs21.existsSync(path22.join(cwd, "Cargo.lock")) || fs21.existsSync(path22.join(cwd, "Cargo.toml"))) {
9709
+ if (fs22.existsSync(path23.join(cwd, "Cargo.lock")) || fs22.existsSync(path23.join(cwd, "Cargo.toml"))) {
9561
9710
  return {
9562
9711
  command: ["cargo", "build"],
9563
9712
  description: "Building Rust project (downloads dependencies)",
9564
- detectedFrom: fs21.existsSync(path22.join(cwd, "Cargo.lock")) ? "Cargo.lock" : "Cargo.toml"
9713
+ detectedFrom: fs22.existsSync(path23.join(cwd, "Cargo.lock")) ? "Cargo.lock" : "Cargo.toml"
9565
9714
  };
9566
9715
  }
9567
9716
  return null;
9568
9717
  }
9569
9718
 
9570
9719
  // src/daemon/daemon-process.ts
9571
- var fs22 = __toESM(require("fs"));
9720
+ var fs23 = __toESM(require("fs"));
9572
9721
  var http2 = __toESM(require("http"));
9573
9722
  var os8 = __toESM(require("os"));
9574
- var path23 = __toESM(require("path"));
9723
+ var path24 = __toESM(require("path"));
9575
9724
  var packageJson = require_package();
9576
9725
  async function ensureValidToken(config, bufferMs = 5 * 60 * 1e3) {
9577
9726
  const now = Date.now();
@@ -9792,9 +9941,9 @@ var Daemon = class _Daemon {
9792
9941
  this.healthServer = http2.createServer((req, res) => {
9793
9942
  if (req.url === "/health" || req.url === "/") {
9794
9943
  const isConnected = this.liveConnections.size > 0;
9795
- const projects = Array.from(this.connections.entries()).map(([path24, conn]) => ({
9796
- path: path24,
9797
- connected: this.liveConnections.has(path24)
9944
+ const projects = Array.from(this.connections.entries()).map(([path25, conn]) => ({
9945
+ path: path25,
9946
+ connected: this.liveConnections.has(path25)
9798
9947
  }));
9799
9948
  const status = {
9800
9949
  status: isConnected ? "healthy" : "degraded",
@@ -10162,7 +10311,7 @@ var Daemon = class _Daemon {
10162
10311
  client.updateActivity();
10163
10312
  try {
10164
10313
  const gitCmd = message.command;
10165
- const bareRepoPath = path23.join(projectPath, ".bare");
10314
+ const bareRepoPath = path24.join(projectPath, ".bare");
10166
10315
  const cwd = gitCmd.worktreePath || bareRepoPath;
10167
10316
  if (gitCmd.worktreePath) {
10168
10317
  console.log(`[Daemon] Routing command to worktree: ${gitCmd.worktreePath}`);
@@ -10747,8 +10896,8 @@ var Daemon = class _Daemon {
10747
10896
  let daemonPid;
10748
10897
  try {
10749
10898
  const pidPath = getPidFilePath();
10750
- if (fs22.existsSync(pidPath)) {
10751
- const pidStr = fs22.readFileSync(pidPath, "utf-8").trim();
10899
+ if (fs23.existsSync(pidPath)) {
10900
+ const pidStr = fs23.readFileSync(pidPath, "utf-8").trim();
10752
10901
  daemonPid = parseInt(pidStr, 10);
10753
10902
  }
10754
10903
  } catch (pidError) {
@@ -10829,28 +10978,28 @@ var Daemon = class _Daemon {
10829
10978
  * - workDir: The directory to run git commands in (cwd)
10830
10979
  */
10831
10980
  getGitDirs(projectPath) {
10832
- const bareDir = path23.join(projectPath, ".bare");
10833
- const gitPath = path23.join(projectPath, ".git");
10834
- if (fs22.existsSync(bareDir) && fs22.statSync(bareDir).isDirectory()) {
10981
+ const bareDir = path24.join(projectPath, ".bare");
10982
+ const gitPath = path24.join(projectPath, ".git");
10983
+ if (fs23.existsSync(bareDir) && fs23.statSync(bareDir).isDirectory()) {
10835
10984
  return { gitDir: bareDir, workDir: projectPath };
10836
10985
  }
10837
- if (fs22.existsSync(gitPath) && fs22.statSync(gitPath).isDirectory()) {
10986
+ if (fs23.existsSync(gitPath) && fs23.statSync(gitPath).isDirectory()) {
10838
10987
  return { gitDir: null, workDir: projectPath };
10839
10988
  }
10840
- if (fs22.existsSync(gitPath) && fs22.statSync(gitPath).isFile()) {
10989
+ if (fs23.existsSync(gitPath) && fs23.statSync(gitPath).isFile()) {
10841
10990
  return { gitDir: null, workDir: projectPath };
10842
10991
  }
10843
- const entries = fs22.readdirSync(projectPath, { withFileTypes: true });
10992
+ const entries = fs23.readdirSync(projectPath, { withFileTypes: true });
10844
10993
  for (const entry of entries) {
10845
10994
  if (entry.isDirectory() && entry.name.startsWith("EP")) {
10846
- const worktreePath = path23.join(projectPath, entry.name);
10847
- const worktreeGit = path23.join(worktreePath, ".git");
10848
- if (fs22.existsSync(worktreeGit)) {
10995
+ const worktreePath = path24.join(projectPath, entry.name);
10996
+ const worktreeGit = path24.join(worktreePath, ".git");
10997
+ if (fs23.existsSync(worktreeGit)) {
10849
10998
  return { gitDir: null, workDir: worktreePath };
10850
10999
  }
10851
11000
  }
10852
11001
  }
10853
- if (fs22.existsSync(bareDir)) {
11002
+ if (fs23.existsSync(bareDir)) {
10854
11003
  return { gitDir: bareDir, workDir: projectPath };
10855
11004
  }
10856
11005
  return { gitDir: null, workDir: projectPath };
@@ -10914,24 +11063,24 @@ var Daemon = class _Daemon {
10914
11063
  async installGitHooks(projectPath) {
10915
11064
  const hooks = ["post-checkout", "pre-commit", "post-commit"];
10916
11065
  let hooksDir;
10917
- const bareHooksDir = path23.join(projectPath, ".bare", "hooks");
10918
- const gitHooksDir = path23.join(projectPath, ".git", "hooks");
10919
- if (fs22.existsSync(bareHooksDir)) {
11066
+ const bareHooksDir = path24.join(projectPath, ".bare", "hooks");
11067
+ const gitHooksDir = path24.join(projectPath, ".git", "hooks");
11068
+ if (fs23.existsSync(bareHooksDir)) {
10920
11069
  hooksDir = bareHooksDir;
10921
- } else if (fs22.existsSync(gitHooksDir) && fs22.statSync(path23.join(projectPath, ".git")).isDirectory()) {
11070
+ } else if (fs23.existsSync(gitHooksDir) && fs23.statSync(path24.join(projectPath, ".git")).isDirectory()) {
10922
11071
  hooksDir = gitHooksDir;
10923
11072
  } else {
10924
- const parentBareHooks = path23.join(projectPath, "..", ".bare", "hooks");
10925
- if (fs22.existsSync(parentBareHooks)) {
11073
+ const parentBareHooks = path24.join(projectPath, "..", ".bare", "hooks");
11074
+ if (fs23.existsSync(parentBareHooks)) {
10926
11075
  hooksDir = parentBareHooks;
10927
11076
  } else {
10928
11077
  console.warn(`[Daemon] Hooks directory not found for: ${projectPath}`);
10929
11078
  return;
10930
11079
  }
10931
11080
  }
10932
- if (!fs22.existsSync(hooksDir)) {
11081
+ if (!fs23.existsSync(hooksDir)) {
10933
11082
  try {
10934
- fs22.mkdirSync(hooksDir, { recursive: true });
11083
+ fs23.mkdirSync(hooksDir, { recursive: true });
10935
11084
  } catch (error) {
10936
11085
  console.warn(`[Daemon] Hooks directory not found and could not create: ${hooksDir}`);
10937
11086
  return;
@@ -10939,20 +11088,20 @@ var Daemon = class _Daemon {
10939
11088
  }
10940
11089
  for (const hookName of hooks) {
10941
11090
  try {
10942
- const hookPath = path23.join(hooksDir, hookName);
10943
- const bundledHookPath = path23.join(__dirname, "..", "hooks", hookName);
10944
- if (!fs22.existsSync(bundledHookPath)) {
11091
+ const hookPath = path24.join(hooksDir, hookName);
11092
+ const bundledHookPath = path24.join(__dirname, "..", "hooks", hookName);
11093
+ if (!fs23.existsSync(bundledHookPath)) {
10945
11094
  console.warn(`[Daemon] Bundled hook not found: ${bundledHookPath}`);
10946
11095
  continue;
10947
11096
  }
10948
- const hookContent = fs22.readFileSync(bundledHookPath, "utf-8");
10949
- if (fs22.existsSync(hookPath)) {
10950
- const existingContent = fs22.readFileSync(hookPath, "utf-8");
11097
+ const hookContent = fs23.readFileSync(bundledHookPath, "utf-8");
11098
+ if (fs23.existsSync(hookPath)) {
11099
+ const existingContent = fs23.readFileSync(hookPath, "utf-8");
10951
11100
  if (existingContent === hookContent) {
10952
11101
  continue;
10953
11102
  }
10954
11103
  }
10955
- fs22.writeFileSync(hookPath, hookContent, { mode: 493 });
11104
+ fs23.writeFileSync(hookPath, hookContent, { mode: 493 });
10956
11105
  console.log(`[Daemon] Installed git hook: ${hookName}`);
10957
11106
  } catch (error) {
10958
11107
  console.warn(`[Daemon] Failed to install ${hookName} hook:`, error instanceof Error ? error.message : error);
@@ -11290,7 +11439,7 @@ var Daemon = class _Daemon {
11290
11439
  console.log(`[Daemon] EP1002: Writing .env with ${Object.keys(envVars).length} variables`);
11291
11440
  writeEnvFile(worktreePath, envVars);
11292
11441
  }
11293
- const installCmd = getInstallCommand(worktreePath);
11442
+ const installCmd = getInstallCommand2(worktreePath);
11294
11443
  if (installCmd) {
11295
11444
  console.log(`[Daemon] EP1002: ${installCmd.description} (detected from ${installCmd.detectedFrom})`);
11296
11445
  console.log(`[Daemon] EP1002: Running: ${installCmd.command.join(" ")}`);
@@ -11344,7 +11493,7 @@ var Daemon = class _Daemon {
11344
11493
  console.warn(`[Daemon] EP964: File copy failed (non-fatal): ${copyResult.error}`);
11345
11494
  }
11346
11495
  }
11347
- const installCmd = getInstallCommand(worktreePath);
11496
+ const installCmd = getInstallCommand2(worktreePath);
11348
11497
  if (installCmd) {
11349
11498
  console.log(`[Daemon] EP986: ${installCmd.description} (detected from ${installCmd.detectedFrom})`);
11350
11499
  console.log(`[Daemon] EP986: Running: ${installCmd.command.join(" ")}`);
@@ -11956,8 +12105,8 @@ var Daemon = class _Daemon {
11956
12105
  await this.shutdown();
11957
12106
  try {
11958
12107
  const pidPath = getPidFilePath();
11959
- if (fs22.existsSync(pidPath)) {
11960
- fs22.unlinkSync(pidPath);
12108
+ if (fs23.existsSync(pidPath)) {
12109
+ fs23.unlinkSync(pidPath);
11961
12110
  console.log("[Daemon] PID file cleaned up");
11962
12111
  }
11963
12112
  } catch (error) {