diff --git a/claude-config/hooks/role-router.mjs b/claude-config/hooks/role-router.mjs index 70e9a27..aa0f339 100755 --- a/claude-config/hooks/role-router.mjs +++ b/claude-config/hooks/role-router.mjs @@ -14,9 +14,11 @@ import { readFileSync } from 'fs'; -export const DEV_RE = /(?:\b(?:dev|develop|develops?|implement|implements?|refactor|refactors?|fix|fixes|bug|bugs|hotfix|patch|patches|impl)\b|开发|实现|重构|修(?:复|bug)|写代码|编码|添加功能|新功能|改(?:bug|代码))/i; +export const DEV_RE = /(?:\b(?:dev|develops?|implements?|refactors?|fixes?|bugs?|hotfix|patch(?:es)?|impl)\b|开发|实现|重构|修(?:复|bug)|写代码|编码|添加功能|新功能|改(?:bug|代码))/i; export const TEST_RE = /(?:\b(?:tests?|qa|unit\s?tests?|regression|e2e|integration\s?tests?|specs?)\b|测试|单测|单元测试|回归(?:测试)?|集成测试|端到端|质量保证|QA)/i; -export const PM_RE = /(?:\b(?:pm|product|spec|requirement|roadmap|planning|backlog|user\s?story|prd)\b|产品(?:经理)?|需求|排期|规划|计划|调研|路线图|用户故事)/i; +export const PM_RE = /(?:\b(?:pm|product|spec|requirements?|roadmap|planning|backlog|user\s?story|prd)\b|产品(?:经理)?|需求|排期|规划|计划|调研|路线图|用户故事)/i; + +const NOOP = JSON.stringify({ continue: true, suppressOutput: true }); const ROLE_HINTS = { dev: ` @@ -63,30 +65,21 @@ function readStdinSync() { function main() { try { const raw = readStdinSync(); - if (!raw) { - console.log(JSON.stringify({ continue: true, suppressOutput: true })); - return; - } + if (!raw) { console.log(NOOP); return; } const data = JSON.parse(raw); const prompt = data.prompt || data.user_prompt || ''; - if (!prompt) { - console.log(JSON.stringify({ continue: true, suppressOutput: true })); - return; - } - const roles = detectRoles(prompt); - const ctx = buildContext(roles); - if (!ctx) { - console.log(JSON.stringify({ continue: true, suppressOutput: true })); - return; - } + if (!prompt) { console.log(NOOP); return; } + const ctx = buildContext(detectRoles(prompt)); + if (!ctx) { console.log(NOOP); return; } console.log(JSON.stringify({ hookSpecificOutput: { hookEventName: 'UserPromptSubmit', additionalContext: ctx, }, })); - } catch { - console.log(JSON.stringify({ continue: true, suppressOutput: true })); + } catch (e) { + console.error('[role-router]', e.message); + console.log(NOOP); } } diff --git a/claude-config/hooks/role-router.test.mjs b/claude-config/hooks/role-router.test.mjs index e0c7599..77b5c6f 100755 --- a/claude-config/hooks/role-router.test.mjs +++ b/claude-config/hooks/role-router.test.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node /** - * role-router unit tests — 6 fixture (每角色 2 条) + * role-router unit tests — 10 tests (8 fixture + 2 subprocess integration) * 跑法: node role-router.test.mjs */ @@ -27,9 +27,11 @@ const fixtures = [ let pass = 0, fail = 0; const failures = []; +const sortKey = a => a.slice().sort().join(','); + for (const f of fixtures) { const got = detectRoles(f.prompt); - const ok = JSON.stringify(got.sort()) === JSON.stringify(f.expect.sort()); + const ok = sortKey(got) === sortKey(f.expect); if (ok) { pass++; console.log(`PASS "${f.prompt}" → [${got.join(',')}]`);