docs(agent rules): require React best-practices review

This commit is contained in:
Tommaso Casaburi
2026-04-27 12:39:15 +07:00
parent 5dc5408a15
commit 4fe0494be6
4 changed files with 77 additions and 22 deletions
+69 -16
View File
@@ -1,6 +1,6 @@
#!/bin/bash
# afterFileEdit/stop hook: remind agents to review new React effects and memoization
# afterFileEdit/stop hook: remind agents to review React UI source changes
set -u
@@ -61,6 +61,13 @@ matches_scope() {
return 1
}
is_react_ui_source_file() {
case "$1" in
src/components/*|src/views/*|src/hooks/*|src/stores/*) return 0 ;;
*) return 1 ;;
esac
}
parse_matches_from_diff() {
awk '
/^\+\+\+ b\// {
@@ -109,11 +116,25 @@ append_results() {
printf '%s\n%s' "$existing" "$incoming"
}
append_file_if_react_ui_source() {
local existing="$1"
local file_path="$2"
if is_source_file "$file_path" && matches_scope "$file_path" && is_react_ui_source_file "$file_path"; then
append_results "$existing" "$file_path"
return
fi
printf '%s' "$existing"
}
results=""
react_source_files=""
file_path="$(extract_file_path)"
if [ -n "$file_path" ]; then
if is_source_file "$file_path" && matches_scope "$file_path"; then
react_source_files="$(append_file_if_react_ui_source "$react_source_files" "$file_path")"
if git ls-files --others --exclude-standard -- "$file_path" | grep -q '.'; then
results="$(scan_untracked_file "$file_path")"
else
@@ -125,18 +146,25 @@ else
diff_output="$(git diff --no-ext-diff --unified=0 --no-color HEAD -- '*.js' '*.jsx' '*.ts' '*.tsx' '*.mjs' '*.cjs' 2>/dev/null || true)"
results="$(printf '%s\n' "$diff_output" | parse_matches_from_diff)"
while IFS= read -r changed_file; do
[ -z "$changed_file" ] && continue
react_source_files="$(append_file_if_react_ui_source "$react_source_files" "$changed_file")"
done < <(git diff --name-only --diff-filter=ACMRT HEAD -- 'src/components' 'src/views' 'src/hooks' 'src/stores' 2>/dev/null || true)
while IFS= read -r untracked_file; do
[ -z "$untracked_file" ] && continue
is_source_file "$untracked_file" || continue
matches_scope "$untracked_file" || continue
react_source_files="$(append_file_if_react_ui_source "$react_source_files" "$untracked_file")"
file_results="$(scan_untracked_file "$untracked_file")"
results="$(append_results "$results" "$file_results")"
done < <(git ls-files --others --exclude-standard -- '*.js' '*.jsx' '*.ts' '*.tsx' '*.mjs' '*.cjs')
fi
results="$(printf '%s\n' "$results" | sed '/^$/d' | awk '!seen[$0]++')"
react_source_files="$(printf '%s\n' "$react_source_files" | sed '/^$/d' | awk '!seen[$0]++')"
if [ -z "$results" ]; then
if [ -z "$results" ] && [ -z "$react_source_files" ]; then
exit 0
fi
@@ -150,26 +178,51 @@ if [ -n "$skill_dir" ] && [ -f "$repo_root/$skill_dir/vercel-react-best-practice
vercel_skill="$repo_root/$skill_dir/vercel-react-best-practices/SKILL.md"
fi
echo "=== React Hook Review Reminder ==="
echo "New React effect or memo primitives were added in the current diff:"
echo "=== React Best Practices Review Reminder ==="
match_count=0
while IFS= read -r match_line; do
[ -z "$match_line" ] && continue
match_count=$((match_count + 1))
if [ "$match_count" -le 10 ]; then
echo "- $match_line"
if [ -n "$react_source_files" ]; then
echo "React UI source changed in the current diff:"
file_count=0
while IFS= read -r changed_file; do
[ -z "$changed_file" ] && continue
file_count=$((file_count + 1))
if [ "$file_count" -le 10 ]; then
echo "- $changed_file"
fi
done <<< "$react_source_files"
if [ "$file_count" -gt 10 ]; then
echo "- ... and $((file_count - 10)) more"
fi
done <<< "$results"
if [ "$match_count" -gt 10 ]; then
echo "- ... and $((match_count - 10)) more"
echo "Before finishing, review the changed diff with:"
echo "- $vercel_skill"
echo "- vercel:react-best-practices, when available in the current harness"
fi
if [ -n "$results" ]; then
echo "New React effect or memo primitives were also added in the current diff:"
match_count=0
while IFS= read -r match_line; do
[ -z "$match_line" ] && continue
match_count=$((match_count + 1))
if [ "$match_count" -le 10 ]; then
echo "- $match_line"
fi
done <<< "$results"
if [ "$match_count" -gt 10 ]; then
echo "- ... and $((match_count - 10)) more"
fi
echo "Also reconsider effect/memo usage with:"
echo "- $effect_skill"
fi
echo "Reconsider this change with:"
echo "- $effect_skill"
echo "- $vercel_skill"
echo "Questions to resolve before finishing:"
echo "- Does the TSX avoid inline object/array prop churn and unnecessary component work?"
echo "- Can this be derived during render instead of synchronized with an effect?"
echo "- Can interaction logic move to an event handler or a key-based reset?"
echo "- Is the memoization actually needed, or is simpler render-time code better?"