diff --git a/.githooks/pre-commit b/.githooks/pre-commit new file mode 100755 index 0000000..317f38a --- /dev/null +++ b/.githooks/pre-commit @@ -0,0 +1,11 @@ +#!/bin/sh +set -eu + +branch="$(git branch --show-current)" + +if [ "$branch" = "main" ]; then + echo "Committing directly to main is blocked. Create a feature branch." >&2 + exit 1 +fi + +npm run commit-check diff --git a/.githooks/pre-push b/.githooks/pre-push new file mode 100755 index 0000000..6154e24 --- /dev/null +++ b/.githooks/pre-push @@ -0,0 +1,11 @@ +#!/bin/sh +set -eu + +while read -r local_ref _ remote_ref _; do + case "$remote_ref" in + refs/heads/main) + echo "Pushing directly to main is blocked. Open a pull request instead." >&2 + exit 1 + ;; + esac +done diff --git a/README.md b/README.md index 454da94..50b2e75 100644 --- a/README.md +++ b/README.md @@ -64,7 +64,7 @@ Default-style configuration: }, { "id": "openai/gpt-5.3-codex-spark", - "description": "Faster, lower-cost code-focused option for lightweight implementation tasks." + "description": "Faster, lower-cost code-focused option for small code implementations or quickly searching for things." } ], diff --git a/package.json b/package.json index ec5676f..9b98fc5 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,9 @@ "build": "npm run clean && tsc -p tsconfig.build.json", "check": "npm run lint && npm run typecheck && npm run test", "clean": "rm -rf dist", + "commit-check": "npm run check && npm run build", "lint": "eslint . --max-warnings=0", + "prepare": "node --import tsx scripts/install-hooks.ts", "test": "node --import tsx --test test/**/*.test.ts", "typecheck": "tsc -p tsconfig.json --noEmit", "prepack": "npm run build" diff --git a/scripts/install-hooks.ts b/scripts/install-hooks.ts new file mode 100644 index 0000000..d95209a --- /dev/null +++ b/scripts/install-hooks.ts @@ -0,0 +1,18 @@ +import { execFileSync } from "node:child_process" +import { existsSync } from "node:fs" +import * as path from "node:path" +import { fileURLToPath } from "node:url" + +const scriptDir = path.dirname(fileURLToPath(import.meta.url)) +const repoRoot = path.resolve(scriptDir, "..") +const hooksDir = path.join(repoRoot, ".githooks") +const gitDir = path.join(repoRoot, ".git") + +if (!existsSync(gitDir) || !existsSync(hooksDir)) { + process.exit(0) +} + +execFileSync("git", ["config", "--local", "core.hooksPath", ".githooks"], { + cwd: repoRoot, + stdio: "inherit", +}) diff --git a/tsconfig.json b/tsconfig.json index 3f07af3..f21e313 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -20,6 +20,6 @@ "forceConsistentCasingInFileNames": true, "noEmit": true }, - "include": ["src/**/*.ts", "test/**/*.ts"], + "include": ["src/**/*.ts", "test/**/*.ts", "scripts/**/*.ts"], "exclude": ["dist", "coverage", "node_modules"] }