mirror of
https://github.com/affaan-m/everything-claude-code.git
synced 2026-02-16 03:13:08 +08:00
Core library fixes: - session-manager.js: wrap all statSync calls in try-catch to prevent TOCTOU crashes when files are deleted between readdir and stat - session-manager.js: use birthtime||ctime fallback for Linux compat - session-manager.js: remove redundant existsSync before readFile - utils.js: fix findFiles TOCTOU race on statSync inside readdir loop Hook improvements: - Add 1MB stdin buffer limits to all PostToolUse hooks to prevent unbounded memory growth from large payloads - suggest-compact.js: use fd-based atomic read+write for counter file to reduce race window between concurrent invocations - session-end.js: log when transcript file is missing, check replaceInFile return value for failed timestamp updates - start-observer.sh: log claude CLI failures instead of silently swallowing them, check observations file exists before analysis Test fixes: - Fix blocking hook tests to send matching input (dev server command) and expect correct exit code 2 instead of 1
73 lines
2.1 KiB
JavaScript
73 lines
2.1 KiB
JavaScript
#!/usr/bin/env node
|
|
/**
|
|
* PostToolUse Hook: TypeScript check after editing .ts/.tsx files
|
|
*
|
|
* Cross-platform (Windows, macOS, Linux)
|
|
*
|
|
* Runs after Edit tool use on TypeScript files. Walks up from the file's
|
|
* directory to find the nearest tsconfig.json, then runs tsc --noEmit
|
|
* and reports only errors related to the edited file.
|
|
*/
|
|
|
|
const { execFileSync } = require('child_process');
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
const MAX_STDIN = 1024 * 1024; // 1MB limit
|
|
let data = '';
|
|
|
|
process.stdin.on('data', chunk => {
|
|
if (data.length < MAX_STDIN) {
|
|
data += chunk;
|
|
}
|
|
});
|
|
|
|
process.stdin.on('end', () => {
|
|
try {
|
|
const input = JSON.parse(data);
|
|
const filePath = input.tool_input?.file_path;
|
|
|
|
if (filePath && /\.(ts|tsx)$/.test(filePath) && fs.existsSync(filePath)) {
|
|
// Find nearest tsconfig.json by walking up (max 20 levels to prevent infinite loop)
|
|
let dir = path.dirname(path.resolve(filePath));
|
|
const root = path.parse(dir).root;
|
|
let depth = 0;
|
|
|
|
while (dir !== root && depth < 20) {
|
|
if (fs.existsSync(path.join(dir, 'tsconfig.json'))) {
|
|
break;
|
|
}
|
|
dir = path.dirname(dir);
|
|
depth++;
|
|
}
|
|
|
|
if (fs.existsSync(path.join(dir, 'tsconfig.json'))) {
|
|
try {
|
|
execFileSync('npx', ['tsc', '--noEmit', '--pretty', 'false'], {
|
|
cwd: dir,
|
|
encoding: 'utf8',
|
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
timeout: 30000
|
|
});
|
|
} catch (err) {
|
|
// tsc exits non-zero when there are errors — filter to edited file
|
|
const output = err.stdout || '';
|
|
const relevantLines = output
|
|
.split('\n')
|
|
.filter(line => line.includes(filePath) || line.includes(path.basename(filePath)))
|
|
.slice(0, 10);
|
|
|
|
if (relevantLines.length > 0) {
|
|
console.error('[Hook] TypeScript errors in ' + path.basename(filePath) + ':');
|
|
relevantLines.forEach(line => console.error(line));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} catch {
|
|
// Invalid input — pass through
|
|
}
|
|
|
|
console.log(data);
|
|
});
|