fix(settings): prevent ~/.claude/ localSettings from overriding userSettings

When CWD is the home directory, projectSettings and localSettings
resolve to files inside ~/.claude/ (e.g. settings.local.json). These
are not legitimate project-level files — they are user config files
that should not take priority over explicit userSettings.

Added a guard in loadSettingsFromDisk() that skips projectSettings
and localSettings when their resolved path is under the user's
claude config home directory.

Fixes: CCP --settings flag and default settings loading not working
when ~/.claude/settings.local.json contains model overrides.
This commit is contained in:
James Feng 2026-06-06 01:07:53 +08:00
parent 18f5f99e7d
commit 95f0c99584

View File

@ -274,25 +274,31 @@ function getUserSettingsFilePath(): string {
export function getSettingsFilePathForSource(
source: SettingSource,
): string | undefined {
let result: string | undefined
switch (source) {
case 'userSettings':
return join(
result = join(
getSettingsRootPathForSource(source),
getUserSettingsFilePath(),
)
break
case 'projectSettings':
case 'localSettings': {
return join(
result = join(
getSettingsRootPathForSource(source),
getRelativeSettingsFilePathForSource(source),
)
break
}
case 'policySettings':
return getManagedSettingsFilePath()
result = getManagedSettingsFilePath()
break
case 'flagSettings': {
return getFlagSettingsPath()
result = getFlagSettingsPath()
break
}
}
return result
}
export function getRelativeSettingsFilePathForSource(
@ -746,6 +752,21 @@ function loadSettingsFromDisk(): SettingsWithErrors {
if (!seenFiles.has(resolvedPath)) {
seenFiles.add(resolvedPath)
// Skip project and local settings when they resolve to the user's
// claude config directory (~/.claude/). These are not legitimately
// separate project-level files — the CWD just happens to be the same
// directory as the claude config home. Loading them would let a
// local override (e.g. settings.local.json) silently clobber the
// user's explicit global settings values.
if (
(source === 'projectSettings' || source === 'localSettings') &&
resolvedPath.startsWith(
resolve(getSettingsRootPathForSource('userSettings')),
)
) {
continue
}
const { settings, errors } = parseSettingsFile(filePath)
// Add unique errors (deduplication)