@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.
|
|
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
|
-
|
|
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
|
-
...
|
|
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
|
-
|
|
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 {
|
|
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
|
-
},
|
|
13220
|
-
|
|
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(
|
|
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.
|
|
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
|
-
|
|
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:
|
|
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
|
|
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
|
|
13417
|
+
function handleStartupData(session, data) {
|
|
13280
13418
|
const startup = session.startup;
|
|
13281
|
-
if (!startup
|
|
13419
|
+
if (!startup) {
|
|
13282
13420
|
return;
|
|
13283
13421
|
}
|
|
13284
|
-
|
|
13285
|
-
|
|
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
|
-
|
|
13288
|
-
|
|
13289
|
-
|
|
13290
|
-
|
|
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 (
|
|
13462
|
+
if (startup.readinessObserved) {
|
|
13293
13463
|
return;
|
|
13294
13464
|
}
|
|
13295
|
-
|
|
13296
|
-
startup.
|
|
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 ||
|
|
13301
|
-
|
|
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
|
});
|