@episoda/cli 0.2.218 → 0.2.220

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.
@@ -39,8 +39,9 @@ var require_command_protocol = __commonJS({
39
39
  exports2.WORKTREE_STATUS_VALUES = void 0;
40
40
  exports2.WORKTREE_STATUS_VALUES = [
41
41
  "pending",
42
- "setup",
43
- "ready",
42
+ "provisioning",
43
+ "verified",
44
+ "missing",
44
45
  "error",
45
46
  "removing"
46
47
  ];
@@ -2241,7 +2242,7 @@ var require_websocket_client = __commonJS({
2241
2242
  clearTimeout(this.reconnectTimeout);
2242
2243
  this.reconnectTimeout = void 0;
2243
2244
  }
2244
- return new Promise((resolve9, reject) => {
2245
+ return new Promise((resolve10, reject) => {
2245
2246
  const connectionTimeout = setTimeout(() => {
2246
2247
  if (this.ws) {
2247
2248
  this.ws.terminate();
@@ -2272,7 +2273,7 @@ var require_websocket_client = __commonJS({
2272
2273
  daemonPid: this.daemonPid
2273
2274
  });
2274
2275
  this.startHeartbeat();
2275
- resolve9();
2276
+ resolve10();
2276
2277
  });
2277
2278
  this.ws.on("pong", () => {
2278
2279
  if (this.heartbeatTimeoutTimer) {
@@ -2416,13 +2417,13 @@ var require_websocket_client = __commonJS({
2416
2417
  console.warn("[EpisodaClient] Cannot send - WebSocket not connected");
2417
2418
  return false;
2418
2419
  }
2419
- return new Promise((resolve9) => {
2420
+ return new Promise((resolve10) => {
2420
2421
  this.ws.send(JSON.stringify(message), (error) => {
2421
2422
  if (error) {
2422
2423
  console.error("[EpisodaClient] Failed to send message:", error);
2423
- resolve9(false);
2424
+ resolve10(false);
2424
2425
  } else {
2425
- resolve9(true);
2426
+ resolve10(true);
2426
2427
  }
2427
2428
  });
2428
2429
  });
@@ -3051,7 +3052,7 @@ var require_package = __commonJS({
3051
3052
  "package.json"(exports2, module2) {
3052
3053
  module2.exports = {
3053
3054
  name: "@episoda/cli",
3054
- version: "0.2.218",
3055
+ version: "0.2.220",
3055
3056
  description: "CLI tool for Episoda local development workflow orchestration",
3056
3057
  main: "dist/index.js",
3057
3058
  types: "dist/index.d.ts",
@@ -3468,10 +3469,10 @@ var IPCServer = class {
3468
3469
  this.server = net.createServer((socket) => {
3469
3470
  this.handleConnection(socket);
3470
3471
  });
3471
- return new Promise((resolve9, reject) => {
3472
+ return new Promise((resolve10, reject) => {
3472
3473
  this.server.listen(socketPath, () => {
3473
3474
  fs4.chmodSync(socketPath, 384);
3474
- resolve9();
3475
+ resolve10();
3475
3476
  });
3476
3477
  this.server.on("error", reject);
3477
3478
  });
@@ -3482,12 +3483,12 @@ var IPCServer = class {
3482
3483
  async stop() {
3483
3484
  if (!this.server) return;
3484
3485
  const socketPath = getSocketPath();
3485
- return new Promise((resolve9) => {
3486
+ return new Promise((resolve10) => {
3486
3487
  this.server.close(() => {
3487
3488
  if (fs4.existsSync(socketPath)) {
3488
3489
  fs4.unlinkSync(socketPath);
3489
3490
  }
3490
- resolve9();
3491
+ resolve10();
3491
3492
  });
3492
3493
  });
3493
3494
  }
@@ -3732,7 +3733,7 @@ function getDownloadUrl() {
3732
3733
  return platformUrls[arch4] || null;
3733
3734
  }
3734
3735
  async function downloadFile(url, destPath) {
3735
- return new Promise((resolve9, reject) => {
3736
+ return new Promise((resolve10, reject) => {
3736
3737
  const followRedirect = (currentUrl, redirectCount = 0) => {
3737
3738
  if (redirectCount > 5) {
3738
3739
  reject(new Error("Too many redirects"));
@@ -3762,7 +3763,7 @@ async function downloadFile(url, destPath) {
3762
3763
  response.pipe(file);
3763
3764
  file.on("finish", () => {
3764
3765
  file.close();
3765
- resolve9();
3766
+ resolve10();
3766
3767
  });
3767
3768
  file.on("error", (err) => {
3768
3769
  fs5.unlinkSync(destPath);
@@ -4176,10 +4177,10 @@ var TunnelManager = class extends import_events.EventEmitter {
4176
4177
  const isTracked = Array.from(this.tunnelStates.values()).some((s) => s.info.pid === pid);
4177
4178
  console.log(`[Tunnel] EP904: Found cloudflared PID ${pid} on port ${port} (tracked: ${isTracked})`);
4178
4179
  this.killByPid(pid, "SIGTERM");
4179
- await new Promise((resolve9) => setTimeout(resolve9, 500));
4180
+ await new Promise((resolve10) => setTimeout(resolve10, 500));
4180
4181
  if (this.isProcessRunning(pid)) {
4181
4182
  this.killByPid(pid, "SIGKILL");
4182
- await new Promise((resolve9) => setTimeout(resolve9, 200));
4183
+ await new Promise((resolve10) => setTimeout(resolve10, 200));
4183
4184
  }
4184
4185
  killed.push(pid);
4185
4186
  }
@@ -4213,7 +4214,7 @@ var TunnelManager = class extends import_events.EventEmitter {
4213
4214
  if (!this.tunnelStates.has(moduleUid)) {
4214
4215
  console.log(`[Tunnel] EP877: Found orphaned process PID ${pid} for ${moduleUid}, killing...`);
4215
4216
  this.killByPid(pid, "SIGTERM");
4216
- await new Promise((resolve9) => setTimeout(resolve9, 1e3));
4217
+ await new Promise((resolve10) => setTimeout(resolve10, 1e3));
4217
4218
  if (this.isProcessRunning(pid)) {
4218
4219
  this.killByPid(pid, "SIGKILL");
4219
4220
  }
@@ -4228,7 +4229,7 @@ var TunnelManager = class extends import_events.EventEmitter {
4228
4229
  if (!trackedPids.includes(pid) && !cleaned.includes(pid)) {
4229
4230
  console.log(`[Tunnel] EP877: Found untracked cloudflared process PID ${pid}, killing...`);
4230
4231
  this.killByPid(pid, "SIGTERM");
4231
- await new Promise((resolve9) => setTimeout(resolve9, 500));
4232
+ await new Promise((resolve10) => setTimeout(resolve10, 500));
4232
4233
  if (this.isProcessRunning(pid)) {
4233
4234
  this.killByPid(pid, "SIGKILL");
4234
4235
  }
@@ -4318,7 +4319,7 @@ var TunnelManager = class extends import_events.EventEmitter {
4318
4319
  return { success: false, error: `Failed to get cloudflared: ${errorMessage}` };
4319
4320
  }
4320
4321
  }
4321
- return new Promise((resolve9) => {
4322
+ return new Promise((resolve10) => {
4322
4323
  const tunnelInfo = {
4323
4324
  moduleUid,
4324
4325
  url: previewUrl || "",
@@ -4384,7 +4385,7 @@ var TunnelManager = class extends import_events.EventEmitter {
4384
4385
  moduleUid,
4385
4386
  url: tunnelInfo.url
4386
4387
  });
4387
- resolve9({ success: true, url: tunnelInfo.url });
4388
+ resolve10({ success: true, url: tunnelInfo.url });
4388
4389
  }
4389
4390
  };
4390
4391
  process2.stderr?.on("data", (data) => {
@@ -4411,7 +4412,7 @@ var TunnelManager = class extends import_events.EventEmitter {
4411
4412
  onStatusChange?.("error", errorMsg);
4412
4413
  this.emitEvent({ type: "error", moduleUid, error: errorMsg });
4413
4414
  }
4414
- resolve9({ success: false, error: errorMsg });
4415
+ resolve10({ success: false, error: errorMsg });
4415
4416
  } else if (wasConnected) {
4416
4417
  if (currentState && !currentState.intentionallyStopped) {
4417
4418
  console.log(`[Tunnel] EP948: Named tunnel ${moduleUid} crashed unexpectedly, attempting reconnect...`);
@@ -4442,7 +4443,7 @@ var TunnelManager = class extends import_events.EventEmitter {
4442
4443
  this.emitEvent({ type: "error", moduleUid, error: error.message });
4443
4444
  }
4444
4445
  if (!connected) {
4445
- resolve9({ success: false, error: error.message });
4446
+ resolve10({ success: false, error: error.message });
4446
4447
  }
4447
4448
  });
4448
4449
  setTimeout(() => {
@@ -4465,7 +4466,7 @@ var TunnelManager = class extends import_events.EventEmitter {
4465
4466
  onStatusChange?.("error", errorMsg);
4466
4467
  this.emitEvent({ type: "error", moduleUid, error: errorMsg });
4467
4468
  }
4468
- resolve9({ success: false, error: errorMsg });
4469
+ resolve10({ success: false, error: errorMsg });
4469
4470
  }
4470
4471
  }, TUNNEL_TIMEOUTS.NAMED_TUNNEL_CONNECT);
4471
4472
  });
@@ -4526,7 +4527,7 @@ var TunnelManager = class extends import_events.EventEmitter {
4526
4527
  if (orphanPid && this.isProcessRunning(orphanPid)) {
4527
4528
  console.log(`[Tunnel] EP877: Killing orphaned process ${orphanPid} for ${moduleUid} before starting new tunnel`);
4528
4529
  this.killByPid(orphanPid, "SIGTERM");
4529
- await new Promise((resolve9) => setTimeout(resolve9, 500));
4530
+ await new Promise((resolve10) => setTimeout(resolve10, 500));
4530
4531
  if (this.isProcessRunning(orphanPid)) {
4531
4532
  this.killByPid(orphanPid, "SIGKILL");
4532
4533
  }
@@ -4535,7 +4536,7 @@ var TunnelManager = class extends import_events.EventEmitter {
4535
4536
  const killedOnPort = await this.killCloudflaredOnPort(port);
4536
4537
  if (killedOnPort.length > 0) {
4537
4538
  console.log(`[Tunnel] EP904: Pre-start port cleanup killed ${killedOnPort.length} process(es) on port ${port}`);
4538
- await new Promise((resolve9) => setTimeout(resolve9, 1e3));
4539
+ await new Promise((resolve10) => setTimeout(resolve10, 1e3));
4539
4540
  }
4540
4541
  const cleanup = await this.cleanupOrphanedProcesses();
4541
4542
  if (cleanup.cleaned > 0) {
@@ -4575,7 +4576,7 @@ var TunnelManager = class extends import_events.EventEmitter {
4575
4576
  if (orphanPid && this.isProcessRunning(orphanPid)) {
4576
4577
  console.log(`[Tunnel] EP877: Stopping orphaned process ${orphanPid} for ${moduleUid} via PID file`);
4577
4578
  this.killByPid(orphanPid, "SIGTERM");
4578
- await new Promise((resolve9) => setTimeout(resolve9, 1e3));
4579
+ await new Promise((resolve10) => setTimeout(resolve10, 1e3));
4579
4580
  if (this.isProcessRunning(orphanPid)) {
4580
4581
  this.killByPid(orphanPid, "SIGKILL");
4581
4582
  }
@@ -4591,16 +4592,16 @@ var TunnelManager = class extends import_events.EventEmitter {
4591
4592
  const tunnel = state.info;
4592
4593
  if (tunnel.process && !tunnel.process.killed) {
4593
4594
  tunnel.process.kill("SIGTERM");
4594
- await new Promise((resolve9) => {
4595
+ await new Promise((resolve10) => {
4595
4596
  const timeout = setTimeout(() => {
4596
4597
  if (tunnel.process && !tunnel.process.killed) {
4597
4598
  tunnel.process.kill("SIGKILL");
4598
4599
  }
4599
- resolve9();
4600
+ resolve10();
4600
4601
  }, 3e3);
4601
4602
  tunnel.process.once("exit", () => {
4602
4603
  clearTimeout(timeout);
4603
- resolve9();
4604
+ resolve10();
4604
4605
  });
4605
4606
  });
4606
4607
  }
@@ -4972,15 +4973,15 @@ async function writeToStdinWithBackpressure(process2, data, drainTimeoutMs, labe
4972
4973
  if (!stdin || stdin.destroyed) {
4973
4974
  throw new Error(`[${label}] stdin not available. session=${sessionId}`);
4974
4975
  }
4975
- await new Promise((resolve9, reject) => {
4976
+ await new Promise((resolve10, reject) => {
4976
4977
  const ok = stdin.write(data);
4977
4978
  if (ok) {
4978
- resolve9();
4979
+ resolve10();
4979
4980
  return;
4980
4981
  }
4981
4982
  const onDrain = () => {
4982
4983
  cleanup();
4983
- resolve9();
4984
+ resolve10();
4984
4985
  };
4985
4986
  const onError = (err) => {
4986
4987
  cleanup();
@@ -5001,18 +5002,18 @@ async function writeToStdinWithBackpressure(process2, data, drainTimeoutMs, labe
5001
5002
  });
5002
5003
  }
5003
5004
  function waitForProcessExit(process2, alive, timeoutMs) {
5004
- return new Promise((resolve9) => {
5005
+ return new Promise((resolve10) => {
5005
5006
  if (!process2 || !alive) {
5006
- resolve9(true);
5007
+ resolve10(true);
5007
5008
  return;
5008
5009
  }
5009
5010
  const onExit = () => {
5010
5011
  clearTimeout(timer);
5011
- resolve9(true);
5012
+ resolve10(true);
5012
5013
  };
5013
5014
  const timer = setTimeout(() => {
5014
5015
  process2.removeListener("exit", onExit);
5015
- resolve9(false);
5016
+ resolve10(false);
5016
5017
  }, timeoutMs);
5017
5018
  process2.once("exit", onExit);
5018
5019
  });
@@ -6008,10 +6009,10 @@ var CodexPersistentRuntime = class {
6008
6009
  }
6009
6010
  waitForThreadId(timeoutMs) {
6010
6011
  if (this._agentSessionId) return Promise.resolve(this._agentSessionId);
6011
- return new Promise((resolve9, reject) => {
6012
+ return new Promise((resolve10, reject) => {
6012
6013
  const onId = (id) => {
6013
6014
  clearTimeout(timer);
6014
- resolve9(id);
6015
+ resolve10(id);
6015
6016
  };
6016
6017
  const timer = setTimeout(() => {
6017
6018
  this.threadIdWaiters = this.threadIdWaiters.filter((w) => w !== onId);
@@ -6042,12 +6043,12 @@ var CodexPersistentRuntime = class {
6042
6043
  sendRequest(method, params, timeoutMs = INIT_TIMEOUT_MS) {
6043
6044
  const id = this.nextId++;
6044
6045
  const msg = { jsonrpc: "2.0", id, method, params };
6045
- return new Promise(async (resolve9, reject) => {
6046
+ return new Promise(async (resolve10, reject) => {
6046
6047
  const timeout = setTimeout(() => {
6047
6048
  this.pending.delete(id);
6048
6049
  reject(new Error(`JSON-RPC timeout: ${method}`));
6049
6050
  }, timeoutMs);
6050
- this.pending.set(id, { resolve: resolve9, reject, timeout });
6051
+ this.pending.set(id, { resolve: resolve10, reject, timeout });
6051
6052
  try {
6052
6053
  await this.writeToStdin(JSON.stringify(msg) + "\n");
6053
6054
  } catch (err) {
@@ -6197,11 +6198,11 @@ var UnifiedAgentRuntime = class {
6197
6198
  if (!this.currentTurn && this.impl.turnState === "idle") {
6198
6199
  return this.dispatchTurn(message, callbacks);
6199
6200
  }
6200
- return new Promise((resolve9, reject) => {
6201
+ return new Promise((resolve10, reject) => {
6201
6202
  this.queuedTurns.push({
6202
6203
  message,
6203
6204
  callbacks,
6204
- resolve: resolve9,
6205
+ resolve: resolve10,
6205
6206
  reject
6206
6207
  });
6207
6208
  });
@@ -7719,13 +7720,13 @@ async function getChildProcessRssMb(pid) {
7719
7720
  if (!pid || pid <= 0) return null;
7720
7721
  try {
7721
7722
  if (typeof import_child_process10.execFile !== "function") return null;
7722
- const stdout = await new Promise((resolve9, reject) => {
7723
+ const stdout = await new Promise((resolve10, reject) => {
7723
7724
  (0, import_child_process10.execFile)("ps", ["-o", "rss=", "-p", String(pid)], { timeout: 1e3 }, (err, out) => {
7724
7725
  if (err) {
7725
7726
  reject(err);
7726
7727
  return;
7727
7728
  }
7728
- resolve9(String(out));
7729
+ resolve10(String(out));
7729
7730
  });
7730
7731
  });
7731
7732
  const kb = Number(String(stdout).trim());
@@ -7828,8 +7829,8 @@ var AgentControlPlane = class {
7828
7829
  async withConfigLock(fn) {
7829
7830
  const previousLock = this.configWriteLock;
7830
7831
  let releaseLock;
7831
- this.configWriteLock = new Promise((resolve9) => {
7832
- releaseLock = resolve9;
7832
+ this.configWriteLock = new Promise((resolve10) => {
7833
+ releaseLock = resolve10;
7833
7834
  });
7834
7835
  try {
7835
7836
  await previousLock;
@@ -9058,7 +9059,7 @@ var WorktreeManager = class _WorktreeManager {
9058
9059
  const lockContent = fs15.readFileSync(lockPath, "utf-8").trim();
9059
9060
  const lockPid = parseInt(lockContent, 10);
9060
9061
  if (!isNaN(lockPid) && this.isProcessRunning(lockPid)) {
9061
- await new Promise((resolve9) => setTimeout(resolve9, retryInterval));
9062
+ await new Promise((resolve10) => setTimeout(resolve10, retryInterval));
9062
9063
  continue;
9063
9064
  }
9064
9065
  } catch {
@@ -9072,7 +9073,7 @@ var WorktreeManager = class _WorktreeManager {
9072
9073
  } catch {
9073
9074
  continue;
9074
9075
  }
9075
- await new Promise((resolve9) => setTimeout(resolve9, retryInterval));
9076
+ await new Promise((resolve10) => setTimeout(resolve10, retryInterval));
9076
9077
  continue;
9077
9078
  }
9078
9079
  throw err;
@@ -9180,9 +9181,9 @@ var WorktreeManager = class _WorktreeManager {
9180
9181
  const worktree = config.worktrees.find((w) => w.moduleUid === moduleUid);
9181
9182
  if (worktree) {
9182
9183
  worktree.setupStatus = status;
9183
- if (status === "setup") {
9184
+ if (status === "provisioning") {
9184
9185
  worktree.setupStartedAt = (/* @__PURE__ */ new Date()).toISOString();
9185
- } else if (status === "ready" || status === "error") {
9186
+ } else if (status === "verified" || status === "error") {
9186
9187
  worktree.setupCompletedAt = (/* @__PURE__ */ new Date()).toISOString();
9187
9188
  }
9188
9189
  if (error) {
@@ -9392,7 +9393,7 @@ async function resolveAgentWorkingDirectory(options) {
9392
9393
  command,
9393
9394
  projectPath,
9394
9395
  getWorktreeInfoForModule: getWorktreeInfoForModule2,
9395
- pathExists = async (candidatePath) => {
9396
+ pathExists: pathExists2 = async (candidatePath) => {
9396
9397
  try {
9397
9398
  await fs16.promises.access(candidatePath);
9398
9399
  return true;
@@ -9412,7 +9413,7 @@ async function resolveAgentWorkingDirectory(options) {
9412
9413
  if (command.sessionContext === "project_root") {
9413
9414
  if (command.workspaceSlug && command.projectSlug) {
9414
9415
  const resolvedProjectPath = getProjectPath(command.workspaceSlug, command.projectSlug);
9415
- if (resolvedProjectPath !== projectPath && await pathExists(resolvedProjectPath)) {
9416
+ if (resolvedProjectPath !== projectPath && await pathExists2(resolvedProjectPath)) {
9416
9417
  return resolvedProjectPath;
9417
9418
  }
9418
9419
  }
@@ -10597,7 +10598,7 @@ async function handleExec(command, projectPath) {
10597
10598
  env = {}
10598
10599
  } = command;
10599
10600
  const effectiveTimeout = Math.min(Math.max(timeout, 1e3), MAX_TIMEOUT);
10600
- return new Promise((resolve9) => {
10601
+ return new Promise((resolve10) => {
10601
10602
  let stdout = "";
10602
10603
  let stderr = "";
10603
10604
  let timedOut = false;
@@ -10605,7 +10606,7 @@ async function handleExec(command, projectPath) {
10605
10606
  const done = (result) => {
10606
10607
  if (resolved) return;
10607
10608
  resolved = true;
10608
- resolve9(result);
10609
+ resolve10(result);
10609
10610
  };
10610
10611
  try {
10611
10612
  const proc = (0, import_child_process12.spawn)(cmd, {
@@ -10709,18 +10710,18 @@ var import_core14 = __toESM(require_dist());
10709
10710
  // src/utils/port-check.ts
10710
10711
  var net2 = __toESM(require("net"));
10711
10712
  async function isPortInUse(port) {
10712
- return new Promise((resolve9) => {
10713
+ return new Promise((resolve10) => {
10713
10714
  const server = net2.createServer();
10714
10715
  server.once("error", (err) => {
10715
10716
  if (err.code === "EADDRINUSE") {
10716
- resolve9(true);
10717
+ resolve10(true);
10717
10718
  } else {
10718
- resolve9(false);
10719
+ resolve10(false);
10719
10720
  }
10720
10721
  });
10721
10722
  server.once("listening", () => {
10722
10723
  server.close();
10723
- resolve9(false);
10724
+ resolve10(false);
10724
10725
  });
10725
10726
  server.listen(port);
10726
10727
  });
@@ -11123,7 +11124,7 @@ var DevServerRegistry = class {
11123
11124
  return killed;
11124
11125
  }
11125
11126
  wait(ms) {
11126
- return new Promise((resolve9) => setTimeout(resolve9, ms));
11127
+ return new Promise((resolve10) => setTimeout(resolve10, ms));
11127
11128
  }
11128
11129
  killWsServerOnPort(wsPort, worktreePath) {
11129
11130
  const killed = [];
@@ -11697,7 +11698,7 @@ var DevServerRunner = class extends import_events2.EventEmitter {
11697
11698
  return Math.min(delay, DEV_SERVER_CONSTANTS.MAX_RESTART_DELAY_MS);
11698
11699
  }
11699
11700
  async checkHealth(port) {
11700
- return new Promise((resolve9) => {
11701
+ return new Promise((resolve10) => {
11701
11702
  const req = http.request(
11702
11703
  {
11703
11704
  hostname: "localhost",
@@ -11706,18 +11707,18 @@ var DevServerRunner = class extends import_events2.EventEmitter {
11706
11707
  method: "HEAD",
11707
11708
  timeout: DEV_SERVER_CONSTANTS.HEALTH_CHECK_TIMEOUT_MS
11708
11709
  },
11709
- () => resolve9(true)
11710
+ () => resolve10(true)
11710
11711
  );
11711
- req.on("error", () => resolve9(false));
11712
+ req.on("error", () => resolve10(false));
11712
11713
  req.on("timeout", () => {
11713
11714
  req.destroy();
11714
- resolve9(false);
11715
+ resolve10(false);
11715
11716
  });
11716
11717
  req.end();
11717
11718
  });
11718
11719
  }
11719
11720
  async checkWsHealth(wsPort) {
11720
- return new Promise((resolve9) => {
11721
+ return new Promise((resolve10) => {
11721
11722
  const req = http.request(
11722
11723
  {
11723
11724
  hostname: "127.0.0.1",
@@ -11727,14 +11728,14 @@ var DevServerRunner = class extends import_events2.EventEmitter {
11727
11728
  timeout: DEV_SERVER_CONSTANTS.HEALTH_CHECK_TIMEOUT_MS
11728
11729
  },
11729
11730
  (res) => {
11730
- resolve9(res.statusCode === 200);
11731
+ resolve10(res.statusCode === 200);
11731
11732
  res.resume();
11732
11733
  }
11733
11734
  );
11734
- req.on("error", () => resolve9(false));
11735
+ req.on("error", () => resolve10(false));
11735
11736
  req.on("timeout", () => {
11736
11737
  req.destroy();
11737
- resolve9(false);
11738
+ resolve10(false);
11738
11739
  });
11739
11740
  req.end();
11740
11741
  });
@@ -11762,7 +11763,7 @@ var DevServerRunner = class extends import_events2.EventEmitter {
11762
11763
  return false;
11763
11764
  }
11764
11765
  wait(ms) {
11765
- return new Promise((resolve9) => setTimeout(resolve9, ms));
11766
+ return new Promise((resolve10) => setTimeout(resolve10, ms));
11766
11767
  }
11767
11768
  getLogsDir() {
11768
11769
  const logsDir = path26.join((0, import_core14.getConfigDir)(), "logs");
@@ -11961,7 +11962,7 @@ var PreviewManager = class extends import_events3.EventEmitter {
11961
11962
  for (let attempt = 1; attempt <= MAX_TUNNEL_RETRIES; attempt++) {
11962
11963
  if (attempt > 1) {
11963
11964
  console.log(`[PreviewManager] Retrying tunnel for ${moduleUid} (attempt ${attempt}/${MAX_TUNNEL_RETRIES})...`);
11964
- await new Promise((resolve9) => setTimeout(resolve9, 2e3));
11965
+ await new Promise((resolve10) => setTimeout(resolve10, 2e3));
11965
11966
  }
11966
11967
  tunnelResult = await this.tunnel.startTunnel({
11967
11968
  moduleUid,
@@ -12093,7 +12094,7 @@ var PreviewManager = class extends import_events3.EventEmitter {
12093
12094
  }
12094
12095
  console.log(`[PreviewManager] Restarting preview for ${moduleUid}`);
12095
12096
  await this.stopPreview(moduleUid);
12096
- await new Promise((resolve9) => setTimeout(resolve9, 1e3));
12097
+ await new Promise((resolve10) => setTimeout(resolve10, 1e3));
12097
12098
  return this.startPreview({
12098
12099
  moduleUid,
12099
12100
  worktreePath: state.worktreePath,
@@ -12628,6 +12629,92 @@ async function autoDetectSetupScript(worktreePath) {
12628
12629
  console.log(`[Worktree] EP1222: Detected ${name} (${language}) via ${detection.matchedFile}`);
12629
12630
  return installCmd;
12630
12631
  }
12632
+ function isPathWithinRoot(candidatePath, rootPath) {
12633
+ const relative5 = path29.relative(rootPath, candidatePath);
12634
+ return relative5 === "" || !relative5.startsWith("..") && !path29.isAbsolute(relative5);
12635
+ }
12636
+ async function pathExists(candidatePath) {
12637
+ try {
12638
+ await fs29.promises.access(candidatePath, fs29.constants.F_OK);
12639
+ return true;
12640
+ } catch {
12641
+ return false;
12642
+ }
12643
+ }
12644
+ async function resolveGitPath(worktreePath, gitPathName) {
12645
+ try {
12646
+ const { stdout } = await execAsync2(`git -C "${worktreePath}" rev-parse --git-path ${gitPathName}`);
12647
+ return stdout.trim() || null;
12648
+ } catch {
12649
+ return null;
12650
+ }
12651
+ }
12652
+ async function handleWorktreeVerify(command, projectPath) {
12653
+ const projectRoot = path29.resolve(projectPath);
12654
+ const candidatePath = path29.resolve(command.worktreePath);
12655
+ const checkedAt = (/* @__PURE__ */ new Date()).toISOString();
12656
+ const issues = [];
12657
+ const exists = await pathExists(candidatePath);
12658
+ const withinProjectRoot = exists && isPathWithinRoot(candidatePath, projectRoot);
12659
+ let gitWorktreeValid = false;
12660
+ let observedBranch = null;
12661
+ let structurallySound = true;
12662
+ if (!exists) {
12663
+ issues.push("PATH_MISSING");
12664
+ }
12665
+ if (exists && !withinProjectRoot) {
12666
+ issues.push("OUTSIDE_PROJECT_ROOT");
12667
+ }
12668
+ if (exists && withinProjectRoot) {
12669
+ try {
12670
+ await execAsync2(`git -C "${candidatePath}" rev-parse --is-inside-work-tree`);
12671
+ gitWorktreeValid = true;
12672
+ } catch {
12673
+ issues.push("INVALID_GIT_WORKTREE");
12674
+ }
12675
+ }
12676
+ if (gitWorktreeValid) {
12677
+ try {
12678
+ const { stdout } = await execAsync2(`git -C "${candidatePath}" rev-parse --abbrev-ref HEAD`);
12679
+ observedBranch = stdout.trim() || null;
12680
+ } catch {
12681
+ observedBranch = null;
12682
+ }
12683
+ const brokenMarkers = await Promise.all([
12684
+ resolveGitPath(candidatePath, "MERGE_HEAD"),
12685
+ resolveGitPath(candidatePath, "REBASE_HEAD"),
12686
+ resolveGitPath(candidatePath, "rebase-merge"),
12687
+ resolveGitPath(candidatePath, "rebase-apply")
12688
+ ]);
12689
+ const markerExists = await Promise.all(
12690
+ brokenMarkers.filter((value) => Boolean(value)).map((value) => pathExists(value))
12691
+ );
12692
+ if (markerExists.some(Boolean)) {
12693
+ structurallySound = false;
12694
+ issues.push("BROKEN_STATE");
12695
+ }
12696
+ }
12697
+ const branchMatches = command.expectedBranch ? observedBranch === command.expectedBranch : true;
12698
+ if (command.expectedBranch && !branchMatches) {
12699
+ issues.push("BRANCH_MISMATCH");
12700
+ }
12701
+ const verification = {
12702
+ checkedAt,
12703
+ path: candidatePath,
12704
+ projectRoot,
12705
+ exists,
12706
+ withinProjectRoot,
12707
+ gitWorktreeValid,
12708
+ branchMatches,
12709
+ structurallySound,
12710
+ observedBranch,
12711
+ issues
12712
+ };
12713
+ return {
12714
+ success: true,
12715
+ verification
12716
+ };
12717
+ }
12631
12718
  async function handleWorktreeCreate(request2) {
12632
12719
  const {
12633
12720
  workspaceSlug,
@@ -12741,11 +12828,11 @@ ${buildCmd}` : buildCmd;
12741
12828
  setTimeout(() => {
12742
12829
  void (async () => {
12743
12830
  if (!effectiveSetupScript) {
12744
- await manager.updateWorktreeStatus(moduleUid, "ready");
12831
+ await manager.updateWorktreeStatus(moduleUid, "provisioning");
12745
12832
  return;
12746
12833
  }
12747
12834
  const setupStartMs = Date.now();
12748
- await manager.updateWorktreeStatus(moduleUid, "setup");
12835
+ await manager.updateWorktreeStatus(moduleUid, "provisioning");
12749
12836
  console.log(`[Worktree] EP1143: Running setup script asynchronously...`);
12750
12837
  const scriptResult = await manager.runSetupScript(moduleUid, effectiveSetupScript);
12751
12838
  console.log(`[Worktree] EP1373: setup_script phase=worktree_setup durationMs=${Date.now() - setupStartMs} moduleUid=${moduleUid} correlationId=${correlationId || "none"} success=${scriptResult.success}`);
@@ -12754,7 +12841,7 @@ ${buildCmd}` : buildCmd;
12754
12841
  await manager.updateWorktreeStatus(moduleUid, "error", scriptResult.error);
12755
12842
  return;
12756
12843
  }
12757
- await manager.updateWorktreeStatus(moduleUid, "ready");
12844
+ await manager.updateWorktreeStatus(moduleUid, "provisioning");
12758
12845
  })().catch(async (setupError) => {
12759
12846
  const errorMessage = setupError instanceof Error ? setupError.message : String(setupError);
12760
12847
  console.error(`[Worktree] EP1458: Async setup failed for ${moduleUid}: ${errorMessage}`);
@@ -12767,7 +12854,7 @@ ${buildCmd}` : buildCmd;
12767
12854
  }, 0);
12768
12855
  let previewUrl;
12769
12856
  let port;
12770
- const finalStatus = effectiveSetupScript ? "setup" : "ready";
12857
+ const finalStatus = "provisioning";
12771
12858
  if (moduleType === "ops") {
12772
12859
  console.log(`[Worktree] EP1363: Skipping preview for ops module ${moduleUid}`);
12773
12860
  } else {
@@ -13087,6 +13174,19 @@ var CODEX_BANNER_SIGNAL = /(openai codex|\bmodel:)/i;
13087
13174
  var CODEX_PROMPT_SIGNAL = /(?:^|\n)\s*(?:>|❯)\s*$/m;
13088
13175
  var MAX_CODEX_STARTUP_READY_TIMEOUT_MS = 3e4;
13089
13176
  var sessions = /* @__PURE__ */ new Map();
13177
+ function bestEffortTerminateProcessGroup(session) {
13178
+ if (process.platform === "win32") {
13179
+ return;
13180
+ }
13181
+ const pid = session.pty.pid;
13182
+ if (!pid || pid <= 0) {
13183
+ return;
13184
+ }
13185
+ try {
13186
+ process.kill(-pid, "SIGTERM");
13187
+ } catch {
13188
+ }
13189
+ }
13090
13190
  function killPtySessionsForModule(moduleUid) {
13091
13191
  const killedRunIds = [];
13092
13192
  for (const [id, session] of sessions.entries()) {
@@ -13095,6 +13195,7 @@ function killPtySessionsForModule(moduleUid) {
13095
13195
  }
13096
13196
  if (session.watchdogTimer) clearTimeout(session.watchdogTimer);
13097
13197
  try {
13198
+ bestEffortTerminateProcessGroup(session);
13098
13199
  session.pty.kill();
13099
13200
  killedRunIds.push(id);
13100
13201
  } catch {
@@ -13221,6 +13322,7 @@ async function handlePtySpawn(payload, client) {
13221
13322
  if (session.watchdogTimer) clearTimeout(session.watchdogTimer);
13222
13323
  console.log(`[PTY] Process exited for ${agent_run_id} with code ${exitCode} after ${durationMs}ms`);
13223
13324
  sessions.delete(agent_run_id);
13325
+ bestEffortTerminateProcessGroup(session);
13224
13326
  client.send({
13225
13327
  type: "pty_exit",
13226
13328
  moduleUid,
@@ -13277,6 +13379,7 @@ function handlePtyKill(payload) {
13277
13379
  return;
13278
13380
  }
13279
13381
  try {
13382
+ bestEffortTerminateProcessGroup(session);
13280
13383
  session.pty.kill();
13281
13384
  console.log(`[PTY] Kill signal sent for session ${agent_run_id}`);
13282
13385
  } catch {
@@ -13366,8 +13469,8 @@ function createStartupState(payload, resolvedArgs) {
13366
13469
  const mode = payload.run_type === "persistent" ? trimmedStdin.length > 0 ? "seed_after_prompt" : "prompt_ready" : "first_output";
13367
13470
  let resolveReady;
13368
13471
  let rejectReady;
13369
- const waitForReady = new Promise((resolve9, reject) => {
13370
- resolveReady = resolve9;
13472
+ const waitForReady = new Promise((resolve10, reject) => {
13473
+ resolveReady = resolve10;
13371
13474
  rejectReady = reject;
13372
13475
  });
13373
13476
  const startup = {
@@ -13659,7 +13762,7 @@ async function killProcessOnPort(port) {
13659
13762
  } catch {
13660
13763
  }
13661
13764
  }
13662
- await new Promise((resolve9) => setTimeout(resolve9, 1e3));
13765
+ await new Promise((resolve10) => setTimeout(resolve10, 1e3));
13663
13766
  for (const pid of pids) {
13664
13767
  try {
13665
13768
  (0, import_child_process16.execSync)(`kill -0 ${pid} 2>/dev/null`, { encoding: "utf8" });
@@ -13668,7 +13771,7 @@ async function killProcessOnPort(port) {
13668
13771
  } catch {
13669
13772
  }
13670
13773
  }
13671
- await new Promise((resolve9) => setTimeout(resolve9, 500));
13774
+ await new Promise((resolve10) => setTimeout(resolve10, 500));
13672
13775
  const stillInUse = await isPortInUse(port);
13673
13776
  if (stillInUse) {
13674
13777
  console.error(`[DevServer] EP929: Port ${port} still in use after kill attempts`);
@@ -13688,7 +13791,7 @@ async function waitForPort(port, timeoutMs = 3e4) {
13688
13791
  if (await isPortInUse(port)) {
13689
13792
  return true;
13690
13793
  }
13691
- await new Promise((resolve9) => setTimeout(resolve9, checkInterval));
13794
+ await new Promise((resolve10) => setTimeout(resolve10, checkInterval));
13692
13795
  }
13693
13796
  return false;
13694
13797
  }
@@ -13760,7 +13863,7 @@ async function handleProcessExit(moduleUid, code, signal) {
13760
13863
  const delay = calculateRestartDelay(serverInfo.restartCount);
13761
13864
  console.log(`[DevServer] EP932: Restarting ${moduleUid} in ${delay}ms (attempt ${serverInfo.restartCount + 1}/${MAX_RESTART_ATTEMPTS})`);
13762
13865
  writeToLog(serverInfo.logFile || "", `Scheduling restart in ${delay}ms (attempt ${serverInfo.restartCount + 1})`, false);
13763
- await new Promise((resolve9) => setTimeout(resolve9, delay));
13866
+ await new Promise((resolve10) => setTimeout(resolve10, delay));
13764
13867
  if (!activeServers.has(moduleUid)) {
13765
13868
  console.log(`[DevServer] EP932: Server ${moduleUid} was removed during restart delay, aborting restart`);
13766
13869
  return;
@@ -13885,7 +13988,7 @@ async function stopDevServer(moduleUid) {
13885
13988
  writeToLog(serverInfo.logFile, `Stopping server (manual stop)`, false);
13886
13989
  }
13887
13990
  serverInfo.process.kill("SIGTERM");
13888
- await new Promise((resolve9) => setTimeout(resolve9, 2e3));
13991
+ await new Promise((resolve10) => setTimeout(resolve10, 2e3));
13889
13992
  if (!serverInfo.process.killed) {
13890
13993
  serverInfo.process.kill("SIGKILL");
13891
13994
  }
@@ -13903,7 +14006,7 @@ async function restartDevServer(moduleUid) {
13903
14006
  writeToLog(logFile, `Manual restart requested`, false);
13904
14007
  }
13905
14008
  await stopDevServer(moduleUid);
13906
- await new Promise((resolve9) => setTimeout(resolve9, 1e3));
14009
+ await new Promise((resolve10) => setTimeout(resolve10, 1e3));
13907
14010
  if (await isPortInUse(port)) {
13908
14011
  await killProcessOnPort(port);
13909
14012
  }
@@ -14024,7 +14127,7 @@ var IPCRouter = class {
14024
14127
  if (attempt < MAX_RETRIES) {
14025
14128
  const delay = INITIAL_DELAY * Math.pow(2, attempt - 1);
14026
14129
  console.log(`[Daemon] Retrying in ${delay / 1e3}s...`);
14027
- await new Promise((resolve9) => setTimeout(resolve9, delay));
14130
+ await new Promise((resolve10) => setTimeout(resolve10, delay));
14028
14131
  await this.host.disconnectProject(projectPath);
14029
14132
  }
14030
14133
  }
@@ -14988,7 +15091,7 @@ var ConnectionManager = class {
14988
15091
  * handlers are removed deterministically on every exit path.
14989
15092
  */
14990
15093
  async waitForAuthentication(client, timeoutMs = 3e4) {
14991
- await new Promise((resolve9, reject) => {
15094
+ await new Promise((resolve10, reject) => {
14992
15095
  let settled = false;
14993
15096
  const cleanup = () => {
14994
15097
  clearTimeout(timeout);
@@ -15007,7 +15110,7 @@ var ConnectionManager = class {
15007
15110
  if (settled) return;
15008
15111
  settled = true;
15009
15112
  cleanup();
15010
- resolve9();
15113
+ resolve10();
15011
15114
  };
15012
15115
  const authErrorHandler = (message) => {
15013
15116
  if (settled) return;
@@ -15222,6 +15325,9 @@ var ProjectMessageRouter = class {
15222
15325
  case "worktree:release":
15223
15326
  result = await handleWorktreeRelease(cmd);
15224
15327
  break;
15328
+ case "worktree:verify":
15329
+ result = await handleWorktreeVerify(cmd, projectPath);
15330
+ break;
15225
15331
  case "worktree:list":
15226
15332
  result = await handleWorktreeList(
15227
15333
  cmd.workspaceSlug,
@@ -15680,8 +15786,8 @@ async function cacheMachineUuid(machineUuid, machineId) {
15680
15786
  // src/daemon/reconciliation-utils.ts
15681
15787
  var path36 = __toESM(require("path"));
15682
15788
  function isPathUnderRoot(candidatePath, projectRoot) {
15683
- const relative4 = path36.relative(projectRoot, candidatePath);
15684
- return relative4 !== "" && !relative4.startsWith("..") && !path36.isAbsolute(relative4);
15789
+ const relative5 = path36.relative(projectRoot, candidatePath);
15790
+ return relative5 !== "" && !relative5.startsWith("..") && !path36.isAbsolute(relative5);
15685
15791
  }
15686
15792
  function collectUnexpectedWorktrees(params) {
15687
15793
  const projectRootResolved = path36.resolve(params.projectRoot);
@@ -16051,8 +16157,8 @@ var Daemon = class _Daemon {
16051
16157
  }
16052
16158
  }
16053
16159
  let releaseLock;
16054
- const lockPromise = new Promise((resolve9) => {
16055
- releaseLock = resolve9;
16160
+ const lockPromise = new Promise((resolve10) => {
16161
+ releaseLock = resolve10;
16056
16162
  });
16057
16163
  this.tunnelOperationLocks.set(moduleUid, lockPromise);
16058
16164
  try {
@@ -16098,7 +16204,7 @@ var Daemon = class _Daemon {
16098
16204
  const maxWait = 35e3;
16099
16205
  const startTime = Date.now();
16100
16206
  while (this.connectionManager.hasPendingConnection(projectPath) && Date.now() - startTime < maxWait) {
16101
- await new Promise((resolve9) => setTimeout(resolve9, 500));
16207
+ await new Promise((resolve10) => setTimeout(resolve10, 500));
16102
16208
  }
16103
16209
  if (this.connectionManager.hasLiveConnection(projectPath)) {
16104
16210
  console.log(`[Daemon] Pending connection succeeded for ${projectPath}`);
@@ -17168,8 +17274,8 @@ var Daemon = class _Daemon {
17168
17274
  */
17169
17275
  async runWorktreeSetupSync(moduleUid, worktreeManager, copyFiles, setupScript, worktreePath, envVars = {}) {
17170
17276
  console.log(`[Daemon] EP1002: Running worktree setup for ${moduleUid}`);
17171
- await worktreeManager.updateWorktreeStatus(moduleUid, "setup");
17172
- await this.updateModuleWorktreeStatus(moduleUid, "setup", worktreePath);
17277
+ await worktreeManager.updateWorktreeStatus(moduleUid, "provisioning");
17278
+ await this.updateModuleWorktreeStatus(moduleUid, "provisioning", worktreePath);
17173
17279
  if (Object.keys(envVars).length > 0) {
17174
17280
  console.log(`[Daemon] EP1002: Writing .env with ${Object.keys(envVars).length} variables`);
17175
17281
  writeEnvFile(worktreePath, envVars);
@@ -17223,12 +17329,12 @@ var Daemon = class _Daemon {
17223
17329
  throw new Error(`Setup script failed: ${scriptResult.error}`);
17224
17330
  }
17225
17331
  }
17226
- await worktreeManager.updateWorktreeStatus(moduleUid, "ready");
17227
- await this.updateModuleWorktreeStatus(moduleUid, "ready", worktreePath);
17332
+ await worktreeManager.updateWorktreeStatus(moduleUid, "provisioning");
17333
+ await this.updateModuleWorktreeStatus(moduleUid, "provisioning", worktreePath);
17228
17334
  console.log(`[Daemon] EP1002: Worktree setup complete for ${moduleUid}`);
17229
17335
  }
17230
17336
  async runForegroundCommand(command, args, cwd, env, timeoutMs) {
17231
- await new Promise((resolve9, reject) => {
17337
+ await new Promise((resolve10, reject) => {
17232
17338
  const commandLabel = `${command} ${args.join(" ")}`.trim();
17233
17339
  const child = (0, import_child_process18.spawn)(command, args, {
17234
17340
  cwd,
@@ -17251,7 +17357,7 @@ var Daemon = class _Daemon {
17251
17357
  reject(error);
17252
17358
  return;
17253
17359
  }
17254
- resolve9();
17360
+ resolve10();
17255
17361
  };
17256
17362
  termTimer = setTimeout(() => {
17257
17363
  timedOut = true;