项目文件夹

文件
2026-07-13 13:39:12 +08:00

409 行
30 KiB
Markdown

此文件含有模棱两可的 Unicode 字符
此文件含有可能会与其他字符混淆的 Unicode 字符。 如果您是想特意这样的,可以安全地忽略该警告。 使用 Escape 按钮显示他们。
# CLAUDE.md (עברית)
🌐 **Languages:** 🇺🇸 [English](../../../CLAUDE.md) · 🇸🇦 [ar](../ar/CLAUDE.md) · 🇦🇿 [az](../az/CLAUDE.md) · 🇧🇬 [bg](../bg/CLAUDE.md) · 🇧🇩 [bn](../bn/CLAUDE.md) · 🇨🇿 [cs](../cs/CLAUDE.md) · 🇩🇰 [da](../da/CLAUDE.md) · 🇩🇪 [de](../de/CLAUDE.md) · 🇪🇸 [es](../es/CLAUDE.md) · 🇮🇷 [fa](../fa/CLAUDE.md) · 🇫🇮 [fi](../fi/CLAUDE.md) · 🇫🇷 [fr](../fr/CLAUDE.md) · 🇮🇳 [gu](../gu/CLAUDE.md) · 🇮🇳 [hi](../hi/CLAUDE.md) · 🇭🇺 [hu](../hu/CLAUDE.md) · 🇮🇩 [id](../id/CLAUDE.md) · 🇮🇩 [in](../in/CLAUDE.md) · 🇮🇹 [it](../it/CLAUDE.md) · 🇯🇵 [ja](../ja/CLAUDE.md) · 🇰🇷 [ko](../ko/CLAUDE.md) · 🇮🇳 [mr](../mr/CLAUDE.md) · 🇲🇾 [ms](../ms/CLAUDE.md) · 🇳🇱 [nl](../nl/CLAUDE.md) · 🇳🇴 [no](../no/CLAUDE.md) · 🇵🇭 [phi](../phi/CLAUDE.md) · 🇵🇱 [pl](../pl/CLAUDE.md) · 🇵🇹 [pt](../pt/CLAUDE.md) · 🇧🇷 [pt-BR](../pt-BR/CLAUDE.md) · 🇷🇴 [ro](../ro/CLAUDE.md) · 🇷🇺 [ru](../ru/CLAUDE.md) · 🇸🇰 [sk](../sk/CLAUDE.md) · 🇸🇪 [sv](../sv/CLAUDE.md) · 🇰🇪 [sw](../sw/CLAUDE.md) · 🇮🇳 [ta](../ta/CLAUDE.md) · 🇮🇳 [te](../te/CLAUDE.md) · 🇹🇭 [th](../th/CLAUDE.md) · 🇹🇷 [tr](../tr/CLAUDE.md) · 🇺🇦 [uk-UA](../uk-UA/CLAUDE.md) · 🇵🇰 [ur](../ur/CLAUDE.md) · 🇻🇳 [vi](../vi/CLAUDE.md) · 🇨🇳 [zh-CN](../zh-CN/CLAUDE.md)
---
הקובץ הזה מספק הנחיות ל-Claude Code (claude.ai/code) כאשר עובדים עם קוד במאגר זה.
## התחלה מהירה
```bash
npm install # התקנת תלותים (יוצר אוטומטית .env מ-.env.example)
npm run dev # שרת פיתוח ב-http://localhost:20128
npm run build # בניית הפקה (Next.js 16 עצמאי)
npm run lint # ESLint (0 שגיאות צפויות; אזהרות קיימות מראש)
npm run typecheck:core # בדיקת TypeScript (אמור להיות נקי)
npm run typecheck:noimplicit:core # בדיקה מחמירה (בלי implicit any)
npm run test:coverage # בדיקות יחידה + שער כיסוי (75/75/75/70 — משפטים/שורות/פונקציות/סניפים)
npm run check # lint + בדיקות משולבות
npm run check:cycles # זיהוי תלותיות מעגליות
```
### הרצת בדיקות
```bash
# קובץ בדיקה בודד (רץ בדיקות מקורי של Node.js — רוב הבדיקות)
node --import tsx/esm --test tests/unit/your-file.test.ts
# Vitest (שרת MCP, autoCombo, cache)
npm run test:vitest
# כל הסוויטות
npm run test:all
```
למטריצת הבדיקות המלאה, ראה `CONTRIBUTING.md` → "הרצת בדיקות". לארכיטקטורה מעמיקה, ראה `AGENTS.md`.
---
## פרויקט במבט חטוף
**OmniRoute** — פרוקסי/נתב AI מאוחד. נקודת קצה אחת, 160+ ספקי LLM, חזרה אוטומטית.
| שכבה | מיקום | מטרה |
| ------------- | ----------------------- | ---------------------------------------------------------------- |
| API Routes | `src/app/api/v1/` | נתב אפליקציית Next.js — נקודות כניסה |
| Handlers | `open-sse/handlers/` | עיבוד בקשות (צ'אט, הטמעות, וכו') |
| Executors | `open-sse/executors/` | הפצת HTTP ספציפית לספק |
| Translators | `open-sse/translator/` | המרת פורמטים (OpenAI↔Claude↔Gemini) |
| Transformer | `open-sse/transformer/` | API תגובות ↔ השלמות צ'אט |
| Services | `open-sse/services/` | ניתוב קומבו, מגבלות קצב, קאשינג, וכו' |
| Database | `src/lib/db/` | מודולי דומיין SQLite (45+ קבצים, 55 מיגרציות) |
| Domain/Policy | `src/domain/` | מנוע מדיניות, כללי עלות, לוגיקת חזרה |
| MCP Server | `open-sse/mcp-server/` | 37 כלים (30 בסיס + 3 זיכרון + 4 מיומנויות), 3 תחבורה, ~13 תחומים |
| A2A Server | `src/lib/a2a/` | פרוטוקול JSON-RPC 2.0 של סוכן |
| Skills | `src/lib/skills/` | מסגרת מיומנויות ניתנת להרחבה |
| Memory | `src/lib/memory/` | זיכרון שיחה מתמשך |
מונורפו: `src/` (אפליקציית Next.js 16), `open-sse/` (מרחב עבודה של מנוע סטרימינג), `electron/` (אפליקציית שולחן עבודה), `tests/`, `bin/` (נקודת כניסה ל-CLI).
---
## צינור בקשות
```
Client → /v1/chat/completions (Next.js route)
→ CORS → Zod validation → auth? → policy check → prompt injection guard
→ handleChatCore() [open-sse/handlers/chatCore.ts]
→ cache check → rate limit → combo routing?
→ resolveComboTargets() → handleSingleModel() per target
→ translateRequest() → getExecutor() → executor.execute()
→ fetch() upstream → retry w/ backoff
→ response translation → SSE stream or JSON
→ If Responses API: responsesTransformer.ts TransformStream
```
נתיבי API עוקבים אחרי תבנית עקבית: `Route → CORS preflight → Zod body validation → Optional auth (extractApiKey/isValidApiKey) → API key policy enforcement → Handler delegation (open-sse)`. אין middleware גלובלי של Next.js — חיתוך הוא ספציפי לנתיב.
**נתיב קומבו** (`open-sse/services/combo.ts`): 14 אסטרטגיות (עדיפות, משוקלל, מילוי ראשון, סיבוב, P2C, אקראי, הכי פחות בשימוש, אופטימיזציה של עלות, מודע לאיפוס, אקראי מחמיר, אוטומטי, lkgp, אופטימיזציה של הקשר, העברת הקשר). כל יעד קורא ל`handleSingleModel()` שמקיף את `handleChatCore()` עם טיפול בשגיאות ספציפי ליעד ובדיקות מפסק מעגל. ראה `docs/routing/AUTO-COMBO.md` עבור ניקוד Auto-Combo של 9 גורמים ו`docs/architecture/RESILIENCE_GUIDE.md` עבור 3 שכבות חוסן.
---
## מצב ריצה של חוסן
OmniRoute יש שלושה מנגנוני כישלון זמניים הקשורים אך שונים. שמור על התחום שלהם נפרד כאשר אתה מדבג התנהגות נתיב. ראה את
[דיאגרמת חוסן ב-3 שכבות](./docs/diagrams/exported/resilience-3layers.svg)
(מקור: [docs/diagrams/resilience-3layers.mmd](./docs/diagrams/resilience-3layers.mmd))
למפת מבט-על.
### מפסק מעגל ספק
**תחום**: ספק שלם, לדוגמה `glm`, `openai`, `anthropic`.
**מטרה**: להפסיק לשלוח תנועה לספק שנכשל שוב ושוב ברמת ה-upstream/service, כך שספק לא בריא אחד לא יאט את כל הבקשות.
**יישום**:
- מחלקה מרכזית: `src/shared/utils/circuitBreaker.ts`
- חיבור שער/ביצוע צ'אט: `src/sse/handlers/chatHelpers.ts`, `src/sse/handlers/chat.ts`
- API מצב ריצה: `src/app/api/monitoring/health/route.ts`
- עטיפות משותפות: `open-sse/services/accountFallback.ts`
- טבלת מצב מתמשך: `domain_circuit_breakers`
**מצבים**:
- `CLOSED`: תנועה רגילה מותרת.
- `OPEN`: ספק חסום זמנית; callers מקבלים תגובה של provider-circuit-open
או נתיב קומבו מדלג ליעד אחר.
- `HALF_OPEN`: זמן האיפוס חלף; מאפשר בקשת בדיקה. הצלחה סוגרת את
המפסק, כישלון פותח אותו שוב.
**ברירות מחדל** (`open-sse/config/constants.ts`):
- ספקי OAuth: סף `3`, זמן איפוס `60s`.
- ספקי API-key: סף `5`, זמן איפוס `30s`.
- ספקים מקומיים: סף `2`, זמן איפוס `15s`.
רק מצבי כישלון ברמת ספק צריכים להפעיל את מפסק הספק:
```ts
(408, 500, 502, 503, 504);
```
אל תפעיל את מפסק הספק הכולל עבור שגיאות רגילות של חשבון/מפתח/מודל כמו רוב
המקרים של `401`, `403`, או `429`. אלה בדרך כלל שייכים לקירור חיבור או נעילת מודל. ספק API-key כללי `403` צריך להיות ניתן לשחזור אלא אם כן הוא מסווג
כשגיאת ספק/חשבון סופית.
המפסק משתמש בשחזור עצלן, לא בטיימר רקע. כאשר `OPEN` פג, קריאות כמו `getStatus()`, `canExecute()`, ו`getRetryAfterMs()` מעדכנות את המצב ל
`HALF_OPEN`, כך שדשבורדים ובוני מועמדים לקומבו לא ממשיכים להוציא ספק שפג תוקף לנצח.
### קירור חיבור
**תחום**: חיבור/חשבון/מפתח ספק אחד.
**מטרה**: לדלג זמנית על מפתח/חשבון רע אחד תוך מתן אפשרות לחיבורים אחרים עבור
אותו ספק להמשיך לשרת בקשות.
**יישום**:
- נתיב כתיבה/עדכון: `src/sse/services/auth.ts::markAccountUnavailable()`
- בחירת/סינון חשבון: `src/sse/services/auth.ts::getProviderCredentials...`
- חישוב קירור: `open-sse/services/accountFallback.ts::checkFallbackError()`
- הגדרות: `src/lib/resilience/settings.ts`
שדות חשובים על חיבורי ספק:
```ts
rateLimitedUntil;
testStatus: "unavailable";
lastError;
lastErrorType;
errorCode;
backoffLevel;
```
במהלך בחירת חשבון, חיבור מדולג כאשר:
```ts
new Date(rateLimitedUntil).getTime() > Date.now();
```
קירורים הם גם עצלנים: כאשר `rateLimitedUntil` נמצא בעבר, החיבור הופך
לזמין שוב. בשימוש מוצלח, `clearAccountError()` מנקה את `testStatus`,
`rateLimitedUntil`, שדות שגיאה, ו`backoffLevel`.
התנהגות ברירת מחדל של קירור חיבור:
- קירור בסיסי של OAuth: `5s`.
- קירור בסיסי של API-key: `3s`.
- API-key `429` צריך להעדיף רמזי ניסיון מחדש מה-upstream (`Retry-After`, כותרות איפוס, או
טקסט איפוס שניתן לנתח) כאשר הם זמינים.
- כישלונות חוזרים שניתן לשחזר משתמשים באיפוס אקספוננציאלי:
```ts
baseCooldownMs * 2 ** failureIndex;
```
שומר ה"אנטי-המון" מונע כישלונות מקבילים על אותו חיבור מהארכת הקירור שוב ושוב או מהגדלת `backoffLevel` פעמיים.
מצבים סופיים אינם קירורים. `banned`, `expired`, ו`credits_exhausted` מיועדים להישאר לא זמינים עד ששינויים באישורים/הגדרות יתרחשו או שמפעיל יאפס אותם. אל תחליף מצבים סופיים עם מצב קירור זמני.
### נעילת מודל
**תחום**: ספק + חיבור + מודל.
**מטרה**: להימנע מכיבוי חיבור שלם כאשר רק מודל אחד אינו זמין או
מוגבל מכסה עבור אותו חיבור.
דוגמאות:
- ספקי מכסה לפי מודל המחזירים `429`.
- ספקים מקומיים המחזירים `404` עבור מודל חסר אחד.
- כישלונות הרשאה של מצב/מודל ספציפיים לספק כמו מצבי Grok שנבחרו.
נעילת מודל חיה ב`open-sse/services/accountFallback.ts` ומאפשרת לאותו
חיבור להמשיך לשרת מודלים אחרים.
### הנחיות לדיבוג
- אם כל המפתחות עבור ספק מדולגים, בדוק גם את מצב מפסק הספק וגם את
`rateLimitedUntil`/`testStatus` של כל חיבור.
- אם ספק נראה מוד excluded באופן קבוע לאחר חלון האיפוס, בדוק אם הקוד
קורא את `state` הגולמי במקום להשתמש ב`getStatus()`/`canExecute()`.
- אם מפתח ספק אחד נכשל אבל אחרים צריכים לעבוד, העדיף קירור חיבור על פני
מפסק ספק.
- אם רק מודל אחד נכשל, העדיף נעילת מודל על פני קירור חיבור.
- אם מצב צריך לשחזר את עצמו, עליו להיות עם חותמת זמן עתידית/זמן איפוס ונתיב קריאה שמעודכן מצב שפג תוקף. מצבים קבועים דורשים שינויים ידניים באישורים
או בהגדרות.
## קונבנציות מפתח
### סגנון קוד
- **2 רווחים**, נקודותיים, ציטוטים כפולים, רוחב 100 תווים, פסיקים בסוף שורות ב-ES5 (מאוכפים על ידי lint-staged דרך Prettier)
- **ייבוא**: חיצוני → פנימי (`@/`, `@omniroute/open-sse`) → יחסי
- **שמות**: קבצים=camelCase/kebab, רכיבים=PascalCase, קבועים=UPPER_SNAKE
- **ESLint**: `no-eval`, `no-implied-eval`, `no-new-func` = שגיאה בכל מקום; `no-explicit-any` = אזהרה ב-`open-sse/` וב-`tests/`
- **TypeScript**: `strict: false`, יעד ES2022, מודול esnext, פתרון bundler. העדיף סוגים מפורשים.
### מסד נתונים
- **תמיד** עבור דרך מודולי דומיין ב-`src/lib/db/`**לעולם לא** כתוב SQL גולמי בנתיבים או במטפלים
- **לעולם לא** הוסף לוגיקה ל-`src/lib/localDb.ts` (שכבת ייצוא בלבד)
- **לעולם לא** ייבוא ברוול מ-`localDb.ts` — ייבא מודולים ספציפיים מ-`db/` במקום
- DB singleton: `getDbInstance()` מ-`src/lib/db/core.ts` (יומני WAL)
- הגירות: `src/lib/db/migrations/` — קבצי SQL עם גרסאות, אידמפוטנטיים, ריצה בעסקאות
### טיפול בשגיאות
- try/catch עם סוגי שגיאה ספציפיים, רישום עם הקשר pino
- לעולם לא לבלוע שגיאות בזרמי SSE — השתמש באותות הפסקה לניקוי
- החזר קודי סטטוס HTTP נכונים (4xx/5xx)
### אבטחה
- **לעולם לא** השתמש ב-`eval()`, `new Function()`, או eval מרומז
- אמת את כל הקלטים עם סכמות Zod
- הצפן אישורים במצב מנוחה (AES-256-GCM)
- רשימת דחייה של כותרות עליונות: `src/shared/constants/upstreamHeaders.ts` — שמור על סניטיזציה, סכמות Zod, ובדיקות יחידה מסונכרנות בעת עריכה
- **אישורים ציבוריים עליונים** (Gemini/Antigravity/Windsurf-style OAuth client_id/secret + מפתחות Firebase Web שהופקו מ-CLIs ציבוריים): **חייבים** להיות מוטמעים דרך `resolvePublicCred()` מ-`open-sse/utils/publicCreds.ts`**לעולם לא** כמילולי מחרוזת. ראה `docs/security/PUBLIC_CREDS.md` עבור התבנית החובה.
- **תגובות שגיאה** (HTTP / SSE / מפעיל / MCP handler): **חייבות** לעבור דרך `buildErrorBody()` או `sanitizeErrorMessage()` מ-`open-sse/utils/error.ts`**לעולם לא** לשים `err.stack` או `err.message` גולמיים בגוף התגובה. ראה `docs/security/ERROR_SANITIZATION.md`.
- **פקודות Shell שנבנות ממתודולוגיות**: כאשר קוראים ל-`exec()`/`spawn()` עם סקריפט שצריך ערכי ריצה, העבר אותם דרך האופציה `env` (נמלט אוטומטית) — **לעולם לא** לשלב מחרוזות לא מהימנות/חיצוניות בגוף הסקריפט. הפניה: `src/mitm/cert/install.ts::updateNssDatabases`.
- **ספריות מאובטחות כברירת מחדל** ([tldrsec/awesome-secure-defaults](https://github.com/tldrsec/awesome-secure-defaults)): העדיף Helmet.js, DOMPurify, ssrf-req-filter, safe-regex, Google Tink על פני יישומים מותאמים אישית בכל פעם שמוסיפים משטחים רגישים לאבטחה.
---
## תרחישי שינוי נפוצים
### הוספת ספק חדש
1. רשם ב-`src/shared/constants/providers.ts` (מאומת על ידי Zod בעת טעינה)
2. הוסף מפעיל ב-`open-sse/executors/` אם נדרשת לוגיקה מותאמת (הרחב את `BaseExecutor`)
3. הוסף מתרגם ב-`open-sse/translator/` אם פורמט שאינו OpenAI
4. הוסף קונפיגורציית OAuth ב-`src/lib/oauth/constants/oauth.ts` אם מבוסס OAuth — אם ה-CLI העליון מספק client_id/secret ציבורי, מוטמע דרך `resolvePublicCred()` (ראה `docs/security/PUBLIC_CREDS.md`), **לעולם לא** כמילולי
5. רשם מודלים ב-`open-sse/config/providerRegistry.ts`
6. כתוב בדיקות ב-`tests/unit/` (כלול את האישור של צורת publicCreds אם הוספת ברירת מחדל מוטמעת חדשה)
### הוספת נתיב API חדש
1. צור תיקיה תחת `src/app/api/v1/your-route/`
2. צור `route.ts` עם מטפלים `GET`/`POST`
3. עקוב אחרי התבנית: CORS → אימות גוף Zod → אימות אופציונלי → הפניית מטפלים
4. המטפל הולך ל-`open-sse/handlers/` (ייבא משם, לא בשורה)
5. תגובות שגיאה משתמשות ב-`buildErrorBody()` / `errorResponse()` מ-`open-sse/utils/error.ts` (מסונן אוטומטית — לעולם לא לשים `err.stack` או `err.message` גולמיים בגוף). ראה `docs/security/ERROR_SANITIZATION.md`.
6. הוסף בדיקות — כולל לפחות אישור אחד שתגובות שגיאה לא דולפות עקבות מחסומים (`!body.error.message.includes("at /")`)
### הוספת מודול DB חדש
1. צור `src/lib/db/yourModule.ts` — ייבא `getDbInstance` מ-`./core.ts`
2. ייצא פונקציות CRUD עבור טבלת הדומיין שלך
3. הוסף הגירה ב-`src/lib/db/migrations/` אם נדרשות טבלאות חדשות
4. ייצא מחדש מ-`src/lib/localDb.ts` (הוסף לרשימת הייצוא מחדש בלבד)
5. כתוב בדיקות
### הוספת כלי MCP חדש
1. הוסף הגדרת כלי ב-`open-sse/mcp-server/tools/` עם סכמת קלט Zod + מטפל אסינכרוני
2. רשם בערכת הכלים (מחובר על ידי `createMcpServer()`)
3. הקצה להיקפים המתאימים
4. כתוב בדיקות (קריאות הכלי נרשמות בטבלת `mcp_audit`)
### הוספת מיומנות A2A חדשה
1. צור מיומנות ב-`src/lib/a2a/skills/` (5 כבר קיימות: smart-routing, quota-management, provider-discovery, cost-analysis, health-report)
2. המיומנות מקבלת הקשר משימה (הודעות, מטא-נתונים) → מחזירה תוצאה מובנית
3. רשם ב-`A2A_SKILL_HANDLERS` ב-`src/lib/a2a/taskExecution.ts`
4. חשוף ב-`src/app/.well-known/agent.json/route.ts` (כרטיס סוכן)
5. כתוב בדיקות ב-`tests/unit/`
6. תעד ב-`docs/frameworks/A2A-SERVER.md` טבלת מיומנויות
### הוספת סוכן ענן חדש
1. צור מחלקת סוכן ב-`src/lib/cloudAgent/agents/` המרחיבה את `CloudAgentBase` (3 כבר קיימות: codex-cloud, devin, jules)
2. יישם `createTask`, `getStatus`, `approvePlan`, `sendMessage`, `listSources`
3. רשם ב-`src/lib/cloudAgent/registry.ts`
4. הוסף טיפול ב-OAuth/אישורים אם נדרש (`src/lib/oauth/providers/`)
5. בדיקות + תעד ב-`docs/frameworks/CLOUD_AGENT.md`
### הוספת גדר / Eval / מיומנות / אירוע Webhook חדש
- גדר: `src/lib/guardrails/` → תיעוד: `docs/security/GUARDRAILS.md`
- ערכת Eval: `src/lib/evals/` → תיעוד: `docs/frameworks/EVALS.md`
- מיומנות (סנדבוקס): `src/lib/skills/` → תיעוד: `docs/frameworks/SKILLS.md`
- אירוע Webhook: `src/lib/webhookDispatcher.ts` → תיעוד: `docs/frameworks/WEBHOOKS.md`
## תיעוד הפניה
לכל שינוי שאינו טריוויאלי, קרא קודם את המאמר המתאים:
| תחום | מסמך |
| ---------------------------------------- | ----------------------------------------------------------------- |
| ניווט במאגר | `docs/architecture/REPOSITORY_MAP.md` |
| ארכיטקטורה | `docs/architecture/ARCHITECTURE.md` |
| הפניה הנדסית | `docs/architecture/CODEBASE_DOCUMENTATION.md` |
| אוטו-קומבו (ציון 9 גורמים, 14 אסטרטגיות) | `docs/routing/AUTO-COMBO.md` |
| חוסן (3 מנגנונים) | `docs/architecture/RESILIENCE_GUIDE.md` |
| חזרה על הסקת מסקנות | `docs/routing/REASONING_REPLAY.md` |
| מסגרת מיומנויות | `docs/frameworks/SKILLS.md` |
| מערכת זיכרון (FTS5 + Qdrant) | `docs/frameworks/MEMORY.md` |
| סוכני ענן | `docs/frameworks/CLOUD_AGENT.md` |
| מגני בטיחות (PII / הזרקה / חזון) | `docs/security/GUARDRAILS.md` |
| אישורים ציבוריים (Gemini/וכו') | `docs/security/PUBLIC_CREDS.md` |
| סינון הודעות שגיאה | `docs/security/ERROR_SANITIZATION.md` |
| הערכות | `docs/frameworks/EVALS.md` |
| ציות / ביקורת | `docs/security/COMPLIANCE.md` |
| ווב-הוקים | `docs/frameworks/WEBHOOKS.md` |
| צינור הרשאה | `docs/architecture/AUTHZ_GUIDE.md` |
| הסתרה (TLS / טביעת אצבע) | `docs/security/STEALTH_GUIDE.md` |
| פרוטוקולי סוכנים (A2A / ACP / Cloud) | `docs/frameworks/AGENT_PROTOCOLS_GUIDE.md` |
| שרת MCP | `docs/frameworks/MCP-SERVER.md` |
| שרת A2A | `docs/frameworks/A2A-SERVER.md` |
| הפניה ל-API + OpenAPI | `docs/reference/API_REFERENCE.md` + `docs/reference/openapi.yaml` |
| קטלוג ספקים (נוצר אוטומטית) | `docs/reference/PROVIDER_REFERENCE.md` |
| זרימת שחרור | `docs/ops/RELEASE_CHECKLIST.md` |
---
## בדיקות
| מה | פקודה |
| ----------------------- | -------------------------------------------------------------------- |
| בדיקות יחידה | `npm run test:unit` |
| קובץ בודד | `node --import tsx/esm --test tests/unit/file.test.ts` |
| Vitest (MCP, autoCombo) | `npm run test:vitest` |
| E2E (Playwright) | `npm run test:e2e` |
| פרוטוקול E2E (MCP+A2A) | `npm run test:protocols:e2e` |
| אקוסיסטם | `npm run test:ecosystem` |
| שער כיסוי | `npm run test:coverage` (75/75/75/70 — הצהרות/שורות/פונקציות/סניפים) |
| דוח כיסוי | `npm run coverage:report` |
**כלל PR**: אם אתה משנה קוד ייצור ב-`src/`, `open-sse/`, `electron/`, או `bin/`, עליך לכלול או לעדכן בדיקות באותו PR.
**העדפת שכבת בדיקה**: יחידה קודם → אינטגרציה (רב-מודול או מצב DB) → e2e (UI/זרימת עבודה בלבד). קודד שחזורי באגים כבדיקות אוטומטיות לפני או לצד התיקון.
**מדיניות כיסוי Copilot**: כאשר PR משנה קוד ייצור והכיסוי נמוך מ-75% (הצהרות/שורות/פונקציות) או 70% (סניפים), אל תדווח רק — הוסף או עדכן בדיקות, הרץ מחדש את שער הכיסוי, ואז בקש אישור. כלול פקודות שהופעלו, קבצי בדיקה שהשתנו, ותוצאת כיסוי סופית בדוח ה-PR.
---
## זרימת עבודה של Git
```bash
# אל תבצע קומיט ישירות ל-main
git checkout -b feat/your-feature
git commit -m "feat: תאר את השינוי שלך"
git push -u origin feat/your-feature
```
**קידומות סניפים**: `feat/`, `fix/`, `refactor/`, `docs/`, `test/`, `chore/`
**פורמט קומיט** (Commits קונבנציונליים): `feat(db): הוסף מפסק מעגל` — תחומים: `db`, `sse`, `oauth`, `dashboard`, `api`, `cli`, `docker`, `ci`, `mcp`, `a2a`, `memory`, `skills`
**הוקי Husky**:
- **pre-commit**: lint-staged + `check-docs-sync` + `check:any-budget:t11`
- **pre-push**: `npm run test:unit`
---
## סביבה
- **Runtime**: Node.js ≥20.20.2 <21 || ≥22.22.2 <23 || ≥24 <25, מודולי ES
- **TypeScript**: 5.9+, יעד ES2022, מודול esnext, פתרון bundler
- **Alias נתיב**: `@/*``src/`, `@omniroute/open-sse``open-sse/`, `@omniroute/open-sse/*``open-sse/*`
- **פורט ברירת מחדל**: 20128 (API + לוח מחוונים באותו פורט)
- **ספריית נתונים**: משתנה סביבה `DATA_DIR`, ברירת מחדל ל-`~/.omniroute/`
- **משתני סביבה מרכזיים**: `PORT`, `JWT_SECRET`, `API_KEY_SECRET`, `INITIAL_PASSWORD`, `REQUIRE_API_KEY`, `APP_LOG_LEVEL`
- הגדרה: `cp .env.example .env` ואז צור `JWT_SECRET` (`openssl rand -base64 48`) ו-`API_KEY_SECRET` (`openssl rand -hex 32`)
---
## כללים נוקשים
1. אל תבצע קומיט של סודות או אישורים
2. אל תוסיף לוגיקה ל-`localDb.ts`
3. אל תשתמש ב-`eval()` / `new Function()` / eval מרומז
4. אל תבצע קומיט ישירות ל-`main`
5. אל תכתוב SQL גולמי בנתיבים — השתמש במודולים מ-`src/lib/db/`
6. אל תשתיק שגיאות בזרמי SSE בשקט
7. תמיד אמת קלטים עם סכמות Zod
8. תמיד כלול בדיקות כאשר אתה משנה קוד ייצור
9. הכיסוי חייב להישאר ≥75% (הצהרות, שורות, פונקציות) / ≥70% (סניפים). מדוד נוכחי: ~82%.
10. אל תעקוף הוקי Husky (`--no-verify`, `--no-gpg-sign`) ללא אישור מפעיל מפורש.
11. אל תטמיע אישורי OAuth ציבוריים upstream client_id/secret או מפתחות Firebase Web כמלל מיתר — תמיד עבור דרך `resolvePublicCred()` (`open-sse/utils/publicCreds.ts`). ראה `docs/security/PUBLIC_CREDS.md`.
12. אל תחזיר `err.stack` / `err.message` גולמיים בתגובות HTTP / SSE / executor — תמיד נווט דרך `buildErrorBody()` או `sanitizeErrorMessage()` (`open-sse/utils/error.ts`). ראה `docs/security/ERROR_SANITIZATION.md`.
13. אל תבצע אינטרפולציה של מיתרים של נתיבים חיצוניים או ערכי ריצה לתוך סקריפטים של shell המועברים ל-`exec()`/`spawn()` — העבר דרך אפשרות `env` במקום זאת. הפניה: `src/mitm/cert/install.ts::updateNssDatabases`.
14. אל תדחה אזהרת CodeQL / סריקת סודות ללא (א) בדיקה ראשונה של מסמכי התבנית למעלה כדי לראות אם העוזר חל, ו-(ב) תיעוד ההצדקה הטכנית בהערת הדחייה. תקדים: `js/stack-trace-exposure` הועלה על אתרי קריאה שכבר נווטים דרך `sanitizeErrorMessage()` היא מגבלה ידועה של CodeQL (מסננים מותאמים אישית לא מוכרים) — דחה כ-`false positive` בהתייחסות ל-`docs/security/ERROR_SANITIZATION.md`.
15. אל תחשוף נתיבים שמפעילים תהליכים ילדיים (`/api/mcp/`, `/api/cli-tools/runtime/`) ללא סיווג `isLocalOnlyPath()` ב-`src/server/authz/routeGuard.ts`. אכיפת לולאת חזרה מתבצעת ללא תנאים לפני כל בדיקת auth — JWT דלף דרך מנהרה לא יכול להפעיל תהליך. ראה `docs/security/ROUTE_GUARD_TIERS.md`.
16. לעולם אל תכלול `Co-Authored-By` trailers שמיוחסים לעוזר AI, ל-LLM או לחשבון אוטומציה (למשל שמות המכילים "Claude", "GPT", "Copilot", "Bot"; אימיילים ב-`anthropic.com` / `openai.com` / כתובות `noreply.github.com` השייכות לבוטים). trailers כאלה מנתבים את הייחוס של ה-commit לחשבון הבוט ב-GitHub, ומסתירים את המחבר האמיתי (`diegosouzapw`) בהיסטוריית ה-PR. משתפי פעולה אנושיים — כולל מחברי PR upstream ומדווחי issues שמועתקים ל-OmniRoute — יכולים וחייבים לקבל קרדיט עם trailers סטנדרטיים `Co-authored-by: Name <email>`; תהליכי העבודה של upstream-port (`/port-upstream-features`, `/port-upstream-issues`) תלויים בזה.