fix: improve OpenCode settings handling
Improves OpenCode CLI and shortcut settings flows Updates runtime API and persistence handling Adds coverage for settings helper behavior
This commit is contained in:
@@ -21,9 +21,26 @@ export const createSettingsHelpers = (dependencies) => {
|
||||
const STT_SERVER_URL_MAX_LENGTH = 2048;
|
||||
const STT_MODEL_MAX_LENGTH = 256;
|
||||
const STT_LANGUAGE_MAX_LENGTH = 64;
|
||||
const VERSION_STRING_MAX_LENGTH = 128;
|
||||
const SHORTCUT_OVERRIDE_KEY_MAX_LENGTH = 128;
|
||||
const SHORTCUT_OVERRIDE_VALUE_MAX_LENGTH = 128;
|
||||
const PWA_ORIENTATION_VALUES = new Set(['system', 'portrait', 'landscape']);
|
||||
const MOBILE_KEYBOARD_MODE_VALUES = new Set(['native', 'resize-content']);
|
||||
|
||||
const sanitizeShortcutOverrides = (value) => {
|
||||
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
||||
return null;
|
||||
}
|
||||
const result = {};
|
||||
for (const [rawKey, rawValue] of Object.entries(value)) {
|
||||
const key = typeof rawKey === 'string' ? rawKey.trim() : '';
|
||||
const combo = typeof rawValue === 'string' ? rawValue.trim() : '';
|
||||
if (!key || !combo) continue;
|
||||
result[key.slice(0, SHORTCUT_OVERRIDE_KEY_MAX_LENGTH)] = combo.slice(0, SHORTCUT_OVERRIDE_VALUE_MAX_LENGTH);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
const normalizePwaAppName = (value, fallback = '') => {
|
||||
if (typeof value !== 'string') {
|
||||
return fallback;
|
||||
@@ -350,7 +367,7 @@ export const createSettingsHelpers = (dependencies) => {
|
||||
result.pwaOrientation = normalizePwaOrientation(candidate.pwaOrientation, undefined);
|
||||
}
|
||||
if (typeof candidate.mobileKeyboardMode === 'string') {
|
||||
const mode = normalizeMobileKeyboardMode(candidate.mobileKeyboardMode, undefined);
|
||||
const mode = normalizeMobileKeyboardMode(candidate.mobileKeyboardMode, null);
|
||||
if (mode) {
|
||||
result.mobileKeyboardMode = mode;
|
||||
}
|
||||
@@ -364,6 +381,13 @@ export const createSettingsHelpers = (dependencies) => {
|
||||
if (typeof candidate.inputSpellcheckEnabled === 'boolean') {
|
||||
result.inputSpellcheckEnabled = candidate.inputSpellcheckEnabled;
|
||||
}
|
||||
if (typeof candidate.showOpenCodeUpdateNotifications === 'boolean') {
|
||||
result.showOpenCodeUpdateNotifications = candidate.showOpenCodeUpdateNotifications;
|
||||
}
|
||||
if (typeof candidate.openCodeUpdateToastDismissedVersion === 'string') {
|
||||
const version = candidate.openCodeUpdateToastDismissedVersion.trim();
|
||||
result.openCodeUpdateToastDismissedVersion = version.slice(0, VERSION_STRING_MAX_LENGTH);
|
||||
}
|
||||
if (typeof candidate.showToolFileIcons === 'boolean') {
|
||||
result.showToolFileIcons = candidate.showToolFileIcons;
|
||||
}
|
||||
@@ -437,6 +461,11 @@ export const createSettingsHelpers = (dependencies) => {
|
||||
result.inputBarOffset = Math.max(0, Math.min(100, Math.round(candidate.inputBarOffset)));
|
||||
}
|
||||
|
||||
const shortcutOverrides = sanitizeShortcutOverrides(candidate.shortcutOverrides);
|
||||
if (shortcutOverrides) {
|
||||
result.shortcutOverrides = shortcutOverrides;
|
||||
}
|
||||
|
||||
const favoriteModels = sanitizeModelRefs(candidate.favoriteModels, 64);
|
||||
if (favoriteModels) {
|
||||
result.favoriteModels = favoriteModels;
|
||||
|
||||
@@ -94,6 +94,54 @@ describe('settings helpers', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('accepts shortcut overrides as a persisted shared setting', () => {
|
||||
const helpers = createTestHelpers();
|
||||
|
||||
expect(helpers.sanitizeSettingsUpdate({
|
||||
shortcutOverrides: {
|
||||
open_settings: 'mod+comma',
|
||||
new_chat: '__unassigned__',
|
||||
invalid: 123,
|
||||
empty: '',
|
||||
},
|
||||
})).toEqual({
|
||||
shortcutOverrides: {
|
||||
open_settings: 'mod+comma',
|
||||
new_chat: '__unassigned__',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('preserves empty shortcut overrides when resetting all shortcuts', () => {
|
||||
const helpers = createTestHelpers();
|
||||
|
||||
expect(helpers.sanitizeSettingsUpdate({ shortcutOverrides: {} })).toEqual({
|
||||
shortcutOverrides: {},
|
||||
});
|
||||
});
|
||||
|
||||
it('accepts OpenCode update notification preference as a persisted shared setting', () => {
|
||||
const helpers = createTestHelpers();
|
||||
|
||||
expect(helpers.sanitizeSettingsUpdate({ showOpenCodeUpdateNotifications: false })).toEqual({
|
||||
showOpenCodeUpdateNotifications: false,
|
||||
});
|
||||
expect(helpers.sanitizeSettingsUpdate({ showOpenCodeUpdateNotifications: true })).toEqual({
|
||||
showOpenCodeUpdateNotifications: true,
|
||||
});
|
||||
});
|
||||
|
||||
it('accepts dismissed OpenCode update toast version as a persisted shared setting', () => {
|
||||
const helpers = createTestHelpers();
|
||||
|
||||
expect(helpers.sanitizeSettingsUpdate({ openCodeUpdateToastDismissedVersion: ' 1.16.0 ' })).toEqual({
|
||||
openCodeUpdateToastDismissedVersion: '1.16.0',
|
||||
});
|
||||
expect(helpers.sanitizeSettingsUpdate({ openCodeUpdateToastDismissedVersion: '' })).toEqual({
|
||||
openCodeUpdateToastDismissedVersion: '',
|
||||
});
|
||||
});
|
||||
|
||||
it('rejects non-boolean collapsibleThinkingBlocks values', () => {
|
||||
const helpers = createTestHelpers();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user