fix(comment-checker): handle apply_patch payloads
Accept apply_patch edits from nested result/metadata file lists and from raw patchText args when OpenCode does not provide direct metadata.files. Forward tool args through the after-hook pipeline so comment-checker can inspect raw apply_patch inputs while preserving existing write, edit, and multiedit routing. Tests: bun test src/hooks/comment-checker/hook.apply-patch.test.ts src/hooks/comment-checker/hook.before-after.test.ts src/plugin/tool-execute-after.test.ts Tests: bun test src/hooks/comment-checker Tests: bun run typecheck Tests: bun run build
This commit is contained in:
@@ -0,0 +1,133 @@
|
||||
import { afterAll, afterEach, beforeEach, describe, expect, it, mock } from "bun:test"
|
||||
|
||||
const processWithCli = mock(async () => {})
|
||||
|
||||
mock.module("./cli-runner", () => ({
|
||||
initializeCommentCheckerCli: () => {},
|
||||
getCommentCheckerCliPathPromise: () => Promise.resolve("/tmp/fake-comment-checker"),
|
||||
isCliPathUsable: () => true,
|
||||
processWithCli,
|
||||
processApplyPatchEditsWithCli: async () => {},
|
||||
}))
|
||||
|
||||
afterAll(() => {
|
||||
mock.restore()
|
||||
})
|
||||
|
||||
const { createCommentCheckerHooks } = await import("./hook")
|
||||
const { stopPendingCallCleanup } = await import("./pending-calls")
|
||||
const { _resetCommentCheckerInitializationForTesting } = await import("./initialization-gate")
|
||||
|
||||
describe("comment-checker mutation tool routing", () => {
|
||||
beforeEach(() => {
|
||||
processWithCli.mockClear()
|
||||
stopPendingCallCleanup()
|
||||
_resetCommentCheckerInitializationForTesting()
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
stopPendingCallCleanup()
|
||||
_resetCommentCheckerInitializationForTesting()
|
||||
})
|
||||
|
||||
it("#given write tool with filePath #when before and after hooks run #then it checks the pending write", async () => {
|
||||
// given
|
||||
const hooks = createCommentCheckerHooks()
|
||||
const input = { tool: "write", sessionID: "ses_test", callID: "call_write" }
|
||||
|
||||
// when
|
||||
await hooks["tool.execute.before"](input, {
|
||||
args: { filePath: "/repo/src/write.ts", content: "// write comment\nconst a = 1\n" },
|
||||
})
|
||||
await hooks["tool.execute.after"](input, { title: "ok", output: "Success", metadata: {} })
|
||||
|
||||
// then
|
||||
expect(processWithCli).toHaveBeenCalledTimes(1)
|
||||
expect(processWithCli).toHaveBeenCalledWith(
|
||||
input,
|
||||
expect.objectContaining({
|
||||
filePath: "/repo/src/write.ts",
|
||||
content: "// write comment\nconst a = 1\n",
|
||||
tool: "write",
|
||||
sessionID: "ses_test",
|
||||
}),
|
||||
expect.any(Object),
|
||||
"/tmp/fake-comment-checker",
|
||||
undefined,
|
||||
expect.any(Function),
|
||||
)
|
||||
})
|
||||
|
||||
it("#given edit tool with file_path #when before and after hooks run #then it checks the pending edit", async () => {
|
||||
// given
|
||||
const hooks = createCommentCheckerHooks()
|
||||
const input = { tool: "edit", sessionID: "ses_test", callID: "call_edit" }
|
||||
|
||||
// when
|
||||
await hooks["tool.execute.before"](input, {
|
||||
args: {
|
||||
file_path: "/repo/src/edit.ts",
|
||||
old_string: "const b = 1\n",
|
||||
new_string: "// edit comment\nconst b = 1\n",
|
||||
},
|
||||
})
|
||||
await hooks["tool.execute.after"](input, { title: "ok", output: "Success", metadata: {} })
|
||||
|
||||
// then
|
||||
expect(processWithCli).toHaveBeenCalledTimes(1)
|
||||
expect(processWithCli).toHaveBeenCalledWith(
|
||||
input,
|
||||
expect.objectContaining({
|
||||
filePath: "/repo/src/edit.ts",
|
||||
oldString: "const b = 1\n",
|
||||
newString: "// edit comment\nconst b = 1\n",
|
||||
tool: "edit",
|
||||
}),
|
||||
expect.any(Object),
|
||||
"/tmp/fake-comment-checker",
|
||||
undefined,
|
||||
expect.any(Function),
|
||||
)
|
||||
})
|
||||
|
||||
it("#given multiedit tool with path #when before and after hooks run #then it checks the pending multiedit", async () => {
|
||||
// given
|
||||
const hooks = createCommentCheckerHooks()
|
||||
const input = { tool: "multiedit", sessionID: "ses_test", callID: "call_multiedit" }
|
||||
const edits = [{ old_string: "const c = 1\n", new_string: "// multiedit comment\nconst c = 1\n" }]
|
||||
|
||||
// when
|
||||
await hooks["tool.execute.before"](input, {
|
||||
args: { path: "/repo/src/multiedit.ts", edits },
|
||||
})
|
||||
await hooks["tool.execute.after"](input, { title: "ok", output: "Success", metadata: {} })
|
||||
|
||||
// then
|
||||
expect(processWithCli).toHaveBeenCalledTimes(1)
|
||||
expect(processWithCli).toHaveBeenCalledWith(
|
||||
input,
|
||||
expect.objectContaining({
|
||||
filePath: "/repo/src/multiedit.ts",
|
||||
edits,
|
||||
tool: "multiedit",
|
||||
}),
|
||||
expect.any(Object),
|
||||
"/tmp/fake-comment-checker",
|
||||
undefined,
|
||||
expect.any(Function),
|
||||
)
|
||||
})
|
||||
|
||||
it("#given non-mutation tool #when before and after hooks run #then it does not run the checker", async () => {
|
||||
// given
|
||||
const hooks = createCommentCheckerHooks()
|
||||
const input = { tool: "read", sessionID: "ses_test", callID: "call_read" }
|
||||
|
||||
// when
|
||||
await hooks["tool.execute.before"](input, { args: { filePath: "/repo/src/read.ts" } })
|
||||
await hooks["tool.execute.after"](input, { title: "ok", output: "Success", metadata: {} })
|
||||
|
||||
// then
|
||||
expect(processWithCli).toHaveBeenCalledTimes(0)
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user