import { execFileSync } from "node:child_process"; /** * Pre-commit scope: run check + lint only for the extensions whose files are * staged. Any staged file outside `extensions//` (scripts, root config, * shared test helpers) widens the scope to the whole repository, because it can * affect every extension. Pre-push stays repository-wide; this keeps the fast, * offline pre-commit proportional to the change. */ function git(args: string[]): string { return execFileSync("git", args, { encoding: "utf8" }); } function run(args: string[]): void { execFileSync("mise", ["run", ...args], { stdio: "inherit" }); } const dryRun = process.argv.includes("--dry-run"); const staged = git(["diff", "--cached", "--name-only"]) .split("\n") .map((line) => line.trim()) .filter(Boolean); const extensions = new Set(); let repositoryWide = false; for (const file of staged) { const match = /^extensions\/([^/]+)\//.exec(file); if (match) extensions.add(match[1] as string); else repositoryWide = true; } if (staged.length === 0) { console.log("scope: nothing staged"); } else if (repositoryWide || extensions.size === 0) { console.log("scope: repository-wide (shared files staged) → check + lint"); if (!dryRun) run(["//:check", ":::", "//:lint"]); } else { const names = [...extensions].sort(); console.log(`scope: ${names.join(", ")} → check + lint`); if (!dryRun) for (const name of names) { run([`//extensions/${name}:check`]); run([`//extensions/${name}:lint`]); } }