feat: implement version-based migrations for global settings

- Added versioning to global settings, enabling automatic migrations for breaking changes.
- Updated default global settings to reflect the new versioning schema.
- Implemented logic to disable sandbox mode for existing users during migration from version 1 to 2.
- Enhanced error handling for saving migrated settings, ensuring data integrity during updates.
This commit is contained in:
WebDevCody
2025-12-31 23:30:44 -05:00
parent 98381441b9
commit 6d4ab9cc13
2 changed files with 39 additions and 11 deletions

View File

@@ -124,6 +124,8 @@ export class SettingsService {
* Missing fields are filled in from DEFAULT_GLOBAL_SETTINGS for forward/backward
* compatibility during schema migrations.
*
* Also applies version-based migrations for breaking changes.
*
* @returns Promise resolving to complete GlobalSettings object
*/
async getGlobalSettings(): Promise<GlobalSettings> {
@@ -131,7 +133,7 @@ export class SettingsService {
const settings = await readJsonFile<GlobalSettings>(settingsPath, DEFAULT_GLOBAL_SETTINGS);
// Apply any missing defaults (for backwards compatibility)
return {
let result: GlobalSettings = {
...DEFAULT_GLOBAL_SETTINGS,
...settings,
keyboardShortcuts: {
@@ -139,6 +141,32 @@ export class SettingsService {
...settings.keyboardShortcuts,
},
};
// Version-based migrations
const storedVersion = settings.version || 1;
let needsSave = false;
// Migration v1 -> v2: Force enableSandboxMode to false for existing users
// Sandbox mode can cause issues on some systems, so we're disabling it by default
if (storedVersion < 2) {
logger.info('Migrating settings from v1 to v2: disabling sandbox mode');
result.enableSandboxMode = false;
result.version = SETTINGS_VERSION;
needsSave = true;
}
// Save migrated settings if needed
if (needsSave) {
try {
await ensureDataDir(this.dataDir);
await atomicWriteJson(settingsPath, result);
logger.info('Settings migration complete');
} catch (error) {
logger.error('Failed to save migrated settings:', error);
}
}
return result;
}
/**

View File

@@ -470,6 +470,13 @@ export interface ProjectSettings {
* Default values and constants
*/
/** Current version of the global settings schema */
export const SETTINGS_VERSION = 2;
/** Current version of the credentials schema */
export const CREDENTIALS_VERSION = 1;
/** Current version of the project settings schema */
export const PROJECT_SETTINGS_VERSION = 1;
/** Default keyboard shortcut bindings */
export const DEFAULT_KEYBOARD_SHORTCUTS: KeyboardShortcuts = {
board: 'K',
@@ -496,7 +503,7 @@ export const DEFAULT_KEYBOARD_SHORTCUTS: KeyboardShortcuts = {
/** Default global settings used when no settings file exists */
export const DEFAULT_GLOBAL_SETTINGS: GlobalSettings = {
version: 1,
version: SETTINGS_VERSION,
theme: 'dark',
sidebarOpen: true,
chatHistoryOpen: false,
@@ -533,7 +540,7 @@ export const DEFAULT_GLOBAL_SETTINGS: GlobalSettings = {
/** Default credentials (empty strings - user must provide API keys) */
export const DEFAULT_CREDENTIALS: Credentials = {
version: 1,
version: CREDENTIALS_VERSION,
apiKeys: {
anthropic: '',
google: '',
@@ -543,12 +550,5 @@ export const DEFAULT_CREDENTIALS: Credentials = {
/** Default project settings (empty - all settings are optional and fall back to global) */
export const DEFAULT_PROJECT_SETTINGS: ProjectSettings = {
version: 1,
version: PROJECT_SETTINGS_VERSION,
};
/** Current version of the global settings schema */
export const SETTINGS_VERSION = 1;
/** Current version of the credentials schema */
export const CREDENTIALS_VERSION = 1;
/** Current version of the project settings schema */
export const PROJECT_SETTINGS_VERSION = 1;