@episoda/cli 0.2.164 → 0.2.166

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.
@@ -1640,15 +1640,15 @@ var require_git_executor = __commonJS({
1640
1640
  try {
1641
1641
  const { stdout: gitDir } = await execAsync3("git rev-parse --git-dir", { cwd, timeout: 5e3 });
1642
1642
  const gitDirPath = gitDir.trim();
1643
- const fs29 = await Promise.resolve().then(() => __importStar(require("fs"))).then((m) => m.promises);
1643
+ const fs30 = await Promise.resolve().then(() => __importStar(require("fs"))).then((m) => m.promises);
1644
1644
  const rebaseMergePath = `${gitDirPath}/rebase-merge`;
1645
1645
  const rebaseApplyPath = `${gitDirPath}/rebase-apply`;
1646
1646
  try {
1647
- await fs29.access(rebaseMergePath);
1647
+ await fs30.access(rebaseMergePath);
1648
1648
  inRebase = true;
1649
1649
  } catch {
1650
1650
  try {
1651
- await fs29.access(rebaseApplyPath);
1651
+ await fs30.access(rebaseApplyPath);
1652
1652
  inRebase = true;
1653
1653
  } catch {
1654
1654
  inRebase = false;
@@ -1704,9 +1704,9 @@ var require_git_executor = __commonJS({
1704
1704
  };
1705
1705
  }
1706
1706
  }
1707
- const fs29 = await Promise.resolve().then(() => __importStar(require("fs"))).then((m) => m.promises);
1707
+ const fs30 = await Promise.resolve().then(() => __importStar(require("fs"))).then((m) => m.promises);
1708
1708
  try {
1709
- await fs29.access(command.path);
1709
+ await fs30.access(command.path);
1710
1710
  return {
1711
1711
  success: false,
1712
1712
  error: "WORKTREE_EXISTS",
@@ -1765,9 +1765,9 @@ var require_git_executor = __commonJS({
1765
1765
  */
1766
1766
  async executeWorktreeRemove(command, cwd, options) {
1767
1767
  try {
1768
- const fs29 = await Promise.resolve().then(() => __importStar(require("fs"))).then((m) => m.promises);
1768
+ const fs30 = await Promise.resolve().then(() => __importStar(require("fs"))).then((m) => m.promises);
1769
1769
  try {
1770
- await fs29.access(command.path);
1770
+ await fs30.access(command.path);
1771
1771
  } catch {
1772
1772
  return {
1773
1773
  success: false,
@@ -1802,7 +1802,7 @@ var require_git_executor = __commonJS({
1802
1802
  const result = await this.runGitCommand(args, cwd, options);
1803
1803
  if (result.success) {
1804
1804
  try {
1805
- await fs29.rm(command.path, { recursive: true, force: true });
1805
+ await fs30.rm(command.path, { recursive: true, force: true });
1806
1806
  } catch {
1807
1807
  }
1808
1808
  return {
@@ -1936,10 +1936,10 @@ var require_git_executor = __commonJS({
1936
1936
  */
1937
1937
  async executeCloneBare(command, options) {
1938
1938
  try {
1939
- const fs29 = await Promise.resolve().then(() => __importStar(require("fs"))).then((m) => m.promises);
1940
- const path30 = await Promise.resolve().then(() => __importStar(require("path")));
1939
+ const fs30 = await Promise.resolve().then(() => __importStar(require("fs"))).then((m) => m.promises);
1940
+ const path31 = await Promise.resolve().then(() => __importStar(require("path")));
1941
1941
  try {
1942
- await fs29.access(command.path);
1942
+ await fs30.access(command.path);
1943
1943
  return {
1944
1944
  success: false,
1945
1945
  error: "BRANCH_ALREADY_EXISTS",
@@ -1948,9 +1948,9 @@ var require_git_executor = __commonJS({
1948
1948
  };
1949
1949
  } catch {
1950
1950
  }
1951
- const parentDir = path30.dirname(command.path);
1951
+ const parentDir = path31.dirname(command.path);
1952
1952
  try {
1953
- await fs29.mkdir(parentDir, { recursive: true });
1953
+ await fs30.mkdir(parentDir, { recursive: true });
1954
1954
  } catch {
1955
1955
  }
1956
1956
  const { stdout, stderr } = await execAsync3(
@@ -1998,22 +1998,22 @@ var require_git_executor = __commonJS({
1998
1998
  */
1999
1999
  async executeProjectInfo(cwd, options) {
2000
2000
  try {
2001
- const fs29 = await Promise.resolve().then(() => __importStar(require("fs"))).then((m) => m.promises);
2002
- const path30 = await Promise.resolve().then(() => __importStar(require("path")));
2001
+ const fs30 = await Promise.resolve().then(() => __importStar(require("fs"))).then((m) => m.promises);
2002
+ const path31 = await Promise.resolve().then(() => __importStar(require("path")));
2003
2003
  let currentPath = cwd;
2004
2004
  let projectPath = cwd;
2005
2005
  let bareRepoPath;
2006
2006
  for (let i = 0; i < 10; i++) {
2007
- const bareDir = path30.join(currentPath, ".bare");
2008
- const episodaDir = path30.join(currentPath, ".episoda");
2007
+ const bareDir = path31.join(currentPath, ".bare");
2008
+ const episodaDir = path31.join(currentPath, ".episoda");
2009
2009
  try {
2010
- await fs29.access(bareDir);
2011
- await fs29.access(episodaDir);
2010
+ await fs30.access(bareDir);
2011
+ await fs30.access(episodaDir);
2012
2012
  projectPath = currentPath;
2013
2013
  bareRepoPath = bareDir;
2014
2014
  break;
2015
2015
  } catch {
2016
- const parentPath = path30.dirname(currentPath);
2016
+ const parentPath = path31.dirname(currentPath);
2017
2017
  if (parentPath === currentPath) {
2018
2018
  break;
2019
2019
  }
@@ -2674,33 +2674,33 @@ var require_auth = __commonJS({
2674
2674
  exports2.loadConfig = loadConfig16;
2675
2675
  exports2.saveConfig = saveConfig4;
2676
2676
  exports2.validateToken = validateToken;
2677
- var fs29 = __importStar(require("fs"));
2678
- var path30 = __importStar(require("path"));
2677
+ var fs30 = __importStar(require("fs"));
2678
+ var path31 = __importStar(require("path"));
2679
2679
  var os13 = __importStar(require("os"));
2680
2680
  var child_process_1 = require("child_process");
2681
2681
  var DEFAULT_CONFIG_FILE = "config.json";
2682
2682
  var hasWarnedMissingProjectId = false;
2683
2683
  var hasWarnedMissingRequiredFields = false;
2684
2684
  function getConfigDir10() {
2685
- return process.env.EPISODA_CONFIG_DIR || path30.join(os13.homedir(), ".episoda");
2685
+ return process.env.EPISODA_CONFIG_DIR || path31.join(os13.homedir(), ".episoda");
2686
2686
  }
2687
2687
  function getConfigPath(configPath) {
2688
2688
  if (configPath) {
2689
2689
  return configPath;
2690
2690
  }
2691
- return path30.join(getConfigDir10(), DEFAULT_CONFIG_FILE);
2691
+ return path31.join(getConfigDir10(), DEFAULT_CONFIG_FILE);
2692
2692
  }
2693
2693
  function ensureConfigDir(configPath) {
2694
- const dir = path30.dirname(configPath);
2695
- const isNew = !fs29.existsSync(dir);
2694
+ const dir = path31.dirname(configPath);
2695
+ const isNew = !fs30.existsSync(dir);
2696
2696
  if (isNew) {
2697
- fs29.mkdirSync(dir, { recursive: true, mode: 448 });
2697
+ fs30.mkdirSync(dir, { recursive: true, mode: 448 });
2698
2698
  }
2699
2699
  if (process.platform === "darwin") {
2700
- const nosyncPath = path30.join(dir, ".nosync");
2701
- if (isNew || !fs29.existsSync(nosyncPath)) {
2700
+ const nosyncPath = path31.join(dir, ".nosync");
2701
+ if (isNew || !fs30.existsSync(nosyncPath)) {
2702
2702
  try {
2703
- fs29.writeFileSync(nosyncPath, "", { mode: 384 });
2703
+ fs30.writeFileSync(nosyncPath, "", { mode: 384 });
2704
2704
  (0, child_process_1.execSync)(`xattr -w com.apple.fileprovider.ignore 1 "${dir}"`, {
2705
2705
  stdio: "ignore",
2706
2706
  timeout: 5e3
@@ -2714,11 +2714,11 @@ var require_auth = __commonJS({
2714
2714
  const fullPath = getConfigPath(configPath);
2715
2715
  const isCloudMode = process.env.EPISODA_MODE === "cloud";
2716
2716
  const readConfigFile = (pathToFile) => {
2717
- if (!fs29.existsSync(pathToFile)) {
2717
+ if (!fs30.existsSync(pathToFile)) {
2718
2718
  return null;
2719
2719
  }
2720
2720
  try {
2721
- const content = fs29.readFileSync(pathToFile, "utf8");
2721
+ const content = fs30.readFileSync(pathToFile, "utf8");
2722
2722
  return JSON.parse(content);
2723
2723
  } catch (error) {
2724
2724
  console.error("Error loading config:", error);
@@ -2757,11 +2757,11 @@ var require_auth = __commonJS({
2757
2757
  }
2758
2758
  const homeDir = process.env.HOME || require("os").homedir();
2759
2759
  const workspaceConfigPath = require("path").join(homeDir, "episoda", process.env.EPISODA_WORKSPACE, ".episoda", "config.json");
2760
- if (!fs29.existsSync(workspaceConfigPath)) {
2760
+ if (!fs30.existsSync(workspaceConfigPath)) {
2761
2761
  return null;
2762
2762
  }
2763
2763
  try {
2764
- const content = fs29.readFileSync(workspaceConfigPath, "utf8");
2764
+ const content = fs30.readFileSync(workspaceConfigPath, "utf8");
2765
2765
  const workspaceConfig2 = JSON.parse(content);
2766
2766
  const expiresAtEnv = envValue(process.env.EPISODA_ACCESS_TOKEN_EXPIRES_AT);
2767
2767
  return {
@@ -2789,11 +2789,11 @@ var require_auth = __commonJS({
2789
2789
  }
2790
2790
  const homeDir = process.env.HOME || require("os").homedir();
2791
2791
  const projectConfigPath = require("path").join(homeDir, "episoda", workspaceSlug, projectSlug, ".episoda", "config.json");
2792
- if (!fs29.existsSync(projectConfigPath)) {
2792
+ if (!fs30.existsSync(projectConfigPath)) {
2793
2793
  return null;
2794
2794
  }
2795
2795
  try {
2796
- const content = fs29.readFileSync(projectConfigPath, "utf8");
2796
+ const content = fs30.readFileSync(projectConfigPath, "utf8");
2797
2797
  const projectConfig2 = JSON.parse(content);
2798
2798
  return {
2799
2799
  project_id: projectConfig2.projectId || projectConfig2.project_id,
@@ -2861,7 +2861,7 @@ var require_auth = __commonJS({
2861
2861
  ensureConfigDir(fullPath);
2862
2862
  try {
2863
2863
  const content = JSON.stringify(config, null, 2);
2864
- fs29.writeFileSync(fullPath, content, { mode: 384 });
2864
+ fs30.writeFileSync(fullPath, content, { mode: 384 });
2865
2865
  } catch (error) {
2866
2866
  throw new Error(`Failed to save config: ${error instanceof Error ? error.message : String(error)}`);
2867
2867
  }
@@ -2978,7 +2978,7 @@ var require_package = __commonJS({
2978
2978
  "package.json"(exports2, module2) {
2979
2979
  module2.exports = {
2980
2980
  name: "@episoda/cli",
2981
- version: "0.2.164",
2981
+ version: "0.2.166",
2982
2982
  description: "CLI tool for Episoda local development workflow orchestration",
2983
2983
  main: "dist/index.js",
2984
2984
  types: "dist/index.d.ts",
@@ -4979,7 +4979,9 @@ var import_core9 = __toESM(require_dist());
4979
4979
 
4980
4980
  // src/agent/claude-persistent-runtime.ts
4981
4981
  var import_child_process7 = require("child_process");
4982
- var ECHO_TIMEOUT_MS = parseInt(process.env.AGENT_ECHO_TIMEOUT_MS || "10000", 10);
4982
+ var DEFAULT_STARTUP_GRACE_MS = 3e4;
4983
+ var HEARTBEAT_ACK_MARKER = "__EPISODA_HEARTBEAT_ACK__";
4984
+ var ECHO_TIMEOUT_MS = parseInt(process.env.AGENT_ECHO_TIMEOUT_MS || `${DEFAULT_STARTUP_GRACE_MS}`, 10);
4983
4985
  var INACTIVITY_TIMEOUT_MS = parseInt(process.env.AGENT_STREAM_INACTIVITY_TIMEOUT_MS || "180000", 10);
4984
4986
  var SHUTDOWN_SIGTERM_WAIT_MS = 2e3;
4985
4987
  var SHUTDOWN_SIGKILL_WAIT_MS = 2e3;
@@ -5015,7 +5017,6 @@ var ClaudePersistentRuntime = class {
5015
5017
  this.echoTimer = null;
5016
5018
  this.inactivityTimer = null;
5017
5019
  this.turnStartTime = 0;
5018
- this.sawAnyStdoutThisTurn = false;
5019
5020
  // EP1360: Instrumentation
5020
5021
  this.spawnTimestamp = 0;
5021
5022
  this.sessionId = options.sessionId;
@@ -5055,6 +5056,11 @@ var ClaudePersistentRuntime = class {
5055
5056
  this.alive = true;
5056
5057
  this.process.stderr?.on("data", (data) => {
5057
5058
  const chunk = data.toString();
5059
+ this.resetInactivityTimer();
5060
+ if (this._turnState === "waiting_for_echo") {
5061
+ const source = chunk.includes(HEARTBEAT_ACK_MARKER) ? "stderr-marker" : "stderr";
5062
+ this.recordStartupHeartbeatAck(source);
5063
+ }
5058
5064
  this.stderrTail = (this.stderrTail + chunk).slice(-this.maxStderrTailBytes);
5059
5065
  if (RUNTIME_DEBUG) {
5060
5066
  console.error(`[ClaudePersistentRuntime] stderr (session=${this.sessionId}): ${chunk.trimEnd()}`);
@@ -5062,6 +5068,7 @@ var ClaudePersistentRuntime = class {
5062
5068
  });
5063
5069
  this.process.stdout?.on("data", (data) => {
5064
5070
  this.resetInactivityTimer();
5071
+ this.recordStartupHeartbeatAck("stdout");
5065
5072
  this.stdoutBuffer += data.toString();
5066
5073
  const lines = this.stdoutBuffer.split("\n");
5067
5074
  this.stdoutBuffer = lines.pop() || "";
@@ -5112,7 +5119,6 @@ var ClaudePersistentRuntime = class {
5112
5119
  this.turnStartTime = Date.now();
5113
5120
  this.turnTtftLogged = false;
5114
5121
  this.seenToolUseIds.clear();
5115
- this.sawAnyStdoutThisTurn = false;
5116
5122
  this._turnState = "waiting_for_echo";
5117
5123
  const payload = JSON.stringify({ type: "user", message: { role: "user", content: message } }) + "\n";
5118
5124
  try {
@@ -5125,9 +5131,9 @@ var ClaudePersistentRuntime = class {
5125
5131
  }
5126
5132
  this.echoTimer = setTimeout(() => {
5127
5133
  if (this._turnState === "waiting_for_echo") {
5128
- console.warn(`[ClaudePersistentRuntime] Echo timeout after ${ECHO_TIMEOUT_MS}ms \u2014 auto-degrading. session=${this.sessionId}`);
5134
+ console.warn(`[ClaudePersistentRuntime] Startup heartbeat timeout after ${ECHO_TIMEOUT_MS}ms \u2014 auto-degrading. session=${this.sessionId}`);
5129
5135
  if (this.callbacks) {
5130
- this.callbacks.onError(`ECHO_TIMEOUT: No stdout event within ${ECHO_TIMEOUT_MS}ms after send`);
5136
+ this.callbacks.onError(`ECHO_TIMEOUT: No startup heartbeat within ${ECHO_TIMEOUT_MS}ms after send`);
5131
5137
  this.endTurn();
5132
5138
  }
5133
5139
  }
@@ -5210,14 +5216,7 @@ var ClaudePersistentRuntime = class {
5210
5216
  }
5211
5217
  handleParsedEvent(parsed) {
5212
5218
  const type = parsed.type;
5213
- if (this._turnState === "waiting_for_echo") {
5214
- this.sawAnyStdoutThisTurn = true;
5215
- this.clearEchoTimer();
5216
- this._turnState = "streaming";
5217
- if (RUNTIME_DEBUG) {
5218
- console.log(`[ClaudePersistentRuntime] First stdout for turn \u2014 streaming started. session=${this.sessionId}`);
5219
- }
5220
- }
5219
+ this.recordStartupHeartbeatAck("stdout");
5221
5220
  if (type === "user") {
5222
5221
  return;
5223
5222
  }
@@ -5403,6 +5402,14 @@ var ClaudePersistentRuntime = class {
5403
5402
  this.endTurn();
5404
5403
  cb.onComplete(this._agentSessionId, resultMeta);
5405
5404
  }
5405
+ recordStartupHeartbeatAck(source) {
5406
+ if (this._turnState !== "waiting_for_echo") return;
5407
+ this.clearEchoTimer();
5408
+ this._turnState = "streaming";
5409
+ if (RUNTIME_DEBUG) {
5410
+ console.log(`[ClaudePersistentRuntime] Startup heartbeat ack via ${source}; streaming started. session=${this.sessionId}`);
5411
+ }
5412
+ }
5406
5413
  endTurn() {
5407
5414
  this.clearTimers();
5408
5415
  this.callbacks = null;
@@ -9472,7 +9479,7 @@ function getInstallCommand(cwd) {
9472
9479
  }
9473
9480
 
9474
9481
  // src/daemon/daemon-process.ts
9475
- var fs28 = __toESM(require("fs"));
9482
+ var fs29 = __toESM(require("fs"));
9476
9483
  var http2 = __toESM(require("http"));
9477
9484
  var os12 = __toESM(require("os"));
9478
9485
 
@@ -10280,8 +10287,8 @@ async function handleExec(command, projectPath) {
10280
10287
  }
10281
10288
 
10282
10289
  // src/daemon/handlers/worktree-handlers.ts
10283
- var path23 = __toESM(require("path"));
10284
- var fs22 = __toESM(require("fs"));
10290
+ var path24 = __toESM(require("path"));
10291
+ var fs23 = __toESM(require("fs"));
10285
10292
  var os10 = __toESM(require("os"));
10286
10293
  var import_child_process15 = require("child_process");
10287
10294
  var import_util2 = require("util");
@@ -11628,7 +11635,7 @@ function pnpmCommand(args) {
11628
11635
  ' echo "[setup] ERROR: pnpm is not installed and corepack is unavailable" >&2',
11629
11636
  " exit 127",
11630
11637
  "fi"
11631
- ].join(" ");
11638
+ ].join("\n");
11632
11639
  }
11633
11640
  var PACKAGE_MANAGERS = {
11634
11641
  javascript: [
@@ -11765,6 +11772,51 @@ function detectPackageManager(worktreePath, preferredLanguages) {
11765
11772
  };
11766
11773
  }
11767
11774
 
11775
+ // src/daemon/build-packages.ts
11776
+ var fs22 = __toESM(require("fs"));
11777
+ var path23 = __toESM(require("path"));
11778
+ function hasPackageScript(worktreePath, scriptName) {
11779
+ try {
11780
+ const packageJsonPath = path23.join(worktreePath, "package.json");
11781
+ if (!fs22.existsSync(packageJsonPath)) {
11782
+ return false;
11783
+ }
11784
+ const packageJson2 = JSON.parse(fs22.readFileSync(packageJsonPath, "utf-8"));
11785
+ return typeof packageJson2.scripts?.[scriptName] === "string";
11786
+ } catch {
11787
+ return false;
11788
+ }
11789
+ }
11790
+ function getBuildPackagesCommand(packageManagerName, hasBuildPackagesScript) {
11791
+ if (!hasBuildPackagesScript) {
11792
+ return null;
11793
+ }
11794
+ switch (packageManagerName) {
11795
+ case "pnpm":
11796
+ return [
11797
+ "if command -v pnpm >/dev/null 2>&1; then",
11798
+ " pnpm run build:packages",
11799
+ "elif command -v corepack >/dev/null 2>&1; then",
11800
+ " corepack pnpm run build:packages",
11801
+ "else",
11802
+ ' echo "[setup] ERROR: pnpm is not installed and corepack is unavailable" >&2',
11803
+ " exit 127",
11804
+ "fi"
11805
+ ].join("\n");
11806
+ case "yarn":
11807
+ return "yarn build:packages";
11808
+ case "npm":
11809
+ return "npm run build:packages";
11810
+ case "bun":
11811
+ return "bun run build:packages";
11812
+ default:
11813
+ return null;
11814
+ }
11815
+ }
11816
+ function shouldRunBuildPackagesBootstrap(installSucceeded, buildPackagesCommand) {
11817
+ return installSucceeded && !!buildPackagesCommand;
11818
+ }
11819
+
11768
11820
  // src/daemon/handlers/worktree-handlers.ts
11769
11821
  async function getConfigForApi() {
11770
11822
  if (process.env.EPISODA_MODE === "cloud" && process.env.EPISODA_ACCESS_TOKEN) {
@@ -11788,18 +11840,18 @@ function persistWorkspaceProjectContext(workspaceSlug, projectSlug, projectId) {
11788
11840
  return;
11789
11841
  }
11790
11842
  const homeDir = process.env.HOME || os10.homedir();
11791
- const workspaceConfigPath = path23.join(
11843
+ const workspaceConfigPath = path24.join(
11792
11844
  homeDir,
11793
11845
  "episoda",
11794
11846
  workspaceSlug,
11795
11847
  ".episoda",
11796
11848
  "config.json"
11797
11849
  );
11798
- if (!fs22.existsSync(workspaceConfigPath)) {
11850
+ if (!fs23.existsSync(workspaceConfigPath)) {
11799
11851
  return;
11800
11852
  }
11801
11853
  try {
11802
- const content = fs22.readFileSync(workspaceConfigPath, "utf8");
11854
+ const content = fs23.readFileSync(workspaceConfigPath, "utf8");
11803
11855
  const workspaceConfig = JSON.parse(content);
11804
11856
  let changed = false;
11805
11857
  if (projectId && workspaceConfig.projectId !== projectId && workspaceConfig.project_id !== projectId) {
@@ -11811,7 +11863,7 @@ function persistWorkspaceProjectContext(workspaceSlug, projectSlug, projectId) {
11811
11863
  changed = true;
11812
11864
  }
11813
11865
  if (changed) {
11814
- fs22.writeFileSync(workspaceConfigPath, JSON.stringify(workspaceConfig, null, 2), "utf8");
11866
+ fs23.writeFileSync(workspaceConfigPath, JSON.stringify(workspaceConfig, null, 2), "utf8");
11815
11867
  console.log("[Worktree] Updated workspace config with project context");
11816
11868
  }
11817
11869
  } catch (error) {
@@ -11828,32 +11880,6 @@ async function autoDetectSetupScript(worktreePath) {
11828
11880
  console.log(`[Worktree] EP1222: Detected ${name} (${language}) via ${detection.matchedFile}`);
11829
11881
  return installCmd;
11830
11882
  }
11831
- function getBuildPackagesCommand(packageManagerName) {
11832
- switch (packageManagerName) {
11833
- case "pnpm":
11834
- return 'if command -v pnpm >/dev/null 2>&1; then pnpm run build:packages; elif command -v corepack >/dev/null 2>&1; then corepack pnpm run build:packages; else echo "[setup] ERROR: pnpm is not installed and corepack is unavailable" >&2; exit 127; fi';
11835
- case "yarn":
11836
- return "yarn build:packages";
11837
- case "npm":
11838
- return "npm run build:packages";
11839
- case "bun":
11840
- return "bun run build:packages";
11841
- default:
11842
- return null;
11843
- }
11844
- }
11845
- function hasPackageScript(worktreePath, scriptName) {
11846
- try {
11847
- const packageJsonPath = path23.join(worktreePath, "package.json");
11848
- if (!fs22.existsSync(packageJsonPath)) {
11849
- return false;
11850
- }
11851
- const packageJson2 = JSON.parse(fs22.readFileSync(packageJsonPath, "utf-8"));
11852
- return typeof packageJson2.scripts?.[scriptName] === "string";
11853
- } catch {
11854
- return false;
11855
- }
11856
- }
11857
11883
  async function handleWorktreeCreate(request2) {
11858
11884
  const {
11859
11885
  workspaceSlug,
@@ -11884,19 +11910,19 @@ async function handleWorktreeCreate(request2) {
11884
11910
  }
11885
11911
  try {
11886
11912
  const projectPath = getProjectPath(workspaceSlug, projectSlug);
11887
- const bareRepoPath = path23.join(projectPath, ".bare");
11913
+ const bareRepoPath = path24.join(projectPath, ".bare");
11888
11914
  const gitEnv = projectId ? { ...process.env, EPISODA_PROJECT_ID: projectId } : process.env;
11889
- if (!fs22.existsSync(bareRepoPath)) {
11915
+ if (!fs23.existsSync(bareRepoPath)) {
11890
11916
  console.log(`[Worktree] K1273: Project not found, cloning lazily...`);
11891
11917
  console.log(`[Worktree] Repo URL: ${repoUrl.replace(/\/\/[^@]*@/, "//***@")}`);
11892
- const episodaDir = path23.join(projectPath, ".episoda");
11893
- fs22.mkdirSync(episodaDir, { recursive: true });
11918
+ const episodaDir = path24.join(projectPath, ".episoda");
11919
+ fs23.mkdirSync(episodaDir, { recursive: true });
11894
11920
  try {
11895
11921
  console.log(`[Worktree] K1273: Starting git clone...`);
11896
11922
  await execAsync2(`git clone --bare "${repoUrl}" "${bareRepoPath}"`, { env: gitEnv });
11897
11923
  console.log(`[Worktree] K1273: Clone successful`);
11898
11924
  await execAsync2(`git -C "${bareRepoPath}" config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*"`, { env: gitEnv });
11899
- const configPath = path23.join(episodaDir, "config.json");
11925
+ const configPath = path24.join(episodaDir, "config.json");
11900
11926
  const config = {
11901
11927
  projectId,
11902
11928
  workspaceSlug,
@@ -11905,7 +11931,7 @@ async function handleWorktreeCreate(request2) {
11905
11931
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
11906
11932
  worktrees: []
11907
11933
  };
11908
- fs22.writeFileSync(configPath, JSON.stringify(config, null, 2), "utf-8");
11934
+ fs23.writeFileSync(configPath, JSON.stringify(config, null, 2), "utf-8");
11909
11935
  console.log(`[Worktree] K1273: Project initialized at ${projectPath}`);
11910
11936
  } catch (cloneError) {
11911
11937
  console.error(`[Worktree] K1273: Git clone failed: ${cloneError.message}`);
@@ -11940,16 +11966,16 @@ async function handleWorktreeCreate(request2) {
11940
11966
  let finalError;
11941
11967
  if (envVars && Object.keys(envVars).length > 0) {
11942
11968
  const envContent = Object.entries(envVars).map(([key, value]) => `${key}=${value}`).join("\n");
11943
- const envPath = path23.join(worktreePath, ".env");
11944
- fs22.writeFileSync(envPath, envContent + "\n", "utf-8");
11969
+ const envPath = path24.join(worktreePath, ".env");
11970
+ fs23.writeFileSync(envPath, envContent + "\n", "utf-8");
11945
11971
  console.log(`[Worktree] EP1143: Wrote ${Object.keys(envVars).length} env vars to .env`);
11946
11972
  }
11947
11973
  const isCloud = process.env.EPISODA_MODE === "cloud";
11948
11974
  let effectiveSetupScript = setupScript || await autoDetectSetupScript(worktreePath);
11949
11975
  const detection = detectPackageManager(worktreePath);
11950
- const buildCmd = getBuildPackagesCommand(detection.packageManager?.name);
11951
11976
  const hasBuildPackages = hasPackageScript(worktreePath, "build:packages");
11952
- if (buildCmd && hasBuildPackages && !effectiveSetupScript?.includes("build:packages")) {
11977
+ const buildCmd = getBuildPackagesCommand(detection.packageManager?.name, hasBuildPackages);
11978
+ if (buildCmd && !effectiveSetupScript?.includes("build:packages")) {
11953
11979
  effectiveSetupScript = effectiveSetupScript ? `${effectiveSetupScript}
11954
11980
  ${buildCmd}` : buildCmd;
11955
11981
  console.log(`[Worktree] EP1386: Added build:packages bootstrap for ${isCloud ? "cloud" : "local"} setup`);
@@ -12082,12 +12108,12 @@ async function handleProjectEject(request2) {
12082
12108
  console.log(`[Worktree] EP1144: Ejecting project ${projectSlug} from workspace ${workspaceSlug}`);
12083
12109
  try {
12084
12110
  const projectPath = getProjectPath(workspaceSlug, projectSlug);
12085
- const bareRepoPath = path23.join(projectPath, ".bare");
12086
- if (!fs22.existsSync(projectPath)) {
12111
+ const bareRepoPath = path24.join(projectPath, ".bare");
12112
+ if (!fs23.existsSync(projectPath)) {
12087
12113
  console.log(`[Worktree] EP1144: Project path not found, nothing to eject: ${projectPath}`);
12088
12114
  return { success: true };
12089
12115
  }
12090
- if (!fs22.existsSync(bareRepoPath)) {
12116
+ if (!fs23.existsSync(bareRepoPath)) {
12091
12117
  console.log(`[Worktree] EP1144: Bare repo not found, nothing to eject: ${bareRepoPath}`);
12092
12118
  return { success: true };
12093
12119
  }
@@ -12102,12 +12128,12 @@ async function handleProjectEject(request2) {
12102
12128
  };
12103
12129
  }
12104
12130
  }
12105
- const artifactsPath = path23.join(projectPath, "artifacts");
12106
- if (fs22.existsSync(artifactsPath)) {
12131
+ const artifactsPath = path24.join(projectPath, "artifacts");
12132
+ if (fs23.existsSync(artifactsPath)) {
12107
12133
  await persistArtifactsBeforeEject(artifactsPath, projectId, projectSlug);
12108
12134
  }
12109
12135
  console.log(`[Worktree] EP1144: Removing project directory: ${projectPath}`);
12110
- await fs22.promises.rm(projectPath, { recursive: true, force: true });
12136
+ await fs23.promises.rm(projectPath, { recursive: true, force: true });
12111
12137
  console.log(`[Worktree] EP1144: Successfully ejected project ${projectSlug}`);
12112
12138
  return { success: true };
12113
12139
  } catch (error) {
@@ -12121,7 +12147,7 @@ async function handleProjectEject(request2) {
12121
12147
  async function persistArtifactsBeforeEject(artifactsPath, projectId, projectSlug) {
12122
12148
  const MAX_ARTIFACT_SIZE = 10 * 1024 * 1024;
12123
12149
  try {
12124
- const files = await fs22.promises.readdir(artifactsPath);
12150
+ const files = await fs23.promises.readdir(artifactsPath);
12125
12151
  if (files.length === 0) {
12126
12152
  return;
12127
12153
  }
@@ -12135,8 +12161,8 @@ async function persistArtifactsBeforeEject(artifactsPath, projectId, projectSlug
12135
12161
  }
12136
12162
  const artifacts = [];
12137
12163
  for (const fileName of files) {
12138
- const filePath = path23.join(artifactsPath, fileName);
12139
- const stat = await fs22.promises.stat(filePath);
12164
+ const filePath = path24.join(artifactsPath, fileName);
12165
+ const stat = await fs23.promises.stat(filePath);
12140
12166
  if (stat.isDirectory()) {
12141
12167
  continue;
12142
12168
  }
@@ -12145,9 +12171,9 @@ async function persistArtifactsBeforeEject(artifactsPath, projectId, projectSlug
12145
12171
  continue;
12146
12172
  }
12147
12173
  try {
12148
- const content = await fs22.promises.readFile(filePath);
12174
+ const content = await fs23.promises.readFile(filePath);
12149
12175
  const base64Content = content.toString("base64");
12150
- const ext = path23.extname(fileName).toLowerCase();
12176
+ const ext = path24.extname(fileName).toLowerCase();
12151
12177
  const mimeTypes = {
12152
12178
  ".json": "application/json",
12153
12179
  ".txt": "text/plain",
@@ -12203,8 +12229,8 @@ async function persistArtifactsBeforeEject(artifactsPath, projectId, projectSlug
12203
12229
  }
12204
12230
 
12205
12231
  // src/daemon/handlers/project-handlers.ts
12206
- var path24 = __toESM(require("path"));
12207
- var fs23 = __toESM(require("fs"));
12232
+ var path25 = __toESM(require("path"));
12233
+ var fs24 = __toESM(require("fs"));
12208
12234
  function validateSlug(slug, fieldName) {
12209
12235
  if (!slug || typeof slug !== "string") {
12210
12236
  return `${fieldName} is required`;
@@ -12244,14 +12270,14 @@ async function handleProjectSetup(params) {
12244
12270
  console.log(`[ProjectSetup] EP1199: Setting up project ${workspaceSlug}/${projectSlug}`);
12245
12271
  try {
12246
12272
  const projectPath = getProjectPath(workspaceSlug, projectSlug);
12247
- const artifactsPath = path24.join(projectPath, "artifacts");
12248
- const configDir = path24.join(projectPath, ".episoda");
12249
- const configPath = path24.join(configDir, "config.json");
12250
- await fs23.promises.mkdir(artifactsPath, { recursive: true });
12251
- await fs23.promises.mkdir(configDir, { recursive: true });
12273
+ const artifactsPath = path25.join(projectPath, "artifacts");
12274
+ const configDir = path25.join(projectPath, ".episoda");
12275
+ const configPath = path25.join(configDir, "config.json");
12276
+ await fs24.promises.mkdir(artifactsPath, { recursive: true });
12277
+ await fs24.promises.mkdir(configDir, { recursive: true });
12252
12278
  let existingConfig = {};
12253
12279
  try {
12254
- const existing = await fs23.promises.readFile(configPath, "utf-8");
12280
+ const existing = await fs24.promises.readFile(configPath, "utf-8");
12255
12281
  existingConfig = JSON.parse(existing);
12256
12282
  } catch {
12257
12283
  }
@@ -12264,7 +12290,7 @@ async function handleProjectSetup(params) {
12264
12290
  // Only set created_at if not already present
12265
12291
  created_at: existingConfig.created_at || (/* @__PURE__ */ new Date()).toISOString()
12266
12292
  };
12267
- await fs23.promises.writeFile(configPath, JSON.stringify(config, null, 2));
12293
+ await fs24.promises.writeFile(configPath, JSON.stringify(config, null, 2));
12268
12294
  console.log(`[ProjectSetup] EP1199: Project setup complete at ${projectPath}`);
12269
12295
  return {
12270
12296
  success: true,
@@ -12284,8 +12310,8 @@ async function handleProjectSetup(params) {
12284
12310
  // src/utils/dev-server.ts
12285
12311
  var import_child_process16 = require("child_process");
12286
12312
  var import_core14 = __toESM(require_dist());
12287
- var fs24 = __toESM(require("fs"));
12288
- var path25 = __toESM(require("path"));
12313
+ var fs25 = __toESM(require("fs"));
12314
+ var path26 = __toESM(require("path"));
12289
12315
  var MAX_RESTART_ATTEMPTS = 5;
12290
12316
  var INITIAL_RESTART_DELAY_MS = 2e3;
12291
12317
  var MAX_RESTART_DELAY_MS = 3e4;
@@ -12293,26 +12319,26 @@ var MAX_LOG_SIZE_BYTES2 = 5 * 1024 * 1024;
12293
12319
  var NODE_MEMORY_LIMIT_MB = 2048;
12294
12320
  var activeServers = /* @__PURE__ */ new Map();
12295
12321
  function getLogsDir() {
12296
- const logsDir = path25.join((0, import_core14.getConfigDir)(), "logs");
12297
- if (!fs24.existsSync(logsDir)) {
12298
- fs24.mkdirSync(logsDir, { recursive: true });
12322
+ const logsDir = path26.join((0, import_core14.getConfigDir)(), "logs");
12323
+ if (!fs25.existsSync(logsDir)) {
12324
+ fs25.mkdirSync(logsDir, { recursive: true });
12299
12325
  }
12300
12326
  return logsDir;
12301
12327
  }
12302
12328
  function getLogFilePath(moduleUid) {
12303
- return path25.join(getLogsDir(), `dev-${moduleUid}.log`);
12329
+ return path26.join(getLogsDir(), `dev-${moduleUid}.log`);
12304
12330
  }
12305
12331
  function rotateLogIfNeeded(logPath) {
12306
12332
  try {
12307
- if (fs24.existsSync(logPath)) {
12308
- const stats = fs24.statSync(logPath);
12333
+ if (fs25.existsSync(logPath)) {
12334
+ const stats = fs25.statSync(logPath);
12309
12335
  if (stats.size > MAX_LOG_SIZE_BYTES2) {
12310
12336
  const backupPath = `${logPath}.1`;
12311
- if (fs24.existsSync(backupPath)) {
12312
- fs24.unlinkSync(backupPath);
12337
+ if (fs25.existsSync(backupPath)) {
12338
+ fs25.unlinkSync(backupPath);
12313
12339
  }
12314
- fs24.renameSync(logPath, backupPath);
12315
- console.log(`[DevServer] EP932: Rotated log file for ${path25.basename(logPath)}`);
12340
+ fs25.renameSync(logPath, backupPath);
12341
+ console.log(`[DevServer] EP932: Rotated log file for ${path26.basename(logPath)}`);
12316
12342
  }
12317
12343
  }
12318
12344
  } catch (error) {
@@ -12325,7 +12351,7 @@ function writeToLog(logPath, line, isError = false) {
12325
12351
  const prefix = isError ? "ERR" : "OUT";
12326
12352
  const logLine = `[${timestamp}] [${prefix}] ${line}
12327
12353
  `;
12328
- fs24.appendFileSync(logPath, logLine);
12354
+ fs25.appendFileSync(logPath, logLine);
12329
12355
  } catch {
12330
12356
  }
12331
12357
  }
@@ -12504,8 +12530,8 @@ async function startDevServer(projectPath, port = 3e3, moduleUid = "default", op
12504
12530
  });
12505
12531
  injectedEnvVars = result.envVars;
12506
12532
  console.log(`[DevServer] EP998: Loaded ${Object.keys(injectedEnvVars).length} env vars (from ${result.fromCache ? "cache" : "server"})`);
12507
- const envFilePath = path25.join(projectPath, ".env");
12508
- if (!fs24.existsSync(envFilePath) && Object.keys(injectedEnvVars).length > 0) {
12533
+ const envFilePath = path26.join(projectPath, ".env");
12534
+ if (!fs25.existsSync(envFilePath) && Object.keys(injectedEnvVars).length > 0) {
12509
12535
  console.log(`[DevServer] EP1004: .env file missing, writing ${Object.keys(injectedEnvVars).length} vars to ${envFilePath}`);
12510
12536
  writeEnvFile(projectPath, injectedEnvVars);
12511
12537
  }
@@ -12846,8 +12872,8 @@ var IPCRouter = class {
12846
12872
  };
12847
12873
 
12848
12874
  // src/daemon/update-manager.ts
12849
- var fs25 = __toESM(require("fs"));
12850
- var path26 = __toESM(require("path"));
12875
+ var fs26 = __toESM(require("fs"));
12876
+ var path27 = __toESM(require("path"));
12851
12877
  var import_child_process18 = require("child_process");
12852
12878
  var import_core17 = __toESM(require_dist());
12853
12879
  var semver2 = __toESM(require("semver"));
@@ -13105,8 +13131,8 @@ var UpdateManager = class _UpdateManager {
13105
13131
  console.log(`[Daemon] EP1324: Update to ${targetVersion} installed, restarting daemon...`);
13106
13132
  await this.host.shutdown();
13107
13133
  const configDir = (0, import_core17.getConfigDir)();
13108
- const logPath = path26.join(configDir, "daemon.log");
13109
- const logFd = fs25.openSync(logPath, "a");
13134
+ const logPath = path27.join(configDir, "daemon.log");
13135
+ const logFd = fs26.openSync(logPath, "a");
13110
13136
  const child = (0, import_child_process18.spawn)("node", [this.daemonEntryFile], {
13111
13137
  detached: true,
13112
13138
  stdio: ["ignore", logFd, logFd],
@@ -13114,7 +13140,7 @@ var UpdateManager = class _UpdateManager {
13114
13140
  });
13115
13141
  if (!child.pid) {
13116
13142
  try {
13117
- fs25.closeSync(logFd);
13143
+ fs26.closeSync(logFd);
13118
13144
  } catch {
13119
13145
  }
13120
13146
  this.recordUpdateFailure(targetVersion, "Failed to spawn replacement daemon (missing pid)");
@@ -13122,7 +13148,7 @@ var UpdateManager = class _UpdateManager {
13122
13148
  }
13123
13149
  child.unref();
13124
13150
  const pidPath = getPidFilePath();
13125
- fs25.writeFileSync(pidPath, child.pid.toString(), "utf-8");
13151
+ fs26.writeFileSync(pidPath, child.pid.toString(), "utf-8");
13126
13152
  console.log(`[Daemon] EP1324: New daemon spawned (PID: ${child.pid}), exiting old process`);
13127
13153
  process.exit(0);
13128
13154
  } catch (error) {
@@ -13173,8 +13199,8 @@ var UpdateManager = class _UpdateManager {
13173
13199
  };
13174
13200
 
13175
13201
  // src/daemon/health-orchestrator.ts
13176
- var fs26 = __toESM(require("fs"));
13177
- var path27 = __toESM(require("path"));
13202
+ var fs27 = __toESM(require("fs"));
13203
+ var path28 = __toESM(require("path"));
13178
13204
  var import_core18 = __toESM(require_dist());
13179
13205
  var HealthOrchestrator = class _HealthOrchestrator {
13180
13206
  constructor(host) {
@@ -13416,26 +13442,26 @@ var HealthOrchestrator = class _HealthOrchestrator {
13416
13442
  checkAndRotateLog() {
13417
13443
  try {
13418
13444
  const configDir = (0, import_core18.getConfigDir)();
13419
- const logPath = path27.join(configDir, "daemon.log");
13420
- if (!fs26.existsSync(logPath)) return;
13421
- const stats = fs26.statSync(logPath);
13445
+ const logPath = path28.join(configDir, "daemon.log");
13446
+ if (!fs27.existsSync(logPath)) return;
13447
+ const stats = fs27.statSync(logPath);
13422
13448
  if (stats.size < _HealthOrchestrator.MAX_LOG_SIZE_BYTES) return;
13423
13449
  console.log(`[Daemon] EP1351: daemon.log is ${Math.round(stats.size / 1024 / 1024)}MB, rotating...`);
13424
13450
  for (let i = _HealthOrchestrator.MAX_LOG_FILES - 1; i >= 1; i--) {
13425
13451
  const src = `${logPath}.${i}`;
13426
13452
  const dst = `${logPath}.${i + 1}`;
13427
- if (fs26.existsSync(src)) {
13453
+ if (fs27.existsSync(src)) {
13428
13454
  try {
13429
- fs26.renameSync(src, dst);
13455
+ fs27.renameSync(src, dst);
13430
13456
  } catch {
13431
13457
  }
13432
13458
  }
13433
13459
  }
13434
13460
  try {
13435
- fs26.copyFileSync(logPath, `${logPath}.1`);
13461
+ fs27.copyFileSync(logPath, `${logPath}.1`);
13436
13462
  } catch {
13437
13463
  }
13438
- fs26.truncateSync(logPath, 0);
13464
+ fs27.truncateSync(logPath, 0);
13439
13465
  console.log("[Daemon] EP1351: Log rotated successfully");
13440
13466
  } catch (error) {
13441
13467
  console.warn("[Daemon] EP1351: Log rotation failed:", error instanceof Error ? error.message : error);
@@ -13865,7 +13891,7 @@ function resolveDaemonWsEndpoint(config, env = process.env) {
13865
13891
 
13866
13892
  // src/daemon/project-message-router.ts
13867
13893
  var import_core19 = __toESM(require_dist());
13868
- var path28 = __toESM(require("path"));
13894
+ var path29 = __toESM(require("path"));
13869
13895
  var ProjectMessageRouter = class {
13870
13896
  constructor(host) {
13871
13897
  this.host = host;
@@ -13882,7 +13908,7 @@ var ProjectMessageRouter = class {
13882
13908
  client.updateActivity();
13883
13909
  try {
13884
13910
  const gitCmd = message.command;
13885
- const bareRepoPath = path28.join(projectPath, ".bare");
13911
+ const bareRepoPath = path29.join(projectPath, ".bare");
13886
13912
  const cwd = gitCmd.worktreePath || bareRepoPath;
13887
13913
  if (gitCmd.worktreePath) {
13888
13914
  console.log(`[Daemon] Routing command to worktree: ${gitCmd.worktreePath}`);
@@ -14222,32 +14248,32 @@ async function fetchEnvVars2(projectId) {
14222
14248
  }
14223
14249
 
14224
14250
  // src/daemon/project-git-config.ts
14225
- var fs27 = __toESM(require("fs"));
14226
- var path29 = __toESM(require("path"));
14251
+ var fs28 = __toESM(require("fs"));
14252
+ var path30 = __toESM(require("path"));
14227
14253
  var import_core21 = __toESM(require_dist());
14228
14254
  function getGitDirs(projectPath) {
14229
- const bareDir = path29.join(projectPath, ".bare");
14230
- const gitPath = path29.join(projectPath, ".git");
14231
- if (fs27.existsSync(bareDir) && fs27.statSync(bareDir).isDirectory()) {
14255
+ const bareDir = path30.join(projectPath, ".bare");
14256
+ const gitPath = path30.join(projectPath, ".git");
14257
+ if (fs28.existsSync(bareDir) && fs28.statSync(bareDir).isDirectory()) {
14232
14258
  return { gitDir: bareDir, workDir: projectPath };
14233
14259
  }
14234
- if (fs27.existsSync(gitPath) && fs27.statSync(gitPath).isDirectory()) {
14260
+ if (fs28.existsSync(gitPath) && fs28.statSync(gitPath).isDirectory()) {
14235
14261
  return { gitDir: null, workDir: projectPath };
14236
14262
  }
14237
- if (fs27.existsSync(gitPath) && fs27.statSync(gitPath).isFile()) {
14263
+ if (fs28.existsSync(gitPath) && fs28.statSync(gitPath).isFile()) {
14238
14264
  return { gitDir: null, workDir: projectPath };
14239
14265
  }
14240
- const entries = fs27.readdirSync(projectPath, { withFileTypes: true });
14266
+ const entries = fs28.readdirSync(projectPath, { withFileTypes: true });
14241
14267
  for (const entry of entries) {
14242
14268
  if (entry.isDirectory() && entry.name.startsWith("EP")) {
14243
- const worktreePath = path29.join(projectPath, entry.name);
14244
- const worktreeGit = path29.join(worktreePath, ".git");
14245
- if (fs27.existsSync(worktreeGit)) {
14269
+ const worktreePath = path30.join(projectPath, entry.name);
14270
+ const worktreeGit = path30.join(worktreePath, ".git");
14271
+ if (fs28.existsSync(worktreeGit)) {
14246
14272
  return { gitDir: null, workDir: worktreePath };
14247
14273
  }
14248
14274
  }
14249
14275
  }
14250
- if (fs27.existsSync(bareDir)) {
14276
+ if (fs28.existsSync(bareDir)) {
14251
14277
  return { gitDir: bareDir, workDir: projectPath };
14252
14278
  }
14253
14279
  return { gitDir: null, workDir: projectPath };
@@ -14292,24 +14318,24 @@ async function configureGitUser(projectPath, userId, workspaceId, machineId, pro
14292
14318
  async function installGitHooks(projectPath) {
14293
14319
  const hooks = ["post-checkout", "pre-commit", "post-commit"];
14294
14320
  let hooksDir;
14295
- const bareHooksDir = path29.join(projectPath, ".bare", "hooks");
14296
- const gitHooksDir = path29.join(projectPath, ".git", "hooks");
14297
- if (fs27.existsSync(bareHooksDir)) {
14321
+ const bareHooksDir = path30.join(projectPath, ".bare", "hooks");
14322
+ const gitHooksDir = path30.join(projectPath, ".git", "hooks");
14323
+ if (fs28.existsSync(bareHooksDir)) {
14298
14324
  hooksDir = bareHooksDir;
14299
- } else if (fs27.existsSync(gitHooksDir) && fs27.statSync(path29.join(projectPath, ".git")).isDirectory()) {
14325
+ } else if (fs28.existsSync(gitHooksDir) && fs28.statSync(path30.join(projectPath, ".git")).isDirectory()) {
14300
14326
  hooksDir = gitHooksDir;
14301
14327
  } else {
14302
- const parentBareHooks = path29.join(projectPath, "..", ".bare", "hooks");
14303
- if (fs27.existsSync(parentBareHooks)) {
14328
+ const parentBareHooks = path30.join(projectPath, "..", ".bare", "hooks");
14329
+ if (fs28.existsSync(parentBareHooks)) {
14304
14330
  hooksDir = parentBareHooks;
14305
14331
  } else {
14306
14332
  console.warn(`[Daemon] Hooks directory not found for: ${projectPath}`);
14307
14333
  return;
14308
14334
  }
14309
14335
  }
14310
- if (!fs27.existsSync(hooksDir)) {
14336
+ if (!fs28.existsSync(hooksDir)) {
14311
14337
  try {
14312
- fs27.mkdirSync(hooksDir, { recursive: true });
14338
+ fs28.mkdirSync(hooksDir, { recursive: true });
14313
14339
  } catch {
14314
14340
  console.warn(`[Daemon] Hooks directory not found and could not create: ${hooksDir}`);
14315
14341
  return;
@@ -14317,20 +14343,20 @@ async function installGitHooks(projectPath) {
14317
14343
  }
14318
14344
  for (const hookName of hooks) {
14319
14345
  try {
14320
- const hookPath = path29.join(hooksDir, hookName);
14321
- const bundledHookPath = path29.join(__dirname, "..", "hooks", hookName);
14322
- if (!fs27.existsSync(bundledHookPath)) {
14346
+ const hookPath = path30.join(hooksDir, hookName);
14347
+ const bundledHookPath = path30.join(__dirname, "..", "hooks", hookName);
14348
+ if (!fs28.existsSync(bundledHookPath)) {
14323
14349
  console.warn(`[Daemon] Bundled hook not found: ${bundledHookPath}`);
14324
14350
  continue;
14325
14351
  }
14326
- const hookContent = fs27.readFileSync(bundledHookPath, "utf-8");
14327
- if (fs27.existsSync(hookPath)) {
14328
- const existingContent = fs27.readFileSync(hookPath, "utf-8");
14352
+ const hookContent = fs28.readFileSync(bundledHookPath, "utf-8");
14353
+ if (fs28.existsSync(hookPath)) {
14354
+ const existingContent = fs28.readFileSync(hookPath, "utf-8");
14329
14355
  if (existingContent === hookContent) {
14330
14356
  continue;
14331
14357
  }
14332
14358
  }
14333
- fs27.writeFileSync(hookPath, hookContent, { mode: 493 });
14359
+ fs28.writeFileSync(hookPath, hookContent, { mode: 493 });
14334
14360
  console.log(`[Daemon] Installed git hook: ${hookName}`);
14335
14361
  } catch (error) {
14336
14362
  console.warn(`[Daemon] Failed to install ${hookName} hook:`, error instanceof Error ? error.message : error);
@@ -14362,21 +14388,6 @@ async function cacheMachineUuid(machineUuid, machineId) {
14362
14388
 
14363
14389
  // src/daemon/daemon-process.ts
14364
14390
  var packageJson = require_package();
14365
- function getBuildPackagesCommand2(installCmd) {
14366
- const runner = installCmd?.command?.[0];
14367
- switch (runner) {
14368
- case "pnpm":
14369
- return 'if command -v pnpm >/dev/null 2>&1; then pnpm run build:packages; elif command -v corepack >/dev/null 2>&1; then corepack pnpm run build:packages; else echo "[setup] ERROR: pnpm is not installed and corepack is unavailable" >&2; exit 127; fi';
14370
- case "yarn":
14371
- return "yarn build:packages";
14372
- case "npm":
14373
- return "npm run build:packages";
14374
- case "bun":
14375
- return "bun run build:packages";
14376
- default:
14377
- return null;
14378
- }
14379
- }
14380
14391
  var Daemon = class _Daemon {
14381
14392
  constructor() {
14382
14393
  this.machineId = "";
@@ -14488,9 +14499,9 @@ var Daemon = class _Daemon {
14488
14499
  this.healthServer = http2.createServer((req, res) => {
14489
14500
  if (req.url === "/health" || req.url === "/") {
14490
14501
  const isConnected = this.connectionManager.liveConnectionCount() > 0;
14491
- const projects = Array.from(this.connectionManager.entries()).map(([path30, conn]) => ({
14492
- path: path30,
14493
- connected: this.connectionManager.hasLiveConnection(path30)
14502
+ const projects = Array.from(this.connectionManager.entries()).map(([path31, conn]) => ({
14503
+ path: path31,
14504
+ connected: this.connectionManager.hasLiveConnection(path31)
14494
14505
  }));
14495
14506
  const status = {
14496
14507
  status: isConnected ? "healthy" : "degraded",
@@ -14563,8 +14574,8 @@ var Daemon = class _Daemon {
14563
14574
  await this.shutdown();
14564
14575
  try {
14565
14576
  const pidPath = getPidFilePath();
14566
- if (fs28.existsSync(pidPath)) {
14567
- fs28.unlinkSync(pidPath);
14577
+ if (fs29.existsSync(pidPath)) {
14578
+ fs29.unlinkSync(pidPath);
14568
14579
  console.log("[Daemon] PID file cleaned up (watchdog)");
14569
14580
  }
14570
14581
  } catch (error) {
@@ -14830,7 +14841,7 @@ var Daemon = class _Daemon {
14830
14841
  const resolvedProjectPath = getProjectPath(cmd.workspaceSlug, cmd.projectSlug);
14831
14842
  if (resolvedProjectPath !== projectPath) {
14832
14843
  try {
14833
- await fs28.promises.access(resolvedProjectPath);
14844
+ await fs29.promises.access(resolvedProjectPath);
14834
14845
  agentWorkingDir = resolvedProjectPath;
14835
14846
  console.log(`[Daemon] EP1230: Agent for ${cmd.moduleUid || "project"} in resolved project path: ${agentWorkingDir}`);
14836
14847
  } catch {
@@ -15162,8 +15173,8 @@ var Daemon = class _Daemon {
15162
15173
  let daemonPid;
15163
15174
  try {
15164
15175
  const pidPath = getPidFilePath();
15165
- if (fs28.existsSync(pidPath)) {
15166
- const pidStr = fs28.readFileSync(pidPath, "utf-8").trim();
15176
+ if (fs29.existsSync(pidPath)) {
15177
+ const pidStr = fs29.readFileSync(pidPath, "utf-8").trim();
15167
15178
  daemonPid = parseInt(pidStr, 10);
15168
15179
  }
15169
15180
  } catch (pidError) {
@@ -15633,23 +15644,25 @@ var Daemon = class _Daemon {
15633
15644
  } else {
15634
15645
  console.log(`[Daemon] EP1002: No package manager detected, skipping dependency installation`);
15635
15646
  }
15636
- if (process.env.EPISODA_MODE === "cloud" && installSucceeded) {
15637
- const buildCmd = getBuildPackagesCommand2(installCmd);
15638
- if (buildCmd) {
15639
- console.log(`[Daemon] EP1262: Bootstrapping packages for cloud dev (${buildCmd})`);
15640
- try {
15641
- const { execSync: execSync10 } = await import("child_process");
15642
- execSync10(buildCmd, {
15643
- cwd: worktreePath,
15644
- stdio: "inherit",
15645
- timeout: 10 * 60 * 1e3,
15646
- env: { ...process.env, CI: "true" }
15647
- });
15648
- console.log("[Daemon] EP1262: Package bootstrap completed");
15649
- } catch (buildError) {
15650
- const errorMsg = buildError instanceof Error ? buildError.message : String(buildError);
15651
- console.warn(`[Daemon] EP1262: Package bootstrap failed (non-fatal): ${errorMsg}`);
15652
- }
15647
+ const hasBuildPackages = hasPackageScript(worktreePath, "build:packages");
15648
+ const buildCmd = getBuildPackagesCommand(installCmd?.command?.[0], hasBuildPackages);
15649
+ if (buildCmd && shouldRunBuildPackagesBootstrap(installSucceeded, buildCmd)) {
15650
+ const bootstrapCmd = buildCmd;
15651
+ console.log(`[Daemon] EP1386: Bootstrapping packages after dependency install (${bootstrapCmd})`);
15652
+ try {
15653
+ const { execSync: execSync10 } = await import("child_process");
15654
+ execSync10(bootstrapCmd, {
15655
+ cwd: worktreePath,
15656
+ stdio: "inherit",
15657
+ timeout: 10 * 60 * 1e3,
15658
+ env: { ...process.env, CI: "true" }
15659
+ });
15660
+ console.log("[Daemon] EP1386: Package bootstrap completed");
15661
+ } catch (buildError) {
15662
+ const errorMsg = buildError instanceof Error ? buildError.message : String(buildError);
15663
+ await worktreeManager.updateWorktreeStatus(moduleUid, "error", errorMsg);
15664
+ await this.updateModuleWorktreeStatus(moduleUid, "error", worktreePath, errorMsg);
15665
+ throw new Error(`Package bootstrap failed: ${errorMsg}`);
15653
15666
  }
15654
15667
  }
15655
15668
  if (setupScript) {
@@ -15731,8 +15744,8 @@ var Daemon = class _Daemon {
15731
15744
  await this.shutdown();
15732
15745
  try {
15733
15746
  const pidPath = getPidFilePath();
15734
- if (fs28.existsSync(pidPath)) {
15735
- fs28.unlinkSync(pidPath);
15747
+ if (fs29.existsSync(pidPath)) {
15748
+ fs29.unlinkSync(pidPath);
15736
15749
  console.log("[Daemon] PID file cleaned up");
15737
15750
  }
15738
15751
  } catch (error) {