Merge branch 'pr-1557' into integration/validation-batch

# Conflicts:
#	plugin/hooks/hooks.json
#	tests/infrastructure/plugin-distribution.test.ts
This commit is contained in:
Alex Newman
2026-04-06 14:20:49 -07:00
2 changed files with 26 additions and 24 deletions
+9 -9
View File
@@ -7,7 +7,7 @@
"hooks": [ "hooks": [
{ {
"type": "command", "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 "timeout": 300
} }
] ]
@@ -19,17 +19,17 @@
"hooks": [ "hooks": [
{ {
"type": "command", "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 "timeout": 300
}, },
{ {
"type": "command", "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 "timeout": 60
}, },
{ {
"type": "command", "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 "timeout": 60
} }
] ]
@@ -40,7 +40,7 @@
"hooks": [ "hooks": [
{ {
"type": "command", "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 "timeout": 60
} }
] ]
@@ -52,7 +52,7 @@
"hooks": [ "hooks": [
{ {
"type": "command", "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 "timeout": 120
} }
] ]
@@ -63,7 +63,7 @@
"hooks": [ "hooks": [
{ {
"type": "command", "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 "timeout": 120
} }
] ]
@@ -74,8 +74,8 @@
"hooks": [ "hooks": [
{ {
"type": "command", "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)}})\"", "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": 2 "timeout": 30
} }
] ]
} }
@@ -67,14 +67,11 @@ describe('Plugin Distribution - hooks.json Integrity', () => {
expect(parsed.hooks).toBeDefined(); 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 hooksPath = path.join(projectRoot, 'plugin/hooks/hooks.json');
const parsed = JSON.parse(readFileSync(hooksPath, 'utf-8')); 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)) { for (const [eventName, matchers] of Object.entries(parsed.hooks)) {
if (inlineHookEvents.has(eventName)) continue;
for (const matcher of matchers as any[]) { for (const matcher of matchers as any[]) {
for (const hook of matcher.hooks) { for (const hook of matcher.hooks) {
if (hook.type === 'command') { 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 hooksPath = path.join(projectRoot, 'plugin/hooks/hooks.json');
const parsed = JSON.parse(readFileSync(hooksPath, 'utf-8')); const parsed = JSON.parse(readFileSync(hooksPath, 'utf-8'));
const expectedFallbackPath = '$HOME/.claude/plugins/marketplaces/thedotmack/plugin'; const expectedFallbackPath = '$HOME/.claude/plugins/marketplaces/thedotmack/plugin';
const inlineHookEvents = new Set(['SessionEnd']);
for (const [eventName, matchers] of Object.entries(parsed.hooks)) { for (const [eventName, matchers] of Object.entries(parsed.hooks)) {
if (inlineHookEvents.has(eventName)) continue;
for (const matcher of matchers as any[]) { for (const matcher of matchers as any[]) {
for (const hook of matcher.hooks) { for (const hook of matcher.hooks) {
if (hook.type === 'command') { 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 hooksPath = path.join(projectRoot, 'plugin/hooks/hooks.json');
const parsed = JSON.parse(readFileSync(hooksPath, 'utf-8')); const parsed = JSON.parse(readFileSync(hooksPath, 'utf-8'));
const sessionEndHooks = parsed.hooks.SessionEnd; const cachePath = '$HOME/.claude/plugins/cache/thedotmack/claude-mem';
expect(sessionEndHooks).toBeDefined(); const marketplacesPath = '$HOME/.claude/plugins/marketplaces/thedotmack/plugin';
expect(sessionEndHooks.length).toBe(1);
const command = sessionEndHooks[0].hooks[0].command; for (const [eventName, matchers] of Object.entries(parsed.hooks)) {
expect(command).toContain('node -e'); for (const matcher of matchers as any[]) {
expect(command).toContain('/api/sessions/complete'); for (const hook of matcher.hooks) {
expect(sessionEndHooks[0].hooks[0].timeout).toBeLessThanOrEqual(10); 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));
}
}
}
}
}); });
}); });