episoda 0.2.83 → 0.2.85

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 fs19 = await Promise.resolve().then(() => __importStar(require("fs"))).then((m) => m.promises);
1566
+ const fs20 = 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 fs19.access(rebaseMergePath);
1570
+ await fs20.access(rebaseMergePath);
1571
1571
  inRebase = true;
1572
1572
  } catch {
1573
1573
  try {
1574
- await fs19.access(rebaseApplyPath);
1574
+ await fs20.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 fs19 = await Promise.resolve().then(() => __importStar(require("fs"))).then((m) => m.promises);
1628
+ const fs20 = await Promise.resolve().then(() => __importStar(require("fs"))).then((m) => m.promises);
1629
1629
  try {
1630
- await fs19.access(command.path);
1630
+ await fs20.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 fs19 = await Promise.resolve().then(() => __importStar(require("fs"))).then((m) => m.promises);
1684
+ const fs20 = await Promise.resolve().then(() => __importStar(require("fs"))).then((m) => m.promises);
1685
1685
  try {
1686
- await fs19.access(command.path);
1686
+ await fs20.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 fs19.rm(command.path, { recursive: true, force: true });
1721
+ await fs20.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 fs19 = await Promise.resolve().then(() => __importStar(require("fs"))).then((m) => m.promises);
1856
- const path20 = await Promise.resolve().then(() => __importStar(require("path")));
1855
+ const fs20 = await Promise.resolve().then(() => __importStar(require("fs"))).then((m) => m.promises);
1856
+ const path21 = await Promise.resolve().then(() => __importStar(require("path")));
1857
1857
  try {
1858
- await fs19.access(command.path);
1858
+ await fs20.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 = path20.dirname(command.path);
1867
+ const parentDir = path21.dirname(command.path);
1868
1868
  try {
1869
- await fs19.mkdir(parentDir, { recursive: true });
1869
+ await fs20.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 fs19 = await Promise.resolve().then(() => __importStar(require("fs"))).then((m) => m.promises);
1918
- const path20 = await Promise.resolve().then(() => __importStar(require("path")));
1917
+ const fs20 = await Promise.resolve().then(() => __importStar(require("fs"))).then((m) => m.promises);
1918
+ const path21 = 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 = path20.join(currentPath, ".bare");
1924
- const episodaDir = path20.join(currentPath, ".episoda");
1923
+ const bareDir = path21.join(currentPath, ".bare");
1924
+ const episodaDir = path21.join(currentPath, ".episoda");
1925
1925
  try {
1926
- await fs19.access(bareDir);
1927
- await fs19.access(episodaDir);
1926
+ await fs20.access(bareDir);
1927
+ await fs20.access(episodaDir);
1928
1928
  projectPath = currentPath;
1929
1929
  bareRepoPath = bareDir;
1930
1930
  break;
1931
1931
  } catch {
1932
- const parentPath = path20.dirname(currentPath);
1932
+ const parentPath = path21.dirname(currentPath);
1933
1933
  if (parentPath === currentPath) {
1934
1934
  break;
1935
1935
  }
@@ -2564,31 +2564,31 @@ var require_auth = __commonJS({
2564
2564
  exports2.loadConfig = loadConfig7;
2565
2565
  exports2.saveConfig = saveConfig2;
2566
2566
  exports2.validateToken = validateToken;
2567
- var fs19 = __importStar(require("fs"));
2568
- var path20 = __importStar(require("path"));
2567
+ var fs20 = __importStar(require("fs"));
2568
+ var path21 = __importStar(require("path"));
2569
2569
  var os9 = __importStar(require("os"));
2570
2570
  var child_process_1 = require("child_process");
2571
2571
  var DEFAULT_CONFIG_FILE = "config.json";
2572
2572
  function getConfigDir8() {
2573
- return process.env.EPISODA_CONFIG_DIR || path20.join(os9.homedir(), ".episoda");
2573
+ return process.env.EPISODA_CONFIG_DIR || path21.join(os9.homedir(), ".episoda");
2574
2574
  }
2575
2575
  function getConfigPath(configPath) {
2576
2576
  if (configPath) {
2577
2577
  return configPath;
2578
2578
  }
2579
- return path20.join(getConfigDir8(), DEFAULT_CONFIG_FILE);
2579
+ return path21.join(getConfigDir8(), DEFAULT_CONFIG_FILE);
2580
2580
  }
2581
2581
  function ensureConfigDir(configPath) {
2582
- const dir = path20.dirname(configPath);
2583
- const isNew = !fs19.existsSync(dir);
2582
+ const dir = path21.dirname(configPath);
2583
+ const isNew = !fs20.existsSync(dir);
2584
2584
  if (isNew) {
2585
- fs19.mkdirSync(dir, { recursive: true, mode: 448 });
2585
+ fs20.mkdirSync(dir, { recursive: true, mode: 448 });
2586
2586
  }
2587
2587
  if (process.platform === "darwin") {
2588
- const nosyncPath = path20.join(dir, ".nosync");
2589
- if (isNew || !fs19.existsSync(nosyncPath)) {
2588
+ const nosyncPath = path21.join(dir, ".nosync");
2589
+ if (isNew || !fs20.existsSync(nosyncPath)) {
2590
2590
  try {
2591
- fs19.writeFileSync(nosyncPath, "", { mode: 384 });
2591
+ fs20.writeFileSync(nosyncPath, "", { mode: 384 });
2592
2592
  (0, child_process_1.execSync)(`xattr -w com.apple.fileprovider.ignore 1 "${dir}"`, {
2593
2593
  stdio: "ignore",
2594
2594
  timeout: 5e3
@@ -2600,9 +2600,9 @@ var require_auth = __commonJS({
2600
2600
  }
2601
2601
  async function loadConfig7(configPath) {
2602
2602
  const fullPath = getConfigPath(configPath);
2603
- if (fs19.existsSync(fullPath)) {
2603
+ if (fs20.existsSync(fullPath)) {
2604
2604
  try {
2605
- const content = fs19.readFileSync(fullPath, "utf8");
2605
+ const content = fs20.readFileSync(fullPath, "utf8");
2606
2606
  const config = JSON.parse(content);
2607
2607
  return config;
2608
2608
  } catch (error) {
@@ -2631,7 +2631,7 @@ var require_auth = __commonJS({
2631
2631
  ensureConfigDir(fullPath);
2632
2632
  try {
2633
2633
  const content = JSON.stringify(config, null, 2);
2634
- fs19.writeFileSync(fullPath, content, { mode: 384 });
2634
+ fs20.writeFileSync(fullPath, content, { mode: 384 });
2635
2635
  } catch (error) {
2636
2636
  throw new Error(`Failed to save config: ${error instanceof Error ? error.message : String(error)}`);
2637
2637
  }
@@ -2748,7 +2748,7 @@ var require_package = __commonJS({
2748
2748
  "package.json"(exports2, module2) {
2749
2749
  module2.exports = {
2750
2750
  name: "episoda",
2751
- version: "0.2.83",
2751
+ version: "0.2.85",
2752
2752
  description: "CLI tool for Episoda local development workflow orchestration",
2753
2753
  main: "dist/index.js",
2754
2754
  types: "dist/index.d.ts",
@@ -2782,7 +2782,8 @@ var require_package = __commonJS({
2782
2782
  zod: "^4.0.10"
2783
2783
  },
2784
2784
  optionalDependencies: {
2785
- "@anthropic-ai/claude-code": "^2.0.0"
2785
+ "@anthropic-ai/claude-code": "^2.0.0",
2786
+ "@openai/codex": "^0.86.0"
2786
2787
  },
2787
2788
  devDependencies: {
2788
2789
  "@episoda/core": "*",
@@ -4947,10 +4948,112 @@ async function ensureClaudeBinary() {
4947
4948
  );
4948
4949
  }
4949
4950
 
4950
- // src/agent/agent-manager.ts
4951
+ // src/agent/codex-binary.ts
4951
4952
  var import_child_process8 = require("child_process");
4952
4953
  var path9 = __toESM(require("path"));
4953
4954
  var fs8 = __toESM(require("fs"));
4955
+ var cachedBinaryPath2 = null;
4956
+ function isValidCodexBinary(binaryPath) {
4957
+ try {
4958
+ fs8.accessSync(binaryPath, fs8.constants.X_OK);
4959
+ const version = (0, import_child_process8.execSync)(`"${binaryPath}" --version`, {
4960
+ encoding: "utf-8",
4961
+ timeout: 5e3,
4962
+ stdio: ["pipe", "pipe", "pipe"]
4963
+ }).trim();
4964
+ if (version && /codex.*\d+\.\d+/i.test(version)) {
4965
+ console.log(`[CodexBinary] Found Codex CLI at ${binaryPath}: ${version}`);
4966
+ return true;
4967
+ }
4968
+ return false;
4969
+ } catch {
4970
+ return false;
4971
+ }
4972
+ }
4973
+ async function ensureCodexBinary() {
4974
+ if (cachedBinaryPath2) {
4975
+ return cachedBinaryPath2;
4976
+ }
4977
+ try {
4978
+ const pathResult = (0, import_child_process8.execSync)("which codex", {
4979
+ encoding: "utf-8",
4980
+ timeout: 5e3,
4981
+ stdio: ["pipe", "pipe", "pipe"]
4982
+ }).trim();
4983
+ if (pathResult && isValidCodexBinary(pathResult)) {
4984
+ cachedBinaryPath2 = pathResult;
4985
+ return cachedBinaryPath2;
4986
+ }
4987
+ } catch {
4988
+ }
4989
+ const bundledPaths = [
4990
+ // In production: node_modules/.bin/codex
4991
+ path9.join(__dirname, "..", "..", "node_modules", ".bin", "codex"),
4992
+ // In monorepo development: packages/episoda/node_modules/.bin/codex
4993
+ path9.join(__dirname, "..", "..", "..", "..", "node_modules", ".bin", "codex"),
4994
+ // Root monorepo node_modules
4995
+ path9.join(__dirname, "..", "..", "..", "..", "..", "node_modules", ".bin", "codex")
4996
+ ];
4997
+ for (const bundledPath of bundledPaths) {
4998
+ if (fs8.existsSync(bundledPath) && isValidCodexBinary(bundledPath)) {
4999
+ cachedBinaryPath2 = bundledPath;
5000
+ return cachedBinaryPath2;
5001
+ }
5002
+ }
5003
+ try {
5004
+ const npxResult = (0, import_child_process8.execSync)("npx --yes @openai/codex --version", {
5005
+ encoding: "utf-8",
5006
+ timeout: 3e4,
5007
+ // npx might need to download
5008
+ stdio: ["pipe", "pipe", "pipe"]
5009
+ }).trim();
5010
+ if (npxResult && /codex.*\d+\.\d+/i.test(npxResult)) {
5011
+ cachedBinaryPath2 = "npx:@openai/codex";
5012
+ console.log(`[CodexBinary] Using npx to run Codex CLI: ${npxResult}`);
5013
+ return cachedBinaryPath2;
5014
+ }
5015
+ } catch {
5016
+ }
5017
+ throw new Error(
5018
+ "Codex CLI not found. Please install it globally with: npm install -g @openai/codex"
5019
+ );
5020
+ }
5021
+
5022
+ // src/agent/codex-config.ts
5023
+ function generateCodexAuthJson(credentials) {
5024
+ const authData = {
5025
+ OPENAI_API_KEY: null,
5026
+ tokens: {
5027
+ id_token: credentials.idToken || credentials.accessToken,
5028
+ // Fallback to access_token if no id_token
5029
+ access_token: credentials.accessToken,
5030
+ refresh_token: credentials.refreshToken || null,
5031
+ account_id: credentials.accountId || null
5032
+ },
5033
+ last_refresh: (/* @__PURE__ */ new Date()).toISOString()
5034
+ };
5035
+ return JSON.stringify(authData, null, 2);
5036
+ }
5037
+ function generateCodexConfigToml(projectPath) {
5038
+ const escapedPath = projectPath.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
5039
+ return `[projects."${escapedPath}"]
5040
+ trust_level = "trusted"
5041
+ `;
5042
+ }
5043
+ function generateCodexConfig(credentials, projectPath) {
5044
+ const files = {
5045
+ "auth.json": generateCodexAuthJson(credentials)
5046
+ };
5047
+ if (projectPath) {
5048
+ files["config.toml"] = generateCodexConfigToml(projectPath);
5049
+ }
5050
+ return files;
5051
+ }
5052
+
5053
+ // src/agent/agent-manager.ts
5054
+ var import_child_process9 = require("child_process");
5055
+ var path10 = __toESM(require("path"));
5056
+ var fs9 = __toESM(require("fs"));
4954
5057
  var os3 = __toESM(require("os"));
4955
5058
 
4956
5059
  // src/agent/claude-config.ts
@@ -5255,11 +5358,30 @@ var AgentManager = class {
5255
5358
  this.sessions = /* @__PURE__ */ new Map();
5256
5359
  this.processes = /* @__PURE__ */ new Map();
5257
5360
  this.initialized = false;
5258
- this.pidDir = path9.join(os3.homedir(), ".episoda", "agent-pids");
5361
+ // EP1133: Lock for config file writes to prevent race conditions
5362
+ this.configWriteLock = Promise.resolve();
5363
+ this.pidDir = path10.join(os3.homedir(), ".episoda", "agent-pids");
5364
+ }
5365
+ /**
5366
+ * EP1133: Acquire lock for config file writes
5367
+ * Ensures sequential writes to prevent file corruption
5368
+ */
5369
+ async withConfigLock(fn) {
5370
+ const previousLock = this.configWriteLock;
5371
+ let releaseLock;
5372
+ this.configWriteLock = new Promise((resolve3) => {
5373
+ releaseLock = resolve3;
5374
+ });
5375
+ try {
5376
+ await previousLock;
5377
+ return await fn();
5378
+ } finally {
5379
+ releaseLock();
5380
+ }
5259
5381
  }
5260
5382
  /**
5261
5383
  * Initialize the agent manager
5262
- * - Ensure Claude Code is available
5384
+ * - Ensure agent CLIs are available (Claude Code, Codex)
5263
5385
  * - Clean up any orphaned processes from previous daemon runs
5264
5386
  */
5265
5387
  async initialize() {
@@ -5267,8 +5389,8 @@ var AgentManager = class {
5267
5389
  return;
5268
5390
  }
5269
5391
  console.log("[AgentManager] Initializing...");
5270
- if (!fs8.existsSync(this.pidDir)) {
5271
- fs8.mkdirSync(this.pidDir, { recursive: true });
5392
+ if (!fs9.existsSync(this.pidDir)) {
5393
+ fs9.mkdirSync(this.pidDir, { recursive: true });
5272
5394
  }
5273
5395
  await this.cleanupOrphanedProcesses();
5274
5396
  try {
@@ -5277,6 +5399,12 @@ var AgentManager = class {
5277
5399
  } catch (error) {
5278
5400
  console.warn("[AgentManager] Claude Code not available:", error instanceof Error ? error.message : error);
5279
5401
  }
5402
+ try {
5403
+ await ensureCodexBinary();
5404
+ console.log("[AgentManager] Codex CLI binary verified");
5405
+ } catch (error) {
5406
+ console.warn("[AgentManager] Codex CLI not available:", error instanceof Error ? error.message : error);
5407
+ }
5280
5408
  this.initialized = true;
5281
5409
  console.log("[AgentManager] Initialized");
5282
5410
  }
@@ -5285,28 +5413,38 @@ var AgentManager = class {
5285
5413
  *
5286
5414
  * Creates the session record but doesn't spawn the process yet.
5287
5415
  * The process is spawned on the first message.
5416
+ *
5417
+ * EP1133: Added provider parameter for multi-provider support
5288
5418
  */
5289
5419
  async startSession(options) {
5290
- const { sessionId, moduleId, moduleUid, projectPath, message, credentials, systemPrompt, onChunk, onComplete, onError } = options;
5420
+ const { sessionId, moduleId, moduleUid, projectPath, provider = "claude", message, credentials, systemPrompt, onChunk, onComplete, onError } = options;
5291
5421
  if (this.sessions.has(sessionId)) {
5292
5422
  return { success: false, error: "Session already exists" };
5293
5423
  }
5294
5424
  const oauthToken = credentials?.oauthToken;
5295
5425
  const apiKey = credentials?.apiKey;
5296
5426
  if (!oauthToken && !apiKey) {
5427
+ const providerName = provider === "claude" ? "Claude" : "Codex";
5297
5428
  return {
5298
5429
  success: false,
5299
- error: "Missing credentials. Please connect your Claude account in Settings or provide an API key."
5430
+ error: `Missing credentials. Please connect your ${providerName} account in Settings.`
5300
5431
  };
5301
5432
  }
5302
5433
  const authMethod = oauthToken ? "OAuth" : "API key";
5303
- console.log(`[AgentManager] Using ${authMethod} authentication`);
5434
+ console.log(`[AgentManager] Using ${provider} provider with ${authMethod} authentication`);
5304
5435
  try {
5305
- await ensureClaudeBinary();
5436
+ if (provider === "claude") {
5437
+ await ensureClaudeBinary();
5438
+ } else if (provider === "codex") {
5439
+ await ensureCodexBinary();
5440
+ } else {
5441
+ return { success: false, error: `Unknown provider: ${provider}` };
5442
+ }
5306
5443
  } catch (error) {
5444
+ const cliName = provider === "claude" ? "Claude Code" : "Codex CLI";
5307
5445
  return {
5308
5446
  success: false,
5309
- error: error instanceof Error ? error.message : "Claude Code not available"
5447
+ error: error instanceof Error ? error.message : `${cliName} not available`
5310
5448
  };
5311
5449
  }
5312
5450
  const session = {
@@ -5314,6 +5452,8 @@ var AgentManager = class {
5314
5452
  moduleId,
5315
5453
  moduleUid,
5316
5454
  projectPath,
5455
+ provider,
5456
+ // EP1133: Store provider in session
5317
5457
  credentials,
5318
5458
  systemPrompt,
5319
5459
  status: "starting",
@@ -5321,7 +5461,7 @@ var AgentManager = class {
5321
5461
  lastActivityAt: /* @__PURE__ */ new Date()
5322
5462
  };
5323
5463
  this.sessions.set(sessionId, session);
5324
- console.log(`[AgentManager] Started session ${sessionId} for ${moduleUid}`);
5464
+ console.log(`[AgentManager] Started ${provider} session ${sessionId} for ${moduleUid}`);
5325
5465
  return this.sendMessage({
5326
5466
  sessionId,
5327
5467
  message,
@@ -5334,38 +5474,70 @@ var AgentManager = class {
5334
5474
  /**
5335
5475
  * Send a message to an agent session
5336
5476
  *
5337
- * Spawns a new Claude Code process for each message.
5338
- * Uses --print for non-interactive mode and --output-format stream-json for structured output.
5339
- * Subsequent messages use --resume with the claudeSessionId for conversation continuity.
5477
+ * Spawns a new agent CLI process for each message.
5478
+ * EP1133: Supports both Claude Code and Codex CLI with provider-specific handling.
5340
5479
  */
5341
5480
  async sendMessage(options) {
5342
- const { sessionId, message, isFirstMessage, claudeSessionId, onChunk, onComplete, onError } = options;
5481
+ const { sessionId, message, isFirstMessage, agentSessionId, claudeSessionId, onChunk, onComplete, onError } = options;
5343
5482
  const session = this.sessions.get(sessionId);
5344
5483
  if (!session) {
5345
5484
  return { success: false, error: "Session not found" };
5346
5485
  }
5347
5486
  session.lastActivityAt = /* @__PURE__ */ new Date();
5348
5487
  session.status = "running";
5488
+ const resumeSessionId = agentSessionId || claudeSessionId;
5349
5489
  try {
5350
- const binaryPath = await ensureClaudeBinary();
5351
- const args = [
5352
- "--print",
5353
- // Non-interactive mode
5354
- "--output-format",
5355
- "stream-json",
5356
- // Structured streaming output
5357
- "--verbose"
5358
- // Required for stream-json with --print
5359
- ];
5360
- if (isFirstMessage && session.systemPrompt) {
5361
- args.push("--system-prompt", session.systemPrompt);
5362
- }
5363
- if (claudeSessionId) {
5364
- args.push("--resume", claudeSessionId);
5365
- session.claudeSessionId = claudeSessionId;
5366
- }
5367
- args.push("--", message);
5368
- console.log(`[AgentManager] Spawning Claude Code for session ${sessionId}`);
5490
+ const provider = session.provider || "claude";
5491
+ let binaryPath;
5492
+ let args;
5493
+ if (provider === "codex") {
5494
+ binaryPath = await ensureCodexBinary();
5495
+ args = [
5496
+ "exec",
5497
+ "--json",
5498
+ // JSONL streaming output
5499
+ "--skip-git-repo-check",
5500
+ // Allow running outside git repos
5501
+ "--full-auto",
5502
+ // Automatic execution with sandbox
5503
+ "--cd",
5504
+ session.projectPath
5505
+ // Working directory
5506
+ ];
5507
+ if (resumeSessionId) {
5508
+ args.push("resume", resumeSessionId);
5509
+ }
5510
+ let fullMessage = message;
5511
+ if (isFirstMessage && session.systemPrompt) {
5512
+ fullMessage = `${session.systemPrompt}
5513
+
5514
+ ---
5515
+
5516
+ ${message}`;
5517
+ }
5518
+ args.push(fullMessage);
5519
+ } else {
5520
+ binaryPath = await ensureClaudeBinary();
5521
+ args = [
5522
+ "--print",
5523
+ // Non-interactive mode
5524
+ "--output-format",
5525
+ "stream-json",
5526
+ // Structured streaming output
5527
+ "--verbose"
5528
+ // Required for stream-json with --print
5529
+ ];
5530
+ if (isFirstMessage && session.systemPrompt) {
5531
+ args.push("--system-prompt", session.systemPrompt);
5532
+ }
5533
+ if (resumeSessionId) {
5534
+ args.push("--resume", resumeSessionId);
5535
+ session.agentSessionId = resumeSessionId;
5536
+ session.claudeSessionId = resumeSessionId;
5537
+ }
5538
+ args.push("--", message);
5539
+ }
5540
+ console.log(`[AgentManager] Spawning ${provider} CLI for session ${sessionId}`);
5369
5541
  console.log(`[AgentManager] Command: ${binaryPath} ${args.join(" ").substring(0, 100)}...`);
5370
5542
  let spawnCmd;
5371
5543
  let spawnArgs;
@@ -5378,68 +5550,110 @@ var AgentManager = class {
5378
5550
  }
5379
5551
  const useOAuth = !!session.credentials.oauthToken;
5380
5552
  const useApiKey = !useOAuth && !!session.credentials.apiKey;
5381
- const claudeDir = path9.join(os3.homedir(), ".claude");
5382
- const credentialsPath = path9.join(claudeDir, ".credentials.json");
5383
- const statsigDir = path9.join(claudeDir, "statsig");
5384
- if (!fs8.existsSync(claudeDir)) {
5385
- fs8.mkdirSync(claudeDir, { recursive: true });
5386
- }
5387
- if (!fs8.existsSync(statsigDir)) {
5388
- fs8.mkdirSync(statsigDir, { recursive: true });
5389
- }
5390
- if (useOAuth) {
5391
- const oauthCredentials = {
5392
- accessToken: session.credentials.oauthToken
5393
- };
5394
- if (session.credentials.refreshToken) {
5395
- oauthCredentials.refreshToken = session.credentials.refreshToken;
5396
- }
5397
- if (session.credentials.expiresAt) {
5398
- oauthCredentials.expiresAt = session.credentials.expiresAt;
5399
- }
5400
- if (session.credentials.scopes) {
5401
- oauthCredentials.scopes = session.credentials.scopes;
5402
- }
5403
- const credentialsContent = JSON.stringify({
5404
- claudeAiOauth: oauthCredentials
5405
- }, null, 2);
5406
- fs8.writeFileSync(credentialsPath, credentialsContent, { mode: 384 });
5407
- console.log(
5408
- "[AgentManager] EP1126: Wrote OAuth credentials to ~/.claude/.credentials.json (with %s fields)",
5409
- Object.keys(oauthCredentials).join(", ")
5410
- );
5411
- try {
5412
- const claudeConfig = generateClaudeConfig();
5413
- const statsigFiles = Object.keys(claudeConfig.statsig);
5414
- const hasEvaluations = statsigFiles.some((f) => f.includes("cached.evaluations"));
5415
- const hasStableId = statsigFiles.some((f) => f.includes("stable_id"));
5416
- if (!hasEvaluations || !hasStableId) {
5417
- throw new Error(`Invalid statsig config: missing required files (evaluations=${hasEvaluations}, stableId=${hasStableId})`);
5418
- }
5419
- const settingsPath = path9.join(claudeDir, "settings.json");
5420
- fs8.writeFileSync(settingsPath, claudeConfig["settings.json"], { mode: 384 });
5421
- console.log("[AgentManager] EP1126: Wrote settings.json");
5422
- for (const [filename, content] of Object.entries(claudeConfig.statsig)) {
5423
- const filePath = path9.join(statsigDir, filename);
5424
- fs8.writeFileSync(filePath, content, { mode: 420 });
5425
- }
5426
- console.log("[AgentManager] EP1126: Wrote statsig cache files (%d files) for eligibility verification", statsigFiles.length);
5427
- } catch (configError) {
5428
- console.warn("[AgentManager] EP1126: Failed to write config files:", configError instanceof Error ? configError.message : configError);
5429
- }
5430
- } else if (useApiKey) {
5431
- console.log("[AgentManager] EP1126: Using API key authentication (ANTHROPIC_API_KEY)");
5432
- }
5433
- const childProcess = (0, import_child_process8.spawn)(spawnCmd, spawnArgs, {
5553
+ if (provider === "codex") {
5554
+ await this.withConfigLock(async () => {
5555
+ const codexDir = path10.join(os3.homedir(), ".codex");
5556
+ if (!fs9.existsSync(codexDir)) {
5557
+ fs9.mkdirSync(codexDir, { recursive: true });
5558
+ }
5559
+ if (useOAuth) {
5560
+ const codexConfig = generateCodexConfig({
5561
+ accessToken: session.credentials.oauthToken,
5562
+ refreshToken: session.credentials.refreshToken,
5563
+ idToken: session.credentials.idToken,
5564
+ accountId: session.credentials.accountId,
5565
+ expiresAt: session.credentials.expiresAt
5566
+ }, session.projectPath);
5567
+ const authJsonPath = path10.join(codexDir, "auth.json");
5568
+ fs9.writeFileSync(authJsonPath, codexConfig["auth.json"], { mode: 384 });
5569
+ console.log("[AgentManager] EP1133: Wrote Codex auth.json to ~/.codex/auth.json");
5570
+ if (codexConfig["config.toml"]) {
5571
+ const configTomlPath = path10.join(codexDir, "config.toml");
5572
+ let existingConfig = "";
5573
+ try {
5574
+ existingConfig = fs9.readFileSync(configTomlPath, "utf-8");
5575
+ } catch {
5576
+ }
5577
+ const escapedPathForRegex = session.projectPath.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
5578
+ const projectKeyPattern = new RegExp(`\\[projects\\."${escapedPathForRegex}"\\]`);
5579
+ const projectAlreadyTrusted = projectKeyPattern.test(existingConfig);
5580
+ if (!projectAlreadyTrusted) {
5581
+ fs9.writeFileSync(configTomlPath, existingConfig + "\n" + codexConfig["config.toml"], { mode: 420 });
5582
+ console.log("[AgentManager] EP1133: Updated Codex config.toml with project trust");
5583
+ }
5584
+ }
5585
+ } else if (useApiKey) {
5586
+ console.log("[AgentManager] EP1133: Using Codex with API key (OPENAI_API_KEY)");
5587
+ }
5588
+ });
5589
+ } else {
5590
+ await this.withConfigLock(async () => {
5591
+ const claudeDir = path10.join(os3.homedir(), ".claude");
5592
+ const credentialsPath = path10.join(claudeDir, ".credentials.json");
5593
+ const statsigDir = path10.join(claudeDir, "statsig");
5594
+ if (!fs9.existsSync(claudeDir)) {
5595
+ fs9.mkdirSync(claudeDir, { recursive: true });
5596
+ }
5597
+ if (!fs9.existsSync(statsigDir)) {
5598
+ fs9.mkdirSync(statsigDir, { recursive: true });
5599
+ }
5600
+ if (useOAuth) {
5601
+ const oauthCredentials = {
5602
+ accessToken: session.credentials.oauthToken
5603
+ };
5604
+ if (session.credentials.refreshToken) {
5605
+ oauthCredentials.refreshToken = session.credentials.refreshToken;
5606
+ }
5607
+ if (session.credentials.expiresAt) {
5608
+ oauthCredentials.expiresAt = session.credentials.expiresAt;
5609
+ }
5610
+ if (session.credentials.scopes) {
5611
+ oauthCredentials.scopes = session.credentials.scopes;
5612
+ }
5613
+ const credentialsContent = JSON.stringify({
5614
+ claudeAiOauth: oauthCredentials
5615
+ }, null, 2);
5616
+ fs9.writeFileSync(credentialsPath, credentialsContent, { mode: 384 });
5617
+ console.log("[AgentManager] Wrote OAuth credentials to ~/.claude/.credentials.json");
5618
+ try {
5619
+ const claudeConfig = generateClaudeConfig();
5620
+ const statsigFiles = Object.keys(claudeConfig.statsig);
5621
+ const hasEvaluations = statsigFiles.some((f) => f.includes("cached.evaluations"));
5622
+ const hasStableId = statsigFiles.some((f) => f.includes("stable_id"));
5623
+ if (!hasEvaluations || !hasStableId) {
5624
+ throw new Error(`Invalid statsig config: missing required files`);
5625
+ }
5626
+ const settingsPath = path10.join(claudeDir, "settings.json");
5627
+ fs9.writeFileSync(settingsPath, claudeConfig["settings.json"], { mode: 384 });
5628
+ for (const [filename, content] of Object.entries(claudeConfig.statsig)) {
5629
+ const filePath = path10.join(statsigDir, filename);
5630
+ fs9.writeFileSync(filePath, content, { mode: 420 });
5631
+ }
5632
+ console.log("[AgentManager] Wrote Claude config files");
5633
+ } catch (configError) {
5634
+ console.warn("[AgentManager] Failed to write Claude config files:", configError instanceof Error ? configError.message : configError);
5635
+ }
5636
+ } else if (useApiKey) {
5637
+ console.log("[AgentManager] Using Claude with API key (ANTHROPIC_API_KEY)");
5638
+ }
5639
+ });
5640
+ }
5641
+ const envVars = {
5642
+ ...process.env,
5643
+ // Disable color output for cleaner JSON parsing
5644
+ NO_COLOR: "1",
5645
+ FORCE_COLOR: "0"
5646
+ };
5647
+ if (useApiKey && session.credentials.apiKey) {
5648
+ if (provider === "codex") {
5649
+ envVars.OPENAI_API_KEY = session.credentials.apiKey;
5650
+ } else {
5651
+ envVars.ANTHROPIC_API_KEY = session.credentials.apiKey;
5652
+ }
5653
+ }
5654
+ const childProcess = (0, import_child_process9.spawn)(spawnCmd, spawnArgs, {
5434
5655
  cwd: session.projectPath,
5435
- env: {
5436
- ...process.env,
5437
- // Disable color output for cleaner JSON parsing
5438
- NO_COLOR: "1",
5439
- FORCE_COLOR: "0",
5440
- // Add API key if using API key auth mode
5441
- ...useApiKey && session.credentials.apiKey ? { ANTHROPIC_API_KEY: session.credentials.apiKey } : {}
5442
- },
5656
+ env: envVars,
5443
5657
  stdio: ["pipe", "pipe", "pipe"]
5444
5658
  });
5445
5659
  this.processes.set(sessionId, childProcess);
@@ -5464,42 +5678,76 @@ var AgentManager = class {
5464
5678
  if (!line.trim()) continue;
5465
5679
  try {
5466
5680
  const parsed = JSON.parse(line);
5467
- switch (parsed.type) {
5468
- case "assistant":
5469
- if (parsed.message?.content) {
5470
- for (const block of parsed.message.content) {
5471
- if (block.type === "text" && block.text) {
5472
- onChunk(block.text);
5681
+ if (provider === "codex") {
5682
+ switch (parsed.type) {
5683
+ case "thread.started":
5684
+ if (parsed.thread_id) {
5685
+ extractedSessionId = parsed.thread_id;
5686
+ session.agentSessionId = extractedSessionId;
5687
+ }
5688
+ break;
5689
+ case "item.completed":
5690
+ if (parsed.item?.type === "agent_message" && parsed.item.text) {
5691
+ onChunk(parsed.item.text);
5692
+ } else if (parsed.item?.type === "reasoning" && parsed.item.summary) {
5693
+ onChunk(`[Thinking: ${parsed.item.summary}]
5694
+ `);
5695
+ }
5696
+ break;
5697
+ case "item.failed":
5698
+ case "turn.failed":
5699
+ onError(parsed.item?.error || parsed.error?.message || "Codex operation failed");
5700
+ break;
5701
+ case "error":
5702
+ onError(parsed.message || parsed.error?.message || "Unknown error from Codex");
5703
+ break;
5704
+ // Ignore: turn.started, turn.completed (usage stats), item.started
5705
+ default:
5706
+ if (!["turn.started", "turn.completed", "item.started"].includes(parsed.type)) {
5707
+ console.log(`[AgentManager] Codex event: ${parsed.type}`);
5708
+ }
5709
+ }
5710
+ } else {
5711
+ switch (parsed.type) {
5712
+ case "assistant":
5713
+ if (parsed.message?.content) {
5714
+ for (const block of parsed.message.content) {
5715
+ if (block.type === "text" && block.text) {
5716
+ onChunk(block.text);
5717
+ }
5473
5718
  }
5474
5719
  }
5475
- }
5476
- break;
5477
- case "content_block_delta":
5478
- if (parsed.delta?.text) {
5479
- onChunk(parsed.delta.text);
5480
- }
5481
- break;
5482
- case "result":
5483
- if (parsed.session_id) {
5484
- extractedSessionId = parsed.session_id;
5485
- session.claudeSessionId = extractedSessionId;
5486
- }
5487
- if (parsed.result?.session_id) {
5488
- extractedSessionId = parsed.result.session_id;
5489
- session.claudeSessionId = extractedSessionId;
5490
- }
5491
- break;
5492
- case "system":
5493
- if (parsed.session_id) {
5494
- extractedSessionId = parsed.session_id;
5495
- session.claudeSessionId = extractedSessionId;
5496
- }
5497
- break;
5498
- case "error":
5499
- onError(parsed.error?.message || parsed.message || "Unknown error from Claude Code");
5500
- break;
5501
- default:
5502
- console.log(`[AgentManager] Unknown stream-json type: ${parsed.type}`);
5720
+ break;
5721
+ case "content_block_delta":
5722
+ if (parsed.delta?.text) {
5723
+ onChunk(parsed.delta.text);
5724
+ }
5725
+ break;
5726
+ case "result":
5727
+ if (parsed.session_id) {
5728
+ extractedSessionId = parsed.session_id;
5729
+ session.agentSessionId = extractedSessionId;
5730
+ session.claudeSessionId = extractedSessionId;
5731
+ }
5732
+ if (parsed.result?.session_id) {
5733
+ extractedSessionId = parsed.result.session_id;
5734
+ session.agentSessionId = extractedSessionId;
5735
+ session.claudeSessionId = extractedSessionId;
5736
+ }
5737
+ break;
5738
+ case "system":
5739
+ if (parsed.session_id) {
5740
+ extractedSessionId = parsed.session_id;
5741
+ session.agentSessionId = extractedSessionId;
5742
+ session.claudeSessionId = extractedSessionId;
5743
+ }
5744
+ break;
5745
+ case "error":
5746
+ onError(parsed.error?.message || parsed.message || "Unknown error from Claude Code");
5747
+ break;
5748
+ default:
5749
+ console.log(`[AgentManager] Claude event: ${parsed.type}`);
5750
+ }
5503
5751
  }
5504
5752
  } catch (parseError) {
5505
5753
  if (line.trim()) {
@@ -5513,15 +5761,15 @@ var AgentManager = class {
5513
5761
  stderrBuffer += data.toString();
5514
5762
  });
5515
5763
  childProcess.on("exit", (code, signal) => {
5516
- console.log(`[AgentManager] Claude Code exited for session ${sessionId}: code=${code}, signal=${signal}`);
5764
+ console.log(`[AgentManager] ${provider} CLI exited for session ${sessionId}: code=${code}, signal=${signal}`);
5517
5765
  this.processes.delete(sessionId);
5518
5766
  this.removePidFile(sessionId);
5519
5767
  if (code === 0) {
5520
5768
  session.status = "stopped";
5521
- onComplete(extractedSessionId || session.claudeSessionId);
5769
+ onComplete(extractedSessionId || session.agentSessionId || session.claudeSessionId);
5522
5770
  } else if (signal === "SIGINT") {
5523
5771
  session.status = "stopped";
5524
- onComplete(extractedSessionId || session.claudeSessionId);
5772
+ onComplete(extractedSessionId || session.agentSessionId || session.claudeSessionId);
5525
5773
  } else {
5526
5774
  session.status = "error";
5527
5775
  const errorMsg = stderrBuffer.trim() || `Process exited with code ${code}`;
@@ -5546,13 +5794,13 @@ var AgentManager = class {
5546
5794
  /**
5547
5795
  * Abort an agent session (SIGINT)
5548
5796
  *
5549
- * Sends SIGINT to the Claude Code process to abort the current operation.
5797
+ * Sends SIGINT to the agent CLI process to abort the current operation.
5550
5798
  */
5551
5799
  async abortSession(sessionId) {
5552
- const process2 = this.processes.get(sessionId);
5553
- if (process2 && !process2.killed) {
5800
+ const agentProcess = this.processes.get(sessionId);
5801
+ if (agentProcess && !agentProcess.killed) {
5554
5802
  console.log(`[AgentManager] Aborting session ${sessionId} with SIGINT`);
5555
- process2.kill("SIGINT");
5803
+ agentProcess.kill("SIGINT");
5556
5804
  }
5557
5805
  const session = this.sessions.get(sessionId);
5558
5806
  if (session) {
@@ -5566,23 +5814,23 @@ var AgentManager = class {
5566
5814
  * If it doesn't exit within 5 seconds, sends SIGTERM.
5567
5815
  */
5568
5816
  async stopSession(sessionId) {
5569
- const process2 = this.processes.get(sessionId);
5817
+ const agentProcess = this.processes.get(sessionId);
5570
5818
  const session = this.sessions.get(sessionId);
5571
5819
  if (session) {
5572
5820
  session.status = "stopping";
5573
5821
  }
5574
- if (process2 && !process2.killed) {
5822
+ if (agentProcess && !agentProcess.killed) {
5575
5823
  console.log(`[AgentManager] Stopping session ${sessionId}`);
5576
- process2.kill("SIGINT");
5824
+ agentProcess.kill("SIGINT");
5577
5825
  await new Promise((resolve3) => {
5578
5826
  const timeout = setTimeout(() => {
5579
- if (!process2.killed) {
5827
+ if (!agentProcess.killed) {
5580
5828
  console.log(`[AgentManager] Force killing session ${sessionId}`);
5581
- process2.kill("SIGTERM");
5829
+ agentProcess.kill("SIGTERM");
5582
5830
  }
5583
5831
  resolve3();
5584
5832
  }, 5e3);
5585
- process2.once("exit", () => {
5833
+ agentProcess.once("exit", () => {
5586
5834
  clearTimeout(timeout);
5587
5835
  resolve3();
5588
5836
  });
@@ -5626,14 +5874,14 @@ var AgentManager = class {
5626
5874
  */
5627
5875
  async cleanupOrphanedProcesses() {
5628
5876
  let cleaned = 0;
5629
- if (!fs8.existsSync(this.pidDir)) {
5877
+ if (!fs9.existsSync(this.pidDir)) {
5630
5878
  return { cleaned };
5631
5879
  }
5632
- const pidFiles = fs8.readdirSync(this.pidDir).filter((f) => f.endsWith(".pid"));
5880
+ const pidFiles = fs9.readdirSync(this.pidDir).filter((f) => f.endsWith(".pid"));
5633
5881
  for (const pidFile of pidFiles) {
5634
- const pidPath = path9.join(this.pidDir, pidFile);
5882
+ const pidPath = path10.join(this.pidDir, pidFile);
5635
5883
  try {
5636
- const pidStr = fs8.readFileSync(pidPath, "utf-8").trim();
5884
+ const pidStr = fs9.readFileSync(pidPath, "utf-8").trim();
5637
5885
  const pid = parseInt(pidStr, 10);
5638
5886
  if (!isNaN(pid)) {
5639
5887
  try {
@@ -5644,7 +5892,7 @@ var AgentManager = class {
5644
5892
  } catch {
5645
5893
  }
5646
5894
  }
5647
- fs8.unlinkSync(pidPath);
5895
+ fs9.unlinkSync(pidPath);
5648
5896
  } catch (error) {
5649
5897
  console.warn(`[AgentManager] Error cleaning PID file ${pidFile}:`, error);
5650
5898
  }
@@ -5658,17 +5906,17 @@ var AgentManager = class {
5658
5906
  * Write PID file for session tracking
5659
5907
  */
5660
5908
  writePidFile(sessionId, pid) {
5661
- const pidPath = path9.join(this.pidDir, `${sessionId}.pid`);
5662
- fs8.writeFileSync(pidPath, pid.toString());
5909
+ const pidPath = path10.join(this.pidDir, `${sessionId}.pid`);
5910
+ fs9.writeFileSync(pidPath, pid.toString());
5663
5911
  }
5664
5912
  /**
5665
5913
  * Remove PID file for session
5666
5914
  */
5667
5915
  removePidFile(sessionId) {
5668
- const pidPath = path9.join(this.pidDir, `${sessionId}.pid`);
5916
+ const pidPath = path10.join(this.pidDir, `${sessionId}.pid`);
5669
5917
  try {
5670
- if (fs8.existsSync(pidPath)) {
5671
- fs8.unlinkSync(pidPath);
5918
+ if (fs9.existsSync(pidPath)) {
5919
+ fs9.unlinkSync(pidPath);
5672
5920
  }
5673
5921
  } catch {
5674
5922
  }
@@ -5699,10 +5947,10 @@ var import_events3 = require("events");
5699
5947
  var import_fs = require("fs");
5700
5948
 
5701
5949
  // src/preview/dev-server-runner.ts
5702
- var import_child_process10 = require("child_process");
5950
+ var import_child_process11 = require("child_process");
5703
5951
  var http = __toESM(require("http"));
5704
- var fs12 = __toESM(require("fs"));
5705
- var path13 = __toESM(require("path"));
5952
+ var fs13 = __toESM(require("fs"));
5953
+ var path14 = __toESM(require("path"));
5706
5954
  var import_events2 = require("events");
5707
5955
  var import_core8 = __toESM(require_dist());
5708
5956
 
@@ -5727,13 +5975,13 @@ async function isPortInUse(port) {
5727
5975
  }
5728
5976
 
5729
5977
  // src/utils/env-cache.ts
5730
- var fs10 = __toESM(require("fs"));
5731
- var path11 = __toESM(require("path"));
5978
+ var fs11 = __toESM(require("fs"));
5979
+ var path12 = __toESM(require("path"));
5732
5980
  var os4 = __toESM(require("os"));
5733
5981
 
5734
5982
  // src/utils/env-setup.ts
5735
- var fs9 = __toESM(require("fs"));
5736
- var path10 = __toESM(require("path"));
5983
+ var fs10 = __toESM(require("fs"));
5984
+ var path11 = __toESM(require("path"));
5737
5985
  async function fetchEnvVars(apiUrl, accessToken) {
5738
5986
  try {
5739
5987
  const url = `${apiUrl}/api/cli/env-vars`;
@@ -5768,29 +6016,29 @@ function writeEnvFile(targetPath, envVars) {
5768
6016
  }
5769
6017
  return `${key}=${value}`;
5770
6018
  }).join("\n") + "\n";
5771
- const envPath = path10.join(targetPath, ".env");
5772
- fs9.writeFileSync(envPath, envContent, { mode: 384 });
6019
+ const envPath = path11.join(targetPath, ".env");
6020
+ fs10.writeFileSync(envPath, envContent, { mode: 384 });
5773
6021
  console.log(`[env-setup] Wrote ${Object.keys(envVars).length} env vars to ${envPath}`);
5774
6022
  }
5775
6023
 
5776
6024
  // src/utils/env-cache.ts
5777
6025
  var DEFAULT_CACHE_TTL = 60;
5778
- var CACHE_DIR = path11.join(os4.homedir(), ".episoda", "cache");
6026
+ var CACHE_DIR = path12.join(os4.homedir(), ".episoda", "cache");
5779
6027
  function getCacheFilePath(projectId) {
5780
- return path11.join(CACHE_DIR, `env-vars-${projectId}.json`);
6028
+ return path12.join(CACHE_DIR, `env-vars-${projectId}.json`);
5781
6029
  }
5782
6030
  function ensureCacheDir() {
5783
- if (!fs10.existsSync(CACHE_DIR)) {
5784
- fs10.mkdirSync(CACHE_DIR, { recursive: true, mode: 448 });
6031
+ if (!fs11.existsSync(CACHE_DIR)) {
6032
+ fs11.mkdirSync(CACHE_DIR, { recursive: true, mode: 448 });
5785
6033
  }
5786
6034
  }
5787
6035
  function readCache(projectId) {
5788
6036
  try {
5789
6037
  const cacheFile = getCacheFilePath(projectId);
5790
- if (!fs10.existsSync(cacheFile)) {
6038
+ if (!fs11.existsSync(cacheFile)) {
5791
6039
  return null;
5792
6040
  }
5793
- const content = fs10.readFileSync(cacheFile, "utf-8");
6041
+ const content = fs11.readFileSync(cacheFile, "utf-8");
5794
6042
  const data = JSON.parse(content);
5795
6043
  if (!data.vars || typeof data.vars !== "object" || !data.fetchedAt) {
5796
6044
  return null;
@@ -5809,7 +6057,7 @@ function writeCache(projectId, vars) {
5809
6057
  fetchedAt: Date.now(),
5810
6058
  projectId
5811
6059
  };
5812
- fs10.writeFileSync(cacheFile, JSON.stringify(data, null, 2), { mode: 384 });
6060
+ fs11.writeFileSync(cacheFile, JSON.stringify(data, null, 2), { mode: 384 });
5813
6061
  } catch (error) {
5814
6062
  console.warn("[env-cache] Failed to write cache:", error instanceof Error ? error.message : error);
5815
6063
  }
@@ -5878,11 +6126,11 @@ No cached values available as fallback.`
5878
6126
  }
5879
6127
 
5880
6128
  // src/preview/dev-server-registry.ts
5881
- var fs11 = __toESM(require("fs"));
5882
- var path12 = __toESM(require("path"));
6129
+ var fs12 = __toESM(require("fs"));
6130
+ var path13 = __toESM(require("path"));
5883
6131
  var os5 = __toESM(require("os"));
5884
- var import_child_process9 = require("child_process");
5885
- var DEV_SERVER_REGISTRY_DIR = path12.join(os5.homedir(), ".episoda", "dev-servers");
6132
+ var import_child_process10 = require("child_process");
6133
+ var DEV_SERVER_REGISTRY_DIR = path13.join(os5.homedir(), ".episoda", "dev-servers");
5886
6134
  var DevServerRegistry = class {
5887
6135
  constructor() {
5888
6136
  this.ensureRegistryDir();
@@ -5892,9 +6140,9 @@ var DevServerRegistry = class {
5892
6140
  */
5893
6141
  ensureRegistryDir() {
5894
6142
  try {
5895
- if (!fs11.existsSync(DEV_SERVER_REGISTRY_DIR)) {
6143
+ if (!fs12.existsSync(DEV_SERVER_REGISTRY_DIR)) {
5896
6144
  console.log(`[DevServerRegistry] EP1042: Creating registry directory: ${DEV_SERVER_REGISTRY_DIR}`);
5897
- fs11.mkdirSync(DEV_SERVER_REGISTRY_DIR, { recursive: true });
6145
+ fs12.mkdirSync(DEV_SERVER_REGISTRY_DIR, { recursive: true });
5898
6146
  }
5899
6147
  } catch (error) {
5900
6148
  console.error(`[DevServerRegistry] EP1042: Failed to create registry directory:`, error);
@@ -5905,7 +6153,7 @@ var DevServerRegistry = class {
5905
6153
  * Get the registry file path for a module
5906
6154
  */
5907
6155
  getEntryPath(moduleUid) {
5908
- return path12.join(DEV_SERVER_REGISTRY_DIR, `${moduleUid}.json`);
6156
+ return path13.join(DEV_SERVER_REGISTRY_DIR, `${moduleUid}.json`);
5909
6157
  }
5910
6158
  /**
5911
6159
  * Register a dev server
@@ -5916,7 +6164,7 @@ var DevServerRegistry = class {
5916
6164
  try {
5917
6165
  this.ensureRegistryDir();
5918
6166
  const entryPath = this.getEntryPath(entry.moduleUid);
5919
- fs11.writeFileSync(entryPath, JSON.stringify(entry, null, 2), "utf8");
6167
+ fs12.writeFileSync(entryPath, JSON.stringify(entry, null, 2), "utf8");
5920
6168
  console.log(`[DevServerRegistry] EP1042: Registered ${entry.moduleUid} (PID ${entry.pid}, port ${entry.port})`);
5921
6169
  } catch (error) {
5922
6170
  console.error(`[DevServerRegistry] EP1042: Failed to register ${entry.moduleUid}:`, error);
@@ -5930,8 +6178,8 @@ var DevServerRegistry = class {
5930
6178
  unregister(moduleUid) {
5931
6179
  try {
5932
6180
  const entryPath = this.getEntryPath(moduleUid);
5933
- if (fs11.existsSync(entryPath)) {
5934
- fs11.unlinkSync(entryPath);
6181
+ if (fs12.existsSync(entryPath)) {
6182
+ fs12.unlinkSync(entryPath);
5935
6183
  console.log(`[DevServerRegistry] EP1042: Unregistered ${moduleUid}`);
5936
6184
  }
5937
6185
  } catch (error) {
@@ -5947,10 +6195,10 @@ var DevServerRegistry = class {
5947
6195
  getByModule(moduleUid) {
5948
6196
  try {
5949
6197
  const entryPath = this.getEntryPath(moduleUid);
5950
- if (!fs11.existsSync(entryPath)) {
6198
+ if (!fs12.existsSync(entryPath)) {
5951
6199
  return null;
5952
6200
  }
5953
- const content = fs11.readFileSync(entryPath, "utf8");
6201
+ const content = fs12.readFileSync(entryPath, "utf8");
5954
6202
  const entry = JSON.parse(content);
5955
6203
  if (!entry.pid || !entry.port || !entry.worktreePath) {
5956
6204
  console.warn(`[DevServerRegistry] EP1042: Invalid entry for ${moduleUid}, removing`);
@@ -5988,7 +6236,7 @@ var DevServerRegistry = class {
5988
6236
  const entries = [];
5989
6237
  try {
5990
6238
  this.ensureRegistryDir();
5991
- const files = fs11.readdirSync(DEV_SERVER_REGISTRY_DIR).filter((f) => f.endsWith(".json"));
6239
+ const files = fs12.readdirSync(DEV_SERVER_REGISTRY_DIR).filter((f) => f.endsWith(".json"));
5992
6240
  for (const file of files) {
5993
6241
  const moduleUid = file.replace(".json", "");
5994
6242
  const entry = this.getByModule(moduleUid);
@@ -6036,7 +6284,7 @@ var DevServerRegistry = class {
6036
6284
  */
6037
6285
  getProcessCwd(pid) {
6038
6286
  try {
6039
- const output = (0, import_child_process9.execSync)(`lsof -p ${pid} -Fn | grep ^n | grep cwd | head -1`, {
6287
+ const output = (0, import_child_process10.execSync)(`lsof -p ${pid} -Fn | grep ^n | grep cwd | head -1`, {
6040
6288
  encoding: "utf8",
6041
6289
  timeout: 5e3
6042
6290
  }).trim();
@@ -6046,7 +6294,7 @@ var DevServerRegistry = class {
6046
6294
  return null;
6047
6295
  } catch {
6048
6296
  try {
6049
- return fs11.readlinkSync(`/proc/${pid}/cwd`);
6297
+ return fs12.readlinkSync(`/proc/${pid}/cwd`);
6050
6298
  } catch {
6051
6299
  return null;
6052
6300
  }
@@ -6061,7 +6309,7 @@ var DevServerRegistry = class {
6061
6309
  findProcessesInWorktree(worktreePath) {
6062
6310
  const pids = [];
6063
6311
  try {
6064
- const output = (0, import_child_process9.execSync)(
6312
+ const output = (0, import_child_process10.execSync)(
6065
6313
  `lsof -c node -c next | grep "${worktreePath}" | awk '{print $2}' | sort -u`,
6066
6314
  { encoding: "utf8", timeout: 5e3 }
6067
6315
  ).trim();
@@ -6122,7 +6370,7 @@ var DevServerRegistry = class {
6122
6370
  */
6123
6371
  findProcessesOnPort(port) {
6124
6372
  try {
6125
- const output = (0, import_child_process9.execSync)(`lsof -ti:${port} 2>/dev/null || true`, { encoding: "utf8" }).trim();
6373
+ const output = (0, import_child_process10.execSync)(`lsof -ti:${port} 2>/dev/null || true`, { encoding: "utf8" }).trim();
6126
6374
  if (!output) {
6127
6375
  return [];
6128
6376
  }
@@ -6376,7 +6624,7 @@ var DevServerRunner = class extends import_events2.EventEmitter {
6376
6624
  */
6377
6625
  async killProcessOnPort(port) {
6378
6626
  try {
6379
- const result = (0, import_child_process10.execSync)(`lsof -ti:${port} 2>/dev/null || true`, { encoding: "utf8" }).trim();
6627
+ const result = (0, import_child_process11.execSync)(`lsof -ti:${port} 2>/dev/null || true`, { encoding: "utf8" }).trim();
6380
6628
  if (!result) {
6381
6629
  return true;
6382
6630
  }
@@ -6384,15 +6632,15 @@ var DevServerRunner = class extends import_events2.EventEmitter {
6384
6632
  console.log(`[DevServerRunner] Found ${pids.length} process(es) on port ${port}`);
6385
6633
  for (const pid of pids) {
6386
6634
  try {
6387
- (0, import_child_process10.execSync)(`kill -15 ${pid} 2>/dev/null || true`);
6635
+ (0, import_child_process11.execSync)(`kill -15 ${pid} 2>/dev/null || true`);
6388
6636
  } catch {
6389
6637
  }
6390
6638
  }
6391
6639
  await this.wait(1e3);
6392
6640
  for (const pid of pids) {
6393
6641
  try {
6394
- (0, import_child_process10.execSync)(`kill -0 ${pid} 2>/dev/null`);
6395
- (0, import_child_process10.execSync)(`kill -9 ${pid} 2>/dev/null || true`);
6642
+ (0, import_child_process11.execSync)(`kill -0 ${pid} 2>/dev/null`);
6643
+ (0, import_child_process11.execSync)(`kill -9 ${pid} 2>/dev/null || true`);
6396
6644
  } catch {
6397
6645
  }
6398
6646
  }
@@ -6416,8 +6664,8 @@ var DevServerRunner = class extends import_events2.EventEmitter {
6416
6664
  cacheTtl: 300
6417
6665
  });
6418
6666
  console.log(`[DevServerRunner] Loaded ${Object.keys(result.envVars).length} env vars`);
6419
- const envFilePath = path13.join(projectPath, ".env");
6420
- if (!fs12.existsSync(envFilePath) && Object.keys(result.envVars).length > 0) {
6667
+ const envFilePath = path14.join(projectPath, ".env");
6668
+ if (!fs13.existsSync(envFilePath) && Object.keys(result.envVars).length > 0) {
6421
6669
  console.log(`[DevServerRunner] Writing .env file`);
6422
6670
  writeEnvFile(projectPath, result.envVars);
6423
6671
  }
@@ -6441,7 +6689,7 @@ var DevServerRunner = class extends import_events2.EventEmitter {
6441
6689
  PORT: String(port),
6442
6690
  NODE_OPTIONS: enhancedNodeOptions
6443
6691
  };
6444
- const proc = (0, import_child_process10.spawn)(cmd, args, {
6692
+ const proc = (0, import_child_process11.spawn)(cmd, args, {
6445
6693
  cwd: projectPath,
6446
6694
  env: mergedEnv,
6447
6695
  stdio: ["ignore", "pipe", "pipe"],
@@ -6566,25 +6814,25 @@ var DevServerRunner = class extends import_events2.EventEmitter {
6566
6814
  return new Promise((resolve3) => setTimeout(resolve3, ms));
6567
6815
  }
6568
6816
  getLogsDir() {
6569
- const logsDir = path13.join((0, import_core8.getConfigDir)(), "logs");
6570
- if (!fs12.existsSync(logsDir)) {
6571
- fs12.mkdirSync(logsDir, { recursive: true });
6817
+ const logsDir = path14.join((0, import_core8.getConfigDir)(), "logs");
6818
+ if (!fs13.existsSync(logsDir)) {
6819
+ fs13.mkdirSync(logsDir, { recursive: true });
6572
6820
  }
6573
6821
  return logsDir;
6574
6822
  }
6575
6823
  getLogFilePath(moduleUid) {
6576
- return path13.join(this.getLogsDir(), `dev-${moduleUid}.log`);
6824
+ return path14.join(this.getLogsDir(), `dev-${moduleUid}.log`);
6577
6825
  }
6578
6826
  rotateLogIfNeeded(logPath) {
6579
6827
  try {
6580
- if (fs12.existsSync(logPath)) {
6581
- const stats = fs12.statSync(logPath);
6828
+ if (fs13.existsSync(logPath)) {
6829
+ const stats = fs13.statSync(logPath);
6582
6830
  if (stats.size > DEV_SERVER_CONSTANTS.MAX_LOG_SIZE_BYTES) {
6583
6831
  const backupPath = `${logPath}.1`;
6584
- if (fs12.existsSync(backupPath)) {
6585
- fs12.unlinkSync(backupPath);
6832
+ if (fs13.existsSync(backupPath)) {
6833
+ fs13.unlinkSync(backupPath);
6586
6834
  }
6587
- fs12.renameSync(logPath, backupPath);
6835
+ fs13.renameSync(logPath, backupPath);
6588
6836
  }
6589
6837
  }
6590
6838
  } catch {
@@ -6595,7 +6843,7 @@ var DevServerRunner = class extends import_events2.EventEmitter {
6595
6843
  try {
6596
6844
  const timestamp = (/* @__PURE__ */ new Date()).toISOString();
6597
6845
  const prefix = isError ? "ERR" : "OUT";
6598
- fs12.appendFileSync(logPath, `[${timestamp}] [${prefix}] ${line}
6846
+ fs13.appendFileSync(logPath, `[${timestamp}] [${prefix}] ${line}
6599
6847
  `);
6600
6848
  } catch {
6601
6849
  }
@@ -6623,21 +6871,21 @@ function getDevServerRunner() {
6623
6871
  }
6624
6872
 
6625
6873
  // src/utils/port-allocator.ts
6626
- var fs13 = __toESM(require("fs"));
6627
- var path14 = __toESM(require("path"));
6874
+ var fs14 = __toESM(require("fs"));
6875
+ var path15 = __toESM(require("path"));
6628
6876
  var os6 = __toESM(require("os"));
6629
6877
  var PORT_RANGE_START = 3100;
6630
6878
  var PORT_RANGE_END = 3199;
6631
6879
  var PORT_WARNING_THRESHOLD = 80;
6632
- var PORTS_FILE = path14.join(os6.homedir(), ".episoda", "ports.json");
6880
+ var PORTS_FILE = path15.join(os6.homedir(), ".episoda", "ports.json");
6633
6881
  var portAssignments = /* @__PURE__ */ new Map();
6634
6882
  var initialized = false;
6635
6883
  function loadFromDisk() {
6636
6884
  if (initialized) return;
6637
6885
  initialized = true;
6638
6886
  try {
6639
- if (fs13.existsSync(PORTS_FILE)) {
6640
- const content = fs13.readFileSync(PORTS_FILE, "utf8");
6887
+ if (fs14.existsSync(PORTS_FILE)) {
6888
+ const content = fs14.readFileSync(PORTS_FILE, "utf8");
6641
6889
  const data = JSON.parse(content);
6642
6890
  for (const [moduleUid, port] of Object.entries(data)) {
6643
6891
  if (typeof port === "number" && port >= PORT_RANGE_START && port <= PORT_RANGE_END) {
@@ -6654,15 +6902,15 @@ function loadFromDisk() {
6654
6902
  }
6655
6903
  function saveToDisk() {
6656
6904
  try {
6657
- const dir = path14.dirname(PORTS_FILE);
6658
- if (!fs13.existsSync(dir)) {
6659
- fs13.mkdirSync(dir, { recursive: true });
6905
+ const dir = path15.dirname(PORTS_FILE);
6906
+ if (!fs14.existsSync(dir)) {
6907
+ fs14.mkdirSync(dir, { recursive: true });
6660
6908
  }
6661
6909
  const data = {};
6662
6910
  for (const [moduleUid, port] of portAssignments) {
6663
6911
  data[moduleUid] = port;
6664
6912
  }
6665
- fs13.writeFileSync(PORTS_FILE, JSON.stringify(data, null, 2), "utf8");
6913
+ fs14.writeFileSync(PORTS_FILE, JSON.stringify(data, null, 2), "utf8");
6666
6914
  } catch (error) {
6667
6915
  console.warn(`[PortAllocator] EP1042: Failed to save ports.json:`, error);
6668
6916
  }
@@ -7138,10 +7386,10 @@ function getPreviewManager() {
7138
7386
  }
7139
7387
 
7140
7388
  // src/utils/dev-server.ts
7141
- var import_child_process11 = require("child_process");
7389
+ var import_child_process12 = require("child_process");
7142
7390
  var import_core9 = __toESM(require_dist());
7143
- var fs14 = __toESM(require("fs"));
7144
- var path15 = __toESM(require("path"));
7391
+ var fs15 = __toESM(require("fs"));
7392
+ var path16 = __toESM(require("path"));
7145
7393
  var MAX_RESTART_ATTEMPTS = 5;
7146
7394
  var INITIAL_RESTART_DELAY_MS = 2e3;
7147
7395
  var MAX_RESTART_DELAY_MS = 3e4;
@@ -7149,26 +7397,26 @@ var MAX_LOG_SIZE_BYTES = 5 * 1024 * 1024;
7149
7397
  var NODE_MEMORY_LIMIT_MB = 2048;
7150
7398
  var activeServers = /* @__PURE__ */ new Map();
7151
7399
  function getLogsDir() {
7152
- const logsDir = path15.join((0, import_core9.getConfigDir)(), "logs");
7153
- if (!fs14.existsSync(logsDir)) {
7154
- fs14.mkdirSync(logsDir, { recursive: true });
7400
+ const logsDir = path16.join((0, import_core9.getConfigDir)(), "logs");
7401
+ if (!fs15.existsSync(logsDir)) {
7402
+ fs15.mkdirSync(logsDir, { recursive: true });
7155
7403
  }
7156
7404
  return logsDir;
7157
7405
  }
7158
7406
  function getLogFilePath(moduleUid) {
7159
- return path15.join(getLogsDir(), `dev-${moduleUid}.log`);
7407
+ return path16.join(getLogsDir(), `dev-${moduleUid}.log`);
7160
7408
  }
7161
7409
  function rotateLogIfNeeded(logPath) {
7162
7410
  try {
7163
- if (fs14.existsSync(logPath)) {
7164
- const stats = fs14.statSync(logPath);
7411
+ if (fs15.existsSync(logPath)) {
7412
+ const stats = fs15.statSync(logPath);
7165
7413
  if (stats.size > MAX_LOG_SIZE_BYTES) {
7166
7414
  const backupPath = `${logPath}.1`;
7167
- if (fs14.existsSync(backupPath)) {
7168
- fs14.unlinkSync(backupPath);
7415
+ if (fs15.existsSync(backupPath)) {
7416
+ fs15.unlinkSync(backupPath);
7169
7417
  }
7170
- fs14.renameSync(logPath, backupPath);
7171
- console.log(`[DevServer] EP932: Rotated log file for ${path15.basename(logPath)}`);
7418
+ fs15.renameSync(logPath, backupPath);
7419
+ console.log(`[DevServer] EP932: Rotated log file for ${path16.basename(logPath)}`);
7172
7420
  }
7173
7421
  }
7174
7422
  } catch (error) {
@@ -7181,13 +7429,13 @@ function writeToLog(logPath, line, isError = false) {
7181
7429
  const prefix = isError ? "ERR" : "OUT";
7182
7430
  const logLine = `[${timestamp}] [${prefix}] ${line}
7183
7431
  `;
7184
- fs14.appendFileSync(logPath, logLine);
7432
+ fs15.appendFileSync(logPath, logLine);
7185
7433
  } catch {
7186
7434
  }
7187
7435
  }
7188
7436
  async function killProcessOnPort(port) {
7189
7437
  try {
7190
- const result = (0, import_child_process11.execSync)(`lsof -ti:${port} 2>/dev/null || true`, { encoding: "utf8" }).trim();
7438
+ const result = (0, import_child_process12.execSync)(`lsof -ti:${port} 2>/dev/null || true`, { encoding: "utf8" }).trim();
7191
7439
  if (!result) {
7192
7440
  console.log(`[DevServer] EP929: No process found on port ${port}`);
7193
7441
  return true;
@@ -7196,7 +7444,7 @@ async function killProcessOnPort(port) {
7196
7444
  console.log(`[DevServer] EP929: Found ${pids.length} process(es) on port ${port}: ${pids.join(", ")}`);
7197
7445
  for (const pid of pids) {
7198
7446
  try {
7199
- (0, import_child_process11.execSync)(`kill -15 ${pid} 2>/dev/null || true`, { encoding: "utf8" });
7447
+ (0, import_child_process12.execSync)(`kill -15 ${pid} 2>/dev/null || true`, { encoding: "utf8" });
7200
7448
  console.log(`[DevServer] EP929: Sent SIGTERM to PID ${pid}`);
7201
7449
  } catch {
7202
7450
  }
@@ -7204,8 +7452,8 @@ async function killProcessOnPort(port) {
7204
7452
  await new Promise((resolve3) => setTimeout(resolve3, 1e3));
7205
7453
  for (const pid of pids) {
7206
7454
  try {
7207
- (0, import_child_process11.execSync)(`kill -0 ${pid} 2>/dev/null`, { encoding: "utf8" });
7208
- (0, import_child_process11.execSync)(`kill -9 ${pid} 2>/dev/null || true`, { encoding: "utf8" });
7455
+ (0, import_child_process12.execSync)(`kill -0 ${pid} 2>/dev/null`, { encoding: "utf8" });
7456
+ (0, import_child_process12.execSync)(`kill -9 ${pid} 2>/dev/null || true`, { encoding: "utf8" });
7209
7457
  console.log(`[DevServer] EP929: Force killed PID ${pid}`);
7210
7458
  } catch {
7211
7459
  }
@@ -7256,7 +7504,7 @@ function spawnDevServerProcess(projectPath, port, moduleUid, logPath, customComm
7256
7504
  if (injectedCount > 0) {
7257
7505
  console.log(`[DevServer] EP998: Injecting ${injectedCount} env vars from database`);
7258
7506
  }
7259
- const devProcess = (0, import_child_process11.spawn)(cmd, args, {
7507
+ const devProcess = (0, import_child_process12.spawn)(cmd, args, {
7260
7508
  cwd: projectPath,
7261
7509
  env: mergedEnv,
7262
7510
  stdio: ["ignore", "pipe", "pipe"],
@@ -7360,8 +7608,8 @@ async function startDevServer(projectPath, port = 3e3, moduleUid = "default", op
7360
7608
  });
7361
7609
  injectedEnvVars = result.envVars;
7362
7610
  console.log(`[DevServer] EP998: Loaded ${Object.keys(injectedEnvVars).length} env vars (from ${result.fromCache ? "cache" : "server"})`);
7363
- const envFilePath = path15.join(projectPath, ".env");
7364
- if (!fs14.existsSync(envFilePath) && Object.keys(injectedEnvVars).length > 0) {
7611
+ const envFilePath = path16.join(projectPath, ".env");
7612
+ if (!fs15.existsSync(envFilePath) && Object.keys(injectedEnvVars).length > 0) {
7365
7613
  console.log(`[DevServer] EP1004: .env file missing, writing ${Object.keys(injectedEnvVars).length} vars to ${envFilePath}`);
7366
7614
  writeEnvFile(projectPath, injectedEnvVars);
7367
7615
  }
@@ -7467,8 +7715,8 @@ function getDevServerStatus() {
7467
7715
  }
7468
7716
 
7469
7717
  // src/daemon/worktree-manager.ts
7470
- var fs15 = __toESM(require("fs"));
7471
- var path16 = __toESM(require("path"));
7718
+ var fs16 = __toESM(require("fs"));
7719
+ var path17 = __toESM(require("path"));
7472
7720
  var import_core10 = __toESM(require_dist());
7473
7721
  function validateModuleUid(moduleUid) {
7474
7722
  if (!moduleUid || typeof moduleUid !== "string" || !moduleUid.trim()) {
@@ -7492,8 +7740,8 @@ var WorktreeManager = class _WorktreeManager {
7492
7740
  // ============================================================
7493
7741
  this.lockPath = "";
7494
7742
  this.projectRoot = projectRoot;
7495
- this.bareRepoPath = path16.join(projectRoot, ".bare");
7496
- this.configPath = path16.join(projectRoot, ".episoda", "config.json");
7743
+ this.bareRepoPath = path17.join(projectRoot, ".bare");
7744
+ this.configPath = path17.join(projectRoot, ".episoda", "config.json");
7497
7745
  this.gitExecutor = new import_core10.GitExecutor();
7498
7746
  }
7499
7747
  /**
@@ -7504,13 +7752,13 @@ var WorktreeManager = class _WorktreeManager {
7504
7752
  */
7505
7753
  async initialize() {
7506
7754
  const debug = process.env.EPISODA_DEBUG === "1" || process.env.GIT_CREDENTIAL_EPISODA_DEBUG === "1";
7507
- if (!fs15.existsSync(this.bareRepoPath)) {
7755
+ if (!fs16.existsSync(this.bareRepoPath)) {
7508
7756
  if (debug) {
7509
7757
  console.log(`[WorktreeManager] initialize: .bare not found at ${this.bareRepoPath}`);
7510
7758
  }
7511
7759
  return false;
7512
7760
  }
7513
- if (!fs15.existsSync(this.configPath)) {
7761
+ if (!fs16.existsSync(this.configPath)) {
7514
7762
  if (debug) {
7515
7763
  console.log(`[WorktreeManager] initialize: config not found at ${this.configPath}`);
7516
7764
  }
@@ -7542,10 +7790,10 @@ var WorktreeManager = class _WorktreeManager {
7542
7790
  */
7543
7791
  async ensureFetchRefspecConfigured() {
7544
7792
  try {
7545
- const { execSync: execSync9 } = require("child_process");
7793
+ const { execSync: execSync10 } = require("child_process");
7546
7794
  let fetchRefspec = null;
7547
7795
  try {
7548
- fetchRefspec = execSync9("git config --get remote.origin.fetch", {
7796
+ fetchRefspec = execSync10("git config --get remote.origin.fetch", {
7549
7797
  cwd: this.bareRepoPath,
7550
7798
  encoding: "utf-8",
7551
7799
  timeout: 5e3
@@ -7554,7 +7802,7 @@ var WorktreeManager = class _WorktreeManager {
7554
7802
  }
7555
7803
  if (!fetchRefspec) {
7556
7804
  console.log("[WorktreeManager] EP1014: Configuring missing fetch refspec for bare repo");
7557
- execSync9('git config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*"', {
7805
+ execSync10('git config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*"', {
7558
7806
  cwd: this.bareRepoPath,
7559
7807
  timeout: 5e3
7560
7808
  });
@@ -7569,8 +7817,8 @@ var WorktreeManager = class _WorktreeManager {
7569
7817
  */
7570
7818
  static async createProject(projectRoot, repoUrl, projectId, workspaceSlug, projectSlug) {
7571
7819
  const manager = new _WorktreeManager(projectRoot);
7572
- const episodaDir = path16.join(projectRoot, ".episoda");
7573
- fs15.mkdirSync(episodaDir, { recursive: true });
7820
+ const episodaDir = path17.join(projectRoot, ".episoda");
7821
+ fs16.mkdirSync(episodaDir, { recursive: true });
7574
7822
  const cloneResult = await manager.gitExecutor.execute({
7575
7823
  action: "clone_bare",
7576
7824
  url: repoUrl,
@@ -7601,7 +7849,7 @@ var WorktreeManager = class _WorktreeManager {
7601
7849
  error: `Invalid module UID: "${moduleUid}" - contains disallowed characters`
7602
7850
  };
7603
7851
  }
7604
- const worktreePath = path16.join(this.projectRoot, moduleUid);
7852
+ const worktreePath = path17.join(this.projectRoot, moduleUid);
7605
7853
  const lockAcquired = await this.acquireLock();
7606
7854
  if (!lockAcquired) {
7607
7855
  return {
@@ -7792,7 +8040,7 @@ var WorktreeManager = class _WorktreeManager {
7792
8040
  let prunedCount = 0;
7793
8041
  await this.updateConfigSafe((config) => {
7794
8042
  const initialCount = config.worktrees.length;
7795
- config.worktrees = config.worktrees.filter((w) => fs15.existsSync(w.worktreePath));
8043
+ config.worktrees = config.worktrees.filter((w) => fs16.existsSync(w.worktreePath));
7796
8044
  prunedCount = initialCount - config.worktrees.length;
7797
8045
  return config;
7798
8046
  });
@@ -7873,16 +8121,16 @@ var WorktreeManager = class _WorktreeManager {
7873
8121
  const retryInterval = 50;
7874
8122
  while (Date.now() - startTime < timeoutMs) {
7875
8123
  try {
7876
- fs15.writeFileSync(lockPath, String(process.pid), { flag: "wx" });
8124
+ fs16.writeFileSync(lockPath, String(process.pid), { flag: "wx" });
7877
8125
  return true;
7878
8126
  } catch (err) {
7879
8127
  if (err.code === "EEXIST") {
7880
8128
  try {
7881
- const stats = fs15.statSync(lockPath);
8129
+ const stats = fs16.statSync(lockPath);
7882
8130
  const lockAge = Date.now() - stats.mtimeMs;
7883
8131
  if (lockAge > 3e4) {
7884
8132
  try {
7885
- const lockContent = fs15.readFileSync(lockPath, "utf-8").trim();
8133
+ const lockContent = fs16.readFileSync(lockPath, "utf-8").trim();
7886
8134
  const lockPid = parseInt(lockContent, 10);
7887
8135
  if (!isNaN(lockPid) && this.isProcessRunning(lockPid)) {
7888
8136
  await new Promise((resolve3) => setTimeout(resolve3, retryInterval));
@@ -7891,7 +8139,7 @@ var WorktreeManager = class _WorktreeManager {
7891
8139
  } catch {
7892
8140
  }
7893
8141
  try {
7894
- fs15.unlinkSync(lockPath);
8142
+ fs16.unlinkSync(lockPath);
7895
8143
  } catch {
7896
8144
  }
7897
8145
  continue;
@@ -7912,7 +8160,7 @@ var WorktreeManager = class _WorktreeManager {
7912
8160
  */
7913
8161
  releaseLock() {
7914
8162
  try {
7915
- fs15.unlinkSync(this.getLockPath());
8163
+ fs16.unlinkSync(this.getLockPath());
7916
8164
  } catch {
7917
8165
  }
7918
8166
  }
@@ -7936,11 +8184,11 @@ var WorktreeManager = class _WorktreeManager {
7936
8184
  // Turborepo cache
7937
8185
  ];
7938
8186
  for (const cacheDir of cacheDirs) {
7939
- const cachePath = path16.join(worktreePath, cacheDir);
8187
+ const cachePath = path17.join(worktreePath, cacheDir);
7940
8188
  try {
7941
- if (fs15.existsSync(cachePath)) {
8189
+ if (fs16.existsSync(cachePath)) {
7942
8190
  console.log(`[WorktreeManager] EP1070: Cleaning build cache: ${cacheDir}`);
7943
- fs15.rmSync(cachePath, { recursive: true, force: true });
8191
+ fs16.rmSync(cachePath, { recursive: true, force: true });
7944
8192
  }
7945
8193
  } catch (error) {
7946
8194
  console.warn(`[WorktreeManager] EP1070: Failed to clean ${cacheDir} (non-blocking):`, error.message);
@@ -7949,10 +8197,10 @@ var WorktreeManager = class _WorktreeManager {
7949
8197
  }
7950
8198
  readConfig() {
7951
8199
  try {
7952
- if (!fs15.existsSync(this.configPath)) {
8200
+ if (!fs16.existsSync(this.configPath)) {
7953
8201
  return null;
7954
8202
  }
7955
- const content = fs15.readFileSync(this.configPath, "utf-8");
8203
+ const content = fs16.readFileSync(this.configPath, "utf-8");
7956
8204
  return JSON.parse(content);
7957
8205
  } catch (error) {
7958
8206
  if (error instanceof SyntaxError) {
@@ -7966,11 +8214,11 @@ var WorktreeManager = class _WorktreeManager {
7966
8214
  }
7967
8215
  writeConfig(config) {
7968
8216
  try {
7969
- const dir = path16.dirname(this.configPath);
7970
- if (!fs15.existsSync(dir)) {
7971
- fs15.mkdirSync(dir, { recursive: true });
8217
+ const dir = path17.dirname(this.configPath);
8218
+ if (!fs16.existsSync(dir)) {
8219
+ fs16.mkdirSync(dir, { recursive: true });
7972
8220
  }
7973
- fs15.writeFileSync(this.configPath, JSON.stringify(config, null, 2), "utf-8");
8221
+ fs16.writeFileSync(this.configPath, JSON.stringify(config, null, 2), "utf-8");
7974
8222
  } catch (error) {
7975
8223
  console.error("[WorktreeManager] Failed to write config:", error);
7976
8224
  throw error;
@@ -8051,14 +8299,14 @@ var WorktreeManager = class _WorktreeManager {
8051
8299
  }
8052
8300
  try {
8053
8301
  for (const file of files) {
8054
- const srcPath = path16.join(mainWorktree.worktreePath, file);
8055
- const destPath = path16.join(worktree.worktreePath, file);
8056
- if (fs15.existsSync(srcPath)) {
8057
- const destDir = path16.dirname(destPath);
8058
- if (!fs15.existsSync(destDir)) {
8059
- fs15.mkdirSync(destDir, { recursive: true });
8060
- }
8061
- fs15.copyFileSync(srcPath, destPath);
8302
+ const srcPath = path17.join(mainWorktree.worktreePath, file);
8303
+ const destPath = path17.join(worktree.worktreePath, file);
8304
+ if (fs16.existsSync(srcPath)) {
8305
+ const destDir = path17.dirname(destPath);
8306
+ if (!fs16.existsSync(destDir)) {
8307
+ fs16.mkdirSync(destDir, { recursive: true });
8308
+ }
8309
+ fs16.copyFileSync(srcPath, destPath);
8062
8310
  console.log(`[WorktreeManager] EP964: Copied ${file} to ${moduleUid} (deprecated)`);
8063
8311
  } else {
8064
8312
  console.log(`[WorktreeManager] EP964: Skipped ${file} (not found in main)`);
@@ -8089,8 +8337,8 @@ var WorktreeManager = class _WorktreeManager {
8089
8337
  console.log(`[WorktreeManager] EP959: Timeout: ${TIMEOUT_MINUTES} minutes`);
8090
8338
  console.log(`[WorktreeManager] EP959: Script: ${scriptPreview}`);
8091
8339
  try {
8092
- const { execSync: execSync9 } = require("child_process");
8093
- execSync9(script, {
8340
+ const { execSync: execSync10 } = require("child_process");
8341
+ execSync10(script, {
8094
8342
  cwd: worktree.worktreePath,
8095
8343
  stdio: "inherit",
8096
8344
  timeout: TIMEOUT_MINUTES * 60 * 1e3,
@@ -8124,8 +8372,8 @@ var WorktreeManager = class _WorktreeManager {
8124
8372
  console.log(`[WorktreeManager] EP959: Timeout: ${TIMEOUT_MINUTES} minutes`);
8125
8373
  console.log(`[WorktreeManager] EP959: Script: ${scriptPreview}`);
8126
8374
  try {
8127
- const { execSync: execSync9 } = require("child_process");
8128
- execSync9(script, {
8375
+ const { execSync: execSync10 } = require("child_process");
8376
+ execSync10(script, {
8129
8377
  cwd: worktree.worktreePath,
8130
8378
  stdio: "inherit",
8131
8379
  timeout: TIMEOUT_MINUTES * 60 * 1e3,
@@ -8141,7 +8389,7 @@ var WorktreeManager = class _WorktreeManager {
8141
8389
  }
8142
8390
  };
8143
8391
  function getEpisodaRoot() {
8144
- return process.env.EPISODA_ROOT || path16.join(require("os").homedir(), "episoda");
8392
+ return process.env.EPISODA_ROOT || path17.join(require("os").homedir(), "episoda");
8145
8393
  }
8146
8394
  async function isWorktreeProject(projectRoot) {
8147
8395
  const debug = process.env.EPISODA_DEBUG === "1" || process.env.GIT_CREDENTIAL_EPISODA_DEBUG === "1";
@@ -8156,7 +8404,7 @@ async function isWorktreeProject(projectRoot) {
8156
8404
  return result;
8157
8405
  }
8158
8406
  async function findProjectRoot(startPath) {
8159
- let current = path16.resolve(startPath);
8407
+ let current = path17.resolve(startPath);
8160
8408
  const episodaRoot = getEpisodaRoot();
8161
8409
  const debug = process.env.EPISODA_DEBUG === "1" || process.env.GIT_CREDENTIAL_EPISODA_DEBUG === "1";
8162
8410
  if (debug) {
@@ -8169,14 +8417,14 @@ async function findProjectRoot(startPath) {
8169
8417
  return null;
8170
8418
  }
8171
8419
  for (let i = 0; i < 10; i++) {
8172
- const bareDir = path16.join(current, ".bare");
8173
- const episodaDir = path16.join(current, ".episoda");
8420
+ const bareDir = path17.join(current, ".bare");
8421
+ const episodaDir = path17.join(current, ".episoda");
8174
8422
  if (debug) {
8175
- const bareExists = fs15.existsSync(bareDir);
8176
- const episodaExists = fs15.existsSync(episodaDir);
8423
+ const bareExists = fs16.existsSync(bareDir);
8424
+ const episodaExists = fs16.existsSync(episodaDir);
8177
8425
  console.log(`[WorktreeManager] findProjectRoot: checking ${current} (.bare=${bareExists}, .episoda=${episodaExists})`);
8178
8426
  }
8179
- if (fs15.existsSync(bareDir) && fs15.existsSync(episodaDir)) {
8427
+ if (fs16.existsSync(bareDir) && fs16.existsSync(episodaDir)) {
8180
8428
  if (await isWorktreeProject(current)) {
8181
8429
  if (debug) {
8182
8430
  console.log(`[WorktreeManager] findProjectRoot: found valid project at ${current}`);
@@ -8184,7 +8432,7 @@ async function findProjectRoot(startPath) {
8184
8432
  return current;
8185
8433
  }
8186
8434
  }
8187
- const parent = path16.dirname(current);
8435
+ const parent = path17.dirname(current);
8188
8436
  if (parent === current) {
8189
8437
  break;
8190
8438
  }
@@ -8197,19 +8445,19 @@ async function findProjectRoot(startPath) {
8197
8445
  }
8198
8446
 
8199
8447
  // src/utils/worktree.ts
8200
- var path17 = __toESM(require("path"));
8201
- var fs16 = __toESM(require("fs"));
8448
+ var path18 = __toESM(require("path"));
8449
+ var fs17 = __toESM(require("fs"));
8202
8450
  var os7 = __toESM(require("os"));
8203
8451
  var import_core11 = __toESM(require_dist());
8204
8452
  function getEpisodaRoot2() {
8205
- return process.env.EPISODA_ROOT || path17.join(os7.homedir(), "episoda");
8453
+ return process.env.EPISODA_ROOT || path18.join(os7.homedir(), "episoda");
8206
8454
  }
8207
8455
  function getWorktreeInfo(moduleUid, workspaceSlug, projectSlug) {
8208
8456
  const root = getEpisodaRoot2();
8209
- const worktreePath = path17.join(root, workspaceSlug, projectSlug, moduleUid);
8457
+ const worktreePath = path18.join(root, workspaceSlug, projectSlug, moduleUid);
8210
8458
  return {
8211
8459
  path: worktreePath,
8212
- exists: fs16.existsSync(worktreePath),
8460
+ exists: fs17.existsSync(worktreePath),
8213
8461
  moduleUid
8214
8462
  };
8215
8463
  }
@@ -8223,61 +8471,61 @@ async function getWorktreeInfoForModule(moduleUid) {
8223
8471
  }
8224
8472
 
8225
8473
  // src/framework-detector.ts
8226
- var fs17 = __toESM(require("fs"));
8227
- var path18 = __toESM(require("path"));
8474
+ var fs18 = __toESM(require("fs"));
8475
+ var path19 = __toESM(require("path"));
8228
8476
  function getInstallCommand(cwd) {
8229
- if (fs17.existsSync(path18.join(cwd, "bun.lockb"))) {
8477
+ if (fs18.existsSync(path19.join(cwd, "bun.lockb"))) {
8230
8478
  return {
8231
8479
  command: ["bun", "install"],
8232
8480
  description: "Installing dependencies with bun",
8233
8481
  detectedFrom: "bun.lockb"
8234
8482
  };
8235
8483
  }
8236
- if (fs17.existsSync(path18.join(cwd, "pnpm-lock.yaml"))) {
8484
+ if (fs18.existsSync(path19.join(cwd, "pnpm-lock.yaml"))) {
8237
8485
  return {
8238
8486
  command: ["pnpm", "install"],
8239
8487
  description: "Installing dependencies with pnpm",
8240
8488
  detectedFrom: "pnpm-lock.yaml"
8241
8489
  };
8242
8490
  }
8243
- if (fs17.existsSync(path18.join(cwd, "yarn.lock"))) {
8491
+ if (fs18.existsSync(path19.join(cwd, "yarn.lock"))) {
8244
8492
  return {
8245
8493
  command: ["yarn", "install"],
8246
8494
  description: "Installing dependencies with yarn",
8247
8495
  detectedFrom: "yarn.lock"
8248
8496
  };
8249
8497
  }
8250
- if (fs17.existsSync(path18.join(cwd, "package-lock.json"))) {
8498
+ if (fs18.existsSync(path19.join(cwd, "package-lock.json"))) {
8251
8499
  return {
8252
8500
  command: ["npm", "ci"],
8253
8501
  description: "Installing dependencies with npm ci",
8254
8502
  detectedFrom: "package-lock.json"
8255
8503
  };
8256
8504
  }
8257
- if (fs17.existsSync(path18.join(cwd, "package.json"))) {
8505
+ if (fs18.existsSync(path19.join(cwd, "package.json"))) {
8258
8506
  return {
8259
8507
  command: ["npm", "install"],
8260
8508
  description: "Installing dependencies with npm",
8261
8509
  detectedFrom: "package.json"
8262
8510
  };
8263
8511
  }
8264
- if (fs17.existsSync(path18.join(cwd, "Pipfile.lock")) || fs17.existsSync(path18.join(cwd, "Pipfile"))) {
8512
+ if (fs18.existsSync(path19.join(cwd, "Pipfile.lock")) || fs18.existsSync(path19.join(cwd, "Pipfile"))) {
8265
8513
  return {
8266
8514
  command: ["pipenv", "install"],
8267
8515
  description: "Installing dependencies with pipenv",
8268
- detectedFrom: fs17.existsSync(path18.join(cwd, "Pipfile.lock")) ? "Pipfile.lock" : "Pipfile"
8516
+ detectedFrom: fs18.existsSync(path19.join(cwd, "Pipfile.lock")) ? "Pipfile.lock" : "Pipfile"
8269
8517
  };
8270
8518
  }
8271
- if (fs17.existsSync(path18.join(cwd, "poetry.lock"))) {
8519
+ if (fs18.existsSync(path19.join(cwd, "poetry.lock"))) {
8272
8520
  return {
8273
8521
  command: ["poetry", "install"],
8274
8522
  description: "Installing dependencies with poetry",
8275
8523
  detectedFrom: "poetry.lock"
8276
8524
  };
8277
8525
  }
8278
- if (fs17.existsSync(path18.join(cwd, "pyproject.toml"))) {
8279
- const pyprojectPath = path18.join(cwd, "pyproject.toml");
8280
- const content = fs17.readFileSync(pyprojectPath, "utf-8");
8526
+ if (fs18.existsSync(path19.join(cwd, "pyproject.toml"))) {
8527
+ const pyprojectPath = path19.join(cwd, "pyproject.toml");
8528
+ const content = fs18.readFileSync(pyprojectPath, "utf-8");
8281
8529
  if (content.includes("[tool.poetry]")) {
8282
8530
  return {
8283
8531
  command: ["poetry", "install"],
@@ -8286,41 +8534,41 @@ function getInstallCommand(cwd) {
8286
8534
  };
8287
8535
  }
8288
8536
  }
8289
- if (fs17.existsSync(path18.join(cwd, "requirements.txt"))) {
8537
+ if (fs18.existsSync(path19.join(cwd, "requirements.txt"))) {
8290
8538
  return {
8291
8539
  command: ["pip", "install", "-r", "requirements.txt"],
8292
8540
  description: "Installing dependencies with pip",
8293
8541
  detectedFrom: "requirements.txt"
8294
8542
  };
8295
8543
  }
8296
- if (fs17.existsSync(path18.join(cwd, "Gemfile.lock")) || fs17.existsSync(path18.join(cwd, "Gemfile"))) {
8544
+ if (fs18.existsSync(path19.join(cwd, "Gemfile.lock")) || fs18.existsSync(path19.join(cwd, "Gemfile"))) {
8297
8545
  return {
8298
8546
  command: ["bundle", "install"],
8299
8547
  description: "Installing dependencies with bundler",
8300
- detectedFrom: fs17.existsSync(path18.join(cwd, "Gemfile.lock")) ? "Gemfile.lock" : "Gemfile"
8548
+ detectedFrom: fs18.existsSync(path19.join(cwd, "Gemfile.lock")) ? "Gemfile.lock" : "Gemfile"
8301
8549
  };
8302
8550
  }
8303
- if (fs17.existsSync(path18.join(cwd, "go.sum")) || fs17.existsSync(path18.join(cwd, "go.mod"))) {
8551
+ if (fs18.existsSync(path19.join(cwd, "go.sum")) || fs18.existsSync(path19.join(cwd, "go.mod"))) {
8304
8552
  return {
8305
8553
  command: ["go", "mod", "download"],
8306
8554
  description: "Downloading Go modules",
8307
- detectedFrom: fs17.existsSync(path18.join(cwd, "go.sum")) ? "go.sum" : "go.mod"
8555
+ detectedFrom: fs18.existsSync(path19.join(cwd, "go.sum")) ? "go.sum" : "go.mod"
8308
8556
  };
8309
8557
  }
8310
- if (fs17.existsSync(path18.join(cwd, "Cargo.lock")) || fs17.existsSync(path18.join(cwd, "Cargo.toml"))) {
8558
+ if (fs18.existsSync(path19.join(cwd, "Cargo.lock")) || fs18.existsSync(path19.join(cwd, "Cargo.toml"))) {
8311
8559
  return {
8312
8560
  command: ["cargo", "build"],
8313
8561
  description: "Building Rust project (downloads dependencies)",
8314
- detectedFrom: fs17.existsSync(path18.join(cwd, "Cargo.lock")) ? "Cargo.lock" : "Cargo.toml"
8562
+ detectedFrom: fs18.existsSync(path19.join(cwd, "Cargo.lock")) ? "Cargo.lock" : "Cargo.toml"
8315
8563
  };
8316
8564
  }
8317
8565
  return null;
8318
8566
  }
8319
8567
 
8320
8568
  // src/daemon/daemon-process.ts
8321
- var fs18 = __toESM(require("fs"));
8569
+ var fs19 = __toESM(require("fs"));
8322
8570
  var os8 = __toESM(require("os"));
8323
- var path19 = __toESM(require("path"));
8571
+ var path20 = __toESM(require("path"));
8324
8572
  var packageJson = require_package();
8325
8573
  async function ensureValidToken(config, bufferMs = 5 * 60 * 1e3) {
8326
8574
  const now = Date.now();
@@ -8834,7 +9082,7 @@ var Daemon = class _Daemon {
8834
9082
  client.updateActivity();
8835
9083
  try {
8836
9084
  const gitCmd = message.command;
8837
- const bareRepoPath = path19.join(projectPath, ".bare");
9085
+ const bareRepoPath = path20.join(projectPath, ".bare");
8838
9086
  const cwd = gitCmd.worktreePath || bareRepoPath;
8839
9087
  if (gitCmd.worktreePath) {
8840
9088
  console.log(`[Daemon] Routing command to worktree: ${gitCmd.worktreePath}`);
@@ -9108,6 +9356,8 @@ var Daemon = class _Daemon {
9108
9356
  moduleId: cmd.moduleId,
9109
9357
  moduleUid: cmd.moduleUid,
9110
9358
  projectPath: agentWorkingDir,
9359
+ provider: cmd.provider || "claude",
9360
+ // EP1133: Multi-provider support
9111
9361
  message: cmd.message,
9112
9362
  credentials: cmd.credentials,
9113
9363
  systemPrompt: cmd.systemPrompt,
@@ -9125,7 +9375,9 @@ var Daemon = class _Daemon {
9125
9375
  sessionId: cmd.sessionId,
9126
9376
  message: cmd.message,
9127
9377
  isFirstMessage: false,
9378
+ agentSessionId: cmd.agentSessionId || cmd.claudeSessionId,
9128
9379
  claudeSessionId: cmd.claudeSessionId,
9380
+ // Backward compat
9129
9381
  ...callbacks
9130
9382
  });
9131
9383
  result = {
@@ -9359,8 +9611,8 @@ var Daemon = class _Daemon {
9359
9611
  let daemonPid;
9360
9612
  try {
9361
9613
  const pidPath = getPidFilePath();
9362
- if (fs18.existsSync(pidPath)) {
9363
- const pidStr = fs18.readFileSync(pidPath, "utf-8").trim();
9614
+ if (fs19.existsSync(pidPath)) {
9615
+ const pidStr = fs19.readFileSync(pidPath, "utf-8").trim();
9364
9616
  daemonPid = parseInt(pidStr, 10);
9365
9617
  }
9366
9618
  } catch (pidError) {
@@ -9441,28 +9693,28 @@ var Daemon = class _Daemon {
9441
9693
  * - workDir: The directory to run git commands in (cwd)
9442
9694
  */
9443
9695
  getGitDirs(projectPath) {
9444
- const bareDir = path19.join(projectPath, ".bare");
9445
- const gitPath = path19.join(projectPath, ".git");
9446
- if (fs18.existsSync(bareDir) && fs18.statSync(bareDir).isDirectory()) {
9696
+ const bareDir = path20.join(projectPath, ".bare");
9697
+ const gitPath = path20.join(projectPath, ".git");
9698
+ if (fs19.existsSync(bareDir) && fs19.statSync(bareDir).isDirectory()) {
9447
9699
  return { gitDir: bareDir, workDir: projectPath };
9448
9700
  }
9449
- if (fs18.existsSync(gitPath) && fs18.statSync(gitPath).isDirectory()) {
9701
+ if (fs19.existsSync(gitPath) && fs19.statSync(gitPath).isDirectory()) {
9450
9702
  return { gitDir: null, workDir: projectPath };
9451
9703
  }
9452
- if (fs18.existsSync(gitPath) && fs18.statSync(gitPath).isFile()) {
9704
+ if (fs19.existsSync(gitPath) && fs19.statSync(gitPath).isFile()) {
9453
9705
  return { gitDir: null, workDir: projectPath };
9454
9706
  }
9455
- const entries = fs18.readdirSync(projectPath, { withFileTypes: true });
9707
+ const entries = fs19.readdirSync(projectPath, { withFileTypes: true });
9456
9708
  for (const entry of entries) {
9457
9709
  if (entry.isDirectory() && entry.name.startsWith("EP")) {
9458
- const worktreePath = path19.join(projectPath, entry.name);
9459
- const worktreeGit = path19.join(worktreePath, ".git");
9460
- if (fs18.existsSync(worktreeGit)) {
9710
+ const worktreePath = path20.join(projectPath, entry.name);
9711
+ const worktreeGit = path20.join(worktreePath, ".git");
9712
+ if (fs19.existsSync(worktreeGit)) {
9461
9713
  return { gitDir: null, workDir: worktreePath };
9462
9714
  }
9463
9715
  }
9464
9716
  }
9465
- if (fs18.existsSync(bareDir)) {
9717
+ if (fs19.existsSync(bareDir)) {
9466
9718
  return { gitDir: bareDir, workDir: projectPath };
9467
9719
  }
9468
9720
  return { gitDir: null, workDir: projectPath };
@@ -9480,31 +9732,31 @@ var Daemon = class _Daemon {
9480
9732
  */
9481
9733
  async configureGitUser(projectPath, userId, workspaceId, machineId, projectId, machineUuid) {
9482
9734
  try {
9483
- const { execSync: execSync9 } = await import("child_process");
9735
+ const { execSync: execSync10 } = await import("child_process");
9484
9736
  const { gitDir, workDir } = this.getGitDirs(projectPath);
9485
9737
  const gitCmd = gitDir ? `git --git-dir="${gitDir}"` : "git";
9486
- execSync9(`${gitCmd} config episoda.userId ${userId}`, {
9738
+ execSync10(`${gitCmd} config episoda.userId ${userId}`, {
9487
9739
  cwd: workDir,
9488
9740
  encoding: "utf8",
9489
9741
  stdio: "pipe"
9490
9742
  });
9491
- execSync9(`${gitCmd} config episoda.workspaceId ${workspaceId}`, {
9743
+ execSync10(`${gitCmd} config episoda.workspaceId ${workspaceId}`, {
9492
9744
  cwd: workDir,
9493
9745
  encoding: "utf8",
9494
9746
  stdio: "pipe"
9495
9747
  });
9496
- execSync9(`${gitCmd} config episoda.machineId ${machineId}`, {
9748
+ execSync10(`${gitCmd} config episoda.machineId ${machineId}`, {
9497
9749
  cwd: workDir,
9498
9750
  encoding: "utf8",
9499
9751
  stdio: "pipe"
9500
9752
  });
9501
- execSync9(`${gitCmd} config episoda.projectId ${projectId}`, {
9753
+ execSync10(`${gitCmd} config episoda.projectId ${projectId}`, {
9502
9754
  cwd: workDir,
9503
9755
  encoding: "utf8",
9504
9756
  stdio: "pipe"
9505
9757
  });
9506
9758
  if (machineUuid) {
9507
- execSync9(`${gitCmd} config episoda.deviceId ${machineUuid}`, {
9759
+ execSync10(`${gitCmd} config episoda.deviceId ${machineUuid}`, {
9508
9760
  cwd: workDir,
9509
9761
  encoding: "utf8",
9510
9762
  stdio: "pipe"
@@ -9526,24 +9778,24 @@ var Daemon = class _Daemon {
9526
9778
  async installGitHooks(projectPath) {
9527
9779
  const hooks = ["post-checkout", "pre-commit", "post-commit"];
9528
9780
  let hooksDir;
9529
- const bareHooksDir = path19.join(projectPath, ".bare", "hooks");
9530
- const gitHooksDir = path19.join(projectPath, ".git", "hooks");
9531
- if (fs18.existsSync(bareHooksDir)) {
9781
+ const bareHooksDir = path20.join(projectPath, ".bare", "hooks");
9782
+ const gitHooksDir = path20.join(projectPath, ".git", "hooks");
9783
+ if (fs19.existsSync(bareHooksDir)) {
9532
9784
  hooksDir = bareHooksDir;
9533
- } else if (fs18.existsSync(gitHooksDir) && fs18.statSync(path19.join(projectPath, ".git")).isDirectory()) {
9785
+ } else if (fs19.existsSync(gitHooksDir) && fs19.statSync(path20.join(projectPath, ".git")).isDirectory()) {
9534
9786
  hooksDir = gitHooksDir;
9535
9787
  } else {
9536
- const parentBareHooks = path19.join(projectPath, "..", ".bare", "hooks");
9537
- if (fs18.existsSync(parentBareHooks)) {
9788
+ const parentBareHooks = path20.join(projectPath, "..", ".bare", "hooks");
9789
+ if (fs19.existsSync(parentBareHooks)) {
9538
9790
  hooksDir = parentBareHooks;
9539
9791
  } else {
9540
9792
  console.warn(`[Daemon] Hooks directory not found for: ${projectPath}`);
9541
9793
  return;
9542
9794
  }
9543
9795
  }
9544
- if (!fs18.existsSync(hooksDir)) {
9796
+ if (!fs19.existsSync(hooksDir)) {
9545
9797
  try {
9546
- fs18.mkdirSync(hooksDir, { recursive: true });
9798
+ fs19.mkdirSync(hooksDir, { recursive: true });
9547
9799
  } catch (error) {
9548
9800
  console.warn(`[Daemon] Hooks directory not found and could not create: ${hooksDir}`);
9549
9801
  return;
@@ -9551,20 +9803,20 @@ var Daemon = class _Daemon {
9551
9803
  }
9552
9804
  for (const hookName of hooks) {
9553
9805
  try {
9554
- const hookPath = path19.join(hooksDir, hookName);
9555
- const bundledHookPath = path19.join(__dirname, "..", "hooks", hookName);
9556
- if (!fs18.existsSync(bundledHookPath)) {
9806
+ const hookPath = path20.join(hooksDir, hookName);
9807
+ const bundledHookPath = path20.join(__dirname, "..", "hooks", hookName);
9808
+ if (!fs19.existsSync(bundledHookPath)) {
9557
9809
  console.warn(`[Daemon] Bundled hook not found: ${bundledHookPath}`);
9558
9810
  continue;
9559
9811
  }
9560
- const hookContent = fs18.readFileSync(bundledHookPath, "utf-8");
9561
- if (fs18.existsSync(hookPath)) {
9562
- const existingContent = fs18.readFileSync(hookPath, "utf-8");
9812
+ const hookContent = fs19.readFileSync(bundledHookPath, "utf-8");
9813
+ if (fs19.existsSync(hookPath)) {
9814
+ const existingContent = fs19.readFileSync(hookPath, "utf-8");
9563
9815
  if (existingContent === hookContent) {
9564
9816
  continue;
9565
9817
  }
9566
9818
  }
9567
- fs18.writeFileSync(hookPath, hookContent, { mode: 493 });
9819
+ fs19.writeFileSync(hookPath, hookContent, { mode: 493 });
9568
9820
  console.log(`[Daemon] Installed git hook: ${hookName}`);
9569
9821
  } catch (error) {
9570
9822
  console.warn(`[Daemon] Failed to install ${hookName} hook:`, error instanceof Error ? error.message : error);
@@ -10031,8 +10283,8 @@ var Daemon = class _Daemon {
10031
10283
  console.log(`[Daemon] EP1002: ${installCmd.description} (detected from ${installCmd.detectedFrom})`);
10032
10284
  console.log(`[Daemon] EP1002: Running: ${installCmd.command.join(" ")}`);
10033
10285
  try {
10034
- const { execSync: execSync9 } = await import("child_process");
10035
- execSync9(installCmd.command.join(" "), {
10286
+ const { execSync: execSync10 } = await import("child_process");
10287
+ execSync10(installCmd.command.join(" "), {
10036
10288
  cwd: worktreePath,
10037
10289
  stdio: "inherit",
10038
10290
  timeout: 10 * 60 * 1e3,
@@ -10085,8 +10337,8 @@ var Daemon = class _Daemon {
10085
10337
  console.log(`[Daemon] EP986: ${installCmd.description} (detected from ${installCmd.detectedFrom})`);
10086
10338
  console.log(`[Daemon] EP986: Running: ${installCmd.command.join(" ")}`);
10087
10339
  try {
10088
- const { execSync: execSync9 } = await import("child_process");
10089
- execSync9(installCmd.command.join(" "), {
10340
+ const { execSync: execSync10 } = await import("child_process");
10341
+ execSync10(installCmd.command.join(" "), {
10090
10342
  cwd: worktreePath,
10091
10343
  stdio: "inherit",
10092
10344
  timeout: 10 * 60 * 1e3,
@@ -10670,8 +10922,8 @@ var Daemon = class _Daemon {
10670
10922
  await this.shutdown();
10671
10923
  try {
10672
10924
  const pidPath = getPidFilePath();
10673
- if (fs18.existsSync(pidPath)) {
10674
- fs18.unlinkSync(pidPath);
10925
+ if (fs19.existsSync(pidPath)) {
10926
+ fs19.unlinkSync(pidPath);
10675
10927
  console.log("[Daemon] PID file cleaned up");
10676
10928
  }
10677
10929
  } catch (error) {