#!/usr/bin/env node /** * Stop Hook: Check for console.log statements in modified files * * Cross-platform (Windows, macOS, Linux) * * Runs after each response and checks if any modified JavaScript/TypeScript * files contain console.log statements. Provides warnings to help developers * remember to remove debug statements before committing. * * Exclusions: test files, config files, and scripts/ directory (where * console.log is often intentional). */ const fs = require('fs'); const { isGitRepo, getGitModifiedFiles, readFile, log } = require('../lib/utils'); // Files where console.log is expected and should not trigger warnings const EXCLUDED_PATTERNS = [ /\.test\.[jt]sx?$/, /\.spec\.[jt]sx?$/, /\.config\.[jt]s$/, /scripts\//, /__tests__\//, /__mocks__\//, ]; const MAX_STDIN = 1024 * 1024; // 1MB limit let data = ''; let truncated = false; process.stdin.setEncoding('utf8'); process.stdin.on('data', chunk => { if (data.length < MAX_STDIN) { const remaining = MAX_STDIN - data.length; data += chunk.substring(0, remaining); if (chunk.length > remaining) truncated = true; } else { truncated = true; } }); /** * Echo stdin back (ECC pass-through convention), then exit once the pipe has * flushed. Truncated stdin is never echoed: a JSON document cut mid-stream is * reported by the harness as a Stop hook JSON validation failure (#2090). */ function passThroughAndExit() { if (truncated) { log('[Hook] check-console-log: stdin exceeded 1MB; suppressing pass-through (fail-open)'); process.exit(0); } if (!data) { process.exit(0); } process.stdout.write(data, () => process.exit(0)); } process.stdin.on('end', () => { try { if (!isGitRepo()) { passThroughAndExit(); return; } const files = getGitModifiedFiles(['\\.tsx?$', '\\.jsx?$']) .filter(f => fs.existsSync(f)) .filter(f => !EXCLUDED_PATTERNS.some(pattern => pattern.test(f))); let hasConsole = false; for (const file of files) { const content = readFile(file); if (content && content.includes('console.log')) { log(`[Hook] WARNING: console.log found in ${file}`); hasConsole = true; } } if (hasConsole) { log('[Hook] Remove console.log statements before committing'); } } catch (err) { log(`[Hook] check-console-log error: ${err.message}`); } // Always output the original data (unless truncated) passThroughAndExit(); });