mirror of
https://github.com/kochetkov-ma/claude-brewcode.git
synced 2026-09-14 20:16:41 +08:00
v4.7.0: brewtools:agent-router (experimental) + hook timeout units are seconds
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "brewcode",
|
||||
"version": "4.6.0",
|
||||
"version": "4.7.0",
|
||||
"description": "Brewcode - full-featured development platform for Claude Code: infinite focus tasks, prompt optimization, skill/agent creation, quorum reviews, rules management",
|
||||
"author": {
|
||||
"name": "Maksim Kochetkov",
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@
|
||||
|
||||
| Field | Value |
|
||||
|-------|-------|
|
||||
| Version | 4.6.0 |
|
||||
| Version | 4.7.0 |
|
||||
| Skills | 9 |
|
||||
| Agents | 10 |
|
||||
| Hooks | 2 |
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
"type": "command",
|
||||
"command": "node",
|
||||
"args": ["${CLAUDE_PLUGIN_ROOT}/hooks/forced-eval.mjs"],
|
||||
"timeout": 1000
|
||||
"timeout": 2
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -19,7 +19,7 @@
|
||||
"type": "command",
|
||||
"command": "node",
|
||||
"args": ["${CLAUDE_PLUGIN_ROOT}/hooks/session-start.mjs"],
|
||||
"timeout": 3000
|
||||
"timeout": 3
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "claude-plugin-brewcode",
|
||||
"version": "4.6.0",
|
||||
"version": "4.7.0",
|
||||
"description": "Infinite task execution with automatic handoff for Claude Code",
|
||||
"keywords": [
|
||||
"claude-code",
|
||||
@@ -36,6 +36,6 @@
|
||||
},
|
||||
"claude-plugin": {
|
||||
"name": "brewcode",
|
||||
"version": "4.6.0"
|
||||
"version": "4.7.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -188,14 +188,14 @@ process. The matcher is exactly `Explore` — no other subagent type is touched.
|
||||
{
|
||||
"hooks": {
|
||||
"SessionStart": [
|
||||
{ "hooks": [ { "type": "command", "command": "node", "args": ["<absdir>/semble-session.mjs"], "timeout": 5000 } ] }
|
||||
{ "hooks": [ { "type": "command", "command": "node", "args": ["<absdir>/semble-session.mjs"], "timeout": 5 } ] }
|
||||
],
|
||||
"PreToolUse": [
|
||||
{ "matcher": "Bash", "hooks": [ { "type": "command", "command": "node", "args": ["<absdir>/semble-reminder.mjs"], "timeout": 5000 } ] },
|
||||
{ "matcher": "Grep", "hooks": [ { "type": "command", "command": "node", "args": ["<absdir>/semble-reminder.mjs"], "timeout": 5000 } ] }
|
||||
{ "matcher": "Bash", "hooks": [ { "type": "command", "command": "node", "args": ["<absdir>/semble-reminder.mjs"], "timeout": 5 } ] },
|
||||
{ "matcher": "Grep", "hooks": [ { "type": "command", "command": "node", "args": ["<absdir>/semble-reminder.mjs"], "timeout": 5 } ] }
|
||||
],
|
||||
"SubagentStart": [
|
||||
{ "matcher": "Explore", "hooks": [ { "type": "command", "command": "node", "args": ["<absdir>/semble-explore.mjs"], "timeout": 5000 } ] }
|
||||
{ "matcher": "Explore", "hooks": [ { "type": "command", "command": "node", "args": ["<absdir>/semble-explore.mjs"], "timeout": 5 } ] }
|
||||
]
|
||||
},
|
||||
"permissions": {
|
||||
@@ -204,9 +204,9 @@ process. The matcher is exactly `Explore` — no other subagent type is touched.
|
||||
}
|
||||
```
|
||||
|
||||
`timeout` is in MILLISECONDS and is **not optional**: an entry without it
|
||||
inherits Claude Code's 60 s default, so a hung `node` on the `Bash` matcher would
|
||||
stall every tool call in the session for a minute. 5000 is ~80x the measured
|
||||
`timeout` is in SECONDS and is **not optional**: an entry without it
|
||||
inherits Claude Code's 600 s default, so a hung `node` on the `Bash` matcher would
|
||||
stall the tool call for 10 minutes. 5 s is ~80x the measured
|
||||
runtime of these hooks.
|
||||
|
||||
The marker for all semble entries is `args` containing a path whose basename is
|
||||
@@ -243,10 +243,10 @@ SETTINGS="$PWD/.claude/settings.json" HOOKS_DIR="$PWD/.claude/hooks" node -e '
|
||||
const fs=require("fs"), path=require("path");
|
||||
const f=process.env.SETTINGS, dir=process.env.HOOKS_DIR;
|
||||
const marks=["semble-session.mjs","semble-reminder.mjs","semble-explore.mjs"];
|
||||
const want=[["SessionStart",null,"semble-session.mjs",5000],
|
||||
["PreToolUse","Bash","semble-reminder.mjs",5000],
|
||||
["PreToolUse","Grep","semble-reminder.mjs",5000],
|
||||
["SubagentStart","Explore","semble-explore.mjs",5000]];
|
||||
const want=[["SessionStart",null,"semble-session.mjs",5],
|
||||
["PreToolUse","Bash","semble-reminder.mjs",5],
|
||||
["PreToolUse","Grep","semble-reminder.mjs",5],
|
||||
["SubagentStart","Explore","semble-explore.mjs",5]];
|
||||
const tools=["mcp__semble_code__search","mcp__semble_code__find_related"];
|
||||
let s={};
|
||||
if(fs.existsSync(f)){
|
||||
|
||||
@@ -327,10 +327,10 @@ const fs=require("fs"), path=require("path");
|
||||
const f=process.env.SG_SETTINGS, dir=process.env.SG_HOOKS;
|
||||
const doHooks=process.env.SG_DO_HOOKS==="1", doPerms=process.env.SG_DO_PERMS==="1";
|
||||
const marks=["semble-session.mjs","semble-reminder.mjs","semble-explore.mjs"];
|
||||
const want=[["SessionStart",null,"semble-session.mjs",5000],
|
||||
["PreToolUse","Bash","semble-reminder.mjs",5000],
|
||||
["PreToolUse","Grep","semble-reminder.mjs",5000],
|
||||
["SubagentStart","Explore","semble-explore.mjs",5000]];
|
||||
const want=[["SessionStart",null,"semble-session.mjs",5],
|
||||
["PreToolUse","Bash","semble-reminder.mjs",5],
|
||||
["PreToolUse","Grep","semble-reminder.mjs",5],
|
||||
["SubagentStart","Explore","semble-explore.mjs",5]];
|
||||
const tools=[process.env.SG_SEARCH,process.env.SG_RELATED];
|
||||
let s={};
|
||||
if(fs.existsSync(f)){
|
||||
|
||||
@@ -261,14 +261,14 @@ const REMIND_OK = (cwd) => ({
|
||||
const s = readSettings(p);
|
||||
const { session, reminder: rem, explore: exp } = semblePaths(p);
|
||||
check('A1.sessionEntry', s.hooks.SessionStart, [
|
||||
{ hooks: [{ type: 'command', command: 'node', args: [session], timeout: 5000 }] },
|
||||
], 'SessionStart entry has the exact contract shape with an explicit 5000 ms timeout');
|
||||
{ hooks: [{ type: 'command', command: 'node', args: [session], timeout: 5 }] },
|
||||
], 'SessionStart entry has the exact contract shape with an explicit 5 s timeout');
|
||||
check('A1.preToolUse', s.hooks.PreToolUse, [
|
||||
{ hooks: [{ type: 'command', command: 'node', args: [rem], timeout: 5000 }], matcher: 'Bash' },
|
||||
{ hooks: [{ type: 'command', command: 'node', args: [rem], timeout: 5000 }], matcher: 'Grep' },
|
||||
{ hooks: [{ type: 'command', command: 'node', args: [rem], timeout: 5 }], matcher: 'Bash' },
|
||||
{ hooks: [{ type: 'command', command: 'node', args: [rem], timeout: 5 }], matcher: 'Grep' },
|
||||
], 'the reminder is registered once under Bash and once under Grep');
|
||||
check('A1.subagentStart', s.hooks.SubagentStart, [
|
||||
{ hooks: [{ type: 'command', command: 'node', args: [exp], timeout: 5000 }], matcher: 'Explore' },
|
||||
{ hooks: [{ type: 'command', command: 'node', args: [exp], timeout: 5 }], matcher: 'Explore' },
|
||||
], 'the explore hook is registered once under SubagentStart with matcher Explore');
|
||||
check('A1.perm', s.permissions.allow, ['mcp__semble_code__search', 'mcp__semble_code__find_related'],
|
||||
'both MCP tool names land in permissions.allow');
|
||||
@@ -358,10 +358,10 @@ const FOREIGN = {
|
||||
const seed = {
|
||||
hooks: {
|
||||
SessionStart: [
|
||||
{ hooks: [{ type: 'command', command: 'node', args: [staleDir + '/semble-session.mjs'], timeout: 5000 }] },
|
||||
{ hooks: [{ type: 'command', command: 'node', args: [staleDir + '/semble-session.mjs'], timeout: 5 }] },
|
||||
],
|
||||
PreToolUse: [
|
||||
{ matcher: 'Bash', hooks: [{ type: 'command', command: 'node', args: [staleDir + '/semble-reminder.mjs'], timeout: 5000 }] },
|
||||
{ matcher: 'Bash', hooks: [{ type: 'command', command: 'node', args: [staleDir + '/semble-reminder.mjs'], timeout: 5 }] },
|
||||
{ matcher: 'Write', hooks: [{ type: 'command', command: 'node', args: ['/opt/foreign/other.mjs'], timeout: 2000 }] },
|
||||
],
|
||||
},
|
||||
@@ -955,7 +955,7 @@ const PRE_MD = '# CLAUDE.md\n\n## Overview\n\nproject text\n';
|
||||
const FOREIGN_HOOK = { type: 'command', command: 'node', args: ['/opt/foreign/guard.mjs'], timeout: 3000 };
|
||||
{
|
||||
const staleDir = '/old/elsewhere/.claude/hooks';
|
||||
const staleHook = { type: 'command', command: 'node', args: [staleDir + '/semble-reminder.mjs'], timeout: 5000 };
|
||||
const staleHook = { type: 'command', command: 'node', args: [staleDir + '/semble-reminder.mjs'], timeout: 5 };
|
||||
const seed = { hooks: { PreToolUse: [{ matcher: 'Bash', hooks: [FOREIGN_HOOK, staleHook] }] } };
|
||||
const p = freshProject({ settings: JSON.stringify(seed, null, 2) + '\n' });
|
||||
const r = guidance(p, ['install', '--part', 'hooks', '--json']);
|
||||
|
||||
Reference in New Issue
Block a user