From 91b69835642cf1360d30f80ab6d32fe3f3d6f3cc Mon Sep 17 00:00:00 2001 From: Diego Rodrigues de Sa e Souza <8016841+diegosouzapw@users.noreply.github.com> Date: Thu, 21 May 2026 01:29:12 -0300 Subject: [PATCH] Release v3.8.1 (#2441) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Release v3.8.1 — feature flags settings page, bracketed combo names, security hardening, multi-driver SQLite --- .env.example | 10 +- .vscode/settings.json | 1 + .../opencode-provider/package-lock.json | 22 +- @omniroute/opencode-provider/package.json | 10 +- @omniroute/opencode-provider/tsup.config.ts | 2 +- CHANGELOG.md | 38 + CONTRIBUTING.md | 2 +- Dockerfile | 4 +- README.md | 2 +- bin/cli/encryption.mjs | 7 +- docs/README.md | 2 +- docs/architecture/ARCHITECTURE.md | 2 +- docs/architecture/AUTHZ_GUIDE.md | 2 +- docs/architecture/CODEBASE_DOCUMENTATION.md | 2 +- docs/architecture/REPOSITORY_MAP.md | 2 +- docs/architecture/RESILIENCE_GUIDE.md | 2 +- docs/comparison/OMNIROUTE_VS_ALTERNATIVES.md | 2 +- docs/compression/COMPRESSION_ENGINES.md | 2 +- docs/compression/COMPRESSION_GUIDE.md | 2 +- .../compression/COMPRESSION_LANGUAGE_PACKS.md | 2 +- docs/compression/COMPRESSION_RULES_FORMAT.md | 2 +- docs/compression/RTK_COMPRESSION.md | 2 +- docs/diagrams/README.md | 2 +- docs/frameworks/A2A-SERVER.md | 2 +- docs/frameworks/AGENT_PROTOCOLS_GUIDE.md | 2 +- docs/frameworks/CLOUD_AGENT.md | 2 +- docs/frameworks/EVALS.md | 2 +- docs/frameworks/GAMIFICATION.md | 2 +- docs/frameworks/MCP-SERVER.md | 2 +- docs/frameworks/MEMORY.md | 2 +- docs/frameworks/OPENCODE.md | 2 +- docs/frameworks/SKILLS.md | 2 +- docs/frameworks/WEBHOOKS.md | 2 +- docs/guides/DOCKER_GUIDE.md | 2 +- docs/guides/ELECTRON_GUIDE.md | 2 +- docs/guides/FEATURES.md | 2 +- docs/guides/I18N.md | 2 +- docs/guides/PWA_GUIDE.md | 2 +- docs/guides/SETUP_GUIDE.md | 2 +- docs/guides/TERMUX_GUIDE.md | 2 +- docs/guides/TROUBLESHOOTING.md | 2 +- docs/guides/UNINSTALL.md | 2 +- docs/guides/USER_GUIDE.md | 2 +- docs/i18n/ar/CHANGELOG.md | 20 + docs/i18n/ar/docs/reference/ENVIRONMENT.md | 8 +- docs/i18n/ar/llm.txt | 4 +- docs/i18n/az/CHANGELOG.md | 20 + docs/i18n/az/docs/reference/ENVIRONMENT.md | 8 +- docs/i18n/az/llm.txt | 4 +- docs/i18n/bg/CHANGELOG.md | 20 + docs/i18n/bg/docs/reference/ENVIRONMENT.md | 8 +- docs/i18n/bg/llm.txt | 4 +- docs/i18n/bn/CHANGELOG.md | 20 + docs/i18n/bn/docs/reference/ENVIRONMENT.md | 8 +- docs/i18n/bn/llm.txt | 4 +- docs/i18n/cs/CHANGELOG.md | 20 + docs/i18n/cs/docs/reference/ENVIRONMENT.md | 8 +- docs/i18n/cs/llm.txt | 4 +- docs/i18n/da/CHANGELOG.md | 20 + docs/i18n/da/docs/reference/ENVIRONMENT.md | 8 +- docs/i18n/da/llm.txt | 4 +- docs/i18n/de/CHANGELOG.md | 20 + docs/i18n/de/docs/reference/ENVIRONMENT.md | 8 +- docs/i18n/de/llm.txt | 4 +- docs/i18n/es/CHANGELOG.md | 20 + docs/i18n/es/docs/reference/ENVIRONMENT.md | 8 +- docs/i18n/es/llm.txt | 4 +- docs/i18n/fa/CHANGELOG.md | 20 + docs/i18n/fa/docs/reference/ENVIRONMENT.md | 8 +- docs/i18n/fa/llm.txt | 4 +- docs/i18n/fi/CHANGELOG.md | 20 + docs/i18n/fi/docs/reference/ENVIRONMENT.md | 8 +- docs/i18n/fi/llm.txt | 4 +- docs/i18n/fr/CHANGELOG.md | 20 + docs/i18n/fr/docs/reference/ENVIRONMENT.md | 8 +- docs/i18n/fr/llm.txt | 4 +- docs/i18n/gu/CHANGELOG.md | 20 + docs/i18n/gu/docs/reference/ENVIRONMENT.md | 8 +- docs/i18n/gu/llm.txt | 4 +- docs/i18n/he/CHANGELOG.md | 20 + docs/i18n/he/docs/reference/ENVIRONMENT.md | 8 +- docs/i18n/he/llm.txt | 4 +- docs/i18n/hi/CHANGELOG.md | 20 + docs/i18n/hi/docs/reference/ENVIRONMENT.md | 8 +- docs/i18n/hi/llm.txt | 4 +- docs/i18n/hu/CHANGELOG.md | 20 + docs/i18n/hu/docs/reference/ENVIRONMENT.md | 8 +- docs/i18n/hu/llm.txt | 4 +- docs/i18n/id/CHANGELOG.md | 20 + docs/i18n/id/docs/reference/ENVIRONMENT.md | 8 +- docs/i18n/id/llm.txt | 4 +- docs/i18n/in/CHANGELOG.md | 20 + docs/i18n/in/docs/reference/ENVIRONMENT.md | 8 +- docs/i18n/in/llm.txt | 4 +- docs/i18n/it/CHANGELOG.md | 20 + docs/i18n/it/docs/reference/ENVIRONMENT.md | 8 +- docs/i18n/it/llm.txt | 4 +- docs/i18n/ja/CHANGELOG.md | 20 + docs/i18n/ja/docs/reference/ENVIRONMENT.md | 8 +- docs/i18n/ja/llm.txt | 4 +- docs/i18n/ko/CHANGELOG.md | 20 + docs/i18n/ko/docs/reference/ENVIRONMENT.md | 8 +- docs/i18n/ko/llm.txt | 4 +- docs/i18n/mr/CHANGELOG.md | 20 + docs/i18n/mr/docs/reference/ENVIRONMENT.md | 8 +- docs/i18n/mr/llm.txt | 4 +- docs/i18n/ms/CHANGELOG.md | 20 + docs/i18n/ms/docs/reference/ENVIRONMENT.md | 8 +- docs/i18n/ms/llm.txt | 4 +- docs/i18n/nl/CHANGELOG.md | 20 + docs/i18n/nl/docs/reference/ENVIRONMENT.md | 8 +- docs/i18n/nl/llm.txt | 4 +- docs/i18n/no/CHANGELOG.md | 20 + docs/i18n/no/docs/reference/ENVIRONMENT.md | 8 +- docs/i18n/no/llm.txt | 4 +- docs/i18n/phi/CHANGELOG.md | 20 + docs/i18n/phi/docs/reference/ENVIRONMENT.md | 8 +- docs/i18n/phi/llm.txt | 4 +- docs/i18n/pl/CHANGELOG.md | 20 + docs/i18n/pl/docs/reference/ENVIRONMENT.md | 8 +- docs/i18n/pl/llm.txt | 4 +- docs/i18n/pt-BR/CHANGELOG.md | 20 + docs/i18n/pt-BR/docs/reference/ENVIRONMENT.md | 8 +- docs/i18n/pt-BR/llm.txt | 4 +- docs/i18n/pt/CHANGELOG.md | 20 + docs/i18n/pt/docs/reference/ENVIRONMENT.md | 8 +- docs/i18n/pt/llm.txt | 4 +- docs/i18n/ro/CHANGELOG.md | 20 + docs/i18n/ro/docs/reference/ENVIRONMENT.md | 8 +- docs/i18n/ro/llm.txt | 4 +- docs/i18n/ru/CHANGELOG.md | 20 + docs/i18n/ru/docs/reference/ENVIRONMENT.md | 8 +- docs/i18n/ru/llm.txt | 4 +- docs/i18n/sk/CHANGELOG.md | 20 + docs/i18n/sk/docs/reference/ENVIRONMENT.md | 8 +- docs/i18n/sk/llm.txt | 4 +- docs/i18n/sv/CHANGELOG.md | 20 + docs/i18n/sv/docs/reference/ENVIRONMENT.md | 8 +- docs/i18n/sv/llm.txt | 4 +- docs/i18n/sw/CHANGELOG.md | 20 + docs/i18n/sw/docs/reference/ENVIRONMENT.md | 8 +- docs/i18n/sw/llm.txt | 4 +- docs/i18n/ta/CHANGELOG.md | 20 + docs/i18n/ta/docs/reference/ENVIRONMENT.md | 8 +- docs/i18n/ta/llm.txt | 4 +- docs/i18n/te/CHANGELOG.md | 20 + docs/i18n/te/docs/reference/ENVIRONMENT.md | 8 +- docs/i18n/te/llm.txt | 4 +- docs/i18n/th/CHANGELOG.md | 20 + docs/i18n/th/docs/reference/ENVIRONMENT.md | 8 +- docs/i18n/th/llm.txt | 4 +- docs/i18n/tr/CHANGELOG.md | 20 + docs/i18n/tr/docs/reference/ENVIRONMENT.md | 8 +- docs/i18n/tr/llm.txt | 4 +- docs/i18n/uk-UA/CHANGELOG.md | 20 + docs/i18n/uk-UA/docs/reference/ENVIRONMENT.md | 8 +- docs/i18n/uk-UA/llm.txt | 4 +- docs/i18n/ur/CHANGELOG.md | 20 + docs/i18n/ur/docs/reference/ENVIRONMENT.md | 8 +- docs/i18n/ur/llm.txt | 4 +- docs/i18n/vi/CHANGELOG.md | 20 + docs/i18n/vi/docs/reference/ENVIRONMENT.md | 8 +- docs/i18n/vi/llm.txt | 4 +- docs/i18n/zh-CN/CHANGELOG.md | 20 + docs/i18n/zh-CN/docs/reference/ENVIRONMENT.md | 8 +- docs/i18n/zh-CN/llm.txt | 4 +- docs/marketing/TIERS.md | 2 +- docs/ops/COVERAGE_PLAN.md | 2 +- docs/ops/FLY_IO_DEPLOYMENT_GUIDE.md | 2 +- docs/ops/PROXY_GUIDE.md | 2 +- docs/ops/RELEASE_CHECKLIST.md | 2 +- docs/ops/TUNNELS_GUIDE.md | 2 +- docs/ops/VM_DEPLOYMENT_GUIDE.md | 2 +- docs/reference/API_REFERENCE.md | 2 +- docs/reference/CLI-TOOLS.md | 2 +- docs/reference/ENVIRONMENT.md | 8 +- docs/reference/FREE_TIERS.md | 8 +- docs/reference/PROVIDER_REFERENCE.md | 2 +- docs/reference/openapi.yaml | 2 +- docs/routing/AUTO-COMBO.md | 2 +- docs/routing/REASONING_REPLAY.md | 2 +- docs/security/COMPLIANCE.md | 2 +- docs/security/ERROR_SANITIZATION.md | 2 +- docs/security/GUARDRAILS.md | 2 +- docs/security/PUBLIC_CREDS.md | 2 +- docs/security/STEALTH_GUIDE.md | 8 +- electron/package-lock.json | 340 ++++++- electron/package.json | 12 +- llm.txt | 4 +- next.config.mjs | 2 + open-sse/config/antigravityModelAliases.ts | 137 ++- open-sse/config/antigravityUpstream.ts | 2 +- open-sse/config/cliFingerprints.ts | 11 +- open-sse/config/codexClient.ts | 2 +- open-sse/config/providerRegistry.ts | 34 + open-sse/executors/antigravity.ts | 53 +- .../deepseek-web-with-auto-refresh.ts | 54 +- open-sse/executors/deepseek-web.ts | 366 ++++--- open-sse/handlers/chatCore.ts | 33 +- open-sse/handlers/imageGeneration.ts | 32 +- open-sse/lib/deepseek-pow.ts | 159 ++- open-sse/lib/sha3_wasm_bg.wasm | Bin 0 -> 26612 bytes open-sse/package.json | 2 +- open-sse/services/antigravityClientProfile.ts | 167 ++++ open-sse/services/antigravityHeaders.ts | 77 +- open-sse/services/antigravityIdentity.ts | 45 +- .../services/antigravityProjectBootstrap.ts | 41 +- open-sse/services/antigravityVersion.ts | 3 +- .../services/geminiThoughtSignatureStore.ts | 168 +++- open-sse/services/usage.ts | 69 +- open-sse/translator/index.ts | 9 +- .../translator/request/openai-to-claude.ts | 10 +- .../translator/request/openai-to-gemini.ts | 82 +- open-sse/translator/request/openai-to-kiro.ts | 54 +- .../translator/response/gemini-to-openai.ts | 151 +-- open-sse/utils/stream.ts | 5 +- open-sse/utils/streamHandler.ts | 111 ++- package-lock.json | 187 ++-- package.json | 28 +- package/package.json | 24 +- scripts/i18n/extract-keys-from-diff.mjs | 13 +- src/app/(dashboard)/dashboard/combos/page.tsx | 4 +- .../dashboard/providers/[id]/page.tsx | 104 +- .../dashboard/settings/ai/page.tsx | 4 + .../settings/components/ClaudeFastModeTab.tsx | 166 ++++ .../settings/components/CodexFastTierTab.tsx | 204 ++++ .../settings/components/FeatureFlagCard.tsx | 178 ++++ .../settings/components/FeatureFlagsGrid.tsx | 307 ++++++ .../dashboard/settings/feature-flags/page.tsx | 7 + src/app/api/oauth/cursor/auto-import/route.ts | 11 +- src/app/api/providers/[id]/models/route.ts | 16 +- src/app/api/settings/feature-flags/route.ts | 176 ++++ src/app/docs/[slug]/page.tsx | 10 +- src/app/docs/components/MermaidDiagram.tsx | 5 +- src/domain/assessment/migration.ts | 8 +- src/i18n/messages/ar.json | 819 ++++++++++++++- src/i18n/messages/az.json | 929 +++++++++++++++++- src/i18n/messages/bg.json | 819 ++++++++++++++- src/i18n/messages/bn.json | 819 ++++++++++++++- src/i18n/messages/cs.json | 819 ++++++++++++++- src/i18n/messages/da.json | 819 ++++++++++++++- src/i18n/messages/de.json | 819 ++++++++++++++- src/i18n/messages/en.json | 37 +- src/i18n/messages/es.json | 819 ++++++++++++++- src/i18n/messages/fa.json | 819 ++++++++++++++- src/i18n/messages/fi.json | 819 ++++++++++++++- src/i18n/messages/fr.json | 819 ++++++++++++++- src/i18n/messages/gu.json | 819 ++++++++++++++- src/i18n/messages/he.json | 819 ++++++++++++++- src/i18n/messages/hi.json | 819 ++++++++++++++- src/i18n/messages/hu.json | 819 ++++++++++++++- src/i18n/messages/id.json | 819 ++++++++++++++- src/i18n/messages/in.json | 819 ++++++++++++++- src/i18n/messages/it.json | 819 ++++++++++++++- src/i18n/messages/ja.json | 819 ++++++++++++++- src/i18n/messages/ko.json | 819 ++++++++++++++- src/i18n/messages/mr.json | 819 ++++++++++++++- src/i18n/messages/ms.json | 819 ++++++++++++++- src/i18n/messages/nl.json | 819 ++++++++++++++- src/i18n/messages/no.json | 819 ++++++++++++++- src/i18n/messages/phi.json | 819 ++++++++++++++- src/i18n/messages/pl.json | 819 ++++++++++++++- src/i18n/messages/pt-BR.json | 817 ++++++++++++++- src/i18n/messages/pt.json | 822 +++++++++++++++- src/i18n/messages/ro.json | 819 ++++++++++++++- src/i18n/messages/ru.json | 819 ++++++++++++++- src/i18n/messages/sk.json | 819 ++++++++++++++- src/i18n/messages/sv.json | 819 ++++++++++++++- src/i18n/messages/sw.json | 819 ++++++++++++++- src/i18n/messages/ta.json | 819 ++++++++++++++- src/i18n/messages/te.json | 819 ++++++++++++++- src/i18n/messages/th.json | 819 ++++++++++++++- src/i18n/messages/tr.json | 819 ++++++++++++++- src/i18n/messages/uk-UA.json | 819 ++++++++++++++- src/i18n/messages/ur.json | 819 ++++++++++++++- src/i18n/messages/vi.json | 819 ++++++++++++++- src/i18n/messages/zh-CN.json | 802 ++++++++++++++- src/instrumentation-node.ts | 2 + src/lib/cloudAgent/agents/jules.ts | 316 ++++-- src/lib/cloudAgent/julesApi.ts | 7 + src/lib/compliance/index.ts | 7 +- src/lib/db/adapters/betterSqliteAdapter.ts | 58 ++ src/lib/db/adapters/driverFactory.ts | 204 ++++ src/lib/db/adapters/nodeSqliteAdapter.ts | 170 ++++ src/lib/db/adapters/sqljsAdapter.ts | 199 ++++ src/lib/db/adapters/types.ts | 34 + src/lib/db/backup.ts | 33 +- src/lib/db/core.ts | 85 +- src/lib/db/encryption.ts | 15 +- src/lib/db/featureFlags.ts | 76 ++ src/lib/db/healthCheck.ts | 3 +- src/lib/db/jsonMigration.ts | 4 +- src/lib/db/migrationRunner.ts | 44 +- src/lib/db/settings.ts | 1 + src/lib/db/stats.ts | 2 +- src/lib/localDb.ts | 2 + .../memory/__tests__/qdrant-wiring.test.ts | 77 ++ src/lib/memory/store.ts | 37 + src/lib/oauth/constants/oauth.ts | 19 +- src/lib/oauth/providers/antigravity.ts | 54 +- src/lib/oauth/services/antigravity.ts | 73 +- src/lib/providers/catalog.ts | 1 + src/lib/providers/claudeFastMode.ts | 70 ++ src/lib/providers/codexFastTier.ts | 132 ++- src/lib/providers/validation.ts | 83 ++ src/lib/usage/fetcher.ts | 32 +- src/server/authz/policies/clientApi.ts | 13 +- .../constants/antigravityClientProfile.ts | 29 + .../constants/featureFlagDefinitions.ts | 303 ++++++ src/shared/constants/providers.ts | 3 +- src/shared/constants/sidebarVisibility.ts | 8 + src/shared/utils/featureFlags.ts | 54 +- src/shared/validation/schemas.ts | 24 + src/shared/validation/settingsSchemas.ts | 25 +- tests/integration/chat-pipeline.test.ts | 2 +- tests/unit/antigravity-client-profile.test.ts | 143 +++ .../antigravity-discovery-bootstrap.test.ts | 44 +- tests/unit/antigravity-model-aliases.test.ts | 82 +- .../authz/client-api-policy-fallback.test.ts | 44 + tests/unit/authz/client-api-policy.test.ts | 14 + tests/unit/autocombo-unification.test.ts | 11 +- tests/unit/bootstrap-env.test.ts | 4 +- tests/unit/cli-tools.test.ts | 4 +- .../db-adapters/betterSqliteAdapter.test.ts | 81 ++ tests/unit/db-adapters/driverFactory.test.ts | 115 +++ tests/unit/db-adapters/sqljsAdapter.test.ts | 92 ++ tests/unit/db-encryption.test.ts | 15 + tests/unit/deepseek-web.test.ts | 538 ++++------ tests/unit/docs-site-overhaul.test.ts | 47 + tests/unit/executor-antigravity.test.ts | 2 +- tests/unit/executor-codex.test.ts | 10 +- tests/unit/feature-flags-settings.test.ts | 294 ++++++ tests/unit/image-generation-handler.test.ts | 27 +- tests/unit/oauth-providers-config.test.ts | 20 +- tests/unit/provider-header-profiles.test.ts | 2 +- tests/unit/provider-models-route.test.ts | 9 +- tests/unit/providers-page-utils.test.ts | 3 + .../providers-route-managed-catalog.test.ts | 8 + tests/unit/services-branch-hardening.test.ts | 8 +- tests/unit/signature-cache-bypass.test.ts | 32 + tests/unit/stream-handler.test.ts | 65 +- tests/unit/sync-env.test.ts | 8 +- tests/unit/t20-t22-provider-headers.test.ts | 7 +- .../unit/translator-openai-to-claude.test.ts | 29 + .../unit/translator-openai-to-gemini.test.ts | 69 ++ tests/unit/translator-openai-to-kiro.test.ts | 282 ++++++ tests/unit/usage-service-hardening.test.ts | 17 +- 347 files changed, 40139 insertions(+), 3219 deletions(-) create mode 100644 open-sse/lib/sha3_wasm_bg.wasm create mode 100644 open-sse/services/antigravityClientProfile.ts create mode 100644 src/app/(dashboard)/dashboard/settings/components/ClaudeFastModeTab.tsx create mode 100644 src/app/(dashboard)/dashboard/settings/components/CodexFastTierTab.tsx create mode 100644 src/app/(dashboard)/dashboard/settings/components/FeatureFlagCard.tsx create mode 100644 src/app/(dashboard)/dashboard/settings/components/FeatureFlagsGrid.tsx create mode 100644 src/app/(dashboard)/dashboard/settings/feature-flags/page.tsx create mode 100644 src/app/api/settings/feature-flags/route.ts create mode 100644 src/lib/cloudAgent/julesApi.ts create mode 100644 src/lib/db/adapters/betterSqliteAdapter.ts create mode 100644 src/lib/db/adapters/driverFactory.ts create mode 100644 src/lib/db/adapters/nodeSqliteAdapter.ts create mode 100644 src/lib/db/adapters/sqljsAdapter.ts create mode 100644 src/lib/db/adapters/types.ts create mode 100644 src/lib/db/featureFlags.ts create mode 100644 src/lib/memory/__tests__/qdrant-wiring.test.ts create mode 100644 src/lib/providers/claudeFastMode.ts create mode 100644 src/shared/constants/antigravityClientProfile.ts create mode 100644 src/shared/constants/featureFlagDefinitions.ts create mode 100644 tests/unit/antigravity-client-profile.test.ts create mode 100644 tests/unit/db-adapters/betterSqliteAdapter.test.ts create mode 100644 tests/unit/db-adapters/driverFactory.test.ts create mode 100644 tests/unit/db-adapters/sqljsAdapter.test.ts create mode 100644 tests/unit/feature-flags-settings.test.ts diff --git a/.env.example b/.env.example index bd83328d19..1bda4388c7 100644 --- a/.env.example +++ b/.env.example @@ -600,19 +600,19 @@ GITHUB_OAUTH_CLIENT_ID=Iv1.b507a08c87ecfe98 # Used by: open-sse/executors/base.ts — buildHeaders() dynamic lookup. # Update these when providers release new CLI versions to avoid blocks. -CLAUDE_USER_AGENT="claude-cli/2.1.143 (external, cli)" -CODEX_USER_AGENT="codex-cli/0.131.0 (Windows 10.0.26200; x64)" +CLAUDE_USER_AGENT="claude-cli/2.1.145 (external, cli)" +CODEX_USER_AGENT="codex-cli/0.132.0 (Windows 10.0.26200; x64)" GITHUB_USER_AGENT="GitHubCopilotChat/0.45.1" -ANTIGRAVITY_USER_AGENT="antigravity/1.23.2 darwin/arm64" +ANTIGRAVITY_USER_AGENT="antigravity/2.0.1 linux/arm64 google-api-nodejs-client/10.3.0" KIRO_USER_AGENT="AWS-SDK-JS/3.0.0 kiro-ide/1.0.0" QODER_USER_AGENT="Qoder-Cli" -QWEN_USER_AGENT="QwenCode/0.15.9 (linux; x64)" +QWEN_USER_AGENT="QwenCode/0.15.11 (linux; x64)" CURSOR_USER_AGENT="Cursor/3.4" GEMINI_CLI_USER_AGENT="google-api-nodejs-client/10.3.0" # Override Codex client version sent in headers independently of the # CODEX_USER_AGENT string. Used by: open-sse/config/codexClient.ts. -# CODEX_CLIENT_VERSION=0.131.0 +# CODEX_CLIENT_VERSION=0.132.0 # ═══════════════════════════════════════════════════════════════════════════════ diff --git a/.vscode/settings.json b/.vscode/settings.json index 442a2bedab..b5113dde4d 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,4 +1,5 @@ { + "workbench.sideBar.location": "left", "css.lint.unknownAtRules": "ignore", "sonarlint.rules": { "css:S4662": { diff --git a/@omniroute/opencode-provider/package-lock.json b/@omniroute/opencode-provider/package-lock.json index ad01c86c67..8ff67447a2 100644 --- a/@omniroute/opencode-provider/package-lock.json +++ b/@omniroute/opencode-provider/package-lock.json @@ -9,13 +9,13 @@ "version": "0.1.0", "license": "MIT", "devDependencies": { - "@types/node": "^20.19.41", - "tsup": "^8.5.0", - "tsx": "^4.20.0", - "typescript": "^5.9.0" + "@types/node": "^22.19.19", + "tsup": "^8.5.1", + "tsx": "^4.22.3", + "typescript": "^5.9.3" }, "engines": { - "node": ">=20.20.2" + "node": ">=22.22.3" } }, "node_modules/@esbuild/aix-ppc64": { @@ -857,9 +857,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "20.19.41", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.41.tgz", - "integrity": "sha512-ECymXOukMnOoVkC2bb1Vc/w/836DXncOg5m8Xj1RH7xSHZJWNYY6Zh7EH477vcnD5egKNNfy2RpNOmuChhFPgQ==", + "version": "22.19.19", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.19.tgz", + "integrity": "sha512-dyh/xO2Fh5bYrfWaaqGrRQQGkNdmYw6AmaAUvYeUMNTWQtvb796ikLdmTchRmOlOiIJ1TDXfWgVx1QkUlQ6Hew==", "dev": true, "license": "MIT", "dependencies": { @@ -1464,9 +1464,9 @@ } }, "node_modules/tsx": { - "version": "4.22.0", - "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.22.0.tgz", - "integrity": "sha512-8ccZMPD69s1AbKXx0C5ddTNZfNjwV04iIKgjZmKfKxMynEtSYcK0Lh7iQFh53fI5Yu4pb9usgAiqyPmEONaALg==", + "version": "4.22.3", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.22.3.tgz", + "integrity": "sha512-mdoNxBC/cSQObGGVQ5Bpn5i+yv7j68gk3Nfm3wFjcJg3Z0Mix9jzAFfP12prmm5eVGmDKtp0yyArrs0Q+8gZHg==", "dev": true, "license": "MIT", "dependencies": { diff --git a/@omniroute/opencode-provider/package.json b/@omniroute/opencode-provider/package.json index baec64fbf7..62aafc4b5a 100644 --- a/@omniroute/opencode-provider/package.json +++ b/@omniroute/opencode-provider/package.json @@ -46,15 +46,15 @@ }, "homepage": "https://github.com/diegosouzapw/OmniRoute/tree/main/%40omniroute/opencode-provider#readme", "engines": { - "node": ">=20.20.2" + "node": ">=22.22.3" }, "publishConfig": { "access": "public" }, "devDependencies": { - "@types/node": "^20.19.41", - "tsup": "^8.5.0", - "tsx": "^4.20.0", - "typescript": "^5.9.0" + "@types/node": "^22.19.19", + "tsup": "^8.5.1", + "tsx": "^4.22.3", + "typescript": "^5.9.3" } } diff --git a/@omniroute/opencode-provider/tsup.config.ts b/@omniroute/opencode-provider/tsup.config.ts index 20c4ad1b59..95f9a77feb 100644 --- a/@omniroute/opencode-provider/tsup.config.ts +++ b/@omniroute/opencode-provider/tsup.config.ts @@ -8,7 +8,7 @@ export default defineConfig({ sourcemap: false, splitting: false, treeshake: true, - target: "node20", + target: "node22", outDir: "dist", minify: false, }); diff --git a/CHANGELOG.md b/CHANGELOG.md index b3ee711ba3..1631eb2abf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,44 @@ --- +## [3.8.1] — 2026-05-21 + +### ✨ New Features + +- **feat(settings):** Feature Flags Settings Page (Card Grid + DB overrides) — fully implements the feature flags UI dashboard using Variant A (Card Grid) with Glassmorphism, complete with global `GET/PUT/DELETE` API routes, Zod validation, debounced search, category filters, and full 30+ locale i18n support. Resolves priority hierarchy to DB > ENV > Defaults. ([#2457](https://github.com/diegosouzapw/OmniRoute/pull/2457)) +- **feat(db):** multi-driver SQLite abstraction layer — new `SqliteAdapter` interface with 3 concrete adapters (`betterSqliteAdapter`, `nodeSqliteAdapter`, `sqljsAdapter`) and a `driverFactory` that cascades `better-sqlite3` → `node:sqlite` → `sql.js (WASM)`. Enables OmniRoute to run on any JavaScript runtime (Node.js, Bun, Deno, Cloudflare Workers) without native binary dependencies. `better-sqlite3` moved to `optionalDependencies`. ([#2447](https://github.com/diegosouzapw/OmniRoute/pull/2447)) +- **feat(settings):** Claude Fast Mode toggle in Settings › AI — opt-in toggle that forwards `X-CPA-Force-Fast-Mode` header so a paired CLIProxyAPI build can reach Anthropic Fast Mode (`speed:"fast"`). Model-gated to Opus models matching Anthropic's binary KT() check. ([#2449](https://github.com/diegosouzapw/OmniRoute/pull/2449) — thanks @NomenAK) +- **feat(settings):** Codex Fast Tier — tier dropdown (`default`/`priority`/`flex`) + per-model gate preventing 400 errors from OpenAI when the tier toggle was on for non-Fast-eligible models. ([#2451](https://github.com/diegosouzapw/OmniRoute/pull/2451) — thanks @NomenAK) +- **feat:** align Antigravity 2.0.1 support — updated client profile, upstream headers, and model aliases. ([#2443](https://github.com/diegosouzapw/OmniRoute/pull/2443) — thanks @dhaern) +- **feat:** enhance `extractBearer` to support `x-api-key` for Anthropic API style auth. ([#2436](https://github.com/diegosouzapw/OmniRoute/pull/2436) — thanks @thedtvn) +- **feat(memory):** wire `createMemory` to `upsertSemanticMemoryPoint` (Qdrant). ([#2439](https://github.com/diegosouzapw/OmniRoute/pull/2439) — thanks @NomenAK) + +### 🔧 Bug Fixes & Refactors + +- **fix(deepseek-web):** rewrite auth to userToken Bearer + WASM PoW solver. ([#2452](https://github.com/diegosouzapw/OmniRoute/pull/2452) — thanks @ovehbe) +- **chore:** update node dependencies and runtime support. ([#2453](https://github.com/diegosouzapw/OmniRoute/pull/2453) — thanks @backryun) +- **fix(translator):** fix 3 Kiro `tool_result` defects causing 400 on follow-up turns — missing `tool_use_id` mapping, orphan result blocks, and conversation ID collision on assistant-first turns. ([#2447](https://github.com/diegosouzapw/OmniRoute/pull/2447)) +- **fix(translator):** treat `developer` role as system in OpenAI → Claude translation — `openAIToClaude` now extracts `developer`-role messages into `systemParts` (same as `system`) and filters them from the non-system message list, preventing identity context injected via the Responses API `developer` role from silently becoming an assistant turn when routing to a Claude-format provider. ([#2407](https://github.com/diegosouzapw/OmniRoute/issues/2407)) +- **fix(antigravity):** deduplicate `removeHeaderCaseInsensitive` — export canonical implementation from `antigravityClientProfile.ts` and remove the local copy in `antigravity.ts`; export `AntigravityCredentialsLike` type for cross-module use. (#2433 — thanks @Gi99lin) +- **refactor(docs):** enhance frontmatter handling in DocPage — gray-matter Date object parsing bug fix. ([#2448](https://github.com/diegosouzapw/OmniRoute/pull/2448) — thanks @ovehbe) +- **fix(jules):** Jules API parity and cloud-agent provider registration. ([#2438](https://github.com/diegosouzapw/OmniRoute/pull/2438)) +- **fix(i18n):** harden diff key extraction tag sanitization in `extract-keys-from-diff.mjs`. +- **chore(i18n):** refresh fr/es/de locales + add missing `settings.update` key. ([#2437](https://github.com/diegosouzapw/OmniRoute/pull/2437)) +- **fix(dashboard):** allow bracketed combo names — align dashboard combo-name validator regex with the shared/server schema updated in PR #2354; names like `Claude [1m]` are now accepted in the create/edit form. ([#2458](https://github.com/diegosouzapw/OmniRoute/pull/2458) — thanks @congvc-dev) + +### 🔒 Security Fixes + +- **fix(security):** replace `execSync` string-template with `spawnSync` arg-array in `plugin.mjs` — eliminates shell command injection via malicious plugin names. +- **fix(security):** gate Electron CSP `unsafe-eval` on `!app.isPackaged` instead of URL substring match — was leaking `unsafe-eval` into production builds; merged duplicate `connect-src` directives. +- **fix(api):** add `requireManagementAuth` to `/api/usage/budget/bulk` and `/api/resilience/reset` — both endpoints exposed spend data and circuit-breaker controls without auth. +- **fix(security):** route catch-block error messages through `sanitizeErrorMessage()` in `gemini-web`, `claude-web`, `copilot-web` executors, `oauth` route, and cloud-agent task routes — prevents stack traces and internal paths leaking into HTTP responses. +- **fix(codex):** `refreshCredentials` returns `null` (not error-object) on token refresh failure — prevents base executor from spreading `{error}` onto active credentials. +- **fix(tokenRefresh):** safe `unknown`-error access in `catch` block (`error instanceof Error ? error.message : String(error)`). +- **fix(combo):** reset `exhaustedProviders` set at start of each set-retry iteration — providers excluded in a failing pass now get a second chance on retry. +- **fix(circuitBreaker):** persist and restore `lastFailureKind` via the `options` JSON column — kind-based cooldown overrides (`cooldownByKind`) now survive server restarts. + +--- + ## [3.8.0] — 2026-05-06 ### 🚀 Post-release hotfixes e contribuições (2026-05-06 → 2026-05-20) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index aa20f27f18..f125ea29da 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -8,7 +8,7 @@ Thank you for your interest in contributing! This guide covers everything you ne ### Prerequisites -- **Node.js** `>=20.20.2 <21`, `>=22.22.2 <23`, or `>=24.0.0 <25` (recommended: 24 LTS) +- **Node.js** `>=22.22.3 <23`, or `>=24.0.0 <27` (recommended: 24 LTS) - **npm** 10+ - **Git** diff --git a/Dockerfile b/Dockerfile index bf41ee8585..1d589820a0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM node:26.1.0-trixie-slim AS builder +FROM node:26.2.0-trixie-slim AS builder WORKDIR /app RUN apt-get update \ @@ -19,7 +19,7 @@ RUN if [ -f package-lock.json ]; then \ COPY . ./ RUN mkdir -p /app/data && npm run build -- --webpack -FROM node:26.1.0-trixie-slim AS runner-base +FROM node:26.2.0-trixie-slim AS runner-base WORKDIR /app LABEL org.opencontainers.image.title="omniroute" \ diff --git a/README.md b/README.md index f5e07bc567..9f51b304f8 100644 --- a/README.md +++ b/README.md @@ -1672,7 +1672,7 @@ MIT License - see [LICENSE](LICENSE) for details. **[⬆ Back to top](#-omniroute)** · Built with ❤️ for the open-source AI community. -OmniRoute v3.8.0 · Node ≥22.22.2 · MIT License · omniroute.online +OmniRoute v3.8.1 · Node ≥22.22.2 · MIT License · omniroute.online diff --git a/bin/cli/encryption.mjs b/bin/cli/encryption.mjs index 3011941232..007b7091f2 100644 --- a/bin/cli/encryption.mjs +++ b/bin/cli/encryption.mjs @@ -3,6 +3,9 @@ import { createCipheriv, createDecipheriv, randomBytes, scryptSync } from "node: const ALGORITHM = "aes-256-gcm"; const IV_LENGTH = 16; const KEY_LENGTH = 32; +// Full 16-byte GCM tag produced by cipher.getAuthTag(). Pinning authTagLength on +// decrypt rejects truncated tags, closing the GCM tag-truncation forgery vector. +const AUTH_TAG_LENGTH = 16; const PREFIX = "enc:v1:"; // Keep this salt in sync with the app-side field encryption format so credentials written by // CLI setup remain decryptable by the dashboard/server and vice versa. @@ -53,7 +56,9 @@ export function decryptCredential(value) { } const [ivHex, encryptedHex, authTagHex] = parts; - const decipher = createDecipheriv(ALGORITHM, key, Buffer.from(ivHex, "hex")); + const decipher = createDecipheriv(ALGORITHM, key, Buffer.from(ivHex, "hex"), { + authTagLength: AUTH_TAG_LENGTH, + }); decipher.setAuthTag(Buffer.from(authTagHex, "hex")); let decrypted = decipher.update(encryptedHex, "hex", "utf8"); diff --git a/docs/README.md b/docs/README.md index 61171a841c..5af6775e3d 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,6 +1,6 @@ --- title: "OmniRoute Documentation" -version: 3.8.0 +version: 3.8.1 lastUpdated: 2026-05-13 --- diff --git a/docs/architecture/ARCHITECTURE.md b/docs/architecture/ARCHITECTURE.md index 50fe7c681e..6dc9b6ce21 100644 --- a/docs/architecture/ARCHITECTURE.md +++ b/docs/architecture/ARCHITECTURE.md @@ -1,6 +1,6 @@ --- title: "OmniRoute Architecture" -version: 3.8.0 +version: 3.8.1 lastUpdated: 2026-05-13 --- diff --git a/docs/architecture/AUTHZ_GUIDE.md b/docs/architecture/AUTHZ_GUIDE.md index 588364948e..533e3509fa 100644 --- a/docs/architecture/AUTHZ_GUIDE.md +++ b/docs/architecture/AUTHZ_GUIDE.md @@ -1,6 +1,6 @@ --- title: "Authorization Guide" -version: 3.8.0 +version: 3.8.1 lastUpdated: 2026-05-13 --- diff --git a/docs/architecture/CODEBASE_DOCUMENTATION.md b/docs/architecture/CODEBASE_DOCUMENTATION.md index 8e55302f4b..130e6ea14a 100644 --- a/docs/architecture/CODEBASE_DOCUMENTATION.md +++ b/docs/architecture/CODEBASE_DOCUMENTATION.md @@ -1,6 +1,6 @@ --- title: "OmniRoute Codebase Documentation" -version: 3.8.0 +version: 3.8.1 lastUpdated: 2026-05-13 --- diff --git a/docs/architecture/REPOSITORY_MAP.md b/docs/architecture/REPOSITORY_MAP.md index 8d3ada80fc..c4fa1b394e 100644 --- a/docs/architecture/REPOSITORY_MAP.md +++ b/docs/architecture/REPOSITORY_MAP.md @@ -1,6 +1,6 @@ --- title: "Repository Map" -version: 3.8.0 +version: 3.8.1 lastUpdated: 2026-05-13 --- diff --git a/docs/architecture/RESILIENCE_GUIDE.md b/docs/architecture/RESILIENCE_GUIDE.md index 8561b9e179..da86782af6 100644 --- a/docs/architecture/RESILIENCE_GUIDE.md +++ b/docs/architecture/RESILIENCE_GUIDE.md @@ -1,6 +1,6 @@ --- title: "Resilience Guide" -version: 3.8.0 +version: 3.8.1 lastUpdated: 2026-05-13 --- diff --git a/docs/comparison/OMNIROUTE_VS_ALTERNATIVES.md b/docs/comparison/OMNIROUTE_VS_ALTERNATIVES.md index a717e36ec6..093c3d22b3 100644 --- a/docs/comparison/OMNIROUTE_VS_ALTERNATIVES.md +++ b/docs/comparison/OMNIROUTE_VS_ALTERNATIVES.md @@ -1,6 +1,6 @@ --- title: "OmniRoute vs Alternatives" -version: 3.8.0 +version: 3.8.1 lastUpdated: 2026-05-15 --- diff --git a/docs/compression/COMPRESSION_ENGINES.md b/docs/compression/COMPRESSION_ENGINES.md index a5efb02093..10e4b455f0 100644 --- a/docs/compression/COMPRESSION_ENGINES.md +++ b/docs/compression/COMPRESSION_ENGINES.md @@ -1,6 +1,6 @@ --- title: "Compression Engines" -version: 3.8.0 +version: 3.8.1 lastUpdated: 2026-05-13 --- diff --git a/docs/compression/COMPRESSION_GUIDE.md b/docs/compression/COMPRESSION_GUIDE.md index 12da9d2910..bbd2edfb5c 100644 --- a/docs/compression/COMPRESSION_GUIDE.md +++ b/docs/compression/COMPRESSION_GUIDE.md @@ -1,6 +1,6 @@ --- title: "🗜️ Prompt Compression Guide — OmniRoute" -version: 3.8.0 +version: 3.8.1 lastUpdated: 2026-05-13 --- diff --git a/docs/compression/COMPRESSION_LANGUAGE_PACKS.md b/docs/compression/COMPRESSION_LANGUAGE_PACKS.md index cedfed4106..b228085945 100644 --- a/docs/compression/COMPRESSION_LANGUAGE_PACKS.md +++ b/docs/compression/COMPRESSION_LANGUAGE_PACKS.md @@ -1,6 +1,6 @@ --- title: "Compression Language Packs" -version: 3.8.0 +version: 3.8.1 lastUpdated: 2026-05-13 --- diff --git a/docs/compression/COMPRESSION_RULES_FORMAT.md b/docs/compression/COMPRESSION_RULES_FORMAT.md index e874c6c9fd..ee9923db30 100644 --- a/docs/compression/COMPRESSION_RULES_FORMAT.md +++ b/docs/compression/COMPRESSION_RULES_FORMAT.md @@ -1,6 +1,6 @@ --- title: "Compression Rules Format" -version: 3.8.0 +version: 3.8.1 lastUpdated: 2026-05-13 --- diff --git a/docs/compression/RTK_COMPRESSION.md b/docs/compression/RTK_COMPRESSION.md index 43df17ecdf..7011c0fa37 100644 --- a/docs/compression/RTK_COMPRESSION.md +++ b/docs/compression/RTK_COMPRESSION.md @@ -1,6 +1,6 @@ --- title: "RTK Compression" -version: 3.8.0 +version: 3.8.1 lastUpdated: 2026-05-13 --- diff --git a/docs/diagrams/README.md b/docs/diagrams/README.md index 3ae2bc003b..43b8e0f9c5 100644 --- a/docs/diagrams/README.md +++ b/docs/diagrams/README.md @@ -1,6 +1,6 @@ --- title: "Diagrams" -version: 3.8.0 +version: 3.8.1 lastUpdated: 2026-05-13 --- diff --git a/docs/frameworks/A2A-SERVER.md b/docs/frameworks/A2A-SERVER.md index b814c6f35c..38e71b9472 100644 --- a/docs/frameworks/A2A-SERVER.md +++ b/docs/frameworks/A2A-SERVER.md @@ -1,6 +1,6 @@ --- title: "OmniRoute A2A Server Documentation" -version: 3.8.0 +version: 3.8.1 lastUpdated: 2026-05-13 --- diff --git a/docs/frameworks/AGENT_PROTOCOLS_GUIDE.md b/docs/frameworks/AGENT_PROTOCOLS_GUIDE.md index 15ac69679c..ea2de6877a 100644 --- a/docs/frameworks/AGENT_PROTOCOLS_GUIDE.md +++ b/docs/frameworks/AGENT_PROTOCOLS_GUIDE.md @@ -1,6 +1,6 @@ --- title: "Agent Protocols Guide" -version: 3.8.0 +version: 3.8.1 lastUpdated: 2026-05-13 --- diff --git a/docs/frameworks/CLOUD_AGENT.md b/docs/frameworks/CLOUD_AGENT.md index c80c604771..1027e32778 100644 --- a/docs/frameworks/CLOUD_AGENT.md +++ b/docs/frameworks/CLOUD_AGENT.md @@ -1,6 +1,6 @@ --- title: "Cloud Agents" -version: 3.8.0 +version: 3.8.1 lastUpdated: 2026-05-13 --- diff --git a/docs/frameworks/EVALS.md b/docs/frameworks/EVALS.md index 45d210a0cb..327ce3fae3 100644 --- a/docs/frameworks/EVALS.md +++ b/docs/frameworks/EVALS.md @@ -1,6 +1,6 @@ --- title: "Evaluations (Evals)" -version: 3.8.0 +version: 3.8.1 lastUpdated: 2026-05-13 --- diff --git a/docs/frameworks/GAMIFICATION.md b/docs/frameworks/GAMIFICATION.md index e8ce74689f..e211723efd 100644 --- a/docs/frameworks/GAMIFICATION.md +++ b/docs/frameworks/GAMIFICATION.md @@ -1,6 +1,6 @@ --- title: "Gamification & Leaderboard System" -version: 3.8.0 +version: 3.8.1 lastUpdated: 2026-05-19 --- diff --git a/docs/frameworks/MCP-SERVER.md b/docs/frameworks/MCP-SERVER.md index 115adab6a5..e660923b30 100644 --- a/docs/frameworks/MCP-SERVER.md +++ b/docs/frameworks/MCP-SERVER.md @@ -1,6 +1,6 @@ --- title: "OmniRoute MCP Server Documentation" -version: 3.8.0 +version: 3.8.1 lastUpdated: 2026-05-13 --- diff --git a/docs/frameworks/MEMORY.md b/docs/frameworks/MEMORY.md index 7216a50656..bbe70c5763 100644 --- a/docs/frameworks/MEMORY.md +++ b/docs/frameworks/MEMORY.md @@ -1,6 +1,6 @@ --- title: "Memory System" -version: 3.8.0 +version: 3.8.1 lastUpdated: 2026-05-13 --- diff --git a/docs/frameworks/OPENCODE.md b/docs/frameworks/OPENCODE.md index 1cd954d09b..a6191a2569 100644 --- a/docs/frameworks/OPENCODE.md +++ b/docs/frameworks/OPENCODE.md @@ -1,6 +1,6 @@ --- title: "OpenCode Integration" -version: 3.8.0 +version: 3.8.1 lastUpdated: 2026-05-14 --- diff --git a/docs/frameworks/SKILLS.md b/docs/frameworks/SKILLS.md index 37f8d85628..31aa27fddb 100644 --- a/docs/frameworks/SKILLS.md +++ b/docs/frameworks/SKILLS.md @@ -1,6 +1,6 @@ --- title: "Skills Framework" -version: 3.8.0 +version: 3.8.1 lastUpdated: 2026-05-13 --- diff --git a/docs/frameworks/WEBHOOKS.md b/docs/frameworks/WEBHOOKS.md index a39b906929..18b7bcddf1 100644 --- a/docs/frameworks/WEBHOOKS.md +++ b/docs/frameworks/WEBHOOKS.md @@ -1,6 +1,6 @@ --- title: "Webhooks" -version: 3.8.0 +version: 3.8.1 lastUpdated: 2026-05-13 --- diff --git a/docs/guides/DOCKER_GUIDE.md b/docs/guides/DOCKER_GUIDE.md index 913b583725..36c2dcb3bc 100644 --- a/docs/guides/DOCKER_GUIDE.md +++ b/docs/guides/DOCKER_GUIDE.md @@ -1,6 +1,6 @@ --- title: "🐳 Docker Guide — OmniRoute" -version: 3.8.0 +version: 3.8.1 lastUpdated: 2026-05-13 --- diff --git a/docs/guides/ELECTRON_GUIDE.md b/docs/guides/ELECTRON_GUIDE.md index b6af20f64b..ea0cdd67b6 100644 --- a/docs/guides/ELECTRON_GUIDE.md +++ b/docs/guides/ELECTRON_GUIDE.md @@ -1,6 +1,6 @@ --- title: "Electron Desktop Guide" -version: 3.8.0 +version: 3.8.1 lastUpdated: 2026-05-13 --- diff --git a/docs/guides/FEATURES.md b/docs/guides/FEATURES.md index 1ba1699032..745f0a790a 100644 --- a/docs/guides/FEATURES.md +++ b/docs/guides/FEATURES.md @@ -1,6 +1,6 @@ --- title: "OmniRoute — Dashboard Features Gallery" -version: 3.8.0 +version: 3.8.1 lastUpdated: 2026-05-13 --- diff --git a/docs/guides/I18N.md b/docs/guides/I18N.md index 8ef8a2965f..9241ca3cb2 100644 --- a/docs/guides/I18N.md +++ b/docs/guides/I18N.md @@ -1,6 +1,6 @@ --- title: "i18n — Internationalization Guide" -version: 3.8.0 +version: 3.8.1 lastUpdated: 2026-05-13 --- diff --git a/docs/guides/PWA_GUIDE.md b/docs/guides/PWA_GUIDE.md index c52a35ddb3..266ec915bf 100644 --- a/docs/guides/PWA_GUIDE.md +++ b/docs/guides/PWA_GUIDE.md @@ -1,6 +1,6 @@ --- title: "Progressive Web App (PWA) Guide" -version: 3.8.0 +version: 3.8.1 lastUpdated: 2026-05-13 --- diff --git a/docs/guides/SETUP_GUIDE.md b/docs/guides/SETUP_GUIDE.md index 4031ea6160..13646883f5 100644 --- a/docs/guides/SETUP_GUIDE.md +++ b/docs/guides/SETUP_GUIDE.md @@ -1,6 +1,6 @@ --- title: "📖 Setup Guide — OmniRoute" -version: 3.8.0 +version: 3.8.1 lastUpdated: 2026-05-13 --- diff --git a/docs/guides/TERMUX_GUIDE.md b/docs/guides/TERMUX_GUIDE.md index 6b8a8b3306..881990e030 100644 --- a/docs/guides/TERMUX_GUIDE.md +++ b/docs/guides/TERMUX_GUIDE.md @@ -1,6 +1,6 @@ --- title: "Termux Headless Setup" -version: 3.8.0 +version: 3.8.1 lastUpdated: 2026-05-13 --- diff --git a/docs/guides/TROUBLESHOOTING.md b/docs/guides/TROUBLESHOOTING.md index f8b3f53398..01c7485b65 100644 --- a/docs/guides/TROUBLESHOOTING.md +++ b/docs/guides/TROUBLESHOOTING.md @@ -1,6 +1,6 @@ --- title: "Troubleshooting" -version: 3.8.0 +version: 3.8.1 lastUpdated: 2026-05-13 --- diff --git a/docs/guides/UNINSTALL.md b/docs/guides/UNINSTALL.md index fc069987a3..6625c7c0d3 100644 --- a/docs/guides/UNINSTALL.md +++ b/docs/guides/UNINSTALL.md @@ -1,6 +1,6 @@ --- title: "OmniRoute — Uninstall Guide" -version: 3.8.0 +version: 3.8.1 lastUpdated: 2026-05-13 --- diff --git a/docs/guides/USER_GUIDE.md b/docs/guides/USER_GUIDE.md index 8f8297faad..bd6bd6530a 100644 --- a/docs/guides/USER_GUIDE.md +++ b/docs/guides/USER_GUIDE.md @@ -1,6 +1,6 @@ --- title: "User Guide" -version: 3.8.0 +version: 3.8.1 lastUpdated: 2026-05-13 --- diff --git a/docs/i18n/ar/CHANGELOG.md b/docs/i18n/ar/CHANGELOG.md index 48993cc38a..c7eb743fba 100644 --- a/docs/i18n/ar/CHANGELOG.md +++ b/docs/i18n/ar/CHANGELOG.md @@ -6,6 +6,26 @@ ## [Unreleased] +## [3.8.1] — 2026-05-20 + +### 🔧 Bug Fixes & Refactors + +- **fix(translator):** treat `developer` role as system in OpenAI → Claude translation — `openAIToClaude` now extracts `developer`-role messages into `systemParts` (same as `system`) and filters them from the non-system message list, preventing identity context injected via the Responses API `developer` role from silently becoming an assistant turn when routing to a Claude-format provider. ([#2407](https://github.com/diegosouzapw/OmniRoute/issues/2407)) +- **fix(antigravity):** deduplicate `removeHeaderCaseInsensitive` — export canonical implementation from `antigravityClientProfile.ts` and remove the local copy in `antigravity.ts`; export `AntigravityCredentialsLike` type for cross-module use. (#2433 — thanks @Gi99lin) + +### 🔒 Security Fixes + +- **fix(security):** replace execSync string-template with spawnSync arg-array in plugin.mjs — eliminates shell command injection. +- **fix(security):** gate Electron CSP unsafe-eval on !app.isPackaged — was leaking unsafe-eval into production builds. +- **fix(api):** add requireManagementAuth to /api/usage/budget/bulk and /api/resilience/reset. +- **fix(security):** route catch-block error messages through sanitizeErrorMessage() in executors and API routes. +- **fix(codex):** refreshCredentials returns null on token refresh failure. +- **fix(tokenRefresh):** safe unknown-error access in catch block. +- **fix(combo):** reset exhaustedProviders set at start of each set-retry iteration. +- **fix(circuitBreaker):** persist and restore lastFailureKind via options JSON column. + +--- + ## [3.8.0] — 2026-05-06 ### ✨ New Features diff --git a/docs/i18n/ar/docs/reference/ENVIRONMENT.md b/docs/i18n/ar/docs/reference/ENVIRONMENT.md index 6c3fc5ae72..e51897ab8d 100644 --- a/docs/i18n/ar/docs/reference/ENVIRONMENT.md +++ b/docs/i18n/ar/docs/reference/ENVIRONMENT.md @@ -339,14 +339,14 @@ process.env[`${PROVIDER_ID}_USER_AGENT`] | Variable | Default Value | When to Update | | ------------------------ | --------------------------------------------- | ------------------------------------------------------------- | -| `CLAUDE_USER_AGENT` | `claude-cli/2.1.143 (external, cli)` | When Anthropic releases a new CLI version | -| `CODEX_USER_AGENT` | `codex-cli/0.131.0 (Windows 10.0.26200; x64)` | When OpenAI updates the Codex CLI | +| `CLAUDE_USER_AGENT` | `claude-cli/2.1.145 (external, cli)` | When Anthropic releases a new CLI version | +| `CODEX_USER_AGENT` | `codex-cli/0.132.0 (Windows 10.0.26200; x64)` | When OpenAI updates the Codex CLI | | `CODEX_CLIENT_VERSION` | `0.131.0` | Override Codex client version independently of full UA string | | `GITHUB_USER_AGENT` | `GitHubCopilotChat/0.45.1` | When GitHub Copilot Chat updates | -| `ANTIGRAVITY_USER_AGENT` | `antigravity/1.107.0 darwin/arm64` | When Antigravity IDE updates | +| `ANTIGRAVITY_USER_AGENT` | `antigravity/2.0.1 darwin/arm64` | When Antigravity IDE updates | | `KIRO_USER_AGENT` | `AWS-SDK-JS/3.0.0 kiro-ide/1.0.0` | When Kiro IDE updates | | `QODER_USER_AGENT` | `Qoder-Cli` | When Qoder CLI updates | -| `QWEN_USER_AGENT` | `QwenCode/0.15.3 (linux; x64)` | When Qwen Code updates | +| `QWEN_USER_AGENT` | `QwenCode/0.15.11 (linux; x64)` | When Qwen Code updates | | `CURSOR_USER_AGENT` | `connect-es/1.6.1` | When Cursor updates | | `GEMINI_CLI_USER_AGENT` | `google-api-nodejs-client/10.3.0` | When Google API client updates | diff --git a/docs/i18n/ar/llm.txt b/docs/i18n/ar/llm.txt index 22ac55f46e..96c63e8b96 100644 --- a/docs/i18n/ar/llm.txt +++ b/docs/i18n/ar/llm.txt @@ -12,7 +12,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo **Key value:** One endpoint (`http://localhost:20128/v1`), unlimited models, zero downtime, minimal cost. -**Current version:** 3.8.0 +**Current version:** 3.8.1 ## Tech Stack @@ -283,7 +283,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo └── .env.example # Environment variable template ``` -## Key Features (v3.8.0) +## Key Features (v3.8.1) ### Core Proxy - **177 AI providers** with automatic format translation diff --git a/docs/i18n/az/CHANGELOG.md b/docs/i18n/az/CHANGELOG.md index 4e0dc7fdb9..2e22b4d40f 100644 --- a/docs/i18n/az/CHANGELOG.md +++ b/docs/i18n/az/CHANGELOG.md @@ -6,6 +6,26 @@ ## [Unreleased] +## [3.8.1] — 2026-05-20 + +### 🔧 Bug Fixes & Refactors + +- **fix(translator):** treat `developer` role as system in OpenAI → Claude translation — `openAIToClaude` now extracts `developer`-role messages into `systemParts` (same as `system`) and filters them from the non-system message list, preventing identity context injected via the Responses API `developer` role from silently becoming an assistant turn when routing to a Claude-format provider. ([#2407](https://github.com/diegosouzapw/OmniRoute/issues/2407)) +- **fix(antigravity):** deduplicate `removeHeaderCaseInsensitive` — export canonical implementation from `antigravityClientProfile.ts` and remove the local copy in `antigravity.ts`; export `AntigravityCredentialsLike` type for cross-module use. (#2433 — thanks @Gi99lin) + +### 🔒 Security Fixes + +- **fix(security):** replace execSync string-template with spawnSync arg-array in plugin.mjs — eliminates shell command injection. +- **fix(security):** gate Electron CSP unsafe-eval on !app.isPackaged — was leaking unsafe-eval into production builds. +- **fix(api):** add requireManagementAuth to /api/usage/budget/bulk and /api/resilience/reset. +- **fix(security):** route catch-block error messages through sanitizeErrorMessage() in executors and API routes. +- **fix(codex):** refreshCredentials returns null on token refresh failure. +- **fix(tokenRefresh):** safe unknown-error access in catch block. +- **fix(combo):** reset exhaustedProviders set at start of each set-retry iteration. +- **fix(circuitBreaker):** persist and restore lastFailureKind via options JSON column. + +--- + ## [3.8.0] — 2026-05-06 ### ✨ New Features diff --git a/docs/i18n/az/docs/reference/ENVIRONMENT.md b/docs/i18n/az/docs/reference/ENVIRONMENT.md index 1fc06604f0..ca7142edbf 100644 --- a/docs/i18n/az/docs/reference/ENVIRONMENT.md +++ b/docs/i18n/az/docs/reference/ENVIRONMENT.md @@ -339,14 +339,14 @@ process.env[`${PROVIDER_ID}_USER_AGENT`] | Variable | Default Value | When to Update | | ------------------------ | --------------------------------------------- | ------------------------------------------------------------- | -| `CLAUDE_USER_AGENT` | `claude-cli/2.1.143 (external, cli)` | When Anthropic releases a new CLI version | -| `CODEX_USER_AGENT` | `codex-cli/0.131.0 (Windows 10.0.26200; x64)` | When OpenAI updates the Codex CLI | +| `CLAUDE_USER_AGENT` | `claude-cli/2.1.145 (external, cli)` | When Anthropic releases a new CLI version | +| `CODEX_USER_AGENT` | `codex-cli/0.132.0 (Windows 10.0.26200; x64)` | When OpenAI updates the Codex CLI | | `CODEX_CLIENT_VERSION` | `0.131.0` | Override Codex client version independently of full UA string | | `GITHUB_USER_AGENT` | `GitHubCopilotChat/0.45.1` | When GitHub Copilot Chat updates | -| `ANTIGRAVITY_USER_AGENT` | `antigravity/1.107.0 darwin/arm64` | When Antigravity IDE updates | +| `ANTIGRAVITY_USER_AGENT` | `antigravity/2.0.1 darwin/arm64` | When Antigravity IDE updates | | `KIRO_USER_AGENT` | `AWS-SDK-JS/3.0.0 kiro-ide/1.0.0` | When Kiro IDE updates | | `QODER_USER_AGENT` | `Qoder-Cli` | When Qoder CLI updates | -| `QWEN_USER_AGENT` | `QwenCode/0.15.3 (linux; x64)` | When Qwen Code updates | +| `QWEN_USER_AGENT` | `QwenCode/0.15.11 (linux; x64)` | When Qwen Code updates | | `CURSOR_USER_AGENT` | `connect-es/1.6.1` | When Cursor updates | | `GEMINI_CLI_USER_AGENT` | `google-api-nodejs-client/10.3.0` | When Google API client updates | diff --git a/docs/i18n/az/llm.txt b/docs/i18n/az/llm.txt index 99ed8aba0b..a2a3fea77d 100644 --- a/docs/i18n/az/llm.txt +++ b/docs/i18n/az/llm.txt @@ -12,7 +12,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo **Key value:** One endpoint (`http://localhost:20128/v1`), unlimited models, zero downtime, minimal cost. -**Current version:** 3.8.0 +**Current version:** 3.8.1 ## Tech Stack @@ -283,7 +283,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo └── .env.example # Environment variable template ``` -## Key Features (v3.8.0) +## Key Features (v3.8.1) ### Core Proxy - **177 AI providers** with automatic format translation diff --git a/docs/i18n/bg/CHANGELOG.md b/docs/i18n/bg/CHANGELOG.md index 978df0e44e..b81806c374 100644 --- a/docs/i18n/bg/CHANGELOG.md +++ b/docs/i18n/bg/CHANGELOG.md @@ -6,6 +6,26 @@ ## [Unreleased] +## [3.8.1] — 2026-05-20 + +### 🔧 Bug Fixes & Refactors + +- **fix(translator):** treat `developer` role as system in OpenAI → Claude translation — `openAIToClaude` now extracts `developer`-role messages into `systemParts` (same as `system`) and filters them from the non-system message list, preventing identity context injected via the Responses API `developer` role from silently becoming an assistant turn when routing to a Claude-format provider. ([#2407](https://github.com/diegosouzapw/OmniRoute/issues/2407)) +- **fix(antigravity):** deduplicate `removeHeaderCaseInsensitive` — export canonical implementation from `antigravityClientProfile.ts` and remove the local copy in `antigravity.ts`; export `AntigravityCredentialsLike` type for cross-module use. (#2433 — thanks @Gi99lin) + +### 🔒 Security Fixes + +- **fix(security):** replace execSync string-template with spawnSync arg-array in plugin.mjs — eliminates shell command injection. +- **fix(security):** gate Electron CSP unsafe-eval on !app.isPackaged — was leaking unsafe-eval into production builds. +- **fix(api):** add requireManagementAuth to /api/usage/budget/bulk and /api/resilience/reset. +- **fix(security):** route catch-block error messages through sanitizeErrorMessage() in executors and API routes. +- **fix(codex):** refreshCredentials returns null on token refresh failure. +- **fix(tokenRefresh):** safe unknown-error access in catch block. +- **fix(combo):** reset exhaustedProviders set at start of each set-retry iteration. +- **fix(circuitBreaker):** persist and restore lastFailureKind via options JSON column. + +--- + ## [3.8.0] — 2026-05-06 ### ✨ New Features diff --git a/docs/i18n/bg/docs/reference/ENVIRONMENT.md b/docs/i18n/bg/docs/reference/ENVIRONMENT.md index 1fc06604f0..ca7142edbf 100644 --- a/docs/i18n/bg/docs/reference/ENVIRONMENT.md +++ b/docs/i18n/bg/docs/reference/ENVIRONMENT.md @@ -339,14 +339,14 @@ process.env[`${PROVIDER_ID}_USER_AGENT`] | Variable | Default Value | When to Update | | ------------------------ | --------------------------------------------- | ------------------------------------------------------------- | -| `CLAUDE_USER_AGENT` | `claude-cli/2.1.143 (external, cli)` | When Anthropic releases a new CLI version | -| `CODEX_USER_AGENT` | `codex-cli/0.131.0 (Windows 10.0.26200; x64)` | When OpenAI updates the Codex CLI | +| `CLAUDE_USER_AGENT` | `claude-cli/2.1.145 (external, cli)` | When Anthropic releases a new CLI version | +| `CODEX_USER_AGENT` | `codex-cli/0.132.0 (Windows 10.0.26200; x64)` | When OpenAI updates the Codex CLI | | `CODEX_CLIENT_VERSION` | `0.131.0` | Override Codex client version independently of full UA string | | `GITHUB_USER_AGENT` | `GitHubCopilotChat/0.45.1` | When GitHub Copilot Chat updates | -| `ANTIGRAVITY_USER_AGENT` | `antigravity/1.107.0 darwin/arm64` | When Antigravity IDE updates | +| `ANTIGRAVITY_USER_AGENT` | `antigravity/2.0.1 darwin/arm64` | When Antigravity IDE updates | | `KIRO_USER_AGENT` | `AWS-SDK-JS/3.0.0 kiro-ide/1.0.0` | When Kiro IDE updates | | `QODER_USER_AGENT` | `Qoder-Cli` | When Qoder CLI updates | -| `QWEN_USER_AGENT` | `QwenCode/0.15.3 (linux; x64)` | When Qwen Code updates | +| `QWEN_USER_AGENT` | `QwenCode/0.15.11 (linux; x64)` | When Qwen Code updates | | `CURSOR_USER_AGENT` | `connect-es/1.6.1` | When Cursor updates | | `GEMINI_CLI_USER_AGENT` | `google-api-nodejs-client/10.3.0` | When Google API client updates | diff --git a/docs/i18n/bg/llm.txt b/docs/i18n/bg/llm.txt index 99ed8aba0b..a2a3fea77d 100644 --- a/docs/i18n/bg/llm.txt +++ b/docs/i18n/bg/llm.txt @@ -12,7 +12,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo **Key value:** One endpoint (`http://localhost:20128/v1`), unlimited models, zero downtime, minimal cost. -**Current version:** 3.8.0 +**Current version:** 3.8.1 ## Tech Stack @@ -283,7 +283,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo └── .env.example # Environment variable template ``` -## Key Features (v3.8.0) +## Key Features (v3.8.1) ### Core Proxy - **177 AI providers** with automatic format translation diff --git a/docs/i18n/bn/CHANGELOG.md b/docs/i18n/bn/CHANGELOG.md index 122ff95964..e7250e504d 100644 --- a/docs/i18n/bn/CHANGELOG.md +++ b/docs/i18n/bn/CHANGELOG.md @@ -6,6 +6,26 @@ ## [Unreleased] +## [3.8.1] — 2026-05-20 + +### 🔧 Bug Fixes & Refactors + +- **fix(translator):** treat `developer` role as system in OpenAI → Claude translation — `openAIToClaude` now extracts `developer`-role messages into `systemParts` (same as `system`) and filters them from the non-system message list, preventing identity context injected via the Responses API `developer` role from silently becoming an assistant turn when routing to a Claude-format provider. ([#2407](https://github.com/diegosouzapw/OmniRoute/issues/2407)) +- **fix(antigravity):** deduplicate `removeHeaderCaseInsensitive` — export canonical implementation from `antigravityClientProfile.ts` and remove the local copy in `antigravity.ts`; export `AntigravityCredentialsLike` type for cross-module use. (#2433 — thanks @Gi99lin) + +### 🔒 Security Fixes + +- **fix(security):** replace execSync string-template with spawnSync arg-array in plugin.mjs — eliminates shell command injection. +- **fix(security):** gate Electron CSP unsafe-eval on !app.isPackaged — was leaking unsafe-eval into production builds. +- **fix(api):** add requireManagementAuth to /api/usage/budget/bulk and /api/resilience/reset. +- **fix(security):** route catch-block error messages through sanitizeErrorMessage() in executors and API routes. +- **fix(codex):** refreshCredentials returns null on token refresh failure. +- **fix(tokenRefresh):** safe unknown-error access in catch block. +- **fix(combo):** reset exhaustedProviders set at start of each set-retry iteration. +- **fix(circuitBreaker):** persist and restore lastFailureKind via options JSON column. + +--- + ## [3.8.0] — 2026-05-06 ### ✨ New Features diff --git a/docs/i18n/bn/docs/reference/ENVIRONMENT.md b/docs/i18n/bn/docs/reference/ENVIRONMENT.md index a2abc51eff..2f916c1f9d 100644 --- a/docs/i18n/bn/docs/reference/ENVIRONMENT.md +++ b/docs/i18n/bn/docs/reference/ENVIRONMENT.md @@ -339,14 +339,14 @@ process.env[`${PROVIDER_ID}_USER_AGENT`] | Variable | Default Value | When to Update | | ------------------------ | --------------------------------------------- | ------------------------------------------------------------- | -| `CLAUDE_USER_AGENT` | `claude-cli/2.1.143 (external, cli)` | When Anthropic releases a new CLI version | -| `CODEX_USER_AGENT` | `codex-cli/0.131.0 (Windows 10.0.26200; x64)` | When OpenAI updates the Codex CLI | +| `CLAUDE_USER_AGENT` | `claude-cli/2.1.145 (external, cli)` | When Anthropic releases a new CLI version | +| `CODEX_USER_AGENT` | `codex-cli/0.132.0 (Windows 10.0.26200; x64)` | When OpenAI updates the Codex CLI | | `CODEX_CLIENT_VERSION` | `0.131.0` | Override Codex client version independently of full UA string | | `GITHUB_USER_AGENT` | `GitHubCopilotChat/0.45.1` | When GitHub Copilot Chat updates | -| `ANTIGRAVITY_USER_AGENT` | `antigravity/1.107.0 darwin/arm64` | When Antigravity IDE updates | +| `ANTIGRAVITY_USER_AGENT` | `antigravity/2.0.1 darwin/arm64` | When Antigravity IDE updates | | `KIRO_USER_AGENT` | `AWS-SDK-JS/3.0.0 kiro-ide/1.0.0` | When Kiro IDE updates | | `QODER_USER_AGENT` | `Qoder-Cli` | When Qoder CLI updates | -| `QWEN_USER_AGENT` | `QwenCode/0.15.3 (linux; x64)` | When Qwen Code updates | +| `QWEN_USER_AGENT` | `QwenCode/0.15.11 (linux; x64)` | When Qwen Code updates | | `CURSOR_USER_AGENT` | `connect-es/1.6.1` | When Cursor updates | | `GEMINI_CLI_USER_AGENT` | `google-api-nodejs-client/10.3.0` | When Google API client updates | diff --git a/docs/i18n/bn/llm.txt b/docs/i18n/bn/llm.txt index 51cd5be98b..e1819fb0be 100644 --- a/docs/i18n/bn/llm.txt +++ b/docs/i18n/bn/llm.txt @@ -12,7 +12,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo **Key value:** One endpoint (`http://localhost:20128/v1`), unlimited models, zero downtime, minimal cost. -**Current version:** 3.8.0 +**Current version:** 3.8.1 ## Tech Stack @@ -283,7 +283,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo └── .env.example # Environment variable template ``` -## Key Features (v3.8.0) +## Key Features (v3.8.1) ### Core Proxy - **177 AI providers** with automatic format translation diff --git a/docs/i18n/cs/CHANGELOG.md b/docs/i18n/cs/CHANGELOG.md index bde4960ea6..5f0d6690e1 100644 --- a/docs/i18n/cs/CHANGELOG.md +++ b/docs/i18n/cs/CHANGELOG.md @@ -6,6 +6,26 @@ ## [Unreleased] +## [3.8.1] — 2026-05-20 + +### 🔧 Bug Fixes & Refactors + +- **fix(translator):** treat `developer` role as system in OpenAI → Claude translation — `openAIToClaude` now extracts `developer`-role messages into `systemParts` (same as `system`) and filters them from the non-system message list, preventing identity context injected via the Responses API `developer` role from silently becoming an assistant turn when routing to a Claude-format provider. ([#2407](https://github.com/diegosouzapw/OmniRoute/issues/2407)) +- **fix(antigravity):** deduplicate `removeHeaderCaseInsensitive` — export canonical implementation from `antigravityClientProfile.ts` and remove the local copy in `antigravity.ts`; export `AntigravityCredentialsLike` type for cross-module use. (#2433 — thanks @Gi99lin) + +### 🔒 Security Fixes + +- **fix(security):** replace execSync string-template with spawnSync arg-array in plugin.mjs — eliminates shell command injection. +- **fix(security):** gate Electron CSP unsafe-eval on !app.isPackaged — was leaking unsafe-eval into production builds. +- **fix(api):** add requireManagementAuth to /api/usage/budget/bulk and /api/resilience/reset. +- **fix(security):** route catch-block error messages through sanitizeErrorMessage() in executors and API routes. +- **fix(codex):** refreshCredentials returns null on token refresh failure. +- **fix(tokenRefresh):** safe unknown-error access in catch block. +- **fix(combo):** reset exhaustedProviders set at start of each set-retry iteration. +- **fix(circuitBreaker):** persist and restore lastFailureKind via options JSON column. + +--- + ## [3.8.0] — 2026-05-06 ### ✨ New Features diff --git a/docs/i18n/cs/docs/reference/ENVIRONMENT.md b/docs/i18n/cs/docs/reference/ENVIRONMENT.md index 63ddaa5b38..1b4543b0de 100644 --- a/docs/i18n/cs/docs/reference/ENVIRONMENT.md +++ b/docs/i18n/cs/docs/reference/ENVIRONMENT.md @@ -339,14 +339,14 @@ process.env[`${PROVIDER_ID}_USER_AGENT`] | Variable | Default Value | When to Update | | ------------------------ | --------------------------------------------- | ------------------------------------------------------------- | -| `CLAUDE_USER_AGENT` | `claude-cli/2.1.143 (external, cli)` | When Anthropic releases a new CLI version | -| `CODEX_USER_AGENT` | `codex-cli/0.131.0 (Windows 10.0.26200; x64)` | When OpenAI updates the Codex CLI | +| `CLAUDE_USER_AGENT` | `claude-cli/2.1.145 (external, cli)` | When Anthropic releases a new CLI version | +| `CODEX_USER_AGENT` | `codex-cli/0.132.0 (Windows 10.0.26200; x64)` | When OpenAI updates the Codex CLI | | `CODEX_CLIENT_VERSION` | `0.131.0` | Override Codex client version independently of full UA string | | `GITHUB_USER_AGENT` | `GitHubCopilotChat/0.45.1` | When GitHub Copilot Chat updates | -| `ANTIGRAVITY_USER_AGENT` | `antigravity/1.107.0 darwin/arm64` | When Antigravity IDE updates | +| `ANTIGRAVITY_USER_AGENT` | `antigravity/2.0.1 darwin/arm64` | When Antigravity IDE updates | | `KIRO_USER_AGENT` | `AWS-SDK-JS/3.0.0 kiro-ide/1.0.0` | When Kiro IDE updates | | `QODER_USER_AGENT` | `Qoder-Cli` | When Qoder CLI updates | -| `QWEN_USER_AGENT` | `QwenCode/0.15.3 (linux; x64)` | When Qwen Code updates | +| `QWEN_USER_AGENT` | `QwenCode/0.15.11 (linux; x64)` | When Qwen Code updates | | `CURSOR_USER_AGENT` | `connect-es/1.6.1` | When Cursor updates | | `GEMINI_CLI_USER_AGENT` | `google-api-nodejs-client/10.3.0` | When Google API client updates | diff --git a/docs/i18n/cs/llm.txt b/docs/i18n/cs/llm.txt index 89152db448..9d265f77eb 100644 --- a/docs/i18n/cs/llm.txt +++ b/docs/i18n/cs/llm.txt @@ -12,7 +12,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo **Key value:** One endpoint (`http://localhost:20128/v1`), unlimited models, zero downtime, minimal cost. -**Current version:** 3.8.0 +**Current version:** 3.8.1 ## Tech Stack @@ -283,7 +283,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo └── .env.example # Environment variable template ``` -## Key Features (v3.8.0) +## Key Features (v3.8.1) ### Core Proxy - **177 AI providers** with automatic format translation diff --git a/docs/i18n/da/CHANGELOG.md b/docs/i18n/da/CHANGELOG.md index fc55da477c..2e470cb4c5 100644 --- a/docs/i18n/da/CHANGELOG.md +++ b/docs/i18n/da/CHANGELOG.md @@ -6,6 +6,26 @@ ## [Unreleased] +## [3.8.1] — 2026-05-20 + +### 🔧 Bug Fixes & Refactors + +- **fix(translator):** treat `developer` role as system in OpenAI → Claude translation — `openAIToClaude` now extracts `developer`-role messages into `systemParts` (same as `system`) and filters them from the non-system message list, preventing identity context injected via the Responses API `developer` role from silently becoming an assistant turn when routing to a Claude-format provider. ([#2407](https://github.com/diegosouzapw/OmniRoute/issues/2407)) +- **fix(antigravity):** deduplicate `removeHeaderCaseInsensitive` — export canonical implementation from `antigravityClientProfile.ts` and remove the local copy in `antigravity.ts`; export `AntigravityCredentialsLike` type for cross-module use. (#2433 — thanks @Gi99lin) + +### 🔒 Security Fixes + +- **fix(security):** replace execSync string-template with spawnSync arg-array in plugin.mjs — eliminates shell command injection. +- **fix(security):** gate Electron CSP unsafe-eval on !app.isPackaged — was leaking unsafe-eval into production builds. +- **fix(api):** add requireManagementAuth to /api/usage/budget/bulk and /api/resilience/reset. +- **fix(security):** route catch-block error messages through sanitizeErrorMessage() in executors and API routes. +- **fix(codex):** refreshCredentials returns null on token refresh failure. +- **fix(tokenRefresh):** safe unknown-error access in catch block. +- **fix(combo):** reset exhaustedProviders set at start of each set-retry iteration. +- **fix(circuitBreaker):** persist and restore lastFailureKind via options JSON column. + +--- + ## [3.8.0] — 2026-05-06 ### ✨ New Features diff --git a/docs/i18n/da/docs/reference/ENVIRONMENT.md b/docs/i18n/da/docs/reference/ENVIRONMENT.md index 6a2dec30ca..3fda305278 100644 --- a/docs/i18n/da/docs/reference/ENVIRONMENT.md +++ b/docs/i18n/da/docs/reference/ENVIRONMENT.md @@ -339,14 +339,14 @@ process.env[`${PROVIDER_ID}_USER_AGENT`] | Variable | Default Value | When to Update | | ------------------------ | --------------------------------------------- | ------------------------------------------------------------- | -| `CLAUDE_USER_AGENT` | `claude-cli/2.1.143 (external, cli)` | When Anthropic releases a new CLI version | -| `CODEX_USER_AGENT` | `codex-cli/0.131.0 (Windows 10.0.26200; x64)` | When OpenAI updates the Codex CLI | +| `CLAUDE_USER_AGENT` | `claude-cli/2.1.145 (external, cli)` | When Anthropic releases a new CLI version | +| `CODEX_USER_AGENT` | `codex-cli/0.132.0 (Windows 10.0.26200; x64)` | When OpenAI updates the Codex CLI | | `CODEX_CLIENT_VERSION` | `0.131.0` | Override Codex client version independently of full UA string | | `GITHUB_USER_AGENT` | `GitHubCopilotChat/0.45.1` | When GitHub Copilot Chat updates | -| `ANTIGRAVITY_USER_AGENT` | `antigravity/1.107.0 darwin/arm64` | When Antigravity IDE updates | +| `ANTIGRAVITY_USER_AGENT` | `antigravity/2.0.1 darwin/arm64` | When Antigravity IDE updates | | `KIRO_USER_AGENT` | `AWS-SDK-JS/3.0.0 kiro-ide/1.0.0` | When Kiro IDE updates | | `QODER_USER_AGENT` | `Qoder-Cli` | When Qoder CLI updates | -| `QWEN_USER_AGENT` | `QwenCode/0.15.3 (linux; x64)` | When Qwen Code updates | +| `QWEN_USER_AGENT` | `QwenCode/0.15.11 (linux; x64)` | When Qwen Code updates | | `CURSOR_USER_AGENT` | `connect-es/1.6.1` | When Cursor updates | | `GEMINI_CLI_USER_AGENT` | `google-api-nodejs-client/10.3.0` | When Google API client updates | diff --git a/docs/i18n/da/llm.txt b/docs/i18n/da/llm.txt index eb6507ce56..480b03371f 100644 --- a/docs/i18n/da/llm.txt +++ b/docs/i18n/da/llm.txt @@ -12,7 +12,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo **Key value:** One endpoint (`http://localhost:20128/v1`), unlimited models, zero downtime, minimal cost. -**Current version:** 3.8.0 +**Current version:** 3.8.1 ## Tech Stack @@ -283,7 +283,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo └── .env.example # Environment variable template ``` -## Key Features (v3.8.0) +## Key Features (v3.8.1) ### Core Proxy - **177 AI providers** with automatic format translation diff --git a/docs/i18n/de/CHANGELOG.md b/docs/i18n/de/CHANGELOG.md index 03cc43b778..042d1a334d 100644 --- a/docs/i18n/de/CHANGELOG.md +++ b/docs/i18n/de/CHANGELOG.md @@ -6,6 +6,26 @@ ## [Unreleased] +## [3.8.1] — 2026-05-20 + +### 🔧 Bug Fixes & Refactors + +- **fix(translator):** treat `developer` role as system in OpenAI → Claude translation — `openAIToClaude` now extracts `developer`-role messages into `systemParts` (same as `system`) and filters them from the non-system message list, preventing identity context injected via the Responses API `developer` role from silently becoming an assistant turn when routing to a Claude-format provider. ([#2407](https://github.com/diegosouzapw/OmniRoute/issues/2407)) +- **fix(antigravity):** deduplicate `removeHeaderCaseInsensitive` — export canonical implementation from `antigravityClientProfile.ts` and remove the local copy in `antigravity.ts`; export `AntigravityCredentialsLike` type for cross-module use. (#2433 — thanks @Gi99lin) + +### 🔒 Security Fixes + +- **fix(security):** replace execSync string-template with spawnSync arg-array in plugin.mjs — eliminates shell command injection. +- **fix(security):** gate Electron CSP unsafe-eval on !app.isPackaged — was leaking unsafe-eval into production builds. +- **fix(api):** add requireManagementAuth to /api/usage/budget/bulk and /api/resilience/reset. +- **fix(security):** route catch-block error messages through sanitizeErrorMessage() in executors and API routes. +- **fix(codex):** refreshCredentials returns null on token refresh failure. +- **fix(tokenRefresh):** safe unknown-error access in catch block. +- **fix(combo):** reset exhaustedProviders set at start of each set-retry iteration. +- **fix(circuitBreaker):** persist and restore lastFailureKind via options JSON column. + +--- + ## [3.8.0] — 2026-05-06 ### ✨ New Features diff --git a/docs/i18n/de/docs/reference/ENVIRONMENT.md b/docs/i18n/de/docs/reference/ENVIRONMENT.md index 90fc9061a6..884eed1ddd 100644 --- a/docs/i18n/de/docs/reference/ENVIRONMENT.md +++ b/docs/i18n/de/docs/reference/ENVIRONMENT.md @@ -339,14 +339,14 @@ process.env[`${PROVIDER_ID}_USER_AGENT`] | Variable | Default Value | When to Update | | ------------------------ | --------------------------------------------- | ------------------------------------------------------------- | -| `CLAUDE_USER_AGENT` | `claude-cli/2.1.143 (external, cli)` | When Anthropic releases a new CLI version | -| `CODEX_USER_AGENT` | `codex-cli/0.131.0 (Windows 10.0.26200; x64)` | When OpenAI updates the Codex CLI | +| `CLAUDE_USER_AGENT` | `claude-cli/2.1.145 (external, cli)` | When Anthropic releases a new CLI version | +| `CODEX_USER_AGENT` | `codex-cli/0.132.0 (Windows 10.0.26200; x64)` | When OpenAI updates the Codex CLI | | `CODEX_CLIENT_VERSION` | `0.131.0` | Override Codex client version independently of full UA string | | `GITHUB_USER_AGENT` | `GitHubCopilotChat/0.45.1` | When GitHub Copilot Chat updates | -| `ANTIGRAVITY_USER_AGENT` | `antigravity/1.107.0 darwin/arm64` | When Antigravity IDE updates | +| `ANTIGRAVITY_USER_AGENT` | `antigravity/2.0.1 darwin/arm64` | When Antigravity IDE updates | | `KIRO_USER_AGENT` | `AWS-SDK-JS/3.0.0 kiro-ide/1.0.0` | When Kiro IDE updates | | `QODER_USER_AGENT` | `Qoder-Cli` | When Qoder CLI updates | -| `QWEN_USER_AGENT` | `QwenCode/0.15.3 (linux; x64)` | When Qwen Code updates | +| `QWEN_USER_AGENT` | `QwenCode/0.15.11 (linux; x64)` | When Qwen Code updates | | `CURSOR_USER_AGENT` | `connect-es/1.6.1` | When Cursor updates | | `GEMINI_CLI_USER_AGENT` | `google-api-nodejs-client/10.3.0` | When Google API client updates | diff --git a/docs/i18n/de/llm.txt b/docs/i18n/de/llm.txt index 314bb28f82..57c78112a2 100644 --- a/docs/i18n/de/llm.txt +++ b/docs/i18n/de/llm.txt @@ -12,7 +12,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo **Key value:** One endpoint (`http://localhost:20128/v1`), unlimited models, zero downtime, minimal cost. -**Current version:** 3.8.0 +**Current version:** 3.8.1 ## Tech Stack @@ -283,7 +283,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo └── .env.example # Environment variable template ``` -## Key Features (v3.8.0) +## Key Features (v3.8.1) ### Core Proxy - **177 AI providers** with automatic format translation diff --git a/docs/i18n/es/CHANGELOG.md b/docs/i18n/es/CHANGELOG.md index 1329d66b44..920fa6e17a 100644 --- a/docs/i18n/es/CHANGELOG.md +++ b/docs/i18n/es/CHANGELOG.md @@ -6,6 +6,26 @@ ## [Unreleased] +## [3.8.1] — 2026-05-20 + +### 🔧 Bug Fixes & Refactors + +- **fix(translator):** treat `developer` role as system in OpenAI → Claude translation — `openAIToClaude` now extracts `developer`-role messages into `systemParts` (same as `system`) and filters them from the non-system message list, preventing identity context injected via the Responses API `developer` role from silently becoming an assistant turn when routing to a Claude-format provider. ([#2407](https://github.com/diegosouzapw/OmniRoute/issues/2407)) +- **fix(antigravity):** deduplicate `removeHeaderCaseInsensitive` — export canonical implementation from `antigravityClientProfile.ts` and remove the local copy in `antigravity.ts`; export `AntigravityCredentialsLike` type for cross-module use. (#2433 — thanks @Gi99lin) + +### 🔒 Security Fixes + +- **fix(security):** replace execSync string-template with spawnSync arg-array in plugin.mjs — eliminates shell command injection. +- **fix(security):** gate Electron CSP unsafe-eval on !app.isPackaged — was leaking unsafe-eval into production builds. +- **fix(api):** add requireManagementAuth to /api/usage/budget/bulk and /api/resilience/reset. +- **fix(security):** route catch-block error messages through sanitizeErrorMessage() in executors and API routes. +- **fix(codex):** refreshCredentials returns null on token refresh failure. +- **fix(tokenRefresh):** safe unknown-error access in catch block. +- **fix(combo):** reset exhaustedProviders set at start of each set-retry iteration. +- **fix(circuitBreaker):** persist and restore lastFailureKind via options JSON column. + +--- + ## [3.8.0] — 2026-05-06 ### ✨ New Features diff --git a/docs/i18n/es/docs/reference/ENVIRONMENT.md b/docs/i18n/es/docs/reference/ENVIRONMENT.md index b60874f798..19afe82879 100644 --- a/docs/i18n/es/docs/reference/ENVIRONMENT.md +++ b/docs/i18n/es/docs/reference/ENVIRONMENT.md @@ -339,14 +339,14 @@ process.env[`${PROVIDER_ID}_USER_AGENT`] | Variable | Default Value | When to Update | | ------------------------ | --------------------------------------------- | ------------------------------------------------------------- | -| `CLAUDE_USER_AGENT` | `claude-cli/2.1.143 (external, cli)` | When Anthropic releases a new CLI version | -| `CODEX_USER_AGENT` | `codex-cli/0.131.0 (Windows 10.0.26200; x64)` | When OpenAI updates the Codex CLI | +| `CLAUDE_USER_AGENT` | `claude-cli/2.1.145 (external, cli)` | When Anthropic releases a new CLI version | +| `CODEX_USER_AGENT` | `codex-cli/0.132.0 (Windows 10.0.26200; x64)` | When OpenAI updates the Codex CLI | | `CODEX_CLIENT_VERSION` | `0.131.0` | Override Codex client version independently of full UA string | | `GITHUB_USER_AGENT` | `GitHubCopilotChat/0.45.1` | When GitHub Copilot Chat updates | -| `ANTIGRAVITY_USER_AGENT` | `antigravity/1.107.0 darwin/arm64` | When Antigravity IDE updates | +| `ANTIGRAVITY_USER_AGENT` | `antigravity/2.0.1 darwin/arm64` | When Antigravity IDE updates | | `KIRO_USER_AGENT` | `AWS-SDK-JS/3.0.0 kiro-ide/1.0.0` | When Kiro IDE updates | | `QODER_USER_AGENT` | `Qoder-Cli` | When Qoder CLI updates | -| `QWEN_USER_AGENT` | `QwenCode/0.15.3 (linux; x64)` | When Qwen Code updates | +| `QWEN_USER_AGENT` | `QwenCode/0.15.11 (linux; x64)` | When Qwen Code updates | | `CURSOR_USER_AGENT` | `connect-es/1.6.1` | When Cursor updates | | `GEMINI_CLI_USER_AGENT` | `google-api-nodejs-client/10.3.0` | When Google API client updates | diff --git a/docs/i18n/es/llm.txt b/docs/i18n/es/llm.txt index 8f329dc22c..f9d160a1ca 100644 --- a/docs/i18n/es/llm.txt +++ b/docs/i18n/es/llm.txt @@ -12,7 +12,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo **Key value:** One endpoint (`http://localhost:20128/v1`), unlimited models, zero downtime, minimal cost. -**Current version:** 3.8.0 +**Current version:** 3.8.1 ## Tech Stack @@ -283,7 +283,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo └── .env.example # Environment variable template ``` -## Key Features (v3.8.0) +## Key Features (v3.8.1) ### Core Proxy - **177 AI providers** with automatic format translation diff --git a/docs/i18n/fa/CHANGELOG.md b/docs/i18n/fa/CHANGELOG.md index c00a8c4094..f0f388a659 100644 --- a/docs/i18n/fa/CHANGELOG.md +++ b/docs/i18n/fa/CHANGELOG.md @@ -6,6 +6,26 @@ ## [Unreleased] +## [3.8.1] — 2026-05-20 + +### 🔧 Bug Fixes & Refactors + +- **fix(translator):** treat `developer` role as system in OpenAI → Claude translation — `openAIToClaude` now extracts `developer`-role messages into `systemParts` (same as `system`) and filters them from the non-system message list, preventing identity context injected via the Responses API `developer` role from silently becoming an assistant turn when routing to a Claude-format provider. ([#2407](https://github.com/diegosouzapw/OmniRoute/issues/2407)) +- **fix(antigravity):** deduplicate `removeHeaderCaseInsensitive` — export canonical implementation from `antigravityClientProfile.ts` and remove the local copy in `antigravity.ts`; export `AntigravityCredentialsLike` type for cross-module use. (#2433 — thanks @Gi99lin) + +### 🔒 Security Fixes + +- **fix(security):** replace execSync string-template with spawnSync arg-array in plugin.mjs — eliminates shell command injection. +- **fix(security):** gate Electron CSP unsafe-eval on !app.isPackaged — was leaking unsafe-eval into production builds. +- **fix(api):** add requireManagementAuth to /api/usage/budget/bulk and /api/resilience/reset. +- **fix(security):** route catch-block error messages through sanitizeErrorMessage() in executors and API routes. +- **fix(codex):** refreshCredentials returns null on token refresh failure. +- **fix(tokenRefresh):** safe unknown-error access in catch block. +- **fix(combo):** reset exhaustedProviders set at start of each set-retry iteration. +- **fix(circuitBreaker):** persist and restore lastFailureKind via options JSON column. + +--- + ## [3.8.0] — 2026-05-06 ### ✨ New Features diff --git a/docs/i18n/fa/docs/reference/ENVIRONMENT.md b/docs/i18n/fa/docs/reference/ENVIRONMENT.md index 34e60e9ee9..0f3ab86dba 100644 --- a/docs/i18n/fa/docs/reference/ENVIRONMENT.md +++ b/docs/i18n/fa/docs/reference/ENVIRONMENT.md @@ -339,14 +339,14 @@ process.env[`${PROVIDER_ID}_USER_AGENT`] | Variable | Default Value | When to Update | | ------------------------ | --------------------------------------------- | ------------------------------------------------------------- | -| `CLAUDE_USER_AGENT` | `claude-cli/2.1.143 (external, cli)` | When Anthropic releases a new CLI version | -| `CODEX_USER_AGENT` | `codex-cli/0.131.0 (Windows 10.0.26200; x64)` | When OpenAI updates the Codex CLI | +| `CLAUDE_USER_AGENT` | `claude-cli/2.1.145 (external, cli)` | When Anthropic releases a new CLI version | +| `CODEX_USER_AGENT` | `codex-cli/0.132.0 (Windows 10.0.26200; x64)` | When OpenAI updates the Codex CLI | | `CODEX_CLIENT_VERSION` | `0.131.0` | Override Codex client version independently of full UA string | | `GITHUB_USER_AGENT` | `GitHubCopilotChat/0.45.1` | When GitHub Copilot Chat updates | -| `ANTIGRAVITY_USER_AGENT` | `antigravity/1.107.0 darwin/arm64` | When Antigravity IDE updates | +| `ANTIGRAVITY_USER_AGENT` | `antigravity/2.0.1 darwin/arm64` | When Antigravity IDE updates | | `KIRO_USER_AGENT` | `AWS-SDK-JS/3.0.0 kiro-ide/1.0.0` | When Kiro IDE updates | | `QODER_USER_AGENT` | `Qoder-Cli` | When Qoder CLI updates | -| `QWEN_USER_AGENT` | `QwenCode/0.15.3 (linux; x64)` | When Qwen Code updates | +| `QWEN_USER_AGENT` | `QwenCode/0.15.11 (linux; x64)` | When Qwen Code updates | | `CURSOR_USER_AGENT` | `connect-es/1.6.1` | When Cursor updates | | `GEMINI_CLI_USER_AGENT` | `google-api-nodejs-client/10.3.0` | When Google API client updates | diff --git a/docs/i18n/fa/llm.txt b/docs/i18n/fa/llm.txt index bd9429d7bd..fa80db7787 100644 --- a/docs/i18n/fa/llm.txt +++ b/docs/i18n/fa/llm.txt @@ -12,7 +12,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo **Key value:** One endpoint (`http://localhost:20128/v1`), unlimited models, zero downtime, minimal cost. -**Current version:** 3.8.0 +**Current version:** 3.8.1 ## Tech Stack @@ -283,7 +283,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo └── .env.example # Environment variable template ``` -## Key Features (v3.8.0) +## Key Features (v3.8.1) ### Core Proxy - **177 AI providers** with automatic format translation diff --git a/docs/i18n/fi/CHANGELOG.md b/docs/i18n/fi/CHANGELOG.md index 843d92079b..a7a8b99203 100644 --- a/docs/i18n/fi/CHANGELOG.md +++ b/docs/i18n/fi/CHANGELOG.md @@ -6,6 +6,26 @@ ## [Unreleased] +## [3.8.1] — 2026-05-20 + +### 🔧 Bug Fixes & Refactors + +- **fix(translator):** treat `developer` role as system in OpenAI → Claude translation — `openAIToClaude` now extracts `developer`-role messages into `systemParts` (same as `system`) and filters them from the non-system message list, preventing identity context injected via the Responses API `developer` role from silently becoming an assistant turn when routing to a Claude-format provider. ([#2407](https://github.com/diegosouzapw/OmniRoute/issues/2407)) +- **fix(antigravity):** deduplicate `removeHeaderCaseInsensitive` — export canonical implementation from `antigravityClientProfile.ts` and remove the local copy in `antigravity.ts`; export `AntigravityCredentialsLike` type for cross-module use. (#2433 — thanks @Gi99lin) + +### 🔒 Security Fixes + +- **fix(security):** replace execSync string-template with spawnSync arg-array in plugin.mjs — eliminates shell command injection. +- **fix(security):** gate Electron CSP unsafe-eval on !app.isPackaged — was leaking unsafe-eval into production builds. +- **fix(api):** add requireManagementAuth to /api/usage/budget/bulk and /api/resilience/reset. +- **fix(security):** route catch-block error messages through sanitizeErrorMessage() in executors and API routes. +- **fix(codex):** refreshCredentials returns null on token refresh failure. +- **fix(tokenRefresh):** safe unknown-error access in catch block. +- **fix(combo):** reset exhaustedProviders set at start of each set-retry iteration. +- **fix(circuitBreaker):** persist and restore lastFailureKind via options JSON column. + +--- + ## [3.8.0] — 2026-05-06 ### ✨ New Features diff --git a/docs/i18n/fi/docs/reference/ENVIRONMENT.md b/docs/i18n/fi/docs/reference/ENVIRONMENT.md index 7a62ebebfb..073a612228 100644 --- a/docs/i18n/fi/docs/reference/ENVIRONMENT.md +++ b/docs/i18n/fi/docs/reference/ENVIRONMENT.md @@ -339,14 +339,14 @@ process.env[`${PROVIDER_ID}_USER_AGENT`] | Variable | Default Value | When to Update | | ------------------------ | --------------------------------------------- | ------------------------------------------------------------- | -| `CLAUDE_USER_AGENT` | `claude-cli/2.1.143 (external, cli)` | When Anthropic releases a new CLI version | -| `CODEX_USER_AGENT` | `codex-cli/0.131.0 (Windows 10.0.26200; x64)` | When OpenAI updates the Codex CLI | +| `CLAUDE_USER_AGENT` | `claude-cli/2.1.145 (external, cli)` | When Anthropic releases a new CLI version | +| `CODEX_USER_AGENT` | `codex-cli/0.132.0 (Windows 10.0.26200; x64)` | When OpenAI updates the Codex CLI | | `CODEX_CLIENT_VERSION` | `0.131.0` | Override Codex client version independently of full UA string | | `GITHUB_USER_AGENT` | `GitHubCopilotChat/0.45.1` | When GitHub Copilot Chat updates | -| `ANTIGRAVITY_USER_AGENT` | `antigravity/1.107.0 darwin/arm64` | When Antigravity IDE updates | +| `ANTIGRAVITY_USER_AGENT` | `antigravity/2.0.1 darwin/arm64` | When Antigravity IDE updates | | `KIRO_USER_AGENT` | `AWS-SDK-JS/3.0.0 kiro-ide/1.0.0` | When Kiro IDE updates | | `QODER_USER_AGENT` | `Qoder-Cli` | When Qoder CLI updates | -| `QWEN_USER_AGENT` | `QwenCode/0.15.3 (linux; x64)` | When Qwen Code updates | +| `QWEN_USER_AGENT` | `QwenCode/0.15.11 (linux; x64)` | When Qwen Code updates | | `CURSOR_USER_AGENT` | `connect-es/1.6.1` | When Cursor updates | | `GEMINI_CLI_USER_AGENT` | `google-api-nodejs-client/10.3.0` | When Google API client updates | diff --git a/docs/i18n/fi/llm.txt b/docs/i18n/fi/llm.txt index 373edd765e..188a0dc5c9 100644 --- a/docs/i18n/fi/llm.txt +++ b/docs/i18n/fi/llm.txt @@ -12,7 +12,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo **Key value:** One endpoint (`http://localhost:20128/v1`), unlimited models, zero downtime, minimal cost. -**Current version:** 3.8.0 +**Current version:** 3.8.1 ## Tech Stack @@ -283,7 +283,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo └── .env.example # Environment variable template ``` -## Key Features (v3.8.0) +## Key Features (v3.8.1) ### Core Proxy - **177 AI providers** with automatic format translation diff --git a/docs/i18n/fr/CHANGELOG.md b/docs/i18n/fr/CHANGELOG.md index 44974e2435..d7a4748a3b 100644 --- a/docs/i18n/fr/CHANGELOG.md +++ b/docs/i18n/fr/CHANGELOG.md @@ -6,6 +6,26 @@ ## [Unreleased] +## [3.8.1] — 2026-05-20 + +### 🔧 Bug Fixes & Refactors + +- **fix(translator):** treat `developer` role as system in OpenAI → Claude translation — `openAIToClaude` now extracts `developer`-role messages into `systemParts` (same as `system`) and filters them from the non-system message list, preventing identity context injected via the Responses API `developer` role from silently becoming an assistant turn when routing to a Claude-format provider. ([#2407](https://github.com/diegosouzapw/OmniRoute/issues/2407)) +- **fix(antigravity):** deduplicate `removeHeaderCaseInsensitive` — export canonical implementation from `antigravityClientProfile.ts` and remove the local copy in `antigravity.ts`; export `AntigravityCredentialsLike` type for cross-module use. (#2433 — thanks @Gi99lin) + +### 🔒 Security Fixes + +- **fix(security):** replace execSync string-template with spawnSync arg-array in plugin.mjs — eliminates shell command injection. +- **fix(security):** gate Electron CSP unsafe-eval on !app.isPackaged — was leaking unsafe-eval into production builds. +- **fix(api):** add requireManagementAuth to /api/usage/budget/bulk and /api/resilience/reset. +- **fix(security):** route catch-block error messages through sanitizeErrorMessage() in executors and API routes. +- **fix(codex):** refreshCredentials returns null on token refresh failure. +- **fix(tokenRefresh):** safe unknown-error access in catch block. +- **fix(combo):** reset exhaustedProviders set at start of each set-retry iteration. +- **fix(circuitBreaker):** persist and restore lastFailureKind via options JSON column. + +--- + ## [3.8.0] — 2026-05-06 ### ✨ New Features diff --git a/docs/i18n/fr/docs/reference/ENVIRONMENT.md b/docs/i18n/fr/docs/reference/ENVIRONMENT.md index 7432f80f17..e0b5ef1583 100644 --- a/docs/i18n/fr/docs/reference/ENVIRONMENT.md +++ b/docs/i18n/fr/docs/reference/ENVIRONMENT.md @@ -339,14 +339,14 @@ process.env[`${PROVIDER_ID}_USER_AGENT`] | Variable | Default Value | When to Update | | ------------------------ | --------------------------------------------- | ------------------------------------------------------------- | -| `CLAUDE_USER_AGENT` | `claude-cli/2.1.143 (external, cli)` | When Anthropic releases a new CLI version | -| `CODEX_USER_AGENT` | `codex-cli/0.131.0 (Windows 10.0.26200; x64)` | When OpenAI updates the Codex CLI | +| `CLAUDE_USER_AGENT` | `claude-cli/2.1.145 (external, cli)` | When Anthropic releases a new CLI version | +| `CODEX_USER_AGENT` | `codex-cli/0.132.0 (Windows 10.0.26200; x64)` | When OpenAI updates the Codex CLI | | `CODEX_CLIENT_VERSION` | `0.131.0` | Override Codex client version independently of full UA string | | `GITHUB_USER_AGENT` | `GitHubCopilotChat/0.45.1` | When GitHub Copilot Chat updates | -| `ANTIGRAVITY_USER_AGENT` | `antigravity/1.107.0 darwin/arm64` | When Antigravity IDE updates | +| `ANTIGRAVITY_USER_AGENT` | `antigravity/2.0.1 darwin/arm64` | When Antigravity IDE updates | | `KIRO_USER_AGENT` | `AWS-SDK-JS/3.0.0 kiro-ide/1.0.0` | When Kiro IDE updates | | `QODER_USER_AGENT` | `Qoder-Cli` | When Qoder CLI updates | -| `QWEN_USER_AGENT` | `QwenCode/0.15.3 (linux; x64)` | When Qwen Code updates | +| `QWEN_USER_AGENT` | `QwenCode/0.15.11 (linux; x64)` | When Qwen Code updates | | `CURSOR_USER_AGENT` | `connect-es/1.6.1` | When Cursor updates | | `GEMINI_CLI_USER_AGENT` | `google-api-nodejs-client/10.3.0` | When Google API client updates | diff --git a/docs/i18n/fr/llm.txt b/docs/i18n/fr/llm.txt index f81b9cd4be..0a6042911d 100644 --- a/docs/i18n/fr/llm.txt +++ b/docs/i18n/fr/llm.txt @@ -12,7 +12,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo **Key value:** One endpoint (`http://localhost:20128/v1`), unlimited models, zero downtime, minimal cost. -**Current version:** 3.8.0 +**Current version:** 3.8.1 ## Tech Stack @@ -283,7 +283,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo └── .env.example # Environment variable template ``` -## Key Features (v3.8.0) +## Key Features (v3.8.1) ### Core Proxy - **177 AI providers** with automatic format translation diff --git a/docs/i18n/gu/CHANGELOG.md b/docs/i18n/gu/CHANGELOG.md index 14341f2989..b1e3480184 100644 --- a/docs/i18n/gu/CHANGELOG.md +++ b/docs/i18n/gu/CHANGELOG.md @@ -6,6 +6,26 @@ ## [Unreleased] +## [3.8.1] — 2026-05-20 + +### 🔧 Bug Fixes & Refactors + +- **fix(translator):** treat `developer` role as system in OpenAI → Claude translation — `openAIToClaude` now extracts `developer`-role messages into `systemParts` (same as `system`) and filters them from the non-system message list, preventing identity context injected via the Responses API `developer` role from silently becoming an assistant turn when routing to a Claude-format provider. ([#2407](https://github.com/diegosouzapw/OmniRoute/issues/2407)) +- **fix(antigravity):** deduplicate `removeHeaderCaseInsensitive` — export canonical implementation from `antigravityClientProfile.ts` and remove the local copy in `antigravity.ts`; export `AntigravityCredentialsLike` type for cross-module use. (#2433 — thanks @Gi99lin) + +### 🔒 Security Fixes + +- **fix(security):** replace execSync string-template with spawnSync arg-array in plugin.mjs — eliminates shell command injection. +- **fix(security):** gate Electron CSP unsafe-eval on !app.isPackaged — was leaking unsafe-eval into production builds. +- **fix(api):** add requireManagementAuth to /api/usage/budget/bulk and /api/resilience/reset. +- **fix(security):** route catch-block error messages through sanitizeErrorMessage() in executors and API routes. +- **fix(codex):** refreshCredentials returns null on token refresh failure. +- **fix(tokenRefresh):** safe unknown-error access in catch block. +- **fix(combo):** reset exhaustedProviders set at start of each set-retry iteration. +- **fix(circuitBreaker):** persist and restore lastFailureKind via options JSON column. + +--- + ## [3.8.0] — 2026-05-06 ### ✨ New Features diff --git a/docs/i18n/gu/docs/reference/ENVIRONMENT.md b/docs/i18n/gu/docs/reference/ENVIRONMENT.md index 39aadd1c8e..efb3c4d615 100644 --- a/docs/i18n/gu/docs/reference/ENVIRONMENT.md +++ b/docs/i18n/gu/docs/reference/ENVIRONMENT.md @@ -339,14 +339,14 @@ process.env[`${PROVIDER_ID}_USER_AGENT`] | Variable | Default Value | When to Update | | ------------------------ | --------------------------------------------- | ------------------------------------------------------------- | -| `CLAUDE_USER_AGENT` | `claude-cli/2.1.143 (external, cli)` | When Anthropic releases a new CLI version | -| `CODEX_USER_AGENT` | `codex-cli/0.131.0 (Windows 10.0.26200; x64)` | When OpenAI updates the Codex CLI | +| `CLAUDE_USER_AGENT` | `claude-cli/2.1.145 (external, cli)` | When Anthropic releases a new CLI version | +| `CODEX_USER_AGENT` | `codex-cli/0.132.0 (Windows 10.0.26200; x64)` | When OpenAI updates the Codex CLI | | `CODEX_CLIENT_VERSION` | `0.131.0` | Override Codex client version independently of full UA string | | `GITHUB_USER_AGENT` | `GitHubCopilotChat/0.45.1` | When GitHub Copilot Chat updates | -| `ANTIGRAVITY_USER_AGENT` | `antigravity/1.107.0 darwin/arm64` | When Antigravity IDE updates | +| `ANTIGRAVITY_USER_AGENT` | `antigravity/2.0.1 darwin/arm64` | When Antigravity IDE updates | | `KIRO_USER_AGENT` | `AWS-SDK-JS/3.0.0 kiro-ide/1.0.0` | When Kiro IDE updates | | `QODER_USER_AGENT` | `Qoder-Cli` | When Qoder CLI updates | -| `QWEN_USER_AGENT` | `QwenCode/0.15.3 (linux; x64)` | When Qwen Code updates | +| `QWEN_USER_AGENT` | `QwenCode/0.15.11 (linux; x64)` | When Qwen Code updates | | `CURSOR_USER_AGENT` | `connect-es/1.6.1` | When Cursor updates | | `GEMINI_CLI_USER_AGENT` | `google-api-nodejs-client/10.3.0` | When Google API client updates | diff --git a/docs/i18n/gu/llm.txt b/docs/i18n/gu/llm.txt index 7e759d7cad..edf6f0f72a 100644 --- a/docs/i18n/gu/llm.txt +++ b/docs/i18n/gu/llm.txt @@ -12,7 +12,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo **Key value:** One endpoint (`http://localhost:20128/v1`), unlimited models, zero downtime, minimal cost. -**Current version:** 3.8.0 +**Current version:** 3.8.1 ## Tech Stack @@ -283,7 +283,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo └── .env.example # Environment variable template ``` -## Key Features (v3.8.0) +## Key Features (v3.8.1) ### Core Proxy - **177 AI providers** with automatic format translation diff --git a/docs/i18n/he/CHANGELOG.md b/docs/i18n/he/CHANGELOG.md index 0ed092c689..9a81272daf 100644 --- a/docs/i18n/he/CHANGELOG.md +++ b/docs/i18n/he/CHANGELOG.md @@ -6,6 +6,26 @@ ## [Unreleased] +## [3.8.1] — 2026-05-20 + +### 🔧 Bug Fixes & Refactors + +- **fix(translator):** treat `developer` role as system in OpenAI → Claude translation — `openAIToClaude` now extracts `developer`-role messages into `systemParts` (same as `system`) and filters them from the non-system message list, preventing identity context injected via the Responses API `developer` role from silently becoming an assistant turn when routing to a Claude-format provider. ([#2407](https://github.com/diegosouzapw/OmniRoute/issues/2407)) +- **fix(antigravity):** deduplicate `removeHeaderCaseInsensitive` — export canonical implementation from `antigravityClientProfile.ts` and remove the local copy in `antigravity.ts`; export `AntigravityCredentialsLike` type for cross-module use. (#2433 — thanks @Gi99lin) + +### 🔒 Security Fixes + +- **fix(security):** replace execSync string-template with spawnSync arg-array in plugin.mjs — eliminates shell command injection. +- **fix(security):** gate Electron CSP unsafe-eval on !app.isPackaged — was leaking unsafe-eval into production builds. +- **fix(api):** add requireManagementAuth to /api/usage/budget/bulk and /api/resilience/reset. +- **fix(security):** route catch-block error messages through sanitizeErrorMessage() in executors and API routes. +- **fix(codex):** refreshCredentials returns null on token refresh failure. +- **fix(tokenRefresh):** safe unknown-error access in catch block. +- **fix(combo):** reset exhaustedProviders set at start of each set-retry iteration. +- **fix(circuitBreaker):** persist and restore lastFailureKind via options JSON column. + +--- + ## [3.8.0] — 2026-05-06 ### ✨ New Features diff --git a/docs/i18n/he/docs/reference/ENVIRONMENT.md b/docs/i18n/he/docs/reference/ENVIRONMENT.md index 5737c39230..c59e9de6ea 100644 --- a/docs/i18n/he/docs/reference/ENVIRONMENT.md +++ b/docs/i18n/he/docs/reference/ENVIRONMENT.md @@ -339,14 +339,14 @@ process.env[`${PROVIDER_ID}_USER_AGENT`] | Variable | Default Value | When to Update | | ------------------------ | --------------------------------------------- | ------------------------------------------------------------- | -| `CLAUDE_USER_AGENT` | `claude-cli/2.1.143 (external, cli)` | When Anthropic releases a new CLI version | -| `CODEX_USER_AGENT` | `codex-cli/0.131.0 (Windows 10.0.26200; x64)` | When OpenAI updates the Codex CLI | +| `CLAUDE_USER_AGENT` | `claude-cli/2.1.145 (external, cli)` | When Anthropic releases a new CLI version | +| `CODEX_USER_AGENT` | `codex-cli/0.132.0 (Windows 10.0.26200; x64)` | When OpenAI updates the Codex CLI | | `CODEX_CLIENT_VERSION` | `0.131.0` | Override Codex client version independently of full UA string | | `GITHUB_USER_AGENT` | `GitHubCopilotChat/0.45.1` | When GitHub Copilot Chat updates | -| `ANTIGRAVITY_USER_AGENT` | `antigravity/1.107.0 darwin/arm64` | When Antigravity IDE updates | +| `ANTIGRAVITY_USER_AGENT` | `antigravity/2.0.1 darwin/arm64` | When Antigravity IDE updates | | `KIRO_USER_AGENT` | `AWS-SDK-JS/3.0.0 kiro-ide/1.0.0` | When Kiro IDE updates | | `QODER_USER_AGENT` | `Qoder-Cli` | When Qoder CLI updates | -| `QWEN_USER_AGENT` | `QwenCode/0.15.3 (linux; x64)` | When Qwen Code updates | +| `QWEN_USER_AGENT` | `QwenCode/0.15.11 (linux; x64)` | When Qwen Code updates | | `CURSOR_USER_AGENT` | `connect-es/1.6.1` | When Cursor updates | | `GEMINI_CLI_USER_AGENT` | `google-api-nodejs-client/10.3.0` | When Google API client updates | diff --git a/docs/i18n/he/llm.txt b/docs/i18n/he/llm.txt index e34487b7cf..be82b38f00 100644 --- a/docs/i18n/he/llm.txt +++ b/docs/i18n/he/llm.txt @@ -12,7 +12,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo **Key value:** One endpoint (`http://localhost:20128/v1`), unlimited models, zero downtime, minimal cost. -**Current version:** 3.8.0 +**Current version:** 3.8.1 ## Tech Stack @@ -283,7 +283,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo └── .env.example # Environment variable template ``` -## Key Features (v3.8.0) +## Key Features (v3.8.1) ### Core Proxy - **177 AI providers** with automatic format translation diff --git a/docs/i18n/hi/CHANGELOG.md b/docs/i18n/hi/CHANGELOG.md index 3e538a1da0..64e0e3d3c8 100644 --- a/docs/i18n/hi/CHANGELOG.md +++ b/docs/i18n/hi/CHANGELOG.md @@ -6,6 +6,26 @@ ## [Unreleased] +## [3.8.1] — 2026-05-20 + +### 🔧 Bug Fixes & Refactors + +- **fix(translator):** treat `developer` role as system in OpenAI → Claude translation — `openAIToClaude` now extracts `developer`-role messages into `systemParts` (same as `system`) and filters them from the non-system message list, preventing identity context injected via the Responses API `developer` role from silently becoming an assistant turn when routing to a Claude-format provider. ([#2407](https://github.com/diegosouzapw/OmniRoute/issues/2407)) +- **fix(antigravity):** deduplicate `removeHeaderCaseInsensitive` — export canonical implementation from `antigravityClientProfile.ts` and remove the local copy in `antigravity.ts`; export `AntigravityCredentialsLike` type for cross-module use. (#2433 — thanks @Gi99lin) + +### 🔒 Security Fixes + +- **fix(security):** replace execSync string-template with spawnSync arg-array in plugin.mjs — eliminates shell command injection. +- **fix(security):** gate Electron CSP unsafe-eval on !app.isPackaged — was leaking unsafe-eval into production builds. +- **fix(api):** add requireManagementAuth to /api/usage/budget/bulk and /api/resilience/reset. +- **fix(security):** route catch-block error messages through sanitizeErrorMessage() in executors and API routes. +- **fix(codex):** refreshCredentials returns null on token refresh failure. +- **fix(tokenRefresh):** safe unknown-error access in catch block. +- **fix(combo):** reset exhaustedProviders set at start of each set-retry iteration. +- **fix(circuitBreaker):** persist and restore lastFailureKind via options JSON column. + +--- + ## [3.8.0] — 2026-05-06 ### ✨ New Features diff --git a/docs/i18n/hi/docs/reference/ENVIRONMENT.md b/docs/i18n/hi/docs/reference/ENVIRONMENT.md index 5bed724d32..4cff76db56 100644 --- a/docs/i18n/hi/docs/reference/ENVIRONMENT.md +++ b/docs/i18n/hi/docs/reference/ENVIRONMENT.md @@ -339,14 +339,14 @@ process.env[`${PROVIDER_ID}_USER_AGENT`] | Variable | Default Value | When to Update | | ------------------------ | --------------------------------------------- | ------------------------------------------------------------- | -| `CLAUDE_USER_AGENT` | `claude-cli/2.1.143 (external, cli)` | When Anthropic releases a new CLI version | -| `CODEX_USER_AGENT` | `codex-cli/0.131.0 (Windows 10.0.26200; x64)` | When OpenAI updates the Codex CLI | +| `CLAUDE_USER_AGENT` | `claude-cli/2.1.145 (external, cli)` | When Anthropic releases a new CLI version | +| `CODEX_USER_AGENT` | `codex-cli/0.132.0 (Windows 10.0.26200; x64)` | When OpenAI updates the Codex CLI | | `CODEX_CLIENT_VERSION` | `0.131.0` | Override Codex client version independently of full UA string | | `GITHUB_USER_AGENT` | `GitHubCopilotChat/0.45.1` | When GitHub Copilot Chat updates | -| `ANTIGRAVITY_USER_AGENT` | `antigravity/1.107.0 darwin/arm64` | When Antigravity IDE updates | +| `ANTIGRAVITY_USER_AGENT` | `antigravity/2.0.1 darwin/arm64` | When Antigravity IDE updates | | `KIRO_USER_AGENT` | `AWS-SDK-JS/3.0.0 kiro-ide/1.0.0` | When Kiro IDE updates | | `QODER_USER_AGENT` | `Qoder-Cli` | When Qoder CLI updates | -| `QWEN_USER_AGENT` | `QwenCode/0.15.3 (linux; x64)` | When Qwen Code updates | +| `QWEN_USER_AGENT` | `QwenCode/0.15.11 (linux; x64)` | When Qwen Code updates | | `CURSOR_USER_AGENT` | `connect-es/1.6.1` | When Cursor updates | | `GEMINI_CLI_USER_AGENT` | `google-api-nodejs-client/10.3.0` | When Google API client updates | diff --git a/docs/i18n/hi/llm.txt b/docs/i18n/hi/llm.txt index e32ceda62a..6d9caabd97 100644 --- a/docs/i18n/hi/llm.txt +++ b/docs/i18n/hi/llm.txt @@ -12,7 +12,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo **Key value:** One endpoint (`http://localhost:20128/v1`), unlimited models, zero downtime, minimal cost. -**Current version:** 3.8.0 +**Current version:** 3.8.1 ## Tech Stack @@ -283,7 +283,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo └── .env.example # Environment variable template ``` -## Key Features (v3.8.0) +## Key Features (v3.8.1) ### Core Proxy - **177 AI providers** with automatic format translation diff --git a/docs/i18n/hu/CHANGELOG.md b/docs/i18n/hu/CHANGELOG.md index 62d344c739..989c131268 100644 --- a/docs/i18n/hu/CHANGELOG.md +++ b/docs/i18n/hu/CHANGELOG.md @@ -6,6 +6,26 @@ ## [Unreleased] +## [3.8.1] — 2026-05-20 + +### 🔧 Bug Fixes & Refactors + +- **fix(translator):** treat `developer` role as system in OpenAI → Claude translation — `openAIToClaude` now extracts `developer`-role messages into `systemParts` (same as `system`) and filters them from the non-system message list, preventing identity context injected via the Responses API `developer` role from silently becoming an assistant turn when routing to a Claude-format provider. ([#2407](https://github.com/diegosouzapw/OmniRoute/issues/2407)) +- **fix(antigravity):** deduplicate `removeHeaderCaseInsensitive` — export canonical implementation from `antigravityClientProfile.ts` and remove the local copy in `antigravity.ts`; export `AntigravityCredentialsLike` type for cross-module use. (#2433 — thanks @Gi99lin) + +### 🔒 Security Fixes + +- **fix(security):** replace execSync string-template with spawnSync arg-array in plugin.mjs — eliminates shell command injection. +- **fix(security):** gate Electron CSP unsafe-eval on !app.isPackaged — was leaking unsafe-eval into production builds. +- **fix(api):** add requireManagementAuth to /api/usage/budget/bulk and /api/resilience/reset. +- **fix(security):** route catch-block error messages through sanitizeErrorMessage() in executors and API routes. +- **fix(codex):** refreshCredentials returns null on token refresh failure. +- **fix(tokenRefresh):** safe unknown-error access in catch block. +- **fix(combo):** reset exhaustedProviders set at start of each set-retry iteration. +- **fix(circuitBreaker):** persist and restore lastFailureKind via options JSON column. + +--- + ## [3.8.0] — 2026-05-06 ### ✨ New Features diff --git a/docs/i18n/hu/docs/reference/ENVIRONMENT.md b/docs/i18n/hu/docs/reference/ENVIRONMENT.md index 329912042b..b846efa313 100644 --- a/docs/i18n/hu/docs/reference/ENVIRONMENT.md +++ b/docs/i18n/hu/docs/reference/ENVIRONMENT.md @@ -339,14 +339,14 @@ process.env[`${PROVIDER_ID}_USER_AGENT`] | Variable | Default Value | When to Update | | ------------------------ | --------------------------------------------- | ------------------------------------------------------------- | -| `CLAUDE_USER_AGENT` | `claude-cli/2.1.143 (external, cli)` | When Anthropic releases a new CLI version | -| `CODEX_USER_AGENT` | `codex-cli/0.131.0 (Windows 10.0.26200; x64)` | When OpenAI updates the Codex CLI | +| `CLAUDE_USER_AGENT` | `claude-cli/2.1.145 (external, cli)` | When Anthropic releases a new CLI version | +| `CODEX_USER_AGENT` | `codex-cli/0.132.0 (Windows 10.0.26200; x64)` | When OpenAI updates the Codex CLI | | `CODEX_CLIENT_VERSION` | `0.131.0` | Override Codex client version independently of full UA string | | `GITHUB_USER_AGENT` | `GitHubCopilotChat/0.45.1` | When GitHub Copilot Chat updates | -| `ANTIGRAVITY_USER_AGENT` | `antigravity/1.107.0 darwin/arm64` | When Antigravity IDE updates | +| `ANTIGRAVITY_USER_AGENT` | `antigravity/2.0.1 darwin/arm64` | When Antigravity IDE updates | | `KIRO_USER_AGENT` | `AWS-SDK-JS/3.0.0 kiro-ide/1.0.0` | When Kiro IDE updates | | `QODER_USER_AGENT` | `Qoder-Cli` | When Qoder CLI updates | -| `QWEN_USER_AGENT` | `QwenCode/0.15.3 (linux; x64)` | When Qwen Code updates | +| `QWEN_USER_AGENT` | `QwenCode/0.15.11 (linux; x64)` | When Qwen Code updates | | `CURSOR_USER_AGENT` | `connect-es/1.6.1` | When Cursor updates | | `GEMINI_CLI_USER_AGENT` | `google-api-nodejs-client/10.3.0` | When Google API client updates | diff --git a/docs/i18n/hu/llm.txt b/docs/i18n/hu/llm.txt index 6dd8fe5dc3..425dcb0759 100644 --- a/docs/i18n/hu/llm.txt +++ b/docs/i18n/hu/llm.txt @@ -12,7 +12,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo **Key value:** One endpoint (`http://localhost:20128/v1`), unlimited models, zero downtime, minimal cost. -**Current version:** 3.8.0 +**Current version:** 3.8.1 ## Tech Stack @@ -283,7 +283,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo └── .env.example # Environment variable template ``` -## Key Features (v3.8.0) +## Key Features (v3.8.1) ### Core Proxy - **177 AI providers** with automatic format translation diff --git a/docs/i18n/id/CHANGELOG.md b/docs/i18n/id/CHANGELOG.md index 4e692e5b23..6e066b3023 100644 --- a/docs/i18n/id/CHANGELOG.md +++ b/docs/i18n/id/CHANGELOG.md @@ -6,6 +6,26 @@ ## [Unreleased] +## [3.8.1] — 2026-05-20 + +### 🔧 Bug Fixes & Refactors + +- **fix(translator):** treat `developer` role as system in OpenAI → Claude translation — `openAIToClaude` now extracts `developer`-role messages into `systemParts` (same as `system`) and filters them from the non-system message list, preventing identity context injected via the Responses API `developer` role from silently becoming an assistant turn when routing to a Claude-format provider. ([#2407](https://github.com/diegosouzapw/OmniRoute/issues/2407)) +- **fix(antigravity):** deduplicate `removeHeaderCaseInsensitive` — export canonical implementation from `antigravityClientProfile.ts` and remove the local copy in `antigravity.ts`; export `AntigravityCredentialsLike` type for cross-module use. (#2433 — thanks @Gi99lin) + +### 🔒 Security Fixes + +- **fix(security):** replace execSync string-template with spawnSync arg-array in plugin.mjs — eliminates shell command injection. +- **fix(security):** gate Electron CSP unsafe-eval on !app.isPackaged — was leaking unsafe-eval into production builds. +- **fix(api):** add requireManagementAuth to /api/usage/budget/bulk and /api/resilience/reset. +- **fix(security):** route catch-block error messages through sanitizeErrorMessage() in executors and API routes. +- **fix(codex):** refreshCredentials returns null on token refresh failure. +- **fix(tokenRefresh):** safe unknown-error access in catch block. +- **fix(combo):** reset exhaustedProviders set at start of each set-retry iteration. +- **fix(circuitBreaker):** persist and restore lastFailureKind via options JSON column. + +--- + ## [3.8.0] — 2026-05-06 ### ✨ New Features diff --git a/docs/i18n/id/docs/reference/ENVIRONMENT.md b/docs/i18n/id/docs/reference/ENVIRONMENT.md index 1951ec5866..e16f9f9ec1 100644 --- a/docs/i18n/id/docs/reference/ENVIRONMENT.md +++ b/docs/i18n/id/docs/reference/ENVIRONMENT.md @@ -339,14 +339,14 @@ process.env[`${PROVIDER_ID}_USER_AGENT`] | Variable | Default Value | When to Update | | ------------------------ | --------------------------------------------- | ------------------------------------------------------------- | -| `CLAUDE_USER_AGENT` | `claude-cli/2.1.143 (external, cli)` | When Anthropic releases a new CLI version | -| `CODEX_USER_AGENT` | `codex-cli/0.131.0 (Windows 10.0.26200; x64)` | When OpenAI updates the Codex CLI | +| `CLAUDE_USER_AGENT` | `claude-cli/2.1.145 (external, cli)` | When Anthropic releases a new CLI version | +| `CODEX_USER_AGENT` | `codex-cli/0.132.0 (Windows 10.0.26200; x64)` | When OpenAI updates the Codex CLI | | `CODEX_CLIENT_VERSION` | `0.131.0` | Override Codex client version independently of full UA string | | `GITHUB_USER_AGENT` | `GitHubCopilotChat/0.45.1` | When GitHub Copilot Chat updates | -| `ANTIGRAVITY_USER_AGENT` | `antigravity/1.107.0 darwin/arm64` | When Antigravity IDE updates | +| `ANTIGRAVITY_USER_AGENT` | `antigravity/2.0.1 darwin/arm64` | When Antigravity IDE updates | | `KIRO_USER_AGENT` | `AWS-SDK-JS/3.0.0 kiro-ide/1.0.0` | When Kiro IDE updates | | `QODER_USER_AGENT` | `Qoder-Cli` | When Qoder CLI updates | -| `QWEN_USER_AGENT` | `QwenCode/0.15.3 (linux; x64)` | When Qwen Code updates | +| `QWEN_USER_AGENT` | `QwenCode/0.15.11 (linux; x64)` | When Qwen Code updates | | `CURSOR_USER_AGENT` | `connect-es/1.6.1` | When Cursor updates | | `GEMINI_CLI_USER_AGENT` | `google-api-nodejs-client/10.3.0` | When Google API client updates | diff --git a/docs/i18n/id/llm.txt b/docs/i18n/id/llm.txt index 4bed30dca4..c1d9312578 100644 --- a/docs/i18n/id/llm.txt +++ b/docs/i18n/id/llm.txt @@ -12,7 +12,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo **Key value:** One endpoint (`http://localhost:20128/v1`), unlimited models, zero downtime, minimal cost. -**Current version:** 3.8.0 +**Current version:** 3.8.1 ## Tech Stack @@ -283,7 +283,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo └── .env.example # Environment variable template ``` -## Key Features (v3.8.0) +## Key Features (v3.8.1) ### Core Proxy - **177 AI providers** with automatic format translation diff --git a/docs/i18n/in/CHANGELOG.md b/docs/i18n/in/CHANGELOG.md index 4152c0549f..cdff8561e4 100644 --- a/docs/i18n/in/CHANGELOG.md +++ b/docs/i18n/in/CHANGELOG.md @@ -6,6 +6,26 @@ ## [Unreleased] +## [3.8.1] — 2026-05-20 + +### 🔧 Bug Fixes & Refactors + +- **fix(translator):** treat `developer` role as system in OpenAI → Claude translation — `openAIToClaude` now extracts `developer`-role messages into `systemParts` (same as `system`) and filters them from the non-system message list, preventing identity context injected via the Responses API `developer` role from silently becoming an assistant turn when routing to a Claude-format provider. ([#2407](https://github.com/diegosouzapw/OmniRoute/issues/2407)) +- **fix(antigravity):** deduplicate `removeHeaderCaseInsensitive` — export canonical implementation from `antigravityClientProfile.ts` and remove the local copy in `antigravity.ts`; export `AntigravityCredentialsLike` type for cross-module use. (#2433 — thanks @Gi99lin) + +### 🔒 Security Fixes + +- **fix(security):** replace execSync string-template with spawnSync arg-array in plugin.mjs — eliminates shell command injection. +- **fix(security):** gate Electron CSP unsafe-eval on !app.isPackaged — was leaking unsafe-eval into production builds. +- **fix(api):** add requireManagementAuth to /api/usage/budget/bulk and /api/resilience/reset. +- **fix(security):** route catch-block error messages through sanitizeErrorMessage() in executors and API routes. +- **fix(codex):** refreshCredentials returns null on token refresh failure. +- **fix(tokenRefresh):** safe unknown-error access in catch block. +- **fix(combo):** reset exhaustedProviders set at start of each set-retry iteration. +- **fix(circuitBreaker):** persist and restore lastFailureKind via options JSON column. + +--- + ## [3.8.0] — 2026-05-06 ### ✨ New Features diff --git a/docs/i18n/in/docs/reference/ENVIRONMENT.md b/docs/i18n/in/docs/reference/ENVIRONMENT.md index 551fde8f34..8e890a23ae 100644 --- a/docs/i18n/in/docs/reference/ENVIRONMENT.md +++ b/docs/i18n/in/docs/reference/ENVIRONMENT.md @@ -339,14 +339,14 @@ process.env[`${PROVIDER_ID}_USER_AGENT`] | Variable | Default Value | When to Update | | ------------------------ | --------------------------------------------- | ------------------------------------------------------------- | -| `CLAUDE_USER_AGENT` | `claude-cli/2.1.143 (external, cli)` | When Anthropic releases a new CLI version | -| `CODEX_USER_AGENT` | `codex-cli/0.131.0 (Windows 10.0.26200; x64)` | When OpenAI updates the Codex CLI | +| `CLAUDE_USER_AGENT` | `claude-cli/2.1.145 (external, cli)` | When Anthropic releases a new CLI version | +| `CODEX_USER_AGENT` | `codex-cli/0.132.0 (Windows 10.0.26200; x64)` | When OpenAI updates the Codex CLI | | `CODEX_CLIENT_VERSION` | `0.131.0` | Override Codex client version independently of full UA string | | `GITHUB_USER_AGENT` | `GitHubCopilotChat/0.45.1` | When GitHub Copilot Chat updates | -| `ANTIGRAVITY_USER_AGENT` | `antigravity/1.107.0 darwin/arm64` | When Antigravity IDE updates | +| `ANTIGRAVITY_USER_AGENT` | `antigravity/2.0.1 darwin/arm64` | When Antigravity IDE updates | | `KIRO_USER_AGENT` | `AWS-SDK-JS/3.0.0 kiro-ide/1.0.0` | When Kiro IDE updates | | `QODER_USER_AGENT` | `Qoder-Cli` | When Qoder CLI updates | -| `QWEN_USER_AGENT` | `QwenCode/0.15.3 (linux; x64)` | When Qwen Code updates | +| `QWEN_USER_AGENT` | `QwenCode/0.15.11 (linux; x64)` | When Qwen Code updates | | `CURSOR_USER_AGENT` | `connect-es/1.6.1` | When Cursor updates | | `GEMINI_CLI_USER_AGENT` | `google-api-nodejs-client/10.3.0` | When Google API client updates | diff --git a/docs/i18n/in/llm.txt b/docs/i18n/in/llm.txt index fb7e1f4c03..4c7daf9656 100644 --- a/docs/i18n/in/llm.txt +++ b/docs/i18n/in/llm.txt @@ -12,7 +12,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo **Key value:** One endpoint (`http://localhost:20128/v1`), unlimited models, zero downtime, minimal cost. -**Current version:** 3.8.0 +**Current version:** 3.8.1 ## Tech Stack @@ -283,7 +283,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo └── .env.example # Environment variable template ``` -## Key Features (v3.8.0) +## Key Features (v3.8.1) ### Core Proxy - **177 AI providers** with automatic format translation diff --git a/docs/i18n/it/CHANGELOG.md b/docs/i18n/it/CHANGELOG.md index fbf0847027..70900b5a07 100644 --- a/docs/i18n/it/CHANGELOG.md +++ b/docs/i18n/it/CHANGELOG.md @@ -6,6 +6,26 @@ ## [Unreleased] +## [3.8.1] — 2026-05-20 + +### 🔧 Bug Fixes & Refactors + +- **fix(translator):** treat `developer` role as system in OpenAI → Claude translation — `openAIToClaude` now extracts `developer`-role messages into `systemParts` (same as `system`) and filters them from the non-system message list, preventing identity context injected via the Responses API `developer` role from silently becoming an assistant turn when routing to a Claude-format provider. ([#2407](https://github.com/diegosouzapw/OmniRoute/issues/2407)) +- **fix(antigravity):** deduplicate `removeHeaderCaseInsensitive` — export canonical implementation from `antigravityClientProfile.ts` and remove the local copy in `antigravity.ts`; export `AntigravityCredentialsLike` type for cross-module use. (#2433 — thanks @Gi99lin) + +### 🔒 Security Fixes + +- **fix(security):** replace execSync string-template with spawnSync arg-array in plugin.mjs — eliminates shell command injection. +- **fix(security):** gate Electron CSP unsafe-eval on !app.isPackaged — was leaking unsafe-eval into production builds. +- **fix(api):** add requireManagementAuth to /api/usage/budget/bulk and /api/resilience/reset. +- **fix(security):** route catch-block error messages through sanitizeErrorMessage() in executors and API routes. +- **fix(codex):** refreshCredentials returns null on token refresh failure. +- **fix(tokenRefresh):** safe unknown-error access in catch block. +- **fix(combo):** reset exhaustedProviders set at start of each set-retry iteration. +- **fix(circuitBreaker):** persist and restore lastFailureKind via options JSON column. + +--- + ## [3.8.0] — 2026-05-06 ### ✨ New Features diff --git a/docs/i18n/it/docs/reference/ENVIRONMENT.md b/docs/i18n/it/docs/reference/ENVIRONMENT.md index 4b3309bbf5..5b29273cc7 100644 --- a/docs/i18n/it/docs/reference/ENVIRONMENT.md +++ b/docs/i18n/it/docs/reference/ENVIRONMENT.md @@ -339,14 +339,14 @@ process.env[`${PROVIDER_ID}_USER_AGENT`] | Variable | Default Value | When to Update | | ------------------------ | --------------------------------------------- | ------------------------------------------------------------- | -| `CLAUDE_USER_AGENT` | `claude-cli/2.1.143 (external, cli)` | When Anthropic releases a new CLI version | -| `CODEX_USER_AGENT` | `codex-cli/0.131.0 (Windows 10.0.26200; x64)` | When OpenAI updates the Codex CLI | +| `CLAUDE_USER_AGENT` | `claude-cli/2.1.145 (external, cli)` | When Anthropic releases a new CLI version | +| `CODEX_USER_AGENT` | `codex-cli/0.132.0 (Windows 10.0.26200; x64)` | When OpenAI updates the Codex CLI | | `CODEX_CLIENT_VERSION` | `0.131.0` | Override Codex client version independently of full UA string | | `GITHUB_USER_AGENT` | `GitHubCopilotChat/0.45.1` | When GitHub Copilot Chat updates | -| `ANTIGRAVITY_USER_AGENT` | `antigravity/1.107.0 darwin/arm64` | When Antigravity IDE updates | +| `ANTIGRAVITY_USER_AGENT` | `antigravity/2.0.1 darwin/arm64` | When Antigravity IDE updates | | `KIRO_USER_AGENT` | `AWS-SDK-JS/3.0.0 kiro-ide/1.0.0` | When Kiro IDE updates | | `QODER_USER_AGENT` | `Qoder-Cli` | When Qoder CLI updates | -| `QWEN_USER_AGENT` | `QwenCode/0.15.3 (linux; x64)` | When Qwen Code updates | +| `QWEN_USER_AGENT` | `QwenCode/0.15.11 (linux; x64)` | When Qwen Code updates | | `CURSOR_USER_AGENT` | `connect-es/1.6.1` | When Cursor updates | | `GEMINI_CLI_USER_AGENT` | `google-api-nodejs-client/10.3.0` | When Google API client updates | diff --git a/docs/i18n/it/llm.txt b/docs/i18n/it/llm.txt index 0b39509100..8947fe20c4 100644 --- a/docs/i18n/it/llm.txt +++ b/docs/i18n/it/llm.txt @@ -12,7 +12,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo **Key value:** One endpoint (`http://localhost:20128/v1`), unlimited models, zero downtime, minimal cost. -**Current version:** 3.8.0 +**Current version:** 3.8.1 ## Tech Stack @@ -283,7 +283,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo └── .env.example # Environment variable template ``` -## Key Features (v3.8.0) +## Key Features (v3.8.1) ### Core Proxy - **177 AI providers** with automatic format translation diff --git a/docs/i18n/ja/CHANGELOG.md b/docs/i18n/ja/CHANGELOG.md index 504bcf719e..ebf906a992 100644 --- a/docs/i18n/ja/CHANGELOG.md +++ b/docs/i18n/ja/CHANGELOG.md @@ -6,6 +6,26 @@ ## [Unreleased] +## [3.8.1] — 2026-05-20 + +### 🔧 Bug Fixes & Refactors + +- **fix(translator):** treat `developer` role as system in OpenAI → Claude translation — `openAIToClaude` now extracts `developer`-role messages into `systemParts` (same as `system`) and filters them from the non-system message list, preventing identity context injected via the Responses API `developer` role from silently becoming an assistant turn when routing to a Claude-format provider. ([#2407](https://github.com/diegosouzapw/OmniRoute/issues/2407)) +- **fix(antigravity):** deduplicate `removeHeaderCaseInsensitive` — export canonical implementation from `antigravityClientProfile.ts` and remove the local copy in `antigravity.ts`; export `AntigravityCredentialsLike` type for cross-module use. (#2433 — thanks @Gi99lin) + +### 🔒 Security Fixes + +- **fix(security):** replace execSync string-template with spawnSync arg-array in plugin.mjs — eliminates shell command injection. +- **fix(security):** gate Electron CSP unsafe-eval on !app.isPackaged — was leaking unsafe-eval into production builds. +- **fix(api):** add requireManagementAuth to /api/usage/budget/bulk and /api/resilience/reset. +- **fix(security):** route catch-block error messages through sanitizeErrorMessage() in executors and API routes. +- **fix(codex):** refreshCredentials returns null on token refresh failure. +- **fix(tokenRefresh):** safe unknown-error access in catch block. +- **fix(combo):** reset exhaustedProviders set at start of each set-retry iteration. +- **fix(circuitBreaker):** persist and restore lastFailureKind via options JSON column. + +--- + ## [3.8.0] — 2026-05-06 ### ✨ New Features diff --git a/docs/i18n/ja/docs/reference/ENVIRONMENT.md b/docs/i18n/ja/docs/reference/ENVIRONMENT.md index 8c65daf6b3..51d7dc921f 100644 --- a/docs/i18n/ja/docs/reference/ENVIRONMENT.md +++ b/docs/i18n/ja/docs/reference/ENVIRONMENT.md @@ -339,14 +339,14 @@ process.env[`${PROVIDER_ID}_USER_AGENT`] | Variable | Default Value | When to Update | | ------------------------ | --------------------------------------------- | ------------------------------------------------------------- | -| `CLAUDE_USER_AGENT` | `claude-cli/2.1.143 (external, cli)` | When Anthropic releases a new CLI version | -| `CODEX_USER_AGENT` | `codex-cli/0.131.0 (Windows 10.0.26200; x64)` | When OpenAI updates the Codex CLI | +| `CLAUDE_USER_AGENT` | `claude-cli/2.1.145 (external, cli)` | When Anthropic releases a new CLI version | +| `CODEX_USER_AGENT` | `codex-cli/0.132.0 (Windows 10.0.26200; x64)` | When OpenAI updates the Codex CLI | | `CODEX_CLIENT_VERSION` | `0.131.0` | Override Codex client version independently of full UA string | | `GITHUB_USER_AGENT` | `GitHubCopilotChat/0.45.1` | When GitHub Copilot Chat updates | -| `ANTIGRAVITY_USER_AGENT` | `antigravity/1.107.0 darwin/arm64` | When Antigravity IDE updates | +| `ANTIGRAVITY_USER_AGENT` | `antigravity/2.0.1 darwin/arm64` | When Antigravity IDE updates | | `KIRO_USER_AGENT` | `AWS-SDK-JS/3.0.0 kiro-ide/1.0.0` | When Kiro IDE updates | | `QODER_USER_AGENT` | `Qoder-Cli` | When Qoder CLI updates | -| `QWEN_USER_AGENT` | `QwenCode/0.15.3 (linux; x64)` | When Qwen Code updates | +| `QWEN_USER_AGENT` | `QwenCode/0.15.11 (linux; x64)` | When Qwen Code updates | | `CURSOR_USER_AGENT` | `connect-es/1.6.1` | When Cursor updates | | `GEMINI_CLI_USER_AGENT` | `google-api-nodejs-client/10.3.0` | When Google API client updates | diff --git a/docs/i18n/ja/llm.txt b/docs/i18n/ja/llm.txt index 8a9f2f6adf..93140c4540 100644 --- a/docs/i18n/ja/llm.txt +++ b/docs/i18n/ja/llm.txt @@ -12,7 +12,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo **Key value:** One endpoint (`http://localhost:20128/v1`), unlimited models, zero downtime, minimal cost. -**Current version:** 3.8.0 +**Current version:** 3.8.1 ## Tech Stack @@ -283,7 +283,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo └── .env.example # Environment variable template ``` -## Key Features (v3.8.0) +## Key Features (v3.8.1) ### Core Proxy - **177 AI providers** with automatic format translation diff --git a/docs/i18n/ko/CHANGELOG.md b/docs/i18n/ko/CHANGELOG.md index 86303bd0bb..18e64bd9e2 100644 --- a/docs/i18n/ko/CHANGELOG.md +++ b/docs/i18n/ko/CHANGELOG.md @@ -6,6 +6,26 @@ ## [Unreleased] +## [3.8.1] — 2026-05-20 + +### 🔧 Bug Fixes & Refactors + +- **fix(translator):** treat `developer` role as system in OpenAI → Claude translation — `openAIToClaude` now extracts `developer`-role messages into `systemParts` (same as `system`) and filters them from the non-system message list, preventing identity context injected via the Responses API `developer` role from silently becoming an assistant turn when routing to a Claude-format provider. ([#2407](https://github.com/diegosouzapw/OmniRoute/issues/2407)) +- **fix(antigravity):** deduplicate `removeHeaderCaseInsensitive` — export canonical implementation from `antigravityClientProfile.ts` and remove the local copy in `antigravity.ts`; export `AntigravityCredentialsLike` type for cross-module use. (#2433 — thanks @Gi99lin) + +### 🔒 Security Fixes + +- **fix(security):** replace execSync string-template with spawnSync arg-array in plugin.mjs — eliminates shell command injection. +- **fix(security):** gate Electron CSP unsafe-eval on !app.isPackaged — was leaking unsafe-eval into production builds. +- **fix(api):** add requireManagementAuth to /api/usage/budget/bulk and /api/resilience/reset. +- **fix(security):** route catch-block error messages through sanitizeErrorMessage() in executors and API routes. +- **fix(codex):** refreshCredentials returns null on token refresh failure. +- **fix(tokenRefresh):** safe unknown-error access in catch block. +- **fix(combo):** reset exhaustedProviders set at start of each set-retry iteration. +- **fix(circuitBreaker):** persist and restore lastFailureKind via options JSON column. + +--- + ## [3.8.0] — 2026-05-06 ### ✨ New Features diff --git a/docs/i18n/ko/docs/reference/ENVIRONMENT.md b/docs/i18n/ko/docs/reference/ENVIRONMENT.md index 42c4f13d42..f0dd29e7bf 100644 --- a/docs/i18n/ko/docs/reference/ENVIRONMENT.md +++ b/docs/i18n/ko/docs/reference/ENVIRONMENT.md @@ -339,14 +339,14 @@ process.env[`${PROVIDER_ID}_USER_AGENT`] | Variable | Default Value | When to Update | | ------------------------ | --------------------------------------------- | ------------------------------------------------------------- | -| `CLAUDE_USER_AGENT` | `claude-cli/2.1.143 (external, cli)` | When Anthropic releases a new CLI version | -| `CODEX_USER_AGENT` | `codex-cli/0.131.0 (Windows 10.0.26200; x64)` | When OpenAI updates the Codex CLI | +| `CLAUDE_USER_AGENT` | `claude-cli/2.1.145 (external, cli)` | When Anthropic releases a new CLI version | +| `CODEX_USER_AGENT` | `codex-cli/0.132.0 (Windows 10.0.26200; x64)` | When OpenAI updates the Codex CLI | | `CODEX_CLIENT_VERSION` | `0.131.0` | Override Codex client version independently of full UA string | | `GITHUB_USER_AGENT` | `GitHubCopilotChat/0.45.1` | When GitHub Copilot Chat updates | -| `ANTIGRAVITY_USER_AGENT` | `antigravity/1.107.0 darwin/arm64` | When Antigravity IDE updates | +| `ANTIGRAVITY_USER_AGENT` | `antigravity/2.0.1 darwin/arm64` | When Antigravity IDE updates | | `KIRO_USER_AGENT` | `AWS-SDK-JS/3.0.0 kiro-ide/1.0.0` | When Kiro IDE updates | | `QODER_USER_AGENT` | `Qoder-Cli` | When Qoder CLI updates | -| `QWEN_USER_AGENT` | `QwenCode/0.15.3 (linux; x64)` | When Qwen Code updates | +| `QWEN_USER_AGENT` | `QwenCode/0.15.11 (linux; x64)` | When Qwen Code updates | | `CURSOR_USER_AGENT` | `connect-es/1.6.1` | When Cursor updates | | `GEMINI_CLI_USER_AGENT` | `google-api-nodejs-client/10.3.0` | When Google API client updates | diff --git a/docs/i18n/ko/llm.txt b/docs/i18n/ko/llm.txt index d4f4edc2de..4333283833 100644 --- a/docs/i18n/ko/llm.txt +++ b/docs/i18n/ko/llm.txt @@ -12,7 +12,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo **Key value:** One endpoint (`http://localhost:20128/v1`), unlimited models, zero downtime, minimal cost. -**Current version:** 3.8.0 +**Current version:** 3.8.1 ## Tech Stack @@ -283,7 +283,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo └── .env.example # Environment variable template ``` -## Key Features (v3.8.0) +## Key Features (v3.8.1) ### Core Proxy - **177 AI providers** with automatic format translation diff --git a/docs/i18n/mr/CHANGELOG.md b/docs/i18n/mr/CHANGELOG.md index 9df578edb5..3833a2a49f 100644 --- a/docs/i18n/mr/CHANGELOG.md +++ b/docs/i18n/mr/CHANGELOG.md @@ -6,6 +6,26 @@ ## [Unreleased] +## [3.8.1] — 2026-05-20 + +### 🔧 Bug Fixes & Refactors + +- **fix(translator):** treat `developer` role as system in OpenAI → Claude translation — `openAIToClaude` now extracts `developer`-role messages into `systemParts` (same as `system`) and filters them from the non-system message list, preventing identity context injected via the Responses API `developer` role from silently becoming an assistant turn when routing to a Claude-format provider. ([#2407](https://github.com/diegosouzapw/OmniRoute/issues/2407)) +- **fix(antigravity):** deduplicate `removeHeaderCaseInsensitive` — export canonical implementation from `antigravityClientProfile.ts` and remove the local copy in `antigravity.ts`; export `AntigravityCredentialsLike` type for cross-module use. (#2433 — thanks @Gi99lin) + +### 🔒 Security Fixes + +- **fix(security):** replace execSync string-template with spawnSync arg-array in plugin.mjs — eliminates shell command injection. +- **fix(security):** gate Electron CSP unsafe-eval on !app.isPackaged — was leaking unsafe-eval into production builds. +- **fix(api):** add requireManagementAuth to /api/usage/budget/bulk and /api/resilience/reset. +- **fix(security):** route catch-block error messages through sanitizeErrorMessage() in executors and API routes. +- **fix(codex):** refreshCredentials returns null on token refresh failure. +- **fix(tokenRefresh):** safe unknown-error access in catch block. +- **fix(combo):** reset exhaustedProviders set at start of each set-retry iteration. +- **fix(circuitBreaker):** persist and restore lastFailureKind via options JSON column. + +--- + ## [3.8.0] — 2026-05-06 ### ✨ New Features diff --git a/docs/i18n/mr/docs/reference/ENVIRONMENT.md b/docs/i18n/mr/docs/reference/ENVIRONMENT.md index 1c5f06a082..47bac3dcbc 100644 --- a/docs/i18n/mr/docs/reference/ENVIRONMENT.md +++ b/docs/i18n/mr/docs/reference/ENVIRONMENT.md @@ -339,14 +339,14 @@ process.env[`${PROVIDER_ID}_USER_AGENT`] | Variable | Default Value | When to Update | | ------------------------ | --------------------------------------------- | ------------------------------------------------------------- | -| `CLAUDE_USER_AGENT` | `claude-cli/2.1.143 (external, cli)` | When Anthropic releases a new CLI version | -| `CODEX_USER_AGENT` | `codex-cli/0.131.0 (Windows 10.0.26200; x64)` | When OpenAI updates the Codex CLI | +| `CLAUDE_USER_AGENT` | `claude-cli/2.1.145 (external, cli)` | When Anthropic releases a new CLI version | +| `CODEX_USER_AGENT` | `codex-cli/0.132.0 (Windows 10.0.26200; x64)` | When OpenAI updates the Codex CLI | | `CODEX_CLIENT_VERSION` | `0.131.0` | Override Codex client version independently of full UA string | | `GITHUB_USER_AGENT` | `GitHubCopilotChat/0.45.1` | When GitHub Copilot Chat updates | -| `ANTIGRAVITY_USER_AGENT` | `antigravity/1.107.0 darwin/arm64` | When Antigravity IDE updates | +| `ANTIGRAVITY_USER_AGENT` | `antigravity/2.0.1 darwin/arm64` | When Antigravity IDE updates | | `KIRO_USER_AGENT` | `AWS-SDK-JS/3.0.0 kiro-ide/1.0.0` | When Kiro IDE updates | | `QODER_USER_AGENT` | `Qoder-Cli` | When Qoder CLI updates | -| `QWEN_USER_AGENT` | `QwenCode/0.15.3 (linux; x64)` | When Qwen Code updates | +| `QWEN_USER_AGENT` | `QwenCode/0.15.11 (linux; x64)` | When Qwen Code updates | | `CURSOR_USER_AGENT` | `connect-es/1.6.1` | When Cursor updates | | `GEMINI_CLI_USER_AGENT` | `google-api-nodejs-client/10.3.0` | When Google API client updates | diff --git a/docs/i18n/mr/llm.txt b/docs/i18n/mr/llm.txt index f693a54905..1ca4338ae1 100644 --- a/docs/i18n/mr/llm.txt +++ b/docs/i18n/mr/llm.txt @@ -12,7 +12,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo **Key value:** One endpoint (`http://localhost:20128/v1`), unlimited models, zero downtime, minimal cost. -**Current version:** 3.8.0 +**Current version:** 3.8.1 ## Tech Stack @@ -283,7 +283,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo └── .env.example # Environment variable template ``` -## Key Features (v3.8.0) +## Key Features (v3.8.1) ### Core Proxy - **177 AI providers** with automatic format translation diff --git a/docs/i18n/ms/CHANGELOG.md b/docs/i18n/ms/CHANGELOG.md index a6f6466bd1..03a5294e8e 100644 --- a/docs/i18n/ms/CHANGELOG.md +++ b/docs/i18n/ms/CHANGELOG.md @@ -6,6 +6,26 @@ ## [Unreleased] +## [3.8.1] — 2026-05-20 + +### 🔧 Bug Fixes & Refactors + +- **fix(translator):** treat `developer` role as system in OpenAI → Claude translation — `openAIToClaude` now extracts `developer`-role messages into `systemParts` (same as `system`) and filters them from the non-system message list, preventing identity context injected via the Responses API `developer` role from silently becoming an assistant turn when routing to a Claude-format provider. ([#2407](https://github.com/diegosouzapw/OmniRoute/issues/2407)) +- **fix(antigravity):** deduplicate `removeHeaderCaseInsensitive` — export canonical implementation from `antigravityClientProfile.ts` and remove the local copy in `antigravity.ts`; export `AntigravityCredentialsLike` type for cross-module use. (#2433 — thanks @Gi99lin) + +### 🔒 Security Fixes + +- **fix(security):** replace execSync string-template with spawnSync arg-array in plugin.mjs — eliminates shell command injection. +- **fix(security):** gate Electron CSP unsafe-eval on !app.isPackaged — was leaking unsafe-eval into production builds. +- **fix(api):** add requireManagementAuth to /api/usage/budget/bulk and /api/resilience/reset. +- **fix(security):** route catch-block error messages through sanitizeErrorMessage() in executors and API routes. +- **fix(codex):** refreshCredentials returns null on token refresh failure. +- **fix(tokenRefresh):** safe unknown-error access in catch block. +- **fix(combo):** reset exhaustedProviders set at start of each set-retry iteration. +- **fix(circuitBreaker):** persist and restore lastFailureKind via options JSON column. + +--- + ## [3.8.0] — 2026-05-06 ### ✨ New Features diff --git a/docs/i18n/ms/docs/reference/ENVIRONMENT.md b/docs/i18n/ms/docs/reference/ENVIRONMENT.md index 55117024a0..25da86e65f 100644 --- a/docs/i18n/ms/docs/reference/ENVIRONMENT.md +++ b/docs/i18n/ms/docs/reference/ENVIRONMENT.md @@ -339,14 +339,14 @@ process.env[`${PROVIDER_ID}_USER_AGENT`] | Variable | Default Value | When to Update | | ------------------------ | --------------------------------------------- | ------------------------------------------------------------- | -| `CLAUDE_USER_AGENT` | `claude-cli/2.1.143 (external, cli)` | When Anthropic releases a new CLI version | -| `CODEX_USER_AGENT` | `codex-cli/0.131.0 (Windows 10.0.26200; x64)` | When OpenAI updates the Codex CLI | +| `CLAUDE_USER_AGENT` | `claude-cli/2.1.145 (external, cli)` | When Anthropic releases a new CLI version | +| `CODEX_USER_AGENT` | `codex-cli/0.132.0 (Windows 10.0.26200; x64)` | When OpenAI updates the Codex CLI | | `CODEX_CLIENT_VERSION` | `0.131.0` | Override Codex client version independently of full UA string | | `GITHUB_USER_AGENT` | `GitHubCopilotChat/0.45.1` | When GitHub Copilot Chat updates | -| `ANTIGRAVITY_USER_AGENT` | `antigravity/1.107.0 darwin/arm64` | When Antigravity IDE updates | +| `ANTIGRAVITY_USER_AGENT` | `antigravity/2.0.1 darwin/arm64` | When Antigravity IDE updates | | `KIRO_USER_AGENT` | `AWS-SDK-JS/3.0.0 kiro-ide/1.0.0` | When Kiro IDE updates | | `QODER_USER_AGENT` | `Qoder-Cli` | When Qoder CLI updates | -| `QWEN_USER_AGENT` | `QwenCode/0.15.3 (linux; x64)` | When Qwen Code updates | +| `QWEN_USER_AGENT` | `QwenCode/0.15.11 (linux; x64)` | When Qwen Code updates | | `CURSOR_USER_AGENT` | `connect-es/1.6.1` | When Cursor updates | | `GEMINI_CLI_USER_AGENT` | `google-api-nodejs-client/10.3.0` | When Google API client updates | diff --git a/docs/i18n/ms/llm.txt b/docs/i18n/ms/llm.txt index aee9daf52c..e93a769b01 100644 --- a/docs/i18n/ms/llm.txt +++ b/docs/i18n/ms/llm.txt @@ -12,7 +12,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo **Key value:** One endpoint (`http://localhost:20128/v1`), unlimited models, zero downtime, minimal cost. -**Current version:** 3.8.0 +**Current version:** 3.8.1 ## Tech Stack @@ -283,7 +283,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo └── .env.example # Environment variable template ``` -## Key Features (v3.8.0) +## Key Features (v3.8.1) ### Core Proxy - **177 AI providers** with automatic format translation diff --git a/docs/i18n/nl/CHANGELOG.md b/docs/i18n/nl/CHANGELOG.md index 20114f869a..7661ed7778 100644 --- a/docs/i18n/nl/CHANGELOG.md +++ b/docs/i18n/nl/CHANGELOG.md @@ -6,6 +6,26 @@ ## [Unreleased] +## [3.8.1] — 2026-05-20 + +### 🔧 Bug Fixes & Refactors + +- **fix(translator):** treat `developer` role as system in OpenAI → Claude translation — `openAIToClaude` now extracts `developer`-role messages into `systemParts` (same as `system`) and filters them from the non-system message list, preventing identity context injected via the Responses API `developer` role from silently becoming an assistant turn when routing to a Claude-format provider. ([#2407](https://github.com/diegosouzapw/OmniRoute/issues/2407)) +- **fix(antigravity):** deduplicate `removeHeaderCaseInsensitive` — export canonical implementation from `antigravityClientProfile.ts` and remove the local copy in `antigravity.ts`; export `AntigravityCredentialsLike` type for cross-module use. (#2433 — thanks @Gi99lin) + +### 🔒 Security Fixes + +- **fix(security):** replace execSync string-template with spawnSync arg-array in plugin.mjs — eliminates shell command injection. +- **fix(security):** gate Electron CSP unsafe-eval on !app.isPackaged — was leaking unsafe-eval into production builds. +- **fix(api):** add requireManagementAuth to /api/usage/budget/bulk and /api/resilience/reset. +- **fix(security):** route catch-block error messages through sanitizeErrorMessage() in executors and API routes. +- **fix(codex):** refreshCredentials returns null on token refresh failure. +- **fix(tokenRefresh):** safe unknown-error access in catch block. +- **fix(combo):** reset exhaustedProviders set at start of each set-retry iteration. +- **fix(circuitBreaker):** persist and restore lastFailureKind via options JSON column. + +--- + ## [3.8.0] — 2026-05-06 ### ✨ New Features diff --git a/docs/i18n/nl/docs/reference/ENVIRONMENT.md b/docs/i18n/nl/docs/reference/ENVIRONMENT.md index 4042625784..be1bb4517f 100644 --- a/docs/i18n/nl/docs/reference/ENVIRONMENT.md +++ b/docs/i18n/nl/docs/reference/ENVIRONMENT.md @@ -339,14 +339,14 @@ process.env[`${PROVIDER_ID}_USER_AGENT`] | Variable | Default Value | When to Update | | ------------------------ | --------------------------------------------- | ------------------------------------------------------------- | -| `CLAUDE_USER_AGENT` | `claude-cli/2.1.143 (external, cli)` | When Anthropic releases a new CLI version | -| `CODEX_USER_AGENT` | `codex-cli/0.131.0 (Windows 10.0.26200; x64)` | When OpenAI updates the Codex CLI | +| `CLAUDE_USER_AGENT` | `claude-cli/2.1.145 (external, cli)` | When Anthropic releases a new CLI version | +| `CODEX_USER_AGENT` | `codex-cli/0.132.0 (Windows 10.0.26200; x64)` | When OpenAI updates the Codex CLI | | `CODEX_CLIENT_VERSION` | `0.131.0` | Override Codex client version independently of full UA string | | `GITHUB_USER_AGENT` | `GitHubCopilotChat/0.45.1` | When GitHub Copilot Chat updates | -| `ANTIGRAVITY_USER_AGENT` | `antigravity/1.107.0 darwin/arm64` | When Antigravity IDE updates | +| `ANTIGRAVITY_USER_AGENT` | `antigravity/2.0.1 darwin/arm64` | When Antigravity IDE updates | | `KIRO_USER_AGENT` | `AWS-SDK-JS/3.0.0 kiro-ide/1.0.0` | When Kiro IDE updates | | `QODER_USER_AGENT` | `Qoder-Cli` | When Qoder CLI updates | -| `QWEN_USER_AGENT` | `QwenCode/0.15.3 (linux; x64)` | When Qwen Code updates | +| `QWEN_USER_AGENT` | `QwenCode/0.15.11 (linux; x64)` | When Qwen Code updates | | `CURSOR_USER_AGENT` | `connect-es/1.6.1` | When Cursor updates | | `GEMINI_CLI_USER_AGENT` | `google-api-nodejs-client/10.3.0` | When Google API client updates | diff --git a/docs/i18n/nl/llm.txt b/docs/i18n/nl/llm.txt index 11b0d6a0b8..320507f385 100644 --- a/docs/i18n/nl/llm.txt +++ b/docs/i18n/nl/llm.txt @@ -12,7 +12,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo **Key value:** One endpoint (`http://localhost:20128/v1`), unlimited models, zero downtime, minimal cost. -**Current version:** 3.8.0 +**Current version:** 3.8.1 ## Tech Stack @@ -283,7 +283,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo └── .env.example # Environment variable template ``` -## Key Features (v3.8.0) +## Key Features (v3.8.1) ### Core Proxy - **177 AI providers** with automatic format translation diff --git a/docs/i18n/no/CHANGELOG.md b/docs/i18n/no/CHANGELOG.md index 33a149fe6a..bbf45715fc 100644 --- a/docs/i18n/no/CHANGELOG.md +++ b/docs/i18n/no/CHANGELOG.md @@ -6,6 +6,26 @@ ## [Unreleased] +## [3.8.1] — 2026-05-20 + +### 🔧 Bug Fixes & Refactors + +- **fix(translator):** treat `developer` role as system in OpenAI → Claude translation — `openAIToClaude` now extracts `developer`-role messages into `systemParts` (same as `system`) and filters them from the non-system message list, preventing identity context injected via the Responses API `developer` role from silently becoming an assistant turn when routing to a Claude-format provider. ([#2407](https://github.com/diegosouzapw/OmniRoute/issues/2407)) +- **fix(antigravity):** deduplicate `removeHeaderCaseInsensitive` — export canonical implementation from `antigravityClientProfile.ts` and remove the local copy in `antigravity.ts`; export `AntigravityCredentialsLike` type for cross-module use. (#2433 — thanks @Gi99lin) + +### 🔒 Security Fixes + +- **fix(security):** replace execSync string-template with spawnSync arg-array in plugin.mjs — eliminates shell command injection. +- **fix(security):** gate Electron CSP unsafe-eval on !app.isPackaged — was leaking unsafe-eval into production builds. +- **fix(api):** add requireManagementAuth to /api/usage/budget/bulk and /api/resilience/reset. +- **fix(security):** route catch-block error messages through sanitizeErrorMessage() in executors and API routes. +- **fix(codex):** refreshCredentials returns null on token refresh failure. +- **fix(tokenRefresh):** safe unknown-error access in catch block. +- **fix(combo):** reset exhaustedProviders set at start of each set-retry iteration. +- **fix(circuitBreaker):** persist and restore lastFailureKind via options JSON column. + +--- + ## [3.8.0] — 2026-05-06 ### ✨ New Features diff --git a/docs/i18n/no/docs/reference/ENVIRONMENT.md b/docs/i18n/no/docs/reference/ENVIRONMENT.md index 343aca6ce7..10b1f8fd07 100644 --- a/docs/i18n/no/docs/reference/ENVIRONMENT.md +++ b/docs/i18n/no/docs/reference/ENVIRONMENT.md @@ -339,14 +339,14 @@ process.env[`${PROVIDER_ID}_USER_AGENT`] | Variable | Default Value | When to Update | | ------------------------ | --------------------------------------------- | ------------------------------------------------------------- | -| `CLAUDE_USER_AGENT` | `claude-cli/2.1.143 (external, cli)` | When Anthropic releases a new CLI version | -| `CODEX_USER_AGENT` | `codex-cli/0.131.0 (Windows 10.0.26200; x64)` | When OpenAI updates the Codex CLI | +| `CLAUDE_USER_AGENT` | `claude-cli/2.1.145 (external, cli)` | When Anthropic releases a new CLI version | +| `CODEX_USER_AGENT` | `codex-cli/0.132.0 (Windows 10.0.26200; x64)` | When OpenAI updates the Codex CLI | | `CODEX_CLIENT_VERSION` | `0.131.0` | Override Codex client version independently of full UA string | | `GITHUB_USER_AGENT` | `GitHubCopilotChat/0.45.1` | When GitHub Copilot Chat updates | -| `ANTIGRAVITY_USER_AGENT` | `antigravity/1.107.0 darwin/arm64` | When Antigravity IDE updates | +| `ANTIGRAVITY_USER_AGENT` | `antigravity/2.0.1 darwin/arm64` | When Antigravity IDE updates | | `KIRO_USER_AGENT` | `AWS-SDK-JS/3.0.0 kiro-ide/1.0.0` | When Kiro IDE updates | | `QODER_USER_AGENT` | `Qoder-Cli` | When Qoder CLI updates | -| `QWEN_USER_AGENT` | `QwenCode/0.15.3 (linux; x64)` | When Qwen Code updates | +| `QWEN_USER_AGENT` | `QwenCode/0.15.11 (linux; x64)` | When Qwen Code updates | | `CURSOR_USER_AGENT` | `connect-es/1.6.1` | When Cursor updates | | `GEMINI_CLI_USER_AGENT` | `google-api-nodejs-client/10.3.0` | When Google API client updates | diff --git a/docs/i18n/no/llm.txt b/docs/i18n/no/llm.txt index 10392a7a33..aee2ec11bf 100644 --- a/docs/i18n/no/llm.txt +++ b/docs/i18n/no/llm.txt @@ -12,7 +12,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo **Key value:** One endpoint (`http://localhost:20128/v1`), unlimited models, zero downtime, minimal cost. -**Current version:** 3.8.0 +**Current version:** 3.8.1 ## Tech Stack @@ -283,7 +283,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo └── .env.example # Environment variable template ``` -## Key Features (v3.8.0) +## Key Features (v3.8.1) ### Core Proxy - **177 AI providers** with automatic format translation diff --git a/docs/i18n/phi/CHANGELOG.md b/docs/i18n/phi/CHANGELOG.md index 21fc9f7a34..330a5e6c4e 100644 --- a/docs/i18n/phi/CHANGELOG.md +++ b/docs/i18n/phi/CHANGELOG.md @@ -6,6 +6,26 @@ ## [Unreleased] +## [3.8.1] — 2026-05-20 + +### 🔧 Bug Fixes & Refactors + +- **fix(translator):** treat `developer` role as system in OpenAI → Claude translation — `openAIToClaude` now extracts `developer`-role messages into `systemParts` (same as `system`) and filters them from the non-system message list, preventing identity context injected via the Responses API `developer` role from silently becoming an assistant turn when routing to a Claude-format provider. ([#2407](https://github.com/diegosouzapw/OmniRoute/issues/2407)) +- **fix(antigravity):** deduplicate `removeHeaderCaseInsensitive` — export canonical implementation from `antigravityClientProfile.ts` and remove the local copy in `antigravity.ts`; export `AntigravityCredentialsLike` type for cross-module use. (#2433 — thanks @Gi99lin) + +### 🔒 Security Fixes + +- **fix(security):** replace execSync string-template with spawnSync arg-array in plugin.mjs — eliminates shell command injection. +- **fix(security):** gate Electron CSP unsafe-eval on !app.isPackaged — was leaking unsafe-eval into production builds. +- **fix(api):** add requireManagementAuth to /api/usage/budget/bulk and /api/resilience/reset. +- **fix(security):** route catch-block error messages through sanitizeErrorMessage() in executors and API routes. +- **fix(codex):** refreshCredentials returns null on token refresh failure. +- **fix(tokenRefresh):** safe unknown-error access in catch block. +- **fix(combo):** reset exhaustedProviders set at start of each set-retry iteration. +- **fix(circuitBreaker):** persist and restore lastFailureKind via options JSON column. + +--- + ## [3.8.0] — 2026-05-06 ### ✨ New Features diff --git a/docs/i18n/phi/docs/reference/ENVIRONMENT.md b/docs/i18n/phi/docs/reference/ENVIRONMENT.md index 18b85e4e55..592c431cc1 100644 --- a/docs/i18n/phi/docs/reference/ENVIRONMENT.md +++ b/docs/i18n/phi/docs/reference/ENVIRONMENT.md @@ -339,14 +339,14 @@ process.env[`${PROVIDER_ID}_USER_AGENT`] | Variable | Default Value | When to Update | | ------------------------ | --------------------------------------------- | ------------------------------------------------------------- | -| `CLAUDE_USER_AGENT` | `claude-cli/2.1.143 (external, cli)` | When Anthropic releases a new CLI version | -| `CODEX_USER_AGENT` | `codex-cli/0.131.0 (Windows 10.0.26200; x64)` | When OpenAI updates the Codex CLI | +| `CLAUDE_USER_AGENT` | `claude-cli/2.1.145 (external, cli)` | When Anthropic releases a new CLI version | +| `CODEX_USER_AGENT` | `codex-cli/0.132.0 (Windows 10.0.26200; x64)` | When OpenAI updates the Codex CLI | | `CODEX_CLIENT_VERSION` | `0.131.0` | Override Codex client version independently of full UA string | | `GITHUB_USER_AGENT` | `GitHubCopilotChat/0.45.1` | When GitHub Copilot Chat updates | -| `ANTIGRAVITY_USER_AGENT` | `antigravity/1.107.0 darwin/arm64` | When Antigravity IDE updates | +| `ANTIGRAVITY_USER_AGENT` | `antigravity/2.0.1 darwin/arm64` | When Antigravity IDE updates | | `KIRO_USER_AGENT` | `AWS-SDK-JS/3.0.0 kiro-ide/1.0.0` | When Kiro IDE updates | | `QODER_USER_AGENT` | `Qoder-Cli` | When Qoder CLI updates | -| `QWEN_USER_AGENT` | `QwenCode/0.15.3 (linux; x64)` | When Qwen Code updates | +| `QWEN_USER_AGENT` | `QwenCode/0.15.11 (linux; x64)` | When Qwen Code updates | | `CURSOR_USER_AGENT` | `connect-es/1.6.1` | When Cursor updates | | `GEMINI_CLI_USER_AGENT` | `google-api-nodejs-client/10.3.0` | When Google API client updates | diff --git a/docs/i18n/phi/llm.txt b/docs/i18n/phi/llm.txt index f27e442e11..772f7c65dc 100644 --- a/docs/i18n/phi/llm.txt +++ b/docs/i18n/phi/llm.txt @@ -12,7 +12,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo **Key value:** One endpoint (`http://localhost:20128/v1`), unlimited models, zero downtime, minimal cost. -**Current version:** 3.8.0 +**Current version:** 3.8.1 ## Tech Stack @@ -283,7 +283,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo └── .env.example # Environment variable template ``` -## Key Features (v3.8.0) +## Key Features (v3.8.1) ### Core Proxy - **177 AI providers** with automatic format translation diff --git a/docs/i18n/pl/CHANGELOG.md b/docs/i18n/pl/CHANGELOG.md index e9a76b0f27..03638aeed7 100644 --- a/docs/i18n/pl/CHANGELOG.md +++ b/docs/i18n/pl/CHANGELOG.md @@ -6,6 +6,26 @@ ## [Unreleased] +## [3.8.1] — 2026-05-20 + +### 🔧 Bug Fixes & Refactors + +- **fix(translator):** treat `developer` role as system in OpenAI → Claude translation — `openAIToClaude` now extracts `developer`-role messages into `systemParts` (same as `system`) and filters them from the non-system message list, preventing identity context injected via the Responses API `developer` role from silently becoming an assistant turn when routing to a Claude-format provider. ([#2407](https://github.com/diegosouzapw/OmniRoute/issues/2407)) +- **fix(antigravity):** deduplicate `removeHeaderCaseInsensitive` — export canonical implementation from `antigravityClientProfile.ts` and remove the local copy in `antigravity.ts`; export `AntigravityCredentialsLike` type for cross-module use. (#2433 — thanks @Gi99lin) + +### 🔒 Security Fixes + +- **fix(security):** replace execSync string-template with spawnSync arg-array in plugin.mjs — eliminates shell command injection. +- **fix(security):** gate Electron CSP unsafe-eval on !app.isPackaged — was leaking unsafe-eval into production builds. +- **fix(api):** add requireManagementAuth to /api/usage/budget/bulk and /api/resilience/reset. +- **fix(security):** route catch-block error messages through sanitizeErrorMessage() in executors and API routes. +- **fix(codex):** refreshCredentials returns null on token refresh failure. +- **fix(tokenRefresh):** safe unknown-error access in catch block. +- **fix(combo):** reset exhaustedProviders set at start of each set-retry iteration. +- **fix(circuitBreaker):** persist and restore lastFailureKind via options JSON column. + +--- + ## [3.8.0] — 2026-05-06 ### ✨ New Features diff --git a/docs/i18n/pl/docs/reference/ENVIRONMENT.md b/docs/i18n/pl/docs/reference/ENVIRONMENT.md index cc6be0eb86..65ff1288ed 100644 --- a/docs/i18n/pl/docs/reference/ENVIRONMENT.md +++ b/docs/i18n/pl/docs/reference/ENVIRONMENT.md @@ -339,14 +339,14 @@ process.env[`${PROVIDER_ID}_USER_AGENT`] | Variable | Default Value | When to Update | | ------------------------ | --------------------------------------------- | ------------------------------------------------------------- | -| `CLAUDE_USER_AGENT` | `claude-cli/2.1.143 (external, cli)` | When Anthropic releases a new CLI version | -| `CODEX_USER_AGENT` | `codex-cli/0.131.0 (Windows 10.0.26200; x64)` | When OpenAI updates the Codex CLI | +| `CLAUDE_USER_AGENT` | `claude-cli/2.1.145 (external, cli)` | When Anthropic releases a new CLI version | +| `CODEX_USER_AGENT` | `codex-cli/0.132.0 (Windows 10.0.26200; x64)` | When OpenAI updates the Codex CLI | | `CODEX_CLIENT_VERSION` | `0.131.0` | Override Codex client version independently of full UA string | | `GITHUB_USER_AGENT` | `GitHubCopilotChat/0.45.1` | When GitHub Copilot Chat updates | -| `ANTIGRAVITY_USER_AGENT` | `antigravity/1.107.0 darwin/arm64` | When Antigravity IDE updates | +| `ANTIGRAVITY_USER_AGENT` | `antigravity/2.0.1 darwin/arm64` | When Antigravity IDE updates | | `KIRO_USER_AGENT` | `AWS-SDK-JS/3.0.0 kiro-ide/1.0.0` | When Kiro IDE updates | | `QODER_USER_AGENT` | `Qoder-Cli` | When Qoder CLI updates | -| `QWEN_USER_AGENT` | `QwenCode/0.15.3 (linux; x64)` | When Qwen Code updates | +| `QWEN_USER_AGENT` | `QwenCode/0.15.11 (linux; x64)` | When Qwen Code updates | | `CURSOR_USER_AGENT` | `connect-es/1.6.1` | When Cursor updates | | `GEMINI_CLI_USER_AGENT` | `google-api-nodejs-client/10.3.0` | When Google API client updates | diff --git a/docs/i18n/pl/llm.txt b/docs/i18n/pl/llm.txt index b436f0a750..ab88d658a2 100644 --- a/docs/i18n/pl/llm.txt +++ b/docs/i18n/pl/llm.txt @@ -12,7 +12,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo **Key value:** One endpoint (`http://localhost:20128/v1`), unlimited models, zero downtime, minimal cost. -**Current version:** 3.8.0 +**Current version:** 3.8.1 ## Tech Stack @@ -283,7 +283,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo └── .env.example # Environment variable template ``` -## Key Features (v3.8.0) +## Key Features (v3.8.1) ### Core Proxy - **177 AI providers** with automatic format translation diff --git a/docs/i18n/pt-BR/CHANGELOG.md b/docs/i18n/pt-BR/CHANGELOG.md index 7fb0975707..804127e213 100644 --- a/docs/i18n/pt-BR/CHANGELOG.md +++ b/docs/i18n/pt-BR/CHANGELOG.md @@ -6,6 +6,26 @@ ## [Unreleased] +## [3.8.1] — 2026-05-20 + +### 🔧 Bug Fixes & Refactors + +- **fix(translator):** treat `developer` role as system in OpenAI → Claude translation — `openAIToClaude` now extracts `developer`-role messages into `systemParts` (same as `system`) and filters them from the non-system message list, preventing identity context injected via the Responses API `developer` role from silently becoming an assistant turn when routing to a Claude-format provider. ([#2407](https://github.com/diegosouzapw/OmniRoute/issues/2407)) +- **fix(antigravity):** deduplicate `removeHeaderCaseInsensitive` — export canonical implementation from `antigravityClientProfile.ts` and remove the local copy in `antigravity.ts`; export `AntigravityCredentialsLike` type for cross-module use. (#2433 — thanks @Gi99lin) + +### 🔒 Security Fixes + +- **fix(security):** replace execSync string-template with spawnSync arg-array in plugin.mjs — eliminates shell command injection. +- **fix(security):** gate Electron CSP unsafe-eval on !app.isPackaged — was leaking unsafe-eval into production builds. +- **fix(api):** add requireManagementAuth to /api/usage/budget/bulk and /api/resilience/reset. +- **fix(security):** route catch-block error messages through sanitizeErrorMessage() in executors and API routes. +- **fix(codex):** refreshCredentials returns null on token refresh failure. +- **fix(tokenRefresh):** safe unknown-error access in catch block. +- **fix(combo):** reset exhaustedProviders set at start of each set-retry iteration. +- **fix(circuitBreaker):** persist and restore lastFailureKind via options JSON column. + +--- + ## [3.8.0] — 2026-05-06 ### ✨ New Features diff --git a/docs/i18n/pt-BR/docs/reference/ENVIRONMENT.md b/docs/i18n/pt-BR/docs/reference/ENVIRONMENT.md index 929ea76cf7..8716740263 100644 --- a/docs/i18n/pt-BR/docs/reference/ENVIRONMENT.md +++ b/docs/i18n/pt-BR/docs/reference/ENVIRONMENT.md @@ -339,14 +339,14 @@ process.env[`${PROVIDER_ID}_USER_AGENT`] | Variable | Default Value | When to Update | | ------------------------ | --------------------------------------------- | ------------------------------------------------------------- | -| `CLAUDE_USER_AGENT` | `claude-cli/2.1.143 (external, cli)` | When Anthropic releases a new CLI version | -| `CODEX_USER_AGENT` | `codex-cli/0.131.0 (Windows 10.0.26200; x64)` | When OpenAI updates the Codex CLI | +| `CLAUDE_USER_AGENT` | `claude-cli/2.1.145 (external, cli)` | When Anthropic releases a new CLI version | +| `CODEX_USER_AGENT` | `codex-cli/0.132.0 (Windows 10.0.26200; x64)` | When OpenAI updates the Codex CLI | | `CODEX_CLIENT_VERSION` | `0.131.0` | Override Codex client version independently of full UA string | | `GITHUB_USER_AGENT` | `GitHubCopilotChat/0.45.1` | When GitHub Copilot Chat updates | -| `ANTIGRAVITY_USER_AGENT` | `antigravity/1.107.0 darwin/arm64` | When Antigravity IDE updates | +| `ANTIGRAVITY_USER_AGENT` | `antigravity/2.0.1 darwin/arm64` | When Antigravity IDE updates | | `KIRO_USER_AGENT` | `AWS-SDK-JS/3.0.0 kiro-ide/1.0.0` | When Kiro IDE updates | | `QODER_USER_AGENT` | `Qoder-Cli` | When Qoder CLI updates | -| `QWEN_USER_AGENT` | `QwenCode/0.15.3 (linux; x64)` | When Qwen Code updates | +| `QWEN_USER_AGENT` | `QwenCode/0.15.11 (linux; x64)` | When Qwen Code updates | | `CURSOR_USER_AGENT` | `connect-es/1.6.1` | When Cursor updates | | `GEMINI_CLI_USER_AGENT` | `google-api-nodejs-client/10.3.0` | When Google API client updates | diff --git a/docs/i18n/pt-BR/llm.txt b/docs/i18n/pt-BR/llm.txt index 18691bf78e..061eeb10ff 100644 --- a/docs/i18n/pt-BR/llm.txt +++ b/docs/i18n/pt-BR/llm.txt @@ -12,7 +12,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo **Key value:** One endpoint (`http://localhost:20128/v1`), unlimited models, zero downtime, minimal cost. -**Current version:** 3.8.0 +**Current version:** 3.8.1 ## Tech Stack @@ -283,7 +283,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo └── .env.example # Environment variable template ``` -## Key Features (v3.8.0) +## Key Features (v3.8.1) ### Core Proxy - **177 AI providers** with automatic format translation diff --git a/docs/i18n/pt/CHANGELOG.md b/docs/i18n/pt/CHANGELOG.md index 33e03e4a74..8cae4d40e6 100644 --- a/docs/i18n/pt/CHANGELOG.md +++ b/docs/i18n/pt/CHANGELOG.md @@ -6,6 +6,26 @@ ## [Unreleased] +## [3.8.1] — 2026-05-20 + +### 🔧 Bug Fixes & Refactors + +- **fix(translator):** treat `developer` role as system in OpenAI → Claude translation — `openAIToClaude` now extracts `developer`-role messages into `systemParts` (same as `system`) and filters them from the non-system message list, preventing identity context injected via the Responses API `developer` role from silently becoming an assistant turn when routing to a Claude-format provider. ([#2407](https://github.com/diegosouzapw/OmniRoute/issues/2407)) +- **fix(antigravity):** deduplicate `removeHeaderCaseInsensitive` — export canonical implementation from `antigravityClientProfile.ts` and remove the local copy in `antigravity.ts`; export `AntigravityCredentialsLike` type for cross-module use. (#2433 — thanks @Gi99lin) + +### 🔒 Security Fixes + +- **fix(security):** replace execSync string-template with spawnSync arg-array in plugin.mjs — eliminates shell command injection. +- **fix(security):** gate Electron CSP unsafe-eval on !app.isPackaged — was leaking unsafe-eval into production builds. +- **fix(api):** add requireManagementAuth to /api/usage/budget/bulk and /api/resilience/reset. +- **fix(security):** route catch-block error messages through sanitizeErrorMessage() in executors and API routes. +- **fix(codex):** refreshCredentials returns null on token refresh failure. +- **fix(tokenRefresh):** safe unknown-error access in catch block. +- **fix(combo):** reset exhaustedProviders set at start of each set-retry iteration. +- **fix(circuitBreaker):** persist and restore lastFailureKind via options JSON column. + +--- + ## [3.8.0] — 2026-05-06 ### ✨ New Features diff --git a/docs/i18n/pt/docs/reference/ENVIRONMENT.md b/docs/i18n/pt/docs/reference/ENVIRONMENT.md index 25c69036d1..981b2b1dda 100644 --- a/docs/i18n/pt/docs/reference/ENVIRONMENT.md +++ b/docs/i18n/pt/docs/reference/ENVIRONMENT.md @@ -339,14 +339,14 @@ process.env[`${PROVIDER_ID}_USER_AGENT`] | Variable | Default Value | When to Update | | ------------------------ | --------------------------------------------- | ------------------------------------------------------------- | -| `CLAUDE_USER_AGENT` | `claude-cli/2.1.143 (external, cli)` | When Anthropic releases a new CLI version | -| `CODEX_USER_AGENT` | `codex-cli/0.131.0 (Windows 10.0.26200; x64)` | When OpenAI updates the Codex CLI | +| `CLAUDE_USER_AGENT` | `claude-cli/2.1.145 (external, cli)` | When Anthropic releases a new CLI version | +| `CODEX_USER_AGENT` | `codex-cli/0.132.0 (Windows 10.0.26200; x64)` | When OpenAI updates the Codex CLI | | `CODEX_CLIENT_VERSION` | `0.131.0` | Override Codex client version independently of full UA string | | `GITHUB_USER_AGENT` | `GitHubCopilotChat/0.45.1` | When GitHub Copilot Chat updates | -| `ANTIGRAVITY_USER_AGENT` | `antigravity/1.107.0 darwin/arm64` | When Antigravity IDE updates | +| `ANTIGRAVITY_USER_AGENT` | `antigravity/2.0.1 darwin/arm64` | When Antigravity IDE updates | | `KIRO_USER_AGENT` | `AWS-SDK-JS/3.0.0 kiro-ide/1.0.0` | When Kiro IDE updates | | `QODER_USER_AGENT` | `Qoder-Cli` | When Qoder CLI updates | -| `QWEN_USER_AGENT` | `QwenCode/0.15.3 (linux; x64)` | When Qwen Code updates | +| `QWEN_USER_AGENT` | `QwenCode/0.15.11 (linux; x64)` | When Qwen Code updates | | `CURSOR_USER_AGENT` | `connect-es/1.6.1` | When Cursor updates | | `GEMINI_CLI_USER_AGENT` | `google-api-nodejs-client/10.3.0` | When Google API client updates | diff --git a/docs/i18n/pt/llm.txt b/docs/i18n/pt/llm.txt index f1b6767c7e..49af962e90 100644 --- a/docs/i18n/pt/llm.txt +++ b/docs/i18n/pt/llm.txt @@ -12,7 +12,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo **Key value:** One endpoint (`http://localhost:20128/v1`), unlimited models, zero downtime, minimal cost. -**Current version:** 3.8.0 +**Current version:** 3.8.1 ## Tech Stack @@ -283,7 +283,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo └── .env.example # Environment variable template ``` -## Key Features (v3.8.0) +## Key Features (v3.8.1) ### Core Proxy - **177 AI providers** with automatic format translation diff --git a/docs/i18n/ro/CHANGELOG.md b/docs/i18n/ro/CHANGELOG.md index 6bc375d41e..8b7bef443b 100644 --- a/docs/i18n/ro/CHANGELOG.md +++ b/docs/i18n/ro/CHANGELOG.md @@ -6,6 +6,26 @@ ## [Unreleased] +## [3.8.1] — 2026-05-20 + +### 🔧 Bug Fixes & Refactors + +- **fix(translator):** treat `developer` role as system in OpenAI → Claude translation — `openAIToClaude` now extracts `developer`-role messages into `systemParts` (same as `system`) and filters them from the non-system message list, preventing identity context injected via the Responses API `developer` role from silently becoming an assistant turn when routing to a Claude-format provider. ([#2407](https://github.com/diegosouzapw/OmniRoute/issues/2407)) +- **fix(antigravity):** deduplicate `removeHeaderCaseInsensitive` — export canonical implementation from `antigravityClientProfile.ts` and remove the local copy in `antigravity.ts`; export `AntigravityCredentialsLike` type for cross-module use. (#2433 — thanks @Gi99lin) + +### 🔒 Security Fixes + +- **fix(security):** replace execSync string-template with spawnSync arg-array in plugin.mjs — eliminates shell command injection. +- **fix(security):** gate Electron CSP unsafe-eval on !app.isPackaged — was leaking unsafe-eval into production builds. +- **fix(api):** add requireManagementAuth to /api/usage/budget/bulk and /api/resilience/reset. +- **fix(security):** route catch-block error messages through sanitizeErrorMessage() in executors and API routes. +- **fix(codex):** refreshCredentials returns null on token refresh failure. +- **fix(tokenRefresh):** safe unknown-error access in catch block. +- **fix(combo):** reset exhaustedProviders set at start of each set-retry iteration. +- **fix(circuitBreaker):** persist and restore lastFailureKind via options JSON column. + +--- + ## [3.8.0] — 2026-05-06 ### ✨ New Features diff --git a/docs/i18n/ro/docs/reference/ENVIRONMENT.md b/docs/i18n/ro/docs/reference/ENVIRONMENT.md index 19f31c7c97..72b61fa749 100644 --- a/docs/i18n/ro/docs/reference/ENVIRONMENT.md +++ b/docs/i18n/ro/docs/reference/ENVIRONMENT.md @@ -339,14 +339,14 @@ process.env[`${PROVIDER_ID}_USER_AGENT`] | Variable | Default Value | When to Update | | ------------------------ | --------------------------------------------- | ------------------------------------------------------------- | -| `CLAUDE_USER_AGENT` | `claude-cli/2.1.143 (external, cli)` | When Anthropic releases a new CLI version | -| `CODEX_USER_AGENT` | `codex-cli/0.131.0 (Windows 10.0.26200; x64)` | When OpenAI updates the Codex CLI | +| `CLAUDE_USER_AGENT` | `claude-cli/2.1.145 (external, cli)` | When Anthropic releases a new CLI version | +| `CODEX_USER_AGENT` | `codex-cli/0.132.0 (Windows 10.0.26200; x64)` | When OpenAI updates the Codex CLI | | `CODEX_CLIENT_VERSION` | `0.131.0` | Override Codex client version independently of full UA string | | `GITHUB_USER_AGENT` | `GitHubCopilotChat/0.45.1` | When GitHub Copilot Chat updates | -| `ANTIGRAVITY_USER_AGENT` | `antigravity/1.107.0 darwin/arm64` | When Antigravity IDE updates | +| `ANTIGRAVITY_USER_AGENT` | `antigravity/2.0.1 darwin/arm64` | When Antigravity IDE updates | | `KIRO_USER_AGENT` | `AWS-SDK-JS/3.0.0 kiro-ide/1.0.0` | When Kiro IDE updates | | `QODER_USER_AGENT` | `Qoder-Cli` | When Qoder CLI updates | -| `QWEN_USER_AGENT` | `QwenCode/0.15.3 (linux; x64)` | When Qwen Code updates | +| `QWEN_USER_AGENT` | `QwenCode/0.15.11 (linux; x64)` | When Qwen Code updates | | `CURSOR_USER_AGENT` | `connect-es/1.6.1` | When Cursor updates | | `GEMINI_CLI_USER_AGENT` | `google-api-nodejs-client/10.3.0` | When Google API client updates | diff --git a/docs/i18n/ro/llm.txt b/docs/i18n/ro/llm.txt index 1925e4a819..2f89d40c14 100644 --- a/docs/i18n/ro/llm.txt +++ b/docs/i18n/ro/llm.txt @@ -12,7 +12,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo **Key value:** One endpoint (`http://localhost:20128/v1`), unlimited models, zero downtime, minimal cost. -**Current version:** 3.8.0 +**Current version:** 3.8.1 ## Tech Stack @@ -283,7 +283,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo └── .env.example # Environment variable template ``` -## Key Features (v3.8.0) +## Key Features (v3.8.1) ### Core Proxy - **177 AI providers** with automatic format translation diff --git a/docs/i18n/ru/CHANGELOG.md b/docs/i18n/ru/CHANGELOG.md index a256dc2267..e5377997f6 100644 --- a/docs/i18n/ru/CHANGELOG.md +++ b/docs/i18n/ru/CHANGELOG.md @@ -6,6 +6,26 @@ ## [Unreleased] +## [3.8.1] — 2026-05-20 + +### 🔧 Bug Fixes & Refactors + +- **fix(translator):** treat `developer` role as system in OpenAI → Claude translation — `openAIToClaude` now extracts `developer`-role messages into `systemParts` (same as `system`) and filters them from the non-system message list, preventing identity context injected via the Responses API `developer` role from silently becoming an assistant turn when routing to a Claude-format provider. ([#2407](https://github.com/diegosouzapw/OmniRoute/issues/2407)) +- **fix(antigravity):** deduplicate `removeHeaderCaseInsensitive` — export canonical implementation from `antigravityClientProfile.ts` and remove the local copy in `antigravity.ts`; export `AntigravityCredentialsLike` type for cross-module use. (#2433 — thanks @Gi99lin) + +### 🔒 Security Fixes + +- **fix(security):** replace execSync string-template with spawnSync arg-array in plugin.mjs — eliminates shell command injection. +- **fix(security):** gate Electron CSP unsafe-eval on !app.isPackaged — was leaking unsafe-eval into production builds. +- **fix(api):** add requireManagementAuth to /api/usage/budget/bulk and /api/resilience/reset. +- **fix(security):** route catch-block error messages through sanitizeErrorMessage() in executors and API routes. +- **fix(codex):** refreshCredentials returns null on token refresh failure. +- **fix(tokenRefresh):** safe unknown-error access in catch block. +- **fix(combo):** reset exhaustedProviders set at start of each set-retry iteration. +- **fix(circuitBreaker):** persist and restore lastFailureKind via options JSON column. + +--- + ## [3.8.0] — 2026-05-06 ### ✨ New Features diff --git a/docs/i18n/ru/docs/reference/ENVIRONMENT.md b/docs/i18n/ru/docs/reference/ENVIRONMENT.md index cfed4b0387..7e8a2f86ba 100644 --- a/docs/i18n/ru/docs/reference/ENVIRONMENT.md +++ b/docs/i18n/ru/docs/reference/ENVIRONMENT.md @@ -339,14 +339,14 @@ process.env[`${PROVIDER_ID}_USER_AGENT`] | Variable | Default Value | When to Update | | ------------------------ | --------------------------------------------- | ------------------------------------------------------------- | -| `CLAUDE_USER_AGENT` | `claude-cli/2.1.143 (external, cli)` | When Anthropic releases a new CLI version | -| `CODEX_USER_AGENT` | `codex-cli/0.131.0 (Windows 10.0.26200; x64)` | When OpenAI updates the Codex CLI | +| `CLAUDE_USER_AGENT` | `claude-cli/2.1.145 (external, cli)` | When Anthropic releases a new CLI version | +| `CODEX_USER_AGENT` | `codex-cli/0.132.0 (Windows 10.0.26200; x64)` | When OpenAI updates the Codex CLI | | `CODEX_CLIENT_VERSION` | `0.131.0` | Override Codex client version independently of full UA string | | `GITHUB_USER_AGENT` | `GitHubCopilotChat/0.45.1` | When GitHub Copilot Chat updates | -| `ANTIGRAVITY_USER_AGENT` | `antigravity/1.107.0 darwin/arm64` | When Antigravity IDE updates | +| `ANTIGRAVITY_USER_AGENT` | `antigravity/2.0.1 darwin/arm64` | When Antigravity IDE updates | | `KIRO_USER_AGENT` | `AWS-SDK-JS/3.0.0 kiro-ide/1.0.0` | When Kiro IDE updates | | `QODER_USER_AGENT` | `Qoder-Cli` | When Qoder CLI updates | -| `QWEN_USER_AGENT` | `QwenCode/0.15.3 (linux; x64)` | When Qwen Code updates | +| `QWEN_USER_AGENT` | `QwenCode/0.15.11 (linux; x64)` | When Qwen Code updates | | `CURSOR_USER_AGENT` | `connect-es/1.6.1` | When Cursor updates | | `GEMINI_CLI_USER_AGENT` | `google-api-nodejs-client/10.3.0` | When Google API client updates | diff --git a/docs/i18n/ru/llm.txt b/docs/i18n/ru/llm.txt index f39b397892..817d8a1749 100644 --- a/docs/i18n/ru/llm.txt +++ b/docs/i18n/ru/llm.txt @@ -12,7 +12,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo **Key value:** One endpoint (`http://localhost:20128/v1`), unlimited models, zero downtime, minimal cost. -**Current version:** 3.8.0 +**Current version:** 3.8.1 ## Tech Stack @@ -283,7 +283,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo └── .env.example # Environment variable template ``` -## Key Features (v3.8.0) +## Key Features (v3.8.1) ### Core Proxy - **177 AI providers** with automatic format translation diff --git a/docs/i18n/sk/CHANGELOG.md b/docs/i18n/sk/CHANGELOG.md index 6a49f5b712..16c1837dab 100644 --- a/docs/i18n/sk/CHANGELOG.md +++ b/docs/i18n/sk/CHANGELOG.md @@ -6,6 +6,26 @@ ## [Unreleased] +## [3.8.1] — 2026-05-20 + +### 🔧 Bug Fixes & Refactors + +- **fix(translator):** treat `developer` role as system in OpenAI → Claude translation — `openAIToClaude` now extracts `developer`-role messages into `systemParts` (same as `system`) and filters them from the non-system message list, preventing identity context injected via the Responses API `developer` role from silently becoming an assistant turn when routing to a Claude-format provider. ([#2407](https://github.com/diegosouzapw/OmniRoute/issues/2407)) +- **fix(antigravity):** deduplicate `removeHeaderCaseInsensitive` — export canonical implementation from `antigravityClientProfile.ts` and remove the local copy in `antigravity.ts`; export `AntigravityCredentialsLike` type for cross-module use. (#2433 — thanks @Gi99lin) + +### 🔒 Security Fixes + +- **fix(security):** replace execSync string-template with spawnSync arg-array in plugin.mjs — eliminates shell command injection. +- **fix(security):** gate Electron CSP unsafe-eval on !app.isPackaged — was leaking unsafe-eval into production builds. +- **fix(api):** add requireManagementAuth to /api/usage/budget/bulk and /api/resilience/reset. +- **fix(security):** route catch-block error messages through sanitizeErrorMessage() in executors and API routes. +- **fix(codex):** refreshCredentials returns null on token refresh failure. +- **fix(tokenRefresh):** safe unknown-error access in catch block. +- **fix(combo):** reset exhaustedProviders set at start of each set-retry iteration. +- **fix(circuitBreaker):** persist and restore lastFailureKind via options JSON column. + +--- + ## [3.8.0] — 2026-05-06 ### ✨ New Features diff --git a/docs/i18n/sk/docs/reference/ENVIRONMENT.md b/docs/i18n/sk/docs/reference/ENVIRONMENT.md index cf3c39b401..cfb2390527 100644 --- a/docs/i18n/sk/docs/reference/ENVIRONMENT.md +++ b/docs/i18n/sk/docs/reference/ENVIRONMENT.md @@ -339,14 +339,14 @@ process.env[`${PROVIDER_ID}_USER_AGENT`] | Variable | Default Value | When to Update | | ------------------------ | --------------------------------------------- | ------------------------------------------------------------- | -| `CLAUDE_USER_AGENT` | `claude-cli/2.1.143 (external, cli)` | When Anthropic releases a new CLI version | -| `CODEX_USER_AGENT` | `codex-cli/0.131.0 (Windows 10.0.26200; x64)` | When OpenAI updates the Codex CLI | +| `CLAUDE_USER_AGENT` | `claude-cli/2.1.145 (external, cli)` | When Anthropic releases a new CLI version | +| `CODEX_USER_AGENT` | `codex-cli/0.132.0 (Windows 10.0.26200; x64)` | When OpenAI updates the Codex CLI | | `CODEX_CLIENT_VERSION` | `0.131.0` | Override Codex client version independently of full UA string | | `GITHUB_USER_AGENT` | `GitHubCopilotChat/0.45.1` | When GitHub Copilot Chat updates | -| `ANTIGRAVITY_USER_AGENT` | `antigravity/1.107.0 darwin/arm64` | When Antigravity IDE updates | +| `ANTIGRAVITY_USER_AGENT` | `antigravity/2.0.1 darwin/arm64` | When Antigravity IDE updates | | `KIRO_USER_AGENT` | `AWS-SDK-JS/3.0.0 kiro-ide/1.0.0` | When Kiro IDE updates | | `QODER_USER_AGENT` | `Qoder-Cli` | When Qoder CLI updates | -| `QWEN_USER_AGENT` | `QwenCode/0.15.3 (linux; x64)` | When Qwen Code updates | +| `QWEN_USER_AGENT` | `QwenCode/0.15.11 (linux; x64)` | When Qwen Code updates | | `CURSOR_USER_AGENT` | `connect-es/1.6.1` | When Cursor updates | | `GEMINI_CLI_USER_AGENT` | `google-api-nodejs-client/10.3.0` | When Google API client updates | diff --git a/docs/i18n/sk/llm.txt b/docs/i18n/sk/llm.txt index 0d17744569..262ee4b859 100644 --- a/docs/i18n/sk/llm.txt +++ b/docs/i18n/sk/llm.txt @@ -12,7 +12,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo **Key value:** One endpoint (`http://localhost:20128/v1`), unlimited models, zero downtime, minimal cost. -**Current version:** 3.8.0 +**Current version:** 3.8.1 ## Tech Stack @@ -283,7 +283,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo └── .env.example # Environment variable template ``` -## Key Features (v3.8.0) +## Key Features (v3.8.1) ### Core Proxy - **177 AI providers** with automatic format translation diff --git a/docs/i18n/sv/CHANGELOG.md b/docs/i18n/sv/CHANGELOG.md index bffa975e25..8f94f974fc 100644 --- a/docs/i18n/sv/CHANGELOG.md +++ b/docs/i18n/sv/CHANGELOG.md @@ -6,6 +6,26 @@ ## [Unreleased] +## [3.8.1] — 2026-05-20 + +### 🔧 Bug Fixes & Refactors + +- **fix(translator):** treat `developer` role as system in OpenAI → Claude translation — `openAIToClaude` now extracts `developer`-role messages into `systemParts` (same as `system`) and filters them from the non-system message list, preventing identity context injected via the Responses API `developer` role from silently becoming an assistant turn when routing to a Claude-format provider. ([#2407](https://github.com/diegosouzapw/OmniRoute/issues/2407)) +- **fix(antigravity):** deduplicate `removeHeaderCaseInsensitive` — export canonical implementation from `antigravityClientProfile.ts` and remove the local copy in `antigravity.ts`; export `AntigravityCredentialsLike` type for cross-module use. (#2433 — thanks @Gi99lin) + +### 🔒 Security Fixes + +- **fix(security):** replace execSync string-template with spawnSync arg-array in plugin.mjs — eliminates shell command injection. +- **fix(security):** gate Electron CSP unsafe-eval on !app.isPackaged — was leaking unsafe-eval into production builds. +- **fix(api):** add requireManagementAuth to /api/usage/budget/bulk and /api/resilience/reset. +- **fix(security):** route catch-block error messages through sanitizeErrorMessage() in executors and API routes. +- **fix(codex):** refreshCredentials returns null on token refresh failure. +- **fix(tokenRefresh):** safe unknown-error access in catch block. +- **fix(combo):** reset exhaustedProviders set at start of each set-retry iteration. +- **fix(circuitBreaker):** persist and restore lastFailureKind via options JSON column. + +--- + ## [3.8.0] — 2026-05-06 ### ✨ New Features diff --git a/docs/i18n/sv/docs/reference/ENVIRONMENT.md b/docs/i18n/sv/docs/reference/ENVIRONMENT.md index 65b4d7362b..c635a467c4 100644 --- a/docs/i18n/sv/docs/reference/ENVIRONMENT.md +++ b/docs/i18n/sv/docs/reference/ENVIRONMENT.md @@ -339,14 +339,14 @@ process.env[`${PROVIDER_ID}_USER_AGENT`] | Variable | Default Value | When to Update | | ------------------------ | --------------------------------------------- | ------------------------------------------------------------- | -| `CLAUDE_USER_AGENT` | `claude-cli/2.1.143 (external, cli)` | When Anthropic releases a new CLI version | -| `CODEX_USER_AGENT` | `codex-cli/0.131.0 (Windows 10.0.26200; x64)` | When OpenAI updates the Codex CLI | +| `CLAUDE_USER_AGENT` | `claude-cli/2.1.145 (external, cli)` | When Anthropic releases a new CLI version | +| `CODEX_USER_AGENT` | `codex-cli/0.132.0 (Windows 10.0.26200; x64)` | When OpenAI updates the Codex CLI | | `CODEX_CLIENT_VERSION` | `0.131.0` | Override Codex client version independently of full UA string | | `GITHUB_USER_AGENT` | `GitHubCopilotChat/0.45.1` | When GitHub Copilot Chat updates | -| `ANTIGRAVITY_USER_AGENT` | `antigravity/1.107.0 darwin/arm64` | When Antigravity IDE updates | +| `ANTIGRAVITY_USER_AGENT` | `antigravity/2.0.1 darwin/arm64` | When Antigravity IDE updates | | `KIRO_USER_AGENT` | `AWS-SDK-JS/3.0.0 kiro-ide/1.0.0` | When Kiro IDE updates | | `QODER_USER_AGENT` | `Qoder-Cli` | When Qoder CLI updates | -| `QWEN_USER_AGENT` | `QwenCode/0.15.3 (linux; x64)` | When Qwen Code updates | +| `QWEN_USER_AGENT` | `QwenCode/0.15.11 (linux; x64)` | When Qwen Code updates | | `CURSOR_USER_AGENT` | `connect-es/1.6.1` | When Cursor updates | | `GEMINI_CLI_USER_AGENT` | `google-api-nodejs-client/10.3.0` | When Google API client updates | diff --git a/docs/i18n/sv/llm.txt b/docs/i18n/sv/llm.txt index e0fcd2624e..d762517fc1 100644 --- a/docs/i18n/sv/llm.txt +++ b/docs/i18n/sv/llm.txt @@ -12,7 +12,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo **Key value:** One endpoint (`http://localhost:20128/v1`), unlimited models, zero downtime, minimal cost. -**Current version:** 3.8.0 +**Current version:** 3.8.1 ## Tech Stack @@ -283,7 +283,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo └── .env.example # Environment variable template ``` -## Key Features (v3.8.0) +## Key Features (v3.8.1) ### Core Proxy - **177 AI providers** with automatic format translation diff --git a/docs/i18n/sw/CHANGELOG.md b/docs/i18n/sw/CHANGELOG.md index 2e661aafda..7e192256b3 100644 --- a/docs/i18n/sw/CHANGELOG.md +++ b/docs/i18n/sw/CHANGELOG.md @@ -6,6 +6,26 @@ ## [Unreleased] +## [3.8.1] — 2026-05-20 + +### 🔧 Bug Fixes & Refactors + +- **fix(translator):** treat `developer` role as system in OpenAI → Claude translation — `openAIToClaude` now extracts `developer`-role messages into `systemParts` (same as `system`) and filters them from the non-system message list, preventing identity context injected via the Responses API `developer` role from silently becoming an assistant turn when routing to a Claude-format provider. ([#2407](https://github.com/diegosouzapw/OmniRoute/issues/2407)) +- **fix(antigravity):** deduplicate `removeHeaderCaseInsensitive` — export canonical implementation from `antigravityClientProfile.ts` and remove the local copy in `antigravity.ts`; export `AntigravityCredentialsLike` type for cross-module use. (#2433 — thanks @Gi99lin) + +### 🔒 Security Fixes + +- **fix(security):** replace execSync string-template with spawnSync arg-array in plugin.mjs — eliminates shell command injection. +- **fix(security):** gate Electron CSP unsafe-eval on !app.isPackaged — was leaking unsafe-eval into production builds. +- **fix(api):** add requireManagementAuth to /api/usage/budget/bulk and /api/resilience/reset. +- **fix(security):** route catch-block error messages through sanitizeErrorMessage() in executors and API routes. +- **fix(codex):** refreshCredentials returns null on token refresh failure. +- **fix(tokenRefresh):** safe unknown-error access in catch block. +- **fix(combo):** reset exhaustedProviders set at start of each set-retry iteration. +- **fix(circuitBreaker):** persist and restore lastFailureKind via options JSON column. + +--- + ## [3.8.0] — 2026-05-06 ### ✨ New Features diff --git a/docs/i18n/sw/docs/reference/ENVIRONMENT.md b/docs/i18n/sw/docs/reference/ENVIRONMENT.md index de58be7d59..cc72d3a6ef 100644 --- a/docs/i18n/sw/docs/reference/ENVIRONMENT.md +++ b/docs/i18n/sw/docs/reference/ENVIRONMENT.md @@ -339,14 +339,14 @@ process.env[`${PROVIDER_ID}_USER_AGENT`] | Variable | Default Value | When to Update | | ------------------------ | --------------------------------------------- | ------------------------------------------------------------- | -| `CLAUDE_USER_AGENT` | `claude-cli/2.1.143 (external, cli)` | When Anthropic releases a new CLI version | -| `CODEX_USER_AGENT` | `codex-cli/0.131.0 (Windows 10.0.26200; x64)` | When OpenAI updates the Codex CLI | +| `CLAUDE_USER_AGENT` | `claude-cli/2.1.145 (external, cli)` | When Anthropic releases a new CLI version | +| `CODEX_USER_AGENT` | `codex-cli/0.132.0 (Windows 10.0.26200; x64)` | When OpenAI updates the Codex CLI | | `CODEX_CLIENT_VERSION` | `0.131.0` | Override Codex client version independently of full UA string | | `GITHUB_USER_AGENT` | `GitHubCopilotChat/0.45.1` | When GitHub Copilot Chat updates | -| `ANTIGRAVITY_USER_AGENT` | `antigravity/1.107.0 darwin/arm64` | When Antigravity IDE updates | +| `ANTIGRAVITY_USER_AGENT` | `antigravity/2.0.1 darwin/arm64` | When Antigravity IDE updates | | `KIRO_USER_AGENT` | `AWS-SDK-JS/3.0.0 kiro-ide/1.0.0` | When Kiro IDE updates | | `QODER_USER_AGENT` | `Qoder-Cli` | When Qoder CLI updates | -| `QWEN_USER_AGENT` | `QwenCode/0.15.3 (linux; x64)` | When Qwen Code updates | +| `QWEN_USER_AGENT` | `QwenCode/0.15.11 (linux; x64)` | When Qwen Code updates | | `CURSOR_USER_AGENT` | `connect-es/1.6.1` | When Cursor updates | | `GEMINI_CLI_USER_AGENT` | `google-api-nodejs-client/10.3.0` | When Google API client updates | diff --git a/docs/i18n/sw/llm.txt b/docs/i18n/sw/llm.txt index e249cf8679..1593d0dc49 100644 --- a/docs/i18n/sw/llm.txt +++ b/docs/i18n/sw/llm.txt @@ -12,7 +12,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo **Key value:** One endpoint (`http://localhost:20128/v1`), unlimited models, zero downtime, minimal cost. -**Current version:** 3.8.0 +**Current version:** 3.8.1 ## Tech Stack @@ -283,7 +283,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo └── .env.example # Environment variable template ``` -## Key Features (v3.8.0) +## Key Features (v3.8.1) ### Core Proxy - **177 AI providers** with automatic format translation diff --git a/docs/i18n/ta/CHANGELOG.md b/docs/i18n/ta/CHANGELOG.md index 1c03625bae..ae45a485d0 100644 --- a/docs/i18n/ta/CHANGELOG.md +++ b/docs/i18n/ta/CHANGELOG.md @@ -6,6 +6,26 @@ ## [Unreleased] +## [3.8.1] — 2026-05-20 + +### 🔧 Bug Fixes & Refactors + +- **fix(translator):** treat `developer` role as system in OpenAI → Claude translation — `openAIToClaude` now extracts `developer`-role messages into `systemParts` (same as `system`) and filters them from the non-system message list, preventing identity context injected via the Responses API `developer` role from silently becoming an assistant turn when routing to a Claude-format provider. ([#2407](https://github.com/diegosouzapw/OmniRoute/issues/2407)) +- **fix(antigravity):** deduplicate `removeHeaderCaseInsensitive` — export canonical implementation from `antigravityClientProfile.ts` and remove the local copy in `antigravity.ts`; export `AntigravityCredentialsLike` type for cross-module use. (#2433 — thanks @Gi99lin) + +### 🔒 Security Fixes + +- **fix(security):** replace execSync string-template with spawnSync arg-array in plugin.mjs — eliminates shell command injection. +- **fix(security):** gate Electron CSP unsafe-eval on !app.isPackaged — was leaking unsafe-eval into production builds. +- **fix(api):** add requireManagementAuth to /api/usage/budget/bulk and /api/resilience/reset. +- **fix(security):** route catch-block error messages through sanitizeErrorMessage() in executors and API routes. +- **fix(codex):** refreshCredentials returns null on token refresh failure. +- **fix(tokenRefresh):** safe unknown-error access in catch block. +- **fix(combo):** reset exhaustedProviders set at start of each set-retry iteration. +- **fix(circuitBreaker):** persist and restore lastFailureKind via options JSON column. + +--- + ## [3.8.0] — 2026-05-06 ### ✨ New Features diff --git a/docs/i18n/ta/docs/reference/ENVIRONMENT.md b/docs/i18n/ta/docs/reference/ENVIRONMENT.md index 9bf23a0682..dba373dedc 100644 --- a/docs/i18n/ta/docs/reference/ENVIRONMENT.md +++ b/docs/i18n/ta/docs/reference/ENVIRONMENT.md @@ -339,14 +339,14 @@ process.env[`${PROVIDER_ID}_USER_AGENT`] | Variable | Default Value | When to Update | | ------------------------ | --------------------------------------------- | ------------------------------------------------------------- | -| `CLAUDE_USER_AGENT` | `claude-cli/2.1.143 (external, cli)` | When Anthropic releases a new CLI version | -| `CODEX_USER_AGENT` | `codex-cli/0.131.0 (Windows 10.0.26200; x64)` | When OpenAI updates the Codex CLI | +| `CLAUDE_USER_AGENT` | `claude-cli/2.1.145 (external, cli)` | When Anthropic releases a new CLI version | +| `CODEX_USER_AGENT` | `codex-cli/0.132.0 (Windows 10.0.26200; x64)` | When OpenAI updates the Codex CLI | | `CODEX_CLIENT_VERSION` | `0.131.0` | Override Codex client version independently of full UA string | | `GITHUB_USER_AGENT` | `GitHubCopilotChat/0.45.1` | When GitHub Copilot Chat updates | -| `ANTIGRAVITY_USER_AGENT` | `antigravity/1.107.0 darwin/arm64` | When Antigravity IDE updates | +| `ANTIGRAVITY_USER_AGENT` | `antigravity/2.0.1 darwin/arm64` | When Antigravity IDE updates | | `KIRO_USER_AGENT` | `AWS-SDK-JS/3.0.0 kiro-ide/1.0.0` | When Kiro IDE updates | | `QODER_USER_AGENT` | `Qoder-Cli` | When Qoder CLI updates | -| `QWEN_USER_AGENT` | `QwenCode/0.15.3 (linux; x64)` | When Qwen Code updates | +| `QWEN_USER_AGENT` | `QwenCode/0.15.11 (linux; x64)` | When Qwen Code updates | | `CURSOR_USER_AGENT` | `connect-es/1.6.1` | When Cursor updates | | `GEMINI_CLI_USER_AGENT` | `google-api-nodejs-client/10.3.0` | When Google API client updates | diff --git a/docs/i18n/ta/llm.txt b/docs/i18n/ta/llm.txt index d08af4df34..0af373d59c 100644 --- a/docs/i18n/ta/llm.txt +++ b/docs/i18n/ta/llm.txt @@ -12,7 +12,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo **Key value:** One endpoint (`http://localhost:20128/v1`), unlimited models, zero downtime, minimal cost. -**Current version:** 3.8.0 +**Current version:** 3.8.1 ## Tech Stack @@ -283,7 +283,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo └── .env.example # Environment variable template ``` -## Key Features (v3.8.0) +## Key Features (v3.8.1) ### Core Proxy - **177 AI providers** with automatic format translation diff --git a/docs/i18n/te/CHANGELOG.md b/docs/i18n/te/CHANGELOG.md index cdab749d1f..8d56c098cc 100644 --- a/docs/i18n/te/CHANGELOG.md +++ b/docs/i18n/te/CHANGELOG.md @@ -6,6 +6,26 @@ ## [Unreleased] +## [3.8.1] — 2026-05-20 + +### 🔧 Bug Fixes & Refactors + +- **fix(translator):** treat `developer` role as system in OpenAI → Claude translation — `openAIToClaude` now extracts `developer`-role messages into `systemParts` (same as `system`) and filters them from the non-system message list, preventing identity context injected via the Responses API `developer` role from silently becoming an assistant turn when routing to a Claude-format provider. ([#2407](https://github.com/diegosouzapw/OmniRoute/issues/2407)) +- **fix(antigravity):** deduplicate `removeHeaderCaseInsensitive` — export canonical implementation from `antigravityClientProfile.ts` and remove the local copy in `antigravity.ts`; export `AntigravityCredentialsLike` type for cross-module use. (#2433 — thanks @Gi99lin) + +### 🔒 Security Fixes + +- **fix(security):** replace execSync string-template with spawnSync arg-array in plugin.mjs — eliminates shell command injection. +- **fix(security):** gate Electron CSP unsafe-eval on !app.isPackaged — was leaking unsafe-eval into production builds. +- **fix(api):** add requireManagementAuth to /api/usage/budget/bulk and /api/resilience/reset. +- **fix(security):** route catch-block error messages through sanitizeErrorMessage() in executors and API routes. +- **fix(codex):** refreshCredentials returns null on token refresh failure. +- **fix(tokenRefresh):** safe unknown-error access in catch block. +- **fix(combo):** reset exhaustedProviders set at start of each set-retry iteration. +- **fix(circuitBreaker):** persist and restore lastFailureKind via options JSON column. + +--- + ## [3.8.0] — 2026-05-06 ### ✨ New Features diff --git a/docs/i18n/te/docs/reference/ENVIRONMENT.md b/docs/i18n/te/docs/reference/ENVIRONMENT.md index 907a2afe06..1c25ef8b56 100644 --- a/docs/i18n/te/docs/reference/ENVIRONMENT.md +++ b/docs/i18n/te/docs/reference/ENVIRONMENT.md @@ -339,14 +339,14 @@ process.env[`${PROVIDER_ID}_USER_AGENT`] | Variable | Default Value | When to Update | | ------------------------ | --------------------------------------------- | ------------------------------------------------------------- | -| `CLAUDE_USER_AGENT` | `claude-cli/2.1.143 (external, cli)` | When Anthropic releases a new CLI version | -| `CODEX_USER_AGENT` | `codex-cli/0.131.0 (Windows 10.0.26200; x64)` | When OpenAI updates the Codex CLI | +| `CLAUDE_USER_AGENT` | `claude-cli/2.1.145 (external, cli)` | When Anthropic releases a new CLI version | +| `CODEX_USER_AGENT` | `codex-cli/0.132.0 (Windows 10.0.26200; x64)` | When OpenAI updates the Codex CLI | | `CODEX_CLIENT_VERSION` | `0.131.0` | Override Codex client version independently of full UA string | | `GITHUB_USER_AGENT` | `GitHubCopilotChat/0.45.1` | When GitHub Copilot Chat updates | -| `ANTIGRAVITY_USER_AGENT` | `antigravity/1.107.0 darwin/arm64` | When Antigravity IDE updates | +| `ANTIGRAVITY_USER_AGENT` | `antigravity/2.0.1 darwin/arm64` | When Antigravity IDE updates | | `KIRO_USER_AGENT` | `AWS-SDK-JS/3.0.0 kiro-ide/1.0.0` | When Kiro IDE updates | | `QODER_USER_AGENT` | `Qoder-Cli` | When Qoder CLI updates | -| `QWEN_USER_AGENT` | `QwenCode/0.15.3 (linux; x64)` | When Qwen Code updates | +| `QWEN_USER_AGENT` | `QwenCode/0.15.11 (linux; x64)` | When Qwen Code updates | | `CURSOR_USER_AGENT` | `connect-es/1.6.1` | When Cursor updates | | `GEMINI_CLI_USER_AGENT` | `google-api-nodejs-client/10.3.0` | When Google API client updates | diff --git a/docs/i18n/te/llm.txt b/docs/i18n/te/llm.txt index 7ca43893ab..ac91e53976 100644 --- a/docs/i18n/te/llm.txt +++ b/docs/i18n/te/llm.txt @@ -12,7 +12,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo **Key value:** One endpoint (`http://localhost:20128/v1`), unlimited models, zero downtime, minimal cost. -**Current version:** 3.8.0 +**Current version:** 3.8.1 ## Tech Stack @@ -283,7 +283,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo └── .env.example # Environment variable template ``` -## Key Features (v3.8.0) +## Key Features (v3.8.1) ### Core Proxy - **177 AI providers** with automatic format translation diff --git a/docs/i18n/th/CHANGELOG.md b/docs/i18n/th/CHANGELOG.md index 47857b8332..a924af11a9 100644 --- a/docs/i18n/th/CHANGELOG.md +++ b/docs/i18n/th/CHANGELOG.md @@ -6,6 +6,26 @@ ## [Unreleased] +## [3.8.1] — 2026-05-20 + +### 🔧 Bug Fixes & Refactors + +- **fix(translator):** treat `developer` role as system in OpenAI → Claude translation — `openAIToClaude` now extracts `developer`-role messages into `systemParts` (same as `system`) and filters them from the non-system message list, preventing identity context injected via the Responses API `developer` role from silently becoming an assistant turn when routing to a Claude-format provider. ([#2407](https://github.com/diegosouzapw/OmniRoute/issues/2407)) +- **fix(antigravity):** deduplicate `removeHeaderCaseInsensitive` — export canonical implementation from `antigravityClientProfile.ts` and remove the local copy in `antigravity.ts`; export `AntigravityCredentialsLike` type for cross-module use. (#2433 — thanks @Gi99lin) + +### 🔒 Security Fixes + +- **fix(security):** replace execSync string-template with spawnSync arg-array in plugin.mjs — eliminates shell command injection. +- **fix(security):** gate Electron CSP unsafe-eval on !app.isPackaged — was leaking unsafe-eval into production builds. +- **fix(api):** add requireManagementAuth to /api/usage/budget/bulk and /api/resilience/reset. +- **fix(security):** route catch-block error messages through sanitizeErrorMessage() in executors and API routes. +- **fix(codex):** refreshCredentials returns null on token refresh failure. +- **fix(tokenRefresh):** safe unknown-error access in catch block. +- **fix(combo):** reset exhaustedProviders set at start of each set-retry iteration. +- **fix(circuitBreaker):** persist and restore lastFailureKind via options JSON column. + +--- + ## [3.8.0] — 2026-05-06 ### ✨ New Features diff --git a/docs/i18n/th/docs/reference/ENVIRONMENT.md b/docs/i18n/th/docs/reference/ENVIRONMENT.md index 48f0a0dbb5..2155600d0d 100644 --- a/docs/i18n/th/docs/reference/ENVIRONMENT.md +++ b/docs/i18n/th/docs/reference/ENVIRONMENT.md @@ -339,14 +339,14 @@ process.env[`${PROVIDER_ID}_USER_AGENT`] | Variable | Default Value | When to Update | | ------------------------ | --------------------------------------------- | ------------------------------------------------------------- | -| `CLAUDE_USER_AGENT` | `claude-cli/2.1.143 (external, cli)` | When Anthropic releases a new CLI version | -| `CODEX_USER_AGENT` | `codex-cli/0.131.0 (Windows 10.0.26200; x64)` | When OpenAI updates the Codex CLI | +| `CLAUDE_USER_AGENT` | `claude-cli/2.1.145 (external, cli)` | When Anthropic releases a new CLI version | +| `CODEX_USER_AGENT` | `codex-cli/0.132.0 (Windows 10.0.26200; x64)` | When OpenAI updates the Codex CLI | | `CODEX_CLIENT_VERSION` | `0.131.0` | Override Codex client version independently of full UA string | | `GITHUB_USER_AGENT` | `GitHubCopilotChat/0.45.1` | When GitHub Copilot Chat updates | -| `ANTIGRAVITY_USER_AGENT` | `antigravity/1.107.0 darwin/arm64` | When Antigravity IDE updates | +| `ANTIGRAVITY_USER_AGENT` | `antigravity/2.0.1 darwin/arm64` | When Antigravity IDE updates | | `KIRO_USER_AGENT` | `AWS-SDK-JS/3.0.0 kiro-ide/1.0.0` | When Kiro IDE updates | | `QODER_USER_AGENT` | `Qoder-Cli` | When Qoder CLI updates | -| `QWEN_USER_AGENT` | `QwenCode/0.15.3 (linux; x64)` | When Qwen Code updates | +| `QWEN_USER_AGENT` | `QwenCode/0.15.11 (linux; x64)` | When Qwen Code updates | | `CURSOR_USER_AGENT` | `connect-es/1.6.1` | When Cursor updates | | `GEMINI_CLI_USER_AGENT` | `google-api-nodejs-client/10.3.0` | When Google API client updates | diff --git a/docs/i18n/th/llm.txt b/docs/i18n/th/llm.txt index 5d21cd801f..b4161b601c 100644 --- a/docs/i18n/th/llm.txt +++ b/docs/i18n/th/llm.txt @@ -12,7 +12,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo **Key value:** One endpoint (`http://localhost:20128/v1`), unlimited models, zero downtime, minimal cost. -**Current version:** 3.8.0 +**Current version:** 3.8.1 ## Tech Stack @@ -283,7 +283,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo └── .env.example # Environment variable template ``` -## Key Features (v3.8.0) +## Key Features (v3.8.1) ### Core Proxy - **177 AI providers** with automatic format translation diff --git a/docs/i18n/tr/CHANGELOG.md b/docs/i18n/tr/CHANGELOG.md index f790fdf771..3f7d715850 100644 --- a/docs/i18n/tr/CHANGELOG.md +++ b/docs/i18n/tr/CHANGELOG.md @@ -6,6 +6,26 @@ ## [Unreleased] +## [3.8.1] — 2026-05-20 + +### 🔧 Bug Fixes & Refactors + +- **fix(translator):** treat `developer` role as system in OpenAI → Claude translation — `openAIToClaude` now extracts `developer`-role messages into `systemParts` (same as `system`) and filters them from the non-system message list, preventing identity context injected via the Responses API `developer` role from silently becoming an assistant turn when routing to a Claude-format provider. ([#2407](https://github.com/diegosouzapw/OmniRoute/issues/2407)) +- **fix(antigravity):** deduplicate `removeHeaderCaseInsensitive` — export canonical implementation from `antigravityClientProfile.ts` and remove the local copy in `antigravity.ts`; export `AntigravityCredentialsLike` type for cross-module use. (#2433 — thanks @Gi99lin) + +### 🔒 Security Fixes + +- **fix(security):** replace execSync string-template with spawnSync arg-array in plugin.mjs — eliminates shell command injection. +- **fix(security):** gate Electron CSP unsafe-eval on !app.isPackaged — was leaking unsafe-eval into production builds. +- **fix(api):** add requireManagementAuth to /api/usage/budget/bulk and /api/resilience/reset. +- **fix(security):** route catch-block error messages through sanitizeErrorMessage() in executors and API routes. +- **fix(codex):** refreshCredentials returns null on token refresh failure. +- **fix(tokenRefresh):** safe unknown-error access in catch block. +- **fix(combo):** reset exhaustedProviders set at start of each set-retry iteration. +- **fix(circuitBreaker):** persist and restore lastFailureKind via options JSON column. + +--- + ## [3.8.0] — 2026-05-06 ### ✨ New Features diff --git a/docs/i18n/tr/docs/reference/ENVIRONMENT.md b/docs/i18n/tr/docs/reference/ENVIRONMENT.md index f0b84e1442..573e60accf 100644 --- a/docs/i18n/tr/docs/reference/ENVIRONMENT.md +++ b/docs/i18n/tr/docs/reference/ENVIRONMENT.md @@ -339,14 +339,14 @@ process.env[`${PROVIDER_ID}_USER_AGENT`] | Variable | Default Value | When to Update | | ------------------------ | --------------------------------------------- | ------------------------------------------------------------- | -| `CLAUDE_USER_AGENT` | `claude-cli/2.1.143 (external, cli)` | When Anthropic releases a new CLI version | -| `CODEX_USER_AGENT` | `codex-cli/0.131.0 (Windows 10.0.26200; x64)` | When OpenAI updates the Codex CLI | +| `CLAUDE_USER_AGENT` | `claude-cli/2.1.145 (external, cli)` | When Anthropic releases a new CLI version | +| `CODEX_USER_AGENT` | `codex-cli/0.132.0 (Windows 10.0.26200; x64)` | When OpenAI updates the Codex CLI | | `CODEX_CLIENT_VERSION` | `0.131.0` | Override Codex client version independently of full UA string | | `GITHUB_USER_AGENT` | `GitHubCopilotChat/0.45.1` | When GitHub Copilot Chat updates | -| `ANTIGRAVITY_USER_AGENT` | `antigravity/1.107.0 darwin/arm64` | When Antigravity IDE updates | +| `ANTIGRAVITY_USER_AGENT` | `antigravity/2.0.1 darwin/arm64` | When Antigravity IDE updates | | `KIRO_USER_AGENT` | `AWS-SDK-JS/3.0.0 kiro-ide/1.0.0` | When Kiro IDE updates | | `QODER_USER_AGENT` | `Qoder-Cli` | When Qoder CLI updates | -| `QWEN_USER_AGENT` | `QwenCode/0.15.3 (linux; x64)` | When Qwen Code updates | +| `QWEN_USER_AGENT` | `QwenCode/0.15.11 (linux; x64)` | When Qwen Code updates | | `CURSOR_USER_AGENT` | `connect-es/1.6.1` | When Cursor updates | | `GEMINI_CLI_USER_AGENT` | `google-api-nodejs-client/10.3.0` | When Google API client updates | diff --git a/docs/i18n/tr/llm.txt b/docs/i18n/tr/llm.txt index 95ae4d59b9..fc3ee9d71f 100644 --- a/docs/i18n/tr/llm.txt +++ b/docs/i18n/tr/llm.txt @@ -12,7 +12,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo **Key value:** One endpoint (`http://localhost:20128/v1`), unlimited models, zero downtime, minimal cost. -**Current version:** 3.8.0 +**Current version:** 3.8.1 ## Tech Stack @@ -283,7 +283,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo └── .env.example # Environment variable template ``` -## Key Features (v3.8.0) +## Key Features (v3.8.1) ### Core Proxy - **177 AI providers** with automatic format translation diff --git a/docs/i18n/uk-UA/CHANGELOG.md b/docs/i18n/uk-UA/CHANGELOG.md index 1ce40c916d..cb6f45b621 100644 --- a/docs/i18n/uk-UA/CHANGELOG.md +++ b/docs/i18n/uk-UA/CHANGELOG.md @@ -6,6 +6,26 @@ ## [Unreleased] +## [3.8.1] — 2026-05-20 + +### 🔧 Bug Fixes & Refactors + +- **fix(translator):** treat `developer` role as system in OpenAI → Claude translation — `openAIToClaude` now extracts `developer`-role messages into `systemParts` (same as `system`) and filters them from the non-system message list, preventing identity context injected via the Responses API `developer` role from silently becoming an assistant turn when routing to a Claude-format provider. ([#2407](https://github.com/diegosouzapw/OmniRoute/issues/2407)) +- **fix(antigravity):** deduplicate `removeHeaderCaseInsensitive` — export canonical implementation from `antigravityClientProfile.ts` and remove the local copy in `antigravity.ts`; export `AntigravityCredentialsLike` type for cross-module use. (#2433 — thanks @Gi99lin) + +### 🔒 Security Fixes + +- **fix(security):** replace execSync string-template with spawnSync arg-array in plugin.mjs — eliminates shell command injection. +- **fix(security):** gate Electron CSP unsafe-eval on !app.isPackaged — was leaking unsafe-eval into production builds. +- **fix(api):** add requireManagementAuth to /api/usage/budget/bulk and /api/resilience/reset. +- **fix(security):** route catch-block error messages through sanitizeErrorMessage() in executors and API routes. +- **fix(codex):** refreshCredentials returns null on token refresh failure. +- **fix(tokenRefresh):** safe unknown-error access in catch block. +- **fix(combo):** reset exhaustedProviders set at start of each set-retry iteration. +- **fix(circuitBreaker):** persist and restore lastFailureKind via options JSON column. + +--- + ## [3.8.0] — 2026-05-06 ### ✨ New Features diff --git a/docs/i18n/uk-UA/docs/reference/ENVIRONMENT.md b/docs/i18n/uk-UA/docs/reference/ENVIRONMENT.md index ce122bff0e..e3496d55c6 100644 --- a/docs/i18n/uk-UA/docs/reference/ENVIRONMENT.md +++ b/docs/i18n/uk-UA/docs/reference/ENVIRONMENT.md @@ -339,14 +339,14 @@ process.env[`${PROVIDER_ID}_USER_AGENT`] | Variable | Default Value | When to Update | | ------------------------ | --------------------------------------------- | ------------------------------------------------------------- | -| `CLAUDE_USER_AGENT` | `claude-cli/2.1.143 (external, cli)` | When Anthropic releases a new CLI version | -| `CODEX_USER_AGENT` | `codex-cli/0.131.0 (Windows 10.0.26200; x64)` | When OpenAI updates the Codex CLI | +| `CLAUDE_USER_AGENT` | `claude-cli/2.1.145 (external, cli)` | When Anthropic releases a new CLI version | +| `CODEX_USER_AGENT` | `codex-cli/0.132.0 (Windows 10.0.26200; x64)` | When OpenAI updates the Codex CLI | | `CODEX_CLIENT_VERSION` | `0.131.0` | Override Codex client version independently of full UA string | | `GITHUB_USER_AGENT` | `GitHubCopilotChat/0.45.1` | When GitHub Copilot Chat updates | -| `ANTIGRAVITY_USER_AGENT` | `antigravity/1.107.0 darwin/arm64` | When Antigravity IDE updates | +| `ANTIGRAVITY_USER_AGENT` | `antigravity/2.0.1 darwin/arm64` | When Antigravity IDE updates | | `KIRO_USER_AGENT` | `AWS-SDK-JS/3.0.0 kiro-ide/1.0.0` | When Kiro IDE updates | | `QODER_USER_AGENT` | `Qoder-Cli` | When Qoder CLI updates | -| `QWEN_USER_AGENT` | `QwenCode/0.15.3 (linux; x64)` | When Qwen Code updates | +| `QWEN_USER_AGENT` | `QwenCode/0.15.11 (linux; x64)` | When Qwen Code updates | | `CURSOR_USER_AGENT` | `connect-es/1.6.1` | When Cursor updates | | `GEMINI_CLI_USER_AGENT` | `google-api-nodejs-client/10.3.0` | When Google API client updates | diff --git a/docs/i18n/uk-UA/llm.txt b/docs/i18n/uk-UA/llm.txt index 96f6555ad9..f6c5f196dd 100644 --- a/docs/i18n/uk-UA/llm.txt +++ b/docs/i18n/uk-UA/llm.txt @@ -12,7 +12,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo **Key value:** One endpoint (`http://localhost:20128/v1`), unlimited models, zero downtime, minimal cost. -**Current version:** 3.8.0 +**Current version:** 3.8.1 ## Tech Stack @@ -283,7 +283,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo └── .env.example # Environment variable template ``` -## Key Features (v3.8.0) +## Key Features (v3.8.1) ### Core Proxy - **177 AI providers** with automatic format translation diff --git a/docs/i18n/ur/CHANGELOG.md b/docs/i18n/ur/CHANGELOG.md index c1dfc2fab2..38cb13d0f8 100644 --- a/docs/i18n/ur/CHANGELOG.md +++ b/docs/i18n/ur/CHANGELOG.md @@ -6,6 +6,26 @@ ## [Unreleased] +## [3.8.1] — 2026-05-20 + +### 🔧 Bug Fixes & Refactors + +- **fix(translator):** treat `developer` role as system in OpenAI → Claude translation — `openAIToClaude` now extracts `developer`-role messages into `systemParts` (same as `system`) and filters them from the non-system message list, preventing identity context injected via the Responses API `developer` role from silently becoming an assistant turn when routing to a Claude-format provider. ([#2407](https://github.com/diegosouzapw/OmniRoute/issues/2407)) +- **fix(antigravity):** deduplicate `removeHeaderCaseInsensitive` — export canonical implementation from `antigravityClientProfile.ts` and remove the local copy in `antigravity.ts`; export `AntigravityCredentialsLike` type for cross-module use. (#2433 — thanks @Gi99lin) + +### 🔒 Security Fixes + +- **fix(security):** replace execSync string-template with spawnSync arg-array in plugin.mjs — eliminates shell command injection. +- **fix(security):** gate Electron CSP unsafe-eval on !app.isPackaged — was leaking unsafe-eval into production builds. +- **fix(api):** add requireManagementAuth to /api/usage/budget/bulk and /api/resilience/reset. +- **fix(security):** route catch-block error messages through sanitizeErrorMessage() in executors and API routes. +- **fix(codex):** refreshCredentials returns null on token refresh failure. +- **fix(tokenRefresh):** safe unknown-error access in catch block. +- **fix(combo):** reset exhaustedProviders set at start of each set-retry iteration. +- **fix(circuitBreaker):** persist and restore lastFailureKind via options JSON column. + +--- + ## [3.8.0] — 2026-05-06 ### ✨ New Features diff --git a/docs/i18n/ur/docs/reference/ENVIRONMENT.md b/docs/i18n/ur/docs/reference/ENVIRONMENT.md index 57bf7f4df9..7076e0b631 100644 --- a/docs/i18n/ur/docs/reference/ENVIRONMENT.md +++ b/docs/i18n/ur/docs/reference/ENVIRONMENT.md @@ -339,14 +339,14 @@ process.env[`${PROVIDER_ID}_USER_AGENT`] | Variable | Default Value | When to Update | | ------------------------ | --------------------------------------------- | ------------------------------------------------------------- | -| `CLAUDE_USER_AGENT` | `claude-cli/2.1.143 (external, cli)` | When Anthropic releases a new CLI version | -| `CODEX_USER_AGENT` | `codex-cli/0.131.0 (Windows 10.0.26200; x64)` | When OpenAI updates the Codex CLI | +| `CLAUDE_USER_AGENT` | `claude-cli/2.1.145 (external, cli)` | When Anthropic releases a new CLI version | +| `CODEX_USER_AGENT` | `codex-cli/0.132.0 (Windows 10.0.26200; x64)` | When OpenAI updates the Codex CLI | | `CODEX_CLIENT_VERSION` | `0.131.0` | Override Codex client version independently of full UA string | | `GITHUB_USER_AGENT` | `GitHubCopilotChat/0.45.1` | When GitHub Copilot Chat updates | -| `ANTIGRAVITY_USER_AGENT` | `antigravity/1.107.0 darwin/arm64` | When Antigravity IDE updates | +| `ANTIGRAVITY_USER_AGENT` | `antigravity/2.0.1 darwin/arm64` | When Antigravity IDE updates | | `KIRO_USER_AGENT` | `AWS-SDK-JS/3.0.0 kiro-ide/1.0.0` | When Kiro IDE updates | | `QODER_USER_AGENT` | `Qoder-Cli` | When Qoder CLI updates | -| `QWEN_USER_AGENT` | `QwenCode/0.15.3 (linux; x64)` | When Qwen Code updates | +| `QWEN_USER_AGENT` | `QwenCode/0.15.11 (linux; x64)` | When Qwen Code updates | | `CURSOR_USER_AGENT` | `connect-es/1.6.1` | When Cursor updates | | `GEMINI_CLI_USER_AGENT` | `google-api-nodejs-client/10.3.0` | When Google API client updates | diff --git a/docs/i18n/ur/llm.txt b/docs/i18n/ur/llm.txt index 045ba46b37..53a8c4b377 100644 --- a/docs/i18n/ur/llm.txt +++ b/docs/i18n/ur/llm.txt @@ -12,7 +12,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo **Key value:** One endpoint (`http://localhost:20128/v1`), unlimited models, zero downtime, minimal cost. -**Current version:** 3.8.0 +**Current version:** 3.8.1 ## Tech Stack @@ -283,7 +283,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo └── .env.example # Environment variable template ``` -## Key Features (v3.8.0) +## Key Features (v3.8.1) ### Core Proxy - **177 AI providers** with automatic format translation diff --git a/docs/i18n/vi/CHANGELOG.md b/docs/i18n/vi/CHANGELOG.md index b949c10f47..891e6c0b1c 100644 --- a/docs/i18n/vi/CHANGELOG.md +++ b/docs/i18n/vi/CHANGELOG.md @@ -6,6 +6,26 @@ ## [Unreleased] +## [3.8.1] — 2026-05-20 + +### 🔧 Bug Fixes & Refactors + +- **fix(translator):** treat `developer` role as system in OpenAI → Claude translation — `openAIToClaude` now extracts `developer`-role messages into `systemParts` (same as `system`) and filters them from the non-system message list, preventing identity context injected via the Responses API `developer` role from silently becoming an assistant turn when routing to a Claude-format provider. ([#2407](https://github.com/diegosouzapw/OmniRoute/issues/2407)) +- **fix(antigravity):** deduplicate `removeHeaderCaseInsensitive` — export canonical implementation from `antigravityClientProfile.ts` and remove the local copy in `antigravity.ts`; export `AntigravityCredentialsLike` type for cross-module use. (#2433 — thanks @Gi99lin) + +### 🔒 Security Fixes + +- **fix(security):** replace execSync string-template with spawnSync arg-array in plugin.mjs — eliminates shell command injection. +- **fix(security):** gate Electron CSP unsafe-eval on !app.isPackaged — was leaking unsafe-eval into production builds. +- **fix(api):** add requireManagementAuth to /api/usage/budget/bulk and /api/resilience/reset. +- **fix(security):** route catch-block error messages through sanitizeErrorMessage() in executors and API routes. +- **fix(codex):** refreshCredentials returns null on token refresh failure. +- **fix(tokenRefresh):** safe unknown-error access in catch block. +- **fix(combo):** reset exhaustedProviders set at start of each set-retry iteration. +- **fix(circuitBreaker):** persist and restore lastFailureKind via options JSON column. + +--- + ## [3.8.0] — 2026-05-06 ### ✨ New Features diff --git a/docs/i18n/vi/docs/reference/ENVIRONMENT.md b/docs/i18n/vi/docs/reference/ENVIRONMENT.md index b53a434f89..ddfb573721 100644 --- a/docs/i18n/vi/docs/reference/ENVIRONMENT.md +++ b/docs/i18n/vi/docs/reference/ENVIRONMENT.md @@ -339,14 +339,14 @@ process.env[`${PROVIDER_ID}_USER_AGENT`] | Variable | Default Value | When to Update | | ------------------------ | --------------------------------------------- | ------------------------------------------------------------- | -| `CLAUDE_USER_AGENT` | `claude-cli/2.1.143 (external, cli)` | When Anthropic releases a new CLI version | -| `CODEX_USER_AGENT` | `codex-cli/0.131.0 (Windows 10.0.26200; x64)` | When OpenAI updates the Codex CLI | +| `CLAUDE_USER_AGENT` | `claude-cli/2.1.145 (external, cli)` | When Anthropic releases a new CLI version | +| `CODEX_USER_AGENT` | `codex-cli/0.132.0 (Windows 10.0.26200; x64)` | When OpenAI updates the Codex CLI | | `CODEX_CLIENT_VERSION` | `0.131.0` | Override Codex client version independently of full UA string | | `GITHUB_USER_AGENT` | `GitHubCopilotChat/0.45.1` | When GitHub Copilot Chat updates | -| `ANTIGRAVITY_USER_AGENT` | `antigravity/1.107.0 darwin/arm64` | When Antigravity IDE updates | +| `ANTIGRAVITY_USER_AGENT` | `antigravity/2.0.1 darwin/arm64` | When Antigravity IDE updates | | `KIRO_USER_AGENT` | `AWS-SDK-JS/3.0.0 kiro-ide/1.0.0` | When Kiro IDE updates | | `QODER_USER_AGENT` | `Qoder-Cli` | When Qoder CLI updates | -| `QWEN_USER_AGENT` | `QwenCode/0.15.3 (linux; x64)` | When Qwen Code updates | +| `QWEN_USER_AGENT` | `QwenCode/0.15.11 (linux; x64)` | When Qwen Code updates | | `CURSOR_USER_AGENT` | `connect-es/1.6.1` | When Cursor updates | | `GEMINI_CLI_USER_AGENT` | `google-api-nodejs-client/10.3.0` | When Google API client updates | diff --git a/docs/i18n/vi/llm.txt b/docs/i18n/vi/llm.txt index 7b97ecb790..7584da4ce8 100644 --- a/docs/i18n/vi/llm.txt +++ b/docs/i18n/vi/llm.txt @@ -12,7 +12,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo **Key value:** One endpoint (`http://localhost:20128/v1`), unlimited models, zero downtime, minimal cost. -**Current version:** 3.8.0 +**Current version:** 3.8.1 ## Tech Stack @@ -283,7 +283,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo └── .env.example # Environment variable template ``` -## Key Features (v3.8.0) +## Key Features (v3.8.1) ### Core Proxy - **177 AI providers** with automatic format translation diff --git a/docs/i18n/zh-CN/CHANGELOG.md b/docs/i18n/zh-CN/CHANGELOG.md index 9b6574aa33..6139519cba 100644 --- a/docs/i18n/zh-CN/CHANGELOG.md +++ b/docs/i18n/zh-CN/CHANGELOG.md @@ -6,6 +6,26 @@ ## [Unreleased] +## [3.8.1] — 2026-05-20 + +### 🔧 Bug Fixes & Refactors + +- **fix(translator):** treat `developer` role as system in OpenAI → Claude translation — `openAIToClaude` now extracts `developer`-role messages into `systemParts` (same as `system`) and filters them from the non-system message list, preventing identity context injected via the Responses API `developer` role from silently becoming an assistant turn when routing to a Claude-format provider. ([#2407](https://github.com/diegosouzapw/OmniRoute/issues/2407)) +- **fix(antigravity):** deduplicate `removeHeaderCaseInsensitive` — export canonical implementation from `antigravityClientProfile.ts` and remove the local copy in `antigravity.ts`; export `AntigravityCredentialsLike` type for cross-module use. (#2433 — thanks @Gi99lin) + +### 🔒 Security Fixes + +- **fix(security):** replace execSync string-template with spawnSync arg-array in plugin.mjs — eliminates shell command injection. +- **fix(security):** gate Electron CSP unsafe-eval on !app.isPackaged — was leaking unsafe-eval into production builds. +- **fix(api):** add requireManagementAuth to /api/usage/budget/bulk and /api/resilience/reset. +- **fix(security):** route catch-block error messages through sanitizeErrorMessage() in executors and API routes. +- **fix(codex):** refreshCredentials returns null on token refresh failure. +- **fix(tokenRefresh):** safe unknown-error access in catch block. +- **fix(combo):** reset exhaustedProviders set at start of each set-retry iteration. +- **fix(circuitBreaker):** persist and restore lastFailureKind via options JSON column. + +--- + ## [3.8.0] — 2026-05-06 ### ✨ New Features diff --git a/docs/i18n/zh-CN/docs/reference/ENVIRONMENT.md b/docs/i18n/zh-CN/docs/reference/ENVIRONMENT.md index 8df140d59d..2a7319c79c 100644 --- a/docs/i18n/zh-CN/docs/reference/ENVIRONMENT.md +++ b/docs/i18n/zh-CN/docs/reference/ENVIRONMENT.md @@ -339,14 +339,14 @@ process.env[`${PROVIDER_ID}_USER_AGENT`] | Variable | Default Value | When to Update | | ------------------------ | --------------------------------------------- | ------------------------------------------------------------- | -| `CLAUDE_USER_AGENT` | `claude-cli/2.1.143 (external, cli)` | When Anthropic releases a new CLI version | -| `CODEX_USER_AGENT` | `codex-cli/0.131.0 (Windows 10.0.26200; x64)` | When OpenAI updates the Codex CLI | +| `CLAUDE_USER_AGENT` | `claude-cli/2.1.145 (external, cli)` | When Anthropic releases a new CLI version | +| `CODEX_USER_AGENT` | `codex-cli/0.132.0 (Windows 10.0.26200; x64)` | When OpenAI updates the Codex CLI | | `CODEX_CLIENT_VERSION` | `0.131.0` | Override Codex client version independently of full UA string | | `GITHUB_USER_AGENT` | `GitHubCopilotChat/0.45.1` | When GitHub Copilot Chat updates | -| `ANTIGRAVITY_USER_AGENT` | `antigravity/1.107.0 darwin/arm64` | When Antigravity IDE updates | +| `ANTIGRAVITY_USER_AGENT` | `antigravity/2.0.1 darwin/arm64` | When Antigravity IDE updates | | `KIRO_USER_AGENT` | `AWS-SDK-JS/3.0.0 kiro-ide/1.0.0` | When Kiro IDE updates | | `QODER_USER_AGENT` | `Qoder-Cli` | When Qoder CLI updates | -| `QWEN_USER_AGENT` | `QwenCode/0.15.3 (linux; x64)` | When Qwen Code updates | +| `QWEN_USER_AGENT` | `QwenCode/0.15.11 (linux; x64)` | When Qwen Code updates | | `CURSOR_USER_AGENT` | `connect-es/1.6.1` | When Cursor updates | | `GEMINI_CLI_USER_AGENT` | `google-api-nodejs-client/10.3.0` | When Google API client updates | diff --git a/docs/i18n/zh-CN/llm.txt b/docs/i18n/zh-CN/llm.txt index 0690891034..977a3d58f5 100644 --- a/docs/i18n/zh-CN/llm.txt +++ b/docs/i18n/zh-CN/llm.txt @@ -12,7 +12,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo **Key value:** One endpoint (`http://localhost:20128/v1`), unlimited models, zero downtime, minimal cost. -**Current version:** 3.8.0 +**Current version:** 3.8.1 ## Tech Stack @@ -283,7 +283,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo └── .env.example # Environment variable template ``` -## Key Features (v3.8.0) +## Key Features (v3.8.1) ### Core Proxy - **177 AI providers** with automatic format translation diff --git a/docs/marketing/TIERS.md b/docs/marketing/TIERS.md index b63bca8284..34aed0a22e 100644 --- a/docs/marketing/TIERS.md +++ b/docs/marketing/TIERS.md @@ -1,6 +1,6 @@ --- title: "OmniRoute Tiers — User Guide" -version: 3.8.0 +version: 3.8.1 lastUpdated: 2026-05-15 --- diff --git a/docs/ops/COVERAGE_PLAN.md b/docs/ops/COVERAGE_PLAN.md index 32bb9dde71..4626bc07bb 100644 --- a/docs/ops/COVERAGE_PLAN.md +++ b/docs/ops/COVERAGE_PLAN.md @@ -1,6 +1,6 @@ --- title: "Test Coverage Plan" -version: 3.8.0 +version: 3.8.1 lastUpdated: 2026-05-13 --- diff --git a/docs/ops/FLY_IO_DEPLOYMENT_GUIDE.md b/docs/ops/FLY_IO_DEPLOYMENT_GUIDE.md index d9a40a64c8..e6e1193fe5 100644 --- a/docs/ops/FLY_IO_DEPLOYMENT_GUIDE.md +++ b/docs/ops/FLY_IO_DEPLOYMENT_GUIDE.md @@ -1,6 +1,6 @@ --- title: "OmniRoute Fly.io 部署指南" -version: 3.8.0 +version: 3.8.1 lastUpdated: 2026-05-13 --- diff --git a/docs/ops/PROXY_GUIDE.md b/docs/ops/PROXY_GUIDE.md index 4c7f7b05a4..333ba4c769 100644 --- a/docs/ops/PROXY_GUIDE.md +++ b/docs/ops/PROXY_GUIDE.md @@ -1,6 +1,6 @@ --- title: "🌐 OmniRoute Proxy Guide" -version: 3.8.0 +version: 3.8.1 lastUpdated: 2026-05-13 --- diff --git a/docs/ops/RELEASE_CHECKLIST.md b/docs/ops/RELEASE_CHECKLIST.md index 0cabf18f87..5844247b14 100644 --- a/docs/ops/RELEASE_CHECKLIST.md +++ b/docs/ops/RELEASE_CHECKLIST.md @@ -1,6 +1,6 @@ --- title: "Release Checklist" -version: 3.8.0 +version: 3.8.1 lastUpdated: 2026-05-13 --- diff --git a/docs/ops/TUNNELS_GUIDE.md b/docs/ops/TUNNELS_GUIDE.md index 1861a0fa79..e54d9b8822 100644 --- a/docs/ops/TUNNELS_GUIDE.md +++ b/docs/ops/TUNNELS_GUIDE.md @@ -1,6 +1,6 @@ --- title: "Tunnels Guide" -version: 3.8.0 +version: 3.8.1 lastUpdated: 2026-05-13 --- diff --git a/docs/ops/VM_DEPLOYMENT_GUIDE.md b/docs/ops/VM_DEPLOYMENT_GUIDE.md index 69a4cba1fe..4b9af362c8 100644 --- a/docs/ops/VM_DEPLOYMENT_GUIDE.md +++ b/docs/ops/VM_DEPLOYMENT_GUIDE.md @@ -1,6 +1,6 @@ --- title: "OmniRoute — Deployment Guide on VM with Cloudflare" -version: 3.8.0 +version: 3.8.1 lastUpdated: 2026-05-13 --- diff --git a/docs/reference/API_REFERENCE.md b/docs/reference/API_REFERENCE.md index 719f4a8d07..5c10fd311c 100644 --- a/docs/reference/API_REFERENCE.md +++ b/docs/reference/API_REFERENCE.md @@ -1,6 +1,6 @@ --- title: "API Reference" -version: 3.8.0 +version: 3.8.1 lastUpdated: 2026-05-13 --- diff --git a/docs/reference/CLI-TOOLS.md b/docs/reference/CLI-TOOLS.md index 91378dbb51..70a09f6a26 100644 --- a/docs/reference/CLI-TOOLS.md +++ b/docs/reference/CLI-TOOLS.md @@ -1,6 +1,6 @@ --- title: "CLI Tools — OmniRoute v3.8.0" -version: 3.8.0 +version: 3.8.1 lastUpdated: 2026-05-13 --- diff --git a/docs/reference/ENVIRONMENT.md b/docs/reference/ENVIRONMENT.md index 569d81e5f8..17458638e6 100644 --- a/docs/reference/ENVIRONMENT.md +++ b/docs/reference/ENVIRONMENT.md @@ -1,6 +1,6 @@ --- title: "Environment Variables Reference" -version: 3.8.0 +version: 3.8.1 lastUpdated: 2026-05-13 --- @@ -410,11 +410,11 @@ process.env[`${PROVIDER_ID}_USER_AGENT`] | Variable | Default Value | When to Update | | ------------------------ | --------------------------------------------- | ------------------------------------------------------------- | -| `CLAUDE_USER_AGENT` | `claude-cli/2.1.143 (external, cli)` | When Anthropic releases a new CLI version | -| `CODEX_USER_AGENT` | `codex-cli/0.131.0 (Windows 10.0.26200; x64)` | When OpenAI updates the Codex CLI | +| `CLAUDE_USER_AGENT` | `claude-cli/2.1.145 (external, cli)` | When Anthropic releases a new CLI version | +| `CODEX_USER_AGENT` | `codex-cli/0.132.0 (Windows 10.0.26200; x64)` | When OpenAI updates the Codex CLI | | `CODEX_CLIENT_VERSION` | `0.131.0` | Override Codex client version independently of full UA string | | `GITHUB_USER_AGENT` | `GitHubCopilotChat/0.45.1` | When GitHub Copilot Chat updates | -| `ANTIGRAVITY_USER_AGENT` | `antigravity/1.23.2 darwin/arm64` | When Antigravity IDE updates | +| `ANTIGRAVITY_USER_AGENT` | `antigravity/2.0.1 darwin/arm64` | When Antigravity IDE updates | | `KIRO_USER_AGENT` | `AWS-SDK-JS/3.0.0 kiro-ide/1.0.0` | When Kiro IDE updates | | `QODER_USER_AGENT` | `Qoder-Cli` | When Qoder CLI updates | | `QWEN_USER_AGENT` | `QwenCode/0.15.9 (linux; x64)` | When Qwen Code updates | diff --git a/docs/reference/FREE_TIERS.md b/docs/reference/FREE_TIERS.md index 71a2743ea2..270aaffc75 100644 --- a/docs/reference/FREE_TIERS.md +++ b/docs/reference/FREE_TIERS.md @@ -1,15 +1,15 @@ --- title: "Free Tiers" -version: 3.8.0 +version: 3.8.1 lastUpdated: 2026-05-13 --- # Free Tiers -> **Last consolidated:** 2026-05-13 — OmniRoute v3.8.0 +> **Last consolidated:** 2026-05-13 — OmniRoute v3.8.1 > **Source of truth:** `src/shared/constants/providers.ts` (`FREE_PROVIDERS`, `OAUTH_PROVIDERS`, and `APIKEY_PROVIDERS` entries flagged with `hasFree: true` + `freeNote`) -This page lists providers with usable free tiers shipped in OmniRoute v3.8.0. The data is derived from the provider catalog. If a provider does not appear here, it either has no free tier in the catalog or its `hasFree` flag is `false`. +This page lists providers with usable free tiers shipped in OmniRoute v3.8.1. The data is derived from the provider catalog. If a provider does not appear here, it either has no free tier in the catalog or its `hasFree` flag is `false`. Add credentials from the dashboard (`/dashboard/providers/new`) — OmniRoute reads keys from the database, not from per-provider environment variables. The only env vars that influence provider behavior are listed in the [Environment Variables](#environment-variables) section. @@ -156,7 +156,7 @@ Check Command Code's website for the current free-tier policy. ## Environment variables -OmniRoute v3.8.0 does **not** read provider API keys from environment variables (with one exception below). Keys are stored in the encrypted SQLite database and configured from the dashboard. The env vars listed here are the only ones that affect free-tier behavior: +OmniRoute v3.8.1 does **not** read provider API keys from environment variables (with one exception below). Keys are stored in the encrypted SQLite database and configured from the dashboard. The env vars listed here are the only ones that affect free-tier behavior: ```bash # Windsurf / Devin CLI — Firebase Web API key used by the Secure Token diff --git a/docs/reference/PROVIDER_REFERENCE.md b/docs/reference/PROVIDER_REFERENCE.md index af2c3fb87b..b831d3f109 100644 --- a/docs/reference/PROVIDER_REFERENCE.md +++ b/docs/reference/PROVIDER_REFERENCE.md @@ -1,6 +1,6 @@ --- title: "Provider Reference" -version: 3.8.0 +version: 3.8.1 lastUpdated: 2026-05-17 --- diff --git a/docs/reference/openapi.yaml b/docs/reference/openapi.yaml index 4f43468f53..daceca679b 100644 --- a/docs/reference/openapi.yaml +++ b/docs/reference/openapi.yaml @@ -1,7 +1,7 @@ openapi: 3.1.0 info: title: OmniRoute API - version: 3.8.0 + version: 3.8.1 description: | OmniRoute is a local-first AI API proxy router. It provides an OpenAI-compatible endpoint that routes requests to multiple AI providers with load balancing, diff --git a/docs/routing/AUTO-COMBO.md b/docs/routing/AUTO-COMBO.md index af684a56c4..c240d1c893 100644 --- a/docs/routing/AUTO-COMBO.md +++ b/docs/routing/AUTO-COMBO.md @@ -1,6 +1,6 @@ --- title: "OmniRoute Auto-Combo Engine" -version: 3.8.0 +version: 3.8.1 lastUpdated: 2026-05-13 --- diff --git a/docs/routing/REASONING_REPLAY.md b/docs/routing/REASONING_REPLAY.md index adefd7983a..0eba6af615 100644 --- a/docs/routing/REASONING_REPLAY.md +++ b/docs/routing/REASONING_REPLAY.md @@ -1,6 +1,6 @@ --- title: "Reasoning Replay Cache" -version: 3.8.0 +version: 3.8.1 lastUpdated: 2026-05-13 --- diff --git a/docs/security/COMPLIANCE.md b/docs/security/COMPLIANCE.md index ce4c631f0a..7ff4664823 100644 --- a/docs/security/COMPLIANCE.md +++ b/docs/security/COMPLIANCE.md @@ -1,6 +1,6 @@ --- title: "Compliance & Audit" -version: 3.8.0 +version: 3.8.1 lastUpdated: 2026-05-13 --- diff --git a/docs/security/ERROR_SANITIZATION.md b/docs/security/ERROR_SANITIZATION.md index 4c47a109d0..1181a8a009 100644 --- a/docs/security/ERROR_SANITIZATION.md +++ b/docs/security/ERROR_SANITIZATION.md @@ -1,6 +1,6 @@ --- title: "Error Message Sanitization" -version: 3.8.0 +version: 3.8.1 lastUpdated: 2026-05-14 --- diff --git a/docs/security/GUARDRAILS.md b/docs/security/GUARDRAILS.md index 29d6d5a519..59ec9ff99f 100644 --- a/docs/security/GUARDRAILS.md +++ b/docs/security/GUARDRAILS.md @@ -1,6 +1,6 @@ --- title: "Guardrails" -version: 3.8.0 +version: 3.8.1 lastUpdated: 2026-05-13 --- diff --git a/docs/security/PUBLIC_CREDS.md b/docs/security/PUBLIC_CREDS.md index 9b0c129e2b..f9d672334d 100644 --- a/docs/security/PUBLIC_CREDS.md +++ b/docs/security/PUBLIC_CREDS.md @@ -1,6 +1,6 @@ --- title: "Public Credentials Handling" -version: 3.8.0 +version: 3.8.1 lastUpdated: 2026-05-14 --- diff --git a/docs/security/STEALTH_GUIDE.md b/docs/security/STEALTH_GUIDE.md index 2d22ed7abc..9ff970c577 100644 --- a/docs/security/STEALTH_GUIDE.md +++ b/docs/security/STEALTH_GUIDE.md @@ -1,6 +1,6 @@ --- title: "Stealth Guide" -version: 3.8.0 +version: 3.8.1 lastUpdated: 2026-05-13 --- @@ -212,10 +212,10 @@ All MITM endpoints require management auth (`requireCliToolsAuth`). The sudo pas | Variable | Default | | ------------------------ | --------------------------------------------- | -| `CLAUDE_USER_AGENT` | `claude-cli/2.1.143 (external, cli)` | -| `CODEX_USER_AGENT` | `codex-cli/0.131.0 (Windows 10.0.26200; x64)` | +| `CLAUDE_USER_AGENT` | `claude-cli/2.1.145 (external, cli)` | +| `CODEX_USER_AGENT` | `codex-cli/0.132.0 (Windows 10.0.26200; x64)` | | `GITHUB_USER_AGENT` | `GitHubCopilotChat/0.45.1` | -| `ANTIGRAVITY_USER_AGENT` | `antigravity/1.23.2 darwin/arm64` | +| `ANTIGRAVITY_USER_AGENT` | `antigravity/2.0.1 darwin/arm64` | | `KIRO_USER_AGENT` | `AWS-SDK-JS/3.0.0 kiro-ide/1.0.0` | | `QODER_USER_AGENT` | `Qoder-Cli` | | `QWEN_USER_AGENT` | `QwenCode/0.15.9 (linux; x64)` | diff --git a/electron/package-lock.json b/electron/package-lock.json index fb3fb56937..ca05cc9fd2 100644 --- a/electron/package-lock.json +++ b/electron/package-lock.json @@ -1,23 +1,25 @@ { "name": "omniroute-desktop", - "version": "3.8.0", + "version": "3.8.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "omniroute-desktop", - "version": "3.8.0", + "version": "3.8.1", "license": "MIT", "dependencies": { - "better-sqlite3": "^12.10.0", - "electron-updater": "^6.8.5" + "electron-updater": "^6.8.6" }, "devDependencies": { - "electron": "^42.1.0", - "electron-builder": "^26.10.0" + "electron": "^42.2.0", + "electron-builder": "^26.11.0" }, "engines": { "node": ">=22.22.2 <23 || >=24.0.0 <27" + }, + "optionalDependencies": { + "better-sqlite3": "^12.10.0" } }, "node_modules/@develar/schema-utils": { @@ -324,6 +326,45 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/@electron/windows-sign": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@electron/windows-sign/-/windows-sign-1.2.2.tgz", + "integrity": "sha512-dfZeox66AvdPtb2lD8OsIIQh12Tp0GNCRUDfBHIKGpbmopZto2/A8nSpYYLoedPIHpqkeblZ/k8OV0Gy7PYuyQ==", + "dev": true, + "license": "BSD-2-Clause", + "optional": true, + "peer": true, + "dependencies": { + "cross-dirname": "^0.1.0", + "debug": "^4.3.4", + "fs-extra": "^11.1.1", + "minimist": "^1.2.8", + "postject": "^1.0.0-alpha.6" + }, + "bin": { + "electron-windows-sign": "bin/electron-windows-sign.js" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/@electron/windows-sign/node_modules/fs-extra": { + "version": "11.3.5", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.5.tgz", + "integrity": "sha512-eKpRKAovdpZtR1WopLHxlBWvAgPny3c4gX1G5Jhwmmw4XJj0ifSD5qB5TOo8hmA0wlRKDAOAhEE1yVPgs6Fgcg==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, "node_modules/@isaacs/cliui": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", @@ -775,9 +816,9 @@ "license": "MIT" }, "node_modules/app-builder-lib": { - "version": "26.10.0", - "resolved": "https://registry.npmjs.org/app-builder-lib/-/app-builder-lib-26.10.0.tgz", - "integrity": "sha512-7i97Vua1VtiRs53mvj7l55YJNJNZi6qvSQAC1H8SZ6pRoNJcTkuzgcZLvzu6QczZSo7VpyDiEDjd9I0oQDoElA==", + "version": "26.11.0", + "resolved": "https://registry.npmjs.org/app-builder-lib/-/app-builder-lib-26.11.0.tgz", + "integrity": "sha512-coIDM9smVKp2ZRiEu1Xu6NBjN2xdhViox8bHxaWToMCUYVIusqwUxUl9J/5ef8CKZ2CVHgqd7/rFsFazLrzp6g==", "dev": true, "license": "MIT", "dependencies": { @@ -792,15 +833,15 @@ "@malept/flatpak-bundler": "^0.4.0", "@types/fs-extra": "9.0.13", "async-exit-hook": "^2.0.1", - "builder-util": "26.10.0", - "builder-util-runtime": "9.6.0", + "builder-util": "26.11.0", + "builder-util-runtime": "9.6.1", "chromium-pickle-js": "^0.2.0", "ci-info": "4.3.1", "debug": "^4.3.4", "dotenv": "^16.4.5", "dotenv-expand": "^11.0.6", "ejs": "^3.1.8", - "electron-publish": "26.10.0", + "electron-publish": "26.11.0", "fs-extra": "^10.1.0", "hosted-git-info": "^4.1.0", "isbinaryfile": "^5.0.0", @@ -823,8 +864,8 @@ "node": ">=14.0.0" }, "peerDependencies": { - "dmg-builder": "26.10.0", - "electron-builder-squirrel-windows": "26.10.0" + "dmg-builder": "26.11.0", + "electron-builder-squirrel-windows": "26.11.0" } }, "node_modules/app-builder-lib/node_modules/@electron/get": { @@ -986,6 +1027,7 @@ "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "devOptional": true, "funding": [ { "type": "github", @@ -1008,6 +1050,7 @@ "integrity": "sha512-CyzaZRQKyHkB2ZInfTTl2nvT33EbDpjkLEbE8/Zck3Ll6O0qqvuGdrJ45HgtH+HykRg88ITY3AdreBGN70aBSQ==", "hasInstallScript": true, "license": "MIT", + "optional": true, "dependencies": { "bindings": "^1.5.0", "prebuild-install": "^7.1.1" @@ -1021,6 +1064,7 @@ "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", "license": "MIT", + "optional": true, "dependencies": { "file-uri-to-path": "1.0.0" } @@ -1029,6 +1073,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "devOptional": true, "license": "MIT", "dependencies": { "buffer": "^5.5.0", @@ -1069,6 +1114,7 @@ "version": "5.7.1", "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "devOptional": true, "funding": [ { "type": "github", @@ -1107,16 +1153,16 @@ "license": "MIT" }, "node_modules/builder-util": { - "version": "26.10.0", - "resolved": "https://registry.npmjs.org/builder-util/-/builder-util-26.10.0.tgz", - "integrity": "sha512-OTHb+Y5nehChOQsQQLccDpbi+b6brV0qNAKPV5KYj874wBm68rntZaREreBZ+Wk76b8JvZmbID4oyw2HfE+cUQ==", + "version": "26.11.0", + "resolved": "https://registry.npmjs.org/builder-util/-/builder-util-26.11.0.tgz", + "integrity": "sha512-T+NH1EatZ7dy14dkk4yJrg/rTW6RDOLpDZOhcTSUsqxild21Mcts7CW8TgNemBwMMpwDAinNNoZQiUVgH/LyJg==", "dev": true, "license": "MIT", "dependencies": { "@types/debug": "^4.1.6", "7zip-bin": "~5.2.0", "app-builder-bin": "5.0.0-alpha.12", - "builder-util-runtime": "9.6.0", + "builder-util-runtime": "9.6.1", "chalk": "^4.1.2", "cross-spawn": "^7.0.6", "debug": "^4.3.4", @@ -1135,9 +1181,9 @@ } }, "node_modules/builder-util-runtime": { - "version": "9.6.0", - "resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-9.6.0.tgz", - "integrity": "sha512-k9V5I18PXLepLZ8jVmPzsH+gVCVZ+9aMVLyCZ0ZLOkT2KSyiBblDCCN8WxDbjOpfLGNHZqqJPBmW0HYeqxlgkQ==", + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-9.6.1.tgz", + "integrity": "sha512-gnk+lN50T7TIRp4bHTVydSnWsNkYAxGiDDbed3U26Z82s1lr8em4E4fLs/EPfIEZIbfi4Zfo5NsdA9gHWbPmXg==", "license": "MIT", "dependencies": { "debug": "^4.3.4", @@ -1486,6 +1532,15 @@ "buffer": "^5.1.0" } }, + "node_modules/cross-dirname": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/cross-dirname/-/cross-dirname-0.1.0.tgz", + "integrity": "sha512-+R08/oI0nl3vfPcqftZRpytksBXDzOUveBq/NBVx0sUp1axwzPQrKinNx5yd5sxPu8j1wIy8AfnVQ+5eFdha6Q==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true + }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -1545,6 +1600,7 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "devOptional": true, "license": "MIT", "dependencies": { "mimic-response": "^3.1.0" @@ -1560,6 +1616,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "devOptional": true, "license": "MIT", "engines": { "node": ">=10" @@ -1573,6 +1630,7 @@ "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", "license": "MIT", + "optional": true, "engines": { "node": ">=4.0.0" } @@ -1652,6 +1710,7 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "devOptional": true, "license": "Apache-2.0", "engines": { "node": ">=8" @@ -1708,14 +1767,14 @@ } }, "node_modules/dmg-builder": { - "version": "26.10.0", - "resolved": "https://registry.npmjs.org/dmg-builder/-/dmg-builder-26.10.0.tgz", - "integrity": "sha512-7gtp2YBe2PLDuja9QiWOxE9UITyDXfGKm+9yz9eY6rWL/tP5fL29gFhsMTa/S+eq7YqP/2hBQv/tmj9r19W8Bw==", + "version": "26.11.0", + "resolved": "https://registry.npmjs.org/dmg-builder/-/dmg-builder-26.11.0.tgz", + "integrity": "sha512-bOVrG++ewJZ0aneOAlzHCbZmYdYxaANRuUoGxBXVmwmjMUTI6MBk7ekzr5xRLEf33+Vi8KTLW1eGepLSiTb6GQ==", "dev": true, "license": "MIT", "dependencies": { - "app-builder-lib": "26.10.0", - "builder-util": "26.10.0", + "app-builder-lib": "26.11.0", + "builder-util": "26.11.0", "fs-extra": "^10.1.0", "iconv-lite": "^0.6.2", "js-yaml": "^4.1.0" @@ -1862,9 +1921,9 @@ } }, "node_modules/electron": { - "version": "42.1.0", - "resolved": "https://registry.npmjs.org/electron/-/electron-42.1.0.tgz", - "integrity": "sha512-0szNwC/0dWtkvNce5j3ThiuL0TxBNrZN/BZhdOiGwbLreiD/+u3MGpkct4hA5Ycagb8MXjpEr5/oosi+FwuKRQ==", + "version": "42.2.0", + "resolved": "https://registry.npmjs.org/electron/-/electron-42.2.0.tgz", + "integrity": "sha512-b2Tc7sIKiZEl0tBVwFM5GJ+FT5KYhmy9QJHjx8BGVZPVW2SctXWEvrE959ElB56qw7H05dBkhlikDA1DmpaAMw==", "dev": true, "license": "MIT", "dependencies": { @@ -1881,18 +1940,18 @@ } }, "node_modules/electron-builder": { - "version": "26.10.0", - "resolved": "https://registry.npmjs.org/electron-builder/-/electron-builder-26.10.0.tgz", - "integrity": "sha512-MBKumv0B8I9ypVXA2MuXu6JTaSs6NDfXWMx6w2FmPX7iN0J6v/IKYdOm1ffTjeTbZiYRa1Yc4U9agXot/0gXzA==", + "version": "26.11.0", + "resolved": "https://registry.npmjs.org/electron-builder/-/electron-builder-26.11.0.tgz", + "integrity": "sha512-iAbfODrWHrbWTrwI2IVNNfq88VViMBxBNaKcwozXm4fOlf91hj5yDKVq++XP4iAOHcPWHVZ5m+ngx54MLpFPeQ==", "dev": true, "license": "MIT", "dependencies": { - "app-builder-lib": "26.10.0", - "builder-util": "26.10.0", - "builder-util-runtime": "9.6.0", + "app-builder-lib": "26.11.0", + "builder-util": "26.11.0", + "builder-util-runtime": "9.6.1", "chalk": "^4.1.2", "ci-info": "^4.2.0", - "dmg-builder": "26.10.0", + "dmg-builder": "26.11.0", "fs-extra": "^10.1.0", "lazy-val": "^1.0.5", "simple-update-notifier": "2.0.0", @@ -1906,16 +1965,29 @@ "node": ">=14.0.0" } }, + "node_modules/electron-builder-squirrel-windows": { + "version": "26.11.0", + "resolved": "https://registry.npmjs.org/electron-builder-squirrel-windows/-/electron-builder-squirrel-windows-26.11.0.tgz", + "integrity": "sha512-7Id4jZ2SkunTbxk89L19yLG4s7UoE4KiGXuxAY5idPJP/dJuWfOV2NmMXODQf+CzSWLDV3w1OcT8BtCH9VoqDA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "app-builder-lib": "26.11.0", + "builder-util": "26.11.0", + "electron-winstaller": "5.4.0" + } + }, "node_modules/electron-publish": { - "version": "26.10.0", - "resolved": "https://registry.npmjs.org/electron-publish/-/electron-publish-26.10.0.tgz", - "integrity": "sha512-YlSPcW8NzQMnjvJsmxJNBKcu7LbkztbnsME49Rnj6uefQLkmeyr6KDw56i16sjPAOQmMjvrQvl26QhNIx03waQ==", + "version": "26.11.0", + "resolved": "https://registry.npmjs.org/electron-publish/-/electron-publish-26.11.0.tgz", + "integrity": "sha512-FeGZ3wLrQv9zIat00WhRg/7Pcboe3B9zwkQojdBgtt6pEQ4MgxA2xll5Cnrtgn0c65ENRWOr5TQ8YBIx7j5xSA==", "dev": true, "license": "MIT", "dependencies": { "@types/fs-extra": "^9.0.11", - "builder-util": "26.10.0", - "builder-util-runtime": "9.6.0", + "builder-util": "26.11.0", + "builder-util-runtime": "9.6.1", "chalk": "^4.1.2", "form-data": "^4.0.5", "fs-extra": "^10.1.0", @@ -1924,12 +1996,12 @@ } }, "node_modules/electron-updater": { - "version": "6.8.5", - "resolved": "https://registry.npmjs.org/electron-updater/-/electron-updater-6.8.5.tgz", - "integrity": "sha512-7f9mHKqrlhpp65vM1MmXD6Xs0l3UnKs4Vn/VfrseldIW7fsrS/8H+Wn0DU5AURL89X74e0Y/yVD5tSaAsrjCyA==", + "version": "6.8.6", + "resolved": "https://registry.npmjs.org/electron-updater/-/electron-updater-6.8.6.tgz", + "integrity": "sha512-taWDzUH44Ax0gi2Zx+107nCfLxky2UfVYnkMlcpcu7WBGrkY8GcSdJIYa3ACHe3L6kMfcXWBIT6tjY5kt/cVFg==", "license": "MIT", "dependencies": { - "builder-util-runtime": "9.6.0", + "builder-util-runtime": "9.6.1", "fs-extra": "^10.1.0", "js-yaml": "^4.1.0", "lazy-val": "^1.0.5", @@ -1939,6 +2011,66 @@ "tiny-typed-emitter": "^2.1.0" } }, + "node_modules/electron-winstaller": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/electron-winstaller/-/electron-winstaller-5.4.0.tgz", + "integrity": "sha512-bO3y10YikuUwUuDUQRM4KfwNkKhnpVO7IPdbsrejwN9/AABJzzTQ4GeHwyzNSrVO+tEH3/Np255a3sVZpZDjvg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@electron/asar": "^3.2.1", + "debug": "^4.1.1", + "fs-extra": "^7.0.1", + "lodash": "^4.17.21", + "temp": "^0.9.0" + }, + "engines": { + "node": ">=8.0.0" + }, + "optionalDependencies": { + "@electron/windows-sign": "^1.1.2" + } + }, + "node_modules/electron-winstaller/node_modules/fs-extra": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", + "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/electron-winstaller/node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, + "license": "MIT", + "peer": true, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/electron-winstaller/node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 4.0.0" + } + }, "node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -1961,6 +2093,7 @@ "version": "1.4.5", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", + "devOptional": true, "license": "MIT", "dependencies": { "once": "^1.4.0" @@ -2069,6 +2202,7 @@ "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", "license": "(MIT OR WTFPL)", + "optional": true, "engines": { "node": ">=6" } @@ -2158,7 +2292,8 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", - "license": "MIT" + "license": "MIT", + "optional": true }, "node_modules/filelist": { "version": "1.0.6", @@ -2251,7 +2386,8 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", - "license": "MIT" + "license": "MIT", + "optional": true }, "node_modules/fs-extra": { "version": "10.1.0", @@ -2366,7 +2502,8 @@ "version": "0.0.0", "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", - "license": "MIT" + "license": "MIT", + "optional": true }, "node_modules/glob": { "version": "7.2.3", @@ -2666,6 +2803,7 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "devOptional": true, "funding": [ { "type": "github", @@ -2708,13 +2846,15 @@ "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "devOptional": true, "license": "ISC" }, "node_modules/ini": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "license": "ISC" + "license": "ISC", + "optional": true }, "node_modules/ip-address": { "version": "10.2.0", @@ -3091,6 +3231,7 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "devOptional": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" @@ -3228,11 +3369,26 @@ "node": ">= 18" } }, + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, "node_modules/mkdirp-classic": { "version": "0.5.3", "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", - "license": "MIT" + "license": "MIT", + "optional": true }, "node_modules/ms": { "version": "2.1.3", @@ -3244,7 +3400,8 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-2.0.0.tgz", "integrity": "sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==", - "license": "MIT" + "license": "MIT", + "optional": true }, "node_modules/negotiator": { "version": "1.0.0", @@ -3363,6 +3520,7 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "devOptional": true, "license": "ISC", "dependencies": { "wrappy": "1" @@ -3554,12 +3712,43 @@ "node": ">=18" } }, + "node_modules/postject": { + "version": "1.0.0-alpha.6", + "resolved": "https://registry.npmjs.org/postject/-/postject-1.0.0-alpha.6.tgz", + "integrity": "sha512-b9Eb8h2eVqNE8edvKdwqkrY6O7kAwmI8kcnBv1NScolYJbo59XUF0noFq+lxbC1yN20bmC0WBEbDC5H/7ASb0A==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "commander": "^9.4.0" + }, + "bin": { + "postject": "dist/cli.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/postject/node_modules/commander": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", + "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": "^12.20.0 || >=14" + } + }, "node_modules/prebuild-install": { "version": "7.1.3", "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.3.tgz", "integrity": "sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==", "deprecated": "No longer maintained. Please contact the author of the relevant native addon; alternatives are available.", "license": "MIT", + "optional": true, "dependencies": { "detect-libc": "^2.0.0", "expand-template": "^2.0.3", @@ -3586,6 +3775,7 @@ "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.90.0.tgz", "integrity": "sha512-pZNQT7UnYlMwMBy5N1lV5X/YLTbZM5ncytN3xL7CHEzhDN8uVe0u55yaPUJICIJjaCW8NrM5BFdqr7HLweStNA==", "license": "MIT", + "optional": true, "dependencies": { "semver": "^7.3.5" }, @@ -3650,6 +3840,7 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.4.tgz", "integrity": "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==", + "devOptional": true, "license": "MIT", "dependencies": { "end-of-stream": "^1.1.0", @@ -3684,6 +3875,7 @@ "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", + "optional": true, "dependencies": { "deep-extend": "^0.6.0", "ini": "~1.3.0", @@ -3711,6 +3903,7 @@ "version": "3.6.2", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "devOptional": true, "license": "MIT", "dependencies": { "inherits": "^2.0.3", @@ -3793,6 +3986,21 @@ "node": ">= 4" } }, + "node_modules/rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "license": "ISC", + "peer": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, "node_modules/roarr": { "version": "2.15.4", "resolved": "https://registry.npmjs.org/roarr/-/roarr-2.15.4.tgz", @@ -3816,6 +4024,7 @@ "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "devOptional": true, "funding": [ { "type": "github", @@ -3943,7 +4152,8 @@ "url": "https://feross.org/support" } ], - "license": "MIT" + "license": "MIT", + "optional": true }, "node_modules/simple-get": { "version": "4.0.1", @@ -3964,6 +4174,7 @@ } ], "license": "MIT", + "optional": true, "dependencies": { "decompress-response": "^6.0.0", "once": "^1.3.1", @@ -4096,6 +4307,7 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "devOptional": true, "license": "MIT", "dependencies": { "safe-buffer": "~5.2.0" @@ -4164,6 +4376,7 @@ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", "license": "MIT", + "optional": true, "engines": { "node": ">=0.10.0" } @@ -4216,6 +4429,7 @@ "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.4.tgz", "integrity": "sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==", "license": "MIT", + "optional": true, "dependencies": { "chownr": "^1.1.1", "mkdirp-classic": "^0.5.2", @@ -4227,13 +4441,15 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", - "license": "ISC" + "license": "ISC", + "optional": true }, "node_modules/tar-stream": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", "license": "MIT", + "optional": true, "dependencies": { "bl": "^4.0.3", "end-of-stream": "^1.4.1", @@ -4255,6 +4471,21 @@ "node": ">=18" } }, + "node_modules/temp": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/temp/-/temp-0.9.4.tgz", + "integrity": "sha512-yYrrsWnrXMcdsnu/7YMYAofM1ktpL5By7vZhf15CrXijWWrEYZks5AXBudalfSWJLlnen/QUJUB5aoB0kqZUGA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "mkdirp": "^0.5.1", + "rimraf": "~2.6.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/temp-file": { "version": "3.4.0", "resolved": "https://registry.npmjs.org/temp-file/-/temp-file-3.4.0.tgz", @@ -4344,6 +4575,7 @@ "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", "license": "Apache-2.0", + "optional": true, "dependencies": { "safe-buffer": "^5.0.1" }, @@ -4457,6 +4689,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "devOptional": true, "license": "MIT" }, "node_modules/verror": { @@ -4542,6 +4775,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "devOptional": true, "license": "ISC" }, "node_modules/xmlbuilder": { diff --git a/electron/package.json b/electron/package.json index d266919c3c..af5500818a 100644 --- a/electron/package.json +++ b/electron/package.json @@ -1,6 +1,6 @@ { "name": "omniroute-desktop", - "version": "3.8.0", + "version": "3.8.1", "description": "OmniRoute Desktop Application", "main": "main.js", "author": { @@ -25,12 +25,14 @@ "pack": "npm run prepare:bundle && electron-builder --dir" }, "dependencies": { - "better-sqlite3": "^12.10.0", - "electron-updater": "^6.8.5" + "electron-updater": "^6.8.6" + }, + "optionalDependencies": { + "better-sqlite3": "^12.10.0" }, "devDependencies": { - "electron": "^42.1.0", - "electron-builder": "^26.10.0" + "electron": "^42.2.0", + "electron-builder": "^26.11.0" }, "overrides": { "plist": "^4.0.0" diff --git a/llm.txt b/llm.txt index 15e7b3350a..6360829f7b 100644 --- a/llm.txt +++ b/llm.txt @@ -8,7 +8,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo **Key value:** One endpoint (`http://localhost:20128/v1`), unlimited models, zero downtime, minimal cost. -**Current version:** 3.8.0 +**Current version:** 3.8.1 ## Tech Stack @@ -279,7 +279,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo └── .env.example # Environment variable template ``` -## Key Features (v3.8.0) +## Key Features (v3.8.1) ### Core Proxy - **177 AI providers** with automatic format translation diff --git a/next.config.mjs b/next.config.mjs index b0c1cdb32c..2877257d8f 100644 --- a/next.config.mjs +++ b/next.config.mjs @@ -96,6 +96,8 @@ const nextConfig = { "./src/mitm/server.cjs", "./open-sse/services/compression/engines/rtk/filters/**/*.json", "./open-sse/services/compression/rules/**/*.json", + "./open-sse/lib/sha3_wasm_bg.wasm", + "./open-sse/lib/deepseek-pow-solver.cjs", ], }, outputFileTracingExcludes: { diff --git a/open-sse/config/antigravityModelAliases.ts b/open-sse/config/antigravityModelAliases.ts index 45c6e8d079..ed19f31dbb 100644 --- a/open-sse/config/antigravityModelAliases.ts +++ b/open-sse/config/antigravityModelAliases.ts @@ -1,11 +1,132 @@ export const ANTIGRAVITY_PUBLIC_MODELS = Object.freeze([ - { id: "claude-opus-4-6-thinking", name: "Claude Opus 4.6 Thinking" }, - { id: "claude-sonnet-4-6", name: "Claude Sonnet 4.6 Thinking" }, - { id: "gemini-3-flash-agent", name: "Gemini 3.5 Flash (High)" }, - { id: "gemini-3.5-flash-low", name: "Gemini 3.5 Flash (Medium)" }, - { id: "gemini-pro-agent", name: "Gemini 3.1 Pro (High)" }, - { id: "gemini-3.1-pro-low", name: "Gemini 3.1 Pro (Low)" }, - { id: "gpt-oss-120b-medium", name: "GPT OSS 120B Medium" }, + { + id: "claude-opus-4-6-thinking", + name: "Claude Opus 4.6 (Thinking)", + contextLength: 250000, + maxOutputTokens: 64000, + supportsReasoning: true, + supportsVision: true, + toolCalling: true, + }, + { + id: "claude-sonnet-4-6", + name: "Claude Sonnet 4.6 (Thinking)", + contextLength: 250000, + maxOutputTokens: 64000, + supportsReasoning: true, + supportsVision: true, + toolCalling: true, + }, + { + id: "gemini-3-pro-preview", + name: "Gemini 3.1 Pro (High)", + contextLength: 1048576, + maxOutputTokens: 65535, + supportsReasoning: true, + supportsVision: true, + toolCalling: true, + }, + { + id: "gemini-3.1-pro-low", + name: "Gemini 3.1 Pro (Low)", + contextLength: 1048576, + maxOutputTokens: 65535, + supportsReasoning: true, + supportsVision: true, + toolCalling: true, + }, + { + id: "gemini-3.5-flash-preview", + name: "Gemini 3.5 Flash (High)", + contextLength: 1048576, + maxOutputTokens: 65536, + supportsReasoning: true, + supportsVision: true, + toolCalling: true, + }, + { + id: "gemini-3-flash-agent", + name: "Gemini 3.5 Flash (High)", + contextLength: 1048576, + maxOutputTokens: 65536, + supportsReasoning: true, + supportsVision: true, + toolCalling: true, + }, + { + id: "gemini-3.5-flash-low", + name: "Gemini 3.5 Flash (Low)", + contextLength: 1048576, + maxOutputTokens: 65536, + supportsReasoning: true, + supportsVision: true, + toolCalling: true, + }, + { + id: "gemini-3-flash-preview", + name: "Gemini 3 Flash", + contextLength: 1048576, + maxOutputTokens: 65536, + supportsReasoning: true, + supportsVision: true, + toolCalling: true, + }, + { + id: "gemini-3.1-flash-lite", + name: "Gemini 3.1 Flash Lite", + contextLength: 1048576, + maxOutputTokens: 65535, + toolCalling: true, + }, + { + id: "gemini-2.5-pro", + name: "Gemini 2.5 Pro", + contextLength: 1048576, + maxOutputTokens: 65535, + supportsReasoning: true, + supportsVision: true, + toolCalling: true, + }, + { + id: "gemini-2.5-flash", + name: "Gemini 2.5 Flash", + contextLength: 1048576, + maxOutputTokens: 65535, + toolCalling: true, + }, + { + id: "gemini-2.5-flash-lite", + name: "Gemini 2.5 Flash Lite", + contextLength: 1048576, + maxOutputTokens: 65535, + toolCalling: true, + }, + { + id: "gemini-2.5-flash-thinking", + name: "Gemini 2.5 Flash Thinking", + contextLength: 1048576, + maxOutputTokens: 65535, + toolCalling: true, + }, + { + id: "gemini-pro-agent", + name: "Gemini 3.1 Pro (High)", + contextLength: 1048576, + maxOutputTokens: 65535, + supportsReasoning: true, + supportsVision: true, + toolCalling: true, + }, + { + id: "gpt-oss-120b-medium", + name: "GPT-OSS 120B (Medium)", + contextLength: 131072, + maxOutputTokens: 32768, + supportsReasoning: true, + toolCalling: true, + }, + { id: "gemini-3-pro-image-preview", name: "Gemini 3 Pro Image" }, + { id: "gemini-3.1-flash-image", name: "Gemini 3.1 Flash Image" }, { id: "gemini-2.5-computer-use-preview-10-2025", name: "Gemini 2.5 Computer Use Preview (10/2025)", @@ -14,6 +135,7 @@ export const ANTIGRAVITY_PUBLIC_MODELS = Object.freeze([ export const ANTIGRAVITY_MODEL_ALIASES = Object.freeze({ "gemini-3-pro-preview": "gemini-3.1-pro-high", + "gemini-3.5-flash-preview": "gemini-3-flash-agent", "gemini-3-flash-preview": "gemini-3-flash", "gemini-3-pro-image-preview": "gemini-3-pro-image", "gemini-2.5-computer-use-preview-10-2025": "rev19-uic3-1p", @@ -26,6 +148,7 @@ type AntigravityModelAliasMap = Record; export const ANTIGRAVITY_REVERSE_MODEL_ALIASES: AntigravityModelAliasMap = Object.freeze({ "gemini-3.1-pro-high": "gemini-3-pro-preview", + "gemini-3-flash-agent": "gemini-3.5-flash-preview", "gemini-3-flash": "gemini-3-flash-preview", "gemini-3-pro-image": "gemini-3-pro-image-preview", "rev19-uic3-1p": "gemini-2.5-computer-use-preview-10-2025", diff --git a/open-sse/config/antigravityUpstream.ts b/open-sse/config/antigravityUpstream.ts index 843f917d82..539690665f 100644 --- a/open-sse/config/antigravityUpstream.ts +++ b/open-sse/config/antigravityUpstream.ts @@ -1,7 +1,7 @@ export const ANTIGRAVITY_BASE_URLS = Object.freeze([ - "https://daily-cloudcode-pa.sandbox.googleapis.com", "https://daily-cloudcode-pa.googleapis.com", "https://cloudcode-pa.googleapis.com", + "https://daily-cloudcode-pa.sandbox.googleapis.com", ]); const ANTIGRAVITY_MODELS_PATH = "/v1internal:models"; diff --git a/open-sse/config/cliFingerprints.ts b/open-sse/config/cliFingerprints.ts index b4d4838e75..c1d2ef442d 100644 --- a/open-sse/config/cliFingerprints.ts +++ b/open-sse/config/cliFingerprints.ts @@ -174,17 +174,18 @@ export const CLI_FINGERPRINTS: Record = { }, antigravity: { headerOrder: [ - "Host", - "Content-Type", + "Accept", + "Accept-Encoding", "Authorization", + "Content-Type", "User-Agent", + "x-goog-api-client", "x-client-name", "x-client-version", "x-machine-id", "x-vscode-sessionid", - "x-goog-user-project", - "Accept", - "Accept-Encoding", + "Host", + "Connection", ], bodyFieldOrder: [ "project", diff --git a/open-sse/config/codexClient.ts b/open-sse/config/codexClient.ts index 93560c899f..746870df73 100644 --- a/open-sse/config/codexClient.ts +++ b/open-sse/config/codexClient.ts @@ -1,4 +1,4 @@ -const DEFAULT_CODEX_CLIENT_VERSION = "0.131.0"; +const DEFAULT_CODEX_CLIENT_VERSION = "0.132.0"; const DEFAULT_CODEX_USER_AGENT_PLATFORM = "Windows 10.0.26200"; const DEFAULT_CODEX_USER_AGENT_ARCH = "x64"; const CODEX_VERSION_OVERRIDE_ENV = "CODEX_CLIENT_VERSION"; diff --git a/open-sse/config/providerRegistry.ts b/open-sse/config/providerRegistry.ts index c878d946bb..6a2e82a660 100644 --- a/open-sse/config/providerRegistry.ts +++ b/open-sse/config/providerRegistry.ts @@ -2175,6 +2175,40 @@ export const REGISTRY: Record = { ], }, + "deepseek-web": { + id: "deepseek-web", + alias: "ds-web", + format: "openai", + executor: "deepseek-web", + baseUrl: "https://chat.deepseek.com/api/v0/chat/completion", + authType: "apikey", + authHeader: "bearer", + models: [ + { id: "deepseek-v4-pro", name: "DeepSeek V4 Pro" }, + { id: "deepseek-v4-pro-think", name: "DeepSeek V4 Pro Think", supportsReasoning: true }, + { id: "deepseek-v4-pro-search", name: "DeepSeek V4 Pro Search" }, + { + id: "deepseek-v4-pro-think-search", + name: "DeepSeek V4 Pro Think+Search", + supportsReasoning: true, + }, + { id: "deepseek-v4-flash", name: "DeepSeek V4 Flash" }, + { id: "deepseek-v4-flash-think", name: "DeepSeek V4 Flash Think", supportsReasoning: true }, + { id: "deepseek-v4-flash-search", name: "DeepSeek V4 Flash Search" }, + { + id: "deepseek-v4-flash-think-search", + name: "DeepSeek V4 Flash Think+Search", + supportsReasoning: true, + }, + { id: "deepseek-chat", name: "DeepSeek Chat" }, + { id: "deepseek-reasoner", name: "DeepSeek Reasoner", supportsReasoning: true }, + { id: "DeepSeek-R1", name: "DeepSeek R1", supportsReasoning: true }, + { id: "DeepSeek-R1-Search", name: "DeepSeek R1 Search", supportsReasoning: true }, + { id: "DeepSeek-V3.2", name: "DeepSeek V3.2" }, + { id: "DeepSeek-Search", name: "DeepSeek Search" }, + ], + }, + "grok-web": { id: "grok-web", alias: "gw", diff --git a/open-sse/executors/antigravity.ts b/open-sse/executors/antigravity.ts index 9d6fce0dab..f08ce7e576 100644 --- a/open-sse/executors/antigravity.ts +++ b/open-sse/executors/antigravity.ts @@ -23,10 +23,7 @@ import { } from "../services/antigravityCredits.ts"; import { persistCreditBalance, getAllPersistedCreditBalances } from "@/lib/db/creditBalance"; import { obfuscateSensitiveWords } from "../services/antigravityObfuscation.ts"; -import { - getCachedAntigravityVersion, - resolveAntigravityVersion, -} from "../services/antigravityVersion.ts"; +import { resolveAntigravityVersion } from "../services/antigravityVersion.ts"; import { resolveAntigravityModelId } from "../config/antigravityModelAliases.ts"; import { cloakAntigravityToolPayload } from "../config/toolCloaking.ts"; import { @@ -35,11 +32,13 @@ import { } from "../services/cloudCodeThinking.ts"; import { buildGeminiTools } from "../translator/helpers/geminiToolsSanitizer.ts"; import { - deriveAntigravityMachineId, + applyAntigravityClientProfileHeaders, + removeHeaderCaseInsensitive, +} from "../services/antigravityClientProfile.ts"; +import { generateAntigravityRequestId, getAntigravityEnvelopeUserAgent, getAntigravitySessionId, - getAntigravityVscodeSessionId, } from "../services/antigravityIdentity.ts"; const MAX_RETRY_AFTER_MS = 60_000; @@ -297,40 +296,6 @@ function getRequestTargetModel(body: Record): string { return typeof target === "string" && target.length > 0 ? target : "unknown"; } -function getProjectHeaderValue(body: unknown): string | null { - const project = - body && typeof body === "object" ? (body as Record).project : null; - if (typeof project !== "string" || project.trim().length === 0) return null; - if (project === "test-project" || project === "project-id") return null; - return project; -} - -function applyAntigravityRuntimeHeaders( - headers: Record, - credentials: Record | null | undefined, - body: unknown -): void { - headers["User-Agent"] = antigravityUserAgent(); - headers["x-client-name"] = "antigravity"; - headers["x-client-version"] = getCachedAntigravityVersion(); - headers["x-machine-id"] = deriveAntigravityMachineId(credentials); - headers["x-vscode-sessionid"] = getAntigravityVscodeSessionId(); - - const project = getProjectHeaderValue(body); - if (project) { - headers["x-goog-user-project"] = project; - } -} - -function removeHeaderCaseInsensitive(headers: Record, name: string): void { - const lowerName = name.toLowerCase(); - for (const key of Object.keys(headers)) { - if (key.toLowerCase() === lowerName) { - delete headers[key]; - } - } -} - function applyAntigravityGenerationDefaults(request: Record): void { const generationConfig = request.generationConfig && typeof request.generationConfig === "object" @@ -828,8 +793,6 @@ export class AntigravityExecutor extends BaseExecutor { requestToolNameMap = cloaked.toolNameMap; } - applyAntigravityRuntimeHeaders(headers, credentials, transformedBody); - // Credits-first: inject GOOGLE_ONE_AI upfront so we never try the normal // quota path. If credits are exhausted / disabled shouldUseCreditsFirst() // returns false and we fall back to the legacy retry-on-429 flow. @@ -850,6 +813,11 @@ export class AntigravityExecutor extends BaseExecutor { transformedBody ); let finalHeaders = serializedRequest.headers; + const clientProfile = applyAntigravityClientProfileHeaders( + finalHeaders, + credentials, + transformedBody + ); log?.debug?.( "TELEMETRY", @@ -874,6 +842,7 @@ export class AntigravityExecutor extends BaseExecutor { userAgent: envelope.userAgent, requestType: envelope.requestType, enabledCreditTypes: envelope.enabledCreditTypes, + clientProfile, sessionId: requestInner?.sessionId, generationConfig: requestInner?.generationConfig, }) diff --git a/open-sse/executors/deepseek-web-with-auto-refresh.ts b/open-sse/executors/deepseek-web-with-auto-refresh.ts index ce890eb493..5bf92404f9 100644 --- a/open-sse/executors/deepseek-web-with-auto-refresh.ts +++ b/open-sse/executors/deepseek-web-with-auto-refresh.ts @@ -1,5 +1,5 @@ import type { ExecuteInput } from "./base.ts"; -import { DeepSeekWebExecutor, DEEPSEEK_WEB_BASE } from "./deepseek-web.ts"; +import { DeepSeekWebExecutor, acquireAccessToken, tokenCache } from "./deepseek-web.ts"; interface AutoRefreshConfig { sessionRefreshInterval?: number; @@ -18,12 +18,12 @@ export class DeepSeekWebWithAutoRefreshExecutor extends DeepSeekWebExecutor { private sessionValid = false; private retryCount = 0; private readonly maxRetries = 2; - private currentCookies = ""; + private currentUserToken = ""; constructor(config: AutoRefreshConfig = {}) { super(); this.refreshConfig = { - sessionRefreshInterval: 20 * 60 * 60 * 1000, + sessionRefreshInterval: 50 * 60 * 1000, maxRefreshRetries: 3, autoRefresh: true, ...config, @@ -35,8 +35,8 @@ export class DeepSeekWebWithAutoRefreshExecutor extends DeepSeekWebExecutor { override async execute(input: ExecuteInput) { this.retryCount = 0; - this.currentCookies = - ((input.credentials as unknown as Record).cookies as string) || ""; + const creds = input.credentials as unknown as Record; + this.currentUserToken = (creds.apiKey as string) || (creds.accessToken as string) || ""; return this.executeWithRetry(input); } @@ -71,34 +71,26 @@ export class DeepSeekWebWithAutoRefreshExecutor extends DeepSeekWebExecutor { } private async doRefreshSession(): Promise { - if (!this.currentCookies) { + if (!this.currentUserToken) { this.sessionValid = false; - throw new Error("No cookies available for session refresh"); + throw new Error("No userToken available for session refresh"); } const { maxRefreshRetries } = this.refreshConfig; for (let attempt = 0; attempt < maxRefreshRetries; attempt++) { try { - // Validate session by fetching current user (lightweight, no PoW needed) - const response = await fetch(`${DEEPSEEK_WEB_BASE}/api/v0/users/current`, { - headers: { - "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36", - Cookie: this.currentCookies, - }, - }); - if (response.ok) { - const json = await response.json(); - if (json?.data?.biz_data?.token) { - this.lastRefreshTime = Date.now(); - this.sessionValid = true; - return; - } + tokenCache.delete(this.currentUserToken); + const accessToken = await acquireAccessToken(this.currentUserToken); + if (accessToken) { + this.lastRefreshTime = Date.now(); + this.sessionValid = true; + return; } - if (response.status === 401 || response.status === 403) { - this.sessionValid = false; - throw new Error("Session expired - requires re-authentication"); - } - await new Promise((r) => setTimeout(r, Math.pow(2, attempt) * 1000)); } catch (error) { + const msg = error instanceof Error ? error.message : String(error); + if (msg.includes("invalid") || msg.includes("expired")) { + this.sessionValid = false; + throw new Error("Token expired — get a new userToken from DeepSeek localStorage"); + } if (attempt >= maxRefreshRetries - 1) throw error; await new Promise((r) => setTimeout(r, Math.pow(2, attempt) * 1000)); } @@ -106,18 +98,22 @@ export class DeepSeekWebWithAutoRefreshExecutor extends DeepSeekWebExecutor { throw new Error("Failed to refresh session after max retries"); } + private executeBase(input: ExecuteInput) { + return super.execute(input); + } + private async executeWithRetry(input: ExecuteInput) { try { - return await super.execute(input); + return await this.executeBase(input); } catch (error: unknown) { const msg = error instanceof Error ? error.message : String(error); const isUnauthorized = - msg.includes("401") || msg.includes("Unauthorized") || msg.includes("Session expired"); + msg.includes("401") || msg.includes("Unauthorized") || msg.includes("expired"); if (isUnauthorized && this.retryCount < this.maxRetries) { this.retryCount++; try { await this.doRefreshSession(); - return await super.execute(input); + return await this.executeBase(input); } catch (refreshError) { console.error( `[DeepSeek-WEB] Session refresh failed (attempt ${this.retryCount}/${this.maxRetries}):`, diff --git a/open-sse/executors/deepseek-web.ts b/open-sse/executors/deepseek-web.ts index 498aec34f9..6b88576709 100644 --- a/open-sse/executors/deepseek-web.ts +++ b/open-sse/executors/deepseek-web.ts @@ -1,26 +1,26 @@ import { BaseExecutor, type ExecuteInput } from "./base.ts"; -import { solveDeepSeekPow } from "../lib/deepseek-pow.ts"; +import { solveDeepSeekPowAsync } from "../lib/deepseek-pow.ts"; export const DEEPSEEK_WEB_BASE = "https://chat.deepseek.com"; -const COMPLETION_URL = `${DEEPSEEK_WEB_BASE}/api/v0/chat/completion`; -const USER_AGENT = - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"; +const DEEPSEEK_API_BASE = `${DEEPSEEK_WEB_BASE}/api`; +const COMPLETION_URL = `${DEEPSEEK_API_BASE}/v0/chat/completion`; -// DeepSeek native API headers -const BASE_HEADERS: Record = { - "User-Agent": USER_AGENT, - "x-app-version": "2.0.0", - "x-client-platform": "web", - "x-client-version": "2.0.0", - "x-client-locale": "en_US", +const FAKE_HEADERS: Record = { + Accept: "*/*", + "Accept-Encoding": "gzip, deflate, br, zstd", + "Accept-Language": "en-US,en;q=0.9", + Origin: DEEPSEEK_WEB_BASE, + Referer: `${DEEPSEEK_WEB_BASE}/`, + "User-Agent": + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36", + "X-App-Version": "20241129.1", + "X-Client-Locale": "en-US", + "X-Client-Platform": "web", + "X-Client-Version": "1.8.0", }; // ── Types ──────────────────────────────────────────────────────────────── -export interface DeepSeekCredentials { - cookies: string; -} - interface PowChallenge { algorithm: string; challenge: string; @@ -32,14 +32,39 @@ interface PowChallenge { target_path: string; } +interface TokenInfo { + accessToken: string; + expiresAt: number; +} + +// ── Token cache (keyed by userToken → short-lived access token) ───────── + +const tokenCache = new Map(); +const sessionCache = new Map(); + +const SESSION_CACHE_TTL_MS = 5 * 60 * 1000; +const CACHE_MAX_SIZE = 100; + +function evictOldest(cache: Map): void { + if (cache.size >= CACHE_MAX_SIZE) { + const first = cache.keys().next().value; + if (first) cache.delete(first); + } +} + // ── Helpers ────────────────────────────────────────────────────────────── -function validateCredentials(creds: unknown): creds is DeepSeekCredentials { - const raw = - typeof creds === "object" && creds !== null - ? (creds as Record).cookies - : undefined; - return typeof raw === "string" && raw.includes("ds_session_id="); +function extractUserToken(credentials: Record): string | null { + const raw = credentials?.apiKey || credentials?.accessToken; + if (typeof raw !== "string" || raw.length === 0) return null; + // Handle JSON-wrapped tokens (DeepSeek stores token as {"value":"..."}) + try { + const parsed = JSON.parse(raw); + if (typeof parsed?.value === "string") return parsed.value; + } catch { + // not JSON, use raw + } + return raw; } function errorResponse(status: number, message: string, dsCode?: number): Response { @@ -51,20 +76,47 @@ function errorResponse(status: number, message: string, dsCode?: number): Respon ); } -function mapModelToType(model?: string): { modelType: string; thinking: boolean } { - if (!model) return { modelType: "default", thinking: false }; - const m = model.toLowerCase(); - if (m.includes("r1") || m.includes("reason") || m.includes("think")) - return { modelType: "deepseek_r1", thinking: true }; - if (m.includes("v3")) return { modelType: "deepseek_v3", thinking: false }; - if (m.includes("expert")) return { modelType: "expert", thinking: true }; - return { modelType: "default", thinking: false }; +function resolveModelOptions( + model?: string, + bodyObj?: Record +): { + modelType: string; + thinkingEnabled: boolean; + searchEnabled: boolean; +} { + const m = (model || "").toLowerCase(); + const modelType = m.includes("pro") || m.includes("expert") ? "expert" : "default"; + const thinkingEnabled = + m.includes("r1") || + m.includes("think") || + m.includes("reason") || + bodyObj?.thinking_enabled === true || + bodyObj?.thinking === true || + !!bodyObj?.reasoning_effort; + const searchEnabled = + m.includes("search") || + bodyObj?.search_enabled === true || + bodyObj?.search === true || + bodyObj?.web_search === true; + return { modelType, thinkingEnabled, searchEnabled }; +} + +function generateFakeCookie(): string { + const ts = Date.now(); + const hex = (n: number) => + Array.from({ length: n }, () => Math.floor(Math.random() * 16).toString(16)).join(""); + const uid = () => + "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => { + const r = (Math.random() * 16) | 0; + return (c === "x" ? r : (r & 0x3) | 0x8).toString(16); + }); + return `intercom-HWWAFSESTIME=${ts}; HWWAFSESID=${hex(18)}; Hm_lvt_${uid()}=${Math.floor(ts / 1000)}; _frid=${uid()}`; } // ── PoW Solver (DeepSeekHashV1) ───────────────────────────────────────── -function solvePow(challenge: PowChallenge): Record { - const answer = solveDeepSeekPow( +async function solvePow(challenge: PowChallenge): Promise { + const answer = await solveDeepSeekPowAsync( challenge.algorithm, challenge.challenge, challenge.salt, @@ -72,14 +124,16 @@ function solvePow(challenge: PowChallenge): Record { challenge.expire_at ); if (answer < 0) throw new Error("PoW solver failed"); - return { - algorithm: challenge.algorithm, - challenge: challenge.challenge, - salt: challenge.salt, - answer, - signature: challenge.signature, - target_path: challenge.target_path, - }; + return Buffer.from( + JSON.stringify({ + algorithm: challenge.algorithm, + challenge: challenge.challenge, + salt: challenge.salt, + answer, + signature: challenge.signature, + target_path: challenge.target_path, + }) + ).toString("base64"); } // ── SSE Transform (DeepSeek → OpenAI) ─────────────────────────────────── @@ -120,8 +174,8 @@ function transformSSE(deepseekStream: ReadableStream, model: string): ReadableSt buffer = lines.pop() || ""; for (const line of lines) { - if (!line.startsWith("data: ")) continue; - const payload = line.slice(6).trim(); + if (!line.startsWith("data: ") && !line.startsWith("data:")) continue; + const payload = line.replace(/^data:\s*/, "").trim(); if (payload === "[DONE]") { if (!emittedRole) { @@ -141,7 +195,6 @@ function transformSSE(deepseekStream: ReadableStream, model: string): ReadableSt continue; } - // Extract content from DeepSeek fragments const fragments = (data as any)?.v?.response?.fragments; if (Array.isArray(fragments)) { if (!emittedRole) { @@ -150,12 +203,32 @@ function transformSSE(deepseekStream: ReadableStream, model: string): ReadableSt } for (const frag of fragments) { if (typeof frag.content === "string" && frag.content.length > 0) { - chunk({ content: frag.content }); + if (frag.type === "THINK") { + chunk({ reasoning_content: frag.content }); + } else { + chunk({ content: frag.content }); + } + } + } + } + + // response/fragments path (incremental updates) + if ((data as any)?.p === "response/fragments" && Array.isArray((data as any)?.v)) { + if (!emittedRole) { + emittedRole = true; + chunk({ role: "assistant", content: "" }); + } + for (const frag of (data as any).v) { + if (typeof frag.content === "string" && frag.content.length > 0) { + if (frag.type === "THINK") { + chunk({ reasoning_content: frag.content }); + } else { + chunk({ content: frag.content }); + } } } } - // Check for stream end if ((data as any)?.p === "response/status" && (data as any)?.v === "FINISHED") { if (!emittedRole) { emittedRole = true; @@ -166,18 +239,13 @@ function transformSSE(deepseekStream: ReadableStream, model: string): ReadableSt controller.close(); return; } - - // Also check event: close - if ((data as any)?.click_behavior !== undefined) { - // close event — emit [DONE] if not already - } } } } catch (err) { - // Stream error — emit what we have + controller.error(err); + return; } - // Fallback close if (!emittedRole) { emittedRole = true; chunk({ role: "assistant", content: "" }); @@ -203,8 +271,8 @@ async function collectSSEContent(deepseekStream: ReadableStream): Promise { - const resp = await fetch(`${DEEPSEEK_WEB_BASE}/api/v0/users/current`, { - headers: { ...BASE_HEADERS, Cookie: cookies }, - signal, + const cached = tokenCache.get(userToken); + if (cached && cached.expiresAt > Math.floor(Date.now() / 1000)) { + return cached.accessToken; + } + + log?.info?.("DEEPSEEK-WEB", "Acquiring access token from /users/current..."); + const resp = await fetch(`${DEEPSEEK_API_BASE}/v0/users/current`, { + headers: { + Authorization: `Bearer ${userToken}`, + ...FAKE_HEADERS, + }, + signal: signal ?? undefined, }); + + if (resp.status === 401 || resp.status === 403) { + throw new Error("Token invalid or expired — get a new userToken from DeepSeek localStorage"); + } if (!resp.ok) { throw new Error(`users/current HTTP ${resp.status}`); } + const json = await resp.json(); - const token = json?.data?.biz_data?.token; - if (!token) { - throw new Error(`No token in users/current response: code=${json?.code} msg=${json?.msg}`); + const bizData = json?.data?.biz_data || json?.biz_data; + if (!bizData?.token) { + const errMsg = json?.msg || json?.data?.biz_msg || "Unknown error"; + throw new Error(`Failed to acquire token: ${errMsg}`); } - log?.info?.("DEEPSEEK-WEB", `Got bearer token (${token.length} chars)`); - return token; + + const accessToken = bizData.token; + evictOldest(tokenCache); + tokenCache.set(userToken, { + accessToken, + expiresAt: Math.floor(Date.now() / 1000) + 3600, + }); + + log?.info?.("DEEPSEEK-WEB", `Access token acquired (${accessToken.length} chars)`); + return accessToken; } async function createSession( - token: string, - cookies: string, - signal?: AbortSignal + accessToken: string, + connectionId: string | undefined, + signal?: AbortSignal | null ): Promise { - const resp = await fetch(`${DEEPSEEK_WEB_BASE}/api/v0/chat_session/create`, { + const cacheKey = connectionId || accessToken; + const cached = sessionCache.get(cacheKey); + if (cached && Date.now() - cached.createdAt < SESSION_CACHE_TTL_MS) { + return cached.sessionId; + } + + const resp = await fetch(`${DEEPSEEK_API_BASE}/v0/chat_session/create`, { method: "POST", headers: { - ...BASE_HEADERS, + ...FAKE_HEADERS, "Content-Type": "application/json", - Authorization: `Bearer ${token}`, - Cookie: cookies, + Authorization: `Bearer ${accessToken}`, + Cookie: generateFakeCookie(), }, body: JSON.stringify({}), - signal, + signal: signal ?? undefined, }); + if (!resp.ok) throw new Error(`chat_session/create HTTP ${resp.status}`); const json = await resp.json(); - const id = json?.data?.biz_data?.chat_session?.id; + const bizData = json?.data?.biz_data || json?.biz_data; + const id = bizData?.chat_session?.id; if (!id) throw new Error(`No session id: code=${json?.code}`); + + evictOldest(sessionCache); + sessionCache.set(cacheKey, { sessionId: id, createdAt: Date.now() }); return id; } async function getPowChallenge( - token: string, - cookies: string, - signal?: AbortSignal + accessToken: string, + signal?: AbortSignal | null ): Promise { - const resp = await fetch(`${DEEPSEEK_WEB_BASE}/api/v0/chat/create_pow_challenge`, { + const resp = await fetch(`${DEEPSEEK_API_BASE}/v0/chat/create_pow_challenge`, { method: "POST", headers: { - ...BASE_HEADERS, + ...FAKE_HEADERS, "Content-Type": "application/json", - Authorization: `Bearer ${token}`, - Cookie: cookies, + Authorization: `Bearer ${accessToken}`, }, body: JSON.stringify({ target_path: "/api/v0/chat/completion" }), - signal, + signal: signal ?? undefined, }); if (!resp.ok) throw new Error(`create_pow_challenge HTTP ${resp.status}`); const json = await resp.json(); - const challenge = json?.data?.biz_data?.challenge; - if (!challenge?.challenge) throw new Error(`No PoW challenge: code=${json?.code}`); - return challenge as PowChallenge; + const bizData = json?.data?.biz_data || json?.biz_data; + if (!bizData?.challenge?.challenge) throw new Error(`No PoW challenge: code=${json?.code}`); + return bizData.challenge as PowChallenge; } // ── Executor ───────────────────────────────────────────────────────────── @@ -303,10 +408,10 @@ export class DeepSeekWebExecutor extends BaseExecutor { signal?: AbortSignal ): Promise { try { - const cookies = String((credentials as any)?.cookies || ""); - if (!cookies.includes("ds_session_id=")) return false; - const token = await getBearerToken(cookies, signal); - return !!token; + const userToken = extractUserToken(credentials); + if (!userToken) return false; + const accessToken = await acquireAccessToken(userToken, signal); + return !!accessToken; } catch { return false; } @@ -320,32 +425,42 @@ export class DeepSeekWebExecutor extends BaseExecutor { }>; const rawCreds = credentials as unknown as Record; - // 1. Validate credentials - if (!validateCredentials(rawCreds)) { + // 1. Extract userToken from credentials.apiKey + const userToken = extractUserToken(rawCreds); + if (!userToken) { return { - response: errorResponse(400, "Invalid credentials: requires ds_session_id cookie"), + response: errorResponse( + 400, + "Invalid credentials: paste your userToken from DeepSeek localStorage " + + "(DevTools → Application → Local Storage → chat.deepseek.com → userToken)" + ), url: COMPLETION_URL, headers: {}, transformedBody: body, }; } - const cookies = rawCreds.cookies; try { - // 2. Get bearer token from session cookie - log?.info?.("DEEPSEEK-WEB", "Getting bearer token..."); - const token = await getBearerToken(cookies, signal, log); + // 2. Exchange userToken for short-lived access token (cached 1h) + let t0 = Date.now(); + const accessToken = await acquireAccessToken(userToken, signal, log); + log?.info?.("DEEPSEEK-WEB", `Token acquired in ${Date.now() - t0}ms`); - // 3. Create chat session - log?.info?.("DEEPSEEK-WEB", "Creating chat session..."); - const sessionId = await createSession(token, cookies, signal); + // 3. Create chat session (cached 5min) + t0 = Date.now(); + const sessionId = await createSession(accessToken, rawCreds.connectionId as string, signal); + log?.info?.("DEEPSEEK-WEB", `Session created in ${Date.now() - t0}ms`); // 4. Get PoW challenge and solve - log?.info?.("DEEPSEEK-WEB", "Getting PoW challenge..."); - const powChallenge = await getPowChallenge(token, cookies, signal); - log?.info?.("DEEPSEEK-WEB", `Solving PoW (difficulty=${powChallenge.difficulty})...`); - const powSolution = solvePow(powChallenge); - log?.info?.("DEEPSEEK-WEB", `PoW solved: nonce=${powSolution.answer}`); + t0 = Date.now(); + const powChallenge = await getPowChallenge(accessToken, signal); + log?.info?.( + "DEEPSEEK-WEB", + `PoW challenge fetched in ${Date.now() - t0}ms (difficulty=${powChallenge.difficulty})` + ); + t0 = Date.now(); + const powAnswer = await solvePow(powChallenge); + log?.info?.("DEEPSEEK-WEB", `PoW solved in ${Date.now() - t0}ms`); // 5. Build prompt from messages const prompt = messages @@ -356,12 +471,11 @@ export class DeepSeekWebExecutor extends BaseExecutor { }) .join("\n"); - // 6. Map model and extract features from request body - const { modelType, thinking } = mapModelToType(model as string); - const thinkingEnabled = - thinking || bodyObj.thinking_enabled === true || bodyObj.thinking === true; - const searchEnabled = - bodyObj.search_enabled === true || bodyObj.search === true || bodyObj.web_search === true; + // 6. Resolve model type, thinking, and search from model name + body flags + const { modelType, thinkingEnabled, searchEnabled } = resolveModelOptions( + model as string, + bodyObj + ); const refFileIds = Array.isArray(bodyObj.ref_file_ids) ? bodyObj.ref_file_ids : []; log?.info?.( "DEEPSEEK-WEB", @@ -370,18 +484,13 @@ export class DeepSeekWebExecutor extends BaseExecutor { // 7. Send completion request const headers: Record = { - ...BASE_HEADERS, + ...FAKE_HEADERS, "Content-Type": "application/json", - Accept: "*/*", - Authorization: `Bearer ${token}`, - "x-ds-pow-response": Buffer.from(JSON.stringify(powSolution)).toString("base64"), - "x-client-timezone-offset": String(new Date().getTimezoneOffset() * -60), - Cookie: cookies, - Referer: `${DEEPSEEK_WEB_BASE}/`, + Authorization: `Bearer ${accessToken}`, + "X-Ds-Pow-Response": powAnswer, + "X-Client-Timezone-Offset": String(new Date().getTimezoneOffset() * -60), + Cookie: generateFakeCookie(), }; - if (thinkingEnabled) { - headers["x-thinking-enabled"] = "1"; - } const requestPayload = { chat_session_id: sessionId, @@ -394,25 +503,31 @@ export class DeepSeekWebExecutor extends BaseExecutor { preempt: false, }; + t0 = Date.now(); log?.info?.("DEEPSEEK-WEB", `POST ${COMPLETION_URL}`); const resp = await fetch(COMPLETION_URL, { method: "POST", headers, body: JSON.stringify(requestPayload), - signal, + signal: signal ?? undefined, }); + log?.info?.( + "DEEPSEEK-WEB", + `Completion response in ${Date.now() - t0}ms, status=${resp.status}` + ); + if (!resp.ok) { const status = resp.status; let errMsg = `DeepSeek API error (${status})`; if (status === 401 || status === 403) { - errMsg = "DeepSeek session expired — re-paste your ds_session_id cookie."; + tokenCache.delete(userToken); + errMsg = "DeepSeek token expired — get a fresh userToken from localStorage."; } else if (status === 429) { errMsg = "DeepSeek rate limited. Wait and retry."; } log?.warn?.("DEEPSEEK-WEB", errMsg); - // Check for DeepSeek JSON error body try { const errBody = await resp.json(); if (errBody?.code && errBody.code !== 0) { @@ -439,6 +554,7 @@ export class DeepSeekWebExecutor extends BaseExecutor { const errMsg = `DeepSeek error ${json.code}: ${json.msg}`; log?.warn?.("DEEPSEEK-WEB", errMsg); const status = json.code === 40003 ? 401 : json.code === 40002 ? 429 : 502; + if (json.code === 40003) tokenCache.delete(userToken); return { response: errorResponse(status, errMsg, json.code), url: COMPLETION_URL, @@ -446,7 +562,6 @@ export class DeepSeekWebExecutor extends BaseExecutor { transformedBody: requestPayload, }; } - // Valid JSON response (shouldn't happen for streaming, but handle it) return { response: new Response(JSON.stringify(json), { status: 200, @@ -524,3 +639,6 @@ export class DeepSeekWebExecutor extends BaseExecutor { } export const deepseekWebExecutor = new DeepSeekWebExecutor(); + +// Re-export for auto-refresh executor and tests +export { acquireAccessToken, tokenCache, sessionCache }; diff --git a/open-sse/handlers/chatCore.ts b/open-sse/handlers/chatCore.ts index 5060b72b8c..74a059e2e3 100644 --- a/open-sse/handlers/chatCore.ts +++ b/open-sse/handlers/chatCore.ts @@ -99,6 +99,10 @@ import { } from "../utils/cacheControlPolicy.ts"; import { getCachedSettings } from "@/lib/db/readCache"; import { applyCodexGlobalFastServiceTier } from "@/lib/providers/codexFastTier"; +import { + CPA_FORCE_FAST_MODE_HEADER, + shouldRequestClaudeFastMode, +} from "@/lib/providers/claudeFastMode"; import { getCodexRequestDefaults, normalizeCodexServiceTier, @@ -1752,6 +1756,22 @@ export async function handleChatCore({ } } + // Claude Fast Mode opt-in. When the user has enabled this in + // Settings > AI AND the target provider is the canonical Anthropic + // `claude` provider (Claude Code-compatible CPA bridges are excluded + // since they already select their own entrypoint) AND the model id + // matches the configured list, signal to a paired CLIProxyAPI build to + // rewrite the cc_entrypoint so the request can reach Anthropic Fast + // Mode (speed:"fast"). CPA builds that do not understand the header + // forward it harmlessly. + if ( + provider === "claude" && + typeof settings !== "undefined" && + shouldRequestClaudeFastMode(settings, modelToCall) + ) { + upstreamHeaders[CPA_FORCE_FAST_MODE_HEADER] = "1"; + } + return upstreamHeaders; }; @@ -1787,7 +1807,10 @@ export async function handleChatCore({ ? false : resolveStreamFlag(body?.stream, acceptHeader, sourceFormat); const settings = cachedSettings ?? (await getCachedSettings()); - credentials = applyCodexGlobalFastServiceTier(provider, credentials, settings); + credentials = applyCodexGlobalFastServiceTier(provider, credentials, settings, { + model: requestedModel, + body: body && typeof body === "object" ? (body as Record) : null, + }); effectiveServiceTier = resolveEffectiveServiceTier(body); setGeminiThoughtSignatureMode(settings.antigravitySignatureCacheMode); const semanticCacheEnabled = settings.semanticCacheEnabled !== false; @@ -2820,7 +2843,12 @@ export async function handleChatCore({ credentials, provider, reqLogger, - { normalizeToolCallId, preserveDeveloperRole, preserveCacheControl } + { + normalizeToolCallId, + preserveDeveloperRole, + preserveCacheControl, + signatureNamespace: connectionId, + } ); } } catch (error) { @@ -3071,7 +3099,6 @@ export async function handleChatCore({ // Create stream controller for disconnect detection const streamController = createStreamController({ onDisconnect, - log, provider, model, connectionId, diff --git a/open-sse/handlers/imageGeneration.ts b/open-sse/handlers/imageGeneration.ts index e6cd541657..8ba6286a31 100644 --- a/open-sse/handlers/imageGeneration.ts +++ b/open-sse/handlers/imageGeneration.ts @@ -18,13 +18,8 @@ import { randomUUID } from "crypto"; import { getImageProvider, parseImageModel } from "../config/imageRegistry.ts"; import { HTTP_STATUS } from "../config/constants.ts"; -import { antigravityUserAgent } from "../services/antigravityHeaders.ts"; -import { - deriveAntigravityMachineId, - getAntigravityEnvelopeUserAgent, - getAntigravityVscodeSessionId, -} from "../services/antigravityIdentity.ts"; -import { getCachedAntigravityVersion } from "../services/antigravityVersion.ts"; +import { applyAntigravityClientProfileHeaders } from "../services/antigravityClientProfile.ts"; +import { getAntigravityEnvelopeUserAgent } from "../services/antigravityIdentity.ts"; import { kieExecutor } from "../executors/kie.ts"; import { mapImageSize } from "../translator/image/sizeMapper.ts"; import { getCodexClientVersion, getCodexUserAgent } from "../config/codexClient.ts"; @@ -699,13 +694,9 @@ async function handleGeminiImageGeneration({ model, providerConfig, body, creden const headers = { "Content-Type": "application/json", Authorization: `Bearer ${token}`, - "User-Agent": antigravityUserAgent(), - "x-client-name": "antigravity", - "x-client-version": getCachedAntigravityVersion(), - "x-machine-id": deriveAntigravityMachineId(credentialRecord), - "x-vscode-sessionid": getAntigravityVscodeSessionId(), - "x-goog-user-project": projectId, }; + applyAntigravityClientProfileHeaders(headers, credentialRecord, antigravityBody); + delete headers["x-goog-user-project"]; if (log) { const promptPreview = promptText.slice(0, 60); @@ -716,25 +707,12 @@ async function handleGeminiImageGeneration({ model, providerConfig, body, creden } try { - let response = await fetch(url, { + const response = await fetch(url, { method: "POST", headers, body: JSON.stringify(antigravityBody), }); - if (response.status === HTTP_STATUS.FORBIDDEN && headers["x-goog-user-project"]) { - const retryHeaders = { ...headers }; - delete retryHeaders["x-goog-user-project"]; - if (log) { - log.info("IMAGE", "antigravity image 403 with x-goog-user-project; retrying without it"); - } - response = await fetch(url, { - method: "POST", - headers: retryHeaders, - body: JSON.stringify(antigravityBody), - }); - } - if (!response.ok) { const errorText = await response.text(); const safeError = sanitizeImageProviderError(errorText); diff --git a/open-sse/lib/deepseek-pow.ts b/open-sse/lib/deepseek-pow.ts index 35ac919a2a..29382c6fb3 100644 --- a/open-sse/lib/deepseek-pow.ts +++ b/open-sse/lib/deepseek-pow.ts @@ -1,12 +1,111 @@ -// DeepSeek PoW Solver - loads exact implementation from extracted worker module -// The Keccak sponge has non-standard byte packing that's difficult to replicate exactly, -// so we use the verified extracted module. - import { createRequire } from "node:module"; +import fs from "node:fs"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; + +// ── WASM solver (fast — ~50-100ms at difficulty 144000) ────────────────── + +class DeepSeekHashWasm { + private wasmInstance: any; + private offset = 0; + private cachedUint8Memory: Uint8Array | null = null; + private cachedTextEncoder = new TextEncoder(); + + private getCachedUint8Memory(): Uint8Array { + if (!this.cachedUint8Memory?.byteLength) { + this.cachedUint8Memory = new Uint8Array(this.wasmInstance.memory.buffer); + } + return this.cachedUint8Memory; + } + + private encodeString( + text: string, + allocate: (size: number, align: number) => number, + reallocate: (ptr: number, oldSize: number, newSize: number, align: number) => number + ): number { + const strLength = text.length; + let ptr = allocate(strLength, 1) >>> 0; + const memory = this.getCachedUint8Memory(); + let asciiLength = 0; + + for (; asciiLength < strLength; asciiLength++) { + if (text.charCodeAt(asciiLength) > 127) break; + memory[ptr + asciiLength] = text.charCodeAt(asciiLength); + } + + if (asciiLength !== strLength) { + if (asciiLength > 0) text = text.slice(asciiLength); + ptr = reallocate(ptr, strLength, asciiLength + text.length * 3, 1) >>> 0; + const result = this.cachedTextEncoder.encodeInto( + text, + this.getCachedUint8Memory().subarray(ptr + asciiLength, ptr + asciiLength + text.length * 3) + ); + asciiLength += result.written!; + ptr = reallocate(ptr, asciiLength + text.length * 3, asciiLength, 1) >>> 0; + } + + this.offset = asciiLength; + return ptr; + } + + calculateHash(challenge: string, prefix: string, difficulty: number): number | undefined { + try { + const retptr = this.wasmInstance.__wbindgen_add_to_stack_pointer(-16); + + const ptr0 = this.encodeString( + challenge, + this.wasmInstance.__wbindgen_export_0, + this.wasmInstance.__wbindgen_export_1 + ); + const len0 = this.offset; + + const ptr1 = this.encodeString( + prefix, + this.wasmInstance.__wbindgen_export_0, + this.wasmInstance.__wbindgen_export_1 + ); + const len1 = this.offset; + + this.wasmInstance.wasm_solve(retptr, ptr0, len0, ptr1, len1, difficulty); + + const dv = new DataView(this.wasmInstance.memory.buffer); + const status = dv.getInt32(retptr + 0, true); + const value = dv.getFloat64(retptr + 8, true); + + return status === 0 ? undefined : value; + } finally { + this.wasmInstance.__wbindgen_add_to_stack_pointer(16); + } + } + + async init(wasmPath: string): Promise { + const wasmBuffer = await fs.promises.readFile(wasmPath); + const { instance } = await WebAssembly.instantiate(wasmBuffer, { wbg: {} }); + this.wasmInstance = instance.exports; + } +} + +let _wasmSolver: DeepSeekHashWasm | null = null; +let _wasmInitFailed = false; + +async function getWasmSolver(): Promise { + if (_wasmInitFailed) return null; + if (_wasmSolver) return _wasmSolver; + + try { + const solver = new DeepSeekHashWasm(); + const wasmPath = path.join(path.dirname(fileURLToPath(import.meta.url)), "sha3_wasm_bg.wasm"); + await solver.init(wasmPath); + _wasmSolver = solver; + return solver; + } catch { + _wasmInitFailed = true; + return null; + } +} + +// ── JS fallback solver (slow — ~5-6s at difficulty 144000) ─────────────── -// Load the exact solver extracted from DeepSeek's worker chunk. -// Lazy-loaded inside the function so the standalone Next build can collect -// page data without executing a dynamic require() at module-load time. const require = createRequire(import.meta.url); let _U: any | undefined; function loadU(): any { @@ -16,16 +115,7 @@ function loadU(): any { return _U; } -export function solveDeepSeekPow( - algorithm: string, - challenge: string, - salt: string, - difficulty: number, - expireAt: number -): number { - if (algorithm !== "DeepSeekHashV1") throw new Error(`Unsupported: ${algorithm}`); - const prefix = `${salt}_${expireAt}_`; - +function solveWithJS(challenge: string, prefix: string, difficulty: number): number { const U = loadU(); const createHash = () => { const self: any = {}; @@ -62,3 +152,38 @@ export function solveDeepSeekPow( } return -1; } + +// ── Public API ─────────────────────────────────────────────────────────── + +export async function solveDeepSeekPowAsync( + algorithm: string, + challenge: string, + salt: string, + difficulty: number, + expireAt: number +): Promise { + if (algorithm !== "DeepSeekHashV1") throw new Error(`Unsupported: ${algorithm}`); + const prefix = `${salt}_${expireAt}_`; + + const wasm = await getWasmSolver(); + if (wasm) { + const answer = wasm.calculateHash(challenge, prefix, difficulty); + if (answer === undefined) return -1; + return answer; + } + + return solveWithJS(challenge, prefix, difficulty); +} + +// Sync wrapper kept for backward compat (uses JS fallback only) +export function solveDeepSeekPow( + algorithm: string, + challenge: string, + salt: string, + difficulty: number, + expireAt: number +): number { + if (algorithm !== "DeepSeekHashV1") throw new Error(`Unsupported: ${algorithm}`); + const prefix = `${salt}_${expireAt}_`; + return solveWithJS(challenge, prefix, difficulty); +} diff --git a/open-sse/lib/sha3_wasm_bg.wasm b/open-sse/lib/sha3_wasm_bg.wasm new file mode 100644 index 0000000000000000000000000000000000000000..ac92b1d87e8cdf3a5c2af4d189743c1f9d5feba7 GIT binary patch literal 26612 zcmeHwdwf+_o$p#}?|sfbujGUV2qeHdr?d@)kOV?b09&)8P$GT#XsxyiDWruH8ps1m zZKoV4QLxqGj5E`ZuR(9eQmq!}I$E__oM~%y)Z)ErJ5C+xOdWgg^`m%4$6l@Fe!su9 z&&i`$KhEDn$XWZhp1<{5zx8{qwNKQ**iBj~r7zEHHv9JJeVe^~k^oThtTt;rX%_h? zVj3{5WvI;wfp1frlk&hKucJLkDdqcK!X%YRV+^A_&o_SPd!A=JrM;v|7^Onv2Pnj+ z-lcQ7z|*QBk-~UUrE)@Ll7FU?iJJy*+BtfQQL}Fbx|_BR4(=Ko930xTZD4HMrahf1 zk(T_iojdjnD!pjarkk(dKD_nD!Qo8O?504LysteDVQe$xM zuAQUfn>y6Ov*dQFbI+2yLN%vmX%*>A_I$If=q+!Xv#4(AdFlW4Dc$~WMHBARx0~MS zKUPJ*(pUJsNWXRF)+=%W9x~;kj`ofeg6KmZJE2;QDu(NFezd5NjFb(A3LfhG^30j! zWoQ;e39F-U&y7Vjv?tOdDAMCY(Z%ILGGmjG8ILM|bwZWdiC*XTMyjB)Cc^|x=b?t) zGlX7~(V|P5#|yp(^sH_*KE^L5Y|x)m7ReBvy({pn3&tjjUQVG050J|G8P;z^1=iHo zj~48S{E>2$cY|Ki%z|c&=L55XZ*@*(vN{vp6VJ_$@-pY>1&`Qg`kRYE3xnPuZe6&*Q>SrrW$+`}iCU#kg=-X$Q4XHB=sT4TL#6IRE<__y2O=8T0NUIm~w3G~yaZGq*gZpoNgg z%oi2NhKELZ0I8Y^N!KOmmMyCFKv+kOpn}j*HOpj7PRDD-?2t3%l+cx%5}TCqkuO`- z%yqMVAz=+DgKQ<)9Mhl-AbU5}jxqg2gx-)Q!B?OKMrf(crU+yeshEuNQKL;_4py&k zMz3gMG53ILF8Bb zIbJm2Ml&>uVl_Upt(cg)+{l|;ZlGCPZcWga-pHBnfuM|+#>Hcg~xzG#4wtUgwf9W=%J&a4A}NkL<^K-kNR z@)Rq;C!RT;uzPHE(jLI+llIr;xP8wuYcplmiHMarYkzXqzD>-WHFp+y71ND3qs-a} zDM%bF7cu(%`w%jMWVgXI+GMg2Z0LH_NizekNm3wy2;iD1)?sr2e5bt;6cBDuJw=MPLeiz0D)42UkCLy`dq>PX0`yDt;-|u>Izw2tp z)Au_!Ax4<8-@#rp_q&<8-~Fs70#n#JXJ+nqcINiGhfVB$rqDxg1Q!O;y>0^)6_`?V zM-V+&@wxo@J-yIP(Z2OX1F;H;hW!Kq8y!art}3+sZ6lBs*sjb1vS>w?_$({%16h=h zT-yF-ln{sLfocK9t3X8*6c?XW!I==&#RSCX`kXLBC`(Db_;B1xMz;F0W^x%bE!IJ0 zq7!(G&Me~a2hpk9KgDFNoNXuU|K7AfWXnXglVnXX9*mOOPJQGJxt(uT*92;AC9Fv{vmo0#C;!Ol#GCO5jvn!n9WHmjs@VOPJQGy-476 zT*9<=hJ+BMj{cyWD&R#*71Qff3M30PE(R9?12dx^)ub`(WSz-~OmZ{)BPWGU z6OkRFZVo{QU`|Z{OWBVg@Eqn#j4Gs{n)Bu85HJH+GB7-Bs${~m3Mc*lwow@LFS z5!IJt`ayTo^6-ZWG>2kEu^v`~SGDuj!z}iwBn&)|NYg}z-lR{Y@*F5AqbazuTx6|+ z$w;vy2keC!C17IFdO?mO2FgH;G#!jdVyG#^FdzoKpYftMNeoyXGp#F*E;eN_!=}V= zVK$W!eM>}#iX@6mvN}^NCT0&Bf{@U+)y-736BRh3;AI16eL-Osl<6hKV8TcBmq8!W zDsw7=UXnavD44>vZCTVbTB{Bf_6jR<*&qw~Bp3jH@+YQTYbRA$>iPnytA;RaFD~ee ziMTa|^?+R=y>nkxZ4E9Dn9=H?GI|j@Oq;M@K8y5#4Ipxe$Vo@F-e{{jjAKr(l87q+ z>Cch*0g8!TJFPCz@SO(*uZZ?fwc8>pUj}zt1OlG_bL$0P!JG6KV3EO&rQG6yFXVlfG=L%l^nj1!`OcEF(dP3)C(}iB6 zo-zh8g<4-X6mvD`^lP>tc433hK!WwDOo1&<>T)3u9Q^2A8XL*xF*84(n-9OjXJ-_4 z9D&);c3X+%sRifPZt`|4|psYeI4xBrqq1a z*@MnhF@sUX`9B_@<4m`CfN9umjs>V>h6-8J>-C~>njK1~2qKk>VV!4`h62zwSze}8 z^vJ$Tb18%fZifj?wGh(GXCZ34^4H}I1d&bJ?0Wc>?4}$K4mjyn_Q!? z_%?-cim7e`>V?H5+zskPX^e3y__vp8B(a1|8@V}L8Nw_E%Pw6O!^j_^8q? z=++x4rkX)LYRpumY#P{IP~O;_(>BaA-~t7Q{}`?DzCvhv`}Wz{eahyVYaIIX*KBPr z&b<;m+So@-cHL2E!emY-%7uEQNBwf4foqHBrxEU`GBTL2!REnU`CK7~Tu6$8p-o5^ z`I31ti9BzOdID?`*>3X?Q`C8s>7mLAJf4WN$Wbf;Arp9dF$sD7a1b>Xl6Fq9vG2&Y z)mt&S#=>mD;Sl&Y30i^}mH*%(7qj57*}sb4J_;sMxEVv=BrP&U(F%usAB;d`~Fp3LnQ7iq`23>lwdT@ zBrKPaJ9XUDD~!OtQo?03x&VJnL)HzVrwo#cI!3`u^py9>_7Z-J5bSeka0emiHk411 zufZ{u5LO-17n22Hr-NWTESF8Rsr!OrcBohfE7NA-$fn?@L+JHFIxdEMj7kzfh`uYU zgy=@}s5~{=cqpm{6+vybAo=DUT+1e_`b^0zMis^oKjqlqV9D!|oG{L@$mx)r4lJ@o z-KKK%!u}H~zZe{vwYf5OP0|TA?Emr_pvv74m()p#uwgFJ5OGOc#|2B-x^kwFMK#WF z7`vHLZ&tZ*j%09eIOfgTy8J9q0}W?^w(Q>KENY2B6p9wJu5NVF$Y^cq*GUW^OI^&7 z-)Ex<#0g82z&J|C7N=DIHR_SRcc-F?#%kS-1;D2E$k|K0L*Yb89tn`?mv~2*B@z_? zx5yIj9%k{80Jq2z? z6U^cxvrbFaNoMhpSuaS|)6C){vnuj=idlSQ)*<_ck))DzU%`84L>mK=hfmwWH z)=~Maq>#l&W*w8yL(IZsHt!3=HwjZ!{5MdYwy9$fr4ZehIOu+XbPRn$AQMBM6v&Gq zC@!?~W9U-?1u^t#ff6zFpg_qOIxbKcL!S{S6+?d`P&$VGyFi&3`m8|N82Vd*axwHd zf$C!D^8(e!&_e>{W9SP4HN?;t1)3E@UlQn?7=8a7ieJ&eNCW6(CQgWdxA2Y3N1;6 zmJ@}Rq(VcWG*j-+h1k5%R5s%jnrBn_AYD!8P?A$lNtM;H}r6X80Ehze8VIIvF zsCFpR5XM3as=(T2hJr0LWjKrt{aGC@jo}cW#c(NTd(oe;oiH3Nz>M{QtQWTqiL7fK z64|gB26{iFXeh1yDzYAtHE5{gh8`RGGAyjyk)qd((*rj2(2(AY3=3P94OPuFv^Z;P zUhP2)13x`R=O6+5w7gisZg)meNTVqFe;+=fqUF)Ck3gDQzz^X8@bfYJ&9u($6XO>I zqOVc#xT_2hgqI9ca2;%8Ms$n8I(m>OK$sc^WwKnL+CovbC^nOagBPqI60esBM>Ydf z&Y*ADI99=i19{ZtIarShwi{M?bH4-N38bQ3G2oXojJ*!QJu4(&wg3fKi{KPS#@Qv@ zKJ-NsH%X0W6I??8{ag&Rsv3*XfMPJ&B--GasAU*;$23uqA$PdV-G&3pp&}f;G?t|R+zV_c@tZKZjee^t1ehvw>Ho$9GpMesSP-b$uLQhW33>|{ z2?=Csj%sdhu!UcTh>7%rQvyeU*y2dJ*`|Trh!-DgHf1;2k9sKA7d~)D)LSNAgD+zNBVHTP30&RafauSV#ksqB-j+ALc6cn0E zz#H*$o~S1G0O`b@(P;mHgW(8P9hCjOB{+lpJ#DgQEddU+A;4G^uV9D3W*KowLn?q( z;Ir+C&g_3NiP*kN%hCRdzXRt1GE<8)Zx|D4%;`nMjm$XcN48cm5^550&>lpWSU!DR z|7>-*Kq2W1tXK*0yq9-`O60*L_6^TGC{_yG5-=#iuH>kgF=O7bUUl{O-eobSF9IcoZ*$zMIm>t%X;76nZOTS^sLm*j zjsnuA5OCWf{Iv(vMpEVz#ULJ$gN>U9S0HHu10cZ}n}-dFUU+JU5^yI>-F$-r2-&CW zc~bz{5MM0FHfV))KsNDUQyai%izq{@V@&TtI=4YTg)GLCjyS&SEAv!Fr}x2ThSzAS zaRRA`YX%nxqQx|WDIqX&J~jvfj&LM6`=?0dqONN-I{xPcTKiRCYMLRC1efdR8MQtK zO6llKurZh59R$;-N;-|r@ysc;R!f9)GV6KGEUKnjt>+|*NAtC;XCw=pJel>7WMRQ3 zv%W3eYpiwD5Mh;~2ao#@DGIa;M~faZGKkGW$l@}|`~Tcswm=qqa7tdERc4l1wb7ND zS1g69c!jpFP&xw@hWXZm8T^e1ouJRC!05^(Qbk0oRWuu18T~vcBt#FPk_cOdkx+t@ z-J05A??PMn)9B|F(ml*mbjN@Rfn!w_? z{jq0C1=t|S^7l+{wn%cZ!KZb$P;#>~au-N$enxH!dex&hLIV{w25-U)NZ#K988U<( zihd=J2(;6c#)f}JU=#fgX#q`mUfr&NHRfQ=64O-jgq6Lh82$47uyN*L_9;*>ItYpr z0{ze#FOTTR(znH)P_QFC(u6DnF3Ro;!{q>fJBiS*yRJP&**-gNX5 zmoNIr>GXO4rvy0lt@L`_FNse4EIkz6vJp?mKb#qgMmCNz_w-YE-o@O?X*~UK$42H> zD%qjv!{f|8`EfkH1C>W9v7*X>o}uW$$KHfs6rj_0^Z;cy^ylsdGOf`&k0AM&iH`j# z()$f@gG@tZIlX{~xkiQ5HYQs3`(F3*ST?u&8Y^^MTN`-L7HG!ui$+fFZp{7huXR z@pcvROg0o6nAk!ylZSKxQ4sjLy0C!hw!$nXy|6Qp;0gzm;~J3&q=yhaOFUJ` zMqyz&)LYs%!EZp^WCH&{fOBl4oehx^3T*oH;fW%`mJ^6$wAclffs~vSLAy$!o+z|| zfOQjn=5TSL1U%*=dfZ@}rCJV^teGg9iN4a|;v)21XW^4UKBc6*4uL?9;ZO8ke7I=) z_D$R|0b=HCon$9$(?s8r!^Hv?EI-kA!Qo<&RqUb(kRY&gC;HNdi|1mcTPFH?4i^`r z|Hg^F`oqQZTu(fJXrAb6K3qKCo(t)kndn=5xOjmpMDWt4C;Da`E~aJ1eTl=xR$vxP zVC>=&SBYmE^C$Yk!$q?8tckvPhl@)Eht>(u-M8mV^j&ng$g5Wk6Mc<`p>7aT3;)!AcEDY0LK#g(0yaj9RLaALO51(%rOX+!7Rj~3Bn-=iG2{80RTM(c) z0X|OK3k6s@0WQA4o@dV`I02?D+C@@gC%~jjZL0uFCcvZ1aW+w09-Ux(2CQn+i1lcs z5bAr8%qw|UBFU7zRwQ+Z`mk^gf=f*2mb`0_q+ICGgD?Pe4&r7kY(%(;>FkoX8A<3O zj(*9*UbPyLG!_~JpqS1odE1cWO4uUU>?IGI$krpa#=-h;hO;0}Y5>o zCaG`cnS+zuCKatZ9!57=Eqr)L>Dos#c7$m z1^~CBcD0mrJIkF2cMU+oHgsV#U`MedxRWq6#S2z|3FaNv3v;0ecNDe8tM2Yn(LQvO$vl?SA>G822rzlDFTC0* zu;)&Jk;AjygyE)jXS-0rR*oJ(uIkw?+c8^CH+&p?a3}MmcLy$`6azWiWjkCI2;?XO zXY1J8DL0@y$?)3L*Mfo{DY`7t6NqF5?lgmUSx%s(94OMr4Y{ZY^?5C^QN06Pg$vFE|H5)b?;=b6uZR*Jc3^p8#JjvUz=$5q;v=(;%V#BlEIu;pA^AMSEIu;pgnS-h79W}QgnZt^ zEIu;pqi;v8DUOpdU79W{)T0T!Oi;v8DK|Y^g79LZ1 zgm7LUjgI0b8#o)A9IX@U{e9>Htb=oGWW8vx&NwbZMe*C{ zsKT6gqe=^3#DZ%9!-h@38wtd3%7~g_oKVI|H@o)SM{#@L2t?82#g|yTfglboyX0Qr z&$QUNyj6l=8bbEem_^^k&Uv96dK~*gV&@QPjGZTHBbWwRCjlug+c(eL3I`u=TX=Yj2jZ3~RtD`5_(mJ}i>4p;Ae{Bl{!u;* zA?g`kF$!M?mnFm~!G(`M z)r)MFz8M6~^uDCA7A5H#XCY>*+OUcjtSpCqXW_)&i*c2RqT6ar5pM0~#v6OSpqF$d?< z%PZcl!rZZrw?%t}GB6dr5pWaMMUX_H*Wa9nTbU2U76X4lp2WHHT^lj(FwMzRCS2y{ z(H2+@(+_bk1ne&-Q{cQmaANd_%Fj+uUg`wTFb2SDclSagi|Tg981LFy8nG&Ke?mjr zps;E?Lnr%1EXGs=S~NG%7oAN5+8JdaAO+9M4QMeErY;@_h?hVt9*NUKi`6XXKhknW zLw3n%VYOdQ!C5CY>uc4uu3VaLN5NaIlaWK_x*sKq+uZV?WM5Xu7P z$U(5rIuw!)1soMS6rjNnIvh$jn(BbldlSmwB0ei* zeqzL!;akHnH_&I4zYK>qLwIQkkqbcBGR_1+$~OhdQML>XC9kU)1V6+m!NS0$u?Ta3 zLv%ro-A&CbO3;FVDlJ3ps3Cdx0Q(yNWbhEjlYliW3%-+#dxE_1%DI6;kYBNarlAHg z3j=r3o`4vcX*Yl!XH;@V2Ns0kmx5+D&g^4V>^!))GLooRIh3LCLx(C~78+26O+y3b z2ioH32G(@-vN}eM6;0LD@$)!+gC&Mr@Q^H-Ul>tvSgbfW6pMMs2cGFA8rD#exfg9Q zd%k#Erqp$>^%*&8rLT(NDUw8o$!mR+@9*(dU2wk-*3+=ns&D&2IpWebjeF#ARjVB% zRDg*<+VOs?Z%Bl5FcE^*ZM?vgA3dNNep5m^X=wpoCdG)vNQKuA9e=- z9GF`pFT+%)Kv4@x$k$%0feXI=3qdXIz@=h^K~eDtRf9ehsT;AdR7>&*-d8gJja>$BZ!e|)!BuCMT;YBbQ zwhEyXa0xn#?!i%1e!k)rOdKaGgb5&Ju{=niuCWVv)iR6Z=sQo4bndDpCk;O&zF66T zibpVLFb?*?_jG9pb?f~4AX~U;4X3i9?5*p=p^s+ z(5sLUL=jUss3Gy~sG4}=3YNRog#>5|8378?g`{ki_yzPOy2a_9+z*khiOV{0VK5g>CCgXa5Lkk*uK9*45hR{)E(yOa|*nfm-by z%)}jx^%lW4L?;ylgH4V@GGvi7NYMl`2PmKbS8b&RnAr(GwsgIS_{=w=i6zBkf3UF! zn;aa&S>)m6M=J9r1L5EZ=piFbsf@jVE98z3eJm%LEke8l!W~ODV$<$yb2kiuA9%qW5fHhEKBERTBp3i25Eslhf@u^N7ijp=zbalmKn|J8peG*k z02KylYIoWpXVEz{@>x0;t>*5QPiqcMJq=CQKQ?K#e~2A00VoB=!)}P@AEmJ`@{Ayo ze3>s&nf;f8@}F@~GW%(9f$=IJy1!V(_xB+wS|E?|VnLb6jzC6%$@BHl3lOm)6tHoN zFo9?XBZy}hP%{!xGl=K8n3~ft5DWdN9D|S)h&U(cjuw@@CFB8N%%^@S339_!q))4#=)BjZw9>C!P^LL1H8?_y9nu5hOnV>7c(O8tFU?YXGH~FDq{Szvb@3F#=6>E?~ z@&R`)Fa^HDhy=Z{jpbqkV?V}N)0!b}xB@CZN)2N}WTD=u<^bvw8lmM?ilOK1eMst7~DLZ|5q@SV=|)qKkc*FT(<3)0fg`ji;I z;18?$XweJTm4+`_19z)nn}RR5O&JUp09i)3){W`8vApOZRHqr?xv{)>EHJ4Xh}H~< zFT+}N;>BahT+P`B5}U9(UUi`F#*=#aK($H9SZ-2h8|Zp0o$!gURLmXny1C;H2?H6P zNsv3hl(J3!DDJoxJA;h)N}bE0#?;QSjEqwMp$PIdM1P+|VC97aIS=;0T4JMst3X?< zWj+aOG&A{9s?Mv7>|`t-L?7mbx$)}^_`DAMn%SU$vfdu)OJEA)4&dAB z+pV(YB}hel(;QTxYl+2Um)3(nBVY)=B8T$>MrUlUVwY9TRh}$WElziG3p8MV0y&6O z_An{EJ<0_h@;J`x^Gjs3nk*Lii_#|UI^+vC^>8vq0&~20%FZd&8YEIAVKkCV!ar;S zp$18ZJ8qd*VdzLZGnW(4`3AH{X=C)n0c>6AC%)0ljyVa`DbV!Kv~g5#3JJX-91QWx zlYjxl9&k(Yt1Unzt1|yv;}(K!Wapl6P1fpayn+ZtNm(RlL2Qt-h>6N&wCH?zqP=V!=f46zQ+vA}&j%g%78L&(#|X!Ui=}l?6W| zs?G(4Far;@sZ@S0XHpFnLGFMe5xm)#RhkFnNJD;^U?d)2^;USJ5D~>fORfTh+!uIj z2va|e_mE-zQFw5^(9>WLZr<7tLcFrqbhKZN1E8FjsfxTEkTdXrmZ>v*{c7B%qyy99ZN0~1^{V6soMK4@`jB}%aWIihW->-oc95|2nrG_#2o?64#nvk ztf9QDgIECqfCv_2v&7M9G=z(f_XR`(SkEy$-uH!c#ydJwYoV#s5($8zSXD-wR?CZP zA<*I~Aclu`DEJ;aG&Kg}%L!u3I+PL-z9*5_<8coH8-ch=gwWF90;aV|L%-qZ4kWom zF7zOdhndAnn+BR@6h(<4L(iV>FG#JTMI+!$6>XC1+)-j2U;75158R7oWQ3~QEOtwY zMh1;waVHRKVbfitD?$%Z78&9vdeJQ0n5vvsBOJr4RUgI34CLc0SK_l1bc!A-v@hmk z-PmE^D5NvA*EcjiEs68 zlbq_Czs%VzIjwP>6AD?^NY>&w>m;+Tlq@?XjJ1JZ$wDg@Q6C6(AQNH35QPU0RZ;NH zhJx#TDhjUiDhdpWZD3Rm8x#x~$X5yA?A~>LS8aZfLoc77o6XeD-Ei3{n7iSs?>f8T zpd7&L(bGVkF}~=t5E>FEqm+OEc1U1yPbkp42M--(R|y8o#mdsqa_U1tc7UI_MHSTt zW!Q%x#zhBGk>rs9Yv&>4(FjqQIu-o@K(rKU4Kg}|_U9@X=;x};&wQPsP=eWo_g5f~ z@v8nZB-WiKqSIDD?mhj*z!Mo38A$MDflLr@GQIqvEX=zX1M!q)SXMisNjCQoh9!d` z>d)`P!24Jdze7z`P+l)ed3L#X0JTjK28 z@wizErAJ?h+Za8^p<&2oywX-18_}og&>;f7FT((4{uB&Ec~miwHN^X8ltS|5q(USN z-NKhMgm3_wI1$nf`;(7y)hY$ul#B^QRFMx_Kz$kD%7`S+-HKV{f@nzm0&XqJE2nVb zXefYpxYF3AuFGmyXYB{)LhJ`g+z&2>NI!h>17AMTXklx>Nn&Fx3{Q4vkd=Y~#}~@- zhyX8?#Bp0umHrjzTh@rQ?HIgiaCm%ReEZH}J32VN zdvthks~s4&gB;fG9>zEL4sIDA+`8kI_N&GQN5|Sn-?4nxz;OHW(cNR?yLYvZ@7%d# z%eH~-!(;9E9^mVD47LpnjBeT1-PJa*3!S%Z9T>fN`!MlpXA7pplh4c?9T>f(ePG9q zom(V(Y(a%a?a_u2|W%s=L&)df@skTL*90f@YZN<|}q_?rYZU9=>^W zU{~vs%@&jxu$wR6IXt-8?itvzdk|lDJh<2H+&yl0-e9laxqEo)*cv;&ZP4x*9JbrX zti2vZgk44Cs0oa3G45X@orQD_0MeiT@YOfUAlR8p$-BIf3=~&&_(b?I#qH|?uSLdqE?#@zYPv`0t9VRQ#+ z-Bs%9=~}(2V^!y>6{}XR>RPpGRrjjWs-9J=yF0o&yH|9t?C$Db)!p4)>h9@YUFs-x zmR6Kjmbyx-O5LSWsi(BMr=zE{XGPD-p01u%J>5N}o}Ql7tAXNb48Iy(uST=g$Qm6O zzH!ikM@GkEI#ns^N^StVjqTXJWspP$VQ(DYW|jJearAozX%X~rbq9yH#(m^*VJMIM zYPsvdt%Hm;W(UUI0-=!rssnB2pv`)uIi%MvU%vcp*AL#feb~P0BFny8`LM*^ybbHi z9>J4#^XBcSPhPwkDR<$mNICYMNV&Gx-!fih0dmFg&T;S&_Qt5=8F2bqyB(7s1MXwn zw+>p{$|hqN2~*yz9zZ|b(Vs_pKGGi|<*xrR(gf1#IP75>GrH!r_Km)qU$uUX&#=4N zZ`!$)eD+$@A)oyMzp&0Gd2#pf_ANWN4z};YMwI=`+DdIh{RK$pn-zPr(;FnjOn)R;3@BN6Mt819Gq_bpu7S=9Xlb&NR;LUcKhn{ZId6s&wRi$CBx_7vHe`?munVx#^Lg z{rs)h|MJB%Z+z1SKDfO7g4U}(eDtIL?cV#2ed>!3KZ@@Tn!RAntJl5$Vq_|-r8>CewR_PB4)J@5S1l|5@VyzbH~-+0y4*Sz(*w{PAuc*D@x-apy*?t4G+ z;PDeDKmFkF&L95spS`_!YvB29-VL5^UtT$|!0W7U@fW8S21|q2`gIppK9N}LFZNr* zuFU0LS9X6XH76Z5tzEa;+Y+Wa<^%<=Incd5{>Gr)PbX8!UVDL`O?7)~g84~5o4m5W zv@*9cxjalK&i59CrgHKPd9SoAyl~F^^IIC{rY^@&ug%R%rV|^&3sSo?eHUMtSR14h zug9g%yccBN5}F0qFWeBOD<6M*aa|^z$ept$kxn$WEc549zVNE8Z_I8;rPr@(-VnYq z*Pl#RK3A+uC)TGIc$f5-ygH1!I+@)7v%luT*)Fmn(xZ`QR!OM9!`W#{Meb=i79@6DQZ zPHK*x>o@6n-uz^)? zo{x3B`IZJYk(;CtTtzCXSHGhh7DV~>CR8~^;=kIyJy zHb803+Kc*M_qK!YMd4?^_@&3c@$Dy{`?0ERkG0$%Z{Iq2@O>Zr@YlcnWUgV!nzift z-+b+LZ^s`1c+dOpN0Z0C{-fu9d^*>#u7B%b<>22u{FO((_tfcM+%a+Iy&wO|BaeOU z$shdFhI_vJt;fIpWdG$?y!kC}-*ouBcYo${pMT`5kALl{hBi}RPa z-}m6>ANksoPyOfvs`oGN>9~8*x1anU-~INP%ddFrwaKtPe?j}tem=ajbkVE()*X4@ z8*kkG#Me)L=jng^$xCOH-BdjABmcl_!)8Cxu>XO&$|r+G;rC+lCI zcDBpq5bLe@t-^1`GxetOl)3|+%=?1P>TTy7RkP;WMOnLf(a)FJr5AP_UApt*o0pkm zr;1FDX)KySbo8K83=>ep+N%!b!%lgcFfO*8t_ zx>TnzVvx~`Q~Cy9C(xCdXM8X3*fvPTmp(nfbI>hwF(zIT2q3rEN#dQgBy;7Mcd@o>i~$-zAHc(2lb4~O(U zdb3rD?MC?;$KO{P$TZ+R&jk7}&HPz8eSSDEqxCYc12Y4P(CV)N*Itqc?fR2U+xowHMA7+PZb9OM1a;G)P2t@O(_J&Ri98l5eo%Vfw1mpV}*CZ3Nb_wGx#}cR{$fVye2dJTscO=j~ zRssCSfwaQ}#c8?Y|z}gt;#_b5-Ca!q6la`tQe^EdGj6*XcQd zu1C)e(rd6)A4QvseC5A{@oq}0&4_Eszp4*$pyJ?nyR@SCqg3Ti2h$#vr~Pq$%H>zy zjY|A?$R!H-6+Xg_lN9Y;%1q=PuDH~TQxm5yQI&N35Vx;X$E(Eks(6I1-->hmw&G9B zv~S&UlXz}z9m`iN?-oa>nguyDFa~c^ywV#6w!=|dV|R^hf5)J`_#!LmQhU?(;Z5`g zw+#+#RVVB6YKcWa)Re#eWWmdCOOq{y&&D>M{TT literal 0 HcmV?d00001 diff --git a/open-sse/package.json b/open-sse/package.json index 9194d9fb44..623ed6d8f7 100644 --- a/open-sse/package.json +++ b/open-sse/package.json @@ -1,6 +1,6 @@ { "name": "@omniroute/open-sse", - "version": "3.8.0", + "version": "3.8.1", "description": "Express SSE sidecar for OmniRoute — handles streaming, protocol translation, and provider orchestration", "type": "module", "main": "index.js", diff --git a/open-sse/services/antigravityClientProfile.ts b/open-sse/services/antigravityClientProfile.ts new file mode 100644 index 0000000000..fb76f4f105 --- /dev/null +++ b/open-sse/services/antigravityClientProfile.ts @@ -0,0 +1,167 @@ +import { + DEFAULT_ANTIGRAVITY_CLIENT_PROFILE, + normalizeAntigravityClientProfile, + type AntigravityClientProfile, +} from "@/shared/constants/antigravityClientProfile"; +import { getRuntimeArch, getRuntimePlatform } from "./cloudCodeHeaders.ts"; +import { + deriveAntigravityMachineId, + getAntigravityVscodeSessionId, + type AntigravityCredentialsLike, +} from "./antigravityIdentity.ts"; +import { + antigravityUserAgent, + ANTIGRAVITY_CREDIT_PROBE_API_CLIENT, + ANTIGRAVITY_NODE_API_CLIENT, + getAntigravityLoadCodeAssistMetadata, +} from "./antigravityHeaders.ts"; +import { getCachedAntigravityVersion } from "./antigravityVersion.ts"; + +export { + ANTIGRAVITY_CLIENT_PROFILE_VALUES, + DEFAULT_ANTIGRAVITY_CLIENT_PROFILE, + normalizeAntigravityClientProfile, + type AntigravityClientProfile, +} from "@/shared/constants/antigravityClientProfile"; + +type AntigravityProfileCredentials = AntigravityCredentialsLike & { + providerSpecificData?: Record | null; +}; + +export function getAntigravityClientProfile( + credentials?: AntigravityProfileCredentials | null +): AntigravityClientProfile { + const fromProviderData = + credentials?.providerSpecificData && + typeof credentials.providerSpecificData === "object" && + !Array.isArray(credentials.providerSpecificData) + ? credentials.providerSpecificData.clientProfile + : undefined; + + return normalizeAntigravityClientProfile(fromProviderData); +} + +function normalizeHarnessPlatform( + platform: NodeJS.Platform | string = getRuntimePlatform() +): string { + return platform === "win32" ? "windows" : platform || "unknown"; +} + +function normalizeHarnessArch(arch: NodeJS.Architecture | string = getRuntimeArch()): string { + switch (arch) { + case "x64": + return "amd64"; + case "ia32": + return "386"; + default: + return arch || "unknown"; + } +} + +function getHarnessPlatformArch( + platform: NodeJS.Platform | string = getRuntimePlatform(), + arch: NodeJS.Architecture | string = getRuntimeArch() +): string { + return `${normalizeHarnessPlatform(platform)}/${normalizeHarnessArch(arch)}`; +} + +export function antigravityHarnessUserAgent( + version = getCachedAntigravityVersion(), + platform: NodeJS.Platform | string = getRuntimePlatform(), + arch: NodeJS.Architecture | string = getRuntimeArch() +): string { + return `antigravity/${version} ${getHarnessPlatformArch(platform, arch)}`; +} + +export function antigravityHarnessLoadCodeAssistUserAgent( + version = getCachedAntigravityVersion() +): string { + return `${antigravityHarnessUserAgent(version)} ${ANTIGRAVITY_NODE_API_CLIENT}`; +} + +export function antigravityHarnessApiClientHeader(): string { + return ANTIGRAVITY_CREDIT_PROBE_API_CLIENT; +} + +export function removeHeaderCaseInsensitive(headers: Record, name: string): void { + const lowerName = name.toLowerCase(); + for (const key of Object.keys(headers)) { + if (key.toLowerCase() === lowerName) { + delete headers[key]; + } + } +} + +function getProjectHeaderValue(body: unknown): string | null { + const project = + body && typeof body === "object" ? (body as Record).project : null; + if (typeof project !== "string" || project.trim().length === 0) return null; + if (project === "test-project" || project === "project-id") return null; + return project; +} + +/** Headers used by OAuth/bootstrap calls (loadCodeAssist, token refresh). */ +export function getAntigravityBootstrapHeaders( + profile: AntigravityClientProfile, + accessToken?: string | null +): Record { + const headers: Record = { + "Content-Type": "application/json", + }; + + if (accessToken) { + headers.Authorization = `Bearer ${accessToken}`; + } + + if (profile === "harness") { + headers["User-Agent"] = antigravityHarnessLoadCodeAssistUserAgent(); + headers["X-Goog-Api-Client"] = antigravityHarnessApiClientHeader(); + return headers; + } + + headers["User-Agent"] = antigravityUserAgent(); + headers["Client-Metadata"] = JSON.stringify(getAntigravityLoadCodeAssistMetadata()); + return headers; +} + +/** Apply per-connection client identity to outbound Cloud Code content requests. */ +export function applyAntigravityClientProfileHeaders( + headers: Record, + credentials: AntigravityProfileCredentials | null | undefined, + body: unknown +): AntigravityClientProfile { + const profile = getAntigravityClientProfile(credentials); + const version = getCachedAntigravityVersion(); + + if (profile === "harness") { + headers["User-Agent"] = antigravityHarnessUserAgent(version); + removeHeaderCaseInsensitive(headers, "X-Goog-Api-Client"); + removeHeaderCaseInsensitive(headers, "x-client-name"); + removeHeaderCaseInsensitive(headers, "x-client-version"); + removeHeaderCaseInsensitive(headers, "x-machine-id"); + removeHeaderCaseInsensitive(headers, "x-vscode-sessionid"); + removeHeaderCaseInsensitive(headers, "Client-Metadata"); + } else { + headers["User-Agent"] = antigravityUserAgent(); + headers["x-client-name"] = "antigravity"; + headers["x-client-version"] = version; + const machineId = deriveAntigravityMachineId(credentials); + if (machineId) { + headers["x-machine-id"] = machineId; + } else { + removeHeaderCaseInsensitive(headers, "x-machine-id"); + } + headers["x-vscode-sessionid"] = getAntigravityVscodeSessionId(); + removeHeaderCaseInsensitive(headers, "X-Goog-Api-Client"); + removeHeaderCaseInsensitive(headers, "Client-Metadata"); + } + + const project = getProjectHeaderValue(body); + if (project) { + headers["x-goog-user-project"] = project; + } else { + removeHeaderCaseInsensitive(headers, "x-goog-user-project"); + } + + return profile; +} diff --git a/open-sse/services/antigravityHeaders.ts b/open-sse/services/antigravityHeaders.ts index 92db40d442..3648d56912 100644 --- a/open-sse/services/antigravityHeaders.ts +++ b/open-sse/services/antigravityHeaders.ts @@ -16,14 +16,29 @@ import { type AntigravityHeaderProfile = "loadCodeAssist" | "fetchAvailableModels" | "models"; const ANTIGRAVITY_VERSION = ANTIGRAVITY_FALLBACK_VERSION; +// IDE desktop fingerprint synced with Antigravity-Manager v4.2.0 constants.rs. export const ANTIGRAVITY_CHROME_VERSION = "132.0.6834.160"; export const ANTIGRAVITY_ELECTRON_VERSION = "39.2.3"; export const ANTIGRAVITY_LOAD_CODE_ASSIST_USER_AGENT = `vscode/1.X.X (Antigravity/${ANTIGRAVITY_FALLBACK_VERSION})`; export const ANTIGRAVITY_LOAD_CODE_ASSIST_API_CLIENT = ""; -export const ANTIGRAVITY_CREDIT_PROBE_API_CLIENT = "google-genai-sdk/1.30.0 gl-node/v22.21.1"; -const LOAD_CODE_ASSIST_METADATA = Object.freeze({ - ideType: "ANTIGRAVITY", -}); +export const ANTIGRAVITY_NODE_API_CLIENT = "google-api-nodejs-client/10.3.0"; +// Harness/bootstrap X-Goog-Api-Client synced with CLIProxyAPI misc.AntigravityGoogAPIClientUA. +export const ANTIGRAVITY_CREDIT_PROBE_API_CLIENT = "gl-node/22.21.1"; +export const ANTIGRAVITY_API_CLIENT = ANTIGRAVITY_CREDIT_PROBE_API_CLIENT; +type AntigravityLoadCodeAssistPlatform = "MACOS" | "WINDOWS" | "LINUX"; + +function getAntigravityLoadCodeAssistPlatformLabel( + platform: NodeJS.Platform = process.platform +): AntigravityLoadCodeAssistPlatform { + switch (platform) { + case "darwin": + return "MACOS"; + case "win32": + return "WINDOWS"; + default: + return "LINUX"; + } +} function withOptionalBearerAuth( headers: Record, @@ -35,29 +50,54 @@ function withOptionalBearerAuth( return headers; } -/** - * Antigravity desktop User-Agent: - * "Antigravity/VERSION (Macintosh; Intel Mac OS X 10_15_7) Chrome/132... Electron/39..." - */ -export function antigravityUserAgent(): string { - return `Antigravity/${getCachedAntigravityVersion()} (Macintosh; Intel Mac OS X 10_15_7) Chrome/${ANTIGRAVITY_CHROME_VERSION} Electron/${ANTIGRAVITY_ELECTRON_VERSION}`; +function getAntigravityPlatformInfo(platform: NodeJS.Platform = process.platform): string { + switch (platform) { + case "darwin": + return "Macintosh; Intel Mac OS X 10_15_7"; + case "win32": + return "Windows NT 10.0; Win64; x64"; + case "linux": + default: + return "X11; Linux x86_64"; + } } -export async function resolveAntigravityUserAgent(): Promise { +/** + * Antigravity desktop User-Agent: + * "Antigravity/VERSION (PLATFORM) Chrome/132... Electron/39..." + */ +export function antigravityUserAgent( + version = getCachedAntigravityVersion(), + platform: NodeJS.Platform = process.platform +): string { + return `Antigravity/${version} (${getAntigravityPlatformInfo(platform)}) Chrome/${ANTIGRAVITY_CHROME_VERSION} Electron/${ANTIGRAVITY_ELECTRON_VERSION}`; +} + +export async function resolveAntigravityUserAgent( + platform: NodeJS.Platform = process.platform +): Promise { const version = await resolveAntigravityVersion(); - return `Antigravity/${version} (Macintosh; Intel Mac OS X 10_15_7) Chrome/${ANTIGRAVITY_CHROME_VERSION} Electron/${ANTIGRAVITY_ELECTRON_VERSION}`; + return antigravityUserAgent(version, platform); } export function antigravityNativeOAuthUserAgent(): string { return `vscode/1.X.X (Antigravity/${getCachedAntigravityVersion()})`; } -export function getAntigravityLoadCodeAssistMetadata(): Record { - return { ...LOAD_CODE_ASSIST_METADATA }; +export function getAntigravityLoadCodeAssistMetadata( + platform: NodeJS.Platform = process.platform +): Record { + return { + ideType: "ANTIGRAVITY", + platform: getAntigravityLoadCodeAssistPlatformLabel(platform), + pluginType: "GEMINI", + }; } -export function getAntigravityLoadCodeAssistClientMetadata(): string { - return JSON.stringify(LOAD_CODE_ASSIST_METADATA); +export function getAntigravityLoadCodeAssistClientMetadata( + platform: NodeJS.Platform = process.platform +): string { + return JSON.stringify(getAntigravityLoadCodeAssistMetadata(platform)); } export function getAntigravityHeaders( @@ -92,4 +132,9 @@ export function getAntigravityCreditProbeApiClientHeader(): string { return ANTIGRAVITY_CREDIT_PROBE_API_CLIENT; } +/** X-Goog-Api-Client used by harness/native Node Antigravity paths. */ +export function getAntigravityApiClientHeader(): string { + return ANTIGRAVITY_API_CLIENT; +} + export { ANTIGRAVITY_VERSION }; diff --git a/open-sse/services/antigravityIdentity.ts b/open-sse/services/antigravityIdentity.ts index c5e73cc861..08c9fdeb5c 100644 --- a/open-sse/services/antigravityIdentity.ts +++ b/open-sse/services/antigravityIdentity.ts @@ -1,7 +1,7 @@ import crypto from "node:crypto"; -import os from "node:os"; +import { createRequire } from "node:module"; -type AntigravityCredentialsLike = { +export type AntigravityCredentialsLike = { accessToken?: string | null; connectionId?: string | null; email?: string | null; @@ -12,6 +12,23 @@ type AntigravityCredentialsLike = { const FNV_OFFSET_I64 = -3750763034362895579n; const FNV_PRIME_I64 = 1099511628211n; const PROCESS_SESSION_ID = crypto.randomUUID(); +const require = createRequire(import.meta.url); + +type NodeMachineIdModule = { + machineIdSync?: (original?: boolean) => string; + default?: { + machineIdSync?: (original?: boolean) => string; + }; +}; + +let systemMachineIdSync: ((original?: boolean) => string) | null = null; +try { + const machineIdModule = require("node-machine-id") as NodeMachineIdModule; + systemMachineIdSync = + machineIdModule.machineIdSync ?? machineIdModule.default?.machineIdSync ?? null; +} catch { + systemMachineIdSync = null; +} function toNonEmptyString(value: unknown): string | null { return typeof value === "string" && value.trim().length > 0 ? value.trim() : null; @@ -92,23 +109,17 @@ export function getAntigravitySessionId( ); } -const STABLE_MACHINE_ID = crypto - .createHash("sha256") - .update(`omniroute:machine_id:${os.hostname()}`) - .digest("hex"); - -const FORMATTED_MACHINE_ID = [ - STABLE_MACHINE_ID.slice(0, 8), - STABLE_MACHINE_ID.slice(8, 12), - STABLE_MACHINE_ID.slice(12, 16), - STABLE_MACHINE_ID.slice(16, 20), - STABLE_MACHINE_ID.slice(20, 32), -].join("-"); - export function deriveAntigravityMachineId( _credentials?: AntigravityCredentialsLike | null -): string { - return FORMATTED_MACHINE_ID; +): string | null { + try { + const systemMachineId = toNonEmptyString(systemMachineIdSync?.(true)); + if (systemMachineId) return systemMachineId; + } catch { + // Antigravity Manager omits x-machine-id when machine_uid cannot read the OS id. + } + + return null; } export function getAntigravityVscodeSessionId(): string { diff --git a/open-sse/services/antigravityProjectBootstrap.ts b/open-sse/services/antigravityProjectBootstrap.ts index ce045461a0..d9d4cdb58c 100644 --- a/open-sse/services/antigravityProjectBootstrap.ts +++ b/open-sse/services/antigravityProjectBootstrap.ts @@ -19,6 +19,10 @@ import { getAntigravityHeaders, getAntigravityLoadCodeAssistMetadata, } from "./antigravityHeaders.ts"; +import { + getAntigravityBootstrapHeaders, + type AntigravityClientProfile, +} from "./antigravityClientProfile.ts"; import { ANTIGRAVITY_BASE_URLS } from "../config/antigravityUpstream.ts"; const LOAD_CODE_ASSIST_PATH = "/v1internal:loadCodeAssist"; @@ -34,20 +38,30 @@ const projectCache = new Map(); type FetchLike = (url: string, init?: RequestInit) => Promise; +function getProjectCacheKey(accessToken: string, clientProfile: AntigravityClientProfile): string { + return `${clientProfile}:${accessToken}`; +} + /** * Attempt loadCodeAssist against each known base URL in order. * Returns the discovered project id, or null if all endpoints fail. */ async function tryLoadCodeAssist( accessToken: string, - fetchImpl: FetchLike + fetchImpl: FetchLike, + clientProfile: AntigravityClientProfile ): Promise { const urls = getAntigravityLoadCodeAssistUrls(); + const headers = + clientProfile === "harness" + ? getAntigravityBootstrapHeaders(clientProfile, accessToken) + : getAntigravityHeaders("loadCodeAssist", accessToken); + for (const url of urls) { try { const response = await fetchImpl(url, { method: "POST", - headers: getAntigravityHeaders("loadCodeAssist", accessToken), + headers, body: JSON.stringify({ metadata: getAntigravityLoadCodeAssistMetadata() }), signal: AbortSignal.timeout(BOOTSTRAP_TIMEOUT_MS), }); @@ -100,18 +114,22 @@ async function tryLoadCodeAssist( */ export async function ensureAntigravityProjectAssigned( accessToken: string, - fetchImpl: FetchLike = fetch -): Promise { - if (projectCache.has(accessToken)) { - return; // already bootstrapped for this token + fetchImpl: FetchLike = fetch, + clientProfile: AntigravityClientProfile = "ide" +): Promise { + const cacheKey = getProjectCacheKey(accessToken, clientProfile); + if (projectCache.has(cacheKey)) { + return projectCache.get(cacheKey); // already bootstrapped for this token } - const projectId = await tryLoadCodeAssist(accessToken, fetchImpl); + const projectId = await tryLoadCodeAssist(accessToken, fetchImpl, clientProfile); if (projectId) { - projectCache.set(accessToken, projectId); + projectCache.set(cacheKey, projectId); + return projectId; } // Non-fatal: if all endpoints failed, we proceed without caching. + return undefined; } /** Exported for tests. */ @@ -120,6 +138,9 @@ export function clearAntigravityProjectCache(): void { } /** Exported for tests — inspect cache state. */ -export function getAntigravityProjectFromCache(accessToken: string): string | undefined { - return projectCache.get(accessToken); +export function getAntigravityProjectFromCache( + accessToken: string, + clientProfile: AntigravityClientProfile = "ide" +): string | undefined { + return projectCache.get(getProjectCacheKey(accessToken, clientProfile)); } diff --git a/open-sse/services/antigravityVersion.ts b/open-sse/services/antigravityVersion.ts index b31ee6d29f..052c98487c 100644 --- a/open-sse/services/antigravityVersion.ts +++ b/open-sse/services/antigravityVersion.ts @@ -5,7 +5,8 @@ const ANTIGRAVITY_GITHUB_RELEASE_URL = export const ANTIGRAVITY_VERSION_CACHE_TTL_MS = 6 * 60 * 60 * 1000; export const ANTIGRAVITY_VERSION_FETCH_TIMEOUT_MS = 5_000; -export const ANTIGRAVITY_FALLBACK_VERSION = "4.1.33"; +// Floor version synced with Antigravity-Manager v4.2.0 KNOWN_STABLE_VERSION. +export const ANTIGRAVITY_FALLBACK_VERSION = "4.2.0"; type VersionCache = { fetchedAt: number; diff --git a/open-sse/services/geminiThoughtSignatureStore.ts b/open-sse/services/geminiThoughtSignatureStore.ts index 4f47b7e39a..ccc8d9670f 100644 --- a/open-sse/services/geminiThoughtSignatureStore.ts +++ b/open-sse/services/geminiThoughtSignatureStore.ts @@ -1,5 +1,10 @@ +import { getDbInstance } from "../../src/lib/db/core.ts"; + const MAX_SIGNATURES = 1000; -const TTL_MS = 1000 * 60 * 60; +const MAX_PERSISTED_SIGNATURES = 2_000; +const MEMORY_TTL_MS = 1000 * 60 * 60; +const PERSISTED_TTL_MS = 1000 * 60 * 60 * 24 * 30; +const NAMESPACE = "gemini_thought_signatures"; export type SignatureCacheMode = "enabled" | "bypass" | "bypass-strict"; @@ -8,8 +13,34 @@ type Entry = { expiresAt: number; }; +type PersistedEntry = Entry & { + createdAt: number; +}; + const signatures = new Map(); let signatureCacheMode: SignatureCacheMode = "enabled"; +let persistedPruneCounter = 0; +const loggedPersistenceErrors = new Set(); + +function warnPersistenceError(operation: string, error: unknown) { + if (process.env.NODE_ENV === "test") return; + if (loggedPersistenceErrors.has(operation)) return; + loggedPersistenceErrors.add(operation); + const message = error instanceof Error ? error.message : String(error); + console.warn(`[signature-cache] persisted ${operation} failed: ${message}`); +} + +export function buildGeminiThoughtSignatureKey(namespace: unknown, toolCallId: unknown): unknown { + if ( + typeof namespace === "string" && + namespace.length > 0 && + typeof toolCallId === "string" && + toolCallId.length > 0 + ) { + return `${namespace}:${toolCallId}`; + } + return toolCallId; +} function pruneExpired() { const now = Date.now(); @@ -26,15 +57,93 @@ function pruneExpired() { } } +function serializePersistedEntry(entry: PersistedEntry): string { + return JSON.stringify(entry); +} + +function parsePersistedEntry(value: string, now = Date.now()) { + try { + const parsed = JSON.parse(value) as Partial; + if (typeof parsed.signature !== "string" || parsed.signature.length === 0) return null; + const createdAt = typeof parsed.createdAt === "number" ? parsed.createdAt : now; + const expiresAt = + typeof parsed.expiresAt === "number" ? parsed.expiresAt : now + PERSISTED_TTL_MS; + if (expiresAt <= now) return null; + return { + entry: { signature: parsed.signature, createdAt, expiresAt }, + shouldRewrite: createdAt !== parsed.createdAt || expiresAt !== parsed.expiresAt, + }; + } catch { + if (!value) return null; + return { + entry: { + signature: value, + createdAt: now, + expiresAt: now + PERSISTED_TTL_MS, + }, + shouldRewrite: true, + }; + } +} + +function maybePrunePersistedSignatures(db: ReturnType) { + persistedPruneCounter += 1; + if (persistedPruneCounter % 100 !== 0) return; + + const rows = db + .prepare("SELECT key, value FROM key_value WHERE namespace = ?") + .all(NAMESPACE) as Array<{ key: string; value: string }>; + + const now = Date.now(); + const validRows: Array<{ key: string; createdAt: number }> = []; + const keysToDelete = new Set(); + + for (const row of rows) { + const parsed = parsePersistedEntry(row.value, now); + if (!parsed) { + keysToDelete.add(row.key); + continue; + } + validRows.push({ key: row.key, createdAt: parsed.entry.createdAt }); + } + + if (rows.length <= MAX_PERSISTED_SIGNATURES && keysToDelete.size === 0) return; + + validRows.sort((a, b) => b.createdAt - a.createdAt); + for (const row of validRows.slice(MAX_PERSISTED_SIGNATURES)) { + keysToDelete.add(row.key); + } + + if (keysToDelete.size === 0) return; + const remove = db.prepare("DELETE FROM key_value WHERE namespace = ? AND key = ?"); + const tx = db.transaction((keys: string[]) => { + for (const key of keys) remove.run(NAMESPACE, key); + }); + tx([...keysToDelete]); +} + export function storeGeminiThoughtSignature(toolCallId: unknown, signature: unknown) { if (typeof toolCallId !== "string" || !toolCallId) return; if (typeof signature !== "string" || !signature) return; + const now = Date.now(); pruneExpired(); signatures.set(toolCallId, { signature, - expiresAt: Date.now() + TTL_MS, + expiresAt: now + MEMORY_TTL_MS, }); + + try { + const db = getDbInstance(); + db.prepare("INSERT OR REPLACE INTO key_value (namespace, key, value) VALUES (?, ?, ?)").run( + NAMESPACE, + toolCallId, + serializePersistedEntry({ signature, createdAt: now, expiresAt: now + PERSISTED_TTL_MS }) + ); + maybePrunePersistedSignatures(db); + } catch (error) { + warnPersistenceError("store", error); + } } export function getGeminiThoughtSignature(toolCallId: unknown) { @@ -42,8 +151,44 @@ export function getGeminiThoughtSignature(toolCallId: unknown) { pruneExpired(); const entry = signatures.get(toolCallId); - if (!entry) return null; - return entry.signature; + if (entry) return entry.signature; + + try { + const db = getDbInstance(); + const row = db + .prepare("SELECT value FROM key_value WHERE namespace = ? AND key = ?") + .get(NAMESPACE, toolCallId) as { value: string } | undefined; + + if (row?.value) { + const persisted = parsePersistedEntry(row.value); + if (!persisted) { + db.prepare("DELETE FROM key_value WHERE namespace = ? AND key = ?").run( + NAMESPACE, + toolCallId + ); + return null; + } + + signatures.set(toolCallId, { + signature: persisted.entry.signature, + expiresAt: Date.now() + MEMORY_TTL_MS, + }); + + if (persisted.shouldRewrite) { + db.prepare("UPDATE key_value SET value = ? WHERE namespace = ? AND key = ?").run( + serializePersistedEntry(persisted.entry), + NAMESPACE, + toolCallId + ); + } + + return persisted.entry.signature; + } + } catch (error) { + warnPersistenceError("read", error); + } + + return null; } export function normalizeSignatureCacheMode(value: unknown): SignatureCacheMode { @@ -161,4 +306,19 @@ export function resolveGeminiThoughtSignature( export function clearGeminiThoughtSignatures() { signatures.clear(); signatureCacheMode = "enabled"; + try { + const db = getDbInstance(); + db.prepare("DELETE FROM key_value WHERE namespace = ?").run(NAMESPACE); + } catch (error) { + warnPersistenceError("clear", error); + } +} + +export function clearGeminiThoughtSignatureMemoryForTests() { + signatures.clear(); +} + +export function getGeminiThoughtSignatureMemorySizeForTests() { + pruneExpired(); + return signatures.size; } diff --git a/open-sse/services/usage.ts b/open-sse/services/usage.ts index 8a7f790223..4f2c7a9c62 100644 --- a/open-sse/services/usage.ts +++ b/open-sse/services/usage.ts @@ -21,6 +21,11 @@ import { getGitHubCopilotInternalUserHeaders } from "../config/providerHeaderPro import { safePercentage } from "@/shared/utils/formatting"; import { fetchBailianQuota, type BailianTripleWindowQuota } from "./bailianQuotaFetcher.ts"; import { fetchDeepseekQuota, type DeepseekQuota } from "./deepseekQuotaFetcher.ts"; +import { + applyAntigravityClientProfileHeaders, + getAntigravityBootstrapHeaders, + getAntigravityClientProfile, +} from "./antigravityClientProfile.ts"; import { antigravityUserAgent, getAntigravityHeaders, @@ -32,13 +37,7 @@ import { } from "../executors/antigravity.ts"; import { getCreditsMode } from "./antigravityCredits.ts"; import { CLAUDE_CODE_VERSION, fetchClaudeBootstrap } from "../executors/claudeIdentity.ts"; -import { - deriveAntigravityMachineId, - generateAntigravityRequestId, - getAntigravitySessionId, - getAntigravityVscodeSessionId, -} from "./antigravityIdentity.ts"; -import { getCachedAntigravityVersion } from "./antigravityVersion.ts"; +import { generateAntigravityRequestId, getAntigravitySessionId } from "./antigravityIdentity.ts"; // Antigravity API config (credentials from PROVIDERS via credential loader) const ANTIGRAVITY_CONFIG = { @@ -1679,7 +1678,8 @@ async function probeAntigravityCreditBalance( accessToken: string, accountId: string, projectId?: string | null, - options: AntigravityUsageOptions = {} + options: AntigravityUsageOptions = {}, + providerSpecificData: JsonRecord = {} ): Promise { if (!accessToken) return null; @@ -1696,7 +1696,12 @@ async function probeAntigravityCreditBalance( const inflight = _antigravityCreditProbeInflight.get(cacheKey); if (inflight) return inflight; - const promise = probeAntigravityCreditBalanceUncached(accessToken, accountId, projectId) + const promise = probeAntigravityCreditBalanceUncached( + accessToken, + accountId, + projectId, + providerSpecificData + ) .then( (data) => { _antigravityCreditProbeCache.set(cacheKey, { data, fetchedAt: Date.now() }); @@ -1718,7 +1723,8 @@ async function probeAntigravityCreditBalance( async function probeAntigravityCreditBalanceUncached( accessToken: string, accountId: string, - projectId?: string | null + projectId?: string | null, + providerSpecificData: JsonRecord = {} ): Promise { try { if (!projectId) return null; @@ -1743,17 +1749,16 @@ async function probeAntigravityCreditBalanceUncached( }, }; - const headers = { + const headers: Record = { "Content-Type": "application/json", Authorization: `Bearer ${accessToken}`, - "User-Agent": antigravityUserAgent(), - "x-client-name": "antigravity", - "x-client-version": getCachedAntigravityVersion(), - "x-machine-id": deriveAntigravityMachineId({ connectionId: accountId, projectId }), - "x-vscode-sessionid": getAntigravityVscodeSessionId(), - "x-goog-user-project": projectId, Accept: "text/event-stream", }; + applyAntigravityClientProfileHeaders( + headers, + { connectionId: accountId, projectId, providerSpecificData }, + body + ); try { const res = await fetch(url, { @@ -1817,13 +1822,15 @@ async function getAntigravityUsage( connectionId?: string, options: AntigravityUsageOptions = {} ) { - void providerSpecificData; if (!accessToken) { return { plan: "Free", message: "Antigravity access token not available." }; } try { - const subscriptionInfo = await getAntigravitySubscriptionInfoCached(accessToken); + const subscriptionInfo = await getAntigravitySubscriptionInfoCached( + accessToken, + providerSpecificData + ); const projectId = connectionProjectId || toRecord(subscriptionInfo).cloudaicompanionProject?.toString() || null; @@ -1841,7 +1848,8 @@ async function getAntigravityUsage( accessToken, accountId, projectId, - options + options, + providerSpecificData || {} ); } @@ -1913,15 +1921,19 @@ async function getAntigravityUsage( * Get Antigravity subscription info (cached, 5 min TTL) * Prevents duplicate loadCodeAssist calls within the same quota cycle. */ -async function getAntigravitySubscriptionInfoCached(accessToken: string): Promise { - const cacheKey = accessToken.substring(0, 16); +async function getAntigravitySubscriptionInfoCached( + accessToken: string, + providerSpecificData?: JsonRecord +): Promise { + const profile = getAntigravityClientProfile({ providerSpecificData }); + const cacheKey = `${accessToken.substring(0, 16)}:${profile}`; const cached = _antigravitySubCache.get(cacheKey); if (cached && Date.now() - cached.fetchedAt < ANTIGRAVITY_CACHE_TTL_MS) { return cached.data; } - const data = await getAntigravitySubscriptionInfo(accessToken); + const data = await getAntigravitySubscriptionInfo(accessToken, providerSpecificData); _antigravitySubCache.set(cacheKey, { data, fetchedAt: Date.now() }); return data; } @@ -1930,11 +1942,18 @@ async function getAntigravitySubscriptionInfoCached(accessToken: string): Promis * Get Antigravity subscription info using correct Antigravity headers. * Must match the headers used in providers.js postExchange (not CLI headers). */ -async function getAntigravitySubscriptionInfo(accessToken: string): Promise { +async function getAntigravitySubscriptionInfo( + accessToken: string, + providerSpecificData?: JsonRecord +): Promise { try { + const profile = getAntigravityClientProfile({ providerSpecificData }); const response = await fetch(ANTIGRAVITY_CONFIG.loadProjectApiUrl, { method: "POST", - headers: getAntigravityHeaders("loadCodeAssist", accessToken), + headers: + profile === "harness" + ? getAntigravityBootstrapHeaders(profile, accessToken) + : getAntigravityHeaders("loadCodeAssist", accessToken), body: JSON.stringify({ metadata: getAntigravityLoadCodeAssistMetadata() }), }); diff --git a/open-sse/translator/index.ts b/open-sse/translator/index.ts index d74947c435..ffa9758b2a 100644 --- a/open-sse/translator/index.ts +++ b/open-sse/translator/index.ts @@ -131,6 +131,7 @@ export function translateRequest( normalizeToolCallId?: boolean; preserveDeveloperRole?: boolean; preserveCacheControl?: boolean; + signatureNamespace?: string | null; } ) { let result = body; @@ -184,7 +185,13 @@ export function translateRequest( if (targetFormat !== FORMATS.OPENAI) { const fromOpenAI = getRequestTranslator(FORMATS.OPENAI, targetFormat); if (fromOpenAI) { - result = fromOpenAI(model, result, stream, credentials); + const translationCredentials = options?.signatureNamespace + ? { + ...(credentials && typeof credentials === "object" ? credentials : {}), + _signatureNamespace: options.signatureNamespace, + } + : credentials; + result = fromOpenAI(model, result, stream, translationCredentials); } } } diff --git a/open-sse/translator/request/openai-to-claude.ts b/open-sse/translator/request/openai-to-claude.ts index 8e7262c453..b2fc5910b5 100644 --- a/open-sse/translator/request/openai-to-claude.ts +++ b/open-sse/translator/request/openai-to-claude.ts @@ -206,16 +206,20 @@ export function openaiToClaudeRequest(model, body, stream) { if (body.messages && Array.isArray(body.messages)) { // Extract system messages (T15: handle both string and array content) + // Also treat "developer" role as system — OpenAI Responses API uses developer role + // for system-level instructions, and it must reach the Claude system field, not become an assistant turn. for (const msg of body.messages) { - if (msg.role === "system") { + if (msg.role === "system" || msg.role === "developer") { systemParts.push( typeof msg.content === "string" ? msg.content : normalizeContentToString(msg.content) ); } } - // Filter out system messages for separate processing - const nonSystemMessages = body.messages.filter((m) => m.role !== "system"); + // Filter out system/developer messages for separate processing + const nonSystemMessages = body.messages.filter( + (m) => m.role !== "system" && m.role !== "developer" + ); // Process messages with merging logic // CRITICAL: tool_result must be in separate message immediately after tool_use diff --git a/open-sse/translator/request/openai-to-gemini.ts b/open-sse/translator/request/openai-to-gemini.ts index 1d4d016826..2140278d3f 100644 --- a/open-sse/translator/request/openai-to-gemini.ts +++ b/open-sse/translator/request/openai-to-gemini.ts @@ -2,7 +2,10 @@ import { register } from "../registry.ts"; import { FORMATS } from "../formats.ts"; import { DEFAULT_THINKING_GEMINI_SIGNATURE } from "../../config/defaultThinkingSignature.ts"; import { ANTIGRAVITY_DEFAULT_SYSTEM } from "../../config/constants.ts"; -import { resolveGeminiThoughtSignature } from "../../services/geminiThoughtSignatureStore.ts"; +import { + buildGeminiThoughtSignatureKey, + resolveGeminiThoughtSignature, +} from "../../services/geminiThoughtSignatureStore.ts"; import { generateAntigravityRequestId, getAntigravityEnvelopeUserAgent, @@ -104,6 +107,8 @@ type CloudCodeEnvelope = { type GeminiToolNameOptions = { stripNamespace?: boolean; functionResponseShape?: "result" | "output"; + signatureNamespace?: string | null; + signaturelessToolCallMode?: "native" | "text"; }; type OpenAIToolCallLike = { @@ -286,20 +291,36 @@ function openaiToGeminiBase(model, body, stream, toolNameOptions: GeminiToolName if (msg.tool_calls && Array.isArray(msg.tool_calls)) { const toolCallIds = []; - const firstPersistedSignature = msg.tool_calls - .map((tc) => resolveGeminiThoughtSignature(tc.id, extractClientThoughtSignature(tc))) - .find((signature) => typeof signature === "string" && signature.length > 0); + const resolvedSignatures = new Map(); + let firstPersistedSignature: string | undefined; + for (const tc of msg.tool_calls) { + const resolved = resolveGeminiThoughtSignature( + buildGeminiThoughtSignatureKey(toolNameOptions.signatureNamespace, tc.id), + extractClientThoughtSignature(tc) + ); + if (typeof resolved === "string" && resolved.length > 0) { + resolvedSignatures.set(tc.id, resolved); + firstPersistedSignature ??= resolved; + } + } let shouldUseEmbeddedSignature = !parts.some((p) => p.thoughtSignature); + const stringifySignaturelessToolCalls = + toolNameOptions.signaturelessToolCallMode === "text"; for (const tc of msg.tool_calls) { if (tc.type !== "function") continue; + const signatureForToolCall = resolvedSignatures.get(tc.id); + if (!signatureForToolCall && stringifySignaturelessToolCalls) { + const args = tc.function?.arguments || "{}"; + parts.push({ + text: `[Tool call: ${tc.function?.name || "unknown"}]\nArguments: ${args}`, + }); + continue; + } + const args = tryParseJSON(tc.function?.arguments || "{}"); - const signatureForToolCall = resolveGeminiThoughtSignature( - tc.id, - extractClientThoughtSignature(tc) - ); const embeddedThoughtSignature = shouldUseEmbeddedSignature ? firstPersistedSignature || signatureForToolCall : undefined; @@ -326,7 +347,14 @@ function openaiToGeminiBase(model, body, stream, toolNameOptions: GeminiToolName } // Check if there are actual tool responses in the next messages - const hasActualResponses = toolCallIds.some((fid) => toolResponses[fid]); + const hasSignaturelessTextResponses = + stringifySignaturelessToolCalls && + msg.tool_calls.some( + (tc) => + tc.type === "function" && !resolvedSignatures.has(tc.id) && toolResponses[tc.id] + ); + const hasActualResponses = + toolCallIds.some((fid) => toolResponses[fid]) || hasSignaturelessTextResponses; if (hasActualResponses) { const toolParts = []; @@ -363,6 +391,23 @@ function openaiToGeminiBase(model, body, stream, toolNameOptions: GeminiToolName }, }); } + + if (stringifySignaturelessToolCalls) { + // Signature-less historical tool responses are represented as text + // so strict Gemini/Antigravity endpoints don't reject them as native + // functionResponse parts missing a matching thoughtSignature. + for (const tc of msg.tool_calls) { + if (tc.type !== "function" || !tc.id) continue; + if (!resolvedSignatures.has(tc.id) && toolResponses[tc.id]) { + const name = tcID2Name[tc.id] || tc.function?.name || "unknown"; + const resp = toolResponses[tc.id]; + toolParts.push({ + text: `[Tool response: ${name}]\nResult: ${resp}`, + }); + } + } + } + if (toolParts.length > 0) { result.contents.push({ role: "user", parts: toolParts }); } @@ -420,11 +465,17 @@ export function openaiToGeminiCLIRequest( model, body, stream, - options: { functionResponseShape?: "result" | "output" } = {} + options: { + functionResponseShape?: "result" | "output"; + signatureNamespace?: string | null; + signaturelessToolCallMode?: "native" | "text"; + } = {} ) { const gemini = openaiToGeminiBase(model, body, stream, { stripNamespace: true, functionResponseShape: options.functionResponseShape, + signatureNamespace: options.signatureNamespace, + signaturelessToolCallMode: options.signaturelessToolCallMode, }); // Add thinking config for CLI @@ -536,7 +587,16 @@ function getAntigravityClaudeOutputTokens(body: Record): number // OpenAI -> Antigravity (Sandbox Cloud Code with wrapper) export function openaiToAntigravityRequest(model, body, stream, credentials = null) { const isClaude = model.toLowerCase().includes("claude"); - const geminiCLI = openaiToGeminiCLIRequest(model, body, stream); + const signatureNamespace = + credentials && + typeof credentials === "object" && + typeof (credentials as Record)._signatureNamespace === "string" + ? ((credentials as Record)._signatureNamespace as string) + : null; + const geminiCLI = openaiToGeminiCLIRequest(model, body, stream, { + signatureNamespace, + signaturelessToolCallMode: isClaude ? "native" : "text", + }); if (isClaude) { geminiCLI.generationConfig.maxOutputTokens = getAntigravityClaudeOutputTokens(body); diff --git a/open-sse/translator/request/openai-to-kiro.ts b/open-sse/translator/request/openai-to-kiro.ts index 3404cc4507..0492fdff66 100644 --- a/open-sse/translator/request/openai-to-kiro.ts +++ b/open-sse/translator/request/openai-to-kiro.ts @@ -78,6 +78,41 @@ function normalizeKiroToolSchema(schema: unknown): Record { return result; } +function serializeToolResultContent(content: unknown): string { + if (typeof content === "string") { + return content || "(no output)"; + } + if (!Array.isArray(content)) { + if (content !== null && content !== undefined) { + try { + return JSON.stringify(content); + } catch { + return "(no output)"; + } + } + return "(no output)"; + } + const parts: string[] = []; + for (const block of content as Array>) { + if (!block || typeof block !== "object") continue; + if (block.type === "text" && typeof block.text === "string") { + if (block.text) parts.push(block.text); + } else if (block.type === "image" || block.type === "image_url") { + const src = block.source as Record | undefined; + const mediaType = src?.media_type ?? block.media_type ?? "image"; + parts.push(`[image: ${mediaType}]`); + } else { + try { + const str = JSON.stringify(block); + if (str && str !== "{}") parts.push(str); + } catch { + // skip unserializable block + } + } + } + return parts.join("\n") || "(no output)"; +} + /** * Convert OpenAI messages to Kiro format * Rules: system/tool/user -> user role, merge consecutive same roles @@ -237,15 +272,10 @@ function convertMessages(messages, tools, model) { const toolResultBlocks = msg.content.filter((c) => c.type === "tool_result"); if (toolResultBlocks.length > 0) { toolResultBlocks.forEach((block) => { - const text = Array.isArray(block.content) - ? block.content.map((c) => c.text || "").join("\n") - : typeof block.content === "string" - ? block.content - : ""; - + const text = serializeToolResultContent(block.content); pendingToolResults.push({ toolUseId: block.tool_use_id, - status: "success", + status: block.is_error ? "error" : "success", content: [{ text: text }], }); }); @@ -300,16 +330,20 @@ function convertMessages(messages, tools, model) { const lastMsg = history[history.length - 1]; if (lastMsg?.assistantResponseMessage) { - lastMsg.assistantResponseMessage.toolUses = toolUses.map((tc) => { + const NAMESPACE_KIRO_TOOLUSE = "a1b2c3d4-e5f6-7890-abcd-ef1234567890"; + lastMsg.assistantResponseMessage.toolUses = toolUses.map((tc, idx) => { if (tc.function) { + const stableId = + tc.id || uuidv5(`${tc.function.name}:${idx}`, NAMESPACE_KIRO_TOOLUSE); return { - toolUseId: tc.id || uuidv4(), + toolUseId: stableId, name: tc.function.name, input: parseToolInput(tc.function.arguments), }; } else { + const stableId = tc.id || uuidv5(`${tc.name}:${idx}`, NAMESPACE_KIRO_TOOLUSE); return { - toolUseId: tc.id || uuidv4(), + toolUseId: stableId, name: tc.name, input: parseToolInput(tc.input), }; diff --git a/open-sse/translator/response/gemini-to-openai.ts b/open-sse/translator/response/gemini-to-openai.ts index e558848cde..e6e8681a4f 100644 --- a/open-sse/translator/response/gemini-to-openai.ts +++ b/open-sse/translator/response/gemini-to-openai.ts @@ -1,13 +1,88 @@ import { register } from "../registry.ts"; import { FORMATS } from "../formats.ts"; -import { storeGeminiThoughtSignature } from "../../services/geminiThoughtSignatureStore.ts"; +import { + buildGeminiThoughtSignatureKey, + storeGeminiThoughtSignature, +} from "../../services/geminiThoughtSignatureStore.ts"; -function buildToolCallId(functionCall, toolName, toolCallIndex) { +type GeminiToOpenAIState = { + functionIndex: number; + messageId: string; + model: string; + pendingThoughtSignature?: string | null; + signatureNamespace?: string | null; + toolCalls: Map; + toolNameMap?: Map; +}; + +type GeminiFunctionCallPart = { + functionCall: { + args?: unknown; + id?: string; + name: string; + }; +}; + +function buildToolCallId( + functionCall: GeminiFunctionCallPart["functionCall"], + toolName: string, + toolCallIndex: number +) { return typeof functionCall?.id === "string" && functionCall.id.length > 0 ? functionCall.id : `${toolName}-${Date.now()}-${toolCallIndex}`; } +function getSignatureCacheKey( + state: Pick, + toolCallId: unknown +) { + return buildGeminiThoughtSignatureKey(state?.signatureNamespace, toolCallId); +} + +function emitFunctionCallPart( + part: GeminiFunctionCallPart, + state: GeminiToOpenAIState, + results: Array> +) { + const rawToolName = part.functionCall.name; + const fcName = state.toolNameMap?.get(rawToolName) || rawToolName; + const fcArgs = part.functionCall.args || {}; + const toolCallIndex = state.functionIndex++; + const toolCall = { + id: buildToolCallId(part.functionCall, fcName, toolCallIndex), + index: toolCallIndex, + type: "function", + function: { + name: fcName, + arguments: JSON.stringify(fcArgs), + }, + }; + + if (state.pendingThoughtSignature) { + storeGeminiThoughtSignature( + getSignatureCacheKey(state, toolCall.id), + state.pendingThoughtSignature + ); + state.pendingThoughtSignature = null; + } + + state.toolCalls.set(toolCallIndex, toolCall); + results.push({ + id: `chatcmpl-${state.messageId}`, + object: "chat.completion.chunk", + created: Math.floor(Date.now() / 1000), + model: state.model, + choices: [ + { + index: 0, + delta: { tool_calls: [toolCall] }, + finish_reason: null, + }, + ], + }); +} + // Convert Gemini response chunk to OpenAI format export function geminiToOpenAIResponse(chunk, state) { if (!chunk) return null; @@ -111,41 +186,7 @@ export function geminiToOpenAIResponse(chunk, state) { } if (hasFunctionCall) { - const rawToolName = part.functionCall.name; - const fcName = state.toolNameMap?.get(rawToolName) || rawToolName; - const fcArgs = part.functionCall.args || {}; - const toolCallIndex = state.functionIndex++; - - const toolCall = { - id: buildToolCallId(part.functionCall, fcName, toolCallIndex), - index: toolCallIndex, - type: "function", - function: { - name: fcName, - arguments: JSON.stringify(fcArgs), - }, - }; - - if (state.pendingThoughtSignature) { - storeGeminiThoughtSignature(toolCall.id, state.pendingThoughtSignature); - state.pendingThoughtSignature = null; - } - - state.toolCalls.set(toolCallIndex, toolCall); - - results.push({ - id: `chatcmpl-${state.messageId}`, - object: "chat.completion.chunk", - created: Math.floor(Date.now() / 1000), - model: state.model, - choices: [ - { - index: 0, - delta: { tool_calls: [toolCall] }, - finish_reason: null, - }, - ], - }); + emitFunctionCallPart(part, state, results); } continue; } @@ -169,41 +210,7 @@ export function geminiToOpenAIResponse(chunk, state) { // Function call if (part.functionCall) { - const rawToolName = part.functionCall.name; - const fcName = state.toolNameMap?.get(rawToolName) || rawToolName; - const fcArgs = part.functionCall.args || {}; - const toolCallIndex = state.functionIndex++; - - const toolCall = { - id: buildToolCallId(part.functionCall, fcName, toolCallIndex), - index: toolCallIndex, - type: "function", - function: { - name: fcName, - arguments: JSON.stringify(fcArgs), - }, - }; - - if (state.pendingThoughtSignature) { - storeGeminiThoughtSignature(toolCall.id, state.pendingThoughtSignature); - state.pendingThoughtSignature = null; - } - - state.toolCalls.set(toolCallIndex, toolCall); - - results.push({ - id: `chatcmpl-${state.messageId}`, - object: "chat.completion.chunk", - created: Math.floor(Date.now() / 1000), - model: state.model, - choices: [ - { - index: 0, - delta: { tool_calls: [toolCall] }, - finish_reason: null, - }, - ], - }); + emitFunctionCallPart(part, state, results); } // Inline data (images) diff --git a/open-sse/utils/stream.ts b/open-sse/utils/stream.ts index a34d836173..cda5a84a4d 100644 --- a/open-sse/utils/stream.ts +++ b/open-sse/utils/stream.ts @@ -58,7 +58,7 @@ export { COLORS, formatSSE }; type JsonRecord = Record; -const PENDING_REQUEST_CLEARED_MARKER = "__omniroutePendingRequestCleared"; +export const PENDING_REQUEST_CLEARED_MARKER = "__omniroutePendingRequestCleared"; function markPendingRequestCleared(error: Error): Error { (error as Error & Record)[PENDING_REQUEST_CLEARED_MARKER] = true; @@ -149,6 +149,7 @@ type StreamOptions = { type TranslateState = ReturnType & { provider?: string | null; toolNameMap?: unknown; + signatureNamespace?: string | null; usage?: unknown; finishReason?: unknown; copilotCompatibleReasoning?: boolean; @@ -544,6 +545,7 @@ export function createSSEStream(options: StreamOptions = {}) { onComplete = null, onFailure = null, } = options; + const signatureNamespace = connectionId; const clientExpectsResponsesStream = (mode === STREAM_MODE.PASSTHROUGH @@ -583,6 +585,7 @@ export function createSSEStream(options: StreamOptions = {}) { ...(initState(sourceFormat) as TranslateState), provider, toolNameMap, + signatureNamespace, copilotCompatibleReasoning, accumulatedContent: "", } diff --git a/open-sse/utils/streamHandler.ts b/open-sse/utils/streamHandler.ts index ea33f18e79..e87b96f520 100644 --- a/open-sse/utils/streamHandler.ts +++ b/open-sse/utils/streamHandler.ts @@ -1,9 +1,9 @@ import { trackPendingRequest } from "@/lib/usageDb"; import { FORMATS } from "../translator/formats.ts"; +import { PENDING_REQUEST_CLEARED_MARKER } from "./stream.ts"; // Stream handler with disconnect detection - shared for all providers -const PENDING_REQUEST_CLEARED_MARKER = "__omniroutePendingRequestCleared"; const DISCONNECT_ABORT_DELAY_MS = 2_000; type StreamDisconnectEvent = { @@ -13,7 +13,6 @@ type StreamDisconnectEvent = { type StreamControllerOptions = { onDisconnect?: (event: StreamDisconnectEvent) => void; - log?: unknown; provider?: string; model?: string; connectionId?: string | null; @@ -22,6 +21,18 @@ type StreamControllerOptions = { type StreamController = ReturnType; +type StreamErrorStatusKind = "rate_limit" | "authentication" | "permission" | "client" | "server"; + +type StreamErrorStatusMapping = { + responses: { + type: string; + code: string; + }; + claude: { + type: string; + }; +}; + function isResponsesClientFormat(clientResponseFormat?: string | null): boolean { return ( clientResponseFormat === FORMATS.OPENAI_RESPONSES || @@ -29,27 +40,70 @@ function isResponsesClientFormat(clientResponseFormat?: string | null): boolean ); } -function responsesErrorType(statusCode: number): string { - if (statusCode === 429) return "rate_limit_error"; - if (statusCode === 401 || statusCode === 403) return "authentication_error"; - if (statusCode >= 400 && statusCode < 500) return "invalid_request_error"; - return "server_error"; +function getStreamErrorStatusKind(statusCode: number): StreamErrorStatusKind { + if (statusCode === 429) return "rate_limit"; + if (statusCode === 401) return "authentication"; + if (statusCode === 403) return "permission"; + if (statusCode >= 400 && statusCode < 500) return "client"; + return "server"; } -function responsesErrorCode(statusCode: number): string { - if (statusCode === 429) return "rate_limit_exceeded"; - if (statusCode === 401) return "invalid_authentication"; - if (statusCode === 403) return "permission_denied"; - if (statusCode >= 400 && statusCode < 500) return "bad_request"; - return "server_error"; +function getStreamErrorStatusMapping(statusCode: number): StreamErrorStatusMapping { + switch (getStreamErrorStatusKind(statusCode)) { + case "rate_limit": + return { + responses: { type: "rate_limit_error", code: "rate_limit_exceeded" }, + claude: { type: "rate_limit_error" }, + }; + case "authentication": + return { + responses: { type: "authentication_error", code: "invalid_authentication" }, + claude: { type: "authentication_error" }, + }; + case "permission": + return { + responses: { type: "authentication_error", code: "permission_denied" }, + claude: { type: "permission_error" }, + }; + case "client": + return { + responses: { type: "invalid_request_error", code: "bad_request" }, + claude: { type: "invalid_request_error" }, + }; + case "server": + return { + responses: { type: "server_error", code: "server_error" }, + claude: { type: "api_error" }, + }; + default: + return { + responses: { type: "server_error", code: "server_error" }, + claude: { type: "api_error" }, + }; + } } -function claudeErrorType(statusCode: number): string { - if (statusCode === 429) return "rate_limit_error"; - if (statusCode === 401) return "authentication_error"; - if (statusCode === 403) return "permission_error"; - if (statusCode >= 400 && statusCode < 500) return "invalid_request_error"; - return "api_error"; +function encodeSseEvent( + data: unknown, + { + event, + includeDone = false, + }: { + event?: string; + includeDone?: boolean; + } = {} +) { + if (event && /[\r\n]/.test(event)) { + throw new Error("SSE event names must not contain newlines"); + } + + const encoder = new TextEncoder(); + const prefix = event ? `event: ${event}\n` : ""; + const chunks = [encoder.encode(`${prefix}data: ${JSON.stringify(data)}\n\n`)]; + if (includeDone) { + chunks.push(encoder.encode("data: [DONE]\n\n")); + } + return chunks; } // Get HH:MM:SS timestamp @@ -73,7 +127,6 @@ function getTimeString() { /** @param {StreamControllerOptions} options */ export function createStreamController({ onDisconnect, - log, provider, model, connectionId, @@ -180,7 +233,8 @@ function buildStreamErrorChunks( statusCode: number, clientResponseFormat?: string | null ) { - const encoder = new TextEncoder(); + const statusMapping = getStreamErrorStatusMapping(statusCode); + if (isResponsesClientFormat(clientResponseFormat)) { const errorEvent = { type: "response.failed", @@ -189,25 +243,25 @@ function buildStreamErrorChunks( status: "failed", error: { message: errorMsg, - type: responsesErrorType(statusCode), - code: responsesErrorCode(statusCode), + type: statusMapping.responses.type, + code: statusMapping.responses.code, }, }, }; - return [encoder.encode(`event: response.failed\ndata: ${JSON.stringify(errorEvent)}\n\n`)]; + return encodeSseEvent(errorEvent, { event: "response.failed" }); } if (clientResponseFormat === FORMATS.CLAUDE) { const errorEvent = { type: "error", error: { - type: claudeErrorType(statusCode), + type: statusMapping.claude.type, message: errorMsg, }, }; - return [encoder.encode(`event: error\ndata: ${JSON.stringify(errorEvent)}\n\n`)]; + return encodeSseEvent(errorEvent, { event: "error" }); } const errorEvent = { @@ -226,10 +280,7 @@ function buildStreamErrorChunks( }, }; - return [ - encoder.encode(`data: ${JSON.stringify(errorEvent)}\n\n`), - encoder.encode(`data: [DONE]\n\n`), - ]; + return encodeSseEvent(errorEvent, { includeDone: true }); } /** diff --git a/package-lock.json b/package-lock.json index ac7edf9a44..e0e1d4d2a4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "omniroute", - "version": "3.8.0", + "version": "3.8.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "omniroute", - "version": "3.8.0", + "version": "3.8.1", "hasInstallScript": true, "license": "MIT", "workspaces": [ @@ -21,7 +21,6 @@ "@xyflow/react": "^12.10.2", "axios": "^1.16.1", "bcryptjs": "^3.0.3", - "better-sqlite3": "^12.10.0", "bottleneck": "^2.19.5", "cli-table3": "^0.6.5", "commander": "^14.0.3", @@ -37,13 +36,13 @@ "ink-spinner": "^5.0.0", "ink-text-input": "^6.0.0", "ioredis": "^5.10.1", - "isomorphic-dompurify": "^3.13.0", + "isomorphic-dompurify": "^3.14.0", "jose": "^6.2.3", "js-yaml": "^4.1.1", "jsonc-parser": "^3.3.1", "lowdb": "^7.0.1", "lucide-react": "^1.16.0", - "marked": "^18.0.3", + "marked": "^18.0.4", "marked-terminal": "^7.3.0", "mermaid": "^11.15.0", "monaco-editor": "^0.55.1", @@ -64,8 +63,8 @@ "recharts": "^3.8.1", "selfsigned": "^5.5.0", "sql.js": "^1.14.1", - "tsx": "^4.21.1", - "undici": "^8.2.0", + "tsx": "^4.22.3", + "undici": "^8.3.0", "update-notifier": "^7.3.1", "uuid": "^14.0.0", "xxhash-wasm": "^1.1.0", @@ -85,10 +84,10 @@ "@types/bcryptjs": "^3.0.0", "@types/better-sqlite3": "^7.6.13", "@types/keytar": "^4.4.2", - "@types/node": "^25.7.0", - "@types/react": "^19.2.14", + "@types/node": "^25.9.1", + "@types/react": "^19.2.15", "@types/react-dom": "^19.2.3", - "@vitejs/plugin-react": "^6.0.1", + "@vitejs/plugin-react": "^6.0.2", "c8": "^11.0.0", "concurrently": "^9.2.1", "cross-env": "^10.1.0", @@ -97,23 +96,24 @@ "glob": "^13.0.6", "husky": "^9.1.7", "jsdom": "^29.1.1", - "lint-staged": "^17.0.4", + "lint-staged": "^17.0.5", "node-loader": "^2.1.0", "prettier": "^3.8.3", "tailwindcss": "^4.3.0", "typescript": "^6.0.3", - "typescript-eslint": "^8.59.3", - "vitest": "^4.1.6", + "typescript-eslint": "^8.59.4", + "vitest": "^4.1.7", "wait-on": "^9.0.10", "wtfnode": "^0.10.1" }, "engines": { - "node": ">=22.22.2 <23 || >=24.0.0 <27" + "node": ">=22.22.3 <23 || >=24.0.0 <27" }, "optionalDependencies": { + "better-sqlite3": "^12.10.0", "keytar": "^7.9.0", "tls-client-node": "^0.1.13", - "wreq-js": "^2.3.0" + "wreq-js": "^2.3.1" } }, "node_modules/@adobe/css-tools": { @@ -4549,9 +4549,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "25.9.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-25.9.0.tgz", - "integrity": "sha512-AOQwYUNolgy3VosiRqXrACUXTN8nJUtPl7FJXMqZVyxiiCLhQuG3jXKvCS1ALr+Y2OmZhzzLVlYPEqJaiqkaJQ==", + "version": "25.9.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.9.1.tgz", + "integrity": "sha512-xfrlY7UD5rMJk3ZVJP8BNzS28J36YJg+xp+LPXV1TdWxr8uMH5A860QNxYDGQe/ylDSgjxE52Q9VnO7p75tJxg==", "dev": true, "license": "MIT", "dependencies": { @@ -4565,9 +4565,9 @@ "license": "MIT" }, "node_modules/@types/react": { - "version": "19.2.14", - "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz", - "integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==", + "version": "19.2.15", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.15.tgz", + "integrity": "sha512-eRwcGNHve+E8qtEQSSRl6urh+rFop4v8gm6O8rGv25CodbvFdLjA1vVQ1KkiFE0w0UPOnb8tDiFKL5lp0rtY5Q==", "dev": true, "license": "MIT", "dependencies": { @@ -5210,16 +5210,16 @@ } }, "node_modules/@vitest/expect": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.6.tgz", - "integrity": "sha512-7EHDquPthALSV0jhhjgEW8FXaviMx7rSqu8W6oqCoAuOhKov814P99QDV1pxMA3QPv21YudvJngIhjrNI4opLg==", + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.7.tgz", + "integrity": "sha512-1R+tw0ortHEbZDGMymm+pN7/AFQ/RkFFdtd7EN+VBpynKmLbP8A3rpEXdshBJ7+8hQ9zBJh/i1s0yKNtxAnU7w==", "dev": true, "license": "MIT", "dependencies": { "@standard-schema/spec": "^1.1.0", "@types/chai": "^5.2.2", - "@vitest/spy": "4.1.6", - "@vitest/utils": "4.1.6", + "@vitest/spy": "4.1.7", + "@vitest/utils": "4.1.7", "chai": "^6.2.2", "tinyrainbow": "^3.1.0" }, @@ -5228,13 +5228,13 @@ } }, "node_modules/@vitest/mocker": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.6.tgz", - "integrity": "sha512-MCFc63czMjEInOlcY2cpQCvCN+KgbAn+60xu9cMgP4sKaLC5JNAKw7JH8QdAnoAC88hW1IiSNZ+GgVXlN1UcMQ==", + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.7.tgz", + "integrity": "sha512-vY7nuamKgfvpA1Koa3oYIw/k7D6kZnpGyNMZW8loow2bsBYla1TFdqTaXncWdRn4pgwNs+90RhnXhJScDwQeJA==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/spy": "4.1.6", + "@vitest/spy": "4.1.7", "estree-walker": "^3.0.3", "magic-string": "^0.30.21" }, @@ -5255,9 +5255,9 @@ } }, "node_modules/@vitest/pretty-format": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.6.tgz", - "integrity": "sha512-h5SxD/IzNhZYnrSZRsUZQIC+vD0GY8cUvq0iwsmkFKixRCKLLWqCXa/FIQ4S1R+sI+PGoojkHsdNrbZiM9Qpgw==", + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.7.tgz", + "integrity": "sha512-umgCarTOYQWIaDMvGDRZij+6b9oVeLIyJzfN+AS88e0ZOU3QTgNNSTtjQOpcvWr3np1N0j4WgZj+sb3oYBDscw==", "dev": true, "license": "MIT", "dependencies": { @@ -5268,13 +5268,13 @@ } }, "node_modules/@vitest/runner": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.6.tgz", - "integrity": "sha512-nOPCmn2+yD0ZNmKdsXGv/UxMMWbMuKeD6GyYncNwdkYDxpQvrPSKYj2rWuDjC2Y4b6w6hjip5dBKFzEUuZe3vA==", + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.7.tgz", + "integrity": "sha512-BapjmAQ2aI78WdMEfeUWivnfVzB+VPGwWRQcJE0OUq7qEeEcBsCSf+0T5iREBNE5nBb4wA5Ya0W6IA+sghdEFw==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/utils": "4.1.6", + "@vitest/utils": "4.1.7", "pathe": "^2.0.3" }, "funding": { @@ -5282,14 +5282,14 @@ } }, "node_modules/@vitest/snapshot": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.6.tgz", - "integrity": "sha512-YhsdE6xAVfTDmzjxL2ZDUvjj+ZsgyOKe+TdQzqkD72wIOmHka8NuGQ6NpTNZv9D2Z63fbwWKJPeVpEw4EQgYxw==", + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.7.tgz", + "integrity": "sha512-ZacLzja+TmJeZ1h14xW2FB/WpeimUD3haBXQPyJqxvo8jQTmfeA8zv58mtjN2C7EHXZDYVcVYdYmAxjkWVvKCw==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "4.1.6", - "@vitest/utils": "4.1.6", + "@vitest/pretty-format": "4.1.7", + "@vitest/utils": "4.1.7", "magic-string": "^0.30.21", "pathe": "^2.0.3" }, @@ -5298,9 +5298,9 @@ } }, "node_modules/@vitest/spy": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.6.tgz", - "integrity": "sha512-JFKxMx6udhwKh/Ldo270e17QX710vgunMkuPAvXjHSvC6oqLWAHhVhjg/I71q0u0CBSErIODV1Kjv0FQNSWjdg==", + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.7.tgz", + "integrity": "sha512-kbkI5LMWakyuTIvs6fUJ5qdIVb1XVKsYJAT4OJ938cHMROYMSfmoQdZy0aaAnjbbc8F61vkoTqz/Az+/HiIu5Q==", "dev": true, "license": "MIT", "funding": { @@ -5308,13 +5308,13 @@ } }, "node_modules/@vitest/utils": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.6.tgz", - "integrity": "sha512-FxIY+U81R3LGKCxaHHFRQ5+g6/iRgGLmeHWdp2Amj4ljQRrEIWHmZyDfDYBRZlpyqA7qKxtS9DD1dhk8RnRIVQ==", + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.7.tgz", + "integrity": "sha512-T532WBu791cBxJlCl6SO+J14l81DQx6uQHm1bQbmCDY7nqlEIgkza/UFnSBNaUtSf41unldDFjdOBYEQC4b5Hw==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "4.1.6", + "@vitest/pretty-format": "4.1.7", "convert-source-map": "^2.0.0", "tinyrainbow": "^3.1.0" }, @@ -5944,6 +5944,7 @@ "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "devOptional": true, "funding": [ { "type": "github", @@ -5987,6 +5988,7 @@ "integrity": "sha512-CyzaZRQKyHkB2ZInfTTl2nvT33EbDpjkLEbE8/Zck3Ll6O0qqvuGdrJ45HgtH+HykRg88ITY3AdreBGN70aBSQ==", "hasInstallScript": true, "license": "MIT", + "optional": true, "dependencies": { "bindings": "^1.5.0", "prebuild-install": "^7.1.1" @@ -6019,6 +6021,7 @@ "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", "license": "MIT", + "optional": true, "dependencies": { "file-uri-to-path": "1.0.0" } @@ -6027,6 +6030,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "devOptional": true, "license": "MIT", "dependencies": { "buffer": "^5.5.0", @@ -6205,6 +6209,7 @@ "version": "5.7.1", "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "devOptional": true, "funding": [ { "type": "github", @@ -6491,6 +6496,7 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "devOptional": true, "license": "ISC" }, "node_modules/classcat": { @@ -7794,6 +7800,7 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "devOptional": true, "license": "MIT", "dependencies": { "mimic-response": "^3.1.0" @@ -8956,6 +8963,7 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", + "devOptional": true, "license": "(MIT OR WTFPL)", "engines": { "node": ">=6" @@ -9189,7 +9197,8 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", - "license": "MIT" + "license": "MIT", + "optional": true }, "node_modules/fill-range": { "version": "7.1.1", @@ -9380,6 +9389,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "devOptional": true, "license": "MIT" }, "node_modules/fsevents": { @@ -9563,6 +9573,7 @@ "version": "0.0.0", "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", + "devOptional": true, "license": "MIT" }, "node_modules/glob": { @@ -10071,6 +10082,7 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "devOptional": true, "funding": [ { "type": "github", @@ -11194,12 +11206,12 @@ "license": "ISC" }, "node_modules/isomorphic-dompurify": { - "version": "3.13.0", - "resolved": "https://registry.npmjs.org/isomorphic-dompurify/-/isomorphic-dompurify-3.13.0.tgz", - "integrity": "sha512-QzgzjAGJN0QoOpLWx7mkMhhTQvQXsBpS6oEi2Wy58mEWwrvaRJrx5hrVEdsM70nNKOwHCHj3bwYkwI+HFd3Khg==", + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/isomorphic-dompurify/-/isomorphic-dompurify-3.14.0.tgz", + "integrity": "sha512-64W8/lsfqgaDWfEkvrIVk8FdIk29Mya0Fp39excQEdlcLUPg1Cn7CtCYe6CtPbFW90JpEKTXG0QQtIUNENJ7sw==", "license": "MIT", "dependencies": { - "dompurify": "^3.4.3", + "dompurify": "^3.4.5", "jsdom": "^29.1.1" }, "engines": { @@ -12188,9 +12200,9 @@ } }, "node_modules/marked": { - "version": "18.0.3", - "resolved": "https://registry.npmjs.org/marked/-/marked-18.0.3.tgz", - "integrity": "sha512-7VT90JOkDeaRWpfjOReRGPEKn0ecdARBkDGL+tT1wZY0efPPqkUxLUSmzy/C7TIylQYJC9STISEsCHrqb/7VIA==", + "version": "18.0.4", + "resolved": "https://registry.npmjs.org/marked/-/marked-18.0.4.tgz", + "integrity": "sha512-c/BTaKzg0G6ezQx97DAkYU7k0HM6ys0FqYeKBL6hlBByZwy+ycA1+f0vDdjMHKKeEjdgkx0GOv9Il6D+85cOqA==", "license": "MIT", "bin": { "marked": "bin/marked.js" @@ -13001,6 +13013,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "devOptional": true, "license": "MIT", "engines": { "node": ">=10" @@ -13055,6 +13068,7 @@ "version": "0.5.3", "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", + "devOptional": true, "license": "MIT" }, "node_modules/mlly": { @@ -13130,6 +13144,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-2.0.0.tgz", "integrity": "sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==", + "devOptional": true, "license": "MIT" }, "node_modules/napi-postinstall": { @@ -13277,6 +13292,7 @@ "version": "3.89.0", "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.89.0.tgz", "integrity": "sha512-6u9UwL0HlAl21+agMN3YAMXcKByMqwGx+pq+P76vii5f7hTPtKDp08/H9py6DY+cfDw7kQNTGEj/rly3IgbNQA==", + "devOptional": true, "license": "MIT", "dependencies": { "semver": "^7.3.5" @@ -13289,6 +13305,7 @@ "version": "7.7.4", "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "devOptional": true, "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -14150,6 +14167,7 @@ "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.3.tgz", "integrity": "sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==", "deprecated": "No longer maintained. Please contact the author of the relevant native addon; alternatives are available.", + "devOptional": true, "license": "MIT", "dependencies": { "detect-libc": "^2.0.0", @@ -14509,6 +14527,7 @@ "version": "3.6.2", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "devOptional": true, "license": "MIT", "dependencies": { "inherits": "^2.0.3", @@ -14976,6 +14995,7 @@ "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "devOptional": true, "funding": [ { "type": "github", @@ -15399,6 +15419,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "devOptional": true, "funding": [ { "type": "github", @@ -15419,6 +15440,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", + "devOptional": true, "funding": [ { "type": "github", @@ -15660,6 +15682,7 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "devOptional": true, "license": "MIT", "dependencies": { "safe-buffer": "~5.2.0" @@ -16051,6 +16074,7 @@ "version": "2.1.4", "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.4.tgz", "integrity": "sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==", + "devOptional": true, "license": "MIT", "dependencies": { "chownr": "^1.1.1", @@ -16063,6 +16087,7 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "devOptional": true, "license": "MIT", "dependencies": { "bl": "^4.0.3", @@ -16390,9 +16415,9 @@ "license": "0BSD" }, "node_modules/tsx": { - "version": "4.22.2", - "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.22.2.tgz", - "integrity": "sha512-6w9FwtT8WQqRAyTNR+Z+86kghRqpmOLjXUrBlBT6T+CQGDuIMm0VmAqaFUFBIeKDTGobE6/YSigZYLeomzBaRg==", + "version": "4.22.3", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.22.3.tgz", + "integrity": "sha512-mdoNxBC/cSQObGGVQ5Bpn5i+yv7j68gk3Nfm3wFjcJg3Z0Mix9jzAFfP12prmm5eVGmDKtp0yyArrs0Q+8gZHg==", "license": "MIT", "dependencies": { "esbuild": "~0.28.0" @@ -16443,6 +16468,7 @@ "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "devOptional": true, "license": "Apache-2.0", "dependencies": { "safe-buffer": "^5.0.1" @@ -16919,6 +16945,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "devOptional": true, "license": "MIT" }, "node_modules/uuid": { @@ -17109,19 +17136,19 @@ } }, "node_modules/vitest": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.6.tgz", - "integrity": "sha512-6lvjbS3p9b4CrdCmguzbh2/4uoXhGE2q71R4OX5sqF9R1bo9Xd6fGrMAfvp5wnCzlBnFVdCOp6onuTQVbo8iUQ==", + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.7.tgz", + "integrity": "sha512-flYyaFd2CgoCoU+0UKt3pxksgC+S02iTDN0n3LtqaMeXsI9SBcdNujc2k0DeFLzUn/0k538yNjOSdwgCqcrwJA==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/expect": "4.1.6", - "@vitest/mocker": "4.1.6", - "@vitest/pretty-format": "4.1.6", - "@vitest/runner": "4.1.6", - "@vitest/snapshot": "4.1.6", - "@vitest/spy": "4.1.6", - "@vitest/utils": "4.1.6", + "@vitest/expect": "4.1.7", + "@vitest/mocker": "4.1.7", + "@vitest/pretty-format": "4.1.7", + "@vitest/runner": "4.1.7", + "@vitest/snapshot": "4.1.7", + "@vitest/spy": "4.1.7", + "@vitest/utils": "4.1.7", "es-module-lexer": "^2.0.0", "expect-type": "^1.3.0", "magic-string": "^0.30.21", @@ -17149,12 +17176,12 @@ "@edge-runtime/vm": "*", "@opentelemetry/api": "^1.9.0", "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", - "@vitest/browser-playwright": "4.1.6", - "@vitest/browser-preview": "4.1.6", - "@vitest/browser-webdriverio": "4.1.6", - "@vitest/coverage-istanbul": "4.1.6", - "@vitest/coverage-v8": "4.1.6", - "@vitest/ui": "4.1.6", + "@vitest/browser-playwright": "4.1.7", + "@vitest/browser-preview": "4.1.7", + "@vitest/browser-webdriverio": "4.1.7", + "@vitest/coverage-istanbul": "4.1.7", + "@vitest/coverage-v8": "4.1.7", + "@vitest/ui": "4.1.7", "happy-dom": "*", "jsdom": "*", "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" @@ -17467,9 +17494,9 @@ "license": "ISC" }, "node_modules/wreq-js": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/wreq-js/-/wreq-js-2.3.0.tgz", - "integrity": "sha512-jROBpTUhVH40qG+cAvBhdduKPGDSx55jK1dIDmVuu29sux9i8KY0u0wb5tHkMzXKDy9hrfHP+bpvaSq25rGwEA==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/wreq-js/-/wreq-js-2.3.1.tgz", + "integrity": "sha512-vaKasaKeskrDKEuuO5Q5uamEG9a6FrF5ZSicH7TCvYS4RxF7/gzaU/vYqwJzcs+uydyJPVWY1KCvfVCgp0tiGA==", "cpu": [ "x64", "arm64" @@ -17784,7 +17811,7 @@ }, "open-sse": { "name": "@omniroute/open-sse", - "version": "3.8.0" + "version": "3.8.1" } } } diff --git a/package.json b/package.json index 99bf05ca36..7ef7bc48d2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "omniroute", - "version": "3.8.0", + "version": "3.8.1", "description": "Unified AI router with 160+ providers, RTK+Caveman compression, auto fallback, MCP/A2A, desktop, PWA, and OpenAI-compatible APIs.", "type": "module", "bin": { @@ -41,7 +41,7 @@ "open-sse" ], "engines": { - "node": ">=22.22.2 <23 || >=24.0.0 <27" + "node": ">=22.22.3 <23 || >=24.0.0 <27" }, "keywords": [ "ai", @@ -139,7 +139,6 @@ "@xyflow/react": "^12.10.2", "axios": "^1.16.1", "bcryptjs": "^3.0.3", - "better-sqlite3": "^12.10.0", "bottleneck": "^2.19.5", "cli-table3": "^0.6.5", "commander": "^14.0.3", @@ -155,13 +154,13 @@ "ink-spinner": "^5.0.0", "ink-text-input": "^6.0.0", "ioredis": "^5.10.1", - "isomorphic-dompurify": "^3.13.0", + "isomorphic-dompurify": "^3.14.0", "jose": "^6.2.3", "js-yaml": "^4.1.1", "jsonc-parser": "^3.3.1", "lowdb": "^7.0.1", "lucide-react": "^1.16.0", - "marked": "^18.0.3", + "marked": "^18.0.4", "marked-terminal": "^7.3.0", "mermaid": "^11.15.0", "monaco-editor": "^0.55.1", @@ -182,8 +181,8 @@ "recharts": "^3.8.1", "selfsigned": "^5.5.0", "sql.js": "^1.14.1", - "tsx": "^4.21.1", - "undici": "^8.2.0", + "tsx": "^4.22.3", + "undici": "^8.3.0", "update-notifier": "^7.3.1", "uuid": "^14.0.0", "xxhash-wasm": "^1.1.0", @@ -192,9 +191,10 @@ "zustand": "^5.0.13" }, "optionalDependencies": { + "better-sqlite3": "^12.10.0", "keytar": "^7.9.0", "tls-client-node": "^0.1.13", - "wreq-js": "^2.3.0" + "wreq-js": "^2.3.1" }, "devDependencies": { "@playwright/test": "^1.60.0", @@ -204,10 +204,10 @@ "@types/bcryptjs": "^3.0.0", "@types/better-sqlite3": "^7.6.13", "@types/keytar": "^4.4.2", - "@types/node": "^25.7.0", - "@types/react": "^19.2.14", + "@types/node": "^25.9.1", + "@types/react": "^19.2.15", "@types/react-dom": "^19.2.3", - "@vitejs/plugin-react": "^6.0.1", + "@vitejs/plugin-react": "^6.0.2", "c8": "^11.0.0", "concurrently": "^9.2.1", "cross-env": "^10.1.0", @@ -216,13 +216,13 @@ "glob": "^13.0.6", "husky": "^9.1.7", "jsdom": "^29.1.1", - "lint-staged": "^17.0.4", + "lint-staged": "^17.0.5", "node-loader": "^2.1.0", "prettier": "^3.8.3", "tailwindcss": "^4.3.0", "typescript": "^6.0.3", - "typescript-eslint": "^8.59.3", - "vitest": "^4.1.6", + "typescript-eslint": "^8.59.4", + "vitest": "^4.1.7", "wait-on": "^9.0.10", "wtfnode": "^0.10.1" }, diff --git a/package/package.json b/package/package.json index 6b24002e8e..68990987cc 100644 --- a/package/package.json +++ b/package/package.json @@ -123,15 +123,15 @@ "express": "^5.2.1", "fetch-socks": "^1.3.3", "fuse.js": "^7.3.0", - "http-proxy-middleware": "^3.0.5", + "http-proxy-middleware": "^4.0.0", "https-proxy-agent": "^9.0.0", - "isomorphic-dompurify": "^3.13.0", + "isomorphic-dompurify": "^3.14.0", "jose": "^6.2.3", "js-yaml": "^4.1.1", "jsonc-parser": "^3.3.1", "lowdb": "^7.0.1", "lucide-react": "^1.16.0", - "marked": "^18.0.3", + "marked": "^18.0.4", "mermaid": "^11.15.0", "monaco-editor": "^0.55.1", "next": "^16.2.6", @@ -149,10 +149,10 @@ "recharts": "^3.8.1", "selfsigned": "^5.5.0", "tls-client-node": "^0.1.13", - "tsx": "^4.21.1", - "undici": "^8.2.0", + "tsx": "^4.22.3", + "undici": "^8.3.0", "uuid": "^14.0.0", - "wreq-js": "^2.3.0", + "wreq-js": "^2.3.1", "xxhash-wasm": "^1.1.0", "yazl": "^3.3.1", "zod": "^4.4.3", @@ -169,10 +169,10 @@ "@types/bcryptjs": "^3.0.0", "@types/better-sqlite3": "^7.6.13", "@types/keytar": "^4.4.2", - "@types/node": "^25.7.0", - "@types/react": "^19.2.14", + "@types/node": "^25.9.1", + "@types/react": "^19.2.15", "@types/react-dom": "^19.2.3", - "@vitejs/plugin-react": "^6.0.1", + "@vitejs/plugin-react": "^6.0.2", "c8": "^11.0.0", "concurrently": "^9.2.1", "cross-env": "^10.1.0", @@ -182,13 +182,13 @@ "gray-matter": "^4.0.3", "husky": "^9.1.7", "jsdom": "^29.1.1", - "lint-staged": "^16.4.0", + "lint-staged": "^17.0.5", "node-loader": "^2.1.0", "prettier": "^3.8.3", "tailwindcss": "^4.3.0", "typescript": "^6.0.3", - "typescript-eslint": "^8.59.3", - "vitest": "^4.1.6", + "typescript-eslint": "^8.59.4", + "vitest": "^4.1.7", "wait-on": "^9.0.10", "wtfnode": "^0.10.1" }, diff --git a/scripts/i18n/extract-keys-from-diff.mjs b/scripts/i18n/extract-keys-from-diff.mjs index 7d0aece27e..7d903b3220 100644 --- a/scripts/i18n/extract-keys-from-diff.mjs +++ b/scripts/i18n/extract-keys-from-diff.mjs @@ -84,10 +84,15 @@ for (const { file, removed, added } of allPairs) { for (const m of removed.matchAll(ATTR_RE)) candidates.push(m[1]); // Direct strings without surrounding markup (rare) - const stripped = removed - .replace(/<[^<>]+>/g, "") - .replace(/\bt\([^)]*\)/g, "") - .trim(); + // Apply tag removal repeatedly until stable to prevent incomplete sanitization + // (e.g. "ipt>" collapsing into "