Skip to content

Commit 5097ef0

Browse files
authored
Merge pull request #200 from OpenLAIR/fix/codex-cli-version-drift
Fix Codex CLI version drift in embedded shell
2 parents 88fcee0 + fec9728 commit 5097ef0

7 files changed

Lines changed: 150 additions & 170 deletions

File tree

package-lock.json

Lines changed: 33 additions & 155 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,8 @@
7878
"@iarna/toml": "^2.2.5",
7979
"@modelcontextprotocol/sdk": "^1.29.0",
8080
"@octokit/rest": "^22.0.0",
81-
"@openai/codex": "^0.104.0",
82-
"@openai/codex-sdk": "^0.101.0",
81+
"@openai/codex": "^0.125.0",
82+
"@openai/codex-sdk": "^0.125.0",
8383
"@replit/codemirror-minimap": "^0.5.2",
8484
"@tailwindcss/typography": "^0.5.16",
8585
"@uiw/react-codemirror": "^4.23.13",

server/index.js

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ import { validateApiKey, authenticateToken, authenticateWebSocket } from './midd
7878
import { IS_PLATFORM } from './constants/config.js';
7979
import { enqueueTelemetryEvent } from './telemetry.js';
8080
import { resolveCursorCliCommand, isCursorLoginCommand, isGeminiLoginCommand, normalizeCursorLoginCommand } from './utils/cursorCommand.js';
81+
import { buildCodexCliEnv, codexCommandForShell } from './utils/codexCli.js';
8182
import { getGeminiApiKeyForUser, withGeminiApiKeyEnv } from './utils/geminiApiKey.js';
8283
import {
8384
DEFAULT_BACKEND_PORT,
@@ -2031,18 +2032,18 @@ function handleShellConnection(ws) {
20312032
}
20322033
}
20332034
} else if (provider === 'codex') {
2034-
// Use codex command
2035+
const codexCommand = codexCommandForShell(process.env, os.platform());
20352036
if (os.platform() === 'win32') {
20362037
if (hasSession && sessionId) {
2037-
shellCommand = `Set-Location -Path "${projectPath}"; codex resume ${sessionId}; if ($LASTEXITCODE -ne 0) { codex }`;
2038+
shellCommand = `Set-Location -Path "${projectPath}"; ${codexCommand} resume ${sessionId}; if ($LASTEXITCODE -ne 0) { ${codexCommand} }`;
20382039
} else {
2039-
shellCommand = `Set-Location -Path "${projectPath}"; codex`;
2040+
shellCommand = `Set-Location -Path "${projectPath}"; ${codexCommand}`;
20402041
}
20412042
} else {
20422043
if (hasSession && sessionId) {
2043-
shellCommand = `cd "${projectPath}" && codex resume ${sessionId} || codex`;
2044+
shellCommand = `cd "${projectPath}" && ${codexCommand} resume ${sessionId} || ${codexCommand}`;
20442045
} else {
2045-
shellCommand = `cd "${projectPath}" && codex`;
2046+
shellCommand = `cd "${projectPath}" && ${codexCommand}`;
20462047
}
20472048
}
20482049
} else if (provider === 'gemini') {
@@ -2112,7 +2113,9 @@ function handleShellConnection(ws) {
21122113
cols: termCols,
21132114
rows: termRows,
21142115
cwd: spawnCwd,
2115-
env: buildEmbeddedShellEnv(process.env)
2116+
env: provider === 'codex'
2117+
? buildEmbeddedShellEnv(buildCodexCliEnv(process.env))
2118+
: buildEmbeddedShellEnv(process.env)
21162119
});
21172120

21182121
console.log('🟢 Shell process started with PTY, PID:', shellProcess.pid);

server/routes/cli-auth.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import os from 'os';
66
import fetch from 'node-fetch';
77
import { resolveCursorCliCommand } from '../utils/cursorCommand.js';
88
import { resolveAvailableCliCommand } from '../utils/cliResolution.js';
9+
import { buildCodexCliEnv, getCodexCliCommand } from '../utils/codexCli.js';
910
import {
1011
DEFAULT_OLLAMA_URL,
1112
detectGPUs,
@@ -840,7 +841,8 @@ function checkCursorStatus() {
840841
// 2. OPENAI_API_KEY from server environment variable
841842
// 3. OPENAI_API_KEY from ~/.codex/auth.json
842843
async function checkCodexCredentials() {
843-
let cliCommand = process.env.CODEX_CLI_PATH || 'codex';
844+
const codexCliEnv = buildCodexCliEnv(process.env);
845+
let cliCommand = getCodexCliCommand(process.env);
844846
try {
845847
if (isCliMockedMissing('codex')) {
846848
return {
@@ -856,7 +858,8 @@ async function checkCodexCredentials() {
856858
const resolvedCliCommand = await resolveAvailableCliCommand({
857859
envVarName: 'CODEX_CLI_PATH',
858860
defaultCommands: ['codex'],
859-
appendWindowsSuffixes: true
861+
appendWindowsSuffixes: true,
862+
env: codexCliEnv
860863
});
861864
cliCommand = resolvedCliCommand || cliCommand;
862865

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { describe, expect, it } from 'vitest';
2+
import path from 'path';
3+
import { buildCodexCliEnv, codexCommandForShell } from '../codexCli.js';
4+
5+
describe('codexCli', () => {
6+
it('removes Dr. Claw local node_modules/.bin from Codex CLI PATH probes', () => {
7+
const localBin = path.join(process.cwd(), 'node_modules', '.bin');
8+
const externalBin = path.join(path.sep, 'usr', 'local', 'bin');
9+
const env = buildCodexCliEnv({
10+
PATH: [localBin, externalBin].join(path.delimiter),
11+
});
12+
13+
expect(env.PATH.split(path.delimiter)).toEqual([externalBin]);
14+
});
15+
16+
it('uses CODEX_CLI_PATH as the shell command when configured', () => {
17+
expect(codexCommandForShell({ CODEX_CLI_PATH: '/opt/homebrew/bin/codex' }, 'darwin')).toBe("'/opt/homebrew/bin/codex'");
18+
});
19+
});

0 commit comments

Comments
 (0)