@episoda/cli 0.2.157 → 0.2.159

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.157",
2912
+ version: "0.2.159",
2917
2913
  description: "CLI tool for Episoda local development workflow orchestration",
2918
2914
  main: "dist/index.js",
2919
2915
  types: "dist/index.d.ts",
@@ -4936,6 +4932,8 @@ var ClaudePersistentRuntime = class {
4936
4932
  this.maxStderrTailBytes = 8192;
4937
4933
  // Stdout JSONL parsing state
4938
4934
  this.stdoutBuffer = "";
4935
+ this.stdoutLineQueue = [];
4936
+ this.drainingStdoutQueue = false;
4939
4937
  this.parsedLineCount = 0;
4940
4938
  this.chunksSent = 0;
4941
4939
  this.hasContent = false;
@@ -4998,21 +4996,9 @@ var ClaudePersistentRuntime = class {
4998
4996
  this.stdoutBuffer += data.toString();
4999
4997
  const lines = this.stdoutBuffer.split("\n");
5000
4998
  this.stdoutBuffer = lines.pop() || "";
5001
- for (const line of lines) {
5002
- if (!line.trim()) continue;
5003
- try {
5004
- const parsed = JSON.parse(line);
5005
- this.parsedLineCount++;
5006
- if (this.parsedLineCount === 1) {
5007
- const ttftMs = Date.now() - this.spawnTimestamp;
5008
- console.log(`[ClaudePersistentRuntime] EP1360: TTFT (spawn to first JSON): ${ttftMs}ms, session=${this.sessionId}`);
5009
- }
5010
- this.handleParsedEvent(parsed);
5011
- } catch {
5012
- if (line.trim() && this.callbacks) {
5013
- this.callbacks.onChunk(line + "\n");
5014
- }
5015
- }
4999
+ if (lines.length > 0) {
5000
+ this.stdoutLineQueue.push(...lines);
5001
+ this.drainStdoutQueue();
5016
5002
  }
5017
5003
  });
5018
5004
  this.process.on("exit", (code, signal) => {
@@ -5118,6 +5104,41 @@ var ClaudePersistentRuntime = class {
5118
5104
  // -------------------------------------------------------------------------
5119
5105
  // Event handling
5120
5106
  // -------------------------------------------------------------------------
5107
+ drainStdoutQueue() {
5108
+ if (this.drainingStdoutQueue) return;
5109
+ this.drainingStdoutQueue = true;
5110
+ const BATCH_SIZE = 5;
5111
+ const processBatch = () => {
5112
+ let processed = 0;
5113
+ while (processed < BATCH_SIZE && this.stdoutLineQueue.length > 0) {
5114
+ const line = this.stdoutLineQueue.shift();
5115
+ processed++;
5116
+ if (!line.trim()) continue;
5117
+ try {
5118
+ const parsed = JSON.parse(line);
5119
+ this.parsedLineCount++;
5120
+ if (this.parsedLineCount === 1) {
5121
+ const ttftMs = Date.now() - this.spawnTimestamp;
5122
+ console.log(`[ClaudePersistentRuntime] EP1360: TTFT (spawn to first JSON): ${ttftMs}ms, session=${this.sessionId}`);
5123
+ }
5124
+ this.handleParsedEvent(parsed);
5125
+ } catch {
5126
+ if (line.trim() && this.callbacks) {
5127
+ this.callbacks.onChunk(line + "\n");
5128
+ }
5129
+ }
5130
+ }
5131
+ if (this.stdoutLineQueue.length > 0) {
5132
+ setImmediate(processBatch);
5133
+ return;
5134
+ }
5135
+ this.drainingStdoutQueue = false;
5136
+ if (this.stdoutLineQueue.length > 0) {
5137
+ this.drainStdoutQueue();
5138
+ }
5139
+ };
5140
+ processBatch();
5141
+ }
5121
5142
  handleParsedEvent(parsed) {
5122
5143
  const type = parsed.type;
5123
5144
  if (this._turnState === "waiting_for_echo") {
@@ -5429,6 +5450,8 @@ var CodexPersistentRuntime = class {
5429
5450
  this.stderrTail = "";
5430
5451
  this.maxStderrTailBytes = 8192;
5431
5452
  this.stdoutBuffer = "";
5453
+ this.stdoutLineQueue = [];
5454
+ this.drainingStdoutQueue = false;
5432
5455
  this.parsedLineCount = 0;
5433
5456
  // Per-turn accounting
5434
5457
  this.turnStartTime = 0;
@@ -5483,21 +5506,9 @@ var CodexPersistentRuntime = class {
5483
5506
  this.stdoutBuffer += data.toString();
5484
5507
  const lines = this.stdoutBuffer.split("\n");
5485
5508
  this.stdoutBuffer = lines.pop() || "";
5486
- for (const line of lines) {
5487
- if (!line.trim()) continue;
5488
- try {
5489
- const parsed = JSON.parse(line);
5490
- this.parsedLineCount++;
5491
- if (this.parsedLineCount === 1) {
5492
- const ttftMs = Date.now() - this.spawnTimestamp;
5493
- console.log(`[CodexPersistentRuntime] EP1360: TTFT (spawn to first JSON): ${ttftMs}ms, session=${this.sessionId}`);
5494
- }
5495
- this.handleJsonRpcMessage(parsed);
5496
- } catch {
5497
- if (line.trim() && this.callbacks) {
5498
- this.callbacks.onChunk(line + "\n");
5499
- }
5500
- }
5509
+ if (lines.length > 0) {
5510
+ this.stdoutLineQueue.push(...lines);
5511
+ this.drainStdoutQueue();
5501
5512
  }
5502
5513
  });
5503
5514
  this.process.on("exit", (code, signal) => {
@@ -5608,6 +5619,41 @@ var CodexPersistentRuntime = class {
5608
5619
  // -------------------------------------------------------------------------
5609
5620
  // JSON-RPC plumbing
5610
5621
  // -------------------------------------------------------------------------
5622
+ drainStdoutQueue() {
5623
+ if (this.drainingStdoutQueue) return;
5624
+ this.drainingStdoutQueue = true;
5625
+ const BATCH_SIZE = 5;
5626
+ const processBatch = () => {
5627
+ let processed = 0;
5628
+ while (processed < BATCH_SIZE && this.stdoutLineQueue.length > 0) {
5629
+ const line = this.stdoutLineQueue.shift();
5630
+ processed++;
5631
+ if (!line.trim()) continue;
5632
+ try {
5633
+ const parsed = JSON.parse(line);
5634
+ this.parsedLineCount++;
5635
+ if (this.parsedLineCount === 1) {
5636
+ const ttftMs = Date.now() - this.spawnTimestamp;
5637
+ console.log(`[CodexPersistentRuntime] EP1360: TTFT (spawn to first JSON): ${ttftMs}ms, session=${this.sessionId}`);
5638
+ }
5639
+ this.handleJsonRpcMessage(parsed);
5640
+ } catch {
5641
+ if (line.trim() && this.callbacks) {
5642
+ this.callbacks.onChunk(line + "\n");
5643
+ }
5644
+ }
5645
+ }
5646
+ if (this.stdoutLineQueue.length > 0) {
5647
+ setImmediate(processBatch);
5648
+ return;
5649
+ }
5650
+ this.drainingStdoutQueue = false;
5651
+ if (this.stdoutLineQueue.length > 0) {
5652
+ this.drainStdoutQueue();
5653
+ }
5654
+ };
5655
+ processBatch();
5656
+ }
5611
5657
  handleJsonRpcMessage(msg) {
5612
5658
  if (RUNTIME_DEBUG2 && this.debugTraceCount < 20) {
5613
5659
  this.debugTraceCount++;
@@ -8109,6 +8155,7 @@ var AgentCommandQueue = class {
8109
8155
  // src/daemon/worktree-manager.ts
8110
8156
  var fs11 = __toESM(require("fs"));
8111
8157
  var path12 = __toESM(require("path"));
8158
+ var import_child_process11 = require("child_process");
8112
8159
  var import_core10 = __toESM(require_dist());
8113
8160
  function validateModuleUid(moduleUid) {
8114
8161
  if (!moduleUid || typeof moduleUid !== "string" || !moduleUid.trim()) {
@@ -8125,6 +8172,38 @@ function validateModuleUid(moduleUid) {
8125
8172
  }
8126
8173
  return true;
8127
8174
  }
8175
+ function isValidDefaultBranchName(name) {
8176
+ if (!name || typeof name !== "string") return false;
8177
+ const trimmed = name.trim();
8178
+ if (trimmed !== name) return false;
8179
+ if (name.length > 255) return false;
8180
+ if (name.startsWith("-")) return false;
8181
+ if (name.startsWith("/")) return false;
8182
+ if (name.endsWith("/")) return false;
8183
+ if (name.endsWith(".")) return false;
8184
+ if (name.endsWith(".lock")) return false;
8185
+ if (name.includes("..")) return false;
8186
+ if (name.includes("@{")) return false;
8187
+ if (name.includes("//")) return false;
8188
+ if (name.includes("\\")) return false;
8189
+ if (/[ ~^:?*\[\]\s]/.test(name)) return false;
8190
+ if (!/^[A-Za-z0-9][A-Za-z0-9._/-]*$/.test(name)) return false;
8191
+ return true;
8192
+ }
8193
+ function runGit(args, cwd, timeoutMs) {
8194
+ const res = (0, import_child_process11.spawnSync)("git", args, {
8195
+ cwd,
8196
+ encoding: "utf-8",
8197
+ timeout: timeoutMs,
8198
+ windowsHide: true,
8199
+ shell: false
8200
+ });
8201
+ return {
8202
+ success: res.status === 0,
8203
+ stdout: (res.stdout || "").toString(),
8204
+ stderr: (res.stderr || "").toString()
8205
+ };
8206
+ }
8128
8207
  var WorktreeManager = class _WorktreeManager {
8129
8208
  constructor(projectRoot) {
8130
8209
  // ============================================================
@@ -8182,22 +8261,24 @@ var WorktreeManager = class _WorktreeManager {
8182
8261
  */
8183
8262
  async ensureFetchRefspecConfigured() {
8184
8263
  try {
8185
- const { execSync: execSync10 } = require("child_process");
8186
8264
  let fetchRefspec = null;
8187
8265
  try {
8188
- fetchRefspec = execSync10("git config --get remote.origin.fetch", {
8189
- cwd: this.bareRepoPath,
8190
- encoding: "utf-8",
8191
- timeout: 5e3
8192
- }).trim();
8266
+ const res = runGit(["config", "--get", "remote.origin.fetch"], this.bareRepoPath, 5e3);
8267
+ if (res.success) {
8268
+ fetchRefspec = res.stdout.trim();
8269
+ }
8193
8270
  } catch {
8194
8271
  }
8195
8272
  if (!fetchRefspec) {
8196
8273
  console.log("[WorktreeManager] EP1014: Configuring missing fetch refspec for bare repo");
8197
- execSync10('git config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*"', {
8198
- cwd: this.bareRepoPath,
8199
- timeout: 5e3
8200
- });
8274
+ const setRes = runGit(
8275
+ ["config", "remote.origin.fetch", "+refs/heads/*:refs/remotes/origin/*"],
8276
+ this.bareRepoPath,
8277
+ 5e3
8278
+ );
8279
+ if (!setRes.success) {
8280
+ throw new Error(setRes.stderr || "Failed to configure fetch refspec");
8281
+ }
8201
8282
  console.log("[WorktreeManager] EP1014: Fetch refspec configured successfully");
8202
8283
  }
8203
8284
  } catch (error) {
@@ -8230,11 +8311,44 @@ var WorktreeManager = class _WorktreeManager {
8230
8311
  manager.writeConfig(config);
8231
8312
  return manager;
8232
8313
  }
8314
+ /**
8315
+ * EP1373: Resolve the default branch name using a 3-level fallback:
8316
+ * 1. Explicit defaultBranch parameter (from project GitHub config)
8317
+ * 2. Git-derived: refs/remotes/origin/HEAD symbolic-ref target
8318
+ * 3. Final fallback: 'main' (with warning)
8319
+ */
8320
+ async resolveDefaultBranch(explicitDefault) {
8321
+ if (explicitDefault) {
8322
+ if (isValidDefaultBranchName(explicitDefault)) {
8323
+ return explicitDefault;
8324
+ }
8325
+ console.warn(`[WorktreeManager] EP1373: Invalid defaultBranch provided ("${explicitDefault}"), ignoring`);
8326
+ }
8327
+ try {
8328
+ const res = runGit(["symbolic-ref", "refs/remotes/origin/HEAD"], this.bareRepoPath, 5e3);
8329
+ if (!res.success) {
8330
+ throw new Error(res.stderr || "symbolic-ref failed");
8331
+ }
8332
+ const symref = res.stdout.trim();
8333
+ const match = symref.match(/^refs\/remotes\/origin\/(.+)$/);
8334
+ if (match && match[1]) {
8335
+ const derived = match[1];
8336
+ if (isValidDefaultBranchName(derived)) {
8337
+ return derived;
8338
+ }
8339
+ console.warn(`[WorktreeManager] EP1373: Derived default branch from origin/HEAD is invalid ("${derived}"), ignoring`);
8340
+ }
8341
+ } catch {
8342
+ }
8343
+ console.warn('[WorktreeManager] EP1373: Could not resolve default branch, falling back to "main"');
8344
+ return "main";
8345
+ }
8233
8346
  /**
8234
8347
  * Create a worktree for a module
8235
8348
  * The entire operation is locked to prevent race conditions
8349
+ * EP1373: Added defaultBranch parameter for explicit default branch resolution
8236
8350
  */
8237
- async createWorktree(moduleUid, branchName, createBranch = false) {
8351
+ async createWorktree(moduleUid, branchName, createBranch = false, defaultBranch, correlationId) {
8238
8352
  if (!validateModuleUid(moduleUid)) {
8239
8353
  return {
8240
8354
  success: false,
@@ -8300,25 +8414,63 @@ var WorktreeManager = class _WorktreeManager {
8300
8414
  console.warn("[WorktreeManager] EP1265: Failed to prune worktrees (continuing):", pruneResult.output);
8301
8415
  }
8302
8416
  }
8303
- const fetchResult = await this.gitExecutor.execute({
8304
- action: "fetch",
8305
- remote: "origin",
8306
- branch: "+refs/heads/main:refs/remotes/origin/main"
8307
- }, { cwd: this.bareRepoPath });
8308
- if (!fetchResult.success && createBranch) {
8309
- console.error("[worktree-manager] Failed to fetch from origin:", fetchResult.output);
8310
- return {
8311
- success: false,
8312
- error: "Failed to fetch latest refs from origin. Cannot create worktree with stale refs."
8313
- };
8417
+ const resolvedDefault = await this.resolveDefaultBranch(defaultBranch);
8418
+ let shouldCreateBranch = createBranch;
8419
+ let startPoint;
8420
+ if (createBranch) {
8421
+ const managerFetchStartMs = Date.now();
8422
+ const fetchResult = await this.gitExecutor.execute({
8423
+ action: "fetch",
8424
+ remote: "origin",
8425
+ branch: `+refs/heads/${resolvedDefault}:refs/remotes/origin/${resolvedDefault}`
8426
+ }, { cwd: this.bareRepoPath });
8427
+ console.log(`[WorktreeManager] EP1373: manager_fetch phase=manager_fetch durationMs=${Date.now() - managerFetchStartMs} moduleUid=${moduleUid} correlationId=${correlationId || "none"} defaultBranch=${resolvedDefault} success=${fetchResult.success}`);
8428
+ if (!fetchResult.success) {
8429
+ console.error("[worktree-manager] Failed to fetch from origin:", fetchResult.output);
8430
+ return {
8431
+ success: false,
8432
+ error: "Failed to fetch latest refs from origin. Cannot create worktree with stale refs."
8433
+ };
8434
+ }
8435
+ startPoint = `origin/${resolvedDefault}`;
8436
+ } else {
8437
+ const existingBranchFetchStartMs = Date.now();
8438
+ const branchFetchResult = await this.gitExecutor.execute({
8439
+ action: "fetch",
8440
+ remote: "origin",
8441
+ branch: `+refs/heads/${branchName}:refs/remotes/origin/${branchName}`
8442
+ }, { cwd: this.bareRepoPath });
8443
+ 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}`);
8444
+ const localBranchExists = runGit(
8445
+ ["show-ref", "--verify", `refs/heads/${branchName}`],
8446
+ this.bareRepoPath,
8447
+ 5e3
8448
+ ).success;
8449
+ const remoteBranchExists = runGit(
8450
+ ["show-ref", "--verify", `refs/remotes/origin/${branchName}`],
8451
+ this.bareRepoPath,
8452
+ 5e3
8453
+ ).success;
8454
+ if (!localBranchExists && remoteBranchExists) {
8455
+ shouldCreateBranch = true;
8456
+ startPoint = `origin/${branchName}`;
8457
+ console.log(`[WorktreeManager] EP1373: remote_only_branch phase=remote_only_branch moduleUid=${moduleUid} correlationId=${correlationId || "none"} branch=${branchName}`);
8458
+ } else if (!localBranchExists && !remoteBranchExists) {
8459
+ return {
8460
+ success: false,
8461
+ error: `Branch "${branchName}" not found locally or on origin`
8462
+ };
8463
+ }
8314
8464
  }
8465
+ const gitWorktreeAddStartMs = Date.now();
8315
8466
  const result = await this.gitExecutor.execute({
8316
8467
  action: "worktree_add",
8317
8468
  path: worktreePath,
8318
8469
  branch: branchName,
8319
- create: createBranch,
8320
- startPoint: createBranch ? "origin/main" : void 0
8470
+ create: shouldCreateBranch,
8471
+ startPoint
8321
8472
  }, { cwd: this.bareRepoPath });
8473
+ console.log(`[WorktreeManager] EP1373: git_worktree_add phase=git_worktree_add durationMs=${Date.now() - gitWorktreeAddStartMs} moduleUid=${moduleUid} correlationId=${correlationId || "none"} success=${result.success}`);
8322
8474
  if (!result.success) {
8323
8475
  return {
8324
8476
  success: false,
@@ -9959,7 +10111,7 @@ async function handleFileMkdir(command, projectPath) {
9959
10111
  }
9960
10112
 
9961
10113
  // src/daemon/handlers/exec-handler.ts
9962
- var import_child_process11 = require("child_process");
10114
+ var import_child_process12 = require("child_process");
9963
10115
  var DEFAULT_TIMEOUT = 3e4;
9964
10116
  var MAX_TIMEOUT = 3e5;
9965
10117
  async function handleExec(command, projectPath) {
@@ -9981,7 +10133,7 @@ async function handleExec(command, projectPath) {
9981
10133
  resolve4(result);
9982
10134
  };
9983
10135
  try {
9984
- const proc = (0, import_child_process11.spawn)(cmd, {
10136
+ const proc = (0, import_child_process12.spawn)(cmd, {
9985
10137
  shell: true,
9986
10138
  cwd,
9987
10139
  env: { ...process.env, ...env },
@@ -10045,7 +10197,7 @@ async function handleExec(command, projectPath) {
10045
10197
  var path23 = __toESM(require("path"));
10046
10198
  var fs22 = __toESM(require("fs"));
10047
10199
  var os10 = __toESM(require("os"));
10048
- var import_child_process14 = require("child_process");
10200
+ var import_child_process15 = require("child_process");
10049
10201
  var import_util2 = require("util");
10050
10202
 
10051
10203
  // src/preview/types.ts
@@ -10072,7 +10224,7 @@ var import_events3 = require("events");
10072
10224
  var import_fs = require("fs");
10073
10225
 
10074
10226
  // src/preview/dev-server-runner.ts
10075
- var import_child_process13 = require("child_process");
10227
+ var import_child_process14 = require("child_process");
10076
10228
  var http = __toESM(require("http"));
10077
10229
  var fs20 = __toESM(require("fs"));
10078
10230
  var path21 = __toESM(require("path"));
@@ -10210,7 +10362,7 @@ No cached values available as fallback.`
10210
10362
  var fs19 = __toESM(require("fs"));
10211
10363
  var path20 = __toESM(require("path"));
10212
10364
  var os9 = __toESM(require("os"));
10213
- var import_child_process12 = require("child_process");
10365
+ var import_child_process13 = require("child_process");
10214
10366
  var DEV_SERVER_REGISTRY_DIR = path20.join(os9.homedir(), ".episoda", "dev-servers");
10215
10367
  var DevServerRegistry = class {
10216
10368
  constructor() {
@@ -10365,7 +10517,7 @@ var DevServerRegistry = class {
10365
10517
  */
10366
10518
  getProcessCwd(pid) {
10367
10519
  try {
10368
- const output = (0, import_child_process12.execSync)(`lsof -p ${pid} -Fn | grep ^n | grep cwd | head -1`, {
10520
+ const output = (0, import_child_process13.execSync)(`lsof -p ${pid} -Fn | grep ^n | grep cwd | head -1`, {
10369
10521
  encoding: "utf8",
10370
10522
  timeout: 5e3
10371
10523
  }).trim();
@@ -10390,7 +10542,7 @@ var DevServerRegistry = class {
10390
10542
  findProcessesInWorktree(worktreePath) {
10391
10543
  const pids = [];
10392
10544
  try {
10393
- const output = (0, import_child_process12.execSync)(
10545
+ const output = (0, import_child_process13.execSync)(
10394
10546
  `lsof -c node -c next | grep "${worktreePath}" | awk '{print $2}' | sort -u`,
10395
10547
  { encoding: "utf8", timeout: 5e3 }
10396
10548
  ).trim();
@@ -10451,7 +10603,7 @@ var DevServerRegistry = class {
10451
10603
  */
10452
10604
  findProcessesOnPort(port) {
10453
10605
  try {
10454
- const output = (0, import_child_process12.execSync)(`lsof -ti:${port} 2>/dev/null || true`, { encoding: "utf8" }).trim();
10606
+ const output = (0, import_child_process13.execSync)(`lsof -ti:${port} 2>/dev/null || true`, { encoding: "utf8" }).trim();
10455
10607
  if (!output) {
10456
10608
  return [];
10457
10609
  }
@@ -10705,7 +10857,7 @@ var DevServerRunner = class extends import_events2.EventEmitter {
10705
10857
  */
10706
10858
  async killProcessOnPort(port) {
10707
10859
  try {
10708
- const result = (0, import_child_process13.execSync)(`lsof -ti:${port} 2>/dev/null || true`, { encoding: "utf8" }).trim();
10860
+ const result = (0, import_child_process14.execSync)(`lsof -ti:${port} 2>/dev/null || true`, { encoding: "utf8" }).trim();
10709
10861
  if (!result) {
10710
10862
  return true;
10711
10863
  }
@@ -10713,15 +10865,15 @@ var DevServerRunner = class extends import_events2.EventEmitter {
10713
10865
  console.log(`[DevServerRunner] Found ${pids.length} process(es) on port ${port}`);
10714
10866
  for (const pid of pids) {
10715
10867
  try {
10716
- (0, import_child_process13.execSync)(`kill -15 ${pid} 2>/dev/null || true`);
10868
+ (0, import_child_process14.execSync)(`kill -15 ${pid} 2>/dev/null || true`);
10717
10869
  } catch {
10718
10870
  }
10719
10871
  }
10720
10872
  await this.wait(1e3);
10721
10873
  for (const pid of pids) {
10722
10874
  try {
10723
- (0, import_child_process13.execSync)(`kill -0 ${pid} 2>/dev/null`);
10724
- (0, import_child_process13.execSync)(`kill -9 ${pid} 2>/dev/null || true`);
10875
+ (0, import_child_process14.execSync)(`kill -0 ${pid} 2>/dev/null`);
10876
+ (0, import_child_process14.execSync)(`kill -9 ${pid} 2>/dev/null || true`);
10725
10877
  } catch {
10726
10878
  }
10727
10879
  }
@@ -10770,7 +10922,7 @@ var DevServerRunner = class extends import_events2.EventEmitter {
10770
10922
  PORT: String(port),
10771
10923
  NODE_OPTIONS: enhancedNodeOptions
10772
10924
  };
10773
- const proc = (0, import_child_process13.spawn)(cmd, args, {
10925
+ const proc = (0, import_child_process14.spawn)(cmd, args, {
10774
10926
  cwd: projectPath,
10775
10927
  env: mergedEnv,
10776
10928
  stdio: ["ignore", "pipe", "pipe"],
@@ -11571,7 +11723,7 @@ async function getConfigForApi() {
11571
11723
  }
11572
11724
  return (0, import_core13.loadConfig)();
11573
11725
  }
11574
- var execAsync2 = (0, import_util2.promisify)(import_child_process14.exec);
11726
+ var execAsync2 = (0, import_util2.promisify)(import_child_process15.exec);
11575
11727
  function persistWorkspaceProjectContext(workspaceSlug, projectSlug, projectId) {
11576
11728
  if (process.env.EPISODA_MODE !== "cloud") {
11577
11729
  return;
@@ -11644,8 +11796,11 @@ async function handleWorktreeCreate(request2) {
11644
11796
  envVars,
11645
11797
  setupScript,
11646
11798
  // EP1229: detachedHead removed - planning worktrees no longer exist
11647
- moduleType
11799
+ moduleType,
11800
+ defaultBranch,
11801
+ correlationId
11648
11802
  } = request2;
11803
+ const worktreeStartMs = Date.now();
11649
11804
  console.log(`[Worktree] K1273: Creating worktree for ${moduleUid}`);
11650
11805
  console.log(`[Worktree] Project: ${projectSlug}`);
11651
11806
  console.log(`[Worktree] Branch: ${branchName} (create: ${createBranch})`);
@@ -11689,12 +11844,7 @@ async function handleWorktreeCreate(request2) {
11689
11844
  };
11690
11845
  }
11691
11846
  } else {
11692
- console.log(`[Worktree] K1273: Project exists, fetching latest...`);
11693
- try {
11694
- await execAsync2(`git -C "${bareRepoPath}" fetch origin --prune`, { env: gitEnv });
11695
- } catch (fetchError) {
11696
- console.warn(`[Worktree] K1273: Fetch failed (continuing anyway): ${fetchError.message}`);
11697
- }
11847
+ console.log(`[Worktree] EP1373: Project exists, skipping handler-level fetch (manager handles narrow fetch)`);
11698
11848
  }
11699
11849
  const manager = new WorktreeManager(projectPath);
11700
11850
  const initialized2 = await manager.initialize();
@@ -11704,7 +11854,8 @@ async function handleWorktreeCreate(request2) {
11704
11854
  error: `Failed to initialize WorktreeManager at ${projectPath}`
11705
11855
  };
11706
11856
  }
11707
- const result = await manager.createWorktree(moduleUid, branchName, createBranch);
11857
+ const worktreeAddStartMs = Date.now();
11858
+ const result = await manager.createWorktree(moduleUid, branchName, createBranch, defaultBranch, correlationId);
11708
11859
  if (!result.success) {
11709
11860
  return {
11710
11861
  success: false,
@@ -11712,6 +11863,7 @@ async function handleWorktreeCreate(request2) {
11712
11863
  };
11713
11864
  }
11714
11865
  const worktreePath = result.worktreePath;
11866
+ console.log(`[Worktree] EP1373: worktree_add phase=worktree_add durationMs=${Date.now() - worktreeAddStartMs} moduleUid=${moduleUid} correlationId=${correlationId || "none"}`);
11715
11867
  console.log(`[Worktree] EP1143: Worktree created at ${worktreePath}`);
11716
11868
  const config = await getConfigForApi();
11717
11869
  let finalStatus = "ready";
@@ -11743,6 +11895,7 @@ ${buildCmd}` : buildCmd;
11743
11895
  }
11744
11896
  }
11745
11897
  if (effectiveSetupScript) {
11898
+ const setupStartMs = Date.now();
11746
11899
  await manager.updateWorktreeStatus(moduleUid, "setup");
11747
11900
  if (config?.access_token) {
11748
11901
  await updateWorktree(config, {
@@ -11755,6 +11908,7 @@ ${buildCmd}` : buildCmd;
11755
11908
  }
11756
11909
  console.log(`[Worktree] EP1143: Running setup script...`);
11757
11910
  const scriptResult = await manager.runSetupScript(moduleUid, effectiveSetupScript);
11911
+ console.log(`[Worktree] EP1373: setup_script phase=worktree_setup durationMs=${Date.now() - setupStartMs} moduleUid=${moduleUid} correlationId=${correlationId || "none"} success=${scriptResult.success}`);
11758
11912
  if (!scriptResult.success) {
11759
11913
  console.error(`[Worktree] EP1143: Setup script failed: ${scriptResult.error}`);
11760
11914
  await manager.updateWorktreeStatus(moduleUid, "error", scriptResult.error);
@@ -11814,6 +11968,7 @@ ${buildCmd}` : buildCmd;
11814
11968
  console.error(`[Worktree] EP1143: Failed to update worktrees table: ${apiError.message}`);
11815
11969
  }
11816
11970
  }
11971
+ console.log(`[Worktree] EP1373: worktree_create_total phase=worktree_create_total durationMs=${Date.now() - worktreeStartMs} moduleUid=${moduleUid} correlationId=${correlationId || "none"} status=${finalStatus}`);
11817
11972
  console.log(`[Worktree] EP1143: Worktree ready for ${moduleUid}`);
11818
11973
  return {
11819
11974
  success: true,
@@ -12116,7 +12271,7 @@ async function handleProjectSetup(params) {
12116
12271
  }
12117
12272
 
12118
12273
  // src/utils/dev-server.ts
12119
- var import_child_process15 = require("child_process");
12274
+ var import_child_process16 = require("child_process");
12120
12275
  var import_core14 = __toESM(require_dist());
12121
12276
  var fs24 = __toESM(require("fs"));
12122
12277
  var path25 = __toESM(require("path"));
@@ -12165,7 +12320,7 @@ function writeToLog(logPath, line, isError = false) {
12165
12320
  }
12166
12321
  async function killProcessOnPort(port) {
12167
12322
  try {
12168
- const result = (0, import_child_process15.execSync)(`lsof -ti:${port} 2>/dev/null || true`, { encoding: "utf8" }).trim();
12323
+ const result = (0, import_child_process16.execSync)(`lsof -ti:${port} 2>/dev/null || true`, { encoding: "utf8" }).trim();
12169
12324
  if (!result) {
12170
12325
  console.log(`[DevServer] EP929: No process found on port ${port}`);
12171
12326
  return true;
@@ -12174,7 +12329,7 @@ async function killProcessOnPort(port) {
12174
12329
  console.log(`[DevServer] EP929: Found ${pids.length} process(es) on port ${port}: ${pids.join(", ")}`);
12175
12330
  for (const pid of pids) {
12176
12331
  try {
12177
- (0, import_child_process15.execSync)(`kill -15 ${pid} 2>/dev/null || true`, { encoding: "utf8" });
12332
+ (0, import_child_process16.execSync)(`kill -15 ${pid} 2>/dev/null || true`, { encoding: "utf8" });
12178
12333
  console.log(`[DevServer] EP929: Sent SIGTERM to PID ${pid}`);
12179
12334
  } catch {
12180
12335
  }
@@ -12182,8 +12337,8 @@ async function killProcessOnPort(port) {
12182
12337
  await new Promise((resolve4) => setTimeout(resolve4, 1e3));
12183
12338
  for (const pid of pids) {
12184
12339
  try {
12185
- (0, import_child_process15.execSync)(`kill -0 ${pid} 2>/dev/null`, { encoding: "utf8" });
12186
- (0, import_child_process15.execSync)(`kill -9 ${pid} 2>/dev/null || true`, { encoding: "utf8" });
12340
+ (0, import_child_process16.execSync)(`kill -0 ${pid} 2>/dev/null`, { encoding: "utf8" });
12341
+ (0, import_child_process16.execSync)(`kill -9 ${pid} 2>/dev/null || true`, { encoding: "utf8" });
12187
12342
  console.log(`[DevServer] EP929: Force killed PID ${pid}`);
12188
12343
  } catch {
12189
12344
  }
@@ -12234,7 +12389,7 @@ function spawnDevServerProcess(projectPath, port, moduleUid, logPath, customComm
12234
12389
  if (injectedCount > 0) {
12235
12390
  console.log(`[DevServer] EP998: Injecting ${injectedCount} env vars from database`);
12236
12391
  }
12237
- const devProcess = (0, import_child_process15.spawn)(cmd, args, {
12392
+ const devProcess = (0, import_child_process16.spawn)(cmd, args, {
12238
12393
  cwd: projectPath,
12239
12394
  env: mergedEnv,
12240
12395
  stdio: ["ignore", "pipe", "pipe"],
@@ -12682,11 +12837,11 @@ var IPCRouter = class {
12682
12837
  // src/daemon/update-manager.ts
12683
12838
  var fs25 = __toESM(require("fs"));
12684
12839
  var path26 = __toESM(require("path"));
12685
- var import_child_process17 = require("child_process");
12840
+ var import_child_process18 = require("child_process");
12686
12841
  var import_core17 = __toESM(require_dist());
12687
12842
 
12688
12843
  // src/utils/update-checker.ts
12689
- var import_child_process16 = require("child_process");
12844
+ var import_child_process17 = require("child_process");
12690
12845
  var semver = __toESM(require("semver"));
12691
12846
 
12692
12847
  // src/ipc/ipc-client.ts
@@ -12697,7 +12852,7 @@ var PACKAGE_NAME = "@episoda/cli";
12697
12852
  var NPM_REGISTRY = "https://registry.npmjs.org";
12698
12853
  function isFileLinkedInstall() {
12699
12854
  try {
12700
- const output = (0, import_child_process16.execSync)(`npm list -g ${PACKAGE_NAME} --json`, {
12855
+ const output = (0, import_child_process17.execSync)(`npm list -g ${PACKAGE_NAME} --json`, {
12701
12856
  stdio: ["pipe", "pipe", "pipe"],
12702
12857
  timeout: 1e4
12703
12858
  }).toString();
@@ -12741,7 +12896,7 @@ async function checkForUpdates(currentVersion) {
12741
12896
  }
12742
12897
  function performSyncUpdate(targetVersion) {
12743
12898
  try {
12744
- (0, import_child_process16.execSync)(`npm install -g ${PACKAGE_NAME}@${targetVersion}`, {
12899
+ (0, import_child_process17.execSync)(`npm install -g ${PACKAGE_NAME}@${targetVersion}`, {
12745
12900
  stdio: ["pipe", "pipe", "pipe"],
12746
12901
  timeout: 12e4
12747
12902
  // 2 minute timeout
@@ -12756,7 +12911,7 @@ function performSyncUpdate(targetVersion) {
12756
12911
  }
12757
12912
  function getInstalledVersion() {
12758
12913
  try {
12759
- const output = (0, import_child_process16.execSync)(`npm list -g ${PACKAGE_NAME} --json`, {
12914
+ const output = (0, import_child_process17.execSync)(`npm list -g ${PACKAGE_NAME} --json`, {
12760
12915
  stdio: ["pipe", "pipe", "pipe"],
12761
12916
  timeout: 1e4
12762
12917
  }).toString();
@@ -12891,7 +13046,7 @@ var UpdateManager = class _UpdateManager {
12891
13046
  const configDir = (0, import_core17.getConfigDir)();
12892
13047
  const logPath = path26.join(configDir, "daemon.log");
12893
13048
  const logFd = fs25.openSync(logPath, "a");
12894
- const child = (0, import_child_process17.spawn)("node", [this.daemonEntryFile], {
13049
+ const child = (0, import_child_process18.spawn)("node", [this.daemonEntryFile], {
12895
13050
  detached: true,
12896
13051
  stdio: ["ignore", logFd, logFd],
12897
13052
  env: { ...process.env, EPISODA_DAEMON_MODE: "1" }