@episoda/cli 0.2.215 → 0.2.216

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.
@@ -3051,7 +3051,7 @@ var require_package = __commonJS({
3051
3051
  "package.json"(exports2, module2) {
3052
3052
  module2.exports = {
3053
3053
  name: "@episoda/cli",
3054
- version: "0.2.215",
3054
+ version: "0.2.216",
3055
3055
  description: "CLI tool for Episoda local development workflow orchestration",
3056
3056
  main: "dist/index.js",
3057
3057
  types: "dist/index.d.ts",
@@ -4804,6 +4804,93 @@ async function ensureCodexBinary() {
4804
4804
 
4805
4805
  // src/agent/providers/codex-config.ts
4806
4806
  var DEFAULT_CODEX_MODEL = "gpt-5.4";
4807
+ var SUPPORTED_CODEX_PTY_MODELS = ["gpt-5.4", "gpt-5.3-codex"];
4808
+ function stripUnsupportedCodexFlags(args) {
4809
+ const sanitized = [];
4810
+ for (let index = 0; index < args.length; index += 1) {
4811
+ const current = args[index];
4812
+ if (current === "--effort") {
4813
+ index += 1;
4814
+ continue;
4815
+ }
4816
+ if (current.startsWith("--effort=")) {
4817
+ continue;
4818
+ }
4819
+ sanitized.push(current);
4820
+ }
4821
+ return sanitized;
4822
+ }
4823
+ function extractRequestedModel(args) {
4824
+ for (let index = 0; index < args.length; index += 1) {
4825
+ if (args[index] === "--model") {
4826
+ const candidate = args[index + 1];
4827
+ return typeof candidate === "string" && candidate.trim().length > 0 ? candidate.trim() : null;
4828
+ }
4829
+ }
4830
+ return null;
4831
+ }
4832
+ function resolveSupportedCodexModel(model) {
4833
+ const normalized = (model || "").trim();
4834
+ if (SUPPORTED_CODEX_PTY_MODELS.includes(normalized)) {
4835
+ return normalized;
4836
+ }
4837
+ if (normalized.toLowerCase().endsWith("-high")) {
4838
+ return DEFAULT_CODEX_MODEL;
4839
+ }
4840
+ return DEFAULT_CODEX_MODEL;
4841
+ }
4842
+ function upsertModelArg(args, model) {
4843
+ const nextArgs = [...args];
4844
+ for (let index = 0; index < nextArgs.length; index += 1) {
4845
+ if (nextArgs[index] === "--model") {
4846
+ if (index + 1 < nextArgs.length) {
4847
+ nextArgs[index + 1] = model;
4848
+ return nextArgs;
4849
+ }
4850
+ nextArgs.push(model);
4851
+ return nextArgs;
4852
+ }
4853
+ }
4854
+ if (nextArgs[0] === "exec") {
4855
+ return ["exec", "--model", model, ...nextArgs.slice(1)];
4856
+ }
4857
+ return ["--model", model, ...nextArgs];
4858
+ }
4859
+ function resolveCodexExecutionConfig(options) {
4860
+ const requestedModel = options.preferredModel || extractRequestedModel(options.args || []);
4861
+ const model = resolveSupportedCodexModel(requestedModel);
4862
+ const env = { ...options.env || {} };
4863
+ if (Array.isArray(options.args) && options.args.length > 0) {
4864
+ return {
4865
+ model,
4866
+ args: upsertModelArg(stripUnsupportedCodexFlags(options.args), model),
4867
+ env
4868
+ };
4869
+ }
4870
+ const runType = options.runType || "persistent";
4871
+ const prompt = options.prompt || "";
4872
+ const useYolo = options.useYolo !== false;
4873
+ const effortArgs = options.effort ? ["-c", `reasoning_effort="${options.effort}"`] : [];
4874
+ if (runType === "persistent") {
4875
+ return {
4876
+ model,
4877
+ args: ["--model", model, "--yolo", "--sandbox", "danger-full-access"],
4878
+ env
4879
+ };
4880
+ }
4881
+ if (useYolo) {
4882
+ return {
4883
+ model,
4884
+ args: ["--model", model, ...effortArgs, "--yolo", "--sandbox", "danger-full-access", prompt],
4885
+ env
4886
+ };
4887
+ }
4888
+ return {
4889
+ model,
4890
+ args: ["exec", "--json", "--model", model, ...effortArgs, "--sandbox", "danger-full-access", "--skip-git-repo-check", prompt],
4891
+ env
4892
+ };
4893
+ }
4807
4894
  function generateCodexAuthJson(credentials) {
4808
4895
  const tokens = {
4809
4896
  id_token: credentials.idToken || credentials.accessToken,
@@ -12991,8 +13078,10 @@ var fs31 = __toESM(require("fs"));
12991
13078
  var os14 = __toESM(require("os"));
12992
13079
  var path31 = __toESM(require("path"));
12993
13080
  var INACTIVITY_TIMEOUT_MS3 = 30 * 60 * 1e3;
12994
- var CODEX_READINESS_SIGNAL = /(?:\d+% left ·|\bmodel:\s+gpt-)/i;
12995
13081
  var ANSI_ESCAPE_CODE_REGEX = /\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])/g;
13082
+ var CODEX_BANNER_SIGNAL = /(openai codex|\bmodel:)/i;
13083
+ var CODEX_PROMPT_SIGNAL = /(?:^|\n)\s*(?:>|❯)\s*$/m;
13084
+ var MAX_CODEX_STARTUP_READY_TIMEOUT_MS = 3e4;
12996
13085
  var sessions = /* @__PURE__ */ new Map();
12997
13086
  function killPtySessionsForModule(moduleUid) {
12998
13087
  const killedRunIds = [];
@@ -13031,16 +13120,30 @@ async function handlePtySpawn(payload, client) {
13031
13120
  console.log(`[PTY] Spawning PTY for ${moduleUid} / ${agent_run_id}: ${command} ${args.join(" ")}`);
13032
13121
  let bootstrap = null;
13033
13122
  let proc;
13123
+ let modelUsed;
13124
+ let launchConfig;
13125
+ let spawnArgs = args;
13034
13126
  try {
13035
13127
  bootstrap = createCredentialBootstrap(payload, agent_run_id);
13036
- proc = pty.spawn(command, args, {
13128
+ const executionConfig = command === "codex" ? resolveCodexExecutionConfig({ args, env }) : null;
13129
+ spawnArgs = executionConfig?.args ?? args;
13130
+ const spawnEnv = executionConfig?.env ?? (env || {});
13131
+ modelUsed = executionConfig?.model;
13132
+ launchConfig = buildPtyLaunchConfig({
13133
+ command,
13134
+ args: spawnArgs,
13135
+ env: spawnEnv,
13136
+ cwd: cwd || process.cwd(),
13137
+ bootstrap
13138
+ });
13139
+ proc = pty.spawn(command, spawnArgs, {
13037
13140
  name: "xterm-256color",
13038
13141
  cols,
13039
13142
  rows,
13040
13143
  cwd: cwd || process.cwd(),
13041
13144
  env: {
13042
13145
  ...process.env,
13043
- ...env || {},
13146
+ ...spawnEnv,
13044
13147
  ...bootstrap.env
13045
13148
  }
13046
13149
  });
@@ -13058,7 +13161,10 @@ async function handlePtySpawn(payload, client) {
13058
13161
  });
13059
13162
  return {
13060
13163
  success: false,
13061
- error: err?.message || `Failed to spawn PTY command '${command}'`
13164
+ error: err?.message || `Failed to spawn PTY command '${command}'`,
13165
+ modelUsed,
13166
+ launchConfig,
13167
+ authPath: bootstrap?.authPath
13062
13168
  };
13063
13169
  }
13064
13170
  const session = {
@@ -13070,7 +13176,7 @@ async function handlePtySpawn(payload, client) {
13070
13176
  lastOutputAt: Date.now(),
13071
13177
  watchdogTimer: null,
13072
13178
  credentialDirs: bootstrap.cleanupDirs,
13073
- startup: createStartupState(payload)
13179
+ startup: createStartupState(payload, spawnArgs)
13074
13180
  };
13075
13181
  sessions.set(agent_run_id, session);
13076
13182
  const resetWatchdog = () => {
@@ -13087,7 +13193,7 @@ async function handlePtySpawn(payload, client) {
13087
13193
  resetWatchdog();
13088
13194
  proc.onData((data) => {
13089
13195
  resetWatchdog();
13090
- maybeSeedBufferedInitialPrompt(session, data);
13196
+ handleStartupData(session, data);
13091
13197
  client.send({
13092
13198
  type: "pty_data",
13093
13199
  moduleUid,
@@ -13103,7 +13209,8 @@ async function handlePtySpawn(payload, client) {
13103
13209
  proc.onExit(({ exitCode }) => {
13104
13210
  if (session.startup && !session.startup.readinessObserved) {
13105
13211
  session.startup.markFailed(
13106
- `Codex PTY exited before startup readiness for ${agent_run_id} (exit code ${exitCode}).`
13212
+ `Codex PTY exited before startup readiness for ${agent_run_id} (exit code ${exitCode}).`,
13213
+ session.startup.failureClass || "EXIT_BEFORE_READY"
13107
13214
  );
13108
13215
  }
13109
13216
  const durationMs = Date.now() - session.startedAt;
@@ -13128,11 +13235,22 @@ async function handlePtySpawn(payload, client) {
13128
13235
  } catch (error) {
13129
13236
  return {
13130
13237
  success: false,
13131
- error: error?.message || "Codex PTY failed before startup readiness"
13238
+ error: error?.message || "Codex PTY failed before startup readiness",
13239
+ startupFailureClass: session.startup.failureClass,
13240
+ startupConfirmedAt: session.startup.startupConfirmedAt,
13241
+ modelUsed,
13242
+ launchConfig,
13243
+ authPath: bootstrap.authPath
13132
13244
  };
13133
13245
  }
13134
13246
  }
13135
- return { success: true };
13247
+ return {
13248
+ success: true,
13249
+ startupConfirmedAt: session.startup?.startupConfirmedAt,
13250
+ modelUsed,
13251
+ launchConfig,
13252
+ authPath: bootstrap.authPath
13253
+ };
13136
13254
  }
13137
13255
  function handlePtyResize(payload) {
13138
13256
  const { agent_run_id, cols, rows } = payload;
@@ -13207,29 +13325,40 @@ function createCredentialBootstrap(payload, agentRunId) {
13207
13325
  fs31.writeFileSync(credentialsPath, JSON.stringify({ claudeAiOauth }, null, 2), { mode: 384 });
13208
13326
  return {
13209
13327
  env: { CLAUDE_CONFIG_DIR: claudeConfigDir },
13210
- cleanupDirs
13328
+ cleanupDirs,
13329
+ authPath: credentialsPath
13211
13330
  };
13212
13331
  }
13213
13332
  const codexHome = path31.join(baseDir, ".codex");
13214
13333
  fs31.mkdirSync(codexHome, { recursive: true });
13334
+ const trustedProjectRoot = resolveCodexTrustedProjectRoot(payload);
13215
13335
  const configFiles = generateCodexConfig({
13216
13336
  accessToken: bootstrap.oauth.access_token,
13217
13337
  idToken: bootstrap.oauth.id_token,
13218
13338
  accountId: bootstrap.oauth.account_id
13219
- }, payload.cwd);
13220
- fs31.writeFileSync(path31.join(codexHome, "auth.json"), configFiles["auth.json"], { mode: 384 });
13339
+ }, trustedProjectRoot);
13340
+ const authPath = path31.join(codexHome, "auth.json");
13341
+ const configPath = path31.join(codexHome, "config.toml");
13342
+ fs31.writeFileSync(authPath, configFiles["auth.json"], { mode: 384 });
13221
13343
  if (configFiles["config.toml"]) {
13222
- fs31.writeFileSync(path31.join(codexHome, "config.toml"), configFiles["config.toml"], { mode: 384 });
13344
+ fs31.writeFileSync(configPath, configFiles["config.toml"], { mode: 384 });
13223
13345
  }
13224
13346
  return {
13225
13347
  env: { CODEX_HOME: codexHome },
13226
- cleanupDirs
13348
+ cleanupDirs,
13349
+ authPath,
13350
+ configPath,
13351
+ codexHome,
13352
+ trustedProjectRoot
13227
13353
  };
13228
13354
  }
13229
- function createStartupState(payload) {
13230
- if (payload.run_type !== "persistent" || payload.command !== "codex" || typeof payload.stdin !== "string" || payload.stdin.trim().length === 0) {
13355
+ function createStartupState(payload, resolvedArgs) {
13356
+ if (payload.command !== "codex") {
13231
13357
  return void 0;
13232
13358
  }
13359
+ const trimmedStdin = typeof payload.stdin === "string" ? payload.stdin.trim() : "";
13360
+ const trimmedArgvPrompt = payload.run_type === "persistent" ? "" : resolveCodexArgvPrompt(resolvedArgs);
13361
+ const mode = payload.run_type === "persistent" ? trimmedStdin.length > 0 ? "seed_after_prompt" : "prompt_ready" : "first_output";
13233
13362
  let resolveReady;
13234
13363
  let rejectReady;
13235
13364
  const waitForReady = new Promise((resolve9, reject) => {
@@ -13237,10 +13366,14 @@ function createStartupState(payload) {
13237
13366
  rejectReady = reject;
13238
13367
  });
13239
13368
  const startup = {
13240
- pendingInitialStdin: payload.stdin,
13369
+ mode,
13370
+ pendingInitialStdin: typeof payload.stdin === "string" ? payload.stdin : "",
13371
+ pendingInitialArgvPrompt: trimmedArgvPrompt,
13241
13372
  earlyOutput: "",
13373
+ postSeedOutput: "",
13374
+ bannerObserved: false,
13242
13375
  readinessObserved: false,
13243
- initialPromptSeeded: false,
13376
+ initialPromptSeeded: mode !== "seed_after_prompt",
13244
13377
  readinessTimer: null,
13245
13378
  settled: false,
13246
13379
  waitForReady,
@@ -13250,9 +13383,10 @@ function createStartupState(payload) {
13250
13383
  if (startup.readinessTimer) clearTimeout(startup.readinessTimer);
13251
13384
  resolveReady();
13252
13385
  },
13253
- markFailed: (error) => {
13386
+ markFailed: (error, failureClass) => {
13254
13387
  if (startup.settled) return;
13255
13388
  startup.settled = true;
13389
+ startup.failureClass = failureClass;
13256
13390
  if (startup.readinessTimer) clearTimeout(startup.readinessTimer);
13257
13391
  rejectReady(new Error(error));
13258
13392
  }
@@ -13266,9 +13400,9 @@ function armStartupTimeout(session, proc) {
13266
13400
  }
13267
13401
  const timeoutMs = getCodexStartupReadyTimeoutMs();
13268
13402
  startup.readinessTimer = setTimeout(() => {
13269
- const error = `Codex PTY readiness timeout after ${timeoutMs}ms for ${session.agent_run_id}.`;
13403
+ const error = startup.mode === "seed_after_prompt" ? startup.initialPromptSeeded ? `STARTUP_TIMEOUT: Codex PTY startup acceptance was not observed within ${timeoutMs}ms for ${session.agent_run_id}.` : `STARTUP_TIMEOUT: Codex PTY prompt was not observed within ${timeoutMs}ms for ${session.agent_run_id}.` : startup.mode === "prompt_ready" ? `STARTUP_TIMEOUT: Codex PTY prompt was not observed within ${timeoutMs}ms for ${session.agent_run_id}.` : `STARTUP_TIMEOUT: Codex PTY startup output was not observed within ${timeoutMs}ms for ${session.agent_run_id}.`;
13270
13404
  console.error(`[PTY] EP1498: ${error}`);
13271
- startup.markFailed(error);
13405
+ startup.markFailed(error, "STARTUP_TIMEOUT");
13272
13406
  try {
13273
13407
  proc.kill();
13274
13408
  } catch (killError) {
@@ -13276,29 +13410,162 @@ function armStartupTimeout(session, proc) {
13276
13410
  }
13277
13411
  }, timeoutMs);
13278
13412
  }
13279
- function maybeSeedBufferedInitialPrompt(session, data) {
13413
+ function handleStartupData(session, data) {
13280
13414
  const startup = session.startup;
13281
- if (!startup || startup.initialPromptSeeded) {
13415
+ if (!startup) {
13282
13416
  return;
13283
13417
  }
13284
- if (!startup.readinessObserved) {
13285
- startup.earlyOutput += data;
13418
+ startup.earlyOutput += data;
13419
+ const normalizedEarlyOutput = normalizeCodexStartupOutput(startup.earlyOutput);
13420
+ const detectedFailure = detectCodexStartupFailure(normalizedEarlyOutput);
13421
+ if (detectedFailure) {
13422
+ const error = `${detectedFailure.failureClass}: ${detectedFailure.message}`;
13423
+ console.error(`[PTY] EP1514: ${error}`);
13424
+ startup.markFailed(error, detectedFailure.failureClass);
13425
+ try {
13426
+ session.pty.kill();
13427
+ } catch (killError) {
13428
+ console.warn(`[PTY] EP1514: Failed to kill failed startup PTY for ${session.agent_run_id}:`, killError);
13429
+ }
13430
+ return;
13286
13431
  }
13287
- const normalizedEarlyOutput = startup.earlyOutput.replace(ANSI_ESCAPE_CODE_REGEX, "");
13288
- if (!startup.readinessObserved && CODEX_READINESS_SIGNAL.test(normalizedEarlyOutput)) {
13289
- startup.readinessObserved = true;
13290
- startup.earlyOutput = "";
13432
+ if (!startup.bannerObserved && CODEX_BANNER_SIGNAL.test(normalizedEarlyOutput)) {
13433
+ startup.bannerObserved = true;
13291
13434
  }
13292
- if (!startup.readinessObserved) {
13435
+ if (startup.mode === "seed_after_prompt" && !startup.initialPromptSeeded) {
13436
+ if (!startup.bannerObserved || !CODEX_PROMPT_SIGNAL.test(normalizedEarlyOutput)) {
13437
+ return;
13438
+ }
13439
+ session.pty.write(`${startup.pendingInitialStdin}\r`);
13440
+ startup.initialPromptSeeded = true;
13441
+ startup.postSeedOutput = "";
13293
13442
  return;
13294
13443
  }
13295
- session.pty.write(`${startup.pendingInitialStdin}\r`);
13296
- startup.initialPromptSeeded = true;
13444
+ if (startup.mode === "prompt_ready") {
13445
+ if (!startup.bannerObserved || !CODEX_PROMPT_SIGNAL.test(normalizedEarlyOutput)) {
13446
+ return;
13447
+ }
13448
+ } else {
13449
+ startup.postSeedOutput += data;
13450
+ const normalizedPostSeedOutput = normalizeCodexStartupOutput(
13451
+ startup.mode === "seed_after_prompt" ? startup.postSeedOutput : startup.earlyOutput
13452
+ );
13453
+ const readinessOutput = startup.mode === "first_output" ? stripEchoedCodexStartupInput(normalizedPostSeedOutput, startup.pendingInitialArgvPrompt) : normalizedPostSeedOutput;
13454
+ if (!hasMeaningfulCodexStartupAcceptance(readinessOutput, [startup.pendingInitialStdin])) {
13455
+ return;
13456
+ }
13457
+ }
13458
+ if (startup.readinessObserved) {
13459
+ return;
13460
+ }
13461
+ startup.readinessObserved = true;
13462
+ startup.startupConfirmedAt = (/* @__PURE__ */ new Date()).toISOString();
13297
13463
  startup.markReady();
13298
13464
  }
13299
13465
  function getCodexStartupReadyTimeoutMs() {
13300
- const parsed = Number(process.env.EPISODA_CODEX_READY_TIMEOUT_MS || "8000");
13301
- return Number.isFinite(parsed) && parsed > 0 ? parsed : 8e3;
13466
+ const parsed = Number(process.env.EPISODA_CODEX_READY_TIMEOUT_MS || String(MAX_CODEX_STARTUP_READY_TIMEOUT_MS));
13467
+ if (!Number.isFinite(parsed) || parsed <= 0) {
13468
+ return MAX_CODEX_STARTUP_READY_TIMEOUT_MS;
13469
+ }
13470
+ return Math.min(parsed, MAX_CODEX_STARTUP_READY_TIMEOUT_MS);
13471
+ }
13472
+ function detectCodexStartupFailure(normalizedOutput) {
13473
+ const loweredOutput = normalizedOutput.toLowerCase();
13474
+ if (loweredOutput.includes("do you trust the contents of this directory?")) {
13475
+ return {
13476
+ failureClass: "TRUST_PROMPT_STALL",
13477
+ message: "Codex prompted for directory trust during non-interactive startup."
13478
+ };
13479
+ }
13480
+ if (loweredOutput.includes("access token could not be refreshed")) {
13481
+ return {
13482
+ failureClass: "OAUTH_REFRESH_ROTATION_CONFLICT",
13483
+ message: "Codex attempted refresh-token rotation against externally managed auth."
13484
+ };
13485
+ }
13486
+ if (loweredOutput.includes("--effort") && (loweredOutput.includes("unknown option") || loweredOutput.includes("unexpected argument") || loweredOutput.includes("unrecognized option") || loweredOutput.includes("unexpected value"))) {
13487
+ return {
13488
+ failureClass: "UNSUPPORTED_FLAG",
13489
+ message: "Codex rejected the unsupported --effort launch flag."
13490
+ };
13491
+ }
13492
+ if (/\b(?:unknown|invalid|unsupported)\b[^\n]*\bmodel\b/i.test(normalizedOutput) || /\bmodel\b[^\n]*(?:not supported|unsupported|unknown|invalid)\b/i.test(normalizedOutput) || /\b(?:400|bad request)\b[^\n]*\bmodel\b/i.test(normalizedOutput)) {
13493
+ return {
13494
+ failureClass: "MODEL_UNSUPPORTED",
13495
+ message: "Codex rejected an unsupported model during startup."
13496
+ };
13497
+ }
13498
+ return null;
13499
+ }
13500
+ function normalizeCodexStartupOutput(output) {
13501
+ return output.replace(ANSI_ESCAPE_CODE_REGEX, "").replace(/\r/g, "");
13502
+ }
13503
+ function hasMeaningfulCodexStartupAcceptance(output, echoedInputs) {
13504
+ const withoutEchoes = echoedInputs.reduce((currentOutput, echoedInput) => {
13505
+ return stripEchoedCodexStartupInput(currentOutput, echoedInput);
13506
+ }, output);
13507
+ const sanitized = withoutEchoes.replace(/(?:^|\n)\s*openai codex\s*(?=\n|$)/gi, "\n").replace(/(?:^|\n)\s*model:[^\n]*/gi, "\n").replace(CODEX_PROMPT_SIGNAL, "").replace(/\s+/g, "");
13508
+ return sanitized.length > 0;
13509
+ }
13510
+ function stripEchoedCodexStartupInput(output, echoedInput) {
13511
+ const normalizedEcho = echoedInput.trim();
13512
+ if (normalizedEcho.length === 0) {
13513
+ return output;
13514
+ }
13515
+ let strippedOutput = output.replace(new RegExp(escapeRegExp(normalizedEcho), "g"), "");
13516
+ const whitespaceFlexiblePattern = buildWhitespaceFlexiblePattern(normalizedEcho);
13517
+ if (whitespaceFlexiblePattern) {
13518
+ strippedOutput = strippedOutput.replace(whitespaceFlexiblePattern, "");
13519
+ }
13520
+ return strippedOutput;
13521
+ }
13522
+ function buildWhitespaceFlexiblePattern(value) {
13523
+ const normalizedValue = value.trim().replace(/\s+/g, " ");
13524
+ if (normalizedValue.length === 0) {
13525
+ return null;
13526
+ }
13527
+ return new RegExp(normalizedValue.split(" ").map(escapeRegExp).join("\\s+"), "g");
13528
+ }
13529
+ function resolveCodexArgvPrompt(args) {
13530
+ const positionalArgs = [];
13531
+ for (let index = 0; index < args.length; index += 1) {
13532
+ const current = args[index];
13533
+ if (!current) {
13534
+ continue;
13535
+ }
13536
+ if (current === "--model" || current === "--sandbox" || current === "-c") {
13537
+ index += 1;
13538
+ continue;
13539
+ }
13540
+ if (current.startsWith("--model=") || current.startsWith("--sandbox=") || current.startsWith("-c=") || current.startsWith("--")) {
13541
+ continue;
13542
+ }
13543
+ positionalArgs.push(current);
13544
+ }
13545
+ return positionalArgs.length === 0 ? "" : positionalArgs[positionalArgs.length - 1].trim();
13546
+ }
13547
+ function escapeRegExp(value) {
13548
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
13549
+ }
13550
+ function buildPtyLaunchConfig(params) {
13551
+ const { command, args, env, cwd, bootstrap } = params;
13552
+ const launchConfig = {
13553
+ command,
13554
+ args,
13555
+ env,
13556
+ cwd
13557
+ };
13558
+ if (bootstrap?.authPath) {
13559
+ launchConfig.auth_path = bootstrap.authPath;
13560
+ }
13561
+ if (bootstrap?.configPath) {
13562
+ launchConfig.config_path = bootstrap.configPath;
13563
+ }
13564
+ if (bootstrap?.codexHome) {
13565
+ launchConfig.codex_home = bootstrap.codexHome;
13566
+ launchConfig.trusted_project_root = bootstrap.trustedProjectRoot || null;
13567
+ }
13568
+ return launchConfig;
13302
13569
  }
13303
13570
  function cleanupCredentialDirs(dirs) {
13304
13571
  for (const dirPath of dirs) {
@@ -13311,6 +13578,17 @@ function cleanupCredentialDirs(dirs) {
13311
13578
  }
13312
13579
  }
13313
13580
  }
13581
+ function resolveCodexTrustedProjectRoot(payload) {
13582
+ const cwd = typeof payload.cwd === "string" ? payload.cwd.trim() : "";
13583
+ const envWorktreeDir = typeof payload.env?.EPISODA_WORKTREE_DIR === "string" ? payload.env.EPISODA_WORKTREE_DIR.trim() : "";
13584
+ if (cwd.length > 0) {
13585
+ return cwd;
13586
+ }
13587
+ if (envWorktreeDir.length > 0) {
13588
+ return envWorktreeDir;
13589
+ }
13590
+ return process.cwd();
13591
+ }
13314
13592
 
13315
13593
  // src/utils/dev-server.ts
13316
13594
  var import_child_process16 = require("child_process");
@@ -15102,7 +15380,12 @@ var ProjectMessageRouter = class {
15102
15380
  moduleUid: resolvedPayload.moduleUid,
15103
15381
  agent_run_id: resolvedPayload.agent_run_id,
15104
15382
  success: result.success,
15105
- error: result.error
15383
+ error: result.error,
15384
+ startupFailureClass: result.startupFailureClass,
15385
+ startupConfirmedAt: result.startupConfirmedAt,
15386
+ modelUsed: result.modelUsed,
15387
+ launchConfig: result.launchConfig,
15388
+ authPath: result.authPath
15106
15389
  });
15107
15390
  }
15108
15391
  });