49 lines
2.0 KiB
JavaScript
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)
|
|
})
|
|
}
|