Merge pull request #4205 from code-yeongyu/fix/comment-checker-apply-patch-payloads

fix(comment-checker): handle apply_patch payloads
This commit is contained in:
YeonGyu-Kim
2026-05-20 15:28:35 +09:00
committed by GitHub
7 changed files with 492 additions and 35 deletions
+26
View File
@@ -146,4 +146,30 @@ describe("createToolExecuteAfterHandler", () => {
// then
expect(output).toEqual({ title: "result", output: "read output", metadata: {} })
})
it("#given after input includes tool args #when comment checker runs #then it receives the args", async () => {
// given
let seenArgs: Record<string, unknown> | undefined
const handler = createToolExecuteAfterHandler({
ctx: { directory: "/repo" } as never,
hooks: {
commentChecker: {
"tool.execute.after": async (input) => {
seenArgs = input.args
},
},
} as never,
})
const args = { patchText: "*** Begin Patch\n*** End Patch" }
// when
await handler(
{ tool: "apply_patch", sessionID: "ses_parent", callID: "call_patch", args },
{ title: "result", output: "Success", metadata: {} },
)
// then
expect(seenArgs).toBe(args)
})
})
+20 -6
View File
@@ -6,6 +6,21 @@ import type { PluginContext } from "./types"
const VERIFICATION_ATTEMPT_PATTERN = /<ulw_verification_attempt_id>(.*?)<\/ulw_verification_attempt_id>/i
type ToolExecuteAfterInput = {
readonly tool: string
readonly sessionID: string
readonly callID?: string
readonly callId?: string
readonly call_id?: string
readonly args?: Record<string, unknown>
}
type ToolExecuteAfterOutput = {
title: string
output: string
metadata: Record<string, unknown>
}
function getMetadataString(metadata: Record<string, unknown> | undefined, keys: string[]): string | undefined {
for (const key of keys) {
const value = metadata?.[key]
@@ -29,10 +44,8 @@ export function createToolExecuteAfterHandler(args: {
ctx: PluginContext
hooks: CreatedHooks
}): (
input: { tool: string; sessionID: string; callID: string },
output:
| { title: string; output: string; metadata: Record<string, unknown> }
| undefined,
input: ToolExecuteAfterInput,
output: ToolExecuteAfterOutput | undefined,
) => Promise<void> {
const { ctx, hooks } = args
@@ -40,8 +53,8 @@ export function createToolExecuteAfterHandler(args: {
// We must treat their identity as a best-effort correlation key, not a guaranteed public contract.
return async (
input: { tool: string; sessionID: string; callID?: string; callId?: string; call_id?: string },
output: { title: string; output: string; metadata: Record<string, unknown> } | undefined,
input: ToolExecuteAfterInput,
output: ToolExecuteAfterOutput | undefined,
): Promise<void> => {
if (!output) return
@@ -49,6 +62,7 @@ export function createToolExecuteAfterHandler(args: {
tool: input.tool,
sessionID: input.sessionID,
callID: input.callID ?? input.callId ?? input.call_id ?? "",
...(input.args === undefined ? {} : { args: input.args }),
}
const nativeSessionId = getMetadataString(output.metadata, ["sessionId", "sessionID", "session_id"])