Files

49 lines
2.0 KiB
JavaScript

// SPDX-License-Identifier: LicenseRef-ConusAI-Template-1.0
//
// The format-on-edit hook of a coding agent (`.claude/settings.json`, PostToolUse on Edit and Write): it reads
// the hook's JSON from stdin and formats the one file the agent changed with this repository's Biome, so the
// gate reports real problems instead of whitespace. It never fails the agent's edit: a file Biome does not
// handle, or a missing install, is skipped silently.
//
// echo '{"tool_input":{"file_path":"modules/notes/core/x.ts"}}' | node scripts/agent-format.mjs
import { spawnSync } from "node:child_process"
import { existsSync } from "node:fs"
import { dirname, extname, join, relative, resolve } from "node:path"
import { fileURLToPath } from "node:url"
const ROOT = join(dirname(fileURLToPath(import.meta.url)), "..")
const FORMATTED = new Set([".ts", ".tsx", ".mts", ".cts", ".js", ".mjs", ".cjs", ".json", ".jsonc", ".css"])
/** The repository-relative path the hook names, or null when there is nothing for Biome to format. */
export function fileToFormat(input, root = ROOT) {
const path = input?.tool_input?.file_path
if (typeof path !== "string" || path === "") return null
const absolute = resolve(root, path)
const rel = relative(root, absolute)
if (rel.startsWith("..") || rel.split(/[\\/]/).includes("node_modules")) return null
if (!FORMATTED.has(extname(rel)) || !existsSync(absolute)) return null
return rel
}
if (process.argv[1] && fileURLToPath(import.meta.url) === process.argv[1]) {
let text = ""
process.stdin.setEncoding("utf8")
process.stdin.on("data", (chunk) => {
text += chunk
})
process.stdin.on("end", () => {
let input = null
try {
input = JSON.parse(text)
} catch {
process.exit(0)
}
const file = fileToFormat(input)
const biome = join(ROOT, "node_modules", ".bin", "biome")
if (file === null || !existsSync(biome)) process.exit(0)
spawnSync(biome, ["format", "--write", "--no-errors-on-unmatched", file], { cwd: ROOT, stdio: "ignore" })
process.exit(0)
})
}