feat(hooks): site-wysiwyd-check PostToolUse(Edit|Write) drift advisory

This commit is contained in:
Parfii-bot 2026-04-21 21:33:11 +08:00
parent 7b89aba305
commit 1b382b7fca

75
hooks/site-wysiwyd-check.sh Executable file
View file

@ -0,0 +1,75 @@
#!/bin/sh
# site-wysiwyd-check.sh — PostToolUse(Edit|Write) advisory hook.
#
# Detects frontend source edits on a project that has a live dev server
# (.keisei/dev-server.pid exists) and reports visual drift against the
# most recent approved screenshot (.keisei/target.png).
#
# Non-blocking: every exit path is `exit 0`. If any dependency is missing
# (jq, mock-render, visual-diff, live server, target.png) the hook silently
# no-ops. Drift is printed to stderr; Claude Code surfaces it as advisory.
#
# Stdin: JSON with tool_input.file_path.
command -v jq >/dev/null 2>&1 || exit 0
set -eu
FILE=$(jq -r '.tool_input.file_path // empty' 2>/dev/null || true)
[ -n "$FILE" ] || exit 0
# Extension whitelist — only frontend source files trigger a drift check.
EXT=$(printf '%s' "${FILE##*.}" | tr '[:upper:]' '[:lower:]')
case "$EXT" in
tsx|vue|svelte|astro|css|html|jsx|ts) ;;
*) exit 0 ;;
esac
# Walk up from the edited file looking for .keisei/dev-server.pid. Stop at /
# or at $HOME to avoid unbounded traversal.
dir=$(dirname "$FILE")
pid_file=""
while [ "$dir" != "/" ] && [ "$dir" != "$HOME" ] && [ -n "$dir" ]; do
if [ -f "$dir/.keisei/dev-server.pid" ]; then
pid_file="$dir/.keisei/dev-server.pid"
break
fi
parent=$(dirname "$dir")
[ "$parent" = "$dir" ] && break
dir="$parent"
done
[ -n "$pid_file" ] || exit 0
PROJECT_DIR=$(dirname "$(dirname "$pid_file")")
TARGET_PNG="$PROJECT_DIR/.keisei/target.png"
[ -f "$TARGET_PNG" ] || exit 0
# Locate mock-render + visual-diff in the Rust primitive workspace.
RUST_BIN="$HOME/.claude/agents/_primitives/_rust/target/release"
MOCK="$RUST_BIN/mock-render"
DIFF="$RUST_BIN/visual-diff"
[ -x "$MOCK" ] || exit 0
[ -x "$DIFF" ] || exit 0
# Read dev-server URL (default http://localhost:3000 if unrecorded).
URL_FILE="$PROJECT_DIR/.keisei/dev-server.url"
if [ -f "$URL_FILE" ]; then
URL=$(head -n1 "$URL_FILE")
else
URL="http://localhost:3000"
fi
[ -n "$URL" ] || exit 0
# Let HMR settle before screenshotting.
sleep 0.5
CURRENT_PNG="$PROJECT_DIR/.keisei/current.png"
"$MOCK" screenshot "$URL" --out "$CURRENT_PNG" >/dev/null 2>&1 || exit 0
[ -f "$CURRENT_PNG" ] || exit 0
drift=$("$DIFF" "$TARGET_PNG" "$CURRENT_PNG" 2>/dev/null || true)
if [ -n "$drift" ]; then
echo "[site-wysiwyd] drift vs $TARGET_PNG: $drift" >&2
fi
exit 0