From 7d23fcee20af3033da8f57867590e51231654c58 Mon Sep 17 00:00:00 2001 From: Roberto Cano <3525807+robercano@users.noreply.github.com> Date: Mon, 6 Jul 2026 12:12:24 +0200 Subject: [PATCH] chore(gate): pnpm-gated node_modules freshness preflight Abort a gate early with a clear STDERR message when node_modules is behind pnpm-lock.yaml (resolved lockfile at node_modules/.pnpm/lock.yaml differs), instead of letting TS builds fail with opaque 'Cannot find module' errors on STDOUT that surface to Stop hooks as an unhelpful 'No stderr output'. Guarded by the presence of a root pnpm-lock.yaml, so non-pnpm projects are unaffected. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01DxMR5ytP8qpDAKX6gyVC9d --- .claude/scripts/gate.sh | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/.claude/scripts/gate.sh b/.claude/scripts/gate.sh index fcc6238..8f1a3c4 100755 --- a/.claude/scripts/gate.sh +++ b/.claude/scripts/gate.sh @@ -10,6 +10,23 @@ key="${1:?usage: gate.sh }" # robust whether or not we're nested inside another git repo. script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" root="$(cd "$script_dir/../.." && pwd)" + +# Dependency-freshness preflight (pnpm-gated: no-ops unless the repo uses pnpm). +# pnpm copies the resolved lockfile to node_modules/.pnpm/lock.yaml on every +# install, so a byte-diff against the working pnpm-lock.yaml is a fast, offline +# staleness check. When they differ, node_modules is behind the lockfile (e.g. a +# merged PR added a dependency) and TS builds fail with opaque "Cannot find +# module" errors printed to STDOUT — leaving Stop hooks to report an unhelpful +# "No stderr output". Surface the real cause on STDERR and abort early so the fix +# ('pnpm install') is obvious. Projects without a root pnpm-lock.yaml skip this. +if [ -f "$root/pnpm-lock.yaml" ]; then + installed_lock="$root/node_modules/.pnpm/lock.yaml" + if [ ! -e "$installed_lock" ] || ! cmp -s "$root/pnpm-lock.yaml" "$installed_lock"; then + echo "gate.sh: node_modules is out of sync with pnpm-lock.yaml — run 'pnpm install' (gate '$key' aborted)." >&2 + exit 1 + fi +fi + # Which adapter to read. Defaults to the project adapter; set GATES_FILE to run a # different one (e.g. GATES_FILE=.claude/self/gates.json for the self-host loop — # see .claude/self/README.md). Relative paths resolve from the repo root.