mirror of
https://github.com/affaan-m/everything-claude-code.git
synced 2026-02-16 19:33:11 +08:00
* fix: Windows compatibility for hook scripts
- post-edit-format.js: add `shell: process.platform === 'win32'` to
execFileSync options so npx.cmd is resolved via cmd.exe on Windows
- post-edit-typecheck.js: same fix for tsc invocation via npx
- hooks.json: skip tmux-dependent hooks on Windows where tmux is
unavailable (dev-server blocker and long-running command reminder)
On Windows, execFileSync('npx', ...) without shell:true fails with
ENOENT because Node.js cannot directly execute .cmd files. These
hooks silently fail on all Windows installations.
The tmux hooks unconditionally block dev server commands (exit 2) or
warn about tmux on Windows where tmux is not available.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: parse Claude Code JSONL transcript format correctly
The session-end hook expected user messages at entry.content, but
Claude Code's actual JSONL format nests them at entry.message.content.
This caused all session files to be blank templates (0 user messages
despite 136+ actual entries).
- Check entry.message?.content in addition to entry.content
- Extract tool_use blocks from assistant message.content arrays
Verified with Claude Code v2.1.41 JSONL transcripts.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: ddungan <sckim@mococo.co.kr>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
86 lines
2.4 KiB
JavaScript
86 lines
2.4 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.setEncoding("utf8");
|
|
|
|
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)) {
|
|
const resolvedPath = path.resolve(filePath);
|
|
if (!fs.existsSync(resolvedPath)) {
|
|
console.log(data);
|
|
return;
|
|
}
|
|
// Find nearest tsconfig.json by walking up (max 20 levels to prevent infinite loop)
|
|
let dir = path.dirname(resolvedPath);
|
|
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,
|
|
shell: process.platform === "win32",
|
|
});
|
|
} catch (err) {
|
|
// tsc exits non-zero when there are errors — filter to edited file
|
|
const output = (err.stdout || "") + (err.stderr || "");
|
|
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);
|
|
});
|