diff --git a/bin/install.js b/bin/install.js index 674120eb4..4f8eeced7 100755 --- a/bin/install.js +++ b/bin/install.js @@ -3900,6 +3900,11 @@ function install(isGlobal, runtime = 'claude') { } } + // Clear stale update cache so next session re-evaluates hook versions + // targetDir is e.g. ~/.claude/get-shit-done/, parent is the config dir + const updateCacheFile = path.join(path.dirname(targetDir), 'cache', 'gsd-update-check.json'); + try { fs.unlinkSync(updateCacheFile); } catch (e) { /* cache may not exist yet */ } + if (failures.length > 0) { console.error(`\n ${yellow}Installation incomplete!${reset} Failed: ${failures.join(', ')}`); process.exit(1); diff --git a/hooks/gsd-check-update.js b/hooks/gsd-check-update.js index 9076ec038..1b7b27ed3 100755 --- a/hooks/gsd-check-update.js +++ b/hooks/gsd-check-update.js @@ -65,9 +65,10 @@ const child = spawn(process.execPath, ['-e', ` } catch (e) {} // Check for stale hooks — compare hook version headers against installed VERSION + // Hooks live inside get-shit-done/hooks/, not configDir/hooks/ let staleHooks = []; if (configDir) { - const hooksDir = path.join(configDir, 'hooks'); + const hooksDir = path.join(configDir, 'get-shit-done', 'hooks'); try { if (fs.existsSync(hooksDir)) { const hookFiles = fs.readdirSync(hooksDir).filter(f => f.startsWith('gsd-') && f.endsWith('.js')); diff --git a/tests/core.test.cjs b/tests/core.test.cjs index e43f53f9f..251793d46 100644 --- a/tests/core.test.cjs +++ b/tests/core.test.cjs @@ -967,6 +967,26 @@ describe('stale hook filter', () => { }); }); +// ─── stale hook path regression (#1249) ────────────────────────────────────── + +describe('stale hook path', () => { + test('gsd-check-update.js checks get-shit-done/hooks/ not configDir/hooks/', () => { + const content = fs.readFileSync( + path.join(__dirname, '..', 'hooks', 'gsd-check-update.js'), 'utf-8' + ); + assert.ok( + content.includes("path.join(configDir, 'get-shit-done', 'hooks')"), + 'stale hook check must look in configDir/get-shit-done/hooks/, not configDir/hooks/' + ); + assert.ok( + !content.includes("path.join(configDir, 'hooks')") || + content.indexOf("path.join(configDir, 'get-shit-done', 'hooks')") < + content.indexOf("path.join(configDir, 'hooks')") + 100, // allow the old pattern only if corrected version exists first + 'should not use the wrong hooks path' + ); + }); +}); + // ─── resolveWorktreeRoot ───────────────────────────────────────────────────── describe('resolveWorktreeRoot', () => {