diff --git a/hooks/gsd-check-update.js b/hooks/gsd-check-update.js index 1b7b27ed3..d9fd4bfaf 100755 --- a/hooks/gsd-check-update.js +++ b/hooks/gsd-check-update.js @@ -29,7 +29,10 @@ function detectConfigDir(baseDir) { const globalConfigDir = detectConfigDir(homeDir); const projectConfigDir = detectConfigDir(cwd); -const cacheDir = path.join(globalConfigDir, 'cache'); +// Use a shared, tool-agnostic cache directory to avoid multi-runtime +// resolution mismatches where check-update writes to one runtime's cache +// but statusline reads from another (#1421). +const cacheDir = path.join(homeDir, '.cache', 'gsd'); const cacheFile = path.join(cacheDir, 'gsd-update-check.json'); // VERSION file locations (check project first, then global) @@ -65,10 +68,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/ + // Hooks are installed at configDir/hooks/ (e.g. ~/.claude/hooks/) (#1421) let staleHooks = []; if (configDir) { - const hooksDir = path.join(configDir, 'get-shit-done', 'hooks'); + const hooksDir = path.join(configDir, 'hooks'); try { if (fs.existsSync(hooksDir)) { const hookFiles = fs.readdirSync(hooksDir).filter(f => f.startsWith('gsd-') && f.endsWith('.js')); diff --git a/hooks/gsd-statusline.js b/hooks/gsd-statusline.js index ae7025b99..32742693e 100755 --- a/hooks/gsd-statusline.js +++ b/hooks/gsd-statusline.js @@ -92,8 +92,12 @@ process.stdin.on('end', () => { } // GSD update available? + // Check shared cache first (#1421), fall back to runtime-specific cache for + // backward compatibility with older gsd-check-update.js versions. let gsdUpdate = ''; - const cacheFile = path.join(claudeDir, 'cache', 'gsd-update-check.json'); + const sharedCacheFile = path.join(homeDir, '.cache', 'gsd', 'gsd-update-check.json'); + const legacyCacheFile = path.join(claudeDir, 'cache', 'gsd-update-check.json'); + const cacheFile = fs.existsSync(sharedCacheFile) ? sharedCacheFile : legacyCacheFile; if (fs.existsSync(cacheFile)) { try { const cache = JSON.parse(fs.readFileSync(cacheFile, 'utf8')); diff --git a/tests/core.test.cjs b/tests/core.test.cjs index 4211b3f8e..f329bffa7 100644 --- a/tests/core.test.cjs +++ b/tests/core.test.cjs @@ -996,19 +996,15 @@ 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/', () => { + test('gsd-check-update.js checks configDir/hooks/ where hooks are actually installed (#1421)', () => { const content = fs.readFileSync( path.join(__dirname, '..', 'hooks', 'gsd-check-update.js'), 'utf-8' ); + // Hooks are installed at configDir/hooks/ (e.g. ~/.claude/hooks/), + // not configDir/get-shit-done/hooks/ which doesn't exist (#1421) 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' + content.includes("path.join(configDir, 'hooks')"), + 'stale hook check must look in configDir/hooks/ where hooks are actually installed' ); }); });