diff --git a/bin/install.js b/bin/install.js index 7f9d8ded9..cb1662673 100755 --- a/bin/install.js +++ b/bin/install.js @@ -4432,7 +4432,7 @@ function uninstall(isGlobal, runtime = 'claude') { const before = JSON.stringify(settings.hooks[eventName]); settings.hooks[eventName] = settings.hooks[eventName] .map(entry => { - if (!entry.hooks || !Array.isArray(entry.hooks)) return null; + if (!entry.hooks || !Array.isArray(entry.hooks)) return entry; // Filter out individual GSD hooks, keep user hooks entry.hooks = entry.hooks.filter(h => !isGsdHookCommand(h.command)); return entry.hooks.length > 0 ? entry : null; diff --git a/tests/install-hooks-copy.test.cjs b/tests/install-hooks-copy.test.cjs index 309190c10..422a2ff24 100644 --- a/tests/install-hooks-copy.test.cjs +++ b/tests/install-hooks-copy.test.cjs @@ -325,7 +325,7 @@ describe('uninstall settings cleanup preserves user hooks', () => { function filterGsdHooks(entries) { return entries .map(entry => { - if (!entry.hooks || !Array.isArray(entry.hooks)) return null; + if (!entry.hooks || !Array.isArray(entry.hooks)) return entry; entry.hooks = entry.hooks.filter(h => !isGsdHookCommand(h.command)); return entry.hooks.length > 0 ? entry : null; }) @@ -372,6 +372,19 @@ describe('uninstall settings cleanup preserves user hooks', () => { assert.strictEqual(result[0].hooks.length, 1, 'user hook should remain'); }); + test('non-array hook entries are preserved during uninstall (#1825)', () => { + const entries = [ + { type: 'custom', command: 'echo hello' }, + { matcher: 'Bash', hooks: [{ type: 'command', command: 'node /path/to/gsd-prompt-guard.js' }] }, + { url: 'https://example.com/webhook' }, + ]; + + const result = filterGsdHooks(JSON.parse(JSON.stringify(entries))); + assert.strictEqual(result.length, 2, 'both non-array entries should survive'); + assert.deepStrictEqual(result[0], { type: 'custom', command: 'echo hello' }, 'first non-array entry preserved'); + assert.deepStrictEqual(result[1], { url: 'https://example.com/webhook' }, 'second non-array entry preserved'); + }); + test('all GSD hook names are recognized by isGsdHookCommand', () => { const gsdCommands = [ 'node /path/gsd-check-update.js',