feat(hooks): surface fsync-skip warnings to AI agent via tool output

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
YeonGyu-Kim
2026-05-08 15:08:34 +09:00
parent 6b69505940
commit 43b0529557
9 changed files with 300 additions and 2 deletions
@@ -0,0 +1,98 @@
import { beforeEach, describe, expect, it } from "bun:test"
import { classifyPathEnvironment } from "../../shared/classify-path-environment"
import { clearAllSkips, recordFsyncSkip } from "../../shared/fsync-skip-tracker"
import { createFsyncSkipWarningHook } from "./index"
describe("createFsyncSkipWarningHook", () => {
beforeEach(() => {
clearAllSkips()
})
it("records callID start timestamp in tool.execute.before", async () => {
const hook = createFsyncSkipWarningHook()
const input = { tool: "bash", sessionID: "ses1", callID: "call-1" }
const output = { args: {} as Record<string, unknown> }
await hook["tool.execute.before"](input, output)
await Bun.sleep(2)
recordFsyncSkip({
filePath: "/tmp/a",
contextLabel: "atomicWrite:/tmp/a",
errorCode: "EPERM",
message: "operation not permitted",
pathClassification: classifyPathEnvironment("/tmp/a"),
})
const afterOutput = { title: "ok", output: "done", metadata: {} as Record<string, unknown> }
await hook["tool.execute.after"](input, afterOutput)
expect(afterOutput.output).toContain("[fsync-skipped]")
})
it("drains skips after start time and appends warning to output text", async () => {
const hook = createFsyncSkipWarningHook()
const input = { tool: "write", sessionID: "ses1", callID: "call-2" }
const beforeOutput = { args: {} as Record<string, unknown> }
const afterOutput = { title: "ok", output: "base", metadata: {} as Record<string, unknown> }
await hook["tool.execute.before"](input, beforeOutput)
await Bun.sleep(2)
recordFsyncSkip({
filePath: "/Users/x/OneDrive/a",
contextLabel: "atomicWrite:/Users/x/OneDrive/a",
errorCode: "EPERM",
message: "operation not permitted",
pathClassification: classifyPathEnvironment("/Users/x/OneDrive/a"),
})
await hook["tool.execute.after"](input, afterOutput)
expect(afterOutput.output).toContain("base\n\n---")
expect(afterOutput.output).toContain("OneDrive")
})
it("leaves output unchanged when no skips happen during window", async () => {
const hook = createFsyncSkipWarningHook()
const input = { tool: "write", sessionID: "ses1", callID: "call-3" }
const beforeOutput = { args: {} as Record<string, unknown> }
const afterOutput = { title: "ok", output: "base", metadata: {} as Record<string, unknown> }
await hook["tool.execute.before"](input, beforeOutput)
await hook["tool.execute.after"](input, afterOutput)
expect(afterOutput.output).toBe("base")
})
it("isolates multiple parallel calls by callID watermark", async () => {
const hook = createFsyncSkipWarningHook()
const beforeOutput = { args: {} as Record<string, unknown> }
const inputA = { tool: "write", sessionID: "ses1", callID: "call-A" }
const inputB = { tool: "write", sessionID: "ses1", callID: "call-B" }
await hook["tool.execute.before"](inputA, beforeOutput)
await Bun.sleep(2)
await hook["tool.execute.before"](inputB, beforeOutput)
await Bun.sleep(2)
recordFsyncSkip({
filePath: "/tmp/a",
contextLabel: "atomicWrite:/tmp/a",
errorCode: "EPERM",
message: "operation not permitted",
pathClassification: classifyPathEnvironment("/tmp/a"),
})
const outputA = { title: "ok", output: "A", metadata: {} as Record<string, unknown> }
const outputB = { title: "ok", output: "B", metadata: {} as Record<string, unknown> }
await hook["tool.execute.after"](inputA, outputA)
await hook["tool.execute.after"](inputB, outputB)
expect(outputA.output).toContain("[fsync-skipped]")
expect(outputB.output).toBe("B")
})
})
+50
View File
@@ -0,0 +1,50 @@
import { drainSkipsAfter } from "../../shared/fsync-skip-tracker"
import { formatFsyncSkipWarning } from "../../shared/fsync-skip-warning-formatter"
type ToolExecuteInput = {
tool: string
sessionID: string
callID: string
}
type ToolBeforeOutput = {
args: Record<string, unknown>
}
type ToolAfterOutput = {
title: string
output: string
metadata: unknown
}
export function createFsyncSkipWarningHook() {
const startTimesByCallId = new Map<string, number>()
const toolExecuteBefore = async (
input: ToolExecuteInput,
_output: ToolBeforeOutput,
): Promise<void> => {
startTimesByCallId.set(input.callID, Date.now())
}
const toolExecuteAfter = async (
input: ToolExecuteInput,
output: ToolAfterOutput,
): Promise<void> => {
if (typeof output.output !== "string") return
const startTimestamp = startTimesByCallId.get(input.callID) ?? 0
startTimesByCallId.delete(input.callID)
const skips = drainSkipsAfter(startTimestamp)
const warning = formatFsyncSkipWarning(skips)
if (warning.length === 0) return
output.output = `${output.output}\n\n${warning}`
}
return {
"tool.execute.before": toolExecuteBefore,
"tool.execute.after": toolExecuteAfter,
}
}