* fix(gemini): preserve structured tool calls for antigravity * fix(gemini): parse prefixed textual tool calls * fix(antigravity): preserve textual SSE tool calls * fix(stream): normalize textual passthrough tool calls * fix(stream): normalize split textual tool calls * fix(stream): suppress malformed textual tool calls * fix(stream): suppress compact malformed tool calls * fix(stream): emit structured textual tool calls * fix(stream): suppress unknown textual tool calls * fix(stream): normalize responses textual tool calls * chore: ignore .claude/settings.local.json (per-user Claude Code permissions) * fix(opencode-go): route qwen3.x via claude messages + repair fixMissingToolResponses for Claude-shape upstreams (#2791) Integrated into release/v3.8.6 * fix: resolve npm install warnings — remove dead deps, relax engine constraint (#2792) Integrated into release/v3.8.6 * fix: register missing web-cookie validators (claude-web, gemini-web, copilot-web, t3-web) (#2793) Integrated into release/v3.8.6 * fix: Error: Unable to inspect existing database #2771 (#2795) Integrated into release/v3.8.6 * fix(oauth): repair Google loopback callback flow (#2796) Integrated into release/v3.8.6 * feat(logs): add clean history button (#2799) Integrated into release/v3.8.6 * [codex] home: restore settings-driven home layout and quota auto-refresh (#2800) Integrated into release/v3.8.6 * fix(gemini): emit signaturelessToolCallMode:text for GEMINI format models (#2801) Integrated into release/v3.8.6 * feat(modelSpecs): align opencode-go family with upstream provider limits (#2802) Integrated into release/v3.8.6 * chore: apply unit test fixes, polyfills, and environment precedence fixes * docs(agents): atualiza fluxos de release e triagem Expande os workflows de release para incluir auditoria de segurança, CHANGELOG completo por commits, quality gate obrigatório, homologação em VPS local, publicação oficial, deploy em Akamai e validação de artefatos. Reorganiza a triagem de features com arquivos permanentes por bucket, suporte a itens em andamento, regra de reclaim após 15 dias e novo tratamento para ideias viáveis catalogadas. Corrige a orientação de revisão de discussões para usar a ordem cronológica real dos comentários e respostas ao identificar a última atividade. * fix(lockout): classify Gemini Antigravity resource exhaustion as quota_exhausted * fix(reasoning): gate replay by interleaved field * docs(rule-16): permit human Co-authored-by, restrict only AI/bot trailers Rule #16 previously banned all `Co-Authored-By` trailers absolutely. That blocked the upstream-port workflows (`/port-upstream-features` and `/port-upstream-issues`), which must credit human upstream PR authors and issue reporters in OmniRoute commits. Refine the rule to ban only AI/bot-attributed trailers (Claude, GPT, Copilot, Bot; anthropic.com / openai.com / bot-owned noreply.github.com emails) while allowing standard human `Co-authored-by: Name <email>` attribution. Sync the rule across the source CLAUDE.md, the E2E shakedown doc note, and 41 i18n translations. * fix(gitlawb): add specialty validators for connection test — bypass /models probe GitLawB OpenGateway API (xiaomi-mimo compatible) does not expose a /models endpoint, causing validateOpenAILikeProvider to 404 on the initial probe and report 'Provider validation endpoint not supported'. Add specialty validators for both gitlawb and gitlawb-gmi that follow the same pattern as the existing xiaomi-mimo validator: skip GET /models, validate directly via POST /chat/completions with a minimal test message. Any 401/403 response means an invalid key; all other responses mean auth is OK. Fixes test-connection returning 404 for GitLawB providers. * test(gitlawb): add 12 unit tests for gitlawb and gitlawb-gmi specialty validators Covers success, auth failure (401/403), non-auth acceptance (400/422/429), network errors, and custom baseUrl overrides for both providers. * feat(gitlawb): serve models from static registry without API-unavailable warning GitLawB's OpenGateway API does not expose a /models endpoint per provider-path. Previously the models route fell through to the generic fallback which returned static catalog models with the misleading 'API unavailable — using local catalog' warning. Now gitlawb and gitlawb-gmi are handled as static model providers (same pattern as reka and qwen OAuth) — models are served from the provider registry without any warning, since all registered models are functional via POST /chat/completions. * refactor(gitlawb): extract shared opengateway validator factory, fix docs path in test - Extract gitlawb/gitlawb-gmi validators into buildOpengatewayValidator factory - Fix dockerignore-docs-coverage test: update stale docs/AUTO-COMBO.md -> docs/routing/AUTO-COMBO.md * fix(reasoning): guard interleaved capability lookup * feat(gitlawb): dynamic model fetch with gmi-cloud fallback Hybrid approach: - gitlawb (xiaomi-mimo): dynamic /models endpoint → 356 models - gitlawb-gmi (gmi-cloud): 404 fallback → local catalog gracefully Mimics Gitlawb/openclaude's model-routing pattern * i18n(pt-BR): complete missing translations and sync with en.json * feat(build): nix multi-OS package manager install (#2806) Integrated into release/v3.8.6 * fix(i18n): translate 144 new __MISSING__ pt-BR strings (#2816) Integrated into release/v3.8.6 * chore(docs): set coverage gate to 40/40/40/40 in CLAUDE.md Aligns the documented coverage gate with the v3.8.6 release decision (lowered from 75/75/75/70). Matches the threshold already set in package.json by the large feature PRs (planos 11-22). * fix(cli): respect PORT env var in serve command (#2845) Integrated into release/v3.8.6. * fix(deepseek-web): return 400 when client sends tools[] - chat.deepseek.com has no tool support (#2854) Integrated into release/v3.8.6. * fix(qoder): reject invalid/expired PATs returning Cosy 500 error (#2860) Integrated into release/v3.8.6. * fix(cli): register openclaw in tool-detector (#2833) (#2850) Integrated into release/v3.8.6. * fix(api): include noAuth providers in /v1/models catalog (#2798) (#2814) Integrated into release/v3.8.6. * fix(combo): resolve custom provider targets via combo name (#2778) (#2812) Integrated into release/v3.8.6. * fix(translator): strip safety_identifier in openai-responses cleanup (#2770) (#2809) Integrated into release/v3.8.6. * fix(quota): honor explicit per-connection preflight opt-out (#2831) (#2844) Integrated into release/v3.8.6. * fix(usage): un-invert GitHub Copilot Free/limited quota — limited_user_quotas is remaining (#2876) (#2881) Integrated into release/v3.8.6. * fix(nous-research): correct baseUrl to include /chat/completions (#2826) (#2835) Integrated into release/v3.8.6. * fix(opencode): qwen3.x max/plus models lack vision support (#2822) (#2836) Integrated into release/v3.8.6. * fix(translator): pass-through tool_search built-in tool type (#2766) (#2811) Integrated into release/v3.8.6. * fix(github): route claude-opus-4.6 via chat completions (#2821) Integrated into release/v3.8.6. * docs(oauth): add Windsurf login fix design (Phase 1 hotfix + Phase 2 Firebase OAuth) Two-phase plan to fix the broken Windsurf OAuth flow: - Phase 1: drop the dead app.devin.ai/editor/signin PKCE path, promote import-token from windsurf.com/show-auth-token as the primary path - Phase 2: port Firebase OAuth + RegisterUser flow from fendoushaonian/WindSurf-gRPC-API for full browser-based automation Spec only - no code changes yet. * docs(plan): Phase 1 windsurf login hotfix implementation plan 10 tasks covering: - TDD assertions for flowType + 410 Gone responses - Provider switch to import_token - Route handler retiring authorize/start-callback-server/poll-callback - OAuthModal UI override - i18n sync - Verification + PR steps * fix(cli): replace cli-table3 with hand-rolled formatter (#2752) (#2813) Integrated into release/v3.8.6. * fix(skills): skip interception for unregistered client-native tools (#2815) (#2817) Integrated into release/v3.8.6. * feat(sse): add RTK filters for kubectl, docker-build, composer, gh (#2824) Integrated into release/v3.8.6. * fix(geminiHelper): support rec.image content shape + warn on dropped remote URLs (refs #2807) (#2855) Integrated into release/v3.8.6. * fix(cli): allow nullable/optional apiKey in cliMitmStartSchema (#2857) Integrated into release/v3.8.6. * fix(combo): preserve system messages during context handoff summary generation (#2865) Integrated into release/v3.8.6. * fix: wire CLIProxyAPI fallback settings into chatCore routing engine (#2866) Integrated into release/v3.8.6. * fix(usage): add opencode quota fetcher (#2852) (#2867) Integrated into release/v3.8.6. * feat(claude): default xhigh support for newer Opus models (#2874) Integrated into release/v3.8.6. * fix(cli): restore omniroute logs command stream (#2756) (#2810) Integrated into release/v3.8.6. * fix(combo): normalize upstream Headers for Node 24 undici interop (#2751) (#2823) Integrated into release/v3.8.6. * Rename proxy log Public IP to Client IP (#2880) Integrated into release/v3.8.6. * fix(claude): preserve max effort for supported models (#2875) Integrated into release/v3.8.6. * fix(oauth): switch windsurf provider to import_token flow The PKCE auth URL targeting app.devin.ai/editor/signin returns 404 post-rebrand. Until Phase 2 ports Firebase OAuth + RegisterUser, the only supported path is import-token via windsurf.com/show-auth-token. - windsurf.ts: drop buildAuthUrl, set flowType=import_token - generateAuthData returns supported:false + helpful error for windsurf/devin-cli - tests: assert flowType + disabled stub * fix(oauth): return 410 Gone for retired windsurf/devin-cli PKCE actions start-callback-server, authorize, and poll-callback (GET + POST) now return 410 Gone with a pointer to /import-token. The 410 short-circuit runs before auth so the response is honest about the action being permanently gone, not gated. Codex PKCE flow unchanged. Tests: 5 new assertions cover GET + POST 410 paths and a Codex regression check. * refactor(oauth): annotate retired PKCE fields in WINDSURF_CONFIG No behaviour change - comment-only update documenting that authorizeUrl, codeChallengeMethod, callbackPort, callbackPath, apiServerUrl, and exchangePath are no longer consumed. Active fields (inferenceUrl, showAuthTokenUrl, firebaseApiKey, ideName) called out separately. * fix(cli,docs): use requireCliToolsAuth in logs route + document OPENCODE quota env Post-merge contract fixes for v3.8.6: - src/app/api/cli-tools/logs/route.ts (#2810) now uses the shared requireCliToolsAuth guard (param renamed req->request) to satisfy the cli-tools-auth-hardening contract test. - Document OMNIROUTE_OPENCODE_QUOTA_URL (#2867) in docs/reference/ENVIRONMENT.md to satisfy the env/docs sync contract. * fix(dashboard): force import-token panel for windsurf/devin-cli Phase 1 hotfix: hide the 'Browser Login' tab and start in Paste API Key mode. Removes windsurf/devin-cli from PKCE_CALLBACK_SERVER_PROVIDERS so no callback server is started for them. Codex still uses the PKCE flow. The 'Get token' link continues to point at windsurf.com/show-auth-token via the existing supportsTokenPaste form copy. * fix(oauth): windsurf import-token mapTokens signature mismatch The route at `src/app/api/oauth/[provider]/[action]/route.ts` invokes `providerData.mapTokens({ accessToken: token })` (object), matching the cursor/kiro signature. The windsurf provider was declared with `mapTokens(token: string)` instead, so the entire object was stored as `accessToken`. When the connection record reached the SQLite layer it crashed with: SQLite3 can only bind numbers, strings, bigints, buffers, and null Fix by aligning windsurf's `mapTokens` signature with the route caller and the cursor/kiro convention. Also dedupe a copy-pasted second `if (action === "import-token")` block in the route handler — the second block was unreachable but identical to the first. Adds two regression tests asserting that `provider.mapTokens({ accessToken })` returns a string `accessToken` for both windsurf and devin-cli, so a future signature drift trips the gate instead of the SQLite bind error in production. * feat(compression): expand pt-BR pack with troglodita rules (15 → 49) (#2818) Integrated into release/v3.8.6 * fix(sse): repair RTK engine defaults so dedup and direct calls work (#2825) Integrated into release/v3.8.6 * fix(mcp): redirect console.log/warn to stderr in --mcp stdio mode (#2840) Integrated into release/v3.8.6 * fix(gemini-cli): prefer real project IDs over default-project (#2841) Integrated into release/v3.8.6 * fix(opencode-go): add provider limits quota fetcher (#2861) Integrated into release/v3.8.6 * Audit & add web cookie providers: fix 4 missing registry entries + DuckDuckGo (#2862) Integrated into release/v3.8.6 * fix(antigravity): harden signatureless tool history (#2878) Integrated into release/v3.8.6 * fix: provider model sync pruning and dynamic antigravity MITM proxy mappings (#2886) Integrated into release/v3.8.6 * feat(usage): per-API-key token limits scoped to model/provider/global (#2888) Integrated into release/v3.8.6 * fix(audio): build multipart body manually to preserve Content-Type (#2842) Integrated into release/v3.8.6 * refactor: remove agent skill documentation files and streamline maintenance workflows * test(stabilization): resolve unit test failures in blackbox-web, schema-coercion, translator-helper-branches, usage-service-hardening, and audio-transcription * fix(security): mitigate Socket.dev supply-chain findings + secrets opt-in + minimal build profile (#2863) (#2871) Two real security gaps closed and four cosmetic Socket.dev fingerprints removed. See docs/security/SOCKET_DEV_FINDINGS.md for the per-finding maintainer attestation. Real bugs fixed: - cloudSync: HMAC verification of `X-Cloud-Sig` + opt-in `OMNIROUTE_CLOUD_SYNC_SECRETS=true` before overwriting `accessToken` / `refreshToken` / `providerSpecificData` from a remote response. Closes the silent-credential-swap surface (a misconfigured or hostile CLOUD_URL could previously replace local tokens unverified). - Zed import: split into 2-step `/discover` + `/import` flow. `/import` now requires `confirmedAccounts: [{ service, account, fingerprint }]` and re-reads the keychain server-side to filter by fingerprint, so a tampered discover response cannot trick the endpoint into saving an unrelated token. Cosmetic Socket.dev mitigations: - runElevatedPowerShell writes the elevated payload to a per-call temp `.ps1` file (mode 0o600) and references it via `-File`. Removes the textbook `-EncodedCommand <base64utf16le>` pattern flagged as malware by Socket's AI classifier. - Maintainer attestation `SECURITY-AUDITOR-NOTE:` blocks added at every flagged call site pointing to `docs/security/SOCKET_DEV_FINDINGS.md`. Build-time hardening: - `OMNIROUTE_BUILD_PROFILE=minimal` (`npm run build:secure`) physically removes the four sensitive modules from the standalone bundle via webpack `NormalModuleReplacementPlugin`. Stubs throw `FeatureDisabledError` at runtime. Intended for the `omniroute-secure` artifact. Tests: - 24 new unit tests in `tests/unit/security/` covering the wrapper builder, HMAC verification (4 cases), credential fingerprint determinism (5 cases), confirmedAccounts validation + fingerprint filtering (6 cases), and the minimal-build stubs (5 cases). Docs: - New `docs/security/SOCKET_DEV_FINDINGS.md` — per-finding attestation. - New `socket.yml` — Socket.dev v2 config pointing at the attestation. - Updated `SECURITY.md` — supply-chain scanner section. - Updated `.env.example` — three new env vars documented. Backwards compatibility: - Cloud sync token overwrite is OFF by default. Users who relied on it must set `OMNIROUTE_CLOUD_SYNC_SECRETS=true`. Breaking change documented in CHANGELOG. - Zed import 2-step is the new default; legacy 1-step preserved behind `OMNIROUTE_ZED_IMPORT_LEGACY_ONE_STEP=true` and will be removed in v3.9. Closes #2863 * fix(security): redact public Firebase Web key from windsurf spec; doc SHA-256 cache-key rationale (#2894) Two security-scanning findings on release/v3.8.6: - Secret-scanning alert 7 (google_api_key): the windsurf login-fix design spec embedded the literal public Firebase Web API key on two lines. Firebase Web API keys are non-sensitive by design (they identify the project; access is gated by Firebase Security Rules + key restrictions), but the literal trips secret scanning. Redacted to a placeholder; the embedded default still goes through resolvePublicCred per rule #11. - Code-scanning alert 261 (js/insufficient-password-hash): tokenCacheKey() uses SHA-256 to derive an in-memory cache key from the session token, not for password-at-rest storage. Added a comment documenting why CWE-916 KDFs do not apply (false positive). * fix(ci): resolve release/v3.8.6 gate failures (docs-sync, any-budget, pack-artifact) (#2895) * fix(ci): resolve release/v3.8.6 gate failures (docs-sync, any-budget, pack-artifact) Three CI gates failed on release/v3.8.6 (run 26630300877): - docs-sync: CHANGELOG had a spurious "## [3.8.6-patch]" section above "## [3.8.6]", so the latest release no longer matched package.json (3.8.6) and the 41 i18n CHANGELOG mirrors were flagged as missing that section. Fold the lone #2752 entry into [3.8.6] and drop the patch heading. - any-budget:t11: open-sse/handlers/chatCore.ts regressed to 1 explicit `any` (budget 0). Type the persist callback arg as Record<string, unknown>, which matches runWithOnPersist's RefreshPersistFn contract exactly. - pack-artifact: open-sse/utils/setupPolyfill.ts ships via package.json "files" (bin/omniroute.mjs imports it at startup) but was missing from the pack policy allowlist. Allow it and add a regression test. * fix(security): redact public Firebase Web key from windsurf spec Redact the literal public Firebase Web API key (secret-scanning #7) to a placeholder, mirroring the redaction on release/v3.8.6 (PR #2894) and the windsurf fix branch. Non-sensitive public Web key; trips secret scanning. * feat(combo): Zero-Latency Combos (Hedging, Proactive Compression, Predictive TTFT) (#2868) * feat(combo): implement zero-latency combo optimizations (hedging, proactive compression, predictive TTFT) * fix(combo): fix predictive TTFT skip logic and unhandled promise rejections --------- Co-authored-by: Automation <automation@omniroute> * feat: implement automated skill workflows and update system configuration and validation schemas * test: eliminate dynamic cast warnings in cloud-sync unit test * test: isolate services-branch-hardening database directory to avoid concurrency issues * feat(providers): add 7 new web-cookie providers + research catalog + discovery tool New providers: - huggingchat: free LLM chat via huggingface.co/chat (no subscription) - phind: free dev-focused AI chat via phind.com/api/agent - poe-web: multi-model chat via poe.com GraphQL (p-b cookie) - venice-web: privacy-focused AI chat via venice.ai (session cookie) - v0-vercel-web: Vercel v0 code gen via v0.dev (session cookie) - kimi-web: Moonshot Kimi chat via kimi.moonshot.cn (session cookie) - doubao-web: ByteDance Doubao chat via doubao.com (session cookie) Additional: - Research catalog: docs/research/UNLIMITED_LLM_ACCESS.md - Discovery tool design + stub: src/lib/discovery/ + migration 073 - Unit tests: 33 tests for all 7 providers - Shared helpers consolidated in error.ts (slop cleanup) - All registered in WEB_COOKIE_PROVIDERS + providerRegistry + webSessionCredentials Closes #2885 * fix(typecheck): resolve typecheck errors in combo spec and compression modules * feat(api,oauth): add `agy` (Antigravity CLI) standalone provider with CLI token import (#2899) Add a standalone OAuth provider `agy` (Antigravity CLI) next to gemini-cli/antigravity. It reuses the antigravity inference backend (identical Google client_id + daily-cloudcode-pa.googleapis.com endpoint, executor and token-refresh) but ships its own model catalog — including the Claude models the backend exposes (claude-opus-4-6-thinking, claude-sonnet-4-6) — its own account pool, and four ways to connect: - token-file import (paste/upload the agy oauth token JSON) - auto-detect a local CLI login (~/.gemini/antigravity-cli/antigravity-oauth-token) - browser OAuth (via the shared OAuthModal Google loopback flow) - bulk / ZIP import New routes: POST /api/providers/agy-auth/{import,import-bulk,zip-extract,apply-local}. Catalog pinned from the live :fetchAvailableModels endpoint. Docs (openapi.yaml, ENVIRONMENT.md, .env.example, CHANGELOG) updated; new unit tests for registration, the token parser, and route auth-hardening. * fix(security): redact public Firebase Web key from windsurf spec (#2896) Redact the literal public Firebase Web API key (secret-scanning #7) to a placeholder. Firebase Web API keys are non-sensitive by design but the literal trips GitHub secret scanning. Mirrors the redaction landed on release/v3.8.6 (PR #2894). Embedded default still flows through resolvePublicCred (rule #11). * Pr 2871 (#2897) * fix(security): mitigate Socket.dev supply-chain findings + secrets opt-in + minimal build profile (#2863) Two real security gaps closed and four cosmetic Socket.dev fingerprints removed. See docs/security/SOCKET_DEV_FINDINGS.md for the per-finding maintainer attestation. Real bugs fixed: - cloudSync: HMAC verification of `X-Cloud-Sig` + opt-in `OMNIROUTE_CLOUD_SYNC_SECRETS=true` before overwriting `accessToken` / `refreshToken` / `providerSpecificData` from a remote response. Closes the silent-credential-swap surface (a misconfigured or hostile CLOUD_URL could previously replace local tokens unverified). - Zed import: split into 2-step `/discover` + `/import` flow. `/import` now requires `confirmedAccounts: [{ service, account, fingerprint }]` and re-reads the keychain server-side to filter by fingerprint, so a tampered discover response cannot trick the endpoint into saving an unrelated token. Cosmetic Socket.dev mitigations: - runElevatedPowerShell writes the elevated payload to a per-call temp `.ps1` file (mode 0o600) and references it via `-File`. Removes the textbook `-EncodedCommand <base64utf16le>` pattern flagged as malware by Socket's AI classifier. - Maintainer attestation `SECURITY-AUDITOR-NOTE:` blocks added at every flagged call site pointing to `docs/security/SOCKET_DEV_FINDINGS.md`. Build-time hardening: - `OMNIROUTE_BUILD_PROFILE=minimal` (`npm run build:secure`) physically removes the four sensitive modules from the standalone bundle via webpack `NormalModuleReplacementPlugin`. Stubs throw `FeatureDisabledError` at runtime. Intended for the `omniroute-secure` artifact. Tests: - 24 new unit tests in `tests/unit/security/` covering the wrapper builder, HMAC verification (4 cases), credential fingerprint determinism (5 cases), confirmedAccounts validation + fingerprint filtering (6 cases), and the minimal-build stubs (5 cases). Docs: - New `docs/security/SOCKET_DEV_FINDINGS.md` — per-finding attestation. - New `socket.yml` — Socket.dev v2 config pointing at the attestation. - Updated `SECURITY.md` — supply-chain scanner section. - Updated `.env.example` — three new env vars documented. Backwards compatibility: - Cloud sync token overwrite is OFF by default. Users who relied on it must set `OMNIROUTE_CLOUD_SYNC_SECRETS=true`. Breaking change documented in CHANGELOG. - Zed import 2-step is the new default; legacy 1-step preserved behind `OMNIROUTE_ZED_IMPORT_LEGACY_ONE_STEP=true` and will be removed in v3.9. Closes #2863 * feat: implement automated skill workflows and update system configuration and validation schemas * test: eliminate dynamic cast warnings in cloud-sync unit test * test: isolate services-branch-hardening database directory to avoid concurrency issues * chore(docs): refresh generated docs collection index Update the generated Fumadocs browser collection mapping to keep documentation imports in sync with the current docs structure. * docs: update generated browser docs collection manifest Refresh the generated Fumadocs browser collection mapping so the docs site can resolve the current documentation files correctly. --------- Co-authored-by: OpenClaw <openclaw@kuzhomesrv.local> Co-authored-by: Dmitry Kuznetsov <139351986+dmitry@users.noreply.local> Co-authored-by: KuzyaBot <kuzya@local> Co-authored-by: JeferssonLemes <jeferssondev@gmail.com> Co-authored-by: Paijo <14921983+oyi77@users.noreply.github.com> Co-authored-by: Markus Hartung <mail@hartmark.se> Co-authored-by: akarray <akarray@users.noreply.github.com> Co-authored-by: Apostol Apostolov <theapoapostolov@gmail.com> Co-authored-by: Hernan Javier Ardila Sanchez <hjasgr@gmail.com> Co-authored-by: Dmitry Kuznetsov <dmitry@kuznetsov.me> Co-authored-by: Nikolay Alafuzov <alafuzov_nn@rusklimat.ru> Co-authored-by: oyi77 <oyi77@users.noreply.github.com> Co-authored-by: Ronaldo Davi <alltomatos@users.noreply.github.com> Co-authored-by: levonk <277861+levonk@users.noreply.github.com> Co-authored-by: Lenine Júnior <lenine@engrene.com.br> Co-authored-by: Annas Alghoffar <aag.annas@gmail.com> Co-authored-by: Tushar Agarwal <76201310+Tushar49@users.noreply.github.com> Co-authored-by: GreatLiu <eurasiaxz@qq.com> Co-authored-by: yuna amelia <230527278+yunaamelia@users.noreply.github.com> Co-authored-by: Randi <55005611+rdself@users.noreply.github.com> Co-authored-by: Container <78986709+disonjer@users.noreply.github.com> Co-authored-by: nickwizard <35692452+nickwizard@users.noreply.github.com> Co-authored-by: Rajvardhan Patil <rajvardhanpatil7890@gmail.com> Co-authored-by: Raxxoor <manker_lol@hotmail.com> Co-authored-by: Muhammad Mugni Hadi <mugnimaestra3@gmail.com> Co-authored-by: mi <123757457+soyelmismo@users.noreply.github.com> Co-authored-by: Automation <automation@omniroute>
32 KiB
CLAUDE.md (日本語)
🌐 Languages: 🇺🇸 English · 🇸🇦 ar · 🇦🇿 az · 🇧🇬 bg · 🇧🇩 bn · 🇨🇿 cs · 🇩🇰 da · 🇩🇪 de · 🇪🇸 es · 🇮🇷 fa · 🇫🇮 fi · 🇫🇷 fr · 🇮🇳 gu · 🇮🇱 he · 🇮🇳 hi · 🇭🇺 hu · 🇮🇩 id · 🇮🇩 in · 🇮🇹 it · 🇰🇷 ko · 🇮🇳 mr · 🇲🇾 ms · 🇳🇱 nl · 🇳🇴 no · 🇵🇭 phi · 🇵🇱 pl · 🇵🇹 pt · 🇧🇷 pt-BR · 🇷🇴 ro · 🇷🇺 ru · 🇸🇰 sk · 🇸🇪 sv · 🇰🇪 sw · 🇮🇳 ta · 🇮🇳 te · 🇹🇭 th · 🇹🇷 tr · 🇺🇦 uk-UA · 🇵🇰 ur · 🇻🇳 vi · 🇨🇳 zh-CN
このファイルは、このリポジトリ内のコード作業時にClaude Code (claude.ai/code) に対するガイダンスを提供します。
クイックスタート
npm install # 依存関係をインストール(.env.example から .env を自動生成)
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 # 厳密チェック(暗黙の any はなし)
npm run test:coverage # ユニットテスト + カバレッジゲート(75/75/75/70 — ステートメント/行/関数/ブランチ)
npm run check # lint + テストの組み合わせ
npm run check:cycles # 循環依存関係を検出
テストの実行
# 単一のテストファイル(Node.js ネイティブテストランナー — ほとんどのテスト)
node --import tsx/esm --test tests/unit/your-file.test.ts
# Vitest (MCP サーバー、自動コンボ、キャッシュ)
npm run test:vitest
# すべてのスイート
npm run test:all
完全なテストマトリックスについては、CONTRIBUTING.md → "テストの実行" を参照してください。深いアーキテクチャについては、AGENTS.md を参照してください。
プロジェクトの概要
OmniRoute — 統一されたAIプロキシ/ルーター。1つのエンドポイント、160以上のLLMプロバイダー、自動フォールバック。
| レイヤー | 場所 | 目的 |
|---|---|---|
| APIルート | src/app/api/v1/ |
Next.js アプリルーター — エントリーポイント |
| ハンドラー | open-sse/handlers/ |
リクエスト処理(チャット、埋め込みなど) |
| エグゼキューター | open-sse/executors/ |
プロバイダー固有のHTTPディスパッチ |
| トランスレーター | open-sse/translator/ |
フォーマット変換(OpenAI↔Claude↔Gemini) |
| トランスフォーマー | open-sse/transformer/ |
レスポンスAPI ↔ チャット完了 |
| サービス | open-sse/services/ |
コンボルーティング、レート制限、キャッシングなど |
| データベース | src/lib/db/ |
SQLite ドメインモジュール(45以上のファイル、55のマイグレーション) |
| ドメイン/ポリシー | src/domain/ |
ポリシーエンジン、コストルール、フォールバックロジック |
| MCPサーバー | open-sse/mcp-server/ |
37のツール(30のベース + 3のメモリ + 4のスキル)、3つのトランスポート、約13のスコープ |
| A2Aサーバー | src/lib/a2a/ |
JSON-RPC 2.0 エージェントプロトコル |
| スキル | src/lib/skills/ |
拡張可能なスキルフレームワーク |
| メモリ | src/lib/memory/ |
永続的な会話メモリ |
モノレポ: src/ (Next.js 16 アプリ)、open-sse/ (ストリーミングエンジンワークスペース)、electron/ (デスクトップアプリ)、tests/、bin/ (CLI エントリーポイント)。
リクエストパイプライン
Client → /v1/chat/completions (Next.js ルート)
→ CORS → Zod バリデーション → 認証? → ポリシーチェック → プロンプトインジェクションガード
→ handleChatCore() [open-sse/handlers/chatCore.ts]
→ キャッシュチェック → レート制限 → コンボルーティング?
→ resolveComboTargets() → handleSingleModel() 各ターゲットごと
→ translateRequest() → getExecutor() → executor.execute()
→ fetch() アップストリーム → リトライ w/ バックオフ
→ レスポンストランスレーション → SSE ストリームまたは JSON
→ If Responses API: responsesTransformer.ts TransformStream
API ルートは一貫したパターンに従います: ルート → CORS プレフライト → Zod ボディバリデーション → オプションの認証 (extractApiKey/isValidApiKey) → API キーポリシーの強制 → ハンドラーデリゲーション (open-sse)。グローバルな Next.js ミドルウェアはありません — インターセプションはルート固有です。
コンボルーティング (open-sse/services/combo.ts): 14 の戦略 (優先度、重み付け、フィルファースト、ラウンドロビン、P2C、ランダム、最少使用、コスト最適化、リセット認識、厳密ランダム、自動、lkgp、コンテキスト最適化、コンテキストリレー)。各ターゲットは handleSingleModel() を呼び出し、ターゲットごとのエラーハンドリングとサーキットブレーカーチェックで handleChatCore() をラップします。9要素の Auto-Combo スコアリングについては docs/routing/AUTO-COMBO.md を、3つのレジリエンスレイヤーについては docs/architecture/RESILIENCE_GUIDE.md を参照してください。
レジリエンスランタイム状態
OmniRoute には、関連性があるが異なる一時的な失敗メカニズムが3つあります。ルーティングの動作をデバッグする際には、それぞれのスコープを分けておくことが重要です。概要マップについては、3層レジリエンスダイアグラムを参照してください (出典: docs/diagrams/resilience-3layers.mmd)。
プロバイダーサーキットブレーカー
スコープ: 全体のプロバイダー、例: glm, openai, anthropic。
目的: 上流/サービスレベルで繰り返し失敗しているプロバイダーへのトラフィックを停止し、1つの不健康なプロバイダーがすべてのリクエストを遅くしないようにします。
実装:
- コアクラス:
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: プロバイダーが一時的にブロックされています; 呼び出し元はプロバイダーサーキットオープンのレスポンスを受け取るか、コンボルーティングが別のターゲットにスキップします。HALF_OPEN: リセットタイムアウトが経過しました; プローブリクエストを許可します。成功するとブレーカーが閉じ、失敗すると再びオープンになります。
デフォルト (open-sse/config/constants.ts):
- OAuth プロバイダー: 閾値
3, リセットタイムアウト60s。 - API キープロバイダー: 閾値
5, リセットタイムアウト30s。 - ローカルプロバイダー: 閾値
2, リセットタイムアウト15s。
プロバイダーのレベルでの失敗ステータスのみがプロバイダーブレーカーをトリップさせるべきです:
(408, 500, 502, 503, 504);
通常のアカウント/キー/モデルエラーのようなほとんどの 401, 403, または 429 ケースで全体のプロバイダーブレーカーをトリップさせないでください。これらは通常、接続クールダウンまたはモデルロックアウトに属します。一般的な API キープロバイダーの 403 は、ターミナルプロバイダー/アカウントエラーとして分類されない限り、回復可能であるべきです。
ブレーカーはレイジーリカバリーを使用し、バックグラウンドタイマーではありません。OPEN が期限切れになると、getStatus(), canExecute(), および getRetryAfterMs() などの読み取りが状態を HALF_OPEN に更新し、ダッシュボードやコンボ候補ビルダーが期限切れのプロバイダーを永遠に除外しないようにします。
接続クールダウン
スコープ: 1つのプロバイダー接続/アカウント/キー。
目的: 同じプロバイダーの他の接続がリクエストを処理し続けることを許可しながら、1つの不良キー/アカウントを一時的にスキップします。
実装:
- 書き込み/更新パス:
src/sse/services/auth.ts::markAccountUnavailable() - アカウント選択/フィルタリング:
src/sse/services/auth.ts::getProviderCredentials... - クールダウン計算:
open-sse/services/accountFallback.ts::checkFallbackError() - 設定:
src/lib/resilience/settings.ts
プロバイダー接続の重要なフィールド:
rateLimitedUntil;
testStatus: "unavailable";
lastError;
lastErrorType;
errorCode;
backoffLevel;
アカウント選択中、接続は次の条件でスキップされます:
new Date(rateLimitedUntil).getTime() > Date.now();
クールダウンもレイジーです: rateLimitedUntil が過去にある場合、接続は再び対象となります。成功した使用時に、clearAccountError() は testStatus, rateLimitedUntil, エラーフィールド、および backoffLevel をクリアします。
デフォルトの接続クールダウン動作:
- OAuth ベースのクールダウン:
5s。 - API キー ベースのクールダウン:
3s。 - API キー
429は、利用可能な場合、アップストリームリトライヒント (Retry-After, リセットヘッダー、または解析可能なリセットテキスト) を優先するべきです。 - 繰り返し回復可能な失敗は指数バックオフを使用します:
baseCooldownMs * 2 ** failureIndex;
アンチサンダリングハードガードは、同じ接続での同時失敗がクールダウンを繰り返し延長したり、backoffLevel を二重にインクリメントしたりするのを防ぎます。
ターミナル状態はクールダウンではありません。banned, expired, および credits_exhausted は、資格情報/設定が変更されるか、オペレーターがリセットするまで利用できない状態に留まることを意図しています。ターミナル状態を一時的なクールダウン状態で上書きしないでください。
モデルロックアウト
スコープ: プロバイダー + 接続 + モデル。
目的: 1つのモデルが利用できないまたはクォータ制限されている場合に、全体の接続を無効にしないようにします。
例:
- モデルごとのクォータプロバイダーが
429を返す。 - 1つの欠落したモデルに対して
404を返すローカルプロバイダー。 - 選択された Grok モードのようなプロバイダー固有のモード/モデルの権限失敗。
モデルロックアウトは open-sse/services/accountFallback.ts にあり、同じ接続が他のモデルを処理し続けることを許可します。
デバッグガイダンス
- プロバイダーのすべてのキーがスキップされている場合、プロバイダーブレーカーの状態と各接続の
rateLimitedUntil/testStatusを確認してください。 - リセットウィンドウ後にプロバイダーが永続的に除外されているように見える場合、コードが生の
stateを読み取っているのではなく、getStatus()/canExecute()を使用しているか確認してください。 - 1つのプロバイダーキーが失敗するが他は機能するはずの場合、プロバイダーブレーカーよりも接続クールダウンを優先してください。
- 1つのモデルのみが失敗する場合、接続クールダウンよりもモデルロックアウトを優先してください。
- 状態が自己回復するべき場合、将来のタイムスタンプ/リセットタイムアウトと期限切れの状態を更新する読み取りパスが必要です。永続的なステータスは手動の資格情報または設定変更を必要とします。
主要な規約
コードスタイル
- 2スペース、セミコロン、ダブルクォート、100文字幅、es5トレーリングカンマ(lint-stagedを介してPrettierによって強制)
- インポート: 外部 → 内部 (
@/,@omniroute/open-sse) → 相対 - 命名: ファイル=キャメルケース/ケバブケース、コンポーネント=パスカルケース、定数=UPPER_SNAKE
- ESLint:
no-eval、no-implied-eval、no-new-func= どこでもエラー;no-explicit-any=open-sse/とtests/で警告 - TypeScript:
strict: false、ターゲットES2022、モジュールesnext、解決バンドラー。明示的な型を優先。
データベース
- 常に
src/lib/db/ドメインモジュールを通過する — 決して ルートやハンドラーで生のSQLを書かない - 決して
src/lib/localDb.tsにロジックを追加しない(再エクスポートレイヤーのみ) - 決して
localDb.tsからバレルインポートしない — 代わりに特定のdb/モジュールをインポートする - DBシングルトン:
getDbInstance()fromsrc/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スタイルのOAuth client_id/secret + 公開CLIから抽出されたFirebase Webキー): 必ず
resolvePublicCred()を介してopen-sse/utils/publicCreds.tsに埋め込む — 決して 文字列リテラルとして。必須のパターンについてはdocs/security/PUBLIC_CREDS.mdを参照。 - エラー応答(HTTP / SSE / 実行者 / MCPハンドラー): 必ず
buildErrorBody()またはsanitizeErrorMessage()を介してルーティングするopen-sse/utils/error.ts— 決して 生のerr.stackまたはerr.messageをレスポンスボディに入れない。docs/security/ERROR_SANITIZATION.mdを参照。 - 変数から構築されたシェルコマンド:
exec()/spawn()を呼び出す際にランタイム値が必要なスクリプトを使用する場合、envオプションを介して渡す(自動的にシェルエスケープされる) — 決して 信頼できない/外部のパスをスクリプトボディに文字列補間しない。参照:src/mitm/cert/install.ts::updateNssDatabases。 - デフォルトで安全なライブラリ (tldrsec/awesome-secure-defaults): 新しいセキュリティに敏感な表面を追加する際には、カスタム実装よりもHelmet.js、DOMPurify、ssrf-req-filter、safe-regex、Google Tinkを優先する。
一般的な修正シナリオ
新しいプロバイダーの追加
src/shared/constants/providers.tsに登録する(ロード時にZodで検証)- カスタムロジックが必要な場合は
open-sse/executors/にエグゼキュータを追加する(BaseExecutorを拡張) - OpenAI以外の形式の場合は
open-sse/translator/に翻訳者を追加する - OAuthベースの場合は
src/lib/oauth/constants/oauth.tsにOAuth設定を追加する — アップストリームCLIが公開client_id/secretを出荷する場合は、resolvePublicCred()を介して埋め込む(docs/security/PUBLIC_CREDS.mdを参照)、決して リテラルとして open-sse/config/providerRegistry.tsにモデルを登録するtests/unit/にテストを書く(新しい埋め込みデフォルトを追加した場合はpublicCredsの形状アサーションを含める)
新しいAPIルートの追加
src/app/api/v1/your-route/の下にディレクトリを作成するGET/POSTハンドラーを持つroute.tsを作成する- パターンに従う: CORS → Zodボディ検証 → オプションの認証 → ハンドラーの委任
- ハンドラーは
open-sse/handlers/に配置する(そこからインポートし、インラインではない) - エラー応答は
buildErrorBody()/errorResponse()を使用するopen-sse/utils/error.ts(自動的にサニタイズされる — 生のerr.stackまたはerr.messageをボディに入れない)。docs/security/ERROR_SANITIZATION.mdを参照。 - テストを追加する — エラー応答がスタックトレースを漏らさないことを確認するアサーションを少なくとも1つ含める(
!body.error.message.includes("at /"))
新しいDBモジュールの追加
src/lib/db/yourModule.tsを作成する —./core.tsからgetDbInstanceをインポートする- ドメインテーブルのためのCRUD関数をエクスポートする
- 新しいテーブルが必要な場合は
src/lib/db/migrations/にマイグレーションを追加する src/lib/localDb.tsから再エクスポートする(再エクスポートリストにのみ追加)- テストを書く
新しいMCPツールの追加
- Zod入力スキーマ + 非同期ハンドラーを持つツール定義を
open-sse/mcp-server/tools/に追加する - ツールセットに登録する(
createMcpServer()によって配線される) - 適切なスコープに割り当てる
- テストを書く(ツールの呼び出しは
mcp_auditテーブルにログされる)
新しいA2Aスキルの追加
src/lib/a2a/skills/にスキルを作成する(すでに5つ存在: smart-routing, quota-management, provider-discovery, cost-analysis, health-report)- スキルはタスクコンテキスト(メッセージ、メタデータ)を受け取り → 構造化された結果を返す
src/lib/a2a/taskExecution.tsのA2A_SKILL_HANDLERSに登録するsrc/app/.well-known/agent.json/route.tsに公開する(エージェントカード)tests/unit/にテストを書くdocs/frameworks/A2A-SERVER.mdスキルテーブルに文書化する
新しいクラウドエージェントの追加
src/lib/cloudAgent/agents/にCloudAgentBaseを拡張したエージェントクラスを作成する(すでに3つ存在: codex-cloud, devin, jules)createTask、getStatus、approvePlan、sendMessage、listSourcesを実装するsrc/lib/cloudAgent/registry.tsに登録する- 必要に応じてOAuth/資格情報の処理を追加する(
src/lib/oauth/providers/) - テスト +
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 / クラウド) | 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ワークフロー
# mainに直接コミットしない
git checkout -b feat/your-feature
git commit -m "feat: あなたの変更を説明"
git push -u origin feat/your-feature
ブランチプレフィックス: feat/, fix/, refactor/, docs/, test/, chore/
コミットフォーマット (Conventional 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
環境
- ランタイム: Node.js ≥20.20.2 <21 || ≥22.22.2 <23 || ≥24 <25, ES Modules
- TypeScript: 5.9+, ターゲット ES2022, モジュール esnext, 解決バンドラー
- パスエイリアス:
@/*→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)
ハードルール
- 秘密や資格情報をコミットしない
localDb.tsにロジックを追加しないeval()/new Function()/ 暗黙のevalを使用しないmainに直接コミットしない- ルートで生のSQLを書かない —
src/lib/db/モジュールを使用する - SSEストリームでエラーを静かに飲み込まない
- 常にZodスキーマで入力を検証する
- プロダクションコードを変更する際は常にテストを含める
- カバレッジは常に ≥75% (ステートメント、行、関数) / ≥70% (ブランチ) を維持する必要があります。現在の測定値: ~82%。
- 明示的なオペレーターの承認なしにHuskyフックをバイパスしない (
--no-verify,--no-gpg-sign)。 - 公開の上流OAuth client_id/secretやFirebase Webキーを文字列リテラルとして埋め込まない — 常に
resolvePublicCred()を通過させる (open-sse/utils/publicCreds.ts)。参照:docs/security/PUBLIC_CREDS.md。 - HTTP / SSE / 実行者のレスポンスで生の
err.stack/err.messageを返さない — 常にbuildErrorBody()またはsanitizeErrorMessage()を通過させる (open-sse/utils/error.ts)。参照:docs/security/ERROR_SANITIZATION.md。 - 外部パスやランタイム値を
exec()/spawn()に渡されるシェルスクリプトに文字列補間しない — 代わりにenvオプションを通じて渡す。参照:src/mitm/cert/install.ts::updateNssDatabases。 - CodeQL / Secret-Scanning アラートを無視しない — (a) まず上記のパターンドキュメントを確認してヘルパーが適用されるかどうかを確認し、(b) 無視のコメントに技術的な正当化を記録する。前例:
js/stack-trace-exposureは、すでにsanitizeErrorMessage()を通過するコールサイトで発生する既知のCodeQLの制限(カスタムサニタイザーが認識されない) —false positiveとして無視し、docs/security/ERROR_SANITIZATION.mdを参照。 - 子プロセスを生成するルート(
/api/mcp/,/api/cli-tools/runtime/)をsrc/server/authz/routeGuard.tsでisLocalOnlyPath()分類なしに公開しない。ループバックの強制は、認証チェックの前に無条件に行われます — トンネルを介して漏洩したJWTはプロセスの生成をトリガーできません。参照:docs/security/ROUTE_GUARD_TIERS.md。 - AI アシスタント、LLM、または自動化アカウントを認める
Co-Authored-Byトレーラー (例: "Claude"、"GPT"、"Copilot"、"Bot" を含む名前;anthropic.com/openai.com/ ボット所有のnoreply.github.comアドレスのメール) を絶対にコミットメッセージに含めないでください。そのようなトレーラーは GitHub 上でボットアカウントにコミット帰属をルーティングし、PR 履歴で実際の作者 (diegosouzapw) を隠します。人間の協力者 — upstream PR の作者や OmniRoute に移植される issue 報告者を含む — は標準のCo-authored-by: Name <email>トレーラーで認められることが できる し、認められる べき です; upstream-port ワークフロー (/port-upstream-features、/port-upstream-issues) はこれに依存しています。