@episoda/cli 0.2.215 → 0.2.217

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.217",
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,
@@ -7126,6 +7213,10 @@ ${message}`;
7126
7213
  if (useApiKey && session.credentials.apiKey) {
7127
7214
  envVars.ANTHROPIC_API_KEY = session.credentials.apiKey;
7128
7215
  }
7216
+ if (session.credentials.oauthToken) {
7217
+ envVars.CLAUDE_CODE_OAUTH_TOKEN = session.credentials.oauthToken;
7218
+ console.log("[ClaudeProvider] EP1519: Set CLAUDE_CODE_OAUTH_TOKEN for headless OAuth");
7219
+ }
7129
7220
  envVars.CLAUDE_CODE_DISABLE_PLUGIN_CACHE = "1";
7130
7221
  }
7131
7222
  applyFollowupReadOnlyReminder(message, readOnlyReason) {
@@ -12991,8 +13082,10 @@ var fs31 = __toESM(require("fs"));
12991
13082
  var os14 = __toESM(require("os"));
12992
13083
  var path31 = __toESM(require("path"));
12993
13084
  var INACTIVITY_TIMEOUT_MS3 = 30 * 60 * 1e3;
12994
- var CODEX_READINESS_SIGNAL = /(?:\d+% left ·|\bmodel:\s+gpt-)/i;
12995
13085
  var ANSI_ESCAPE_CODE_REGEX = /\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])/g;
13086
+ var CODEX_BANNER_SIGNAL = /(openai codex|\bmodel:)/i;
13087
+ var CODEX_PROMPT_SIGNAL = /(?:^|\n)\s*(?:>|❯)\s*$/m;
13088
+ var MAX_CODEX_STARTUP_READY_TIMEOUT_MS = 3e4;
12996
13089
  var sessions = /* @__PURE__ */ new Map();
12997
13090
  function killPtySessionsForModule(moduleUid) {
12998
13091
  const killedRunIds = [];
@@ -13031,16 +13124,30 @@ async function handlePtySpawn(payload, client) {
13031
13124
  console.log(`[PTY] Spawning PTY for ${moduleUid} / ${agent_run_id}: ${command} ${args.join(" ")}`);
13032
13125
  let bootstrap = null;
13033
13126
  let proc;
13127
+ let modelUsed;
13128
+ let launchConfig;
13129
+ let spawnArgs = args;
13034
13130
  try {
13035
13131
  bootstrap = createCredentialBootstrap(payload, agent_run_id);
13036
- proc = pty.spawn(command, args, {
13132
+ const executionConfig = command === "codex" ? resolveCodexExecutionConfig({ args, env }) : null;
13133
+ spawnArgs = executionConfig?.args ?? args;
13134
+ const spawnEnv = executionConfig?.env ?? (env || {});
13135
+ modelUsed = executionConfig?.model;
13136
+ launchConfig = buildPtyLaunchConfig({
13137
+ command,
13138
+ args: spawnArgs,
13139
+ env: spawnEnv,
13140
+ cwd: cwd || process.cwd(),
13141
+ bootstrap
13142
+ });
13143
+ proc = pty.spawn(command, spawnArgs, {
13037
13144
  name: "xterm-256color",
13038
13145
  cols,
13039
13146
  rows,
13040
13147
  cwd: cwd || process.cwd(),
13041
13148
  env: {
13042
13149
  ...process.env,
13043
- ...env || {},
13150
+ ...spawnEnv,
13044
13151
  ...bootstrap.env
13045
13152
  }
13046
13153
  });
@@ -13058,7 +13165,10 @@ async function handlePtySpawn(payload, client) {
13058
13165
  });
13059
13166
  return {
13060
13167
  success: false,
13061
- error: err?.message || `Failed to spawn PTY command '${command}'`
13168
+ error: err?.message || `Failed to spawn PTY command '${command}'`,
13169
+ modelUsed,
13170
+ launchConfig,
13171
+ authPath: bootstrap?.authPath
13062
13172
  };
13063
13173
  }
13064
13174
  const session = {
@@ -13070,7 +13180,7 @@ async function handlePtySpawn(payload, client) {
13070
13180
  lastOutputAt: Date.now(),
13071
13181
  watchdogTimer: null,
13072
13182
  credentialDirs: bootstrap.cleanupDirs,
13073
- startup: createStartupState(payload)
13183
+ startup: createStartupState(payload, spawnArgs)
13074
13184
  };
13075
13185
  sessions.set(agent_run_id, session);
13076
13186
  const resetWatchdog = () => {
@@ -13087,7 +13197,7 @@ async function handlePtySpawn(payload, client) {
13087
13197
  resetWatchdog();
13088
13198
  proc.onData((data) => {
13089
13199
  resetWatchdog();
13090
- maybeSeedBufferedInitialPrompt(session, data);
13200
+ handleStartupData(session, data);
13091
13201
  client.send({
13092
13202
  type: "pty_data",
13093
13203
  moduleUid,
@@ -13103,7 +13213,8 @@ async function handlePtySpawn(payload, client) {
13103
13213
  proc.onExit(({ exitCode }) => {
13104
13214
  if (session.startup && !session.startup.readinessObserved) {
13105
13215
  session.startup.markFailed(
13106
- `Codex PTY exited before startup readiness for ${agent_run_id} (exit code ${exitCode}).`
13216
+ `Codex PTY exited before startup readiness for ${agent_run_id} (exit code ${exitCode}).`,
13217
+ session.startup.failureClass || "EXIT_BEFORE_READY"
13107
13218
  );
13108
13219
  }
13109
13220
  const durationMs = Date.now() - session.startedAt;
@@ -13128,11 +13239,22 @@ async function handlePtySpawn(payload, client) {
13128
13239
  } catch (error) {
13129
13240
  return {
13130
13241
  success: false,
13131
- error: error?.message || "Codex PTY failed before startup readiness"
13242
+ error: error?.message || "Codex PTY failed before startup readiness",
13243
+ startupFailureClass: session.startup.failureClass,
13244
+ startupConfirmedAt: session.startup.startupConfirmedAt,
13245
+ modelUsed,
13246
+ launchConfig,
13247
+ authPath: bootstrap.authPath
13132
13248
  };
13133
13249
  }
13134
13250
  }
13135
- return { success: true };
13251
+ return {
13252
+ success: true,
13253
+ startupConfirmedAt: session.startup?.startupConfirmedAt,
13254
+ modelUsed,
13255
+ launchConfig,
13256
+ authPath: bootstrap.authPath
13257
+ };
13136
13258
  }
13137
13259
  function handlePtyResize(payload) {
13138
13260
  const { agent_run_id, cols, rows } = payload;
@@ -13207,29 +13329,40 @@ function createCredentialBootstrap(payload, agentRunId) {
13207
13329
  fs31.writeFileSync(credentialsPath, JSON.stringify({ claudeAiOauth }, null, 2), { mode: 384 });
13208
13330
  return {
13209
13331
  env: { CLAUDE_CONFIG_DIR: claudeConfigDir },
13210
- cleanupDirs
13332
+ cleanupDirs,
13333
+ authPath: credentialsPath
13211
13334
  };
13212
13335
  }
13213
13336
  const codexHome = path31.join(baseDir, ".codex");
13214
13337
  fs31.mkdirSync(codexHome, { recursive: true });
13338
+ const trustedProjectRoot = resolveCodexTrustedProjectRoot(payload);
13215
13339
  const configFiles = generateCodexConfig({
13216
13340
  accessToken: bootstrap.oauth.access_token,
13217
13341
  idToken: bootstrap.oauth.id_token,
13218
13342
  accountId: bootstrap.oauth.account_id
13219
- }, payload.cwd);
13220
- fs31.writeFileSync(path31.join(codexHome, "auth.json"), configFiles["auth.json"], { mode: 384 });
13343
+ }, trustedProjectRoot);
13344
+ const authPath = path31.join(codexHome, "auth.json");
13345
+ const configPath = path31.join(codexHome, "config.toml");
13346
+ fs31.writeFileSync(authPath, configFiles["auth.json"], { mode: 384 });
13221
13347
  if (configFiles["config.toml"]) {
13222
- fs31.writeFileSync(path31.join(codexHome, "config.toml"), configFiles["config.toml"], { mode: 384 });
13348
+ fs31.writeFileSync(configPath, configFiles["config.toml"], { mode: 384 });
13223
13349
  }
13224
13350
  return {
13225
13351
  env: { CODEX_HOME: codexHome },
13226
- cleanupDirs
13352
+ cleanupDirs,
13353
+ authPath,
13354
+ configPath,
13355
+ codexHome,
13356
+ trustedProjectRoot
13227
13357
  };
13228
13358
  }
13229
- function createStartupState(payload) {
13230
- if (payload.run_type !== "persistent" || payload.command !== "codex" || typeof payload.stdin !== "string" || payload.stdin.trim().length === 0) {
13359
+ function createStartupState(payload, resolvedArgs) {
13360
+ if (payload.command !== "codex") {
13231
13361
  return void 0;
13232
13362
  }
13363
+ const trimmedStdin = typeof payload.stdin === "string" ? payload.stdin.trim() : "";
13364
+ const trimmedArgvPrompt = payload.run_type === "persistent" ? "" : resolveCodexArgvPrompt(resolvedArgs);
13365
+ const mode = payload.run_type === "persistent" ? trimmedStdin.length > 0 ? "seed_after_prompt" : "prompt_ready" : "first_output";
13233
13366
  let resolveReady;
13234
13367
  let rejectReady;
13235
13368
  const waitForReady = new Promise((resolve9, reject) => {
@@ -13237,10 +13370,14 @@ function createStartupState(payload) {
13237
13370
  rejectReady = reject;
13238
13371
  });
13239
13372
  const startup = {
13240
- pendingInitialStdin: payload.stdin,
13373
+ mode,
13374
+ pendingInitialStdin: typeof payload.stdin === "string" ? payload.stdin : "",
13375
+ pendingInitialArgvPrompt: trimmedArgvPrompt,
13241
13376
  earlyOutput: "",
13377
+ postSeedOutput: "",
13378
+ bannerObserved: false,
13242
13379
  readinessObserved: false,
13243
- initialPromptSeeded: false,
13380
+ initialPromptSeeded: mode !== "seed_after_prompt",
13244
13381
  readinessTimer: null,
13245
13382
  settled: false,
13246
13383
  waitForReady,
@@ -13250,9 +13387,10 @@ function createStartupState(payload) {
13250
13387
  if (startup.readinessTimer) clearTimeout(startup.readinessTimer);
13251
13388
  resolveReady();
13252
13389
  },
13253
- markFailed: (error) => {
13390
+ markFailed: (error, failureClass) => {
13254
13391
  if (startup.settled) return;
13255
13392
  startup.settled = true;
13393
+ startup.failureClass = failureClass;
13256
13394
  if (startup.readinessTimer) clearTimeout(startup.readinessTimer);
13257
13395
  rejectReady(new Error(error));
13258
13396
  }
@@ -13266,9 +13404,9 @@ function armStartupTimeout(session, proc) {
13266
13404
  }
13267
13405
  const timeoutMs = getCodexStartupReadyTimeoutMs();
13268
13406
  startup.readinessTimer = setTimeout(() => {
13269
- const error = `Codex PTY readiness timeout after ${timeoutMs}ms for ${session.agent_run_id}.`;
13407
+ 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
13408
  console.error(`[PTY] EP1498: ${error}`);
13271
- startup.markFailed(error);
13409
+ startup.markFailed(error, "STARTUP_TIMEOUT");
13272
13410
  try {
13273
13411
  proc.kill();
13274
13412
  } catch (killError) {
@@ -13276,29 +13414,162 @@ function armStartupTimeout(session, proc) {
13276
13414
  }
13277
13415
  }, timeoutMs);
13278
13416
  }
13279
- function maybeSeedBufferedInitialPrompt(session, data) {
13417
+ function handleStartupData(session, data) {
13280
13418
  const startup = session.startup;
13281
- if (!startup || startup.initialPromptSeeded) {
13419
+ if (!startup) {
13282
13420
  return;
13283
13421
  }
13284
- if (!startup.readinessObserved) {
13285
- startup.earlyOutput += data;
13422
+ startup.earlyOutput += data;
13423
+ const normalizedEarlyOutput = normalizeCodexStartupOutput(startup.earlyOutput);
13424
+ const detectedFailure = detectCodexStartupFailure(normalizedEarlyOutput);
13425
+ if (detectedFailure) {
13426
+ const error = `${detectedFailure.failureClass}: ${detectedFailure.message}`;
13427
+ console.error(`[PTY] EP1514: ${error}`);
13428
+ startup.markFailed(error, detectedFailure.failureClass);
13429
+ try {
13430
+ session.pty.kill();
13431
+ } catch (killError) {
13432
+ console.warn(`[PTY] EP1514: Failed to kill failed startup PTY for ${session.agent_run_id}:`, killError);
13433
+ }
13434
+ return;
13435
+ }
13436
+ if (!startup.bannerObserved && CODEX_BANNER_SIGNAL.test(normalizedEarlyOutput)) {
13437
+ startup.bannerObserved = true;
13286
13438
  }
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 = "";
13439
+ if (startup.mode === "seed_after_prompt" && !startup.initialPromptSeeded) {
13440
+ if (!startup.bannerObserved || !CODEX_PROMPT_SIGNAL.test(normalizedEarlyOutput)) {
13441
+ return;
13442
+ }
13443
+ session.pty.write(`${startup.pendingInitialStdin}\r`);
13444
+ startup.initialPromptSeeded = true;
13445
+ startup.postSeedOutput = "";
13446
+ return;
13447
+ }
13448
+ if (startup.mode === "prompt_ready") {
13449
+ if (!startup.bannerObserved || !CODEX_PROMPT_SIGNAL.test(normalizedEarlyOutput)) {
13450
+ return;
13451
+ }
13452
+ } else {
13453
+ startup.postSeedOutput += data;
13454
+ const normalizedPostSeedOutput = normalizeCodexStartupOutput(
13455
+ startup.mode === "seed_after_prompt" ? startup.postSeedOutput : startup.earlyOutput
13456
+ );
13457
+ const readinessOutput = startup.mode === "first_output" ? stripEchoedCodexStartupInput(normalizedPostSeedOutput, startup.pendingInitialArgvPrompt) : normalizedPostSeedOutput;
13458
+ if (!hasMeaningfulCodexStartupAcceptance(readinessOutput, [startup.pendingInitialStdin])) {
13459
+ return;
13460
+ }
13291
13461
  }
13292
- if (!startup.readinessObserved) {
13462
+ if (startup.readinessObserved) {
13293
13463
  return;
13294
13464
  }
13295
- session.pty.write(`${startup.pendingInitialStdin}\r`);
13296
- startup.initialPromptSeeded = true;
13465
+ startup.readinessObserved = true;
13466
+ startup.startupConfirmedAt = (/* @__PURE__ */ new Date()).toISOString();
13297
13467
  startup.markReady();
13298
13468
  }
13299
13469
  function getCodexStartupReadyTimeoutMs() {
13300
- const parsed = Number(process.env.EPISODA_CODEX_READY_TIMEOUT_MS || "8000");
13301
- return Number.isFinite(parsed) && parsed > 0 ? parsed : 8e3;
13470
+ const parsed = Number(process.env.EPISODA_CODEX_READY_TIMEOUT_MS || String(MAX_CODEX_STARTUP_READY_TIMEOUT_MS));
13471
+ if (!Number.isFinite(parsed) || parsed <= 0) {
13472
+ return MAX_CODEX_STARTUP_READY_TIMEOUT_MS;
13473
+ }
13474
+ return Math.min(parsed, MAX_CODEX_STARTUP_READY_TIMEOUT_MS);
13475
+ }
13476
+ function detectCodexStartupFailure(normalizedOutput) {
13477
+ const loweredOutput = normalizedOutput.toLowerCase();
13478
+ if (loweredOutput.includes("do you trust the contents of this directory?")) {
13479
+ return {
13480
+ failureClass: "TRUST_PROMPT_STALL",
13481
+ message: "Codex prompted for directory trust during non-interactive startup."
13482
+ };
13483
+ }
13484
+ if (loweredOutput.includes("access token could not be refreshed")) {
13485
+ return {
13486
+ failureClass: "OAUTH_REFRESH_ROTATION_CONFLICT",
13487
+ message: "Codex attempted refresh-token rotation against externally managed auth."
13488
+ };
13489
+ }
13490
+ if (loweredOutput.includes("--effort") && (loweredOutput.includes("unknown option") || loweredOutput.includes("unexpected argument") || loweredOutput.includes("unrecognized option") || loweredOutput.includes("unexpected value"))) {
13491
+ return {
13492
+ failureClass: "UNSUPPORTED_FLAG",
13493
+ message: "Codex rejected the unsupported --effort launch flag."
13494
+ };
13495
+ }
13496
+ 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)) {
13497
+ return {
13498
+ failureClass: "MODEL_UNSUPPORTED",
13499
+ message: "Codex rejected an unsupported model during startup."
13500
+ };
13501
+ }
13502
+ return null;
13503
+ }
13504
+ function normalizeCodexStartupOutput(output) {
13505
+ return output.replace(ANSI_ESCAPE_CODE_REGEX, "").replace(/\r/g, "");
13506
+ }
13507
+ function hasMeaningfulCodexStartupAcceptance(output, echoedInputs) {
13508
+ const withoutEchoes = echoedInputs.reduce((currentOutput, echoedInput) => {
13509
+ return stripEchoedCodexStartupInput(currentOutput, echoedInput);
13510
+ }, output);
13511
+ 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, "");
13512
+ return sanitized.length > 0;
13513
+ }
13514
+ function stripEchoedCodexStartupInput(output, echoedInput) {
13515
+ const normalizedEcho = echoedInput.trim();
13516
+ if (normalizedEcho.length === 0) {
13517
+ return output;
13518
+ }
13519
+ let strippedOutput = output.replace(new RegExp(escapeRegExp(normalizedEcho), "g"), "");
13520
+ const whitespaceFlexiblePattern = buildWhitespaceFlexiblePattern(normalizedEcho);
13521
+ if (whitespaceFlexiblePattern) {
13522
+ strippedOutput = strippedOutput.replace(whitespaceFlexiblePattern, "");
13523
+ }
13524
+ return strippedOutput;
13525
+ }
13526
+ function buildWhitespaceFlexiblePattern(value) {
13527
+ const normalizedValue = value.trim().replace(/\s+/g, " ");
13528
+ if (normalizedValue.length === 0) {
13529
+ return null;
13530
+ }
13531
+ return new RegExp(normalizedValue.split(" ").map(escapeRegExp).join("\\s+"), "g");
13532
+ }
13533
+ function resolveCodexArgvPrompt(args) {
13534
+ const positionalArgs = [];
13535
+ for (let index = 0; index < args.length; index += 1) {
13536
+ const current = args[index];
13537
+ if (!current) {
13538
+ continue;
13539
+ }
13540
+ if (current === "--model" || current === "--sandbox" || current === "-c") {
13541
+ index += 1;
13542
+ continue;
13543
+ }
13544
+ if (current.startsWith("--model=") || current.startsWith("--sandbox=") || current.startsWith("-c=") || current.startsWith("--")) {
13545
+ continue;
13546
+ }
13547
+ positionalArgs.push(current);
13548
+ }
13549
+ return positionalArgs.length === 0 ? "" : positionalArgs[positionalArgs.length - 1].trim();
13550
+ }
13551
+ function escapeRegExp(value) {
13552
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
13553
+ }
13554
+ function buildPtyLaunchConfig(params) {
13555
+ const { command, args, env, cwd, bootstrap } = params;
13556
+ const launchConfig = {
13557
+ command,
13558
+ args,
13559
+ env,
13560
+ cwd
13561
+ };
13562
+ if (bootstrap?.authPath) {
13563
+ launchConfig.auth_path = bootstrap.authPath;
13564
+ }
13565
+ if (bootstrap?.configPath) {
13566
+ launchConfig.config_path = bootstrap.configPath;
13567
+ }
13568
+ if (bootstrap?.codexHome) {
13569
+ launchConfig.codex_home = bootstrap.codexHome;
13570
+ launchConfig.trusted_project_root = bootstrap.trustedProjectRoot || null;
13571
+ }
13572
+ return launchConfig;
13302
13573
  }
13303
13574
  function cleanupCredentialDirs(dirs) {
13304
13575
  for (const dirPath of dirs) {
@@ -13311,6 +13582,17 @@ function cleanupCredentialDirs(dirs) {
13311
13582
  }
13312
13583
  }
13313
13584
  }
13585
+ function resolveCodexTrustedProjectRoot(payload) {
13586
+ const cwd = typeof payload.cwd === "string" ? payload.cwd.trim() : "";
13587
+ const envWorktreeDir = typeof payload.env?.EPISODA_WORKTREE_DIR === "string" ? payload.env.EPISODA_WORKTREE_DIR.trim() : "";
13588
+ if (cwd.length > 0) {
13589
+ return cwd;
13590
+ }
13591
+ if (envWorktreeDir.length > 0) {
13592
+ return envWorktreeDir;
13593
+ }
13594
+ return process.cwd();
13595
+ }
13314
13596
 
13315
13597
  // src/utils/dev-server.ts
13316
13598
  var import_child_process16 = require("child_process");
@@ -15102,7 +15384,12 @@ var ProjectMessageRouter = class {
15102
15384
  moduleUid: resolvedPayload.moduleUid,
15103
15385
  agent_run_id: resolvedPayload.agent_run_id,
15104
15386
  success: result.success,
15105
- error: result.error
15387
+ error: result.error,
15388
+ startupFailureClass: result.startupFailureClass,
15389
+ startupConfirmedAt: result.startupConfirmedAt,
15390
+ modelUsed: result.modelUsed,
15391
+ launchConfig: result.launchConfig,
15392
+ authPath: result.authPath
15106
15393
  });
15107
15394
  }
15108
15395
  });