MCPcopy Create free account
hub / github.com/github/gh-aw / main

Function main

actions/setup/js/codex_harness.cjs:353–563  ·  view source on GitHub ↗

* Main entry point: run codex with retry logic for transient API failures. * Codex does not support --continue session resumption, so all retries are fresh runs.

()

Source from the content-addressed store, hash-verified

351 * Codex does not support --continue session resumption, so all retries are fresh runs.
352 */
353async function main() {
354 const [, , command, ...args] = process.argv;
355
356 if (!command) {
357 process.stderr.write("codex-harness: Usage: node codex_harness.cjs <command> [args...]\n");
358 process.exit(1);
359 }
360
361 log(`starting: command=${command} maxRetries=${MAX_RETRIES} initialDelayMs=${INITIAL_DELAY_MS}` + ` backoffMultiplier=${BACKOFF_MULTIPLIER} maxDelayMs=${MAX_DELAY_MS}` + ` nodeVersion=${process.version} platform=${process.platform}`);
362
363 // Pre-flight: skip the agent entirely when a noop has already been written by a prior step.
364 // A noop indicates the work is complete or there is nothing to do — starting the agent
365 // would be wasteful and potentially harmful. This check runs before API key validation so
366 // that a noop can be honoured even when credentials are absent.
367 const safeOutputsPath = process.env.GH_AW_SAFE_OUTPUTS || "";
368 if (safeOutputsPath && hasNoopInSafeOutputs(safeOutputsPath, { logger: log })) {
369 log("pre-flight: noop message found in safe-outputs — skipping agent (work is already complete or no work needed)");
370 process.exit(0);
371 }
372
373 // Diagnose API key presence so CI failures can be triaged without exposing secret values.
374 const codexApiKey = process.env.CODEX_API_KEY;
375 const openaiApiKey = process.env.OPENAI_API_KEY;
376 const codexChildEnv = buildCodexChildEnv(process.env, codexApiKey, openaiApiKey);
377 log(`secrets: CODEX_API_KEY=${codexApiKey ? `set (length=${codexApiKey.length})` : "not set"}` + ` OPENAI_API_KEY=${openaiApiKey ? `set (length=${openaiApiKey.length})` : "not set"}`);
378
379 // Pre-flight: require at least one API key before spawning codex.
380 // Without a key, codex exits immediately with "Missing environment variable" and every
381 // retry attempt fails the same way. Failing here avoids burning the retry budget and
382 // surfaces a clear, actionable message in CI logs.
383 if (!codexApiKey && !openaiApiKey) {
384 log("fatal: no API key available - set CODEX_API_KEY or OPENAI_API_KEY and retry");
385 process.exit(1);
386 }
387
388 // Resolve the prompt for the initial run (reads --prompt-file content).
389 // A missing or unreadable prompt file is treated as a fatal startup error.
390 let resolvedArgs;
391 try {
392 resolvedArgs = resolveCodexPromptFileArgs(args);
393 } catch (err) {
394 const e = /** @type {Error} */ err;
395 log(`fatal: ${e.message}`);
396 process.exit(1);
397 }
398
399 // Safe arg list for logging: when --prompt-file was present, the last element of
400 // resolvedArgs is the resolved prompt content. Replace it with a placeholder so that
401 // task instructions are never written to stderr or captured in agent logs.
402 const hadPromptFile = args.includes("--prompt-file");
403 const safeArgs = hadPromptFile && resolvedArgs.length > 0 ? [...resolvedArgs.slice(0, -1), "<prompt omitted>"] : resolvedArgs;
404
405 // Inject --json after `exec` to stream structured JSONL events to stdout, making
406 // Codex output machine-readable in CI without affecting the stderr progress stream.
407 resolvedArgs = injectJsonFlag(resolvedArgs);
408
409 // Fetch AWF API proxy reflection data before running the agent to capture initial proxy state.
410 // This is best-effort: failures are logged but do not affect the agent run.

Callers 1

codex_harness.cjsFile · 0.70

Calls 15

hasNoopInSafeOutputsFunction · 0.85
buildCodexChildEnvFunction · 0.85
injectJsonFlagFunction · 0.85
fetchAWFReflectFunction · 0.85
runProcessFunction · 0.85
isMissingApiKeyErrorFunction · 0.85
isServerErrorFunction · 0.85

Tested by

no test coverage detected