Honor Windows casing for Gemini configuration directories

Keep Gemini native configuration selection consistent with Windows filesystem semantics. Checks: 131 native configuration and readiness tests.
This commit is contained in:
Ryder Sun committed 2026-11-07 21:55:33 +08:00
1 parent 1b2df8dbfe
commit 6af8884601
2 files changed
+21 -2

No files matched your search

@@ -228,7 +228,10 @@ function nativeConfigEnvironment(kind, preferences, env = {}, platform = process
if (!spec || directory === undefined || directory === '') return env
if (typeof directory !== 'string' || directory.length > 4096
|| directory.includes('\u0000') || !path.isAbsolute(directory)) throw new Error('LOCAL_NATIVE_CONFIG_INVALID')
if (kind === 'gemini' && path.basename(path.resolve(directory)) !== '.gemini') throw new Error('LOCAL_NATIVE_CONFIG_INVALID')
if (kind === 'gemini') {
const name = path.basename(path.resolve(directory))
if ((platform === 'win32' ? name.toLowerCase() : name) !== '.gemini') throw new Error('LOCAL_NATIVE_CONFIG_INVALID')
}
if (kind === 'qwen' || kind === 'opencodereview') {
const resolved = path.resolve(directory)
const name = path.basename(resolved)
@@ -252,8 +255,8 @@ function validateNativeConfigDirectory(kind, directory) {
const spec = Object.hasOwn(NATIVE_CONFIG_DIRECTORIES, kind) ? NATIVE_CONFIG_DIRECTORIES[kind] : null
if (!spec || typeof directory !== 'string' || directory.length > 4096
|| directory.includes('\u0000') || !path.isAbsolute(directory)) throw new Error('LOCAL_NATIVE_CONFIG_INVALID')
if (kind === 'gemini' && path.basename(path.resolve(directory)) !== '.gemini') throw new Error('LOCAL_NATIVE_CONFIG_INVALID')
const caseName = value => process.platform === 'win32' ? value.toLowerCase() : value
if (kind === 'gemini' && caseName(path.basename(path.resolve(directory))) !== '.gemini') throw new Error('LOCAL_NATIVE_CONFIG_INVALID')
if (kind === 'qwen' && caseName(path.basename(path.resolve(directory))) !== '.qwen') throw new Error('LOCAL_NATIVE_CONFIG_INVALID')
if (kind === 'opencodereview' && caseName(path.basename(path.resolve(directory))) !== '.opencodereview') throw new Error('LOCAL_NATIVE_CONFIG_INVALID')
if (kind === 'zcode' && (caseName(path.basename(path.resolve(directory))) !== 'cli'
@@ -5,6 +5,22 @@ const os = require('node:os')
const path = require('node:path')
const { nativeAuthIdentityFiles, nativeConfigEnvironment, nativeIdentityDirectory, nativeProjectConfigPaths, validateNativeConfigDirectory } = require('../../src/agents/native-config-directory.cjs')
test('Gemini native configuration respects Windows directory case rules', t => {
const home = fs.mkdtempSync(path.join(os.tmpdir(), 'meldwork-gemini-case-'))
t.after(() => fs.rmSync(home, { recursive: true, force: true }))
const directory = path.join(home, '.GEMINI')
fs.mkdirSync(directory)
fs.writeFileSync(path.join(directory, 'settings.json'), '{}')
const preferences = { gemini: { nativeConfigDirectory: directory } }
assert.equal(nativeConfigEnvironment('gemini', preferences, {}, 'win32').GEMINI_CLI_HOME, home)
if (process.platform === 'win32') {
assert.equal(validateNativeConfigDirectory('gemini', directory), directory)
} else {
assert.throws(() => validateNativeConfigDirectory('gemini', directory), { message: 'LOCAL_NATIVE_CONFIG_INVALID' })
assert.throws(() => nativeConfigEnvironment('gemini', preferences, {}, process.platform), { message: 'LOCAL_NATIVE_CONFIG_INVALID' })
}
})
test('OpenClaw selects its native state directory without changing other Agents', t => {
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'meldwork-openclaw-config-'))
t.after(() => fs.rmSync(root, { recursive: true, force: true }))