diff --git a/src/adapters/cli/codex.ts b/src/adapters/cli/codex.ts index 6cf7b40ff..9aa9898e7 100644 --- a/src/adapters/cli/codex.ts +++ b/src/adapters/cli/codex.ts @@ -249,6 +249,10 @@ export function createCodexAdapter(pathOverride?: string): CliAdapter { completionPattern: undefined, readyPattern: /›|\d+% left/, // › for input box, or status bar pattern (e.g. "97% left") + // Codex cold starts can exceed the worker's 15s soft first-prompt timeout. + // Wait for the real composer marker so the bare-shell guard does not treat + // a still-loading zsh wrapper as a failed launch. + deferFirstPromptTimeoutUntilReady: true, defaultPassthroughCommands: ['/goal'], systemHints: BOTMUX_SHELL_HINTS, // Codex 0.134.0+ accepts a message while the current turn is still running: diff --git a/test/cli-adapters.test.ts b/test/cli-adapters.test.ts index 7ef4348de..43219ddf5 100644 --- a/test/cli-adapters.test.ts +++ b/test/cli-adapters.test.ts @@ -993,6 +993,14 @@ describe('readyPattern', () => { expect(adapter.readyPattern!.test('97% left')).toBe(true); }); + it('codex defers the first-prompt timeout until its readyPattern appears', () => { + // Codex can cold-start slower than the worker's 15s soft timeout; keep the + // first Lark message queued until the composer is visible. + const adapter = createCodexAdapter('/bin/codex'); + expect(adapter.deferFirstPromptTimeoutUntilReady).toBe(true); + expect(adapter.supportsTypeAhead).toBe(true); + }); + it('traex matches prompt and context indicators', () => { const adapter = createTraexAdapter('/bin/traex'); expect(adapter.readyPattern).toBeDefined();