@episoda/cli 0.2.158 → 0.2.160

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.
@@ -1653,10 +1653,6 @@ var require_git_executor = __commonJS({
1653
1653
  };
1654
1654
  } catch {
1655
1655
  }
1656
- try {
1657
- await this.runGitCommand(["fetch", "--all", "--prune"], cwd, options);
1658
- } catch {
1659
- }
1660
1656
  const args = ["worktree", "add"];
1661
1657
  if (command.detach) {
1662
1658
  args.push("--detach", command.path);
@@ -2913,7 +2909,7 @@ var require_package = __commonJS({
2913
2909
  "package.json"(exports2, module2) {
2914
2910
  module2.exports = {
2915
2911
  name: "@episoda/cli",
2916
- version: "0.2.158",
2912
+ version: "0.2.160",
2917
2913
  description: "CLI tool for Episoda local development workflow orchestration",
2918
2914
  main: "dist/index.js",
2919
2915
  types: "dist/index.d.ts",
@@ -6414,6 +6410,24 @@ var path10 = __toESM(require("path"));
6414
6410
  var fs9 = __toESM(require("fs"));
6415
6411
  var os4 = __toESM(require("os"));
6416
6412
  var import_core8 = __toESM(require_dist());
6413
+
6414
+ // src/utils/github-token.ts
6415
+ var INVALID_GITHUB_TOKEN_LITERALS = /* @__PURE__ */ new Set([
6416
+ "${GITHUB_PERSONAL_ACCESS_TOKEN}",
6417
+ "undefined",
6418
+ "null",
6419
+ '""',
6420
+ "''"
6421
+ ]);
6422
+ function sanitizeGithubToken(token) {
6423
+ if (token === void 0) return "";
6424
+ const trimmed = token.trim();
6425
+ if (!trimmed) return "";
6426
+ if (INVALID_GITHUB_TOKEN_LITERALS.has(trimmed)) return "";
6427
+ return trimmed;
6428
+ }
6429
+
6430
+ // src/agent/mcp-server-configurator.ts
6417
6431
  var McpServerConfigurator = class {
6418
6432
  // ---------------------------------------------------------------------------
6419
6433
  // MCP Auth Resolution
@@ -6483,10 +6497,10 @@ var McpServerConfigurator = class {
6483
6497
  }
6484
6498
  servers.push({
6485
6499
  name: "github",
6486
- command: "npx -y @modelcontextprotocol/server-github"
6500
+ command: "bash scripts/github-mcp-server.sh"
6487
6501
  });
6488
- if (!session.credentials.githubToken) {
6489
- console.warn("[McpServerConfigurator] EP1296: GitHub MCP registered without token (githubToken missing)");
6502
+ if (!sanitizeGithubToken(session.credentials.githubToken)) {
6503
+ console.warn('[McpServerConfigurator] EP1377: GitHub MCP registered without token \u2014 GitHub tools may fail with "Requires authentication"');
6490
6504
  } else {
6491
6505
  console.log("[McpServerConfigurator] EP1251: GitHub MCP server registered");
6492
6506
  }
@@ -7373,9 +7387,10 @@ ${message}`;
7373
7387
  if (sessionToken) {
7374
7388
  episodaMcpEnv.EPISODA_SESSION_TOKEN = sessionToken;
7375
7389
  }
7390
+ const githubToken = sanitizeGithubToken(session.credentials.githubToken);
7376
7391
  const githubMcpEnv = {
7377
7392
  ...baseEnv,
7378
- GITHUB_PERSONAL_ACCESS_TOKEN: session.credentials.githubToken || ""
7393
+ GITHUB_PERSONAL_ACCESS_TOKEN: githubToken
7379
7394
  };
7380
7395
  for (const mcpServer of mcpServersToRegister) {
7381
7396
  const parts = mcpServer.command.split(" ");
@@ -7510,10 +7525,7 @@ ${message}`;
7510
7525
  const args2 = parts.slice(1);
7511
7526
  let env;
7512
7527
  if (server.name === "github") {
7513
- env = {
7514
- ...baseEnv,
7515
- GITHUB_PERSONAL_ACCESS_TOKEN: session.credentials.githubToken || ""
7516
- };
7528
+ env = { ...baseEnv };
7517
7529
  } else {
7518
7530
  env = {
7519
7531
  ...baseEnv,
@@ -7633,9 +7645,10 @@ ${message}`;
7633
7645
  console.warn("[AgentManager] EP1287: No session token available for MCP servers");
7634
7646
  }
7635
7647
  }
7636
- if (session.credentials.githubToken) {
7637
- envVars.GITHUB_PERSONAL_ACCESS_TOKEN = session.credentials.githubToken;
7638
- console.log("[AgentManager] EP1251: Set GITHUB_PERSONAL_ACCESS_TOKEN for GitHub MCP");
7648
+ const processGithubToken = sanitizeGithubToken(session.credentials.githubToken);
7649
+ if (processGithubToken) {
7650
+ envVars.GITHUB_PERSONAL_ACCESS_TOKEN = processGithubToken;
7651
+ console.log("[AgentManager] EP1377: Set GITHUB_PERSONAL_ACCESS_TOKEN for GitHub MCP");
7639
7652
  }
7640
7653
  if (useApiKey && session.credentials.apiKey) {
7641
7654
  if (provider === "codex") {
@@ -8159,6 +8172,7 @@ var AgentCommandQueue = class {
8159
8172
  // src/daemon/worktree-manager.ts
8160
8173
  var fs11 = __toESM(require("fs"));
8161
8174
  var path12 = __toESM(require("path"));
8175
+ var import_child_process11 = require("child_process");
8162
8176
  var import_core10 = __toESM(require_dist());
8163
8177
  function validateModuleUid(moduleUid) {
8164
8178
  if (!moduleUid || typeof moduleUid !== "string" || !moduleUid.trim()) {
@@ -8175,6 +8189,38 @@ function validateModuleUid(moduleUid) {
8175
8189
  }
8176
8190
  return true;
8177
8191
  }
8192
+ function isValidDefaultBranchName(name) {
8193
+ if (!name || typeof name !== "string") return false;
8194
+ const trimmed = name.trim();
8195
+ if (trimmed !== name) return false;
8196
+ if (name.length > 255) return false;
8197
+ if (name.startsWith("-")) return false;
8198
+ if (name.startsWith("/")) return false;
8199
+ if (name.endsWith("/")) return false;
8200
+ if (name.endsWith(".")) return false;
8201
+ if (name.endsWith(".lock")) return false;
8202
+ if (name.includes("..")) return false;
8203
+ if (name.includes("@{")) return false;
8204
+ if (name.includes("//")) return false;
8205
+ if (name.includes("\\")) return false;
8206
+ if (/[ ~^:?*\[\]\s]/.test(name)) return false;
8207
+ if (!/^[A-Za-z0-9][A-Za-z0-9._/-]*$/.test(name)) return false;
8208
+ return true;
8209
+ }
8210
+ function runGit(args, cwd, timeoutMs) {
8211
+ const res = (0, import_child_process11.spawnSync)("git", args, {
8212
+ cwd,
8213
+ encoding: "utf-8",
8214
+ timeout: timeoutMs,
8215
+ windowsHide: true,
8216
+ shell: false
8217
+ });
8218
+ return {
8219
+ success: res.status === 0,
8220
+ stdout: (res.stdout || "").toString(),
8221
+ stderr: (res.stderr || "").toString()
8222
+ };
8223
+ }
8178
8224
  var WorktreeManager = class _WorktreeManager {
8179
8225
  constructor(projectRoot) {
8180
8226
  // ============================================================
@@ -8232,22 +8278,24 @@ var WorktreeManager = class _WorktreeManager {
8232
8278
  */
8233
8279
  async ensureFetchRefspecConfigured() {
8234
8280
  try {
8235
- const { execSync: execSync10 } = require("child_process");
8236
8281
  let fetchRefspec = null;
8237
8282
  try {
8238
- fetchRefspec = execSync10("git config --get remote.origin.fetch", {
8239
- cwd: this.bareRepoPath,
8240
- encoding: "utf-8",
8241
- timeout: 5e3
8242
- }).trim();
8283
+ const res = runGit(["config", "--get", "remote.origin.fetch"], this.bareRepoPath, 5e3);
8284
+ if (res.success) {
8285
+ fetchRefspec = res.stdout.trim();
8286
+ }
8243
8287
  } catch {
8244
8288
  }
8245
8289
  if (!fetchRefspec) {
8246
8290
  console.log("[WorktreeManager] EP1014: Configuring missing fetch refspec for bare repo");
8247
- execSync10('git config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*"', {
8248
- cwd: this.bareRepoPath,
8249
- timeout: 5e3
8250
- });
8291
+ const setRes = runGit(
8292
+ ["config", "remote.origin.fetch", "+refs/heads/*:refs/remotes/origin/*"],
8293
+ this.bareRepoPath,
8294
+ 5e3
8295
+ );
8296
+ if (!setRes.success) {
8297
+ throw new Error(setRes.stderr || "Failed to configure fetch refspec");
8298
+ }
8251
8299
  console.log("[WorktreeManager] EP1014: Fetch refspec configured successfully");
8252
8300
  }
8253
8301
  } catch (error) {
@@ -8280,11 +8328,44 @@ var WorktreeManager = class _WorktreeManager {
8280
8328
  manager.writeConfig(config);
8281
8329
  return manager;
8282
8330
  }
8331
+ /**
8332
+ * EP1373: Resolve the default branch name using a 3-level fallback:
8333
+ * 1. Explicit defaultBranch parameter (from project GitHub config)
8334
+ * 2. Git-derived: refs/remotes/origin/HEAD symbolic-ref target
8335
+ * 3. Final fallback: 'main' (with warning)
8336
+ */
8337
+ async resolveDefaultBranch(explicitDefault) {
8338
+ if (explicitDefault) {
8339
+ if (isValidDefaultBranchName(explicitDefault)) {
8340
+ return explicitDefault;
8341
+ }
8342
+ console.warn(`[WorktreeManager] EP1373: Invalid defaultBranch provided ("${explicitDefault}"), ignoring`);
8343
+ }
8344
+ try {
8345
+ const res = runGit(["symbolic-ref", "refs/remotes/origin/HEAD"], this.bareRepoPath, 5e3);
8346
+ if (!res.success) {
8347
+ throw new Error(res.stderr || "symbolic-ref failed");
8348
+ }
8349
+ const symref = res.stdout.trim();
8350
+ const match = symref.match(/^refs\/remotes\/origin\/(.+)$/);
8351
+ if (match && match[1]) {
8352
+ const derived = match[1];
8353
+ if (isValidDefaultBranchName(derived)) {
8354
+ return derived;
8355
+ }
8356
+ console.warn(`[WorktreeManager] EP1373: Derived default branch from origin/HEAD is invalid ("${derived}"), ignoring`);
8357
+ }
8358
+ } catch {
8359
+ }
8360
+ console.warn('[WorktreeManager] EP1373: Could not resolve default branch, falling back to "main"');
8361
+ return "main";
8362
+ }
8283
8363
  /**
8284
8364
  * Create a worktree for a module
8285
8365
  * The entire operation is locked to prevent race conditions
8366
+ * EP1373: Added defaultBranch parameter for explicit default branch resolution
8286
8367
  */
8287
- async createWorktree(moduleUid, branchName, createBranch = false) {
8368
+ async createWorktree(moduleUid, branchName, createBranch = false, defaultBranch, correlationId) {
8288
8369
  if (!validateModuleUid(moduleUid)) {
8289
8370
  return {
8290
8371
  success: false,
@@ -8350,25 +8431,63 @@ var WorktreeManager = class _WorktreeManager {
8350
8431
  console.warn("[WorktreeManager] EP1265: Failed to prune worktrees (continuing):", pruneResult.output);
8351
8432
  }
8352
8433
  }
8353
- const fetchResult = await this.gitExecutor.execute({
8354
- action: "fetch",
8355
- remote: "origin",
8356
- branch: "+refs/heads/main:refs/remotes/origin/main"
8357
- }, { cwd: this.bareRepoPath });
8358
- if (!fetchResult.success && createBranch) {
8359
- console.error("[worktree-manager] Failed to fetch from origin:", fetchResult.output);
8360
- return {
8361
- success: false,
8362
- error: "Failed to fetch latest refs from origin. Cannot create worktree with stale refs."
8363
- };
8434
+ const resolvedDefault = await this.resolveDefaultBranch(defaultBranch);
8435
+ let shouldCreateBranch = createBranch;
8436
+ let startPoint;
8437
+ if (createBranch) {
8438
+ const managerFetchStartMs = Date.now();
8439
+ const fetchResult = await this.gitExecutor.execute({
8440
+ action: "fetch",
8441
+ remote: "origin",
8442
+ branch: `+refs/heads/${resolvedDefault}:refs/remotes/origin/${resolvedDefault}`
8443
+ }, { cwd: this.bareRepoPath });
8444
+ console.log(`[WorktreeManager] EP1373: manager_fetch phase=manager_fetch durationMs=${Date.now() - managerFetchStartMs} moduleUid=${moduleUid} correlationId=${correlationId || "none"} defaultBranch=${resolvedDefault} success=${fetchResult.success}`);
8445
+ if (!fetchResult.success) {
8446
+ console.error("[worktree-manager] Failed to fetch from origin:", fetchResult.output);
8447
+ return {
8448
+ success: false,
8449
+ error: "Failed to fetch latest refs from origin. Cannot create worktree with stale refs."
8450
+ };
8451
+ }
8452
+ startPoint = `origin/${resolvedDefault}`;
8453
+ } else {
8454
+ const existingBranchFetchStartMs = Date.now();
8455
+ const branchFetchResult = await this.gitExecutor.execute({
8456
+ action: "fetch",
8457
+ remote: "origin",
8458
+ branch: `+refs/heads/${branchName}:refs/remotes/origin/${branchName}`
8459
+ }, { cwd: this.bareRepoPath });
8460
+ console.log(`[WorktreeManager] EP1373: existing_branch_fetch phase=existing_branch_fetch durationMs=${Date.now() - existingBranchFetchStartMs} moduleUid=${moduleUid} correlationId=${correlationId || "none"} branch=${branchName} success=${branchFetchResult.success}`);
8461
+ const localBranchExists = runGit(
8462
+ ["show-ref", "--verify", `refs/heads/${branchName}`],
8463
+ this.bareRepoPath,
8464
+ 5e3
8465
+ ).success;
8466
+ const remoteBranchExists = runGit(
8467
+ ["show-ref", "--verify", `refs/remotes/origin/${branchName}`],
8468
+ this.bareRepoPath,
8469
+ 5e3
8470
+ ).success;
8471
+ if (!localBranchExists && remoteBranchExists) {
8472
+ shouldCreateBranch = true;
8473
+ startPoint = `origin/${branchName}`;
8474
+ console.log(`[WorktreeManager] EP1373: remote_only_branch phase=remote_only_branch moduleUid=${moduleUid} correlationId=${correlationId || "none"} branch=${branchName}`);
8475
+ } else if (!localBranchExists && !remoteBranchExists) {
8476
+ return {
8477
+ success: false,
8478
+ error: `Branch "${branchName}" not found locally or on origin`
8479
+ };
8480
+ }
8364
8481
  }
8482
+ const gitWorktreeAddStartMs = Date.now();
8365
8483
  const result = await this.gitExecutor.execute({
8366
8484
  action: "worktree_add",
8367
8485
  path: worktreePath,
8368
8486
  branch: branchName,
8369
- create: createBranch,
8370
- startPoint: createBranch ? "origin/main" : void 0
8487
+ create: shouldCreateBranch,
8488
+ startPoint
8371
8489
  }, { cwd: this.bareRepoPath });
8490
+ console.log(`[WorktreeManager] EP1373: git_worktree_add phase=git_worktree_add durationMs=${Date.now() - gitWorktreeAddStartMs} moduleUid=${moduleUid} correlationId=${correlationId || "none"} success=${result.success}`);
8372
8491
  if (!result.success) {
8373
8492
  return {
8374
8493
  success: false,
@@ -10009,7 +10128,7 @@ async function handleFileMkdir(command, projectPath) {
10009
10128
  }
10010
10129
 
10011
10130
  // src/daemon/handlers/exec-handler.ts
10012
- var import_child_process11 = require("child_process");
10131
+ var import_child_process12 = require("child_process");
10013
10132
  var DEFAULT_TIMEOUT = 3e4;
10014
10133
  var MAX_TIMEOUT = 3e5;
10015
10134
  async function handleExec(command, projectPath) {
@@ -10031,7 +10150,7 @@ async function handleExec(command, projectPath) {
10031
10150
  resolve4(result);
10032
10151
  };
10033
10152
  try {
10034
- const proc = (0, import_child_process11.spawn)(cmd, {
10153
+ const proc = (0, import_child_process12.spawn)(cmd, {
10035
10154
  shell: true,
10036
10155
  cwd,
10037
10156
  env: { ...process.env, ...env },
@@ -10095,7 +10214,7 @@ async function handleExec(command, projectPath) {
10095
10214
  var path23 = __toESM(require("path"));
10096
10215
  var fs22 = __toESM(require("fs"));
10097
10216
  var os10 = __toESM(require("os"));
10098
- var import_child_process14 = require("child_process");
10217
+ var import_child_process15 = require("child_process");
10099
10218
  var import_util2 = require("util");
10100
10219
 
10101
10220
  // src/preview/types.ts
@@ -10122,7 +10241,7 @@ var import_events3 = require("events");
10122
10241
  var import_fs = require("fs");
10123
10242
 
10124
10243
  // src/preview/dev-server-runner.ts
10125
- var import_child_process13 = require("child_process");
10244
+ var import_child_process14 = require("child_process");
10126
10245
  var http = __toESM(require("http"));
10127
10246
  var fs20 = __toESM(require("fs"));
10128
10247
  var path21 = __toESM(require("path"));
@@ -10260,7 +10379,7 @@ No cached values available as fallback.`
10260
10379
  var fs19 = __toESM(require("fs"));
10261
10380
  var path20 = __toESM(require("path"));
10262
10381
  var os9 = __toESM(require("os"));
10263
- var import_child_process12 = require("child_process");
10382
+ var import_child_process13 = require("child_process");
10264
10383
  var DEV_SERVER_REGISTRY_DIR = path20.join(os9.homedir(), ".episoda", "dev-servers");
10265
10384
  var DevServerRegistry = class {
10266
10385
  constructor() {
@@ -10415,7 +10534,7 @@ var DevServerRegistry = class {
10415
10534
  */
10416
10535
  getProcessCwd(pid) {
10417
10536
  try {
10418
- const output = (0, import_child_process12.execSync)(`lsof -p ${pid} -Fn | grep ^n | grep cwd | head -1`, {
10537
+ const output = (0, import_child_process13.execSync)(`lsof -p ${pid} -Fn | grep ^n | grep cwd | head -1`, {
10419
10538
  encoding: "utf8",
10420
10539
  timeout: 5e3
10421
10540
  }).trim();
@@ -10440,7 +10559,7 @@ var DevServerRegistry = class {
10440
10559
  findProcessesInWorktree(worktreePath) {
10441
10560
  const pids = [];
10442
10561
  try {
10443
- const output = (0, import_child_process12.execSync)(
10562
+ const output = (0, import_child_process13.execSync)(
10444
10563
  `lsof -c node -c next | grep "${worktreePath}" | awk '{print $2}' | sort -u`,
10445
10564
  { encoding: "utf8", timeout: 5e3 }
10446
10565
  ).trim();
@@ -10501,7 +10620,7 @@ var DevServerRegistry = class {
10501
10620
  */
10502
10621
  findProcessesOnPort(port) {
10503
10622
  try {
10504
- const output = (0, import_child_process12.execSync)(`lsof -ti:${port} 2>/dev/null || true`, { encoding: "utf8" }).trim();
10623
+ const output = (0, import_child_process13.execSync)(`lsof -ti:${port} 2>/dev/null || true`, { encoding: "utf8" }).trim();
10505
10624
  if (!output) {
10506
10625
  return [];
10507
10626
  }
@@ -10755,7 +10874,7 @@ var DevServerRunner = class extends import_events2.EventEmitter {
10755
10874
  */
10756
10875
  async killProcessOnPort(port) {
10757
10876
  try {
10758
- const result = (0, import_child_process13.execSync)(`lsof -ti:${port} 2>/dev/null || true`, { encoding: "utf8" }).trim();
10877
+ const result = (0, import_child_process14.execSync)(`lsof -ti:${port} 2>/dev/null || true`, { encoding: "utf8" }).trim();
10759
10878
  if (!result) {
10760
10879
  return true;
10761
10880
  }
@@ -10763,15 +10882,15 @@ var DevServerRunner = class extends import_events2.EventEmitter {
10763
10882
  console.log(`[DevServerRunner] Found ${pids.length} process(es) on port ${port}`);
10764
10883
  for (const pid of pids) {
10765
10884
  try {
10766
- (0, import_child_process13.execSync)(`kill -15 ${pid} 2>/dev/null || true`);
10885
+ (0, import_child_process14.execSync)(`kill -15 ${pid} 2>/dev/null || true`);
10767
10886
  } catch {
10768
10887
  }
10769
10888
  }
10770
10889
  await this.wait(1e3);
10771
10890
  for (const pid of pids) {
10772
10891
  try {
10773
- (0, import_child_process13.execSync)(`kill -0 ${pid} 2>/dev/null`);
10774
- (0, import_child_process13.execSync)(`kill -9 ${pid} 2>/dev/null || true`);
10892
+ (0, import_child_process14.execSync)(`kill -0 ${pid} 2>/dev/null`);
10893
+ (0, import_child_process14.execSync)(`kill -9 ${pid} 2>/dev/null || true`);
10775
10894
  } catch {
10776
10895
  }
10777
10896
  }
@@ -10820,7 +10939,7 @@ var DevServerRunner = class extends import_events2.EventEmitter {
10820
10939
  PORT: String(port),
10821
10940
  NODE_OPTIONS: enhancedNodeOptions
10822
10941
  };
10823
- const proc = (0, import_child_process13.spawn)(cmd, args, {
10942
+ const proc = (0, import_child_process14.spawn)(cmd, args, {
10824
10943
  cwd: projectPath,
10825
10944
  env: mergedEnv,
10826
10945
  stdio: ["ignore", "pipe", "pipe"],
@@ -11621,7 +11740,7 @@ async function getConfigForApi() {
11621
11740
  }
11622
11741
  return (0, import_core13.loadConfig)();
11623
11742
  }
11624
- var execAsync2 = (0, import_util2.promisify)(import_child_process14.exec);
11743
+ var execAsync2 = (0, import_util2.promisify)(import_child_process15.exec);
11625
11744
  function persistWorkspaceProjectContext(workspaceSlug, projectSlug, projectId) {
11626
11745
  if (process.env.EPISODA_MODE !== "cloud") {
11627
11746
  return;
@@ -11694,8 +11813,11 @@ async function handleWorktreeCreate(request2) {
11694
11813
  envVars,
11695
11814
  setupScript,
11696
11815
  // EP1229: detachedHead removed - planning worktrees no longer exist
11697
- moduleType
11816
+ moduleType,
11817
+ defaultBranch,
11818
+ correlationId
11698
11819
  } = request2;
11820
+ const worktreeStartMs = Date.now();
11699
11821
  console.log(`[Worktree] K1273: Creating worktree for ${moduleUid}`);
11700
11822
  console.log(`[Worktree] Project: ${projectSlug}`);
11701
11823
  console.log(`[Worktree] Branch: ${branchName} (create: ${createBranch})`);
@@ -11739,12 +11861,7 @@ async function handleWorktreeCreate(request2) {
11739
11861
  };
11740
11862
  }
11741
11863
  } else {
11742
- console.log(`[Worktree] K1273: Project exists, fetching latest...`);
11743
- try {
11744
- await execAsync2(`git -C "${bareRepoPath}" fetch origin --prune`, { env: gitEnv });
11745
- } catch (fetchError) {
11746
- console.warn(`[Worktree] K1273: Fetch failed (continuing anyway): ${fetchError.message}`);
11747
- }
11864
+ console.log(`[Worktree] EP1373: Project exists, skipping handler-level fetch (manager handles narrow fetch)`);
11748
11865
  }
11749
11866
  const manager = new WorktreeManager(projectPath);
11750
11867
  const initialized2 = await manager.initialize();
@@ -11754,7 +11871,8 @@ async function handleWorktreeCreate(request2) {
11754
11871
  error: `Failed to initialize WorktreeManager at ${projectPath}`
11755
11872
  };
11756
11873
  }
11757
- const result = await manager.createWorktree(moduleUid, branchName, createBranch);
11874
+ const worktreeAddStartMs = Date.now();
11875
+ const result = await manager.createWorktree(moduleUid, branchName, createBranch, defaultBranch, correlationId);
11758
11876
  if (!result.success) {
11759
11877
  return {
11760
11878
  success: false,
@@ -11762,6 +11880,7 @@ async function handleWorktreeCreate(request2) {
11762
11880
  };
11763
11881
  }
11764
11882
  const worktreePath = result.worktreePath;
11883
+ console.log(`[Worktree] EP1373: worktree_add phase=worktree_add durationMs=${Date.now() - worktreeAddStartMs} moduleUid=${moduleUid} correlationId=${correlationId || "none"}`);
11765
11884
  console.log(`[Worktree] EP1143: Worktree created at ${worktreePath}`);
11766
11885
  const config = await getConfigForApi();
11767
11886
  let finalStatus = "ready";
@@ -11793,6 +11912,7 @@ ${buildCmd}` : buildCmd;
11793
11912
  }
11794
11913
  }
11795
11914
  if (effectiveSetupScript) {
11915
+ const setupStartMs = Date.now();
11796
11916
  await manager.updateWorktreeStatus(moduleUid, "setup");
11797
11917
  if (config?.access_token) {
11798
11918
  await updateWorktree(config, {
@@ -11805,6 +11925,7 @@ ${buildCmd}` : buildCmd;
11805
11925
  }
11806
11926
  console.log(`[Worktree] EP1143: Running setup script...`);
11807
11927
  const scriptResult = await manager.runSetupScript(moduleUid, effectiveSetupScript);
11928
+ console.log(`[Worktree] EP1373: setup_script phase=worktree_setup durationMs=${Date.now() - setupStartMs} moduleUid=${moduleUid} correlationId=${correlationId || "none"} success=${scriptResult.success}`);
11808
11929
  if (!scriptResult.success) {
11809
11930
  console.error(`[Worktree] EP1143: Setup script failed: ${scriptResult.error}`);
11810
11931
  await manager.updateWorktreeStatus(moduleUid, "error", scriptResult.error);
@@ -11864,6 +11985,7 @@ ${buildCmd}` : buildCmd;
11864
11985
  console.error(`[Worktree] EP1143: Failed to update worktrees table: ${apiError.message}`);
11865
11986
  }
11866
11987
  }
11988
+ console.log(`[Worktree] EP1373: worktree_create_total phase=worktree_create_total durationMs=${Date.now() - worktreeStartMs} moduleUid=${moduleUid} correlationId=${correlationId || "none"} status=${finalStatus}`);
11867
11989
  console.log(`[Worktree] EP1143: Worktree ready for ${moduleUid}`);
11868
11990
  return {
11869
11991
  success: true,
@@ -12166,7 +12288,7 @@ async function handleProjectSetup(params) {
12166
12288
  }
12167
12289
 
12168
12290
  // src/utils/dev-server.ts
12169
- var import_child_process15 = require("child_process");
12291
+ var import_child_process16 = require("child_process");
12170
12292
  var import_core14 = __toESM(require_dist());
12171
12293
  var fs24 = __toESM(require("fs"));
12172
12294
  var path25 = __toESM(require("path"));
@@ -12215,7 +12337,7 @@ function writeToLog(logPath, line, isError = false) {
12215
12337
  }
12216
12338
  async function killProcessOnPort(port) {
12217
12339
  try {
12218
- const result = (0, import_child_process15.execSync)(`lsof -ti:${port} 2>/dev/null || true`, { encoding: "utf8" }).trim();
12340
+ const result = (0, import_child_process16.execSync)(`lsof -ti:${port} 2>/dev/null || true`, { encoding: "utf8" }).trim();
12219
12341
  if (!result) {
12220
12342
  console.log(`[DevServer] EP929: No process found on port ${port}`);
12221
12343
  return true;
@@ -12224,7 +12346,7 @@ async function killProcessOnPort(port) {
12224
12346
  console.log(`[DevServer] EP929: Found ${pids.length} process(es) on port ${port}: ${pids.join(", ")}`);
12225
12347
  for (const pid of pids) {
12226
12348
  try {
12227
- (0, import_child_process15.execSync)(`kill -15 ${pid} 2>/dev/null || true`, { encoding: "utf8" });
12349
+ (0, import_child_process16.execSync)(`kill -15 ${pid} 2>/dev/null || true`, { encoding: "utf8" });
12228
12350
  console.log(`[DevServer] EP929: Sent SIGTERM to PID ${pid}`);
12229
12351
  } catch {
12230
12352
  }
@@ -12232,8 +12354,8 @@ async function killProcessOnPort(port) {
12232
12354
  await new Promise((resolve4) => setTimeout(resolve4, 1e3));
12233
12355
  for (const pid of pids) {
12234
12356
  try {
12235
- (0, import_child_process15.execSync)(`kill -0 ${pid} 2>/dev/null`, { encoding: "utf8" });
12236
- (0, import_child_process15.execSync)(`kill -9 ${pid} 2>/dev/null || true`, { encoding: "utf8" });
12357
+ (0, import_child_process16.execSync)(`kill -0 ${pid} 2>/dev/null`, { encoding: "utf8" });
12358
+ (0, import_child_process16.execSync)(`kill -9 ${pid} 2>/dev/null || true`, { encoding: "utf8" });
12237
12359
  console.log(`[DevServer] EP929: Force killed PID ${pid}`);
12238
12360
  } catch {
12239
12361
  }
@@ -12284,7 +12406,7 @@ function spawnDevServerProcess(projectPath, port, moduleUid, logPath, customComm
12284
12406
  if (injectedCount > 0) {
12285
12407
  console.log(`[DevServer] EP998: Injecting ${injectedCount} env vars from database`);
12286
12408
  }
12287
- const devProcess = (0, import_child_process15.spawn)(cmd, args, {
12409
+ const devProcess = (0, import_child_process16.spawn)(cmd, args, {
12288
12410
  cwd: projectPath,
12289
12411
  env: mergedEnv,
12290
12412
  stdio: ["ignore", "pipe", "pipe"],
@@ -12732,11 +12854,11 @@ var IPCRouter = class {
12732
12854
  // src/daemon/update-manager.ts
12733
12855
  var fs25 = __toESM(require("fs"));
12734
12856
  var path26 = __toESM(require("path"));
12735
- var import_child_process17 = require("child_process");
12857
+ var import_child_process18 = require("child_process");
12736
12858
  var import_core17 = __toESM(require_dist());
12737
12859
 
12738
12860
  // src/utils/update-checker.ts
12739
- var import_child_process16 = require("child_process");
12861
+ var import_child_process17 = require("child_process");
12740
12862
  var semver = __toESM(require("semver"));
12741
12863
 
12742
12864
  // src/ipc/ipc-client.ts
@@ -12747,7 +12869,7 @@ var PACKAGE_NAME = "@episoda/cli";
12747
12869
  var NPM_REGISTRY = "https://registry.npmjs.org";
12748
12870
  function isFileLinkedInstall() {
12749
12871
  try {
12750
- const output = (0, import_child_process16.execSync)(`npm list -g ${PACKAGE_NAME} --json`, {
12872
+ const output = (0, import_child_process17.execSync)(`npm list -g ${PACKAGE_NAME} --json`, {
12751
12873
  stdio: ["pipe", "pipe", "pipe"],
12752
12874
  timeout: 1e4
12753
12875
  }).toString();
@@ -12791,7 +12913,7 @@ async function checkForUpdates(currentVersion) {
12791
12913
  }
12792
12914
  function performSyncUpdate(targetVersion) {
12793
12915
  try {
12794
- (0, import_child_process16.execSync)(`npm install -g ${PACKAGE_NAME}@${targetVersion}`, {
12916
+ (0, import_child_process17.execSync)(`npm install -g ${PACKAGE_NAME}@${targetVersion}`, {
12795
12917
  stdio: ["pipe", "pipe", "pipe"],
12796
12918
  timeout: 12e4
12797
12919
  // 2 minute timeout
@@ -12806,7 +12928,7 @@ function performSyncUpdate(targetVersion) {
12806
12928
  }
12807
12929
  function getInstalledVersion() {
12808
12930
  try {
12809
- const output = (0, import_child_process16.execSync)(`npm list -g ${PACKAGE_NAME} --json`, {
12931
+ const output = (0, import_child_process17.execSync)(`npm list -g ${PACKAGE_NAME} --json`, {
12810
12932
  stdio: ["pipe", "pipe", "pipe"],
12811
12933
  timeout: 1e4
12812
12934
  }).toString();
@@ -12941,7 +13063,7 @@ var UpdateManager = class _UpdateManager {
12941
13063
  const configDir = (0, import_core17.getConfigDir)();
12942
13064
  const logPath = path26.join(configDir, "daemon.log");
12943
13065
  const logFd = fs25.openSync(logPath, "a");
12944
- const child = (0, import_child_process17.spawn)("node", [this.daemonEntryFile], {
13066
+ const child = (0, import_child_process18.spawn)("node", [this.daemonEntryFile], {
12945
13067
  detached: true,
12946
13068
  stdio: ["ignore", logFd, logFd],
12947
13069
  env: { ...process.env, EPISODA_DAEMON_MODE: "1" }
@@ -14244,9 +14366,9 @@ var Daemon = class _Daemon {
14244
14366
  });
14245
14367
  if (!process.env.EPISODA_CONTAINER_ID) {
14246
14368
  if (process.env.GITHUB_PERSONAL_ACCESS_TOKEN) {
14247
- console.log("[Daemon] EP1365: GITHUB_PERSONAL_ACCESS_TOKEN is set in environment");
14369
+ console.log("[Daemon] EP1377: GITHUB_PERSONAL_ACCESS_TOKEN is set in environment");
14248
14370
  } else {
14249
- console.warn("[Daemon] EP1365: GITHUB_PERSONAL_ACCESS_TOKEN not set - GitHub MCP tools in local dev may fail");
14371
+ console.log("[Daemon] EP1377: GITHUB_PERSONAL_ACCESS_TOKEN not set in daemon env (OK - daemon sessions inject token via credentials, local CLI uses scripts/github-mcp-server.sh)");
14250
14372
  }
14251
14373
  }
14252
14374
  this.updateManager.checkOnStartup();