deslop(claude): role-router 简化 + regex 去重 + stderr 错误日志

按 critic + 3 reviewer agent 反馈:
- HIGH: bare catch {} 改 catch(e){console.error(...)} 暴露 bug
- MED: regex 去重复 (develop|develops? → develops?, fix|fixes → fixes?, requirement|requirements? → requirements?)
- MED: 4 处 {continue:true,suppressOutput:true} 抽 NOOP 常量
- MED: test JSON.stringify(.sort()) → 不可变的 sortKey helper
- skip: createHookOutput 抽 lib (违反"不改 OMC keyword-detector" 决策)
- skip: ROLES enum (3 值 over-engineering)

post-deslop 回归: 10/10 PASS

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
pp
2026-04-26 21:44:18 +08:00
parent 8915fa2898
commit 1445214c3c
2 changed files with 15 additions and 20 deletions

View File

@@ -14,9 +14,11 @@
import { readFileSync } from 'fs'; 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 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 = { const ROLE_HINTS = {
dev: `<role-routing role="dev"> dev: `<role-routing role="dev">
@@ -63,30 +65,21 @@ function readStdinSync() {
function main() { function main() {
try { try {
const raw = readStdinSync(); const raw = readStdinSync();
if (!raw) { if (!raw) { console.log(NOOP); return; }
console.log(JSON.stringify({ continue: true, suppressOutput: true }));
return;
}
const data = JSON.parse(raw); const data = JSON.parse(raw);
const prompt = data.prompt || data.user_prompt || ''; const prompt = data.prompt || data.user_prompt || '';
if (!prompt) { if (!prompt) { console.log(NOOP); return; }
console.log(JSON.stringify({ continue: true, suppressOutput: true })); const ctx = buildContext(detectRoles(prompt));
return; if (!ctx) { console.log(NOOP); return; }
}
const roles = detectRoles(prompt);
const ctx = buildContext(roles);
if (!ctx) {
console.log(JSON.stringify({ continue: true, suppressOutput: true }));
return;
}
console.log(JSON.stringify({ console.log(JSON.stringify({
hookSpecificOutput: { hookSpecificOutput: {
hookEventName: 'UserPromptSubmit', hookEventName: 'UserPromptSubmit',
additionalContext: ctx, additionalContext: ctx,
}, },
})); }));
} catch { } catch (e) {
console.log(JSON.stringify({ continue: true, suppressOutput: true })); console.error('[role-router]', e.message);
console.log(NOOP);
} }
} }

View File

@@ -1,6 +1,6 @@
#!/usr/bin/env node #!/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 * 跑法: node role-router.test.mjs
*/ */
@@ -27,9 +27,11 @@ const fixtures = [
let pass = 0, fail = 0; let pass = 0, fail = 0;
const failures = []; const failures = [];
const sortKey = a => a.slice().sort().join(',');
for (const f of fixtures) { for (const f of fixtures) {
const got = detectRoles(f.prompt); 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) { if (ok) {
pass++; pass++;
console.log(`PASS "${f.prompt}" → [${got.join(',')}]`); console.log(`PASS "${f.prompt}" → [${got.join(',')}]`);