chore(pre-commit): run lint, typecheck and coverage as one parallel gate

The hook ran `pnpm test`, the whole coverage suite, and the agent flow in AGENTS.md ran that same suite again before committing: one commit verified identical content twice, about 45s of it.

`pnpm run check` (scripts/check.sh) runs lint, typecheck and coverage concurrently, prints each tool's complete output (also kept in .tmp/check-logs) and fails when any of them does. A green run fingerprints the worktree into .tmp/check.stamp, so the hook skips the suite for content that just passed; any tracked or untracked edit, or a stamp older than an hour (gitignored inputs like lib/ and node_modules can drift unseen), re-runs it, and `--full` always does. The hook gains lint and typecheck at no extra wall time: 3.2s and 1.4s hide inside the 23s test run.

.gitignore now lists the local tool state (.codegraph, .idea, .zcode): it is not a gate input, and its churn would otherwise invalidate every stamp.

Verified: green gate on 146 files / 2305 tests, hook skip in 0.1s, full re-run after any edit, and a stubbed failing tool exits 1 without stamping.
This commit is contained in:
bowenliang123 committed 2026-10-13 23:30:07 +08:00
1 parent d9d3868dc4
commit e0b42ee6a7
5 files changed
+94 -5

No files matched your search

+6
View File
@@ -33,6 +33,12 @@ yarn-error.log*
.pnpm-store/
.tmp/
# Local tool state: CodeGraph index, IDE, agent tooling. They are not gate
# inputs, and their churn would otherwise invalidate the pre-commit stamp.
.codegraph/
.idea/
.zcode/
# Environment variables
.env
.env.local
+1 -1
View File
@@ -1 +1 @@
pnpm test
pnpm run check
+3 -4
View File
@@ -42,10 +42,8 @@ Complete ALL of these before ANY commit:
- Review the full diff independently: every change necessary, correct, and not over-engineered.
- Clean up generated temporary files and temporary or unhelpful comments.
- Load the [code-review](https://github.com/mattpocock/skills/tree/main/skills/engineering/code-review) skill if available, run it to review all the changes, and independently verify or follow each of its suggestions when its multi-axis analysis done.
- Run the following commands concurrently for maximum efficiency
- First, run `pnpm run lint` to fix all lint errors.
- Second, run `pnpm run typecheck` to fix all type errors.
- Third, run `pnpm run coverage` to run and ensure 100% per-file coverage. Please capture the ALL content of the full output without truncation or tailing.
- Run `pnpm run check`: it runs `pnpm run lint`, `pnpm run typecheck` and `pnpm run coverage` concurrently, prints each tool's COMPLETE output, and fails when any of them does (the same logs stay in `.tmp/check-logs/`).
- Fix every lint and type error, and ensure 100% per-file coverage. Please capture the ALL content of the full output without truncation or tailing.
- Example for per-file 100% coverage output:
```
% Coverage report from v8
@@ -54,6 +52,7 @@ Complete ALL of these before ANY commit:
-------------------------|---------|----------|---------|---------|-------------------
-------------------------|---------|----------|---------|---------|-------------------
```
- The `pre-commit` hook runs this same gate, and a green run stamps the worktree into `.tmp/check.stamp`, so a commit of unchanged content skips it; `pnpm run check --full` forces a full re-run.
## Layout & responsive
+1
View File
@@ -41,6 +41,7 @@
"build": "tsdown",
"lint": "oxlint",
"lint:fix": "oxlint --fix",
"check": "bash scripts/check.sh",
"watch": "bash scripts/watch.sh",
"web": "bash scripts/web.sh",
"register": "bash scripts/register.sh",
+83
View File
@@ -0,0 +1,83 @@
#!/usr/bin/env bash
# The pre-commit gate: lint, typecheck and the full coverage suite, run
# concurrently, each tool's complete output kept in .tmp/check-logs.
#
# A green run fingerprints the worktree into .tmp/check.stamp, so the husky
# hook skips the full suite for content that just passed. Any tracked or
# untracked edit invalidates the stamp, and so does a stamp older than an hour:
# gitignored inputs (lib/, node_modules, staged dsh baselines) can drift without
# changing the fingerprint. `--full` always re-runs.
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "$ROOT"
STAMP=".tmp/check.stamp"
LOGS=".tmp/check-logs"
INDEX=".tmp/check-index"
STAMP_TTL_MIN=60
# The fingerprint is the worktree's tree object, built through a THROWAWAY
# index: staged and unstaged edits plus untracked files all count, while
# gitignored outputs (.tmp, coverage, lib, node_modules, IDE/tool state) do not.
fingerprint() {
local tree
mkdir -p .tmp
rm -f "$INDEX"
if ! GIT_INDEX_FILE="$INDEX" git add -A -- . >/dev/null; then
rm -f "$INDEX"
return 1
fi
tree="$(GIT_INDEX_FILE="$INDEX" git write-tree)" || tree=""
rm -f "$INDEX"
[[ -n "$tree" ]] || return 1
printf '%s\n' "$tree"
}
FULL=0
[[ "${1:-}" == "--full" ]] && FULL=1
# Command substitutions do not inherit errexit on bash 3.2 (macOS), so both
# fingerprint calls check their status explicitly.
BEFORE="$(fingerprint)" || { echo "==> check: cannot fingerprint the worktree" >&2; exit 1; }
if (( FULL == 0 )) && [[ -f "$STAMP" ]] && [[ "$(cat "$STAMP")" == "$BEFORE" ]] \
&& [[ -n "$(find "$STAMP" -mmin "-$STAMP_TTL_MIN" 2>/dev/null)" ]]; then
echo "==> check: worktree unchanged since the last green gate — skipping. Run 'pnpm run check --full' to force a full run."
exit 0
fi
rm -rf "$LOGS"
mkdir -p "$LOGS"
echo "==> check: lint, typecheck and coverage in parallel"
pnpm run lint >"$LOGS/lint.log" 2>&1 & LINT=$!
pnpm run typecheck >"$LOGS/typecheck.log" 2>&1 & TYPECHECK=$!
pnpm run coverage >"$LOGS/coverage.log" 2>&1 & COVERAGE=$!
FAILED=""
wait "$LINT" || FAILED="$FAILED lint"
wait "$TYPECHECK" || FAILED="$FAILED typecheck"
wait "$COVERAGE" || FAILED="$FAILED coverage"
for name in lint typecheck coverage; do
echo
echo "===== $name ====="
cat "$LOGS/$name.log"
done
echo
if [[ -n "$FAILED" ]]; then
echo "==> check FAILED:$FAILED" >&2
exit 1
fi
# A gate run over a moving worktree proves nothing, so an edit during the run
# must not be stamped as verified.
AFTER="$(fingerprint)" || { echo "==> check: cannot fingerprint the worktree" >&2; exit 1; }
if [[ "$BEFORE" != "$AFTER" ]]; then
echo "==> check: the worktree changed while the gate ran — re-run before committing." >&2
exit 1
fi
printf '%s\n' "$BEFORE" > "$STAMP"
echo "==> check passed: lint, typecheck and 100% per-file coverage (lint/typecheck/coverage output above; logs in $LOGS)"