fix(settings): keep shortcutOverrides out of the settings PUT

The Shortcuts tab stores overrides in the per-device localStorage blob, and
saveAppSettings() carries them over from the previous blob, but the strip
before the PUT never removed them. SettingsUpdateSchema is .strict() and does
not declare the key, so once a device had any override (even the empty {}
that Reset leaves behind) every App Settings save got a 400 and no synced
setting reached the server again, while the toast still read "Settings
saved" (_apiPut resolves on a 400). Pre-existing, but #560 now points users
at the Shortcuts tab to bind Close Session again, so it would be hit often.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Codeman maintainer
2026-10-08 20:00:10 +02:00
parent f7a41b3fae
commit 9b28c277f0
2 changed files with 17 additions and 0 deletions
+7
View File
@@ -2775,6 +2775,13 @@ Object.assign(CodemanApp.prototype, {
// .strict() schema — syncing it would push a desktop-shaped choice onto
// devices that cannot render it at all.
sessionLineageLines: _sll,
// Keyboard shortcut overrides are per-device (bindings follow the keyboard
// and the OS: Cmd on macOS, Ctrl elsewhere) and absent from the .strict()
// SettingsUpdateSchema. They used to ride along here, so the first
// Shortcuts change on a device (even a Reset, which leaves an empty {})
// made EVERY later App Settings save a 400, and every synced key stopped
// reaching the server while the toast still said "Settings saved".
shortcutOverrides: _sco,
...serverSettings
} = settings;
let webhookError = '';
+10
View File
@@ -69,6 +69,16 @@ describe('shortcut registry and overlay', () => {
);
});
it('keeps shortcutOverrides out of the settings PUT (the .strict() schema would 400 the whole save)', async () => {
// Overrides are per-device and live only in the localStorage blob. Before this
// strip, any device with an override (even an empty {} left by Reset) sent the
// key on every App Settings save, and the server refused the whole PUT, so no
// synced setting reached it again.
expect(settingsSource).toContain('shortcutOverrides: _sco,');
const { SettingsUpdateSchema } = await import('../src/web/schemas.js');
expect(SettingsUpdateSchema.safeParse({ shortcutOverrides: {} }).success).toBe(false);
});
it('keeps the full help modal reachable now that Ctrl+? opens the registry overlay', () => {
// The legacy #helpModal (full shortcut reference) lost its only opener when
// Ctrl+? was rerouted to the overlay; the overlay footer must link to it.