episoda 0.2.50 → 0.2.52

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.
@@ -1563,15 +1563,15 @@ var require_git_executor = __commonJS({
1563
1563
  try {
1564
1564
  const { stdout: gitDir } = await execAsync2("git rev-parse --git-dir", { cwd, timeout: 5e3 });
1565
1565
  const gitDirPath = gitDir.trim();
1566
- const fs18 = await Promise.resolve().then(() => __importStar(require("fs"))).then((m) => m.promises);
1566
+ const fs17 = await Promise.resolve().then(() => __importStar(require("fs"))).then((m) => m.promises);
1567
1567
  const rebaseMergePath = `${gitDirPath}/rebase-merge`;
1568
1568
  const rebaseApplyPath = `${gitDirPath}/rebase-apply`;
1569
1569
  try {
1570
- await fs18.access(rebaseMergePath);
1570
+ await fs17.access(rebaseMergePath);
1571
1571
  inRebase = true;
1572
1572
  } catch {
1573
1573
  try {
1574
- await fs18.access(rebaseApplyPath);
1574
+ await fs17.access(rebaseApplyPath);
1575
1575
  inRebase = true;
1576
1576
  } catch {
1577
1577
  inRebase = false;
@@ -1625,9 +1625,9 @@ var require_git_executor = __commonJS({
1625
1625
  error: validation.error || "UNKNOWN_ERROR"
1626
1626
  };
1627
1627
  }
1628
- const fs18 = await Promise.resolve().then(() => __importStar(require("fs"))).then((m) => m.promises);
1628
+ const fs17 = await Promise.resolve().then(() => __importStar(require("fs"))).then((m) => m.promises);
1629
1629
  try {
1630
- await fs18.access(command.path);
1630
+ await fs17.access(command.path);
1631
1631
  return {
1632
1632
  success: false,
1633
1633
  error: "WORKTREE_EXISTS",
@@ -1681,9 +1681,9 @@ var require_git_executor = __commonJS({
1681
1681
  */
1682
1682
  async executeWorktreeRemove(command, cwd, options) {
1683
1683
  try {
1684
- const fs18 = await Promise.resolve().then(() => __importStar(require("fs"))).then((m) => m.promises);
1684
+ const fs17 = await Promise.resolve().then(() => __importStar(require("fs"))).then((m) => m.promises);
1685
1685
  try {
1686
- await fs18.access(command.path);
1686
+ await fs17.access(command.path);
1687
1687
  } catch {
1688
1688
  return {
1689
1689
  success: false,
@@ -1718,7 +1718,7 @@ var require_git_executor = __commonJS({
1718
1718
  const result = await this.runGitCommand(args, cwd, options);
1719
1719
  if (result.success) {
1720
1720
  try {
1721
- await fs18.rm(command.path, { recursive: true, force: true });
1721
+ await fs17.rm(command.path, { recursive: true, force: true });
1722
1722
  } catch {
1723
1723
  }
1724
1724
  return {
@@ -1852,10 +1852,10 @@ var require_git_executor = __commonJS({
1852
1852
  */
1853
1853
  async executeCloneBare(command, options) {
1854
1854
  try {
1855
- const fs18 = await Promise.resolve().then(() => __importStar(require("fs"))).then((m) => m.promises);
1856
- const path19 = await Promise.resolve().then(() => __importStar(require("path")));
1855
+ const fs17 = await Promise.resolve().then(() => __importStar(require("fs"))).then((m) => m.promises);
1856
+ const path18 = await Promise.resolve().then(() => __importStar(require("path")));
1857
1857
  try {
1858
- await fs18.access(command.path);
1858
+ await fs17.access(command.path);
1859
1859
  return {
1860
1860
  success: false,
1861
1861
  error: "BRANCH_ALREADY_EXISTS",
@@ -1864,9 +1864,9 @@ var require_git_executor = __commonJS({
1864
1864
  };
1865
1865
  } catch {
1866
1866
  }
1867
- const parentDir = path19.dirname(command.path);
1867
+ const parentDir = path18.dirname(command.path);
1868
1868
  try {
1869
- await fs18.mkdir(parentDir, { recursive: true });
1869
+ await fs17.mkdir(parentDir, { recursive: true });
1870
1870
  } catch {
1871
1871
  }
1872
1872
  const { stdout, stderr } = await execAsync2(
@@ -1914,22 +1914,22 @@ var require_git_executor = __commonJS({
1914
1914
  */
1915
1915
  async executeProjectInfo(cwd, options) {
1916
1916
  try {
1917
- const fs18 = await Promise.resolve().then(() => __importStar(require("fs"))).then((m) => m.promises);
1918
- const path19 = await Promise.resolve().then(() => __importStar(require("path")));
1917
+ const fs17 = await Promise.resolve().then(() => __importStar(require("fs"))).then((m) => m.promises);
1918
+ const path18 = await Promise.resolve().then(() => __importStar(require("path")));
1919
1919
  let currentPath = cwd;
1920
1920
  let projectPath = cwd;
1921
1921
  let bareRepoPath;
1922
1922
  for (let i = 0; i < 10; i++) {
1923
- const bareDir = path19.join(currentPath, ".bare");
1924
- const episodaDir = path19.join(currentPath, ".episoda");
1923
+ const bareDir = path18.join(currentPath, ".bare");
1924
+ const episodaDir = path18.join(currentPath, ".episoda");
1925
1925
  try {
1926
- await fs18.access(bareDir);
1927
- await fs18.access(episodaDir);
1926
+ await fs17.access(bareDir);
1927
+ await fs17.access(episodaDir);
1928
1928
  projectPath = currentPath;
1929
1929
  bareRepoPath = bareDir;
1930
1930
  break;
1931
1931
  } catch {
1932
- const parentPath = path19.dirname(currentPath);
1932
+ const parentPath = path18.dirname(currentPath);
1933
1933
  if (parentPath === currentPath) {
1934
1934
  break;
1935
1935
  }
@@ -2533,36 +2533,36 @@ var require_auth = __commonJS({
2533
2533
  };
2534
2534
  })();
2535
2535
  Object.defineProperty(exports2, "__esModule", { value: true });
2536
- exports2.getConfigDir = getConfigDir7;
2536
+ exports2.getConfigDir = getConfigDir8;
2537
2537
  exports2.getConfigPath = getConfigPath;
2538
2538
  exports2.loadConfig = loadConfig7;
2539
2539
  exports2.saveConfig = saveConfig2;
2540
2540
  exports2.validateToken = validateToken;
2541
- var fs18 = __importStar(require("fs"));
2542
- var path19 = __importStar(require("path"));
2541
+ var fs17 = __importStar(require("fs"));
2542
+ var path18 = __importStar(require("path"));
2543
2543
  var os7 = __importStar(require("os"));
2544
2544
  var child_process_1 = require("child_process");
2545
2545
  var DEFAULT_CONFIG_FILE = "config.json";
2546
- function getConfigDir7() {
2547
- return process.env.EPISODA_CONFIG_DIR || path19.join(os7.homedir(), ".episoda");
2546
+ function getConfigDir8() {
2547
+ return process.env.EPISODA_CONFIG_DIR || path18.join(os7.homedir(), ".episoda");
2548
2548
  }
2549
2549
  function getConfigPath(configPath) {
2550
2550
  if (configPath) {
2551
2551
  return configPath;
2552
2552
  }
2553
- return path19.join(getConfigDir7(), DEFAULT_CONFIG_FILE);
2553
+ return path18.join(getConfigDir8(), DEFAULT_CONFIG_FILE);
2554
2554
  }
2555
2555
  function ensureConfigDir(configPath) {
2556
- const dir = path19.dirname(configPath);
2557
- const isNew = !fs18.existsSync(dir);
2556
+ const dir = path18.dirname(configPath);
2557
+ const isNew = !fs17.existsSync(dir);
2558
2558
  if (isNew) {
2559
- fs18.mkdirSync(dir, { recursive: true, mode: 448 });
2559
+ fs17.mkdirSync(dir, { recursive: true, mode: 448 });
2560
2560
  }
2561
2561
  if (process.platform === "darwin") {
2562
- const nosyncPath = path19.join(dir, ".nosync");
2563
- if (isNew || !fs18.existsSync(nosyncPath)) {
2562
+ const nosyncPath = path18.join(dir, ".nosync");
2563
+ if (isNew || !fs17.existsSync(nosyncPath)) {
2564
2564
  try {
2565
- fs18.writeFileSync(nosyncPath, "", { mode: 384 });
2565
+ fs17.writeFileSync(nosyncPath, "", { mode: 384 });
2566
2566
  (0, child_process_1.execSync)(`xattr -w com.apple.fileprovider.ignore 1 "${dir}"`, {
2567
2567
  stdio: "ignore",
2568
2568
  timeout: 5e3
@@ -2574,9 +2574,9 @@ var require_auth = __commonJS({
2574
2574
  }
2575
2575
  async function loadConfig7(configPath) {
2576
2576
  const fullPath = getConfigPath(configPath);
2577
- if (fs18.existsSync(fullPath)) {
2577
+ if (fs17.existsSync(fullPath)) {
2578
2578
  try {
2579
- const content = fs18.readFileSync(fullPath, "utf8");
2579
+ const content = fs17.readFileSync(fullPath, "utf8");
2580
2580
  const config = JSON.parse(content);
2581
2581
  return config;
2582
2582
  } catch (error) {
@@ -2601,7 +2601,7 @@ var require_auth = __commonJS({
2601
2601
  ensureConfigDir(fullPath);
2602
2602
  try {
2603
2603
  const content = JSON.stringify(config, null, 2);
2604
- fs18.writeFileSync(fullPath, content, { mode: 384 });
2604
+ fs17.writeFileSync(fullPath, content, { mode: 384 });
2605
2605
  } catch (error) {
2606
2606
  throw new Error(`Failed to save config: ${error instanceof Error ? error.message : String(error)}`);
2607
2607
  }
@@ -2718,7 +2718,7 @@ var require_package = __commonJS({
2718
2718
  "package.json"(exports2, module2) {
2719
2719
  module2.exports = {
2720
2720
  name: "episoda",
2721
- version: "0.2.50",
2721
+ version: "0.2.52",
2722
2722
  description: "CLI tool for Episoda local development workflow orchestration",
2723
2723
  main: "dist/index.js",
2724
2724
  types: "dist/index.d.ts",
@@ -3095,11 +3095,16 @@ var IPCServer = class {
3095
3095
  };
3096
3096
 
3097
3097
  // src/daemon/daemon-process.ts
3098
- var import_core11 = __toESM(require_dist());
3098
+ var import_core12 = __toESM(require_dist());
3099
3099
 
3100
3100
  // src/utils/update-checker.ts
3101
3101
  var import_child_process2 = require("child_process");
3102
3102
  var semver = __toESM(require("semver"));
3103
+
3104
+ // src/ipc/ipc-client.ts
3105
+ var import_core5 = __toESM(require_dist());
3106
+
3107
+ // src/utils/update-checker.ts
3103
3108
  var PACKAGE_NAME = "episoda";
3104
3109
  var NPM_REGISTRY = "https://registry.npmjs.org";
3105
3110
  async function checkForUpdates(currentVersion) {
@@ -3758,12 +3763,12 @@ async function handleExec(command, projectPath) {
3758
3763
  // src/daemon/handlers/stale-commit-cleanup.ts
3759
3764
  var import_child_process4 = require("child_process");
3760
3765
  var import_util = require("util");
3761
- var import_core5 = __toESM(require_dist());
3766
+ var import_core6 = __toESM(require_dist());
3762
3767
  var execAsync = (0, import_util.promisify)(import_child_process4.exec);
3763
3768
  async function cleanupStaleCommits(projectPath) {
3764
3769
  try {
3765
3770
  const machineId = await getMachineId();
3766
- const config = await (0, import_core5.loadConfig)();
3771
+ const config = await (0, import_core6.loadConfig)();
3767
3772
  if (!config?.access_token) {
3768
3773
  return {
3769
3774
  success: false,
@@ -4013,14 +4018,16 @@ var path7 = __toESM(require("path"));
4013
4018
  var os2 = __toESM(require("os"));
4014
4019
 
4015
4020
  // src/tunnel/tunnel-api.ts
4016
- var import_core6 = __toESM(require_dist());
4021
+ var import_core7 = __toESM(require_dist());
4017
4022
  async function provisionNamedTunnel(moduleId, port = 3e3) {
4018
- const config = await (0, import_core6.loadConfig)();
4023
+ console.log(`[TunnelAPI] EP1038: provisionNamedTunnel called for moduleId ${moduleId} with port ${port}`);
4024
+ const config = await (0, import_core7.loadConfig)();
4019
4025
  if (!config?.access_token) {
4020
4026
  return { success: false, error: "Not authenticated" };
4021
4027
  }
4022
4028
  try {
4023
4029
  const apiUrl = config.api_url || "https://episoda.dev";
4030
+ console.log(`[TunnelAPI] EP1038: POSTing to ${apiUrl}/api/tunnels with port=${port}`);
4024
4031
  const response = await fetch(`${apiUrl}/api/tunnels`, {
4025
4032
  method: "POST",
4026
4033
  headers: {
@@ -4050,7 +4057,8 @@ async function provisionNamedTunnel(moduleId, port = 3e3) {
4050
4057
  }
4051
4058
  }
4052
4059
  async function provisionNamedTunnelByUid(moduleUid, port = 3e3) {
4053
- const config = await (0, import_core6.loadConfig)();
4060
+ console.log(`[TunnelAPI] EP1038: provisionNamedTunnelByUid called for ${moduleUid} with port ${port}`);
4061
+ const config = await (0, import_core7.loadConfig)();
4054
4062
  if (!config?.access_token) {
4055
4063
  return { success: false, error: "Not authenticated" };
4056
4064
  }
@@ -4087,7 +4095,7 @@ async function updateTunnelStatus(moduleUid, status, error) {
4087
4095
  if (!moduleUid || moduleUid === "LOCAL") {
4088
4096
  return;
4089
4097
  }
4090
- const config = await (0, import_core6.loadConfig)();
4098
+ const config = await (0, import_core7.loadConfig)();
4091
4099
  if (!config?.access_token) {
4092
4100
  return;
4093
4101
  }
@@ -4112,7 +4120,7 @@ async function clearTunnelUrl(moduleUid) {
4112
4120
  if (!moduleUid || moduleUid === "LOCAL") {
4113
4121
  return;
4114
4122
  }
4115
- const config = await (0, import_core6.loadConfig)();
4123
+ const config = await (0, import_core7.loadConfig)();
4116
4124
  if (!config?.access_token) {
4117
4125
  return;
4118
4126
  }
@@ -5269,7 +5277,7 @@ var http = __toESM(require("http"));
5269
5277
  var fs11 = __toESM(require("fs"));
5270
5278
  var path12 = __toESM(require("path"));
5271
5279
  var import_events2 = require("events");
5272
- var import_core7 = __toESM(require_dist());
5280
+ var import_core8 = __toESM(require_dist());
5273
5281
 
5274
5282
  // src/utils/port-check.ts
5275
5283
  var net2 = __toESM(require("net"));
@@ -5636,7 +5644,7 @@ var DevServerRunner = class extends import_events2.EventEmitter {
5636
5644
  // ============ Private Methods ============
5637
5645
  async fetchEnvVars(projectPath) {
5638
5646
  try {
5639
- const config = await (0, import_core7.loadConfig)();
5647
+ const config = await (0, import_core8.loadConfig)();
5640
5648
  if (!config?.access_token || !config?.project_id) {
5641
5649
  return {};
5642
5650
  }
@@ -5796,7 +5804,7 @@ var DevServerRunner = class extends import_events2.EventEmitter {
5796
5804
  return new Promise((resolve3) => setTimeout(resolve3, ms));
5797
5805
  }
5798
5806
  getLogsDir() {
5799
- const logsDir = path12.join((0, import_core7.getConfigDir)(), "logs");
5807
+ const logsDir = path12.join((0, import_core8.getConfigDir)(), "logs");
5800
5808
  if (!fs11.existsSync(logsDir)) {
5801
5809
  fs11.mkdirSync(logsDir, { recursive: true });
5802
5810
  }
@@ -5852,6 +5860,48 @@ function getDevServerRunner() {
5852
5860
  return instance2;
5853
5861
  }
5854
5862
 
5863
+ // src/utils/port-allocator.ts
5864
+ var PORT_RANGE_START = 3100;
5865
+ var PORT_RANGE_END = 3199;
5866
+ var PORT_WARNING_THRESHOLD = 80;
5867
+ var portAssignments = /* @__PURE__ */ new Map();
5868
+ function allocatePort(moduleUid) {
5869
+ const existing = portAssignments.get(moduleUid);
5870
+ if (existing) {
5871
+ return existing;
5872
+ }
5873
+ const usedPorts = new Set(portAssignments.values());
5874
+ if (usedPorts.size >= PORT_WARNING_THRESHOLD) {
5875
+ console.warn(
5876
+ `[PortAllocator] Warning: ${usedPorts.size}/${PORT_RANGE_END - PORT_RANGE_START + 1} ports allocated`
5877
+ );
5878
+ }
5879
+ for (let port = PORT_RANGE_START; port <= PORT_RANGE_END; port++) {
5880
+ if (!usedPorts.has(port)) {
5881
+ portAssignments.set(moduleUid, port);
5882
+ console.log(`[PortAllocator] Assigned port ${port} to ${moduleUid}`);
5883
+ return port;
5884
+ }
5885
+ }
5886
+ throw new Error(
5887
+ `No available ports in range ${PORT_RANGE_START}-${PORT_RANGE_END}. ${portAssignments.size} modules are using all available ports.`
5888
+ );
5889
+ }
5890
+ function releasePort(moduleUid) {
5891
+ const port = portAssignments.get(moduleUid);
5892
+ if (port) {
5893
+ portAssignments.delete(moduleUid);
5894
+ console.log(`[PortAllocator] Released port ${port} from ${moduleUid}`);
5895
+ }
5896
+ }
5897
+ function clearAllPorts() {
5898
+ const count = portAssignments.size;
5899
+ portAssignments.clear();
5900
+ if (count > 0) {
5901
+ console.log(`[PortAllocator] Cleared ${count} port assignments`);
5902
+ }
5903
+ }
5904
+
5855
5905
  // src/preview/preview-manager.ts
5856
5906
  var DEFAULT_PORT = 3e3;
5857
5907
  var PreviewManager = class extends import_events3.EventEmitter {
@@ -6064,6 +6114,7 @@ var PreviewManager = class extends import_events3.EventEmitter {
6064
6114
  } catch (error) {
6065
6115
  console.warn(`[PreviewManager] Error clearing tunnel URL for ${moduleUid}:`, error);
6066
6116
  }
6117
+ releasePort(moduleUid);
6067
6118
  if (state) {
6068
6119
  state.state = "stopped";
6069
6120
  state.tunnelUrl = void 0;
@@ -6242,7 +6293,7 @@ function getPreviewManager() {
6242
6293
 
6243
6294
  // src/utils/dev-server.ts
6244
6295
  var import_child_process10 = require("child_process");
6245
- var import_core8 = __toESM(require_dist());
6296
+ var import_core9 = __toESM(require_dist());
6246
6297
  var fs12 = __toESM(require("fs"));
6247
6298
  var path13 = __toESM(require("path"));
6248
6299
  var MAX_RESTART_ATTEMPTS = 5;
@@ -6252,7 +6303,7 @@ var MAX_LOG_SIZE_BYTES = 5 * 1024 * 1024;
6252
6303
  var NODE_MEMORY_LIMIT_MB = 2048;
6253
6304
  var activeServers = /* @__PURE__ */ new Map();
6254
6305
  function getLogsDir() {
6255
- const logsDir = path13.join((0, import_core8.getConfigDir)(), "logs");
6306
+ const logsDir = path13.join((0, import_core9.getConfigDir)(), "logs");
6256
6307
  if (!fs12.existsSync(logsDir)) {
6257
6308
  fs12.mkdirSync(logsDir, { recursive: true });
6258
6309
  }
@@ -6453,7 +6504,7 @@ async function startDevServer(projectPath, port = 3e3, moduleUid = "default", op
6453
6504
  console.log(`[DevServer] EP932: Starting dev server for ${moduleUid} on port ${port} (auto-restart: ${autoRestart})...`);
6454
6505
  let injectedEnvVars = {};
6455
6506
  try {
6456
- const config = await (0, import_core8.loadConfig)();
6507
+ const config = await (0, import_core9.loadConfig)();
6457
6508
  if (config?.access_token && config?.project_id) {
6458
6509
  const apiUrl = config.api_url || "https://episoda.dev";
6459
6510
  const result = await fetchEnvVarsWithCache(apiUrl, config.access_token, {
@@ -6569,81 +6620,10 @@ function getDevServerStatus() {
6569
6620
  }));
6570
6621
  }
6571
6622
 
6572
- // src/utils/port-detect.ts
6623
+ // src/daemon/worktree-manager.ts
6573
6624
  var fs13 = __toESM(require("fs"));
6574
6625
  var path14 = __toESM(require("path"));
6575
- var DEFAULT_PORT2 = 3e3;
6576
- function detectDevPort(projectPath) {
6577
- const envPort = getPortFromEnv(projectPath);
6578
- if (envPort) {
6579
- console.log(`[PortDetect] Found PORT=${envPort} in .env`);
6580
- return envPort;
6581
- }
6582
- const scriptPort = getPortFromPackageJson(projectPath);
6583
- if (scriptPort) {
6584
- console.log(`[PortDetect] Found port ${scriptPort} in package.json dev script`);
6585
- return scriptPort;
6586
- }
6587
- console.log(`[PortDetect] Using default port ${DEFAULT_PORT2}`);
6588
- return DEFAULT_PORT2;
6589
- }
6590
- function getPortFromEnv(projectPath) {
6591
- const envPaths = [
6592
- path14.join(projectPath, ".env"),
6593
- path14.join(projectPath, ".env.local"),
6594
- path14.join(projectPath, ".env.development"),
6595
- path14.join(projectPath, ".env.development.local")
6596
- ];
6597
- for (const envPath of envPaths) {
6598
- try {
6599
- if (!fs13.existsSync(envPath)) continue;
6600
- const content = fs13.readFileSync(envPath, "utf-8");
6601
- const lines = content.split("\n");
6602
- for (const line of lines) {
6603
- const match = line.match(/^\s*PORT\s*=\s*["']?(\d+)["']?\s*(?:#.*)?$/);
6604
- if (match) {
6605
- const port = parseInt(match[1], 10);
6606
- if (port > 0 && port < 65536) {
6607
- return port;
6608
- }
6609
- }
6610
- }
6611
- } catch {
6612
- }
6613
- }
6614
- return null;
6615
- }
6616
- function getPortFromPackageJson(projectPath) {
6617
- const packageJsonPath = path14.join(projectPath, "package.json");
6618
- try {
6619
- if (!fs13.existsSync(packageJsonPath)) return null;
6620
- const content = fs13.readFileSync(packageJsonPath, "utf-8");
6621
- const pkg = JSON.parse(content);
6622
- const devScript = pkg.scripts?.dev;
6623
- if (!devScript) return null;
6624
- const portMatch = devScript.match(/(?:--port[=\s]|-p[=\s])(\d+)/);
6625
- if (portMatch) {
6626
- const port = parseInt(portMatch[1], 10);
6627
- if (port > 0 && port < 65536) {
6628
- return port;
6629
- }
6630
- }
6631
- const envMatch = devScript.match(/PORT[=\s](\d+)/);
6632
- if (envMatch) {
6633
- const port = parseInt(envMatch[1], 10);
6634
- if (port > 0 && port < 65536) {
6635
- return port;
6636
- }
6637
- }
6638
- } catch {
6639
- }
6640
- return null;
6641
- }
6642
-
6643
- // src/daemon/worktree-manager.ts
6644
- var fs14 = __toESM(require("fs"));
6645
- var path15 = __toESM(require("path"));
6646
- var import_core9 = __toESM(require_dist());
6626
+ var import_core10 = __toESM(require_dist());
6647
6627
  function validateModuleUid(moduleUid) {
6648
6628
  if (!moduleUid || typeof moduleUid !== "string" || !moduleUid.trim()) {
6649
6629
  return false;
@@ -6666,9 +6646,9 @@ var WorktreeManager = class _WorktreeManager {
6666
6646
  // ============================================================
6667
6647
  this.lockPath = "";
6668
6648
  this.projectRoot = projectRoot;
6669
- this.bareRepoPath = path15.join(projectRoot, ".bare");
6670
- this.configPath = path15.join(projectRoot, ".episoda", "config.json");
6671
- this.gitExecutor = new import_core9.GitExecutor();
6649
+ this.bareRepoPath = path14.join(projectRoot, ".bare");
6650
+ this.configPath = path14.join(projectRoot, ".episoda", "config.json");
6651
+ this.gitExecutor = new import_core10.GitExecutor();
6672
6652
  }
6673
6653
  /**
6674
6654
  * Initialize worktree manager from existing project root
@@ -6676,10 +6656,10 @@ var WorktreeManager = class _WorktreeManager {
6676
6656
  * @returns true if valid project, false otherwise
6677
6657
  */
6678
6658
  async initialize() {
6679
- if (!fs14.existsSync(this.bareRepoPath)) {
6659
+ if (!fs13.existsSync(this.bareRepoPath)) {
6680
6660
  return false;
6681
6661
  }
6682
- if (!fs14.existsSync(this.configPath)) {
6662
+ if (!fs13.existsSync(this.configPath)) {
6683
6663
  return false;
6684
6664
  }
6685
6665
  try {
@@ -6726,8 +6706,8 @@ var WorktreeManager = class _WorktreeManager {
6726
6706
  */
6727
6707
  static async createProject(projectRoot, repoUrl, projectId, workspaceSlug, projectSlug) {
6728
6708
  const manager = new _WorktreeManager(projectRoot);
6729
- const episodaDir = path15.join(projectRoot, ".episoda");
6730
- fs14.mkdirSync(episodaDir, { recursive: true });
6709
+ const episodaDir = path14.join(projectRoot, ".episoda");
6710
+ fs13.mkdirSync(episodaDir, { recursive: true });
6731
6711
  const cloneResult = await manager.gitExecutor.execute({
6732
6712
  action: "clone_bare",
6733
6713
  url: repoUrl,
@@ -6758,7 +6738,7 @@ var WorktreeManager = class _WorktreeManager {
6758
6738
  error: `Invalid module UID: "${moduleUid}" - contains disallowed characters`
6759
6739
  };
6760
6740
  }
6761
- const worktreePath = path15.join(this.projectRoot, moduleUid);
6741
+ const worktreePath = path14.join(this.projectRoot, moduleUid);
6762
6742
  const lockAcquired = await this.acquireLock();
6763
6743
  if (!lockAcquired) {
6764
6744
  return {
@@ -6940,7 +6920,7 @@ var WorktreeManager = class _WorktreeManager {
6940
6920
  let prunedCount = 0;
6941
6921
  await this.updateConfigSafe((config) => {
6942
6922
  const initialCount = config.worktrees.length;
6943
- config.worktrees = config.worktrees.filter((w) => fs14.existsSync(w.worktreePath));
6923
+ config.worktrees = config.worktrees.filter((w) => fs13.existsSync(w.worktreePath));
6944
6924
  prunedCount = initialCount - config.worktrees.length;
6945
6925
  return config;
6946
6926
  });
@@ -7021,16 +7001,16 @@ var WorktreeManager = class _WorktreeManager {
7021
7001
  const retryInterval = 50;
7022
7002
  while (Date.now() - startTime < timeoutMs) {
7023
7003
  try {
7024
- fs14.writeFileSync(lockPath, String(process.pid), { flag: "wx" });
7004
+ fs13.writeFileSync(lockPath, String(process.pid), { flag: "wx" });
7025
7005
  return true;
7026
7006
  } catch (err) {
7027
7007
  if (err.code === "EEXIST") {
7028
7008
  try {
7029
- const stats = fs14.statSync(lockPath);
7009
+ const stats = fs13.statSync(lockPath);
7030
7010
  const lockAge = Date.now() - stats.mtimeMs;
7031
7011
  if (lockAge > 3e4) {
7032
7012
  try {
7033
- const lockContent = fs14.readFileSync(lockPath, "utf-8").trim();
7013
+ const lockContent = fs13.readFileSync(lockPath, "utf-8").trim();
7034
7014
  const lockPid = parseInt(lockContent, 10);
7035
7015
  if (!isNaN(lockPid) && this.isProcessRunning(lockPid)) {
7036
7016
  await new Promise((resolve3) => setTimeout(resolve3, retryInterval));
@@ -7039,7 +7019,7 @@ var WorktreeManager = class _WorktreeManager {
7039
7019
  } catch {
7040
7020
  }
7041
7021
  try {
7042
- fs14.unlinkSync(lockPath);
7022
+ fs13.unlinkSync(lockPath);
7043
7023
  } catch {
7044
7024
  }
7045
7025
  continue;
@@ -7060,16 +7040,16 @@ var WorktreeManager = class _WorktreeManager {
7060
7040
  */
7061
7041
  releaseLock() {
7062
7042
  try {
7063
- fs14.unlinkSync(this.getLockPath());
7043
+ fs13.unlinkSync(this.getLockPath());
7064
7044
  } catch {
7065
7045
  }
7066
7046
  }
7067
7047
  readConfig() {
7068
7048
  try {
7069
- if (!fs14.existsSync(this.configPath)) {
7049
+ if (!fs13.existsSync(this.configPath)) {
7070
7050
  return null;
7071
7051
  }
7072
- const content = fs14.readFileSync(this.configPath, "utf-8");
7052
+ const content = fs13.readFileSync(this.configPath, "utf-8");
7073
7053
  return JSON.parse(content);
7074
7054
  } catch (error) {
7075
7055
  console.error("[WorktreeManager] Failed to read config:", error);
@@ -7078,11 +7058,11 @@ var WorktreeManager = class _WorktreeManager {
7078
7058
  }
7079
7059
  writeConfig(config) {
7080
7060
  try {
7081
- const dir = path15.dirname(this.configPath);
7082
- if (!fs14.existsSync(dir)) {
7083
- fs14.mkdirSync(dir, { recursive: true });
7061
+ const dir = path14.dirname(this.configPath);
7062
+ if (!fs13.existsSync(dir)) {
7063
+ fs13.mkdirSync(dir, { recursive: true });
7084
7064
  }
7085
- fs14.writeFileSync(this.configPath, JSON.stringify(config, null, 2), "utf-8");
7065
+ fs13.writeFileSync(this.configPath, JSON.stringify(config, null, 2), "utf-8");
7086
7066
  } catch (error) {
7087
7067
  console.error("[WorktreeManager] Failed to write config:", error);
7088
7068
  throw error;
@@ -7163,14 +7143,14 @@ var WorktreeManager = class _WorktreeManager {
7163
7143
  }
7164
7144
  try {
7165
7145
  for (const file of files) {
7166
- const srcPath = path15.join(mainWorktree.worktreePath, file);
7167
- const destPath = path15.join(worktree.worktreePath, file);
7168
- if (fs14.existsSync(srcPath)) {
7169
- const destDir = path15.dirname(destPath);
7170
- if (!fs14.existsSync(destDir)) {
7171
- fs14.mkdirSync(destDir, { recursive: true });
7172
- }
7173
- fs14.copyFileSync(srcPath, destPath);
7146
+ const srcPath = path14.join(mainWorktree.worktreePath, file);
7147
+ const destPath = path14.join(worktree.worktreePath, file);
7148
+ if (fs13.existsSync(srcPath)) {
7149
+ const destDir = path14.dirname(destPath);
7150
+ if (!fs13.existsSync(destDir)) {
7151
+ fs13.mkdirSync(destDir, { recursive: true });
7152
+ }
7153
+ fs13.copyFileSync(srcPath, destPath);
7174
7154
  console.log(`[WorktreeManager] EP964: Copied ${file} to ${moduleUid} (deprecated)`);
7175
7155
  } else {
7176
7156
  console.log(`[WorktreeManager] EP964: Skipped ${file} (not found in main)`);
@@ -7253,27 +7233,27 @@ var WorktreeManager = class _WorktreeManager {
7253
7233
  }
7254
7234
  };
7255
7235
  function getEpisodaRoot() {
7256
- return process.env.EPISODA_ROOT || path15.join(require("os").homedir(), "episoda");
7236
+ return process.env.EPISODA_ROOT || path14.join(require("os").homedir(), "episoda");
7257
7237
  }
7258
7238
  async function isWorktreeProject(projectRoot) {
7259
7239
  const manager = new WorktreeManager(projectRoot);
7260
7240
  return manager.initialize();
7261
7241
  }
7262
7242
  async function findProjectRoot(startPath) {
7263
- let current = path15.resolve(startPath);
7243
+ let current = path14.resolve(startPath);
7264
7244
  const episodaRoot = getEpisodaRoot();
7265
7245
  if (!current.startsWith(episodaRoot)) {
7266
7246
  return null;
7267
7247
  }
7268
7248
  for (let i = 0; i < 10; i++) {
7269
- const bareDir = path15.join(current, ".bare");
7270
- const episodaDir = path15.join(current, ".episoda");
7271
- if (fs14.existsSync(bareDir) && fs14.existsSync(episodaDir)) {
7249
+ const bareDir = path14.join(current, ".bare");
7250
+ const episodaDir = path14.join(current, ".episoda");
7251
+ if (fs13.existsSync(bareDir) && fs13.existsSync(episodaDir)) {
7272
7252
  if (await isWorktreeProject(current)) {
7273
7253
  return current;
7274
7254
  }
7275
7255
  }
7276
- const parent = path15.dirname(current);
7256
+ const parent = path14.dirname(current);
7277
7257
  if (parent === current) {
7278
7258
  break;
7279
7259
  }
@@ -7283,24 +7263,24 @@ async function findProjectRoot(startPath) {
7283
7263
  }
7284
7264
 
7285
7265
  // src/utils/worktree.ts
7286
- var path16 = __toESM(require("path"));
7287
- var fs15 = __toESM(require("fs"));
7266
+ var path15 = __toESM(require("path"));
7267
+ var fs14 = __toESM(require("fs"));
7288
7268
  var os5 = __toESM(require("os"));
7289
- var import_core10 = __toESM(require_dist());
7269
+ var import_core11 = __toESM(require_dist());
7290
7270
  function getEpisodaRoot2() {
7291
- return process.env.EPISODA_ROOT || path16.join(os5.homedir(), "episoda");
7271
+ return process.env.EPISODA_ROOT || path15.join(os5.homedir(), "episoda");
7292
7272
  }
7293
7273
  function getWorktreeInfo(moduleUid, workspaceSlug, projectSlug) {
7294
7274
  const root = getEpisodaRoot2();
7295
- const worktreePath = path16.join(root, workspaceSlug, projectSlug, moduleUid);
7275
+ const worktreePath = path15.join(root, workspaceSlug, projectSlug, moduleUid);
7296
7276
  return {
7297
7277
  path: worktreePath,
7298
- exists: fs15.existsSync(worktreePath),
7278
+ exists: fs14.existsSync(worktreePath),
7299
7279
  moduleUid
7300
7280
  };
7301
7281
  }
7302
7282
  async function getWorktreeInfoForModule(moduleUid) {
7303
- const config = await (0, import_core10.loadConfig)();
7283
+ const config = await (0, import_core11.loadConfig)();
7304
7284
  if (!config?.workspace_slug || !config?.project_slug) {
7305
7285
  console.warn("[Worktree] Missing workspace_slug or project_slug in config");
7306
7286
  return null;
@@ -7308,72 +7288,62 @@ async function getWorktreeInfoForModule(moduleUid) {
7308
7288
  return getWorktreeInfo(moduleUid, config.workspace_slug, config.project_slug);
7309
7289
  }
7310
7290
 
7311
- // src/utils/port-allocator.ts
7312
- var portAssignments = /* @__PURE__ */ new Map();
7313
- function clearAllPorts() {
7314
- const count = portAssignments.size;
7315
- portAssignments.clear();
7316
- if (count > 0) {
7317
- console.log(`[PortAllocator] Cleared ${count} port assignments`);
7318
- }
7319
- }
7320
-
7321
7291
  // src/framework-detector.ts
7322
- var fs16 = __toESM(require("fs"));
7323
- var path17 = __toESM(require("path"));
7292
+ var fs15 = __toESM(require("fs"));
7293
+ var path16 = __toESM(require("path"));
7324
7294
  function getInstallCommand(cwd) {
7325
- if (fs16.existsSync(path17.join(cwd, "bun.lockb"))) {
7295
+ if (fs15.existsSync(path16.join(cwd, "bun.lockb"))) {
7326
7296
  return {
7327
7297
  command: ["bun", "install"],
7328
7298
  description: "Installing dependencies with bun",
7329
7299
  detectedFrom: "bun.lockb"
7330
7300
  };
7331
7301
  }
7332
- if (fs16.existsSync(path17.join(cwd, "pnpm-lock.yaml"))) {
7302
+ if (fs15.existsSync(path16.join(cwd, "pnpm-lock.yaml"))) {
7333
7303
  return {
7334
7304
  command: ["pnpm", "install"],
7335
7305
  description: "Installing dependencies with pnpm",
7336
7306
  detectedFrom: "pnpm-lock.yaml"
7337
7307
  };
7338
7308
  }
7339
- if (fs16.existsSync(path17.join(cwd, "yarn.lock"))) {
7309
+ if (fs15.existsSync(path16.join(cwd, "yarn.lock"))) {
7340
7310
  return {
7341
7311
  command: ["yarn", "install"],
7342
7312
  description: "Installing dependencies with yarn",
7343
7313
  detectedFrom: "yarn.lock"
7344
7314
  };
7345
7315
  }
7346
- if (fs16.existsSync(path17.join(cwd, "package-lock.json"))) {
7316
+ if (fs15.existsSync(path16.join(cwd, "package-lock.json"))) {
7347
7317
  return {
7348
7318
  command: ["npm", "ci"],
7349
7319
  description: "Installing dependencies with npm ci",
7350
7320
  detectedFrom: "package-lock.json"
7351
7321
  };
7352
7322
  }
7353
- if (fs16.existsSync(path17.join(cwd, "package.json"))) {
7323
+ if (fs15.existsSync(path16.join(cwd, "package.json"))) {
7354
7324
  return {
7355
7325
  command: ["npm", "install"],
7356
7326
  description: "Installing dependencies with npm",
7357
7327
  detectedFrom: "package.json"
7358
7328
  };
7359
7329
  }
7360
- if (fs16.existsSync(path17.join(cwd, "Pipfile.lock")) || fs16.existsSync(path17.join(cwd, "Pipfile"))) {
7330
+ if (fs15.existsSync(path16.join(cwd, "Pipfile.lock")) || fs15.existsSync(path16.join(cwd, "Pipfile"))) {
7361
7331
  return {
7362
7332
  command: ["pipenv", "install"],
7363
7333
  description: "Installing dependencies with pipenv",
7364
- detectedFrom: fs16.existsSync(path17.join(cwd, "Pipfile.lock")) ? "Pipfile.lock" : "Pipfile"
7334
+ detectedFrom: fs15.existsSync(path16.join(cwd, "Pipfile.lock")) ? "Pipfile.lock" : "Pipfile"
7365
7335
  };
7366
7336
  }
7367
- if (fs16.existsSync(path17.join(cwd, "poetry.lock"))) {
7337
+ if (fs15.existsSync(path16.join(cwd, "poetry.lock"))) {
7368
7338
  return {
7369
7339
  command: ["poetry", "install"],
7370
7340
  description: "Installing dependencies with poetry",
7371
7341
  detectedFrom: "poetry.lock"
7372
7342
  };
7373
7343
  }
7374
- if (fs16.existsSync(path17.join(cwd, "pyproject.toml"))) {
7375
- const pyprojectPath = path17.join(cwd, "pyproject.toml");
7376
- const content = fs16.readFileSync(pyprojectPath, "utf-8");
7344
+ if (fs15.existsSync(path16.join(cwd, "pyproject.toml"))) {
7345
+ const pyprojectPath = path16.join(cwd, "pyproject.toml");
7346
+ const content = fs15.readFileSync(pyprojectPath, "utf-8");
7377
7347
  if (content.includes("[tool.poetry]")) {
7378
7348
  return {
7379
7349
  command: ["poetry", "install"],
@@ -7382,41 +7352,41 @@ function getInstallCommand(cwd) {
7382
7352
  };
7383
7353
  }
7384
7354
  }
7385
- if (fs16.existsSync(path17.join(cwd, "requirements.txt"))) {
7355
+ if (fs15.existsSync(path16.join(cwd, "requirements.txt"))) {
7386
7356
  return {
7387
7357
  command: ["pip", "install", "-r", "requirements.txt"],
7388
7358
  description: "Installing dependencies with pip",
7389
7359
  detectedFrom: "requirements.txt"
7390
7360
  };
7391
7361
  }
7392
- if (fs16.existsSync(path17.join(cwd, "Gemfile.lock")) || fs16.existsSync(path17.join(cwd, "Gemfile"))) {
7362
+ if (fs15.existsSync(path16.join(cwd, "Gemfile.lock")) || fs15.existsSync(path16.join(cwd, "Gemfile"))) {
7393
7363
  return {
7394
7364
  command: ["bundle", "install"],
7395
7365
  description: "Installing dependencies with bundler",
7396
- detectedFrom: fs16.existsSync(path17.join(cwd, "Gemfile.lock")) ? "Gemfile.lock" : "Gemfile"
7366
+ detectedFrom: fs15.existsSync(path16.join(cwd, "Gemfile.lock")) ? "Gemfile.lock" : "Gemfile"
7397
7367
  };
7398
7368
  }
7399
- if (fs16.existsSync(path17.join(cwd, "go.sum")) || fs16.existsSync(path17.join(cwd, "go.mod"))) {
7369
+ if (fs15.existsSync(path16.join(cwd, "go.sum")) || fs15.existsSync(path16.join(cwd, "go.mod"))) {
7400
7370
  return {
7401
7371
  command: ["go", "mod", "download"],
7402
7372
  description: "Downloading Go modules",
7403
- detectedFrom: fs16.existsSync(path17.join(cwd, "go.sum")) ? "go.sum" : "go.mod"
7373
+ detectedFrom: fs15.existsSync(path16.join(cwd, "go.sum")) ? "go.sum" : "go.mod"
7404
7374
  };
7405
7375
  }
7406
- if (fs16.existsSync(path17.join(cwd, "Cargo.lock")) || fs16.existsSync(path17.join(cwd, "Cargo.toml"))) {
7376
+ if (fs15.existsSync(path16.join(cwd, "Cargo.lock")) || fs15.existsSync(path16.join(cwd, "Cargo.toml"))) {
7407
7377
  return {
7408
7378
  command: ["cargo", "build"],
7409
7379
  description: "Building Rust project (downloads dependencies)",
7410
- detectedFrom: fs16.existsSync(path17.join(cwd, "Cargo.lock")) ? "Cargo.lock" : "Cargo.toml"
7380
+ detectedFrom: fs15.existsSync(path16.join(cwd, "Cargo.lock")) ? "Cargo.lock" : "Cargo.toml"
7411
7381
  };
7412
7382
  }
7413
7383
  return null;
7414
7384
  }
7415
7385
 
7416
7386
  // src/daemon/daemon-process.ts
7417
- var fs17 = __toESM(require("fs"));
7387
+ var fs16 = __toESM(require("fs"));
7418
7388
  var os6 = __toESM(require("os"));
7419
- var path18 = __toESM(require("path"));
7389
+ var path17 = __toESM(require("path"));
7420
7390
  var packageJson = require_package();
7421
7391
  async function ensureValidToken(config, bufferMs = 5 * 60 * 1e3) {
7422
7392
  const now = Date.now();
@@ -7451,7 +7421,7 @@ async function ensureValidToken(config, bufferMs = 5 * 60 * 1e3) {
7451
7421
  refresh_token: tokenResponse.refresh_token || config.refresh_token,
7452
7422
  expires_at: now + tokenResponse.expires_in * 1e3
7453
7423
  };
7454
- await (0, import_core11.saveConfig)(updatedConfig);
7424
+ await (0, import_core12.saveConfig)(updatedConfig);
7455
7425
  console.log("[Daemon] EP904: Access token refreshed successfully");
7456
7426
  return updatedConfig;
7457
7427
  } catch (error) {
@@ -7460,7 +7430,7 @@ async function ensureValidToken(config, bufferMs = 5 * 60 * 1e3) {
7460
7430
  }
7461
7431
  }
7462
7432
  async function fetchWithAuth(url, options = {}, retryOnUnauthorized = true) {
7463
- let config = await (0, import_core11.loadConfig)();
7433
+ let config = await (0, import_core12.loadConfig)();
7464
7434
  if (!config?.access_token) {
7465
7435
  throw new Error("No access token configured");
7466
7436
  }
@@ -7487,7 +7457,7 @@ async function fetchWithAuth(url, options = {}, retryOnUnauthorized = true) {
7487
7457
  }
7488
7458
  async function fetchEnvVars2() {
7489
7459
  try {
7490
- const config = await (0, import_core11.loadConfig)();
7460
+ const config = await (0, import_core12.loadConfig)();
7491
7461
  if (!config?.project_id) {
7492
7462
  console.warn("[Daemon] EP973: No project_id in config, cannot fetch env vars");
7493
7463
  return {};
@@ -7570,7 +7540,7 @@ var Daemon = class _Daemon {
7570
7540
  console.log("[Daemon] Starting Episoda daemon...");
7571
7541
  this.machineId = await getMachineId();
7572
7542
  console.log(`[Daemon] Machine ID: ${this.machineId}`);
7573
- const config = await (0, import_core11.loadConfig)();
7543
+ const config = await (0, import_core12.loadConfig)();
7574
7544
  if (config?.device_id) {
7575
7545
  this.deviceId = config.device_id;
7576
7546
  console.log(`[Daemon] Loaded cached Device ID (UUID): ${this.deviceId}`);
@@ -7707,7 +7677,7 @@ var Daemon = class _Daemon {
7707
7677
  };
7708
7678
  });
7709
7679
  this.ipcServer.on("verify-server-connection", async () => {
7710
- const config = await (0, import_core11.loadConfig)();
7680
+ const config = await (0, import_core12.loadConfig)();
7711
7681
  if (!config?.access_token || !config?.api_url) {
7712
7682
  return {
7713
7683
  verified: false,
@@ -7767,6 +7737,7 @@ var Daemon = class _Daemon {
7767
7737
  }
7768
7738
  await tunnelManager.stopTunnel(moduleUid);
7769
7739
  await stopDevServer(moduleUid);
7740
+ releasePort(moduleUid);
7770
7741
  await clearTunnelUrl(moduleUid);
7771
7742
  this.tunnelHealthFailures.delete(moduleUid);
7772
7743
  console.log(`[Daemon] EP823: Tunnel stopped for ${moduleUid}`);
@@ -7880,7 +7851,7 @@ var Daemon = class _Daemon {
7880
7851
  console.warn(`[Daemon] Stale connection detected for ${projectPath}, forcing reconnection`);
7881
7852
  await this.disconnectProject(projectPath);
7882
7853
  }
7883
- const config = await (0, import_core11.loadConfig)();
7854
+ const config = await (0, import_core12.loadConfig)();
7884
7855
  if (!config || !config.access_token) {
7885
7856
  throw new Error("No access token found. Please run: episoda auth");
7886
7857
  }
@@ -7901,8 +7872,8 @@ var Daemon = class _Daemon {
7901
7872
  wsUrl = `${wsProtocol}//${wsHostname}:${wsPort}`;
7902
7873
  }
7903
7874
  console.log(`[Daemon] Connecting to ${wsUrl} for project ${projectId}...`);
7904
- const client = new import_core11.EpisodaClient();
7905
- const gitExecutor = new import_core11.GitExecutor();
7875
+ const client = new import_core12.EpisodaClient();
7876
+ const gitExecutor = new import_core12.GitExecutor();
7906
7877
  const connection = {
7907
7878
  projectId,
7908
7879
  projectPath,
@@ -7917,7 +7888,7 @@ var Daemon = class _Daemon {
7917
7888
  client.updateActivity();
7918
7889
  try {
7919
7890
  const gitCmd = message.command;
7920
- const bareRepoPath = path18.join(projectPath, ".bare");
7891
+ const bareRepoPath = path17.join(projectPath, ".bare");
7921
7892
  const cwd = gitCmd.worktreePath || bareRepoPath;
7922
7893
  if (gitCmd.worktreePath) {
7923
7894
  console.log(`[Daemon] Routing command to worktree: ${gitCmd.worktreePath}`);
@@ -8071,8 +8042,9 @@ var Daemon = class _Daemon {
8071
8042
  return;
8072
8043
  }
8073
8044
  console.log(`[Daemon] EP1024: Using worktree path ${worktree.path} for ${cmd.moduleUid}`);
8074
- const port = cmd.port || detectDevPort(worktree.path);
8075
- const devConfig = await (0, import_core11.loadConfig)();
8045
+ const port = cmd.port || allocatePort(cmd.moduleUid);
8046
+ console.log(`[Daemon] EP1038: Allocated port ${port} for ${cmd.moduleUid}`);
8047
+ const devConfig = await (0, import_core12.loadConfig)();
8076
8048
  const customCommand = devConfig?.project_settings?.worktree_dev_server_script;
8077
8049
  const startResult = await previewManager.startPreview({
8078
8050
  moduleUid: cmd.moduleUid,
@@ -8332,8 +8304,8 @@ var Daemon = class _Daemon {
8332
8304
  let daemonPid;
8333
8305
  try {
8334
8306
  const pidPath = getPidFilePath();
8335
- if (fs17.existsSync(pidPath)) {
8336
- const pidStr = fs17.readFileSync(pidPath, "utf-8").trim();
8307
+ if (fs16.existsSync(pidPath)) {
8308
+ const pidStr = fs16.readFileSync(pidPath, "utf-8").trim();
8337
8309
  daemonPid = parseInt(pidStr, 10);
8338
8310
  }
8339
8311
  } catch (pidError) {
@@ -8454,27 +8426,27 @@ var Daemon = class _Daemon {
8454
8426
  */
8455
8427
  async installGitHooks(projectPath) {
8456
8428
  const hooks = ["post-checkout", "pre-commit", "post-commit"];
8457
- const hooksDir = path18.join(projectPath, ".git", "hooks");
8458
- if (!fs17.existsSync(hooksDir)) {
8429
+ const hooksDir = path17.join(projectPath, ".git", "hooks");
8430
+ if (!fs16.existsSync(hooksDir)) {
8459
8431
  console.warn(`[Daemon] Hooks directory not found: ${hooksDir}`);
8460
8432
  return;
8461
8433
  }
8462
8434
  for (const hookName of hooks) {
8463
8435
  try {
8464
- const hookPath = path18.join(hooksDir, hookName);
8465
- const bundledHookPath = path18.join(__dirname, "..", "hooks", hookName);
8466
- if (!fs17.existsSync(bundledHookPath)) {
8436
+ const hookPath = path17.join(hooksDir, hookName);
8437
+ const bundledHookPath = path17.join(__dirname, "..", "hooks", hookName);
8438
+ if (!fs16.existsSync(bundledHookPath)) {
8467
8439
  console.warn(`[Daemon] Bundled hook not found: ${bundledHookPath}`);
8468
8440
  continue;
8469
8441
  }
8470
- const hookContent = fs17.readFileSync(bundledHookPath, "utf-8");
8471
- if (fs17.existsSync(hookPath)) {
8472
- const existingContent = fs17.readFileSync(hookPath, "utf-8");
8442
+ const hookContent = fs16.readFileSync(bundledHookPath, "utf-8");
8443
+ if (fs16.existsSync(hookPath)) {
8444
+ const existingContent = fs16.readFileSync(hookPath, "utf-8");
8473
8445
  if (existingContent === hookContent) {
8474
8446
  continue;
8475
8447
  }
8476
8448
  }
8477
- fs17.writeFileSync(hookPath, hookContent, { mode: 493 });
8449
+ fs16.writeFileSync(hookPath, hookContent, { mode: 493 });
8478
8450
  console.log(`[Daemon] Installed git hook: ${hookName}`);
8479
8451
  } catch (error) {
8480
8452
  console.warn(`[Daemon] Failed to install ${hookName} hook:`, error instanceof Error ? error.message : error);
@@ -8489,7 +8461,7 @@ var Daemon = class _Daemon {
8489
8461
  */
8490
8462
  async cacheDeviceId(deviceId) {
8491
8463
  try {
8492
- const config = await (0, import_core11.loadConfig)();
8464
+ const config = await (0, import_core12.loadConfig)();
8493
8465
  if (!config) {
8494
8466
  console.warn("[Daemon] Cannot cache device ID - no config found");
8495
8467
  return;
@@ -8502,7 +8474,7 @@ var Daemon = class _Daemon {
8502
8474
  device_id: deviceId,
8503
8475
  machine_id: this.machineId
8504
8476
  };
8505
- await (0, import_core11.saveConfig)(updatedConfig);
8477
+ await (0, import_core12.saveConfig)(updatedConfig);
8506
8478
  console.log(`[Daemon] Cached device ID to config: ${deviceId}`);
8507
8479
  } catch (error) {
8508
8480
  console.warn("[Daemon] Failed to cache device ID:", error instanceof Error ? error.message : error);
@@ -8516,7 +8488,7 @@ var Daemon = class _Daemon {
8516
8488
  */
8517
8489
  async syncProjectSettings(projectId) {
8518
8490
  try {
8519
- const config = await (0, import_core11.loadConfig)();
8491
+ const config = await (0, import_core12.loadConfig)();
8520
8492
  if (!config) return;
8521
8493
  const apiUrl = config.api_url || "https://episoda.dev";
8522
8494
  const response = await fetchWithAuth(`${apiUrl}/api/projects/${projectId}/settings`);
@@ -8550,7 +8522,7 @@ var Daemon = class _Daemon {
8550
8522
  cached_at: Date.now()
8551
8523
  }
8552
8524
  };
8553
- await (0, import_core11.saveConfig)(updatedConfig);
8525
+ await (0, import_core12.saveConfig)(updatedConfig);
8554
8526
  console.log(`[Daemon] EP973: Project settings synced (slugs: ${projectSlug}/${workspaceSlug})`);
8555
8527
  }
8556
8528
  } catch (error) {
@@ -8570,7 +8542,7 @@ var Daemon = class _Daemon {
8570
8542
  console.warn("[Daemon] EP995: Cannot sync project path - deviceId not available");
8571
8543
  return;
8572
8544
  }
8573
- const config = await (0, import_core11.loadConfig)();
8545
+ const config = await (0, import_core12.loadConfig)();
8574
8546
  if (!config) return;
8575
8547
  const apiUrl = config.api_url || "https://episoda.dev";
8576
8548
  const response = await fetchWithAuth(`${apiUrl}/api/account/machines/${this.deviceId}`, {
@@ -8603,7 +8575,7 @@ var Daemon = class _Daemon {
8603
8575
  */
8604
8576
  async updateModuleWorktreeStatus(moduleUid, status, worktreePath, errorMessage) {
8605
8577
  try {
8606
- const config = await (0, import_core11.loadConfig)();
8578
+ const config = await (0, import_core12.loadConfig)();
8607
8579
  if (!config) return;
8608
8580
  const apiUrl = config.api_url || "https://episoda.dev";
8609
8581
  const body = {
@@ -8658,7 +8630,7 @@ var Daemon = class _Daemon {
8658
8630
  console.log("[Daemon] EP1003: Cannot reconcile - deviceId not available yet");
8659
8631
  return;
8660
8632
  }
8661
- const config = await (0, import_core11.loadConfig)();
8633
+ const config = await (0, import_core12.loadConfig)();
8662
8634
  if (!config) return;
8663
8635
  const apiUrl = config.api_url || "https://episoda.dev";
8664
8636
  const controller = new AbortController();
@@ -8744,7 +8716,7 @@ var Daemon = class _Daemon {
8744
8716
  try {
8745
8717
  const envVars = await fetchEnvVars2();
8746
8718
  console.log(`[Daemon] EP1002: Fetched ${Object.keys(envVars).length} env vars for ${moduleUid}`);
8747
- const config = await (0, import_core11.loadConfig)();
8719
+ const config = await (0, import_core12.loadConfig)();
8748
8720
  const setupConfig = config?.project_settings;
8749
8721
  await this.runWorktreeSetupSync(
8750
8722
  moduleUid,
@@ -8922,7 +8894,7 @@ var Daemon = class _Daemon {
8922
8894
  }
8923
8895
  this.healthCheckInProgress = true;
8924
8896
  try {
8925
- const config = await (0, import_core11.loadConfig)();
8897
+ const config = await (0, import_core12.loadConfig)();
8926
8898
  if (config?.access_token) {
8927
8899
  await this.performHealthChecks(config);
8928
8900
  }
@@ -9041,7 +9013,7 @@ var Daemon = class _Daemon {
9041
9013
  */
9042
9014
  async fetchActiveModuleUids(projectId) {
9043
9015
  try {
9044
- const config = await (0, import_core11.loadConfig)();
9016
+ const config = await (0, import_core12.loadConfig)();
9045
9017
  if (!config?.access_token || !config?.api_url) {
9046
9018
  return null;
9047
9019
  }
@@ -9144,7 +9116,7 @@ var Daemon = class _Daemon {
9144
9116
  async restartTunnel(moduleUid, port) {
9145
9117
  const previewManager = getPreviewManager();
9146
9118
  try {
9147
- const config = await (0, import_core11.loadConfig)();
9119
+ const config = await (0, import_core12.loadConfig)();
9148
9120
  if (!config?.access_token) {
9149
9121
  console.error(`[Daemon] EP833: No access token for tunnel restart`);
9150
9122
  return;
@@ -9337,8 +9309,8 @@ var Daemon = class _Daemon {
9337
9309
  await this.shutdown();
9338
9310
  try {
9339
9311
  const pidPath = getPidFilePath();
9340
- if (fs17.existsSync(pidPath)) {
9341
- fs17.unlinkSync(pidPath);
9312
+ if (fs16.existsSync(pidPath)) {
9313
+ fs16.unlinkSync(pidPath);
9342
9314
  console.log("[Daemon] PID file cleaned up");
9343
9315
  }
9344
9316
  } catch (error) {