#!/usr/bin/env bash # JellyTau pre-commit hook — the fast half of CLAUDE.md's "Before Committing" # list, enforced instead of remembered. # # TRACES: | DR-207 # # Install with: bun run hooks:install (sets core.hooksPath=scripts/hooks) # Skip once with: git commit --no-verify # # What runs here is deliberately limited to gates that finish in seconds: # # bun run check svelte-check (types) # bun run test vitest, single pass # scripts/check-frontend-boundary.sh domain-taxonomy tripwire (DR-094) # cargo fmt --all -- --check only when src-tauri/ is staged # # NOT here, on purpose: `cargo clippy` and `cargo test`. Both take minutes on a # cold target dir, which turns every commit into a coffee break and trains # people to reach for --no-verify. CI (.gitea/workflows/build-and-test.yml) is # where those run; `bun run test:all` is the local equivalent. set -uo pipefail # Merge and rebase commits carry someone else's changes, and conflict resolution # is exactly when a slow gate is least welcome. Let them through — CI still # gates the merge result. GIT_DIR_PATH="$(git rev-parse --git-dir 2>/dev/null)" || exit 0 if [ -e "$GIT_DIR_PATH/MERGE_HEAD" ] || [ -d "$GIT_DIR_PATH/rebase-merge" ] || [ -d "$GIT_DIR_PATH/rebase-apply" ] || [ -e "$GIT_DIR_PATH/CHERRY_PICK_HEAD" ]; then echo "pre-commit: merge/rebase in progress — skipping checks (CI still gates the result)." exit 0 fi # Nothing staged (e.g. `git commit --amend` that only edits the message): nothing # to check. STAGED="$(git diff --cached --name-only --diff-filter=ACMR)" if [ -z "$STAGED" ]; then exit 0 fi REPO_ROOT="$(git rev-parse --show-toplevel)" cd "$REPO_ROOT" || exit 1 FAILED=0 run_gate() { label="$1" shift echo "" echo "🔎 pre-commit: $label" if ! "$@"; then echo "❌ pre-commit: $label failed" FAILED=1 fi } run_gate "svelte-check (bun run check)" bun run check run_gate "frontend tests (bun run test)" bun run test run_gate "frontend/backend boundary" bash scripts/check-frontend-boundary.sh # rustfmt only matters when Rust actually changed, and `cargo fmt --check` is # cheap (no compilation) whenever it does. if printf '%s\n' "$STAGED" | grep -q '^src-tauri/'; then if command -v cargo >/dev/null 2>&1; then echo "" echo "🔎 pre-commit: rustfmt (src-tauri/ is staged)" if ! (cd src-tauri && cargo fmt --all -- --check); then echo "❌ pre-commit: cargo fmt --all -- --check failed" echo " fix with: cd src-tauri && cargo fmt" FAILED=1 fi else echo "⚠️ pre-commit: src-tauri/ staged but cargo is not on PATH — skipping rustfmt." fi fi if [ "$FAILED" -ne 0 ]; then echo "" echo "🛑 pre-commit checks failed. Fix them, or bypass deliberately with:" echo " git commit --no-verify" exit 1 fi echo "" echo "✅ pre-commit checks passed."