فحص الكود تلقائيًا باستخدام Hooks: الجودة مضمونة عند الكتابة

استخدم PostToolUse Hooks لتشغيل lint تلقائيًا بعد كل كتابة. كود الخروج 2 يعيد الأخطاء إلى Claude للتصحيح التلقائي.


يكتب Claude Code بسرعة، لكنه لا يتذكر دائمًا تشغيل lint. تطلب منه "التحقق أثناء الكتابة"، وأحيانًا يفعل وأحيانًا يفوته. تحل Hooks هذه المشكلة — تنقل مسؤولية فحص الكود من Claude إلى النظام.

تركز هذه المقالة على شيء واحد: استخدام PostToolUse Hooks لتشغيل الفحص تلقائيًا بعد أن يكتب Claude الكود، لضمان أن كل تغيير في الملفات يلتزم بمعاييرك.


المنهجية: PostToolUse + تصفية حسب نوع الملف

منطق Hook فحص الكود بسيط:

  1. يستدعي Claude أداة Write أو Edit لكتابة ملف
  2. يعترض Hook هذا الحدث ويحصل على مسار الملف
  3. بناءً على الامتداد، يحدد أداة الفحص المناسبة
  4. الفحص ناجح: كود الخروج 0، يكمل Claude عمله
  5. الفحص فاشل: كود الخروج 2، تُرسل الأخطاء إلى Claude ليصلحها

كود الخروج 2 هو المفتاح — يجعل Claude يتلقى الخطأ ويصلحه تلقائيًا، مشكّلًا دورة "اكتب→افحص→صحح".


الإعداد الأساسي: مشاريع لغة واحدة

Ruby (RuboCop)

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "bash -c 'file=$(echo \"$CLAUDE_TOOL_INPUT\" | jq -r .file_path 2>/dev/null); [[ \"$file\" == *.rb ]] && rubocop -A \"$file\" --no-color -q || true'"
          }
        ]
      }
    ]
  }
}

JavaScript/TypeScript (ESLint)

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "bash -c 'file=$(echo \"$CLAUDE_TOOL_INPUT\" | jq -r .file_path 2>/dev/null); [[ \"$file\" =~ \\.(js|ts|jsx|tsx)$ ]] && npx eslint --fix \"$file\" || true'"
          }
        ]
      }
    ]
  }
}

Python (ruff)

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "bash -c 'file=$(echo \"$CLAUDE_TOOL_INPUT\" | jq -r .file_path 2>/dev/null); [[ \"$file\" == *.py ]] && ruff check --fix \"$file\" && ruff format \"$file\" || true'"
          }
        ]
      }
    ]
  }
}

الإعداد المتقدم: المشاريع متعددة اللغات

نقل منطق الفحص إلى سكريبت مستقل أسهل في الصيانة.

إنشاء .claude/hooks/lint.sh:

#!/bin/bash
set -e

input=$(cat)
file=$(echo "$input" | jq -r '.tool_input.file_path // empty')

[[ -z "$file" ]] && exit 0
[[ ! -f "$file" ]] && exit 0

ext="${file##*.}"

case "$ext" in
  rb)    rubocop -A "$file" --no-color -q ;;
  js|ts|jsx|tsx) npx eslint --fix "$file" --quiet ;;
  py)    ruff check --fix "$file"; ruff format "$file" ;;
  go)    gofmt -w "$file"; golangci-lint run "$file" 2>&1 ;;
  *)     exit 0 ;;
esac

الإشارة إلى السكريبت في settings.json:

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [{ "type": "command", "command": "bash .claude/hooks/lint.sh" }]
      }
    ]
  }
}

جعل Claude يصلح تلقائيًا

كود الخروج 2 + stderr هو مفتاح التصحيح التلقائي لـ Claude:

run_lint() {
  local output exit_code
  output=$(rubocop "$file" --no-color 2>&1)
  exit_code=$?
  if [[ $exit_code -ne 0 ]]; then
    echo "$output" >&2
    exit 2
  fi
  rubocop -A "$file" --no-color -q
}

استبعاد الملفات التي لا تحتاج فحصًا

skip_patterns=("vendor/" "node_modules/" "db/schema.rb" ".min.js" "_test.go")
for pattern in "${skip_patterns[@]}"; do
  [[ "$file" == *"$pattern"* ]] && exit 0
done

النتيجة الفعلية

بعد الإعداد، يصبح سير العمل:

  1. تطلب من Claude كتابة ملف Ruby
  2. يكتبه Claude بأداة Write
  3. يشغّل Hook تلقائيًا rubocop -A — يجد 3 مشاكل
  4. يصلح RuboCop اثنتين تلقائيًا؛ الثالثة تحتاج حكمًا بشريًا
  5. ترسل المشكلة الثالثة إلى Claude عبر stderr
  6. يصلح Claude الكود، يُشغَّل Hook مرة أخرى
  7. الفحص الثاني يمر — تم

لا تحتاج لتشغيل أي أمر فحص يدويًا.


عام مقابل مستوى المشروع

عام (~/.claude/settings.json): مناسب عند استخدام نفس القواعد في جميع المشاريع.

مستوى المشروع (.claude/settings.json في git): موصى به للفرق. كل من يفتح المستودع يحصل على الإعداد الصحيح تلقائيًا.

يمكن التعايش بينهما؛ hooks المشروع تندمج مع العامة وتعمل معًا.


الخلاصة

الفحص التلقائي للكود باستخدام Hooks يتلخص في ثلاث خطوات:

  1. PostToolUse + matcher "Write|Edit" لاعتراض كتابة الملفات
  2. الحصول على مسار الملف وتوجيهه إلى الـ linter المناسب حسب الامتداد
  3. عند الفشل، الخروج بكود 2 ليرى Claude الخطأ ويصلحه

ابدأ بلغة واحدة. بمجرد أن تعمل، أضف المزيد. احفظ السكريبتات في .claude/hooks/ وشاركها مع الفريق.