diff --git a/plugin/hooks/hooks.json b/plugin/hooks/hooks.json index f12600e0..917f6bb6 100644 --- a/plugin/hooks/hooks.json +++ b/plugin/hooks/hooks.json @@ -7,7 +7,7 @@ "hooks": [ { "type": "command", - "command": "_R=\"${CLAUDE_PLUGIN_ROOT}\"; [ -z \"$_R\" ] && _R=\"$HOME/.claude/plugins/marketplaces/thedotmack/plugin\"; \"$_R/scripts/setup.sh\"", + "command": "_R=\"${CLAUDE_PLUGIN_ROOT}\"; [ -z \"$_R\" ] && _R=$(ls -dt $HOME/.claude/plugins/cache/thedotmack/claude-mem/[0-9]*/ 2>/dev/null | head -1); _R=\"${_R%/}\"; [ -z \"$_R\" ] && _R=\"$HOME/.claude/plugins/marketplaces/thedotmack/plugin\"; \"$_R/scripts/setup.sh\"", "timeout": 300 } ] @@ -19,17 +19,17 @@ "hooks": [ { "type": "command", - "command": "_R=\"${CLAUDE_PLUGIN_ROOT}\"; [ -z \"$_R\" ] && _R=\"$HOME/.claude/plugins/marketplaces/thedotmack/plugin\"; node \"$_R/scripts/smart-install.js\"", + "command": "_R=\"${CLAUDE_PLUGIN_ROOT}\"; [ -z \"$_R\" ] && _R=$(ls -dt $HOME/.claude/plugins/cache/thedotmack/claude-mem/[0-9]*/ 2>/dev/null | head -1); _R=\"${_R%/}\"; [ -z \"$_R\" ] && _R=\"$HOME/.claude/plugins/marketplaces/thedotmack/plugin\"; node \"$_R/scripts/smart-install.js\"", "timeout": 300 }, { "type": "command", - "command": "_R=\"${CLAUDE_PLUGIN_ROOT}\"; [ -z \"$_R\" ] && _R=\"$HOME/.claude/plugins/marketplaces/thedotmack/plugin\"; node \"$_R/scripts/bun-runner.js\" \"$_R/scripts/worker-service.cjs\" start; for i in 1 2 3 4 5 6 7 8; do curl -sf http://localhost:37777/health >/dev/null 2>&1 && break; sleep 1; done; curl -sf http://localhost:37777/health >/dev/null 2>&1 || exit 1; echo '{\"continue\":true,\"suppressOutput\":true}'", +"command": "_R=\"${CLAUDE_PLUGIN_ROOT}\"; [ -z \"$_R\" ] && _R=$(ls -dt $HOME/.claude/plugins/cache/thedotmack/claude-mem/[0-9]*/ 2>/dev/null | head -1); _R=\"${_R%/}\"; [ -z \"$_R\" ] && _R=\"$HOME/.claude/plugins/marketplaces/thedotmack/plugin\"; node \"$_R/scripts/bun-runner.js\" \"$_R/scripts/worker-service.cjs\" start; for i in 1 2 3 4 5 6 7 8; do curl -sf http://localhost:37777/health >/dev/null 2>&1 && break; sleep 1; done; curl -sf http://localhost:37777/health >/dev/null 2>&1 || exit 1; echo '{\"continue\":true,\"suppressOutput\":true}'", "timeout": 60 }, { "type": "command", - "command": "_R=\"${CLAUDE_PLUGIN_ROOT}\"; [ -z \"$_R\" ] && _R=\"$HOME/.claude/plugins/marketplaces/thedotmack/plugin\"; for i in 1 2 3 4 5 6 7 8; do curl -sf http://localhost:37777/health >/dev/null 2>&1 && break; sleep 1; done; node \"$_R/scripts/bun-runner.js\" \"$_R/scripts/worker-service.cjs\" hook claude-code context", +"command": "_R=\"${CLAUDE_PLUGIN_ROOT}\"; [ -z \"$_R\" ] && _R=$(ls -dt $HOME/.claude/plugins/cache/thedotmack/claude-mem/[0-9]*/ 2>/dev/null | head -1); _R=\"${_R%/}\"; [ -z \"$_R\" ] && _R=\"$HOME/.claude/plugins/marketplaces/thedotmack/plugin\"; for i in 1 2 3 4 5 6 7 8; do curl -sf http://localhost:37777/health >/dev/null 2>&1 && break; sleep 1; done; node \"$_R/scripts/bun-runner.js\" \"$_R/scripts/worker-service.cjs\" hook claude-code context", "timeout": 60 } ] @@ -40,7 +40,7 @@ "hooks": [ { "type": "command", - "command": "_R=\"${CLAUDE_PLUGIN_ROOT}\"; [ -z \"$_R\" ] && _R=\"$HOME/.claude/plugins/marketplaces/thedotmack/plugin\"; node \"$_R/scripts/bun-runner.js\" \"$_R/scripts/worker-service.cjs\" hook claude-code session-init", + "command": "_R=\"${CLAUDE_PLUGIN_ROOT}\"; [ -z \"$_R\" ] && _R=$(ls -dt $HOME/.claude/plugins/cache/thedotmack/claude-mem/[0-9]*/ 2>/dev/null | head -1); _R=\"${_R%/}\"; [ -z \"$_R\" ] && _R=\"$HOME/.claude/plugins/marketplaces/thedotmack/plugin\"; node \"$_R/scripts/bun-runner.js\" \"$_R/scripts/worker-service.cjs\" hook claude-code session-init", "timeout": 60 } ] @@ -52,7 +52,7 @@ "hooks": [ { "type": "command", - "command": "_R=\"${CLAUDE_PLUGIN_ROOT}\"; [ -z \"$_R\" ] && _R=\"$HOME/.claude/plugins/marketplaces/thedotmack/plugin\"; node \"$_R/scripts/bun-runner.js\" \"$_R/scripts/worker-service.cjs\" hook claude-code observation", + "command": "_R=\"${CLAUDE_PLUGIN_ROOT}\"; [ -z \"$_R\" ] && _R=$(ls -dt $HOME/.claude/plugins/cache/thedotmack/claude-mem/[0-9]*/ 2>/dev/null | head -1); _R=\"${_R%/}\"; [ -z \"$_R\" ] && _R=\"$HOME/.claude/plugins/marketplaces/thedotmack/plugin\"; node \"$_R/scripts/bun-runner.js\" \"$_R/scripts/worker-service.cjs\" hook claude-code observation", "timeout": 120 } ] @@ -63,7 +63,7 @@ "hooks": [ { "type": "command", - "command": "_R=\"${CLAUDE_PLUGIN_ROOT}\"; [ -z \"$_R\" ] && _R=\"$HOME/.claude/plugins/marketplaces/thedotmack/plugin\"; node \"$_R/scripts/bun-runner.js\" \"$_R/scripts/worker-service.cjs\" hook claude-code summarize", + "command": "_R=\"${CLAUDE_PLUGIN_ROOT}\"; [ -z \"$_R\" ] && _R=$(ls -dt $HOME/.claude/plugins/cache/thedotmack/claude-mem/[0-9]*/ 2>/dev/null | head -1); _R=\"${_R%/}\"; [ -z \"$_R\" ] && _R=\"$HOME/.claude/plugins/marketplaces/thedotmack/plugin\"; node \"$_R/scripts/bun-runner.js\" \"$_R/scripts/worker-service.cjs\" hook claude-code summarize", "timeout": 120 } ] @@ -74,8 +74,8 @@ "hooks": [ { "type": "command", - "command": "node -e \"let d='';process.stdin.on('data',c=>d+=c);process.stdin.on('end',()=>{try{const{sessionId:s}=JSON.parse(d);if(!s){process.exit(0)}const r=require('http').request({hostname:'127.0.0.1',port:37777,path:'/api/sessions/complete',method:'POST',headers:{'Content-Type':'application/json'}});r.on('error',()=>{});r.end(JSON.stringify({contentSessionId:s}));process.exit(0)}catch{process.exit(0)}})\"", - "timeout": 2 +"command": "_R=\"${CLAUDE_PLUGIN_ROOT}\"; [ -z \"$_R\" ] && _R=$(ls -dt $HOME/.claude/plugins/cache/thedotmack/claude-mem/[0-9]*/ 2>/dev/null | head -1); _R=\"${_R%/}\"; [ -z \"$_R\" ] && _R=\"$HOME/.claude/plugins/marketplaces/thedotmack/plugin\"; node \"$_R/scripts/bun-runner.js\" \"$_R/scripts/worker-service.cjs\" hook claude-code session-complete", + "timeout": 30 } ] } diff --git a/tests/infrastructure/plugin-distribution.test.ts b/tests/infrastructure/plugin-distribution.test.ts index aecd2035..7daeb380 100644 --- a/tests/infrastructure/plugin-distribution.test.ts +++ b/tests/infrastructure/plugin-distribution.test.ts @@ -67,14 +67,11 @@ describe('Plugin Distribution - hooks.json Integrity', () => { expect(parsed.hooks).toBeDefined(); }); - it('should reference CLAUDE_PLUGIN_ROOT in all hook commands (except inline hooks)', () => { + it('should reference CLAUDE_PLUGIN_ROOT in all hook commands', () => { const hooksPath = path.join(projectRoot, 'plugin/hooks/hooks.json'); const parsed = JSON.parse(readFileSync(hooksPath, 'utf-8')); - // SessionEnd uses a lightweight inline node -e command (no plugin root needed) - const inlineHookEvents = new Set(['SessionEnd']); for (const [eventName, matchers] of Object.entries(parsed.hooks)) { - if (inlineHookEvents.has(eventName)) continue; for (const matcher of matchers as any[]) { for (const hook of matcher.hooks) { if (hook.type === 'command') { @@ -85,14 +82,12 @@ describe('Plugin Distribution - hooks.json Integrity', () => { } }); - it('should include CLAUDE_PLUGIN_ROOT fallback in all hook commands except inline hooks (#1215)', () => { + it('should include CLAUDE_PLUGIN_ROOT fallback in all hook commands (#1215)', () => { const hooksPath = path.join(projectRoot, 'plugin/hooks/hooks.json'); const parsed = JSON.parse(readFileSync(hooksPath, 'utf-8')); const expectedFallbackPath = '$HOME/.claude/plugins/marketplaces/thedotmack/plugin'; - const inlineHookEvents = new Set(['SessionEnd']); for (const [eventName, matchers] of Object.entries(parsed.hooks)) { - if (inlineHookEvents.has(eventName)) continue; for (const matcher of matchers as any[]) { for (const hook of matcher.hooks) { if (hook.type === 'command') { @@ -103,16 +98,23 @@ describe('Plugin Distribution - hooks.json Integrity', () => { } }); - it('should use lightweight inline node command for SessionEnd hook', () => { + it('should try cache path before marketplaces fallback in all hook commands (#1533)', () => { const hooksPath = path.join(projectRoot, 'plugin/hooks/hooks.json'); const parsed = JSON.parse(readFileSync(hooksPath, 'utf-8')); - const sessionEndHooks = parsed.hooks.SessionEnd; - expect(sessionEndHooks).toBeDefined(); - expect(sessionEndHooks.length).toBe(1); - const command = sessionEndHooks[0].hooks[0].command; - expect(command).toContain('node -e'); - expect(command).toContain('/api/sessions/complete'); - expect(sessionEndHooks[0].hooks[0].timeout).toBeLessThanOrEqual(10); + const cachePath = '$HOME/.claude/plugins/cache/thedotmack/claude-mem'; + const marketplacesPath = '$HOME/.claude/plugins/marketplaces/thedotmack/plugin'; + + for (const [eventName, matchers] of Object.entries(parsed.hooks)) { + for (const matcher of matchers as any[]) { + for (const hook of matcher.hooks) { + if (hook.type === 'command') { + expect(hook.command).toContain(cachePath); + // Cache lookup must appear before the final marketplaces fallback + expect(hook.command.indexOf(cachePath)).toBeLessThan(hook.command.indexOf(marketplacesPath)); + } + } + } + } }); });