From 735dcf6f6ac2c993119aee3068e7ac5a7d8a5b95 Mon Sep 17 00:00:00 2001 From: c10l Date: Tue, 24 Mar 2026 23:26:53 +0000 Subject: [PATCH] fix: strip overrides removes keys missing from local config (#49) When a user adds a config section to opencode-synced.overrides.jsonc (e.g. server) that exists in the repo's base config but not in the local config, stripOverrides was restoring the base value instead of removing it. This caused push to report "no changes" even though the override section should have been stripped from the repo. Fix: add check for currentValue === undefined before restoring baseValue. If an override declares a key that doesn't exist in the local config, it should always be stripped (the override means "this key is local-only"). Closes #49 --- src/sync/config.test.ts | 42 +++++++++++++++++++++++++++++++++++++++++ src/sync/config.ts | 2 +- 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/src/sync/config.test.ts b/src/sync/config.test.ts index 66b8894..f1437d6 100644 --- a/src/sync/config.test.ts +++ b/src/sync/config.test.ts @@ -55,6 +55,48 @@ describe('stripOverrides', () => { expect(stripped).toEqual({ theme: 'opencode', other: true }); }); + + it('strips override object keys missing from local config even when present in base', () => { + const base = { + mcp: { context7: { url: 'https://example.com' } }, + server: { port: 8080, hostname: '0.0.0.0' }, + }; + const overrides = { + mcp: { context7: { headers: { apiKey: 'local-key' } } }, + server: { port: 8080, hostname: '0.0.0.0' }, + }; + const local = { + mcp: { context7: { url: 'https://example.com', headers: { apiKey: 'local-key' } } }, + }; + + const stripped = stripOverrides(local, overrides, base); + + expect(stripped).not.toHaveProperty('server'); + expect(stripped).toEqual({ + mcp: { context7: { url: 'https://example.com' } }, + }); + }); + + it('strips override scalar keys missing from local config even when present in base', () => { + const base = { theme: 'dark', port: 3000 }; + const overrides = { theme: 'light', port: 8080 }; + const local = { theme: 'light' }; + + const stripped = stripOverrides(local, overrides, base); + + expect(stripped).not.toHaveProperty('port'); + expect(stripped).toEqual({ theme: 'dark' }); + }); + + it('strips override keys from local when present in local and base', () => { + const base = { theme: 'dark', editor: 'vim' }; + const overrides = { theme: 'light', editor: 'code' }; + const local = { theme: 'light', editor: 'code', extra: true }; + + const stripped = stripOverrides(local, overrides, base); + + expect(stripped).toEqual({ theme: 'dark', editor: 'vim', extra: true }); + }); }); describe('normalizeSyncConfig', () => { diff --git a/src/sync/config.ts b/src/sync/config.ts index b0d4af5..55fdf39 100644 --- a/src/sync/config.ts +++ b/src/sync/config.ts @@ -236,7 +236,7 @@ export function stripOverrides( continue; } - if (baseValue === undefined) { + if (currentValue === undefined || baseValue === undefined) { delete result[key]; } else { result[key] = baseValue;