الانتقال إلى المحتوى الرئيسي

title: العمارة description: “كيفية عمل معالج الخطاف وتحميل الإعدادات وتقييم السياسات بشكل داخلي” icon: sitemap

تشرح هذه الوثيقة كيفية عمل failproofai بشكل داخلي: كيفية اعتراض نظام الخطاف لاستدعاءات أدوات الوكيل، وكيفية تحميل ودمج الإعدادات، وكيفية تقييم السياسات، وكيفية مراقبة لوحة التحكم لنشاط الوكيل.

نظرة عامة

يمتلك failproofai نظامين فرعيين مستقلين:
  1. معالج الخطاف - عملية سطر أوامر سريعة يستدعيها Claude Code على كل استدعاء أداة وكيل. يقيّم السياسات ويعيد قرارًا.
  2. مراقب الوكيل (لوحة التحكم) - تطبيق ويب Next.js لمراقبة جلسات الوكيل وإدارة السياسات.
يشترك كلا النظامين الفرعيين في ملفات الإعدادات في ~/.failproofai/ ومجلد .failproofai/ الخاص بالمشروع، لكنهما يعملان كعمليات منفصلة ويتصلان فقط عبر نظام الملفات.

معالج الخطاف

التكامل مع Claude Code

عند تشغيل failproofai policies --install، يكتب إدخالات مثل هذه في ~/.claude/settings.json:
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "failproofai --hook PreToolUse"
          }
        ]
      }
    ],
    "PostToolUse": [ ... ]
  }
}
ثم يستدعي Claude Code failproofai --hook PreToolUse كعملية فرعية قبل كل استدعاء أداة، مرسلاً حمولة JSON عبر stdin.

تنسيق الحمولة

{
  "session_id": "abc123",
  "transcript_path": "/home/user/.claude/projects/myproject/sessions/abc123.jsonl",
  "cwd": "/home/user/myproject",
  "permission_mode": "default",
  "hook_event_name": "PreToolUse",
  "tool_name": "Bash",
  "tool_input": { "command": "sudo apt install nodejs" }
}
بالنسبة لأحداث PostToolUse، تحتوي الحمولة أيضًا على tool_result مع مخرجات الأداة. يفرض المعالج حدًا أقصى لـ stdin بحجم 1 ميجابايت. يتم تجاهل الحمولات التي تتجاوز هذا الحد وجميع السياسات تسمح ضمنيًا.

تنسيق الاستجابة

رفض (PreToolUse):
{
  "hookSpecificOutput": {
    "permissionDecision": "deny",
    "permissionDecisionReason": "Blocked by failproofai: sudo command blocked"
  }
}
رفض (PostToolUse):
{
  "hookSpecificOutput": {
    "additionalContext": "Blocked by failproofai because: API key detected in output"
  }
}
توجيه (أي حدث ما عدا Stop):
{
  "hookSpecificOutput": {
    "additionalContext": "Instruction from failproofai: Verify tests pass before committing."
  }
}
توجيه حدث التوقف:
  • رمز الخروج: 2
  • السبب مكتوب في stderr (وليس stdout)
السماح:
  • رمز الخروج: 0
  • stdout فارغ
السماح مع رسالة: يسمح allow(message) للسياسة بإرسال سياق معلومات إلى Claude حتى عند السماح بالعملية. يكتب معالج الخطاف JSON التالي إلى stdout (وليس ملف إعدادات — هذه هي استجابة المعالج لـ Claude Code، تماماً مثل الإجابات على الرفض والتوجيه أعلاه):
// Written to stdout by the hook handler process
{
  "hookSpecificOutput": {
    "additionalContext": "All CI checks passed on branch 'feat/my-feature'."
  }
}
  • رمز الخروج: 0 (العملية مسموحة)
  • عند عودة عدة سياسات allow برسالة، يتم ربط رسائلها بفواصل سطر جديد في سلسلة additionalContext واحدة
  • إذا لم توفر أي سياسة رسالة، يكون stdout فارغاً (نفس السابق)

خط أنابيب المعالجة

ينفذ src/hooks/handler.ts خط الأنابيب الكامل:
stdin JSON
  → parse payload (max 1 MB)
  → extract session metadata (session_id, cwd, tool_name, tool_input, etc.)
  → readMergedHooksConfig(cwd)    ← merges project + local + global config
  → register enabled builtin policies with resolved params
  → load custom policies from customPoliciesPath (if set)
  → register custom policies into policy registry
  → evaluate all policies (builtins first, then custom)
      → first deny short-circuits
      → instruct decisions accumulate
      → allow messages accumulate
  → write JSON decision to stdout
  → persist event to ~/.failproofai/hook-activity.jsonl
  → exit
