BMAD-METHOD/tools/claude-code-hooks/reality-guard.js

94 lines
2.9 KiB
JavaScript

#!/usr/bin/env node
/**
* BMAD Reality Guard Hook
* Prevents creation of mock/stub implementations
* Runs on PreToolUse for Write operations
*/
const fs = require('fs-extra');
async function checkForSimulationPatterns() {
try {
const toolInput = JSON.parse(process.env.CLAUDE_CODE_TOOL_INPUT || '{}');
const content = toolInput.content || '';
const filePath = toolInput.file_path || '';
// Simulation patterns to detect
const simulationPatterns = [
/\/\/\s*TODO:?\s*[Ii]mplement/i,
/throw\s+new\s+NotImplementedException/i,
/return\s+(null|undefined|""|''|0|false|Mock|Stub)/i,
/console\.(log|warn|error)\s*\(\s*["']Not implemented/i,
/\bmock\w*\s*[:=]/i,
/\bstub\w*\s*[:=]/i,
/return\s+Task\.CompletedTask\s*;?\s*$/m,
/^\s*pass\s*$/m,
/^\s*\.\.\.\s*$/m,
/return\s+\{\s*\}\s*;?\s*$/m
];
// Check if it's a test file (allow mocks in tests)
const isTestFile = /\.(test|spec|mock|stub)\.(js|ts|jsx|tsx|cs|py)$/i.test(filePath);
if (!isTestFile) {
for (const pattern of simulationPatterns) {
if (pattern.test(content)) {
return {
approve: false,
message: 'BMAD Reality Guard: Detected simulation pattern. ' +
'Please provide complete, functional implementation. ' +
'No stubs, mocks, or placeholders allowed in production code.'
};
}
}
}
// Additional check for empty method bodies
const emptyMethodPattern = /\{[\s\n]*\}/g;
const methodSignatures = content.match(/\b(function|async\s+function|def|public|private|protected)\s+\w+\s*\([^)]*\)\s*[^{]*/g);
if (methodSignatures) {
for (const sig of methodSignatures) {
const afterSig = content.substring(content.indexOf(sig) + sig.length);
const firstBrace = afterSig.indexOf('{');
if (firstBrace !== -1) {
const methodBody = extractBalancedBraces(afterSig.substring(firstBrace));
if (methodBody && methodBody.replace(/[\s\n]/g, '') === '{}') {
return {
approve: false,
message: 'BMAD Reality Guard: Empty method body detected. ' +
'All methods must contain functional implementation.'
};
}
}
}
}
console.log(JSON.stringify({ approve: true }));
} catch (error) {
// On error, approve to avoid blocking
console.log(JSON.stringify({ approve: true }));
}
}
function extractBalancedBraces(str) {
let depth = 0;
let start = -1;
for (let i = 0; i < str.length; i++) {
if (str[i] === '{') {
if (depth === 0) start = i;
depth++;
} else if (str[i] === '}') {
depth--;
if (depth === 0 && start !== -1) {
return str.substring(start, i + 1);
}
}
}
return null;
}
checkForSimulationPatterns();