episoda 0.2.40 → 0.2.42

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.
package/dist/index.js CHANGED
@@ -1552,15 +1552,15 @@ var require_git_executor = __commonJS({
1552
1552
  try {
1553
1553
  const { stdout: gitDir } = await execAsync("git rev-parse --git-dir", { cwd, timeout: 5e3 });
1554
1554
  const gitDirPath = gitDir.trim();
1555
- const fs15 = await Promise.resolve().then(() => __importStar(require("fs"))).then((m) => m.promises);
1555
+ const fs14 = await Promise.resolve().then(() => __importStar(require("fs"))).then((m) => m.promises);
1556
1556
  const rebaseMergePath = `${gitDirPath}/rebase-merge`;
1557
1557
  const rebaseApplyPath = `${gitDirPath}/rebase-apply`;
1558
1558
  try {
1559
- await fs15.access(rebaseMergePath);
1559
+ await fs14.access(rebaseMergePath);
1560
1560
  inRebase = true;
1561
1561
  } catch {
1562
1562
  try {
1563
- await fs15.access(rebaseApplyPath);
1563
+ await fs14.access(rebaseApplyPath);
1564
1564
  inRebase = true;
1565
1565
  } catch {
1566
1566
  inRebase = false;
@@ -1614,9 +1614,9 @@ var require_git_executor = __commonJS({
1614
1614
  error: validation.error || "UNKNOWN_ERROR"
1615
1615
  };
1616
1616
  }
1617
- const fs15 = await Promise.resolve().then(() => __importStar(require("fs"))).then((m) => m.promises);
1617
+ const fs14 = await Promise.resolve().then(() => __importStar(require("fs"))).then((m) => m.promises);
1618
1618
  try {
1619
- await fs15.access(command.path);
1619
+ await fs14.access(command.path);
1620
1620
  return {
1621
1621
  success: false,
1622
1622
  error: "WORKTREE_EXISTS",
@@ -1670,9 +1670,9 @@ var require_git_executor = __commonJS({
1670
1670
  */
1671
1671
  async executeWorktreeRemove(command, cwd, options) {
1672
1672
  try {
1673
- const fs15 = await Promise.resolve().then(() => __importStar(require("fs"))).then((m) => m.promises);
1673
+ const fs14 = await Promise.resolve().then(() => __importStar(require("fs"))).then((m) => m.promises);
1674
1674
  try {
1675
- await fs15.access(command.path);
1675
+ await fs14.access(command.path);
1676
1676
  } catch {
1677
1677
  return {
1678
1678
  success: false,
@@ -1707,7 +1707,7 @@ var require_git_executor = __commonJS({
1707
1707
  const result = await this.runGitCommand(args, cwd, options);
1708
1708
  if (result.success) {
1709
1709
  try {
1710
- await fs15.rm(command.path, { recursive: true, force: true });
1710
+ await fs14.rm(command.path, { recursive: true, force: true });
1711
1711
  } catch {
1712
1712
  }
1713
1713
  return {
@@ -1841,10 +1841,10 @@ var require_git_executor = __commonJS({
1841
1841
  */
1842
1842
  async executeCloneBare(command, options) {
1843
1843
  try {
1844
- const fs15 = await Promise.resolve().then(() => __importStar(require("fs"))).then((m) => m.promises);
1845
- const path17 = await Promise.resolve().then(() => __importStar(require("path")));
1844
+ const fs14 = await Promise.resolve().then(() => __importStar(require("fs"))).then((m) => m.promises);
1845
+ const path16 = await Promise.resolve().then(() => __importStar(require("path")));
1846
1846
  try {
1847
- await fs15.access(command.path);
1847
+ await fs14.access(command.path);
1848
1848
  return {
1849
1849
  success: false,
1850
1850
  error: "BRANCH_ALREADY_EXISTS",
@@ -1853,9 +1853,9 @@ var require_git_executor = __commonJS({
1853
1853
  };
1854
1854
  } catch {
1855
1855
  }
1856
- const parentDir = path17.dirname(command.path);
1856
+ const parentDir = path16.dirname(command.path);
1857
1857
  try {
1858
- await fs15.mkdir(parentDir, { recursive: true });
1858
+ await fs14.mkdir(parentDir, { recursive: true });
1859
1859
  } catch {
1860
1860
  }
1861
1861
  const { stdout, stderr } = await execAsync(
@@ -1903,22 +1903,22 @@ var require_git_executor = __commonJS({
1903
1903
  */
1904
1904
  async executeProjectInfo(cwd, options) {
1905
1905
  try {
1906
- const fs15 = await Promise.resolve().then(() => __importStar(require("fs"))).then((m) => m.promises);
1907
- const path17 = await Promise.resolve().then(() => __importStar(require("path")));
1906
+ const fs14 = await Promise.resolve().then(() => __importStar(require("fs"))).then((m) => m.promises);
1907
+ const path16 = await Promise.resolve().then(() => __importStar(require("path")));
1908
1908
  let currentPath = cwd;
1909
1909
  let projectPath = cwd;
1910
1910
  let bareRepoPath;
1911
1911
  for (let i = 0; i < 10; i++) {
1912
- const bareDir = path17.join(currentPath, ".bare");
1913
- const episodaDir = path17.join(currentPath, ".episoda");
1912
+ const bareDir = path16.join(currentPath, ".bare");
1913
+ const episodaDir = path16.join(currentPath, ".episoda");
1914
1914
  try {
1915
- await fs15.access(bareDir);
1916
- await fs15.access(episodaDir);
1915
+ await fs14.access(bareDir);
1916
+ await fs14.access(episodaDir);
1917
1917
  projectPath = currentPath;
1918
1918
  bareRepoPath = bareDir;
1919
1919
  break;
1920
1920
  } catch {
1921
- const parentPath = path17.dirname(currentPath);
1921
+ const parentPath = path16.dirname(currentPath);
1922
1922
  if (parentPath === currentPath) {
1923
1923
  break;
1924
1924
  }
@@ -2512,31 +2512,31 @@ var require_auth = __commonJS({
2512
2512
  exports2.loadConfig = loadConfig9;
2513
2513
  exports2.saveConfig = saveConfig3;
2514
2514
  exports2.validateToken = validateToken;
2515
- var fs15 = __importStar(require("fs"));
2516
- var path17 = __importStar(require("path"));
2515
+ var fs14 = __importStar(require("fs"));
2516
+ var path16 = __importStar(require("path"));
2517
2517
  var os4 = __importStar(require("os"));
2518
2518
  var child_process_1 = require("child_process");
2519
2519
  var DEFAULT_CONFIG_FILE = "config.json";
2520
2520
  function getConfigDir5() {
2521
- return process.env.EPISODA_CONFIG_DIR || path17.join(os4.homedir(), ".episoda");
2521
+ return process.env.EPISODA_CONFIG_DIR || path16.join(os4.homedir(), ".episoda");
2522
2522
  }
2523
2523
  function getConfigPath4(configPath) {
2524
2524
  if (configPath) {
2525
2525
  return configPath;
2526
2526
  }
2527
- return path17.join(getConfigDir5(), DEFAULT_CONFIG_FILE);
2527
+ return path16.join(getConfigDir5(), DEFAULT_CONFIG_FILE);
2528
2528
  }
2529
2529
  function ensureConfigDir(configPath) {
2530
- const dir = path17.dirname(configPath);
2531
- const isNew = !fs15.existsSync(dir);
2530
+ const dir = path16.dirname(configPath);
2531
+ const isNew = !fs14.existsSync(dir);
2532
2532
  if (isNew) {
2533
- fs15.mkdirSync(dir, { recursive: true, mode: 448 });
2533
+ fs14.mkdirSync(dir, { recursive: true, mode: 448 });
2534
2534
  }
2535
2535
  if (process.platform === "darwin") {
2536
- const nosyncPath = path17.join(dir, ".nosync");
2537
- if (isNew || !fs15.existsSync(nosyncPath)) {
2536
+ const nosyncPath = path16.join(dir, ".nosync");
2537
+ if (isNew || !fs14.existsSync(nosyncPath)) {
2538
2538
  try {
2539
- fs15.writeFileSync(nosyncPath, "", { mode: 384 });
2539
+ fs14.writeFileSync(nosyncPath, "", { mode: 384 });
2540
2540
  (0, child_process_1.execSync)(`xattr -w com.apple.fileprovider.ignore 1 "${dir}"`, {
2541
2541
  stdio: "ignore",
2542
2542
  timeout: 5e3
@@ -2548,11 +2548,11 @@ var require_auth = __commonJS({
2548
2548
  }
2549
2549
  async function loadConfig9(configPath) {
2550
2550
  const fullPath = getConfigPath4(configPath);
2551
- if (!fs15.existsSync(fullPath)) {
2551
+ if (!fs14.existsSync(fullPath)) {
2552
2552
  return null;
2553
2553
  }
2554
2554
  try {
2555
- const content = fs15.readFileSync(fullPath, "utf8");
2555
+ const content = fs14.readFileSync(fullPath, "utf8");
2556
2556
  const config = JSON.parse(content);
2557
2557
  return config;
2558
2558
  } catch (error) {
@@ -2565,7 +2565,7 @@ var require_auth = __commonJS({
2565
2565
  ensureConfigDir(fullPath);
2566
2566
  try {
2567
2567
  const content = JSON.stringify(config, null, 2);
2568
- fs15.writeFileSync(fullPath, content, { mode: 384 });
2568
+ fs14.writeFileSync(fullPath, content, { mode: 384 });
2569
2569
  } catch (error) {
2570
2570
  throw new Error(`Failed to save config: ${error instanceof Error ? error.message : String(error)}`);
2571
2571
  }
@@ -2681,211 +2681,9 @@ var require_dist = __commonJS({
2681
2681
  var import_commander = require("commander");
2682
2682
  var import_core18 = __toESM(require_dist());
2683
2683
 
2684
- // src/commands/dev.ts
2684
+ // src/commands/daemon.ts
2685
2685
  var import_core4 = __toESM(require_dist());
2686
2686
 
2687
- // src/framework-detector.ts
2688
- var fs = __toESM(require("fs"));
2689
- var path = __toESM(require("path"));
2690
- async function detectFramework(cwd = process.cwd()) {
2691
- const packageJsonPath = path.join(cwd, "package.json");
2692
- if (fs.existsSync(packageJsonPath)) {
2693
- const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"));
2694
- const scripts = packageJson.scripts || {};
2695
- if (packageJson.dependencies?.next || packageJson.devDependencies?.next) {
2696
- if (scripts.dev) {
2697
- return {
2698
- framework: "Next.js",
2699
- command: ["npm", "run", "dev"],
2700
- confidence: "high",
2701
- detectedFrom: "package.json (next dependency + dev script)"
2702
- };
2703
- }
2704
- return {
2705
- framework: "Next.js",
2706
- command: ["npx", "next", "dev"],
2707
- confidence: "medium",
2708
- detectedFrom: "package.json (next dependency)"
2709
- };
2710
- }
2711
- if (packageJson.dependencies?.react || packageJson.devDependencies?.react) {
2712
- if (scripts.dev) {
2713
- return {
2714
- framework: "React",
2715
- command: ["npm", "run", "dev"],
2716
- confidence: "high",
2717
- detectedFrom: "package.json (react + dev script)"
2718
- };
2719
- }
2720
- if (scripts.start) {
2721
- return {
2722
- framework: "React",
2723
- command: ["npm", "start"],
2724
- confidence: "high",
2725
- detectedFrom: "package.json (react + start script)"
2726
- };
2727
- }
2728
- }
2729
- if (packageJson.dependencies?.express) {
2730
- if (scripts.dev) {
2731
- return {
2732
- framework: "Express",
2733
- command: ["npm", "run", "dev"],
2734
- confidence: "high",
2735
- detectedFrom: "package.json (express + dev script)"
2736
- };
2737
- }
2738
- if (scripts.start) {
2739
- return {
2740
- framework: "Express",
2741
- command: ["npm", "start"],
2742
- confidence: "medium",
2743
- detectedFrom: "package.json (express + start script)"
2744
- };
2745
- }
2746
- }
2747
- if (packageJson.dependencies?.vue || packageJson.devDependencies?.vue) {
2748
- if (scripts.dev) {
2749
- return {
2750
- framework: "Vue",
2751
- command: ["npm", "run", "dev"],
2752
- confidence: "high",
2753
- detectedFrom: "package.json (vue + dev script)"
2754
- };
2755
- }
2756
- if (scripts.serve) {
2757
- return {
2758
- framework: "Vue",
2759
- command: ["npm", "run", "serve"],
2760
- confidence: "high",
2761
- detectedFrom: "package.json (vue + serve script)"
2762
- };
2763
- }
2764
- }
2765
- if (scripts.dev) {
2766
- return {
2767
- framework: "Node.js",
2768
- command: ["npm", "run", "dev"],
2769
- confidence: "medium",
2770
- detectedFrom: "package.json (dev script)"
2771
- };
2772
- }
2773
- if (scripts.start) {
2774
- return {
2775
- framework: "Node.js",
2776
- command: ["npm", "start"],
2777
- confidence: "low",
2778
- detectedFrom: "package.json (start script)"
2779
- };
2780
- }
2781
- }
2782
- const requirementsPath = path.join(cwd, "requirements.txt");
2783
- if (fs.existsSync(requirementsPath)) {
2784
- const requirements = fs.readFileSync(requirementsPath, "utf-8");
2785
- if (requirements.includes("Django") || requirements.includes("django")) {
2786
- const managePy = path.join(cwd, "manage.py");
2787
- if (fs.existsSync(managePy)) {
2788
- return {
2789
- framework: "Django",
2790
- command: ["python", "manage.py", "runserver"],
2791
- confidence: "high",
2792
- detectedFrom: "requirements.txt (Django) + manage.py"
2793
- };
2794
- }
2795
- return {
2796
- framework: "Django",
2797
- command: ["python", "manage.py", "runserver"],
2798
- confidence: "medium",
2799
- detectedFrom: "requirements.txt (Django)"
2800
- };
2801
- }
2802
- if (requirements.includes("Flask") || requirements.includes("flask")) {
2803
- const appFiles = ["app.py", "application.py", "wsgi.py"];
2804
- for (const file of appFiles) {
2805
- if (fs.existsSync(path.join(cwd, file))) {
2806
- return {
2807
- framework: "Flask",
2808
- command: ["flask", "run"],
2809
- confidence: "high",
2810
- detectedFrom: `requirements.txt (Flask) + ${file}`
2811
- };
2812
- }
2813
- }
2814
- return {
2815
- framework: "Flask",
2816
- command: ["flask", "run"],
2817
- confidence: "medium",
2818
- detectedFrom: "requirements.txt (Flask)"
2819
- };
2820
- }
2821
- if (requirements.includes("fastapi") || requirements.includes("uvicorn")) {
2822
- return {
2823
- framework: "FastAPI",
2824
- command: ["uvicorn", "main:app", "--reload"],
2825
- confidence: "medium",
2826
- detectedFrom: "requirements.txt (fastapi/uvicorn)"
2827
- };
2828
- }
2829
- }
2830
- const gemfilePath = path.join(cwd, "Gemfile");
2831
- if (fs.existsSync(gemfilePath)) {
2832
- const gemfile = fs.readFileSync(gemfilePath, "utf-8");
2833
- if (gemfile.includes("rails")) {
2834
- return {
2835
- framework: "Rails",
2836
- command: ["rails", "server"],
2837
- confidence: "high",
2838
- detectedFrom: "Gemfile (rails)"
2839
- };
2840
- }
2841
- if (gemfile.includes("sinatra")) {
2842
- return {
2843
- framework: "Sinatra",
2844
- command: ["ruby", "app.rb"],
2845
- confidence: "medium",
2846
- detectedFrom: "Gemfile (sinatra)"
2847
- };
2848
- }
2849
- }
2850
- const goModPath = path.join(cwd, "go.mod");
2851
- if (fs.existsSync(goModPath)) {
2852
- return {
2853
- framework: "Go",
2854
- command: ["go", "run", "."],
2855
- confidence: "medium",
2856
- detectedFrom: "go.mod"
2857
- };
2858
- }
2859
- const cargoTomlPath = path.join(cwd, "Cargo.toml");
2860
- if (fs.existsSync(cargoTomlPath)) {
2861
- return {
2862
- framework: "Rust",
2863
- command: ["cargo", "run"],
2864
- confidence: "medium",
2865
- detectedFrom: "Cargo.toml"
2866
- };
2867
- }
2868
- return null;
2869
- }
2870
- async function resolveDevCommand(providedCommand, cwd = process.cwd()) {
2871
- if (providedCommand && providedCommand.length > 0) {
2872
- return { command: providedCommand, detection: null };
2873
- }
2874
- const detection = await detectFramework(cwd);
2875
- if (detection) {
2876
- return { command: detection.command, detection };
2877
- }
2878
- return {
2879
- command: ["npm", "run", "dev"],
2880
- detection: {
2881
- framework: "Unknown",
2882
- command: ["npm", "run", "dev"],
2883
- confidence: "low",
2884
- detectedFrom: "default fallback"
2885
- }
2886
- };
2887
- }
2888
-
2889
2687
  // src/output.ts
2890
2688
  var import_chalk = __toESM(require("chalk"));
2891
2689
  var import_ora = __toESM(require("ora"));
@@ -2904,17 +2702,10 @@ var status = {
2904
2702
  process.stdout.write(`\r${import_chalk.default.blue("\u23F3")} ${message}`);
2905
2703
  }
2906
2704
  };
2907
- function printFrameworkDetection(framework, command, confidence) {
2908
- console.log(import_chalk.default.bold("\n\u{1F50D} Framework Detection"));
2909
- console.log(import_chalk.default.cyan(" Framework:"), framework);
2910
- console.log(import_chalk.default.cyan(" Command:"), command.join(" "));
2911
- console.log(import_chalk.default.cyan(" Confidence:"), confidence);
2912
- console.log();
2913
- }
2914
2705
 
2915
2706
  // src/daemon/daemon-manager.ts
2916
- var fs2 = __toESM(require("fs"));
2917
- var path2 = __toESM(require("path"));
2707
+ var fs = __toESM(require("fs"));
2708
+ var path = __toESM(require("path"));
2918
2709
  var import_child_process = require("child_process");
2919
2710
  var import_core = __toESM(require_dist());
2920
2711
  function killAllEpisodaProcesses() {
@@ -2946,13 +2737,13 @@ function killAllEpisodaProcesses() {
2946
2737
  (0, import_child_process.execSync)("sleep 0.5", { timeout: 2e3 });
2947
2738
  }
2948
2739
  const configDir = (0, import_core.getConfigDir)();
2949
- const pidPath = path2.join(configDir, "daemon.pid");
2950
- const sockPath = path2.join(configDir, "daemon.sock");
2951
- if (fs2.existsSync(pidPath)) {
2952
- fs2.unlinkSync(pidPath);
2740
+ const pidPath = path.join(configDir, "daemon.pid");
2741
+ const sockPath = path.join(configDir, "daemon.sock");
2742
+ if (fs.existsSync(pidPath)) {
2743
+ fs.unlinkSync(pidPath);
2953
2744
  }
2954
- if (fs2.existsSync(sockPath)) {
2955
- fs2.unlinkSync(sockPath);
2745
+ if (fs.existsSync(sockPath)) {
2746
+ fs.unlinkSync(sockPath);
2956
2747
  }
2957
2748
  } catch (error) {
2958
2749
  console.warn("[Cleanup] Error during process cleanup:", error instanceof Error ? error.message : error);
@@ -2960,25 +2751,25 @@ function killAllEpisodaProcesses() {
2960
2751
  return killedCount;
2961
2752
  }
2962
2753
  function getPidFilePath() {
2963
- return path2.join((0, import_core.getConfigDir)(), "daemon.pid");
2754
+ return path.join((0, import_core.getConfigDir)(), "daemon.pid");
2964
2755
  }
2965
2756
  function isDaemonRunning() {
2966
2757
  const pidPath = getPidFilePath();
2967
2758
  try {
2968
- if (!fs2.existsSync(pidPath)) {
2759
+ if (!fs.existsSync(pidPath)) {
2969
2760
  return null;
2970
2761
  }
2971
- const pidStr = fs2.readFileSync(pidPath, "utf-8").trim();
2762
+ const pidStr = fs.readFileSync(pidPath, "utf-8").trim();
2972
2763
  const pid = parseInt(pidStr, 10);
2973
2764
  if (isNaN(pid)) {
2974
- fs2.unlinkSync(pidPath);
2765
+ fs.unlinkSync(pidPath);
2975
2766
  return null;
2976
2767
  }
2977
2768
  try {
2978
2769
  process.kill(pid, 0);
2979
2770
  return pid;
2980
2771
  } catch (error) {
2981
- fs2.unlinkSync(pidPath);
2772
+ fs.unlinkSync(pidPath);
2982
2773
  return null;
2983
2774
  }
2984
2775
  } catch (error) {
@@ -2992,15 +2783,15 @@ async function startDaemon() {
2992
2783
  throw new Error(`Daemon already running (PID: ${existingPid})`);
2993
2784
  }
2994
2785
  const configDir = (0, import_core.getConfigDir)();
2995
- if (!fs2.existsSync(configDir)) {
2996
- fs2.mkdirSync(configDir, { recursive: true });
2786
+ if (!fs.existsSync(configDir)) {
2787
+ fs.mkdirSync(configDir, { recursive: true });
2997
2788
  }
2998
- const daemonScript = path2.join(__dirname, "daemon", "daemon-process.js");
2999
- if (!fs2.existsSync(daemonScript)) {
2789
+ const daemonScript = path.join(__dirname, "daemon", "daemon-process.js");
2790
+ if (!fs.existsSync(daemonScript)) {
3000
2791
  throw new Error(`Daemon script not found: ${daemonScript}. Make sure CLI is built.`);
3001
2792
  }
3002
- const logPath = path2.join(configDir, "daemon.log");
3003
- const logFd = fs2.openSync(logPath, "a");
2793
+ const logPath = path.join(configDir, "daemon.log");
2794
+ const logFd = fs.openSync(logPath, "a");
3004
2795
  const child = (0, import_child_process.spawn)("node", [daemonScript], {
3005
2796
  detached: true,
3006
2797
  // Run independently of parent
@@ -3015,7 +2806,7 @@ async function startDaemon() {
3015
2806
  child.unref();
3016
2807
  const pid = child.pid;
3017
2808
  const pidPath = getPidFilePath();
3018
- fs2.writeFileSync(pidPath, pid.toString(), "utf-8");
2809
+ fs.writeFileSync(pidPath, pid.toString(), "utf-8");
3019
2810
  await new Promise((resolve5) => setTimeout(resolve5, 500));
3020
2811
  const runningPid = isDaemonRunning();
3021
2812
  if (!runningPid) {
@@ -3027,8 +2818,8 @@ async function stopDaemon(timeout = 5e3) {
3027
2818
  const pid = isDaemonRunning();
3028
2819
  if (!pid) {
3029
2820
  const pidPath = getPidFilePath();
3030
- if (fs2.existsSync(pidPath)) {
3031
- fs2.unlinkSync(pidPath);
2821
+ if (fs.existsSync(pidPath)) {
2822
+ fs.unlinkSync(pidPath);
3032
2823
  }
3033
2824
  return false;
3034
2825
  }
@@ -3041,8 +2832,8 @@ async function stopDaemon(timeout = 5e3) {
3041
2832
  await new Promise((resolve5) => setTimeout(resolve5, 100));
3042
2833
  } catch (error) {
3043
2834
  const pidPath2 = getPidFilePath();
3044
- if (fs2.existsSync(pidPath2)) {
3045
- fs2.unlinkSync(pidPath2);
2835
+ if (fs.existsSync(pidPath2)) {
2836
+ fs.unlinkSync(pidPath2);
3046
2837
  }
3047
2838
  return true;
3048
2839
  }
@@ -3050,8 +2841,8 @@ async function stopDaemon(timeout = 5e3) {
3050
2841
  console.warn(`Daemon didn't stop gracefully, forcing shutdown (PID: ${pid})`);
3051
2842
  process.kill(pid, "SIGKILL");
3052
2843
  const pidPath = getPidFilePath();
3053
- if (fs2.existsSync(pidPath)) {
3054
- fs2.unlinkSync(pidPath);
2844
+ if (fs.existsSync(pidPath)) {
2845
+ fs.unlinkSync(pidPath);
3055
2846
  }
3056
2847
  return true;
3057
2848
  } catch (error) {
@@ -3062,10 +2853,10 @@ async function stopDaemon(timeout = 5e3) {
3062
2853
 
3063
2854
  // src/ipc/ipc-client.ts
3064
2855
  var net = __toESM(require("net"));
3065
- var path3 = __toESM(require("path"));
2856
+ var path2 = __toESM(require("path"));
3066
2857
  var crypto = __toESM(require("crypto"));
3067
2858
  var import_core2 = __toESM(require_dist());
3068
- var getSocketPath = () => path3.join((0, import_core2.getConfigDir)(), "daemon.sock");
2859
+ var getSocketPath = () => path2.join((0, import_core2.getConfigDir)(), "daemon.sock");
3069
2860
  var DEFAULT_TIMEOUT = 15e3;
3070
2861
  async function sendCommand(command, params, timeout = DEFAULT_TIMEOUT) {
3071
2862
  return new Promise((resolve5, reject) => {
@@ -3154,40 +2945,14 @@ async function getDevServerStatus() {
3154
2945
  return await sendCommand("dev-server-status");
3155
2946
  }
3156
2947
 
3157
- // src/commands/dev.ts
2948
+ // src/commands/daemon.ts
3158
2949
  var import_child_process3 = require("child_process");
3159
- var path6 = __toESM(require("path"));
3160
- var fs5 = __toESM(require("fs"));
3161
-
3162
- // src/utils/port-check.ts
3163
- var net2 = __toESM(require("net"));
3164
- async function isPortInUse(port) {
3165
- return new Promise((resolve5) => {
3166
- const server = net2.createServer();
3167
- server.once("error", (err) => {
3168
- if (err.code === "EADDRINUSE") {
3169
- resolve5(true);
3170
- } else {
3171
- resolve5(false);
3172
- }
3173
- });
3174
- server.once("listening", () => {
3175
- server.close();
3176
- resolve5(false);
3177
- });
3178
- server.listen(port);
3179
- });
3180
- }
3181
- function getServerPort() {
3182
- if (process.env.PORT) {
3183
- return parseInt(process.env.PORT, 10);
3184
- }
3185
- return 3e3;
3186
- }
2950
+ var path5 = __toESM(require("path"));
2951
+ var fs4 = __toESM(require("fs"));
3187
2952
 
3188
2953
  // src/daemon/worktree-manager.ts
3189
- var fs3 = __toESM(require("fs"));
3190
- var path4 = __toESM(require("path"));
2954
+ var fs2 = __toESM(require("fs"));
2955
+ var path3 = __toESM(require("path"));
3191
2956
  var import_core3 = __toESM(require_dist());
3192
2957
  function validateModuleUid(moduleUid) {
3193
2958
  if (!moduleUid || typeof moduleUid !== "string" || !moduleUid.trim()) {
@@ -3211,8 +2976,8 @@ var WorktreeManager = class _WorktreeManager {
3211
2976
  // ============================================================
3212
2977
  this.lockPath = "";
3213
2978
  this.projectRoot = projectRoot;
3214
- this.bareRepoPath = path4.join(projectRoot, ".bare");
3215
- this.configPath = path4.join(projectRoot, ".episoda", "config.json");
2979
+ this.bareRepoPath = path3.join(projectRoot, ".bare");
2980
+ this.configPath = path3.join(projectRoot, ".episoda", "config.json");
3216
2981
  this.gitExecutor = new import_core3.GitExecutor();
3217
2982
  }
3218
2983
  /**
@@ -3221,10 +2986,10 @@ var WorktreeManager = class _WorktreeManager {
3221
2986
  * @returns true if valid project, false otherwise
3222
2987
  */
3223
2988
  async initialize() {
3224
- if (!fs3.existsSync(this.bareRepoPath)) {
2989
+ if (!fs2.existsSync(this.bareRepoPath)) {
3225
2990
  return false;
3226
2991
  }
3227
- if (!fs3.existsSync(this.configPath)) {
2992
+ if (!fs2.existsSync(this.configPath)) {
3228
2993
  return false;
3229
2994
  }
3230
2995
  try {
@@ -3271,8 +3036,8 @@ var WorktreeManager = class _WorktreeManager {
3271
3036
  */
3272
3037
  static async createProject(projectRoot, repoUrl, projectId, workspaceSlug, projectSlug) {
3273
3038
  const manager = new _WorktreeManager(projectRoot);
3274
- const episodaDir = path4.join(projectRoot, ".episoda");
3275
- fs3.mkdirSync(episodaDir, { recursive: true });
3039
+ const episodaDir = path3.join(projectRoot, ".episoda");
3040
+ fs2.mkdirSync(episodaDir, { recursive: true });
3276
3041
  const cloneResult = await manager.gitExecutor.execute({
3277
3042
  action: "clone_bare",
3278
3043
  url: repoUrl,
@@ -3303,7 +3068,7 @@ var WorktreeManager = class _WorktreeManager {
3303
3068
  error: `Invalid module UID: "${moduleUid}" - contains disallowed characters`
3304
3069
  };
3305
3070
  }
3306
- const worktreePath = path4.join(this.projectRoot, moduleUid);
3071
+ const worktreePath = path3.join(this.projectRoot, moduleUid);
3307
3072
  const lockAcquired = await this.acquireLock();
3308
3073
  if (!lockAcquired) {
3309
3074
  return {
@@ -3485,7 +3250,7 @@ var WorktreeManager = class _WorktreeManager {
3485
3250
  let prunedCount = 0;
3486
3251
  await this.updateConfigSafe((config) => {
3487
3252
  const initialCount = config.worktrees.length;
3488
- config.worktrees = config.worktrees.filter((w) => fs3.existsSync(w.worktreePath));
3253
+ config.worktrees = config.worktrees.filter((w) => fs2.existsSync(w.worktreePath));
3489
3254
  prunedCount = initialCount - config.worktrees.length;
3490
3255
  return config;
3491
3256
  });
@@ -3566,16 +3331,16 @@ var WorktreeManager = class _WorktreeManager {
3566
3331
  const retryInterval = 50;
3567
3332
  while (Date.now() - startTime < timeoutMs) {
3568
3333
  try {
3569
- fs3.writeFileSync(lockPath, String(process.pid), { flag: "wx" });
3334
+ fs2.writeFileSync(lockPath, String(process.pid), { flag: "wx" });
3570
3335
  return true;
3571
3336
  } catch (err) {
3572
3337
  if (err.code === "EEXIST") {
3573
3338
  try {
3574
- const stats = fs3.statSync(lockPath);
3339
+ const stats = fs2.statSync(lockPath);
3575
3340
  const lockAge = Date.now() - stats.mtimeMs;
3576
3341
  if (lockAge > 3e4) {
3577
3342
  try {
3578
- const lockContent = fs3.readFileSync(lockPath, "utf-8").trim();
3343
+ const lockContent = fs2.readFileSync(lockPath, "utf-8").trim();
3579
3344
  const lockPid = parseInt(lockContent, 10);
3580
3345
  if (!isNaN(lockPid) && this.isProcessRunning(lockPid)) {
3581
3346
  await new Promise((resolve5) => setTimeout(resolve5, retryInterval));
@@ -3584,7 +3349,7 @@ var WorktreeManager = class _WorktreeManager {
3584
3349
  } catch {
3585
3350
  }
3586
3351
  try {
3587
- fs3.unlinkSync(lockPath);
3352
+ fs2.unlinkSync(lockPath);
3588
3353
  } catch {
3589
3354
  }
3590
3355
  continue;
@@ -3605,16 +3370,16 @@ var WorktreeManager = class _WorktreeManager {
3605
3370
  */
3606
3371
  releaseLock() {
3607
3372
  try {
3608
- fs3.unlinkSync(this.getLockPath());
3373
+ fs2.unlinkSync(this.getLockPath());
3609
3374
  } catch {
3610
3375
  }
3611
3376
  }
3612
3377
  readConfig() {
3613
3378
  try {
3614
- if (!fs3.existsSync(this.configPath)) {
3379
+ if (!fs2.existsSync(this.configPath)) {
3615
3380
  return null;
3616
3381
  }
3617
- const content = fs3.readFileSync(this.configPath, "utf-8");
3382
+ const content = fs2.readFileSync(this.configPath, "utf-8");
3618
3383
  return JSON.parse(content);
3619
3384
  } catch (error) {
3620
3385
  console.error("[WorktreeManager] Failed to read config:", error);
@@ -3623,11 +3388,11 @@ var WorktreeManager = class _WorktreeManager {
3623
3388
  }
3624
3389
  writeConfig(config) {
3625
3390
  try {
3626
- const dir = path4.dirname(this.configPath);
3627
- if (!fs3.existsSync(dir)) {
3628
- fs3.mkdirSync(dir, { recursive: true });
3391
+ const dir = path3.dirname(this.configPath);
3392
+ if (!fs2.existsSync(dir)) {
3393
+ fs2.mkdirSync(dir, { recursive: true });
3629
3394
  }
3630
- fs3.writeFileSync(this.configPath, JSON.stringify(config, null, 2), "utf-8");
3395
+ fs2.writeFileSync(this.configPath, JSON.stringify(config, null, 2), "utf-8");
3631
3396
  } catch (error) {
3632
3397
  console.error("[WorktreeManager] Failed to write config:", error);
3633
3398
  throw error;
@@ -3708,14 +3473,14 @@ var WorktreeManager = class _WorktreeManager {
3708
3473
  }
3709
3474
  try {
3710
3475
  for (const file of files) {
3711
- const srcPath = path4.join(mainWorktree.worktreePath, file);
3712
- const destPath = path4.join(worktree.worktreePath, file);
3713
- if (fs3.existsSync(srcPath)) {
3714
- const destDir = path4.dirname(destPath);
3715
- if (!fs3.existsSync(destDir)) {
3716
- fs3.mkdirSync(destDir, { recursive: true });
3476
+ const srcPath = path3.join(mainWorktree.worktreePath, file);
3477
+ const destPath = path3.join(worktree.worktreePath, file);
3478
+ if (fs2.existsSync(srcPath)) {
3479
+ const destDir = path3.dirname(destPath);
3480
+ if (!fs2.existsSync(destDir)) {
3481
+ fs2.mkdirSync(destDir, { recursive: true });
3717
3482
  }
3718
- fs3.copyFileSync(srcPath, destPath);
3483
+ fs2.copyFileSync(srcPath, destPath);
3719
3484
  console.log(`[WorktreeManager] EP964: Copied ${file} to ${moduleUid} (deprecated)`);
3720
3485
  } else {
3721
3486
  console.log(`[WorktreeManager] EP964: Skipped ${file} (not found in main)`);
@@ -3798,30 +3563,30 @@ var WorktreeManager = class _WorktreeManager {
3798
3563
  }
3799
3564
  };
3800
3565
  function getEpisodaRoot() {
3801
- return process.env.EPISODA_ROOT || path4.join(require("os").homedir(), "episoda");
3566
+ return process.env.EPISODA_ROOT || path3.join(require("os").homedir(), "episoda");
3802
3567
  }
3803
3568
  function getProjectPath(workspaceSlug, projectSlug) {
3804
- return path4.join(getEpisodaRoot(), workspaceSlug, projectSlug);
3569
+ return path3.join(getEpisodaRoot(), workspaceSlug, projectSlug);
3805
3570
  }
3806
3571
  async function isWorktreeProject(projectRoot) {
3807
3572
  const manager = new WorktreeManager(projectRoot);
3808
3573
  return manager.initialize();
3809
3574
  }
3810
3575
  async function findProjectRoot(startPath) {
3811
- let current = path4.resolve(startPath);
3576
+ let current = path3.resolve(startPath);
3812
3577
  const episodaRoot = getEpisodaRoot();
3813
3578
  if (!current.startsWith(episodaRoot)) {
3814
3579
  return null;
3815
3580
  }
3816
3581
  for (let i = 0; i < 10; i++) {
3817
- const bareDir = path4.join(current, ".bare");
3818
- const episodaDir = path4.join(current, ".episoda");
3819
- if (fs3.existsSync(bareDir) && fs3.existsSync(episodaDir)) {
3582
+ const bareDir = path3.join(current, ".bare");
3583
+ const episodaDir = path3.join(current, ".episoda");
3584
+ if (fs2.existsSync(bareDir) && fs2.existsSync(episodaDir)) {
3820
3585
  if (await isWorktreeProject(current)) {
3821
3586
  return current;
3822
3587
  }
3823
3588
  }
3824
- const parent = path4.dirname(current);
3589
+ const parent = path3.dirname(current);
3825
3590
  if (parent === current) {
3826
3591
  break;
3827
3592
  }
@@ -3859,7 +3624,7 @@ async function fetchProjectPath(config, projectId) {
3859
3624
  return null;
3860
3625
  }
3861
3626
  }
3862
- async function syncProjectPath(config, projectId, path17) {
3627
+ async function syncProjectPath(config, projectId, path16) {
3863
3628
  if (!config.device_id || !config.access_token) {
3864
3629
  return false;
3865
3630
  }
@@ -3872,7 +3637,7 @@ async function syncProjectPath(config, projectId, path17) {
3872
3637
  "Authorization": `Bearer ${config.access_token}`,
3873
3638
  "Content-Type": "application/json"
3874
3639
  },
3875
- body: JSON.stringify({ path: path17 })
3640
+ body: JSON.stringify({ path: path16 })
3876
3641
  });
3877
3642
  if (!response.ok) {
3878
3643
  console.debug(`[MachineSettings] syncProjectPath failed: ${response.status} ${response.statusText}`);
@@ -3885,22 +3650,22 @@ async function syncProjectPath(config, projectId, path17) {
3885
3650
  }
3886
3651
 
3887
3652
  // src/utils/bootstrap.ts
3888
- var fs4 = __toESM(require("fs"));
3889
- var path5 = __toESM(require("path"));
3653
+ var fs3 = __toESM(require("fs"));
3654
+ var path4 = __toESM(require("path"));
3890
3655
  var import_child_process2 = require("child_process");
3891
3656
  async function extractBootstrapScripts(bareRepoPath, projectPath) {
3892
- const scriptsDir = path5.join(projectPath, ".episoda", "scripts");
3893
- const scriptPath = path5.join(scriptsDir, "api-helper.sh");
3894
- if (fs4.existsSync(scriptPath)) {
3657
+ const scriptsDir = path4.join(projectPath, ".episoda", "scripts");
3658
+ const scriptPath = path4.join(scriptsDir, "api-helper.sh");
3659
+ if (fs3.existsSync(scriptPath)) {
3895
3660
  return false;
3896
3661
  }
3897
- fs4.mkdirSync(scriptsDir, { recursive: true });
3662
+ fs3.mkdirSync(scriptsDir, { recursive: true });
3898
3663
  try {
3899
3664
  const scriptContent = (0, import_child_process2.execSync)(
3900
3665
  `git --git-dir="${bareRepoPath}" show main:scripts/api-helper.sh`,
3901
3666
  { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
3902
3667
  );
3903
- fs4.writeFileSync(scriptPath, scriptContent, { mode: 493 });
3668
+ fs3.writeFileSync(scriptPath, scriptContent, { mode: 493 });
3904
3669
  return true;
3905
3670
  } catch (error) {
3906
3671
  console.log("[bootstrap] Could not extract api-helper.sh:", error);
@@ -3908,7 +3673,7 @@ async function extractBootstrapScripts(bareRepoPath, projectPath) {
3908
3673
  }
3909
3674
  }
3910
3675
 
3911
- // src/commands/dev.ts
3676
+ // src/commands/daemon.ts
3912
3677
  var CONNECTION_MAX_RETRIES = 3;
3913
3678
  function findGitRoot(startDir) {
3914
3679
  try {
@@ -3922,7 +3687,7 @@ function findGitRoot(startDir) {
3922
3687
  return null;
3923
3688
  }
3924
3689
  }
3925
- async function devCommand(options = {}) {
3690
+ async function daemonCommand(options = {}) {
3926
3691
  try {
3927
3692
  const config = await (0, import_core4.loadConfig)();
3928
3693
  if (!config || !config.access_token || !config.project_id) {
@@ -3956,8 +3721,6 @@ async function devCommand(options = {}) {
3956
3721
  status.debug("Daemon not reachable via IPC, restarting...");
3957
3722
  needsRestart = true;
3958
3723
  }
3959
- } else {
3960
- needsRestart = false;
3961
3724
  }
3962
3725
  if (needsRestart) {
3963
3726
  const killedCount = killAllEpisodaProcesses();
@@ -3968,22 +3731,18 @@ async function devCommand(options = {}) {
3968
3731
  }
3969
3732
  let projectPath;
3970
3733
  const serverPath = await fetchProjectPath(config, config.project_id);
3971
- if (serverPath && fs5.existsSync(serverPath)) {
3734
+ if (serverPath && fs4.existsSync(serverPath)) {
3972
3735
  projectPath = serverPath;
3973
3736
  status.debug(`Using server-synced project path: ${projectPath}`);
3974
3737
  } else {
3975
3738
  const detectedRoot = findGitRoot(options.cwd || process.cwd());
3976
- projectPath = detectedRoot || path6.resolve(options.cwd || process.cwd());
3739
+ projectPath = detectedRoot || path5.resolve(options.cwd || process.cwd());
3977
3740
  if (detectedRoot) {
3978
3741
  status.debug(`Detected project root: ${projectPath}`);
3979
3742
  } else {
3980
3743
  status.warning(`Could not detect git root, using: ${projectPath}`);
3981
3744
  }
3982
- syncProjectPath(config, config.project_id, projectPath).then((synced) => {
3983
- if (synced) {
3984
- status.debug("Project path synced to server");
3985
- }
3986
- }).catch(() => {
3745
+ syncProjectPath(config, config.project_id, projectPath).catch(() => {
3987
3746
  });
3988
3747
  }
3989
3748
  const isWorktree = await isWorktreeProject(projectPath);
@@ -3994,10 +3753,10 @@ async function devCommand(options = {}) {
3994
3753
  status.info("");
3995
3754
  process.exit(1);
3996
3755
  }
3997
- const bareRepoPath = path6.join(projectPath, ".bare");
3756
+ const bareRepoPath = path5.join(projectPath, ".bare");
3998
3757
  const scriptsExtracted = await extractBootstrapScripts(bareRepoPath, projectPath);
3999
3758
  if (scriptsExtracted) {
4000
- status.success("\u2713 Bootstrap scripts extracted");
3759
+ status.success("Bootstrap scripts extracted");
4001
3760
  }
4002
3761
  let daemonPid = isDaemonRunning();
4003
3762
  if (!daemonPid) {
@@ -4014,10 +3773,10 @@ async function devCommand(options = {}) {
4014
3773
  }
4015
3774
  const reachable = await isDaemonReachable();
4016
3775
  if (!reachable) {
4017
- status.error("Daemon is running but not responding. Try: episoda stop && episoda dev");
3776
+ status.error("Daemon is running but not responding. Try: episoda stop && episoda daemon");
4018
3777
  process.exit(1);
4019
3778
  }
4020
- status.info(`Connecting project to Episoda...`);
3779
+ status.info("Connecting project to Episoda...");
4021
3780
  let connected = false;
4022
3781
  let lastError;
4023
3782
  for (let retry = 0; retry < CONNECTION_MAX_RETRIES && !connected; retry++) {
@@ -4042,41 +3801,25 @@ async function devCommand(options = {}) {
4042
3801
  process.exit(1);
4043
3802
  }
4044
3803
  status.success("Connected to Episoda");
4045
- let command;
4046
- let detection;
4047
- let connectionOnlyMode = false;
4048
- if (options.command && options.command.length === 0) {
4049
- connectionOnlyMode = true;
4050
- status.debug("Connection-only mode (explicit)");
4051
- } else if (!options.command) {
4052
- const serverPort = getServerPort();
4053
- const portInUse = await isPortInUse(serverPort);
4054
- if (portInUse) {
4055
- connectionOnlyMode = true;
4056
- status.info(`Server already running on port ${serverPort}`);
4057
- status.info("Connecting to existing server...");
4058
- }
4059
- }
4060
- if (!connectionOnlyMode) {
4061
- try {
4062
- const result = await resolveDevCommand(options.command || null, projectPath);
4063
- command = result.command;
4064
- detection = result.detection;
4065
- if (detection && !options.command) {
4066
- printFrameworkDetection(detection.framework, detection.command, detection.confidence);
4067
- }
4068
- } catch (error) {
4069
- status.debug("No dev command detected");
4070
- command = void 0;
4071
- }
4072
- }
4073
- if (command && command.length > 0) {
4074
- await runDevServer(command, projectPath, options.autoRestart ?? false);
3804
+ if (options.background) {
3805
+ status.info("");
3806
+ status.info("Daemon running in background.");
3807
+ status.info("Use `episoda status` to check connection.");
3808
+ status.info("Use `episoda stop` to stop the daemon.");
3809
+ process.exit(0);
4075
3810
  } else {
4076
3811
  status.info("");
4077
- status.info("Connected! Git operations will be executed by Episoda.");
4078
- status.info("Press Ctrl+C to disconnect.");
3812
+ status.info("Daemon connected! Dev servers start automatically when you begin work on a module.");
3813
+ status.info("Press Ctrl+C to disconnect (daemon continues in background).");
4079
3814
  status.info("");
3815
+ const shutdownHandler = (signal) => {
3816
+ status.info(`
3817
+ Received ${signal}. Daemon continues running in background.`);
3818
+ status.info("Use `episoda stop` to fully stop the daemon.");
3819
+ process.exit(0);
3820
+ };
3821
+ process.on("SIGTERM", () => shutdownHandler("SIGTERM"));
3822
+ process.on("SIGINT", () => shutdownHandler("SIGINT"));
4080
3823
  await new Promise(() => {
4081
3824
  });
4082
3825
  }
@@ -4085,73 +3828,17 @@ async function devCommand(options = {}) {
4085
3828
  process.exit(1);
4086
3829
  }
4087
3830
  }
4088
- async function runDevServer(command, cwd, autoRestart) {
4089
- let devProcess;
4090
- let restartCount = 0;
4091
- let shuttingDown = false;
4092
- const startServer = () => {
4093
- status.info(`Starting dev server: ${command.join(" ")}`);
4094
- devProcess = (0, import_child_process3.spawn)(command[0], command.slice(1), {
4095
- cwd,
4096
- stdio: ["inherit", "inherit", "inherit"],
4097
- shell: true
4098
- });
4099
- devProcess.on("exit", (code, signal) => {
4100
- if (shuttingDown) {
4101
- status.info("Dev server stopped");
4102
- return;
4103
- }
4104
- if (code === 0) {
4105
- status.success("Dev server exited successfully");
4106
- } else {
4107
- status.error(`Dev server exited with code ${code}${signal ? ` (signal: ${signal})` : ""}`);
4108
- }
4109
- if (autoRestart && !shuttingDown) {
4110
- restartCount++;
4111
- status.info(`Auto-restarting dev server (attempt ${restartCount})...`);
4112
- setTimeout(() => {
4113
- startServer();
4114
- }, 2e3);
4115
- } else if (!shuttingDown) {
4116
- status.info("");
4117
- status.info("Dev server stopped, but daemon remains connected.");
4118
- status.info("Git operations will still be executed by Episoda.");
4119
- status.info("Press Ctrl+C to disconnect.");
4120
- status.info("");
4121
- }
4122
- });
4123
- devProcess.on("error", (error) => {
4124
- status.error(`Dev server error: ${error.message}`);
4125
- });
4126
- };
4127
- const shutdownHandler = async (signal) => {
4128
- if (shuttingDown) return;
4129
- shuttingDown = true;
4130
- status.info(`
4131
- Received ${signal}, shutting down...`);
4132
- if (devProcess) {
4133
- devProcess.kill("SIGTERM");
4134
- }
4135
- status.info("Dev server stopped. Daemon continues running in background.");
4136
- process.exit(0);
4137
- };
4138
- process.on("SIGTERM", () => shutdownHandler("SIGTERM"));
4139
- process.on("SIGINT", () => shutdownHandler("SIGINT"));
4140
- startServer();
4141
- await new Promise(() => {
4142
- });
4143
- }
4144
3831
 
4145
3832
  // src/commands/auth.ts
4146
3833
  var os = __toESM(require("os"));
4147
- var fs7 = __toESM(require("fs"));
4148
- var path8 = __toESM(require("path"));
3834
+ var fs6 = __toESM(require("fs"));
3835
+ var path7 = __toESM(require("path"));
4149
3836
  var import_child_process5 = require("child_process");
4150
3837
  var import_core6 = __toESM(require_dist());
4151
3838
 
4152
3839
  // src/daemon/machine-id.ts
4153
- var fs6 = __toESM(require("fs"));
4154
- var path7 = __toESM(require("path"));
3840
+ var fs5 = __toESM(require("fs"));
3841
+ var path6 = __toESM(require("path"));
4155
3842
  var crypto2 = __toESM(require("crypto"));
4156
3843
  var import_child_process4 = require("child_process");
4157
3844
  var import_core5 = __toESM(require_dist());
@@ -4160,17 +3847,17 @@ function isValidUUID(str) {
4160
3847
  return uuidRegex.test(str);
4161
3848
  }
4162
3849
  async function getMachineId() {
4163
- const machineIdPath = path7.join((0, import_core5.getConfigDir)(), "machine-id");
3850
+ const machineIdPath = path6.join((0, import_core5.getConfigDir)(), "machine-id");
4164
3851
  try {
4165
- if (fs6.existsSync(machineIdPath)) {
4166
- const existingId = fs6.readFileSync(machineIdPath, "utf-8").trim();
3852
+ if (fs5.existsSync(machineIdPath)) {
3853
+ const existingId = fs5.readFileSync(machineIdPath, "utf-8").trim();
4167
3854
  if (existingId) {
4168
3855
  if (isValidUUID(existingId)) {
4169
3856
  return existingId;
4170
3857
  }
4171
3858
  console.log("[MachineId] Migrating legacy machine ID to UUID format...");
4172
3859
  const newUUID = generateMachineId();
4173
- fs6.writeFileSync(machineIdPath, newUUID, "utf-8");
3860
+ fs5.writeFileSync(machineIdPath, newUUID, "utf-8");
4174
3861
  console.log(`[MachineId] Migrated: ${existingId} \u2192 ${newUUID}`);
4175
3862
  return newUUID;
4176
3863
  }
@@ -4179,11 +3866,11 @@ async function getMachineId() {
4179
3866
  }
4180
3867
  const machineId = generateMachineId();
4181
3868
  try {
4182
- const dir = path7.dirname(machineIdPath);
4183
- if (!fs6.existsSync(dir)) {
4184
- fs6.mkdirSync(dir, { recursive: true });
3869
+ const dir = path6.dirname(machineIdPath);
3870
+ if (!fs5.existsSync(dir)) {
3871
+ fs5.mkdirSync(dir, { recursive: true });
4185
3872
  }
4186
- fs6.writeFileSync(machineIdPath, machineId, "utf-8");
3873
+ fs5.writeFileSync(machineIdPath, machineId, "utf-8");
4187
3874
  } catch (error) {
4188
3875
  console.error("Warning: Could not save machine ID to disk:", error);
4189
3876
  }
@@ -4200,14 +3887,14 @@ function getHardwareUUID() {
4200
3887
  return output;
4201
3888
  }
4202
3889
  } else if (process.platform === "linux") {
4203
- if (fs6.existsSync("/etc/machine-id")) {
4204
- const machineId = fs6.readFileSync("/etc/machine-id", "utf-8").trim();
3890
+ if (fs5.existsSync("/etc/machine-id")) {
3891
+ const machineId = fs5.readFileSync("/etc/machine-id", "utf-8").trim();
4205
3892
  if (machineId && machineId.length > 0) {
4206
3893
  return machineId;
4207
3894
  }
4208
3895
  }
4209
- if (fs6.existsSync("/var/lib/dbus/machine-id")) {
4210
- const dbusId = fs6.readFileSync("/var/lib/dbus/machine-id", "utf-8").trim();
3896
+ if (fs5.existsSync("/var/lib/dbus/machine-id")) {
3897
+ const dbusId = fs5.readFileSync("/var/lib/dbus/machine-id", "utf-8").trim();
4211
3898
  if (dbusId && dbusId.length > 0) {
4212
3899
  return dbusId;
4213
3900
  }
@@ -4767,13 +4454,13 @@ function openBrowser(url) {
4767
4454
  async function installGitCredentialHelper(apiUrl) {
4768
4455
  try {
4769
4456
  const homeDir = os.homedir();
4770
- const episodaBinDir = path8.join(homeDir, ".episoda", "bin");
4771
- const helperPath = path8.join(episodaBinDir, "git-credential-episoda");
4772
- fs7.mkdirSync(episodaBinDir, { recursive: true });
4457
+ const episodaBinDir = path7.join(homeDir, ".episoda", "bin");
4458
+ const helperPath = path7.join(episodaBinDir, "git-credential-episoda");
4459
+ fs6.mkdirSync(episodaBinDir, { recursive: true });
4773
4460
  const scriptContent = generateCredentialHelperScript(apiUrl);
4774
- fs7.writeFileSync(helperPath, scriptContent, { mode: 493 });
4461
+ fs6.writeFileSync(helperPath, scriptContent, { mode: 493 });
4775
4462
  try {
4776
- fs7.accessSync(helperPath, fs7.constants.X_OK);
4463
+ fs6.accessSync(helperPath, fs6.constants.X_OK);
4777
4464
  } catch {
4778
4465
  }
4779
4466
  try {
@@ -4804,19 +4491,19 @@ function updateShellProfile(binDir) {
4804
4491
  }
4805
4492
  const homeDir = os.homedir();
4806
4493
  const profiles = [
4807
- path8.join(homeDir, ".bashrc"),
4808
- path8.join(homeDir, ".zshrc"),
4809
- path8.join(homeDir, ".profile")
4494
+ path7.join(homeDir, ".bashrc"),
4495
+ path7.join(homeDir, ".zshrc"),
4496
+ path7.join(homeDir, ".profile")
4810
4497
  ];
4811
4498
  const exportLine = `export PATH="${binDir}:$PATH" # Added by episoda auth`;
4812
4499
  for (const profile of profiles) {
4813
4500
  try {
4814
- if (fs7.existsSync(profile)) {
4815
- const content = fs7.readFileSync(profile, "utf8");
4501
+ if (fs6.existsSync(profile)) {
4502
+ const content = fs6.readFileSync(profile, "utf8");
4816
4503
  if (content.includes(".episoda/bin")) {
4817
4504
  continue;
4818
4505
  }
4819
- fs7.appendFileSync(profile, `
4506
+ fs6.appendFileSync(profile, `
4820
4507
  # Episoda CLI
4821
4508
  ${exportLine}
4822
4509
  `);
@@ -4828,8 +4515,8 @@ ${exportLine}
4828
4515
 
4829
4516
  // src/commands/connect.ts
4830
4517
  var os2 = __toESM(require("os"));
4831
- var fs8 = __toESM(require("fs"));
4832
- var path9 = __toESM(require("path"));
4518
+ var fs7 = __toESM(require("fs"));
4519
+ var path8 = __toESM(require("path"));
4833
4520
  var import_child_process6 = require("child_process");
4834
4521
  var import_core7 = __toESM(require_dist());
4835
4522
  async function connectCommand(options) {
@@ -4904,11 +4591,11 @@ async function exchangeUserCode(apiUrl, userCode, machineId) {
4904
4591
  async function installGitCredentialHelper2(apiUrl) {
4905
4592
  try {
4906
4593
  const homeDir = os2.homedir();
4907
- const episodaBinDir = path9.join(homeDir, ".episoda", "bin");
4908
- const helperPath = path9.join(episodaBinDir, "git-credential-episoda");
4909
- fs8.mkdirSync(episodaBinDir, { recursive: true });
4594
+ const episodaBinDir = path8.join(homeDir, ".episoda", "bin");
4595
+ const helperPath = path8.join(episodaBinDir, "git-credential-episoda");
4596
+ fs7.mkdirSync(episodaBinDir, { recursive: true });
4910
4597
  const scriptContent = generateCredentialHelperScript(apiUrl);
4911
- fs8.writeFileSync(helperPath, scriptContent, { mode: 493 });
4598
+ fs7.writeFileSync(helperPath, scriptContent, { mode: 493 });
4912
4599
  try {
4913
4600
  const allHelpers = (0, import_child_process6.execSync)("git config --global --get-all credential.helper", {
4914
4601
  encoding: "utf8",
@@ -4937,19 +4624,19 @@ function updateShellProfile2(binDir) {
4937
4624
  }
4938
4625
  const homeDir = os2.homedir();
4939
4626
  const profiles = [
4940
- path9.join(homeDir, ".bashrc"),
4941
- path9.join(homeDir, ".zshrc"),
4942
- path9.join(homeDir, ".profile")
4627
+ path8.join(homeDir, ".bashrc"),
4628
+ path8.join(homeDir, ".zshrc"),
4629
+ path8.join(homeDir, ".profile")
4943
4630
  ];
4944
4631
  const exportLine = `export PATH="${binDir}:$PATH" # Added by episoda`;
4945
4632
  for (const profile of profiles) {
4946
4633
  try {
4947
- if (fs8.existsSync(profile)) {
4948
- const content = fs8.readFileSync(profile, "utf8");
4634
+ if (fs7.existsSync(profile)) {
4635
+ const content = fs7.readFileSync(profile, "utf8");
4949
4636
  if (content.includes(".episoda/bin")) {
4950
4637
  continue;
4951
4638
  }
4952
- fs8.appendFileSync(profile, `
4639
+ fs7.appendFileSync(profile, `
4953
4640
  # Episoda CLI
4954
4641
  ${exportLine}
4955
4642
  `);
@@ -5251,24 +4938,24 @@ async function stopCommand(options = {}) {
5251
4938
  }
5252
4939
 
5253
4940
  // src/commands/clone.ts
5254
- var fs10 = __toESM(require("fs"));
5255
- var path11 = __toESM(require("path"));
4941
+ var fs9 = __toESM(require("fs"));
4942
+ var path10 = __toESM(require("path"));
5256
4943
  var import_core10 = __toESM(require_dist());
5257
4944
 
5258
4945
  // src/daemon/project-tracker.ts
5259
- var fs9 = __toESM(require("fs"));
5260
- var path10 = __toESM(require("path"));
4946
+ var fs8 = __toESM(require("fs"));
4947
+ var path9 = __toESM(require("path"));
5261
4948
  var import_core9 = __toESM(require_dist());
5262
4949
  function getProjectsFilePath() {
5263
- return path10.join((0, import_core9.getConfigDir)(), "projects.json");
4950
+ return path9.join((0, import_core9.getConfigDir)(), "projects.json");
5264
4951
  }
5265
4952
  function readProjects() {
5266
4953
  const projectsPath = getProjectsFilePath();
5267
4954
  try {
5268
- if (!fs9.existsSync(projectsPath)) {
4955
+ if (!fs8.existsSync(projectsPath)) {
5269
4956
  return { projects: [] };
5270
4957
  }
5271
- const content = fs9.readFileSync(projectsPath, "utf-8");
4958
+ const content = fs8.readFileSync(projectsPath, "utf-8");
5272
4959
  const data = JSON.parse(content);
5273
4960
  if (!data.projects || !Array.isArray(data.projects)) {
5274
4961
  console.warn("Invalid projects.json structure, resetting");
@@ -5283,11 +4970,11 @@ function readProjects() {
5283
4970
  function writeProjects(data) {
5284
4971
  const projectsPath = getProjectsFilePath();
5285
4972
  try {
5286
- const dir = path10.dirname(projectsPath);
5287
- if (!fs9.existsSync(dir)) {
5288
- fs9.mkdirSync(dir, { recursive: true });
4973
+ const dir = path9.dirname(projectsPath);
4974
+ if (!fs8.existsSync(dir)) {
4975
+ fs8.mkdirSync(dir, { recursive: true });
5289
4976
  }
5290
- fs9.writeFileSync(projectsPath, JSON.stringify(data, null, 2), "utf-8");
4977
+ fs8.writeFileSync(projectsPath, JSON.stringify(data, null, 2), "utf-8");
5291
4978
  } catch (error) {
5292
4979
  throw new Error(`Failed to write projects.json: ${error}`);
5293
4980
  }
@@ -5311,7 +4998,7 @@ function addProject2(projectId, projectPath, options) {
5311
4998
  console.log(`[ProjectTracker] Replacing project entry: ${existingById.path} -> ${projectPath}`);
5312
4999
  data.projects.splice(existingByIdIndex, 1);
5313
5000
  }
5314
- const projectName = path10.basename(projectPath);
5001
+ const projectName = path9.basename(projectPath);
5315
5002
  const newProject = {
5316
5003
  id: projectId,
5317
5004
  path: projectPath,
@@ -5345,9 +5032,9 @@ async function cloneCommand(slugArg, options = {}) {
5345
5032
  }
5346
5033
  const apiUrl = options.apiUrl || config.api_url || "https://episoda.dev";
5347
5034
  const projectPath = getProjectPath(workspaceSlug, projectSlug);
5348
- if (fs10.existsSync(projectPath)) {
5349
- const bareRepoPath = path11.join(projectPath, ".bare");
5350
- if (fs10.existsSync(bareRepoPath)) {
5035
+ if (fs9.existsSync(projectPath)) {
5036
+ const bareRepoPath = path10.join(projectPath, ".bare");
5037
+ if (fs9.existsSync(bareRepoPath)) {
5351
5038
  status.warning(`Project already cloned at ${projectPath}`);
5352
5039
  status.info("");
5353
5040
  status.info("Next steps:");
@@ -5379,7 +5066,7 @@ Please configure a repository in the project settings on episoda.dev.`
5379
5066
  status.info("");
5380
5067
  status.info("Creating project directory...");
5381
5068
  const episodaRoot = getEpisodaRoot();
5382
- fs10.mkdirSync(projectPath, { recursive: true });
5069
+ fs9.mkdirSync(projectPath, { recursive: true });
5383
5070
  status.success(`\u2713 Created ${projectPath}`);
5384
5071
  status.info("Cloning repository (bare)...");
5385
5072
  try {
@@ -5417,9 +5104,9 @@ Please configure a repository in the project settings on episoda.dev.`
5417
5104
  status.info(" 3. episoda checkout {moduleUid} # e.g., episoda checkout EP100");
5418
5105
  status.info("");
5419
5106
  } catch (error) {
5420
- if (fs10.existsSync(projectPath)) {
5107
+ if (fs9.existsSync(projectPath)) {
5421
5108
  try {
5422
- fs10.rmSync(projectPath, { recursive: true, force: true });
5109
+ fs9.rmSync(projectPath, { recursive: true, force: true });
5423
5110
  } catch {
5424
5111
  }
5425
5112
  }
@@ -5520,8 +5207,8 @@ async function fetchWithRetry(url, options, maxRetries = 3) {
5520
5207
  }
5521
5208
 
5522
5209
  // src/utils/env-setup.ts
5523
- var fs11 = __toESM(require("fs"));
5524
- var path12 = __toESM(require("path"));
5210
+ var fs10 = __toESM(require("fs"));
5211
+ var path11 = __toESM(require("path"));
5525
5212
  async function fetchEnvVars(apiUrl, accessToken) {
5526
5213
  try {
5527
5214
  const url = `${apiUrl}/api/cli/env-vars`;
@@ -5556,8 +5243,8 @@ function writeEnvFile(targetPath, envVars) {
5556
5243
  }
5557
5244
  return `${key}=${value}`;
5558
5245
  }).join("\n") + "\n";
5559
- const envPath = path12.join(targetPath, ".env");
5560
- fs11.writeFileSync(envPath, envContent, { mode: 384 });
5246
+ const envPath = path11.join(targetPath, ".env");
5247
+ fs10.writeFileSync(envPath, envContent, { mode: 384 });
5561
5248
  console.log(`[env-setup] Wrote ${Object.keys(envVars).length} env vars to ${envPath}`);
5562
5249
  }
5563
5250
  async function setupWorktreeEnv(worktreePath, apiUrl, accessToken) {
@@ -5735,7 +5422,7 @@ async function updateModuleCheckout(apiUrl, moduleId, accessToken, branchName) {
5735
5422
  }
5736
5423
 
5737
5424
  // src/commands/release.ts
5738
- var path13 = __toESM(require("path"));
5425
+ var path12 = __toESM(require("path"));
5739
5426
  var import_core12 = __toESM(require_dist());
5740
5427
  async function releaseCommand(moduleUid, options = {}) {
5741
5428
  if (!moduleUid || !moduleUid.match(/^EP\d+$/)) {
@@ -5782,7 +5469,7 @@ Commit or stash your changes first, or use --force to discard them.`
5782
5469
  );
5783
5470
  }
5784
5471
  }
5785
- const currentPath = path13.resolve(process.cwd());
5472
+ const currentPath = path12.resolve(process.cwd());
5786
5473
  if (currentPath.startsWith(existing.worktreePath)) {
5787
5474
  status.warning("You are inside the worktree being released.");
5788
5475
  status.info(`Please cd to ${projectRoot} first.`);
@@ -5856,8 +5543,8 @@ async function updateModuleRelease(apiUrl, projectId, workspaceSlug, moduleUid,
5856
5543
  }
5857
5544
 
5858
5545
  // src/commands/list.ts
5859
- var fs12 = __toESM(require("fs"));
5860
- var path14 = __toESM(require("path"));
5546
+ var fs11 = __toESM(require("fs"));
5547
+ var path13 = __toESM(require("path"));
5861
5548
  var import_chalk2 = __toESM(require("chalk"));
5862
5549
  var import_core13 = __toESM(require_dist());
5863
5550
  async function listCommand(subcommand, options = {}) {
@@ -5869,7 +5556,7 @@ async function listCommand(subcommand, options = {}) {
5869
5556
  }
5870
5557
  async function listProjects(options) {
5871
5558
  const episodaRoot = getEpisodaRoot();
5872
- if (!fs12.existsSync(episodaRoot)) {
5559
+ if (!fs11.existsSync(episodaRoot)) {
5873
5560
  status.info("No projects cloned yet.");
5874
5561
  status.info("");
5875
5562
  status.info("Clone a project with:");
@@ -5877,12 +5564,12 @@ async function listProjects(options) {
5877
5564
  return;
5878
5565
  }
5879
5566
  const projects = [];
5880
- const workspaces = fs12.readdirSync(episodaRoot, { withFileTypes: true }).filter((d) => d.isDirectory() && !d.name.startsWith("."));
5567
+ const workspaces = fs11.readdirSync(episodaRoot, { withFileTypes: true }).filter((d) => d.isDirectory() && !d.name.startsWith("."));
5881
5568
  for (const workspace of workspaces) {
5882
- const workspacePath = path14.join(episodaRoot, workspace.name);
5883
- const projectDirs = fs12.readdirSync(workspacePath, { withFileTypes: true }).filter((d) => d.isDirectory() && !d.name.startsWith("."));
5569
+ const workspacePath = path13.join(episodaRoot, workspace.name);
5570
+ const projectDirs = fs11.readdirSync(workspacePath, { withFileTypes: true }).filter((d) => d.isDirectory() && !d.name.startsWith("."));
5884
5571
  for (const projectDir of projectDirs) {
5885
- const projectPath = path14.join(workspacePath, projectDir.name);
5572
+ const projectPath = path13.join(workspacePath, projectDir.name);
5886
5573
  if (await isWorktreeProject(projectPath)) {
5887
5574
  const manager = new WorktreeManager(projectPath);
5888
5575
  await manager.initialize();
@@ -6122,26 +5809,26 @@ var import_child_process9 = require("child_process");
6122
5809
  var import_core15 = __toESM(require_dist());
6123
5810
 
6124
5811
  // src/utils/env-cache.ts
6125
- var fs13 = __toESM(require("fs"));
6126
- var path15 = __toESM(require("path"));
5812
+ var fs12 = __toESM(require("fs"));
5813
+ var path14 = __toESM(require("path"));
6127
5814
  var os3 = __toESM(require("os"));
6128
5815
  var DEFAULT_CACHE_TTL = 60;
6129
- var CACHE_DIR = path15.join(os3.homedir(), ".episoda", "cache");
5816
+ var CACHE_DIR = path14.join(os3.homedir(), ".episoda", "cache");
6130
5817
  function getCacheFilePath(projectId) {
6131
- return path15.join(CACHE_DIR, `env-vars-${projectId}.json`);
5818
+ return path14.join(CACHE_DIR, `env-vars-${projectId}.json`);
6132
5819
  }
6133
5820
  function ensureCacheDir() {
6134
- if (!fs13.existsSync(CACHE_DIR)) {
6135
- fs13.mkdirSync(CACHE_DIR, { recursive: true, mode: 448 });
5821
+ if (!fs12.existsSync(CACHE_DIR)) {
5822
+ fs12.mkdirSync(CACHE_DIR, { recursive: true, mode: 448 });
6136
5823
  }
6137
5824
  }
6138
5825
  function readCache(projectId) {
6139
5826
  try {
6140
5827
  const cacheFile = getCacheFilePath(projectId);
6141
- if (!fs13.existsSync(cacheFile)) {
5828
+ if (!fs12.existsSync(cacheFile)) {
6142
5829
  return null;
6143
5830
  }
6144
- const content = fs13.readFileSync(cacheFile, "utf-8");
5831
+ const content = fs12.readFileSync(cacheFile, "utf-8");
6145
5832
  const data = JSON.parse(content);
6146
5833
  if (!data.vars || typeof data.vars !== "object" || !data.fetchedAt) {
6147
5834
  return null;
@@ -6160,7 +5847,7 @@ function writeCache(projectId, vars) {
6160
5847
  fetchedAt: Date.now(),
6161
5848
  projectId
6162
5849
  };
6163
- fs13.writeFileSync(cacheFile, JSON.stringify(data, null, 2), { mode: 384 });
5850
+ fs12.writeFileSync(cacheFile, JSON.stringify(data, null, 2), { mode: 384 });
6164
5851
  } catch (error) {
6165
5852
  console.warn("[env-cache] Failed to write cache:", error instanceof Error ? error.message : error);
6166
5853
  }
@@ -6396,8 +6083,8 @@ function printExports(envVars) {
6396
6083
  }
6397
6084
 
6398
6085
  // src/commands/env.ts
6399
- var fs14 = __toESM(require("fs"));
6400
- var path16 = __toESM(require("path"));
6086
+ var fs13 = __toESM(require("fs"));
6087
+ var path15 = __toESM(require("path"));
6401
6088
  var readline = __toESM(require("readline"));
6402
6089
  var import_core17 = __toESM(require_dist());
6403
6090
  async function envListCommand(options = {}) {
@@ -6587,8 +6274,8 @@ async function envPullCommand(options = {}) {
6587
6274
  return;
6588
6275
  }
6589
6276
  const filename = options.file || ".env";
6590
- const filepath = path16.resolve(process.cwd(), filename);
6591
- fs14.writeFileSync(filepath, fullContent, { mode: 384 });
6277
+ const filepath = path15.resolve(process.cwd(), filename);
6278
+ fs13.writeFileSync(filepath, fullContent, { mode: 384 });
6592
6279
  status.success(`Wrote ${Object.keys(envVars).length} env vars to ${filename}`);
6593
6280
  }
6594
6281
  async function promptForValue(key) {
@@ -6661,18 +6348,24 @@ import_commander.program.command("connect").description("Connect using a pre-aut
6661
6348
  process.exit(1);
6662
6349
  }
6663
6350
  });
6664
- import_commander.program.command("dev").description("Connect to Episoda and start dev server").option("--auto-restart", "Auto-restart dev server if it crashes").option("--connection-only", "Connection-only mode (don't start dev server)").allowUnknownOption().action(async (options, cmd) => {
6351
+ import_commander.program.command("daemon").description("Connect project to Episoda daemon (dev servers start automatically)").option("--background", "Run in background and exit immediately").action(async (options) => {
6665
6352
  try {
6666
- const args = process.argv.slice(process.argv.indexOf("dev") + 1);
6667
- const separatorIndex = args.indexOf("--");
6668
- const command = separatorIndex >= 0 ? args.slice(separatorIndex + 1) : [];
6669
- const filteredCommand = command.filter((arg) => arg !== "--auto-restart" && arg !== "--connection-only");
6670
- await devCommand({
6671
- command: options.connectionOnly ? [] : filteredCommand.length > 0 ? filteredCommand : void 0,
6672
- autoRestart: options.autoRestart
6353
+ await daemonCommand({
6354
+ background: options.background
6355
+ });
6356
+ } catch (error) {
6357
+ status.error(`Daemon command failed: ${error instanceof Error ? error.message : String(error)}`);
6358
+ process.exit(1);
6359
+ }
6360
+ });
6361
+ import_commander.program.command("dev").description('Alias for "daemon" (deprecated)').option("--background", "Run in background and exit immediately").action(async (options) => {
6362
+ status.warning('Note: "episoda dev" is deprecated. Use "episoda daemon" instead.');
6363
+ try {
6364
+ await daemonCommand({
6365
+ background: options.background
6673
6366
  });
6674
6367
  } catch (error) {
6675
- status.error(`Dev command failed: ${error instanceof Error ? error.message : String(error)}`);
6368
+ status.error(`Command failed: ${error instanceof Error ? error.message : String(error)}`);
6676
6369
  process.exit(1);
6677
6370
  }
6678
6371
  });