تعمل العملية بأكملها في أقل من 100 ميلي ثانية للحمولات النموذجية بدون استدعاءات LLM.

تحميل الإعدادات

يطبق src/hooks/hooks-config.ts تحميل الإعدادات بثلاث نطاقات.
[1] {cwd}/.failproofai/policies-config.json        ← project  (highest priority)
[2] {cwd}/.failproofai/policies-config.local.json  ← local
[3] ~/.failproofai/policies-config.json             ← global   (lowest priority)
منطق الدمج:
  • enabledPolicies - اتحاد مزال التكرار عبر جميع الملفات الثلاثة
  • policyParams - لكل سياسة، الملف الأول الذي يعرّفها يفوز بالكامل
  • customPoliciesPath - الملف الأول الذي يعرّفه يفوز
  • llm - الملف الأول الذي يعرّفه يفوز
تستخدم لوحة تحكم الويب readHooksConfig() (العام فقط) للقراءة والكتابة، حيث لا يتم استدعاؤها مع cwd المشروع.

تقييم السياسة

يشغل src/hooks/policy-evaluator.ts السياسات بالترتيب. لكل سياسة:
  1. البحث عن مخطط params الخاص بالسياسة (إن وجد).
  2. قراءة policyParams[policy.name] من الإعدادات المدمجة.
  3. دمج القيم المقدمة من قبل المستخدم فوق الافتراضيات في المخطط لإنتاج ctx.params.
  4. استدعاء policy.fn(ctx) مع السياق المحل.
  5. إذا كانت النتيجة deny، توقف على الفور وأعد هذا القرار.
  6. إذا كانت النتيجة instruct، تراكم الرسالة والمتابعة.
  7. إذا كانت النتيجة allow، انتقل إلى السياسة التالية.
بعد تشغيل جميع السياسات:
  • إذا تم إرجاع أي deny، أصدر استجابة الرفض.
  • إذا تم جمع أي عائدات instruct، أصدر استجابة توجيه واحدة مع ربط جميع الرسائل.
  • وإلا، أصدر استجابة السماح (stdout فارغ، الخروج 0).

السياسات المدمجة

يعرّف src/hooks/builtin-policies.ts جميع 39 سياسة مدمجة كائنات BuiltinPolicyDefinition:
interface BuiltinPolicyDefinition {
  name: string;
  description: string;
  fn: (ctx: PolicyContext) => PolicyResult;
  match: {
    events: HookEventType[];
    tools?: string[];
  };
  defaultEnabled: boolean;
  category: string;
  beta?: boolean;
  params?: PolicyParamsSchema;
}
السياسات التي تقبل params تعلن PolicyParamsSchema بأنواع وافتراضيات لكل معامل. يحقن مقيّم السياسة القيم المحلة في ctx.params قبل استدعاء fn. تقرأ دوال السياسة ctx.params بدون حماية فارغة لأن الافتراضيات تُطبق دائماً أولاً. يستخدم مطابقة الأنماط داخل السياسات رموز الأوامر المحللة (argv)، وليس مطابقة السلسلة النصية الخام. وهذا يمنع الالتفاف عبر حقن عامل الأوامر (على سبيل المثال، نمط لـ sudo systemctl status * لا يمكن الالتفاف عليه بإضافة ; rm -rf / إلى الأمر).

السياسات المخصصة

ينفذ src/hooks/custom-hooks-registry.ts سجل مدعوم globalThis:
const REGISTRY_KEY = "__failproofai_custom_hooks__";

export const customPolicies = {
  add(hook: CustomHook): void { ... }
};

export function getCustomHooks(): CustomHook[] { ... }
export function clearCustomHooks(): void { ... }  // used in tests
يحمل src/hooks/custom-hooks-loader.ts ملف السياسة الخاص بالمستخدم:
  1. اقرأ customPoliciesPath من الإعدادات؛ تخطي إذا كان غائباً.
  2. حل إلى مسار مطلق؛ تحقق من وجود الملف.
  3. أعد كتابة جميع واردات from "failproofai" إلى مسار dist الفعلي حتى يتم حل customPolicies إلى نفس سجل globalThis.
  4. أعد كتابة الواردات المحلية العابرة بشكل متكرر لضمان التوافقية ESM.
  5. اكتب ملفات .mjs مؤقتة وimport() ملف الدخول.
  6. اتصل بـ getCustomHooks() لاسترجاع الخطافات المسجلة.
  7. نظف جميع الملفات المؤقتة في كتلة finally.
