fix(comment-checker): fix error skip bug and add parser/language caching
- Fix overly broad error detection that skipped comments when LSP warnings present - Add Parser class and language WASM caching for ~3.5x faster subsequent parses - Add debug logging controlled by COMMENT_CHECKER_DEBUG=1 env var
This commit is contained in:
@@ -3,6 +3,18 @@ import { detectComments, isSupportedFile } from "./detector"
|
||||
import { applyFilters } from "./filters"
|
||||
import { formatHookMessage } from "./output"
|
||||
|
||||
import * as fs from "fs"
|
||||
|
||||
const DEBUG = process.env.COMMENT_CHECKER_DEBUG === "1"
|
||||
const DEBUG_FILE = "/tmp/comment-checker-debug.log"
|
||||
|
||||
function debugLog(...args: unknown[]) {
|
||||
if (DEBUG) {
|
||||
const msg = `[${new Date().toISOString()}] [comment-checker:hook] ${args.map(a => typeof a === 'object' ? JSON.stringify(a, null, 2) : String(a)).join(' ')}\n`
|
||||
fs.appendFileSync(DEBUG_FILE, msg)
|
||||
}
|
||||
}
|
||||
|
||||
const pendingCalls = new Map<string, PendingCall>()
|
||||
const PENDING_CALL_TTL = 60_000
|
||||
|
||||
@@ -18,27 +30,37 @@ function cleanupOldPendingCalls(): void {
|
||||
setInterval(cleanupOldPendingCalls, 10_000)
|
||||
|
||||
export function createCommentCheckerHooks() {
|
||||
debugLog("createCommentCheckerHooks called")
|
||||
|
||||
return {
|
||||
"tool.execute.before": async (
|
||||
input: { tool: string; sessionID: string; callID: string },
|
||||
output: { args: Record<string, unknown> }
|
||||
): Promise<void> => {
|
||||
debugLog("tool.execute.before:", { tool: input.tool, callID: input.callID, args: output.args })
|
||||
|
||||
const toolLower = input.tool.toLowerCase()
|
||||
if (toolLower !== "write" && toolLower !== "edit" && toolLower !== "multiedit") {
|
||||
debugLog("skipping non-write/edit tool:", toolLower)
|
||||
return
|
||||
}
|
||||
|
||||
const filePath = (output.args.filePath ?? output.args.file_path ?? output.args.path) as string | undefined
|
||||
const content = output.args.content as string | undefined
|
||||
|
||||
debugLog("extracted filePath:", filePath)
|
||||
|
||||
if (!filePath) {
|
||||
debugLog("no filePath found")
|
||||
return
|
||||
}
|
||||
|
||||
if (!isSupportedFile(filePath)) {
|
||||
debugLog("unsupported file:", filePath)
|
||||
return
|
||||
}
|
||||
|
||||
debugLog("registering pendingCall:", { callID: input.callID, filePath, tool: toolLower })
|
||||
pendingCalls.set(input.callID, {
|
||||
filePath,
|
||||
content,
|
||||
@@ -52,14 +74,28 @@ export function createCommentCheckerHooks() {
|
||||
input: { tool: string; sessionID: string; callID: string },
|
||||
output: { title: string; output: string; metadata: unknown }
|
||||
): Promise<void> => {
|
||||
debugLog("tool.execute.after:", { tool: input.tool, callID: input.callID })
|
||||
|
||||
const pendingCall = pendingCalls.get(input.callID)
|
||||
if (!pendingCall) {
|
||||
debugLog("no pendingCall found for:", input.callID)
|
||||
return
|
||||
}
|
||||
|
||||
pendingCalls.delete(input.callID)
|
||||
debugLog("processing pendingCall:", pendingCall)
|
||||
|
||||
if (output.output.toLowerCase().includes("error")) {
|
||||
// Only skip if the output indicates a tool execution failure
|
||||
// (not LSP warnings/errors or other incidental "error" strings)
|
||||
const outputLower = output.output.toLowerCase()
|
||||
const isToolFailure =
|
||||
outputLower.includes("error:") ||
|
||||
outputLower.includes("failed to") ||
|
||||
outputLower.includes("could not") ||
|
||||
outputLower.startsWith("error")
|
||||
|
||||
if (isToolFailure) {
|
||||
debugLog("skipping due to tool failure in output")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -68,15 +104,23 @@ export function createCommentCheckerHooks() {
|
||||
|
||||
if (pendingCall.content) {
|
||||
content = pendingCall.content
|
||||
debugLog("using content from args")
|
||||
} else {
|
||||
debugLog("reading file:", pendingCall.filePath)
|
||||
const file = Bun.file(pendingCall.filePath)
|
||||
content = await file.text()
|
||||
debugLog("file content length:", content.length)
|
||||
}
|
||||
|
||||
debugLog("calling detectComments...")
|
||||
const rawComments = await detectComments(pendingCall.filePath, content)
|
||||
debugLog("raw comments:", rawComments.length)
|
||||
|
||||
const filteredComments = applyFilters(rawComments)
|
||||
debugLog("filtered comments:", filteredComments.length)
|
||||
|
||||
if (filteredComments.length === 0) {
|
||||
debugLog("no comments after filtering")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -88,8 +132,11 @@ export function createCommentCheckerHooks() {
|
||||
]
|
||||
|
||||
const message = formatHookMessage(fileComments)
|
||||
debugLog("appending message to output")
|
||||
output.output += `\n\n${message}`
|
||||
} catch {}
|
||||
} catch (err) {
|
||||
debugLog("tool.execute.after failed:", err)
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user