fix(cli): preserve codex config args on Windows

This commit is contained in:
weishu
2026-04-26 12:05:44 +08:00
parent 010dc41369
commit 0cfc3b4ed2
6 changed files with 137 additions and 39 deletions
+40 -11
View File
@@ -1,11 +1,13 @@
import { beforeEach, describe, expect, it, vi } from 'vitest'
const { execFileSyncMock } = vi.hoisted(() => ({
execFileSyncMock: vi.fn()
const { spawnSyncMock } = vi.hoisted(() => ({
spawnSyncMock: vi.fn()
}))
vi.mock('node:child_process', () => ({
execFileSync: execFileSyncMock
vi.mock('cross-spawn', () => ({
default: {
sync: spawnSyncMock
}
}))
import {
@@ -17,7 +19,7 @@ import {
describe('codexVersion', () => {
beforeEach(() => {
execFileSyncMock.mockReset()
spawnSyncMock.mockReset()
})
describe('parseCodexVersion', () => {
@@ -47,16 +49,24 @@ describe('codexVersion', () => {
describe('assertCodexLocalSupported', () => {
it('passes when codex is new enough', () => {
execFileSyncMock.mockReturnValueOnce('codex-cli 0.124.0\n')
spawnSyncMock.mockReturnValueOnce({
status: 0,
stdout: 'codex-cli 0.124.0\n',
stderr: ''
})
expect(() => assertCodexLocalSupported()).not.toThrow()
expect(execFileSyncMock).toHaveBeenCalledWith('codex', ['--version'], expect.objectContaining({
expect(spawnSyncMock).toHaveBeenCalledWith('codex', ['--version'], expect.objectContaining({
encoding: 'utf8'
}))
})
it('fails when codex is too old', () => {
execFileSyncMock.mockReturnValueOnce('codex-cli 0.123.9\n')
spawnSyncMock.mockReturnValueOnce({
status: 0,
stdout: 'codex-cli 0.123.9\n',
stderr: ''
})
expect(() => assertCodexLocalSupported()).toThrow(
'Codex CLI 0.124.0+ is required for hapi codex local mode because HAPI depends on stable hooks. Detected: 0.123.9. Please upgrade Codex and retry.'
@@ -64,7 +74,11 @@ describe('codexVersion', () => {
})
it('fails when the version output cannot be parsed', () => {
execFileSyncMock.mockReturnValueOnce('codex-cli version unknown\n')
spawnSyncMock.mockReturnValueOnce({
status: 0,
stdout: 'codex-cli version unknown\n',
stderr: ''
})
expect(() => assertCodexLocalSupported()).toThrow(
'Could not determine Codex CLI version. Codex CLI 0.124.0+ is required for hapi codex local mode because HAPI depends on stable hooks. Please upgrade Codex and retry.'
@@ -74,13 +88,28 @@ describe('codexVersion', () => {
it('fails when codex is not available on PATH', () => {
const error = new Error('spawnSync codex ENOENT') as NodeJS.ErrnoException
error.code = 'ENOENT'
execFileSyncMock.mockImplementationOnce(() => {
throw error
spawnSyncMock.mockReturnValueOnce({
status: null,
stdout: '',
stderr: '',
error
})
expect(() => assertCodexLocalSupported()).toThrow(
'Codex CLI 0.124.0+ is required for hapi codex local mode because HAPI depends on stable hooks. Codex was not found on PATH. Please install or upgrade Codex and retry.'
)
})
it('fails when codex version exits unsuccessfully', () => {
spawnSyncMock.mockReturnValueOnce({
status: 1,
stdout: '',
stderr: 'codex failed'
})
expect(() => assertCodexLocalSupported()).toThrow(
'Could not determine Codex CLI version. codex failed Codex CLI 0.124.0+ is required for hapi codex local mode because HAPI depends on stable hooks. Please upgrade Codex and retry.'
)
})
})
})
+20 -11
View File
@@ -1,4 +1,4 @@
import { execFileSync } from 'node:child_process'
import spawn from 'cross-spawn'
import { withBunRuntimeEnv } from '@/utils/bunRuntime'
export const MIN_CODEX_HOOKS_VERSION = '0.124.0'
@@ -54,30 +54,39 @@ export function isCodexVersionAtLeast(version: string, minimum: string): boolean
export function assertCodexLocalSupported(): void {
let output: string
try {
output = execFileSync('codex', ['--version'], {
encoding: 'utf8',
env: withBunRuntimeEnv(),
shell: process.platform === 'win32'
}).trim()
} catch (error) {
const maybeError = error as NodeJS.ErrnoException
const result = spawn.sync('codex', ['--version'], {
encoding: 'utf8',
env: withBunRuntimeEnv()
})
if (result.error) {
const maybeError = result.error as NodeJS.ErrnoException
const message = maybeError?.message ? ` ${maybeError.message}` : ''
if (maybeError?.code === 'ENOENT') {
throw new Error(
`${getLocalModeRequirementMessage()} Codex was not found on PATH. Please install or upgrade Codex and retry.`,
{ cause: error }
{ cause: result.error }
)
}
throw new Error(
`Could not determine Codex CLI version.${message} ` +
`${getLocalModeRequirementMessage()} Please upgrade Codex and retry.`,
{ cause: error }
{ cause: result.error }
)
}
if (result.status !== 0) {
const detail = result.stderr ? ` ${result.stderr.trim()}` : ''
throw new Error(
`Could not determine Codex CLI version.${detail} ` +
`${getLocalModeRequirementMessage()} Please upgrade Codex and retry.`
)
}
output = result.stdout.trim()
const version = parseCodexVersion(output)
if (!version) {
throw new Error(