في حالة حدوث أي خطأ (ملف غير موجود، خطأ بناء جملة، فشل الاستيراد)، يتم تسجيل الخطأ في ~/.failproofai/hook.log ويعيد المحمل مصفوفة فارغة. السياسات المدمجة غير متأثرة. يتم تقييم السياسات المخصصة بعد جميع السياسات المدمجة. إنكار السياسة المخصصة لا يزال يختصر السياسات المخصصة الإضافية (لكن جميع المدمجة قد عملت بالفعل في تلك النقطة).

تسجيل النشاط

بعد كل حدث خطاف، يضيف المعالج سطر JSONL إلى ~/.failproofai/hook-activity.jsonl:
{
  "timestamp": "2026-04-06T12:34:56.789Z",
  "sessionId": "abc123",
  "eventType": "PreToolUse",
  "toolName": "Bash",
  "policyName": "block-sudo",
  "decision": "deny",
  "reason": "sudo command blocked by failproofai",
  "durationMs": 12
}
سطر واحد لكل سياسة اتخذت قرار غير سماح. لا يتم تسجيل قرارات السماح (للحفاظ على صغر حجم الملف).

عمارة لوحة التحكم

لوحة التحكم هي تطبيق Next.js 16 يستخدم App Router مع React Server Components و Server Actions.
app/
  layout.tsx                  ← Root layout (theme, telemetry, nav)
  projects/page.tsx           ← Server component: list all Claude projects
  project/[name]/page.tsx     ← Server component: list sessions in a project
  project/[name]/session/
    [sessionId]/page.tsx      ← Server component: render session viewer
  policies/page.tsx           ← Client component: policy management + activity log
  actions/
    get-hooks-config.ts       ← Read config + policy list
    update-hooks-config.ts    ← Toggle policy on/off
    update-policy-params.ts   ← Update policy parameters
    get-hook-activity.ts      ← Paginate/search activity log
    install-hooks-web.ts      ← Install/remove hooks from the browser
  api/
    download/[project]/[session]/route.ts   ← Per-CLI session export (JSONL or JSON)
تدفق البيانات:
  • تستدعي مكونات الصفحة lib/projects.ts و lib/log-entries.ts لقراءة بيانات المشروع/الجلسة مباشرة من نظام الملفات (بدون طبقة API للقراءات).
  • تستخدم صفحة السياسات Server Actions لجميع التطبيقات (تبديل، تحديث المعاملات، التثبيت/الإزالة).
  • يحلل عارض الجلسة تنسيق نص Claude JSONL ويعرض جدول زمني للرسائل واستدعاءات الأدوات.
قرارات التصميم الرئيسية:
  • بدون قاعدة بيانات - جميع الحالة الدائمة موجودة في ملفات عادية (~/.failproofai/، ~/.claude/projects/).
  • Server Actions للتطبيقات - لا حاجة إلى REST API لعمليات CRUD.
  • React Server Components لصفحات القراءة - تحميل أولي أسرع، بدون حزمة عميل لجلب البيانات.
  • مكونات العميل فقط حيث تكون التفاعلية مطلوبة (تبديلات السياسة، بحث النشاط، عارض السجل).

تخطيط الملفات

failproofai/
├── bin/
│   └── failproofai.mjs           # CLI router (hook / dashboard / install / etc.)
├── src/hooks/
│   ├── handler.ts                # Hook event pipeline
│   ├── builtin-policies.ts       # 39 policy definitions
│   ├── policy-evaluator.ts       # Policy execution engine
│   ├── policy-registry.ts        # Policy registration and lookup
│   ├── policy-types.ts           # TypeScript interfaces
│   ├── hooks-config.ts           # Multi-scope config loading
│   ├── custom-hooks-registry.ts  # globalThis-backed hook registry
│   ├── custom-hooks-loader.ts    # ESM loader for user JS hooks
│   ├── manager.ts                # install / remove / list operations
│   ├── install-prompt.ts         # Interactive policy selection prompt
│   ├── hook-logger.ts            # Logging to hook.log
│   ├── hook-activity-store.ts    # Persist activity to hook-activity.jsonl
│   └── llm-client.ts             # LLM API client (for AI-powered policies)
├── app/                          # Next.js dashboard (pages + server actions)
├── lib/                          # Shared utilities
│   ├── projects.ts               # Enumerate Claude projects from filesystem
│   ├── log-entries.ts            # Parse Claude transcript JSONL format
│   ├── paths.ts                  # Resolve system paths
│   └── ...
├── components/                   # Shared React UI components
├── contexts/                     # React context providers (theme, auto-refresh, telemetry)
├── examples/                     # Example custom hook files
└── __tests__/                    # Unit and E2E tests