diff --git a/src/server/__tests__/settings.test.ts b/src/server/__tests__/settings.test.ts index dd296623..f04763e4 100644 --- a/src/server/__tests__/settings.test.ts +++ b/src/server/__tests__/settings.test.ts @@ -21,6 +21,11 @@ import { } from '../../utils/secureStorage/macOsKeychainHelpers.js' import type { OpenAIOAuthTokens } from '../../services/openaiAuth/types.js' import { getModelOptions } from '../../utils/model/modelOptions.js' +import { + getSettingsForSource, + updateSettingsForSource, +} from '../../utils/settings/settings.js' +import { resetSettingsCache } from '../../utils/settings/settingsCache.js' // ─── Test helpers ───────────────────────────────────────────────────────────── @@ -40,6 +45,7 @@ let originalAnthropicDefaultOpusModel: string | undefined async function setup() { tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), 'claude-test-')) + resetSettingsCache() originalConfigDir = process.env.CLAUDE_CONFIG_DIR originalHome = process.env.HOME originalUserProfile = process.env.USERPROFILE @@ -72,6 +78,7 @@ async function teardown() { plainTextStorage.delete() clearKeychainCache() clearOpenAIOAuthTokenCache() + resetSettingsCache() if (originalConfigDir !== undefined) { process.env.CLAUDE_CONFIG_DIR = originalConfigDir @@ -222,6 +229,37 @@ describe('SettingsService', () => { expect(settings.model).toBe('claude-haiku-4-5') }) + it('should not let cached CLI settings overwrite desktop settings updates', async () => { + const svc = new SettingsService() + await svc.updateUserSettings({ + enabledPlugins: { + 'demo@test-market': false, + }, + }) + + expect(getSettingsForSource('userSettings')?.enabledPlugins?.['demo@test-market']).toBe(false) + + await svc.updateUserSettings({ + language: 'chinese', + desktopNotificationsEnabled: true, + alwaysThinkingEnabled: false, + }) + + const { error } = updateSettingsForSource('userSettings', { + enabledPlugins: { + ...getSettingsForSource('userSettings')?.enabledPlugins, + 'demo@test-market': true, + }, + }) + expect(error).toBeNull() + + const settings = await svc.getUserSettings() + expect(settings.language).toBe('chinese') + expect(settings.desktopNotificationsEnabled).toBe(true) + expect(settings.alwaysThinkingEnabled).toBe(false) + expect((settings.enabledPlugins as Record)['demo@test-market']).toBe(true) + }) + it('should read and write project settings', async () => { const projectRoot = path.join(tmpDir, 'myproject') await fs.mkdir(path.join(projectRoot, '.claude'), { recursive: true }) diff --git a/src/server/services/settingsService.ts b/src/server/services/settingsService.ts index 84f5c529..6b988ef7 100644 --- a/src/server/services/settingsService.ts +++ b/src/server/services/settingsService.ts @@ -15,6 +15,7 @@ import * as os from 'os' import { ApiError } from '../middleware/errorHandler.js' import { normalizeJsonObject, readRecoverableJsonFile } from './recoverableJsonFile.js' import { ensurePersistentStorageUpgraded } from './persistentStorageMigrations.js' +import { resetSettingsCache } from '../../utils/settings/settingsCache.js' const VALID_PERMISSION_MODES = [ 'default', @@ -129,6 +130,7 @@ export class SettingsService { await fs.mkdir(dir, { recursive: true }) await fs.writeFile(tmpFile, contents, 'utf-8') await fs.rename(tmpFile, filePath) + resetSettingsCache() return } catch (err) { lastError = err