Repository navigation
Resolve apiKeys test-file case collision on case-insensitive filesystems - #2
Closed
TechNickAI wants to merge 1 commit into
Closed
TechNickAI wants to merge 1 commit into
TechNickAI wants to merge 1 commit into
Conversation
tests/unit had two files differing only in case — db-apiKeys-crud.test.ts and db-apikeys-crud.test.ts. On case-insensitive filesystems (macOS/APFS) only one can exist in the working tree, so `git clone` warned about a path collision and checked out just one of them. Keep the canonical camelCase file (matches src/lib/db/apiKeys.ts and the files=camelCase convention); remove the lowercase duplicate. Port the 8 tests from the lowercase file that exercised behavior the canonical superset lacked: malformed access_schedule payloads, throttle/maxRequests scalar fields, streamDefaultMode, allowedCombos, negative maxSessions clamping, scope-clearing back to empty, and createApiKey defaults + sk- key format. Add a test.after hook that closes the SQLite handle and removes the temp data dir so the suite exits cleanly (CLAUDE.md 'Database Handles in Tests'). Result: 62 tests, all passing, no remaining case collision.
Owner
Author
|
Closing in favor of upstream diegosouzapw#3125 (merged 2026-06-03 by @juandisay), which already removed the lowercase case-variant duplicate. The fork will pick up that fix on its next sync from upstream. Note: diegosouzapw#3125 deleted the lowercase file without porting its unique test coverage, so that coverage won't carry over — accepted as upstream's approach. |
TechNickAI
pushed a commit
that referenced
this pull request
Jun 11, 2026
* chore(release): open v3.8.19 development cycle * chore(release): sync electron lockfile to 3.8.19 * feat(quality): quality-gate ratchet + anti-hallucination/rule-enforcement guardrails (Phases 0-6) (diegosouzapw#3471) * feat(quality): generic ratchet comparator (multi-metric, regression-only) * chore(ci): Fase 0 quality-gate fixes — reconcile coverage gate (40->60), tier npm audit, wire orphaned contract gates, re-enable cheap husky pre-commit * feat(quality): ratchet engine (collector + frozen baseline + CI job) and provider-consistency gate - collect-metrics.mjs: emits quality-metrics.json (ESLint warnings + coverage when present) - quality-baseline.json: frozen baseline (eslintWarnings=3482, regression-only) - ci.yml: quality-gate job (ratchet + step summary + artifact) and check:provider-consistency in lint job - check-provider-consistency.ts: every REGISTRY id must be a canonical provider (found krutrim half-registered → allowlisted as known pre-existing, blocks any NEW orphan) - TDD: 9 tests (5 ratchet + 4 provider-consistency) * feat(quality): Fase 2 anti-hallucination gates — fetch-targets, openapi-routes, deps allowlist - check-fetch-targets: every dashboard fetch(/api/...) resolves to a real route.ts; found 7 pre-existing dashboard->route mismatches frozen as KNOWN_MISSING for triage - check-openapi-routes: every openapi.yaml path resolves to a real route; found 1 stale spec entry (agent-bridge agents/{id}/state) frozen as KNOWN_STALE_SPEC - check-deps: anti-slopsquatting allowlist (105 deps); new deps need explicit human-reviewed entry - all wired into CI lint/docs jobs; TDD +12 tests (21 total across 5 gates) * docs(quality): add quality-gates report + implementation plan to repo root * feat(quality): Fase 3a — file-size ratchet (freeze 91 files >800 LOC, cap 800 for new) - check-file-size.mjs: frozen files can only shrink; new files must be <= cap (kills the next 12k-line god-component) - file-size-baseline.json: 91 files frozen at current LOC (largest 12883) - wired into CI lint job; TDD 5 tests; --update ratchets the baseline down on shrink * feat(quality): Fase 3b — duplication ratchet (jscpd@4, baseline 5.72%) - check-duplication.mjs: runs jscpd@4 (pinned; v5 is an incompatible Rust rewrite) over src+open-sse, fails if duplication % rises vs frozen baseline (5.72%, measured: 1358 clones / 22967 dup lines). Targets the executor copy-paste (48/50 override execute() wholesale) - wired into the parallel quality-gate CI job (off the lint critical path); TDD 4 tests; --update ratchets down - snapshot now complete: coverage ~82.6%, eslint 3482 (98.5% no-explicit-any), duplication 5.72%, 91 files >800 LOC * feat(quality): Fase 4a — anti test-masking gate - check-test-masking.mjs: for each MODIFIED test file in a PR, flags net assert removal + new assert.ok(true) tautologies (base...HEAD diff). Directly enforces CLAUDE.md 'never weaken asserts to go green' - wired into pr-test-policy CI job (reuses base fetch); no-op outside PR; TDD 5 tests * feat(quality): Fase 4b — coverage ratchet (conservative floors, CI consumes merged coverage) - quality-baseline.json: coverage.{statements,lines,functions,branches} floors (80/80/82/73, real ~82.58/82.58/84.23/75.22 with margin; tighten via --update after a green main run) - check-quality-ratchet.mjs: --allow-missing (local quality:gate skips coverage.* without a coverage run; CI runs strict) - ci.yml quality-gate job: needs test-coverage + downloads merged coverage-report so the ratchet enforces 'coverage cannot drop' - TDD +1 test (6 total) * feat(quality): Fase 6 — 8 new gates (Rule #11/#12, migrations, known-symbols, route-guard, complexity, docs-symbols, db-rules) Deterministic gates, each freezing pre-existing violations in a documented allowlist (ratchet) so they pass now and block only NEW regressions: - check-error-helper (Rule #12): 7 executors/handlers forwarding raw err.message frozen - check-public-creds (Rule #11): 5 literal client_ids (Claude/Codex/Qwen/Kimi/Copilot) frozen - check-migration-numbering: gaps 026/055 + dup 041 frozen (prevents the git-rm-deleted-migration incident) - check-known-symbols: 93 executors conformance + 15 combo strategies + 18 translator pairs - check-route-guard-membership (diegosouzapw#15/diegosouzapw#17): all 25 spawn-capable routes verified local-only (0 gaps) - check-complexity: cyclomatic>15 / fn-length>80 ratchet (baseline 1739) - check-docs-symbols: 30 stale doc /api refs frozen (docs hallucination) - check-db-rules (#2/#5): 25 unexported db modules + 15 raw-SQL routes frozen Wired into CI (lint / docs-sync-strict / quality-gate jobs). 115 TDD tests, all green. ESLint ratchet held at 3482. * docs(quality): Phase 7 plan (security/dead-code/mutation/community tooling) — GATED to 2026-06-16 Stored, not active. 7 suggested gates + all discussed OSS/Community tools (SonarQube Community + osv-scanner + CodeQL + knip + sonarjs + type-coverage + lockfile-lint + Stryker + size-limit + axe-core + semcheck + agent-lsp + Qlty). Activation gate: do not start before 2026-06-16 (use Phases 0-6 in production for 1 week, validate in practice, then evolve). * docs(quality): Phase 6A critical-audit plan + Phase 7 additions — gated to 2026-06-16 (diegosouzapw#3530) PLANO-QUALITY-GATES-FASE6A.md (12-task audit of Phases 0-6: orphan tests, stale-allowlist enforcement, scope gaps) + Phase 7 additions (gitleaks, actionlint+zizmor, license compliance). Both stored, activation gated to 2026-06-16. Tasks 6A.1/6A.2 were fast-tracked separately (diegosouzapw#3536). * feat(quality): 6A.1+6A.2 — test-discovery gate, 135 orphan tests re-wired, 2 production bug fixes, vitest in CI (diegosouzapw#3536) check-test-discovery gate (TDD; 195 orphans found, 135 re-wired into the node runner, 60 frozen+annotated). Triage fixed 2 real production bugs: missing BYPASS_PREFIX_NOT_ALLOWED zod refine (spawn-capable prefixes accepted into the bypass list, Hard Rules diegosouzapw#15/diegosouzapw#17) and resetDbInstance not firing stateReset resetters (stale schema memo → 503 instead of 403; also hit backup-restore). New test-vitest CI job: test:vitest blocking (146/146), test:vitest:ui informational (14 pre-existing fails, triage 2026-06-16). * chore: ignore generated yt-downloader artifact files Add dated yt-downloader output files to .gitignore to prevent local automation artifacts from being accidentally committed. * chore(quality): green-light the quality-gate — conscious file-size + eslintWarnings re-baselines (diegosouzapw#3538) file-size: 9 files frozen at current sizes (v3.8.18-era growth + core.ts +7 from diegosouzapw#3536 fix). eslintWarnings 3482→3501: the published v3.8.18 tag already measures 3501 (delta predates the quality-gate job); v3.8.19 cycle is neutral. Reduction + --require-tighten = Phase 6A (2026-06-16). * fix(check): exclude internal planning docs (docs/superpowers/) from the docs-symbols gate docs/superpowers/plans/*.md are historical implementation-plan snapshots that may cite planned/abandoned routes — not claims about the current code. Three such refs entered during the v3.8.18 cycle, before this gate was on the pipeline, and would have blocked the v3.8.19 release merge. * chore(release): v3.8.19 — 2026-06-09 CHANGELOG section for the quality-infrastructure release (7 commits, 1:1 coverage), [3.8.18] label corrected to its real release date, local prompt artifacts ignored. * test: hermetic auth context for 2 re-wired suites + real headroom on the breaker reset-timeout flake CI shards exposed what the dev DATA_DIR was masking locally: detect.test.ts and managementCliToken.test.ts asserted 401/403/reject outcomes that only exist when login protection is configured — on a fresh CI DB isAuthRequired() is false and the policy anonymous-allows. Both now create an isolated DATA_DIR with requireLogin+password (the established pattern). observability-fase04: the breaker reset-timeout test ran with a 5ms margin (resetTimeout 10 / sleep 15) — lazy HALF_OPEN refresh under shard contention flipped the first OPEN assert. Now 250/300ms. * test: align bypass-prefix schema test to the restored layer-1 contract + real waitFor headroom appearance-widget-settings-schema asserted that /api/cli-tools/runtime/ was ACCEPTED into the bypass list — written against the buggy schema (missing BYPASS_PREFIX_NOT_ALLOWED refine, restored in diegosouzapw#3536) and consecrating the bug the AC-8 orphan test guards against. Split into accept-safe + reject-spawn-capable cases. chatcore waitFor ceiling 1500→10000ms (green runs return immediately; observed 1580ms expiry on 2-core CI runners). * test(chatcore): fix structurally-broken pending-detail predicate (flatten before find) pendingRequests.details[connectionId] is Record<modelKey, PendingRequestDetail[]> — the upstream-timeout test's waitFor tested each ARRAY's .providerRequest (always undefined), so it could never resolve and expired (failed on 3 CI jobs; reproduced deterministically isolated, including at the published v3.8.18 tag). Flatten to the actual details + declare the call_log_pipeline_enabled dependency explicitly + waitFor ceiling with real CI headroom. * chore(quality): re-baseline coverage floors to the honest post-re-wire denominator + changelog coverage for the stabilization commits The 135 re-wired tests import modules that were never loaded before, so the c8 denominator grew: the old ~82.5% was inflated by never-imported modules being invisible. CI merged coverage now measures 78.4/78.4/83.84/75.73 — floors set ~2pt below (76.5/76.5; functions/branches floors already hold). Tightening via --require-tighten is Phase 6A work (2026-06-16).
TechNickAI
pushed a commit
that referenced
this pull request
Jul 19, 2026
* chore(release): open v3.8.36 development cycle * refactor(chatCore): extrai resolveCompressionSettings (diegosouzapw#3501) (diegosouzapw#4826) Integrated into release/v3.8.36 (diegosouzapw#3501 chatCore extraction stack 1/13) * refactor(chatCore): extrai predicados puros de combo de compressão (diegosouzapw#3501) (diegosouzapw#4824) Integrated into release/v3.8.36 (diegosouzapw#3501 chatCore extraction stack 2/13) * refactor(chatCore): extrai emitOutputStyleTelemetry (diegosouzapw#3501) (diegosouzapw#4811) Integrated into release/v3.8.36 (diegosouzapw#3501 chatCore extraction stack 3/13) * refactor(chatCore): extrai writeCompressionAnalytics (bloco analytics completo, diegosouzapw#3501) (diegosouzapw#4817) Integrated into release/v3.8.36 (diegosouzapw#3501 chatCore extraction stack 4/13) * refactor(chatCore): extrai runPluginOnRequestHook (diegosouzapw#3501) (diegosouzapw#4827) Integrated into release/v3.8.36 (diegosouzapw#3501 chatCore extraction stack 5/13) * refactor(chatCore): extrai applyClientUsageBuffer (buffer/estimate de usage non-streaming, diegosouzapw#3501) (diegosouzapw#4832) Integrated into release/v3.8.36 (diegosouzapw#3501 chatCore extraction stack 6/13) * refactor(chatCore): extrai buildPostCallGuardrailContext (contexto guardrail post-call, diegosouzapw#3501) (diegosouzapw#4831) Integrated into release/v3.8.36 (diegosouzapw#3501 chatCore extraction stack 7/13) * refactor(chatCore): extrai storeSemanticCacheResponse (cache-store non-streaming, diegosouzapw#3501) (diegosouzapw#4828) Integrated into release/v3.8.36 (diegosouzapw#3501 chatCore extraction stack 8/13) * refactor(chatCore): extrai buildNonStreamingResponseHeaders (headers de resposta non-streaming, diegosouzapw#3501) (diegosouzapw#4835) Integrated into release/v3.8.36 (diegosouzapw#3501 chatCore extraction stack 9/13) * refactor(chatCore): extrai maybeConvertJsonBodyToSse (diegosouzapw#3089 JSON→SSE streaming, diegosouzapw#3501) (diegosouzapw#4833) Integrated into release/v3.8.36 (diegosouzapw#3501 chatCore extraction stack 10/13) * refactor(chatCore): extrai assembleStreamingResponseHeaders (headers de resposta streaming, diegosouzapw#3501) (diegosouzapw#4836) Integrated into release/v3.8.36 (diegosouzapw#3501 chatCore extraction stack 11/13) * refactor(chatCore): extrai storeStreamingSemanticCacheResponse (cache-store streaming, diegosouzapw#3501) (diegosouzapw#4829) Integrated into release/v3.8.36 (diegosouzapw#3501 chatCore extraction stack 12/13) * refactor(chatCore): extrai assembleStreamingPipeline (chain de transforms streaming, diegosouzapw#3501) (diegosouzapw#4837) Integrated into release/v3.8.36 (diegosouzapw#3501 chatCore extraction stack 13/13) * ci(quality): shift heavy validations to the PR→release fast-path (release-acceleration) (diegosouzapw#4857) * feat(quality): add check:test-runner-api gate (vitest-only dirs must use vitest API) * feat(release): reusable CHANGELOG i18n-mirror sync script * chore(ops): add prune-stale-worktrees.sh (dry-run by default) * ci(quality): run test-runner-api + docs-all + vitest + full unit suite on PR->release fast-path --------- Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * fix(quota): cota exclusiva lista qtSd/ no /v1/models (diegosouzapw#4806) + limite EPSILON não bloqueia (diegosouzapw#4830) Integrated into release/v3.8.36 — quota-exclusive qtSd/ listing (diegosouzapw#4806) + EPSILON placeholder no longer blocks; rebuilt from stale base (3 defining commits cherry-picked clean over release tip) * feat(sse): add Google Flow video-generation provider (diegosouzapw#4569) (diegosouzapw#4769) Integrated into release/v3.8.36 — Google Flow video-generation provider (diegosouzapw#4569), release-green validated (typecheck + 21 tests + file-size) * fix(api): auth on compression run-telemetry + document OMNIROUTE_EVAL_CREDENTIALS (diegosouzapw#4694, diegosouzapw#4720) (diegosouzapw#4796) Integrated into release/v3.8.36 — auth on compression run-telemetry + OMNIROUTE_EVAL_CREDENTIALS doc, release-green validated (typecheck + 3 tests + env-doc-sync) * fix(translator): strip top-level client_metadata on the OpenAI passthrough (port from 9router#1157) (diegosouzapw#4624) Integrated into release/v3.8.36 — port (rebuilt from stale base; defining commit cherry-picked clean over release tip, release-green validated) * fix(translator): normalize `developer` role to `system` for OpenAI-format providers (diegosouzapw#4625) Integrated into release/v3.8.36 — port (rebuilt from stale base; defining commit cherry-picked clean over release tip, release-green validated) * fix(translator): emit </think> close marker for Anthropic thinking blocks (diegosouzapw#4633) Integrated into release/v3.8.36 — port (rebuilt from stale base; defining commit cherry-picked clean over release tip, release-green validated) * fix(translator): normalize tools to Anthropic-native shape for non-Anthropic providers (diegosouzapw#4650) Integrated into release/v3.8.36 — port (rebuilt from stale base; defining commit cherry-picked clean over release tip, release-green validated) * fix(gemini): preserve `pattern` in antigravity tool schema sanitizer (diegosouzapw#4651) Integrated into release/v3.8.36 — port (rebuilt from stale base; defining commit cherry-picked clean over release tip, release-green validated) * fix(perplexity): validate API keys via /v1/models endpoint (diegosouzapw#4654) Integrated into release/v3.8.36 — port (rebuilt from stale base; defining commit cherry-picked clean over release tip, release-green validated) * fix(image): prevent compatible nodes from shadowing provider aliases (diegosouzapw#4656) Integrated into release/v3.8.36 — port (rebuilt from stale base; defining commit cherry-picked clean over release tip, release-green validated) * fix(cli-tools): tolerate JSONC (comments, trailing commas) in tool settings (diegosouzapw#4659) Integrated into release/v3.8.36 — port (rebuilt from stale base; defining commit cherry-picked clean over release tip, release-green validated) * fix(security): validate kiro region to prevent SSRF (GHSA-6mwv-4mrm-5p3m) (diegosouzapw#4629) Integrated into release/v3.8.36 — kiro region SSRF guard (GHSA-6mwv-4mrm-5p3m), port rebuilt clean over release tip * fix(cli): harden the systray2 tray runtime (port of 9router#1080) (diegosouzapw#4628) Integrated into release/v3.8.36 — port rebuilt clean over release tip, release-green validated * fix(test): validate anthropic-compatible connections via POST /v1/messages (diegosouzapw#4657) Integrated into release/v3.8.36 — anthropic-compat validation via POST /v1/messages (port 584cf66a), rebuilt clean + baseline; release-green * fix(executors): strip params unsupported by the target provider/model (diegosouzapw#4658) Integrated into release/v3.8.36 — port rebuilt clean over release tip, release-green validated * fix(claude-oauth): respect 429 backoff on usage endpoint to reduce spam (diegosouzapw#4655) Integrated into release/v3.8.36 — port rebuilt clean over release tip, release-green validated * feat(api/v1): include alias-backed models in /v1/models listing (diegosouzapw#4630) Integrated into release/v3.8.36 — port rebuilt clean over release tip, release-green validated * chore(quality): rebaseline catalog.ts 1574->1577 (diegosouzapw#4630 aliases sobre quota-exclusive da release) (diegosouzapw#4879) rebaseline * feat(compression): Kiro/CodeWhisperer tool-result compression engine (diegosouzapw#4635) Integrated into release/v3.8.36 — port rebuilt clean, release-green * fix(security): don't trust loopback socket as local when behind reverse proxy (diegosouzapw#4632) Integrated into release/v3.8.36 — port rebuilt clean, release-green * fix(opencode): preserve DeepSeek reasoning content in streamed responses (diegosouzapw#4631) Integrated into release/v3.8.36 — DeepSeek reasoning_content injection (port diegosouzapw#1099); release-green * fix(copilot,antigravity): cap maxOutputTokens at 16384 to stop "Invalid Argument" 400 (diegosouzapw#4636) Integrated into release/v3.8.36 — cap maxOutputTokens 16384 antigravity (port diegosouzapw#779); release-green * fix(dashboard): show custom vision models in LLM selector (diegosouzapw#4653) Integrated into release/v3.8.36 — custom vision models in LLM selector (port 5e5e78d3); release-green * fix(claude): omit adaptive thinking + output_config.effort for haiku (diegosouzapw#4661) Integrated into release/v3.8.36 — haiku adaptive-thinking omit (port); release-green * feat(provider): CodeBuddy CN (copilot.tencent.com) — full stack (diegosouzapw#4664) Integrated into release/v3.8.36 — CodeBuddy CN provider (port efd20be8); usage.ts import + public-creds allowlist line reconciled; release-green * feat(combo): Fusion strategy — parallel panel + judge synthesis (16th strategy) (diegosouzapw#4652) Integrated into release/v3.8.36 — Fusion combo strategy (16th, port 87e5c1c6); combo.ts baseline reconciled; release-green * feat(proxy-pool): Deno Deploy relays + group action buttons (diegosouzapw#4643) Integrated into release/v3.8.36 — Deno Deploy relays (port diegosouzapw#1437); proxies.ts baseline reconciled + env docs restored; release-green * fix(security): pin image fetch DNS resolution to prevent SSRF rebinding (GHSA-cmhj-wh2f-9cgx) (diegosouzapw#4634) Integrated into release/v3.8.36 — pin DNS for image fetch SSRF rebinding guard (GHSA-cmhj-wh2f-9cgx, port c7d07448); caller DNS stubs + test-file baseline reconciled; release-green * fix(github): route Copilot Codex models to /responses (port from 9router#102) (diegosouzapw#4626) Integrated into release/v3.8.36 — route Copilot Codex models to /responses (port diegosouzapw#102); release-green * fix(copilot): never route Gemini/Claude variants to /responses (chat-completions only) (diegosouzapw#4627) Integrated into release/v3.8.36 — never route Gemini/Claude to /responses (port diegosouzapw#1536); fused with diegosouzapw#4626 codex routing via supportsResponsesEndpoint gate; release-green * docs(ops): add canonical incident response runbook (diegosouzapw#4868) Integrated into release/v3.8.36 * docs(perf): add per-endpoint p50/p95/p99 latency + cost budgets (diegosouzapw#4867) Integrated into release/v3.8.36 * fix(proxy): fan out direct dispatcher streams (diegosouzapw#4803) Integrated into release/v3.8.36 * fix(antigravity): exclude standard Gemini rate limit message from quota exhaustion keywords (diegosouzapw#4810) Integrated into release/v3.8.36 * fix(sse): skip third-party tool-name cloak for Anthropic server tools (diegosouzapw#4808) Integrated into release/v3.8.36 * fix(install): make transformers optional for CUDA-host installs (diegosouzapw#4807) Integrated into release/v3.8.36 * fix(combo): propagate selected connection ID to fallback error responses for correct model lockout (diegosouzapw#4809) Integrated into release/v3.8.36 * fix db storage tuning settings (diegosouzapw#4834) Integrated into release/v3.8.36 * fix(sse): drop ccp pin when pinned provider is durably unhealthy (failover + anti-flap) (diegosouzapw#4864) Integrated into release/v3.8.36 * fix(claude): skip mcp__ tool-name cloak + guard missing connectionId (diegosouzapw#4861) Integrated into release/v3.8.36 * chore(quality): reconcile env-doc + file-size base-reds in release/v3.8.36 (diegosouzapw#4886) - env-doc-sync: document PIN_DROP_BACKOFF_LEVEL / PIN_DROP_GRACE_MS (added by the ccp-pin health gate diegosouzapw#4864) in .env.example + ENVIRONMENT.md. - file-size: rebaseline image-generation-handler.test.ts 1996 -> 2019 to its actual size (pre-existing drift). Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * fix(codex): drop non-standard codex.* events that break responses.stream (env-gated, diegosouzapw#4602) (diegosouzapw#4715) Integrated into release/v3.8.36 * feat(routing): honor X-Route-Model header to override body.model (diegosouzapw#4863) Integrated into release/v3.8.36 * feat(live-ws): allow non-loopback clients via LIVE_WS_ALLOWED_HOSTS (closes diegosouzapw#4873) (diegosouzapw#4877) Integrated into release/v3.8.36 (live-ws + combo-api commits; Tailscale CGNAT commit held pending opt-in/opt-out decision) * chore(claude,codex): bump pinned CLI identity — Claude 2.1.158→2.1.187, Codex 0.132.0→0.142.0 (diegosouzapw#4883) Integrated into release/v3.8.36 * fix(security): SSRF allowlist bypass via x-relay-path nos relays Deno/Vercel (diegosouzapw#4899) Integrated into release/v3.8.36 * feat(quota): recuperação proativa de conexões em cooldown (cron heal) [Fase 3 #8] (diegosouzapw#4900) Integrated into release/v3.8.36 * fix(quota): policy inválida não vaza allow + guard connectionIds vazio [Fase 3 #10] (diegosouzapw#4901) Integrated into release/v3.8.36 * feat(quota): saturação real do Claude no fair-share via /api/oauth/usage (diegosouzapw#4885) Integrated into release/v3.8.36 * chore(dashboard): rename Qoder display label from "Qoder AI" to "Qoder" (diegosouzapw#4733) Integrated into release/v3.8.36 * fix(ci): include coverage/lcov.info in coverage-report artifact for SonarQube (diegosouzapw#4670) Integrated into release/v3.8.36 * fix(cli): bump better-sqlite3 runtime pin to 12.10.1 for Node 26 (diegosouzapw#4685) Integrated into release/v3.8.36 * docs: clarify Kiro is ~50 credits/month per account, not unlimited (diegosouzapw#4690) Integrated into release/v3.8.36 * docs(agentbridge): document Electron NODE_EXTRA_CA_CERTS, real model IDs, identity caveat (diegosouzapw#4718) Integrated into release/v3.8.36 * docs(ops): document the release-green family (green-prs, check:release-green, babysit, nightly) (diegosouzapw#4679) Integrated into release/v3.8.36 * fix(translator): replay reasoning_content on plain Xiaomi MiMo turns (port from 9router#1321) (diegosouzapw#4639) Integrated into release/v3.8.36 * feat(opencode-go): advertise glm-5.2 and kimi-k2.7-code (align with official Go endpoints) (diegosouzapw#4711) Integrated into release/v3.8.36 * feat(db): track API endpoint dimension on usage_history (diegosouzapw#4676) Integrated into release/v3.8.36 (migration renumbered 103→105; endpoint plumbed through extracted usage-stats helpers) * fix(cli): SIGKILL systray child PID before IPC close to avoid macOS NSStatusItem orphan (diegosouzapw#4732) Integrated into release/v3.8.36 * feat(proxy-pool): Cloudflare Workers proxy deployer + pool integration (diegosouzapw#4640) Integrated into release/v3.8.36 (relay type added to RELAY_TYPES set; dropdown UX preserved + Cloudflare item added; proxies.ts file-size rebaselined 1057→1060) * chore(quality): conserta base-red de release/v3.8.36 (gates + 7 testes + build MDX) (diegosouzapw#4915) A base tinha base-red sistêmica herdada de PRs de outras sessões, bloqueando TODOS os PRs do ciclo (o TIA roda a suíte full em fail-safe p/ diffs hub). 4 Fast Quality Gates: - test-discovery (diegosouzapw#4877): live-server-allowlist.test.ts em tests/unit/server/ (não-coletado) + vitest → nunca rodava. Convertido p/ node:test em tests/unit/security/. - any-budget:t11 (diegosouzapw#4664): 3 explicit-any em tokenRefresh.ts tipados (sem crescer file-size). - docs-symbols (diegosouzapw#4868): rotas inexistentes → /api/system/version e PUT /api/providers/{id} {isActive:false}. - docs-all fabricated-claim (diegosouzapw#4868 + diegosouzapw#4718): 5 bin/*.sh reais criados (rollback, snapshot-data, restore-data, restore-policies, cold-start-bench) + _ops-common.sh (snapshot VACUUM INTO, guards de confirmação/TTY, testes de contrato); NODE_EXTRA_CA_CERTS (env de runtime Node) na allowlist do checker. 7 testes unit base-red (de features alheias à quota): - oauth-providers-config (diegosouzapw#4664): teste alinhado ao provider codebuddy-cn do registry. - antigravity-model-aliases (diegosouzapw#4636): maxOutputTokens esperado 32769→16384 (cap intencional). - provider-request-capture diegosouzapw#4091 (diegosouzapw#4861): exemplo do teste trocado de mcp__ (que diegosouzapw#4861 isenta de cloak por causa dos 400s de assimetria de histórico) para um tool de terceiro cloakável — preserva o invariante de diegosouzapw#4091 SEM reverter diegosouzapw#4861. - combo-error-response: convertido de vitest p/ node:test (era coletado pelo glob node:test e crashava); api/** e server/** removidos do vitest.config (config morta). Build MDX (dast-smoke, diegosouzapw#4679): - docs/ops/RELEASE_GREEN.md não tinha frontmatter `title` → fumadocs-mdx rejeitava no webpack compile ("invalid frontmatter: title expected string"), quebrando o next build (e o deploy). Frontmatter title adicionado (único doc do collection sem ele). 17/17 Fast Quality Gates + suíte unit completa (17737 testes, 0 fail) + vitest verdes localmente. Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * feat(quota): saturação proativa por headers de tokens (universal) [Fase 3 #2] (diegosouzapw#4907) storeRateLimitHeaders só capturava os headers de REQUESTS (RPM/min), que não refletem a pressão de TOKENS. Agora também parseia os headers de tokens (em toda resposta, sucesso também) para throttle proativo antes do 429: - Anthropic: anthropic-ratelimit-tokens-{limit,remaining,reset} (+ input/output), RFC3339. - OpenAI: x-ratelimit-{limit,remaining,reset}-tokens, reset em duração (6m0s). saturation = 1 − remaining/limit; resetAt normalizado a epoch (parse de duração ReDoS-safe). getTokenHeaderSaturation por (provider, connectionId). fetchGeneric- Saturation passa a usar esse sinal (complementa o oauth/usage do #1, que segue primário p/ Claude). Fail-open, cache mantido, request-path inalterado. 16 testes novos + regressão (oauth/usage #1 8/8, signals 6/6) = 30/30; typecheck:core + eslint limpos. Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * feat(quota): estratégia de combo "headroom" — seleção por folga de cota [Fase 3 #4] (diegosouzapw#4908) Nova estratégia de roteamento que escolhe a conexão com MAIS folga de plano: headroom = 1 − max(util_5h, util_7d) (técnica do dario), via getSaturation (melhorado p/ Claude no #1). Proativo em vez de só fill-first reativo. - Helper PURO headroomRanking.ts (computeHeadroom + rankByHeadroom; saturação injetada, não-mutante, tie-break estável, fail-open). - Orderer async em combo/quotaStrategies.ts (reusa a maquinaria reset-aware de expansão de conexões + concorrência limitada; seam injetável). - Registrada como "headroom" em routingStrategies (combo-only); fill-first segue default — nenhuma estratégia existente tocada. - baseline file-size combo.ts 3168->3180 (só +12L de dispatch; lógica fora do god-file). 16 testes novos + combo-strategies 15/15 = 31/31; typecheck:core + eslint + file-size limpos. Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * feat(quota): cap per-(key,model) — quota_allocation_model_caps [Fase 3 #7] (diegosouzapw#4927) * feat(quota): cap per-(key,model) com tabela quota_allocation_model_caps [Fase 3 #7] Fecha o buraco onde uma API key pode drenar o pool inteiro consumindo um único modelo. Tabela nova: quota_allocation_model_caps(pool_id, api_key_id, model, cap_value, cap_unit) PK composta (pool_id, api_key_id, model). cap_unit alinhado ao QuotaUnit existente. Comportamento: keyA acima do cap para modelo M → bloqueada somente em M; ainda permitida em qualquer outro modelo no mesmo pool. Cap <= EPSILON → ignorado (seed). Consumo por-(key,model) usa bucket segregado no quota_consumption existente (poolId mangled ':model:<model>') com window fixa 'hourly'; nenhuma nova tabela ou método de store necessário. Módulo novo: src/lib/db/quotaModelCaps.ts (getModelCap/setModelCap/deleteModelCap/listModelCaps) enforce.ts ganha o pre-check em enforceQuotaShare + recording em recordConsumption. EnforceInput e RecordConsumptionInput ganham model?: string (backward-compatible). localDb.ts re-exporta os 4 helpers (Hard Rule #2). TDD: tests/unit/quota-per-key-model.test.ts — 4 cenários (bloqueia em M, permite em M2, sem cap → sem bloqueio, EPSILON → ignorado). Todos os gates de qualidade passam. * feat(quota): plumba model resolvido no hot path para ativar o per-(key,model) cap [Fase 3 #7] A tabela/enforce do commit anterior estavam INERTES: o hot path não passava `model` ao enforce nem ao record, então nenhum model-cap disparava em produção. Plumbagem (model resolvido = mesma var usada no log/roteamento, pós background-redirect/alias): - chatCore.ts: enforceQuotaShare ganha `model`; scheduleQuotaShareConsumption recebe `model`. - chatCore/quotaShareConsumption.ts: threade `model` no RecordConsumptionInput (non-streaming). - spendRecorder.ts: recordStreamingConsumption já recebia `model` — agora o coloca no RecordConsumptionInput (streaming accrue por-modelo). - embeddings.ts: enforce + record ganham `model`. Namespace do cap = id do modelo RESOLVIDO (o mesmo de modelForScope/pendingScope/getUnsupportedParams), não o requestedModel cru nem o finalModelToUpstream (sem prefixo de provider). Operador configura o cap contra esse id. `model || undefined` em todos os pontos: vazio/null → check pulado (fail-safe, zero latência — só um campo no objeto). Teste de integração novo (tests/unit/quota-per-key-model-hotpath.test.ts): prova end-to-end que N consumos via scheduleQuotaShareConsumption({model}) → enforceQuotaShare({model}) bloqueia, e que outro modelo no mesmo pool ainda passa; + guard de que enforce SEM model nunca dispara model-cap. --------- Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * feat(quota): session stickiness p/ integridade de prompt-cache [Fase 3 #5] (diegosouzapw#4929) * feat(quota): session stickiness p/ integridade de prompt-cache [Fase 3 #5] Adiciona stickiness de sessão ao roteamento de combo: uma conversa multi-turno é roteada para a MESMA conexão enquanto ela permanecer saudável, evitando a perda do prompt-cache do provider (custo 5-10× sem stickiness, efeito conhecido no dario/clewdr). Implementação: - `open-sse/services/combo/sessionStickiness.ts` (novo, <800 linhas): mapa em memória (messageHash → connectionId) com TTL 15 min + cap 500 entradas; `applySessionStickiness` promove a conexão sticky ao índice 0 dos targets ordenados pelo strategy, guardado por `computeHeadroom > 0.15` (threshold); quando saturada (headroom ≤ 0.15), o binding é limpo e a seleção normal reage. Hash da sessão = SHA-256 dos primeiros chars da 1ª mensagem user → 16 hex chars. Seam de teste: `__setStickinessHeadroomFetcherForTests`. - `open-sse/services/combo.ts`: import + 2 pontos de integração (pré-eval-scores e pós-success), dentro do orçamento congelado de 3180 linhas. - `tests/unit/combo-session-stickiness.test.ts`: 19 testes node:test + assert/strict, todos via injeção de fetcher (zero rede/DB). Threshold 0.15: conexão a >85% de utilização está a um burst de rate-limit; o benefício de cache não compensa manter-se numa conexão degradada. Valor alinhado com a zona de soft-penalty do restante do engine de quota-share. * test(combo): isola combo-strategies da session stickiness (#5) selectedConnectionFor reusa o mesmo body, então o sticky map (#5) fixava a connection após a 1ª chamada e quebrava o round-robin tie-break do teste reset-aware. Limpa o sticky map no início da helper — a stickiness tem suíte própria (combo-session-stickiness). Sem enfraquecer asserts. --------- Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * feat(quota): buckets multi-janela por conexão (5h/7d/per-model) [Fase 3 #3] (diegosouzapw#4928) Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * refactor(providers): decompõe catálogo providers.ts em módulos de dados (godfile sweep, diegosouzapw#3501) (diegosouzapw#4917) Integrado em release/v3.8.36 (godfile sweep providers.ts, diegosouzapw#3501) * refactor(pricing): decompõe pricing.ts em shared-tiers + DEFAULT_PRICING particionado (godfile sweep, diegosouzapw#3501) (diegosouzapw#4918) Integrado em release/v3.8.36 (godfile sweep pricing.ts, diegosouzapw#3501) * refactor(api): extrai camada-folha pura de validation.ts (URL/headers/transport) (diegosouzapw#4921) Integrado em release/v3.8.36 (validation.ts split fatia 1 — leaf layer) * refactor(api): extrai validators web-cookie + Meta AI de validation.ts (diegosouzapw#4922) Integrado em release/v3.8.36 (validation.ts split fatia 2 — web-cookie + Meta AI) * refactor(api): extrai validators enterprise-cloud + probe compartilhado de validation.ts (diegosouzapw#4923) Integrado em release/v3.8.36 (validation.ts split fatia 3 — enterprise-cloud + probe) * refactor(api): extrai validators áudio/speech + misc apikey de validation.ts (diegosouzapw#4930) Integrado em release/v3.8.36 (validation.ts split fatia 4 — áudio/speech + misc apikey) * feat(quota): estratégia dedicada de quota-share (DRR + P2C in-flight + gating per-model) [Fase 3 #9] (diegosouzapw#4939) * feat(quota): estratégia dedicada de quota-share (DRR + P2C in-flight + gating per-model) [Fase 3 #9] Estratégia interna "quota-share" isolada num módulo dedicado — NÃO toca a seleção/ fair-share genérica (decisão do dono: não mexer no que já funciona). Os combos qtSd/ (quotaCombos.ts) passam de fill-first para essa strategy; combo.ts ganha só 1 branch de dispatch que delega 100% ao módulo (nenhum case existente alterado). - quotaShareStrategy.ts: gating per-model (isBucketSaturated do #3) + DRR (quantum proporcional ao weight) + P2C sobre carga in-flight. - quotaShareInflight.ts: contador in-flight com TTL/lease de 120s — fallback do decrement-on-abort sem precisar instrumentar o combo genérico. - "quota-share" registrada como strategy INTERNA (não exposta na UI). - testes de síntese (quota-combo-balancing, quota-multiprovider) alinhados: a strategy esperada dos combos qtSd/ passa de "fill-first" para "quota-share" (alinhamento ao novo comportamento intencional, não mascaramento — os 73 testes de qtSd/ seguem verdes). * test(quota-share): alinha 2 scope-guards ao godfile sweep (base-reds que bloqueavam o CI) Dois testes de "arquivo contém X" quebraram por decomposições de godfile que outras sessões mergearam no release DURANTE a validação de #9 — NÃO são regressão de #9 (que não toca validation/oauth). Alinhados ao novo layout, asserts preservados: - proxy-bypass-scope-guard diegosouzapw#3226: bypassProxyPatch foi extraído de validation.ts para validation/headers.ts (split diegosouzapw#4921–diegosouzapw#4930) → o teste lê a camada de validação. - sse-error-passthrough diegosouzapw#3324: a windsurf authHint foi extraída de providers.ts para providers/oauth.ts → o teste lê o novo local. --------- Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * refactor(api): extrai validators search + embedding/rerank de validation.ts (diegosouzapw#4932) Integrated into release/v3.8.36 * refactor(api): extrai format-validators (OpenAI/Anthropic) de validation.ts (diegosouzapw#4933) Integrated into release/v3.8.36 * refactor(db): extrai model-permission matching de db/apiKeys.ts (diegosouzapw#4936) Integrated into release/v3.8.36 * refactor(db): extrai row-parsers + tipos compartilhados de db/apiKeys.ts (diegosouzapw#4943) Integrated into release/v3.8.36 * refactor(db): extrai column-mapping (snake↔camel) de db/core.ts (diegosouzapw#4947) Integrated into release/v3.8.36 * refactor(db): extrai schema-column reconciliation de db/core.ts (diegosouzapw#4948) Integrated into release/v3.8.36 * refactor(sse): extrai scalar/format helpers de services/usage.ts (diegosouzapw#4949) Integrated into release/v3.8.36 * refactor(sse): extrai quota-core (UsageQuota + builders) de services/usage.ts (diegosouzapw#4950) Integrated into release/v3.8.36 * fix(translator): regroup parallel tool results adjacent to their assistant (diegosouzapw#4714) (diegosouzapw#4882) Integrated into release/v3.8.36 (fixes diegosouzapw#4714) * fix(qoder): exchange PAT for jt-* job token before Cosy chat (diegosouzapw#4683) (diegosouzapw#4884) Integrated into release/v3.8.36 (fixes diegosouzapw#4683) * refactor(sse): dedup fallback tool_call id helper (diegosouzapw#4736) Integrated into release/v3.8.36 * refactor(open-sse): extract safeParseJSON util, dedup tryParseJSON (diegosouzapw#4735) Integrated into release/v3.8.36 * fix(compression): eliminate ReDoS in math_inline preservation pattern (diegosouzapw#4795) (diegosouzapw#4838) Integrated into release/v3.8.36 (fixes diegosouzapw#4795) * fix(combo): fetch models dynamically from custom provider endpoints (diegosouzapw#4860) Integrated into release/v3.8.36 * feat(providers): update volcengine-ark model list with DeepSeek V4 (diegosouzapw#4905) Integrated into release/v3.8.36 * fix(translator): provider thinking compatibility (DeepSeek/Gemini) (diegosouzapw#4946) Integrated into release/v3.8.36 * feat(combo): task-aware routing strategy (diegosouzapw#4945) Integrated into release/v3.8.36 * refactor(sse): extrai a família MiniMax de services/usage.ts (diegosouzapw#4952) Integrated into release/v3.8.36 * refactor(sse): extrai a família GLM de services/usage.ts (diegosouzapw#4953) Integrated into release/v3.8.36 * refactor(sse): extrai a família Antigravity de services/usage.ts (diegosouzapw#4956) Integrated into release/v3.8.36 * fix(dashboard): show custom provider given-name instead of internal id across dashboard pages (diegosouzapw#4603) (diegosouzapw#4960) Integrated into release/v3.8.36 (fixes diegosouzapw#4603) * fix(api): evict stale in-memory rate-limit windows to stop slow heap leak (diegosouzapw#4041) (diegosouzapw#4957) Integrated into release/v3.8.36 (fixes diegosouzapw#4041) * fix(api): parse /v1/responses body once instead of 3-4x on the hot path (diegosouzapw#4041) (diegosouzapw#4958) Integrated into release/v3.8.36 (fixes diegosouzapw#4041) * fix(translator): preserve legitimate empty-string tool arguments in openai-to-claude streaming (diegosouzapw#4951) (diegosouzapw#4959) Integrated into release/v3.8.36 (fixes diegosouzapw#4951) * chore(quality): reconcile file-size baseline for diegosouzapw#4960 provider-display-name (diegosouzapw#4961) Integrated into release/v3.8.36 * fix(dashboard): restore home provider-topology card hidden by diegosouzapw#4596 default (diegosouzapw#4963) Integrated into release/v3.8.36 — restores home topology card (diegosouzapw#4596 regression) * fix(build): drop @omniroute/open-sse from optimizePackageImports (build OOM) (diegosouzapw#4968) Integrated into release/v3.8.36 — fixes build OOM (optimizePackageImports open-sse) * fix(quota): migração 107 ativa estratégia quota-share nos combos qtSd/ existentes [Fase 3 #9] (diegosouzapw#4962) Integrated into release/v3.8.36 * feat(quota): respeita max_concurrent por conexão no roteamento (diegosouzapw#4965) Integrated into release/v3.8.36 * feat(quota): combo quota-share espera cooldown curto e re-despacha (Variante A) (diegosouzapw#4967) Integrated into release/v3.8.36 * fix(quality): resolve base-reds da release — db-rules allowlist + task-aware router precedence (diegosouzapw#4973) Dois base-reds pré-existentes que reprovavam o CI da release v3.8.36 (Fast Quality Gates + Unit Tests fast-path), independentes de qualquer feature em voo: 1. check:db-rules / allowlist: os módulos db-internal caseMapping (diegosouzapw#4947) e schemaColumns (diegosouzapw#4948), extraídos de db/core.ts e importados só por ele, não estavam em INTENTIONALLY_INTERNAL. Registrados na allowlist (correção canônica — são internos legítimos, não re-exportados pelo localDb). 2. auto-strategy honra LKGP/cost (combo-routing-engine.test.ts, 2 testes): o task-aware reordering (diegosouzapw#4945, reorderByTaskWeight) roda para strategy "auto" e era aplicado DEPOIS do router explícito (selectWithStrategy: lkgp/cost), sobrescrevendo o orderedTargets[0] que o operador escolheu. Instrumentação provou: post-filter [0]=claude (LKGP) → post-task [0]=gpt-oss. Correção: quando o auto usa router explícito, preserva o [0] dele e deixa o task-aware refinar só a cauda de fallback. gpt-oss-120b PERMANECE tool-capable (não é mudança de catálogo; o model-capabilities-registry test segue verde). Validado: 121 testes (combo-routing-engine + combo-task-aware + registry) verdes, red-check confirmado, db-rules/file-size/typecheck/lint/prettier OK. Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * feat(quota): serializa concorrência por conexão no caminho quota-share (FASE 2.1) (diegosouzapw#4970) O gating de quota-share em selectQuotaShareTarget é fail-open: uma conexão at-cap só é despriorizada, nunca bloqueada. Com 1 conexão por conta de assinatura (caso comum), chamadas concorrentes ainda floodam a conta (→ 429 + cooldown) — provado live na .15: 3 chamadas concorrentes com max_concurrent=1 despacharam todas em 94ms. Adiciona um semáforo POR CONEXÃO em torno do dispatch quota-share: chamadas excedentes esperam na fila em vez de floodar (key qsconn:<connectionId>, cap = max_concurrent da conexão). Fail-open em fila saturada/timeout para nunca piorar disponibilidade. Gated por strategy===quota-share + kill-switch resilienceSettings.quotaShareConcurrencyLimit (default on; UI no ResilienceTab). Lógica extraível isolada no leaf puro combo/quotaShareConcurrency.ts (unit-testado: estabilidade da key, no-op sem cap, serialização real, fail-open). Settings + schema + UI espelham comboCooldownWait. Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * docs(resilience): document Quota-Share Concurrency Control (max_concurrent + serialization + cooldown-wait) (diegosouzapw#4980) Documents the v3.8.36 quota-share concurrency layers in RESILIENCE_GUIDE.md: per-connection max_concurrent cap, the quota-share request serialization semaphore (FASE 2.1, qsconn:<connectionId>, fail-open, kill-switch), and the combo cooldown-aware retry — so operators know how to cap a subscription account's concurrency and why the routing gate alone cannot contain a single-connection flood. Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * fix(dashboard): proxy-pool success gating, sync timestamp, opt-in Redis (diegosouzapw#4878) (diegosouzapw#4988) Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * fix(sse): fail over on 400 responses carrying rate-limit text (diegosouzapw#4976) (diegosouzapw#4986) * fix(sse): fail over on 400 responses carrying rate-limit text (diegosouzapw#4976) * chore(quality): rebaseline accountFallback.ts file-size for diegosouzapw#4976 fix --------- Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * fix(compression): stop RTK over-truncating file-read tool results (diegosouzapw#4559) (diegosouzapw#4987) * fix(compression): stop RTK over-truncating file-read tool results (diegosouzapw#4559) * chore(quality): trim diegosouzapw#4559 comment to keep rtk/index.ts within size cap --------- Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * fix(sse): honor per-account proxies and fingerprint rotation in opencode executor (diegosouzapw#4954) (diegosouzapw#4989) * fix(sse): honor per-account proxies and fingerprint rotation in opencode executor (diegosouzapw#4954) * chore(quality): rebaseline auth.ts file-size for diegosouzapw#4954 (+39: synthetic no-auth providerSpecificData hydration of fingerprints/accountProxies; irreducible credential-path wiring, covered by opencode-proxy-rotation-4954.test.ts + 159 auth/noauth regression) --------- Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * fix(sse): soft-penalize exhausted providers in auto-combo scoring (diegosouzapw#4540) (diegosouzapw#4990) * fix(sse): soft-penalize exhausted providers in auto-combo scoring (diegosouzapw#4540) * chore(quality): document STATUS_SOFT_DEPRIORITIZE_FACTOR + rebaseline combo.ts for diegosouzapw#4540 --------- Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * fix(dashboard): switch to visible filter after auto-hiding failed models in test-all (diegosouzapw#4887) (diegosouzapw#4991) * fix(dashboard): switch to visible filter after auto-hiding failed models in OAuth provider test-all (diegosouzapw#4887) * test(dashboard): move diegosouzapw#4887 test into tests/unit/ui so a CI runner collects it --------- Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * fix(pollinations): only enable jsonMode when JSON output is requested (diegosouzapw#3981) (diegosouzapw#5009) Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * fix(antigravity): default safetySettings to all-OFF for parity with native Gemini paths (diegosouzapw#5003) (diegosouzapw#5008) * fix(antigravity): default safetySettings to all-OFF for parity with native Gemini paths (diegosouzapw#5003) * docs(changelog): restore diegosouzapw#3981 pollinations entry eaten by merge --------- Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * fix(chatgpt-web): map advertised gpt-5.5/5.4-pro/5.2-pro slugs to prevent silent model substitution (diegosouzapw#4665) (diegosouzapw#5010) * fix(chatgpt-web): map advertised gpt-5.5/5.4-pro/5.2-pro slugs to prevent silent model substitution (diegosouzapw#4665) MODEL_MAP was missing the advertised catalog ids gpt-5.5, gpt-5.5-pro, gpt-5.4-pro and gpt-5.2-pro, so MODEL_MAP[model] ?? model sent the dot-form id verbatim to the ChatGPT backend-api, which silently rejected it and served the default Plus model. Map each to its dash-form slug. gpt-4-5 is already dash-form and falls through correctly, so it is intentionally left unmapped. Extends the executor MODEL_MAP test with the four ids and adds a drift guard asserting every advertised dot-form catalog id reaches the backend in dash-form (never verbatim), guarding future catalog<->map drift. file-size: tests/unit/chatgpt-web.test.ts frozen baseline 2809->2855 (+46) for the added test cases and drift-guard test; executor source unchanged in baseline. * docs(changelog): restore diegosouzapw#3981/diegosouzapw#5003 entries eaten by merge --------- Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * feat(combos): add editable per-combo description field persisted via /api/combos (diegosouzapw#5005) (diegosouzapw#5011) * feat(combos): add editable per-combo description field persisted via /api/combos (diegosouzapw#5005) * docs(changelog): restore diegosouzapw#3981/diegosouzapw#5003/diegosouzapw#4665 entries eaten by merge --------- Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * Fix Ollama Cloud max reasoning effort (diegosouzapw#4993) Integrated into release/v3.8.36 * fix(copilot): replace execSync with execFile to prevent command injection (diegosouzapw#5024) Integrated into release/v3.8.36 * fix(plugin): auth.json dual-key fallback for auto-prefix migration (diegosouzapw#5027) Integrated into release/v3.8.36 * feat(endpoint): per-endpoint custom system prompt injection (diegosouzapw#5022) Integrated into release/v3.8.36 * fix(headroom): translate openai-responses input through OpenAI for compression (diegosouzapw#5023) Integrated into release/v3.8.36 * docs(changelog): add entries for diegosouzapw#4993, diegosouzapw#5024, diegosouzapw#5027 (release notes credit) * fix(api): stop /api/system/env/repair 500 on packaged install (diegosouzapw#5006) (diegosouzapw#5028) * fix(api): stop /api/system/env/repair 500 on packaged install — lazy createRequire in sync-env.mjs (diegosouzapw#5006) scripts/dev/sync-env.mjs ran createRequire(import.meta.url) at module top-level. When webpack bundles it into the standalone env-repair route, import.meta.url is frozen to the build-machine path (file:///home/runner/...) and createRequire throws during module evaluation, so the whole route module fails to load and every GET returns HTTP 500 — breaking the onboarding wizard on packaged/global installs. - Move createRequire into the guarded better-sqlite3 block (only place that needs it); a bad import.meta.url now returns the safe default. - resolveRootDir() falls back to process.cwd() when fileURLToPath throws. - route.ts passes an explicit rootDir (process.cwd()) so the helper never derives the root from the frozen import.meta.url, matching the .env target used by createEnvBackup(). - Regression guard: assert sync-env.mjs has no top-level createRequire + getEnvSyncPlan(oauth) works with explicit rootDir without throwing. * docs(changelog): restore diegosouzapw#4993/diegosouzapw#5023/diegosouzapw#5024/diegosouzapw#5027 + custom-system-prompt/headroom entries eaten by release merge * chore(quality): rebaseline 3 inherited base-reds from release merge Files NOT touched by this PR — grew on release/v3.8.36 via --admin merges and inherited here through 'git merge origin/release': - open-sse/executors/base.ts 1414->1416 (diegosouzapw#4993 Ollama Cloud max-effort) - src/lib/db/settings.ts 1149->1151 (diegosouzapw#5023 custom system prompt) - src/app/(dashboard)/.../endpoint/EndpointPageClient.tsx 2570->2612 (custom system prompt UI) * chore(release): finalize v3.8.36 CHANGELOG + docs (2026-06-25) --------- Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> Co-authored-by: KooshaPari <42529354+KooshaPari@users.noreply.github.com> Co-authored-by: Makcim Ivanov <makcimbx@gmail.com> Co-authored-by: Chewji <126886556+Chewji9875@users.noreply.github.com> Co-authored-by: Anton <39598727+NomenAK@users.noreply.github.com> Co-authored-by: Demiurge The Single <megamen932@gmail.com> Co-authored-by: Randi <55005611+rdself@users.noreply.github.com> Co-authored-by: Éder Costa <eder.almeida.costa@gmail.com> Co-authored-by: Jefferson Felizardo <jeffer1312@gmail.com> Co-authored-by: Arthur Bodera <abodera@gmail.com> Co-authored-by: Hamsa_M <116961508+hamsa0x7@users.noreply.github.com> Co-authored-by: Hernan Javier Ardila Sanchez <hjasgr@gmail.com>
TechNickAI
pushed a commit
that referenced
this pull request
Jul 19, 2026
* chore(release): open v3.8.38 development cycle * fix(executors): strip client_metadata for cerebras and mistral (diegosouzapw#4727) Integrated into release/v3.8.38 (leva 5) * fix(codebuddy): only send reasoning params when client requests reasoning (diegosouzapw#5019) Integrated into release/v3.8.38 (leva 5) * fix(sse): keep streaming for forceStream providers when client requests JSON (diegosouzapw#5021) Integrated into release/v3.8.38 (leva 5) * fix(sse): guard non-JSON SSE lines and duplicate [DONE] (diegosouzapw#4937) Integrated into release/v3.8.38 (leva 5) * feat(blackbox): refresh provider model catalog (diegosouzapw#4935) Integrated into release/v3.8.38 (leva 5) * fix(sse): dedupe case-variant Anthropic version/beta headers (diegosouzapw#4846) Integrated into release/v3.8.38 (leva 5) * feat(sse): Kiro inline <thinking> stream splitter (diegosouzapw#4911) Integrated into release/v3.8.38 (leva 5) * feat(cursor): parse Composer DeepSeek-style inline tool calls (diegosouzapw#4912) Integrated into release/v3.8.38 (leva 5) * feat(proxy): auth-less host:port batch import (diegosouzapw#4938) Integrated into release/v3.8.38 (leva 5) * fix(oauth): support Kiro IDC (organization) token import (diegosouzapw#4944) Integrated into release/v3.8.38 (leva 5) * fix(translator): preserve cache_control for DashScope OpenAI-compat providers (port from 9router#2069) (diegosouzapw#5013) Integrated into release/v3.8.38 (leva 5) * fix(tts): resolve Gemini TTS models from catalog (diegosouzapw#4934) Integrated into release/v3.8.38 (leva 5) * fix(sse): don't cool down the connection on a self-inflicted upstream timeout (504) (diegosouzapw#5064) Integrated into release/v3.8.38 (leva 5) * fix(sse): robust Anthropic /v1/messages streaming — real ping keepalive + client-disconnect guard (diegosouzapw#5063) Integrated into release/v3.8.38 (leva 5) * feat(video): add Alibaba DashScope (wan2.7-t2v) provider (diegosouzapw#5051) Integrated into release/v3.8.38 (leva 5) * fix: preserve model hidden flags (isHidden) across model sync (diegosouzapw#5086) Integrated into release/v3.8.38 (leva 5) * fix(models): derive model discovery config from registry modelsUrl (diegosouzapw#5087) Integrated into release/v3.8.38 (leva 5) * fix(compression): replace fileURLToPath(import.meta.url) with runtime anchors for standalone bundle (diegosouzapw#5089) Integrated into release/v3.8.38 (leva 5) * feat(cc): add summarized thinking display toggle (diegosouzapw#5055) Integrated into release/v3.8.38 (leva 5) * Harden selected API error responses (diegosouzapw#5032) Integrated into release/v3.8.38 (leva 5) * chore(quality): rebaseline file-size for leva 5 PR batch drift 6 frozen files grew from merged leva-5 PRs (cursor diegosouzapw#4912, kiro diegosouzapw#4911, videoGeneration diegosouzapw#5051, default diegosouzapw#4727, base diegosouzapw#4846, chat diegosouzapw#5064); all covered by per-PR tests. See _rebaseline_2026_06_26_leva5 in the baseline. * feat(compression): compression playground (Play + Compare tabs) in the studio (diegosouzapw#5080) Integrated into release/v3.8.38 * fix(combo): fail over on empty-content 502 instead of exhausting the provider (diegosouzapw#5085) (diegosouzapw#5104) * fix(dashboard): surface detailed credential-validation error in add-connection modal (diegosouzapw#5088) (diegosouzapw#5106) * feat(providers): allow local/private provider URLs by default with scoped metadata-safe guard (diegosouzapw#5066) (diegosouzapw#5107) * fix(diagnostics): treat non-streaming Claude messages shape as valid output (diegosouzapw#5108) (diegosouzapw#5116) * fix(db): translate pt-BR SQLite driver-fallback log lines to English (diegosouzapw#5103) (diegosouzapw#5115) * fix(sse): repair release base-reds — malformed-response false positives + header casing + stale tests (diegosouzapw#5117) Repairs the release/v3.8.38 base-reds; unblocks diegosouzapw#5078. * chore(quality): rebaseline file-size for responseSanitizer (diegosouzapw#5117) + AddApiKeyModal drift * fix(translator): forward image tool_result blocks as image_url (diegosouzapw#5100) Base-reds fixed (diegosouzapw#5117); image tool_result→image_url. Integrated into release/v3.8.38. * fix(responses): default text.format for openai-compatible responses providers (diegosouzapw#5101) Base-reds fixed (diegosouzapw#5117); default text.format + file-size rebaseline. Integrated into release/v3.8.38. * feat(dashboard): expose Fusion judgeModel + fusionTuning in the combo editor (diegosouzapw#5074) Base-reds fixed (diegosouzapw#5117); Fusion editor + file-size rebaseline. Integrated into release/v3.8.38. * feat(quota): add opt-in Codex/Claude auto-ping keepalive (diegosouzapw#5102) Base-reds fixed (diegosouzapw#5117); auto-ping keepalive + file-size rebaseline. Integrated into release/v3.8.38. * test(release): relocate 2 orphan test files into the collected flat tests/unit dir (diegosouzapw#5120) Unblocks Lint (test-discovery) on diegosouzapw#5078. Integrated into release/v3.8.38. * fix(translator): preserve reasoning-replay reasoning_content + repair 3 release-green test reds (diegosouzapw#5122) Repairs 3 release-green test reds + test-masking; unblocks diegosouzapw#5078. * test(golden): redact live Node version from provider translate-path snapshot (diegosouzapw#5125) Final golden unblock for diegosouzapw#5078. * test(golden): redact OmniRoute app version from translate-path snapshot (diegosouzapw#5126) Coverage shard golden unblock for diegosouzapw#5078. * Ignore disconnect races during in-band stream error handling (diegosouzapw#5007) Integrated into release/v3.8.38 * Track final connection IDs in failover logs (diegosouzapw#5016) Integrated into release/v3.8.38 * fix(sse): convert Gemini body to OpenAI format in antigravity MITM handler (diegosouzapw#4845) Integrated into release/v3.8.38 (rebased on tip, CHANGELOG re-injected) * feat(providers): add ZenMux Free session-cookie provider (diegosouzapw#5105) Integrated into release/v3.8.38 (rebased on tip, CHANGELOG re-injected) * feat(dashboard): click-to-edit model alias in provider page (diegosouzapw#5119) Integrated into release/v3.8.38 (rebased on tip, i18n scope verified, CHANGELOG re-injected) * feat(mcp): web-session robustness — cookie dedup (PR6) + browser-pool observability (PR7) (diegosouzapw#3368) (diegosouzapw#5121) Integrated into release/v3.8.38 (rebased on tip; cookie-dedup branch extracted to findExistingCookieConnection helper → complexity-neutral; CHANGELOG added) * fix(usage): dedupe request-usage logging and debounce stats (diegosouzapw#4940) Integrated into release/v3.8.38 (rebased on tip; DB-handle hang was stale-base artifact — resetDbInstance already closes the handle, test green 5/5; file-size drift consolidated at release; CHANGELOG re-injected) * fix(dashboard): key model visibility toggle on canonical providerId (diegosouzapw#5091) Integrated into release/v3.8.38 (retargeted main→release; .tsx visibility-key test green 2/2) * chore(deps): bump actions/cache from 5.0.5 to 6.0.0 (diegosouzapw#5112) Integrated into release/v3.8.38 (retargeted main→release; workflow-only actions/cache bump — unit failures were stale main base-reds) * fix(streaming): harden long OpenAI-compatible SSE streams (diegosouzapw#5124) Integrated into release/v3.8.38 (rebased on tip; streamHandler conflict with diegosouzapw#5007 disconnect-guard resolved — both coexist, stream-handler 22/22 green) * feat: Add Grok Build (xAI) provider with OAuth import-token flow (diegosouzapw#5020) Integrated into release/v3.8.38 (rebased on tip; Hard Rule #11 fix — Grok public client_id now via resolvePublicCred(grok_id), 3 literals removed; grok-oauth 7/7 + check:public-creds green) * feat(providers): add Factory (factory.ai) as a subscription gateway provider (diegosouzapw#5065) Integrated into release/v3.8.38 (rebased on tip; added factory registry test for PR Test Policy + fixed check:env-doc-sync phantom FACTORY_API_KEY; factory loads in PROVIDERS, no Zod issue — that flag was a false positive) * chore(test): reconcile golden snapshot + apikey count for new providers diegosouzapw#5020 (grok-cli), diegosouzapw#5065 (factory), diegosouzapw#5105 (zenmux-free) added providers but did not regenerate tests/snapshots/provider/translate-path.json (now +3 entries) nor bump the APIKEY_PROVIDERS count (159->160 for the factory gateway). Test-only reconciliation; no production change. * fix(resilience): harden quota and model lockout edge cases (diegosouzapw#5093) Integrated into release/v3.8.38 (rebased on tip). TRUST-BUT-VERIFY: dropped the PR's 0dd7df6 'fix unit gates' commit which reverted diegosouzapw#5122 reasoning-replay (preserveReasoningContent) + re-introduced diegosouzapw#4849 O(n^2) growth, and restored 5 tests it had realigned. Kept only the 3 declared resilience fixes (quota cutoff guard, gemini MIME, model-lockout maxCooldownMs); 23/23 green. * Hydrate quota cache and scope auto combo candidates (diegosouzapw#5015) Integrated into release/v3.8.38 (rebased on tip). Kept core quota-cache hydration + auto-combo candidate scoping + combos UI; dropped out-of-scope toolCloaking refactor (conflicted with diegosouzapw#4813 stripEnumDescriptions — took tip) and the unrelated sse-auth test split. Added quota-cache-hydrate-5015 regression test (Rule diegosouzapw#18); combo-account-allowlist 8/8 + hydration 2/2 green. * chore(quality): reconcile complexity + file-size baselines for v3.8.38 owner-PR batch complexity 1972->1978 (+6) and file-size providers.ts 1093->1107 / usageHistory.ts 934->983 — drift from the /review-prs merge batch (diegosouzapw#4845/diegosouzapw#5105/diegosouzapw#5020/diegosouzapw#4940/diegosouzapw#5093/ diegosouzapw#5015 + diegosouzapw#5121 cookie-dedup helper extraction). check:complexity/check:file-size do not run on the PR->release fast-path, so the branch accrued unmeasured; all legit feature/fix growth, not regression. See per-key justifications in each baseline. * fix(security): exact-host Anthropic baseUrl check (CodeQL js/incomplete-url-substring-sanitization diegosouzapw#674) (diegosouzapw#5130) The anthropic-compatible Bearer-fallback gate decided whether a configured baseUrl targeted the official api.anthropic.com host via a substring `.includes("api.anthropic.com")`. A look-alike upstream such as `https://api.anthropic.com.evil.test` or `https://evil.test/?x=api.anthropic.com` matched the substring and was wrongly treated as official, suppressing the Bearer fallback meant for third-party gateways (CodeQL diegosouzapw#674, js/incomplete-url-substring-sanitization, high). Replace the substring test with an exported `isOfficialAnthropicBaseUrl()` helper that parses the URL and compares the hostname for exact equality. Empty baseUrl stays official; scheme-less hosts are parsed with an assumed https://; an unparseable baseUrl falls back to third-party (Bearer emitted) as the safer default. Behavior for legitimate official/third-party baseUrls is unchanged. Adds tests/unit/anthropic-official-baseurl-host.test.ts covering official, look-alike, scheme-less, and unparseable inputs plus a static guard that the substring pattern is gone. * fix(proxy): repair one-click Deno & Cloudflare relay deployments (diegosouzapw#5128) (diegosouzapw#5132) * fix(services): embed WS proxy honours LIVE_WS_HOST; reject empty messages early (diegosouzapw#5110) (diegosouzapw#5133) * fix(api): resolve /v1/models/{id} case-insensitively (diegosouzapw#5082) (diegosouzapw#5135) * fix(providers): add MiniMax M3 & Nemotron 3 Ultra to Cline catalog (diegosouzapw#3321) (diegosouzapw#5136) * fix(proxy): make SOCKS5 handshake timeout tunable via SOCKS_HANDSHAKE_TIMEOUT_MS (diegosouzapw#5109) (diegosouzapw#5137) * feat(sidebar): add support for colored menu icons (diegosouzapw#3812) Integrated into release/v3.8.38 (recreated on tip — fork had unrelated history; added getSidebarIconAccent regression test, Rule diegosouzapw#18). Clean 2-file UI feature. * fix(providers): complete grok-cli OAuth wiring + zenmux-free web-session metadata Base-red repair for diegosouzapw#5020 (grok-cli) and diegosouzapw#5105 (zenmux-free), surfaced by the full CI on the release PR (diegosouzapw#5078) — the PR->release fast-path does not run the oauth-providers-config / web-session-credentials / provider-consistency gates. - grok-cli: register in OAUTH_PROVIDERS (providers.ts canonical list, fixes check:provider-consistency), add OAUTH_PROVIDER_IDS.GROK_CLI + GROK_CLI_CONFIG in oauth constants (provider config now sourced there, not a local literal), align oauth-providers-config.test.ts (EXPECTED_PROVIDER_KEYS + config map). - zenmux-free: declare its web-session credential requirement (full Cookie header) in WEB_SESSION_CREDENTIAL_REQUIREMENTS. Local: oauth-providers-config 27/27, web-session-credentials 4/4, grok-cli-oauth 7/7, check:provider-consistency OK, +115 OAUTH_PROVIDERS tests green. * Fix resilience settings page response mapping (diegosouzapw#5139) Integrated into release/v3.8.38. Thanks @rdself for the fix and the regression test. * fix(kiro): retire claude-sonnet-4.5 from catalog + pin 400 model-unavailable test (diegosouzapw#5140) Extracted the real change from diegosouzapw#5140 (the bot PR regenerated the entire freeModelCatalog.data.ts + touched package-lock.json; only the targeted edits are kept here): - remove claude-sonnet-4.5 from the Kiro registry entry - remove the matching kiro free-model catalog row - pin Kiro's verbatim 400 "Invalid model..." to isModelUnavailableError Closes diegosouzapw#4484 * fix(sidebar): drop orphan `settings` accent color (typecheck:core red) (diegosouzapw#5142) SIDEBAR_ICON_ACCENTS is typed Partial<Record<HideableSidebarItemId, string>>, but `settings` is not a hideable item id (only `settings-general`, `settings-appearance`, … and `context-settings` exist; there is no item with `id: "settings"`), so the accent was unreachable. It broke `typecheck:core` on the release tip ("'settings' does not exist in type …", introduced by diegosouzapw#3812 colored menu icons). Removing the orphan key restores a clean typecheck:core (rc=0). * feat: salvage batch 2 — diagnostics null-guard (diegosouzapw#5096) + observed quota reset windows (diegosouzapw#5025) (diegosouzapw#5141) * fix(diagnostics): null-guard content blocks in detectMalformedNonStream A null (or non-object) entry in a Claude-native `content` array made the non-stream classifier throw `TypeError: Cannot read properties of null (reading 'type')`, crashing the malformed-response detection path. Guard before type-asserting each block: a null/non-object block is simply skipped. Two regression tests added (null block among valid blocks → null; only-null blocks → empty_choices). Salvaged from closed PR diegosouzapw#5096 (base-stale; only the defensive guard — the Claude-shape recognition it also carried already landed via diegosouzapw#5108). Co-authored-by: herjarsa <herjarsa@users.noreply.github.com> * feat(quota): persist observed provider quota reset windows Adds `provider_quota_reset_events` (migration 108) + `db/quotaResetEvents.ts` to record real upstream weekly-quota window transitions whenever a quota refresh shows the reset rolling to a new cycle (different day, later resetAt). `apiKeyUsageLimits` now prefers the observed window start over the inferred `resetAt − 7d`, falling back to snapshot inference when no event is recorded yet. `quotaCache.setQuotaCache` records the transition opportunistically. `recordProviderQuotaResetEventIfChanged` only fires for the primary weekly window (not daily/sonnet), is idempotent (INSERT OR IGNORE on the unique window key), and no-ops when the reset didn't actually roll. 4 unit tests (tests/unit/lib/quota-reset-events.test.ts). Salvaged from closed PR diegosouzapw#5025 (which bundled this with two unrelated features + a colliding migration 104). Renumbered to 108; module re-exported from localDb (Rule #2). Co-authored-by: Witroch4 <175152067+Witroch4@users.noreply.github.com> --------- Co-authored-by: herjarsa <herjarsa@users.noreply.github.com> Co-authored-by: Witroch4 <175152067+Witroch4@users.noreply.github.com> * docs(i18n): sync 3.8.38 CHANGELOG section to 41 mirrors (unblock docs-accuracy) (diegosouzapw#5144) The root CHANGELOG [3.8.38] section grew with this cycle's merged PRs, but the docs/i18n/<lang>/CHANGELOG.md mirrors were not re-synced — drifting >25% in body size and failing check:docs-sync (the "Docs accuracy" fast-gate step) for every open PR against the release. Ran scripts/release/sync-changelog-i18n.mjs 3.8.38 3.8.37 to copy the root [3.8.38] section into all 41 mirrors. check:docs-all now passes (exit 0). Sections are copied verbatim; the per-language translation pass runs at release time via i18n:run — this only restores the size-sync the gate enforces. * feat(compression): pure per-step fidelity checker (4 invariants, fail-open) * feat(compression): fidelityGate config + rejected breakdown fields * feat(compression): wire per-step fidelity gate into stacked pipeline (opt-in) * feat(compression): preview route accepts fidelityGate flag (playground) * feat(compression): playground fidelity-gate toggle + lane rejection display * docs(compression): note fidelityGate advanced thresholds are intentionally API-omitted * refactor(compression): extract fidelity-gate step helpers to shrink strategySelector (file-size gate) bodyToText and gateAdvance moved to fidelityGateStep.ts; StackAccumulator exported. strategySelector: 889->854 (-35). Residual +6 vs pre-Milestone-B frozen 848 is the irreducible StackOptions.fidelityGate field + two stacked-loop dispatch reads + import. Baseline updated to 854 with justification. No cycle introduced (import type only). 940 compression tests pass; typecheck clean. * test(usage): wire usageHistoryDedup under unit runner brace-list (diegosouzapw#5145) Integrated into release/v3.8.38. * feat: salvage batch from closed stale PRs (diegosouzapw#5038, diegosouzapw#5057, diegosouzapw#5076) (diegosouzapw#5138) Integrated into release/v3.8.38. * test(combo): deterministic routing-decision matrix for all 17 strategies (diegosouzapw#5146) Integrated into release/v3.8.38. * feat(compression): fuzzy near-duplicate dedup (session-dedup 2nd pass + playground toggle) (diegosouzapw#5143) Integrated into release/v3.8.38. * chore(quality): rebaseline file-size for sidebarVisibility.ts + chat.ts drift (diegosouzapw#5147) Mid-cycle drift on release/v3.8.38 from already-merged PRs that the fast-path (PR->release skips check:file-size) let accumulate without a bump: - src/shared/constants/sidebarVisibility.ts 1100->1198 (diegosouzapw#3812 colored menu icons, per-item accent map; diegosouzapw#5142 dropped one orphan, net still above frozen) - src/sse/handlers/chat.ts 1560->1575 (diegosouzapw#5064 self-inflicted-timeout cooldown skip + diegosouzapw#5124 long OpenAI-compatible SSE hardening + diegosouzapw#5110 embed-WS LIVE_WS_HOST honour / early empty-message reject) Each covered by its own PR tests; structural shrink of chat.ts tracked in diegosouzapw#3501. Unblocks the Fast Quality Gates for PRs targeting release/v3.8.38. * chore(release): finalize v3.8.38 CHANGELOG + cycle reconciliation - Reconcile [3.8.38]: +18 bullets (compression fidelity-gate/fuzzy-dedup diegosouzapw#5143, quota keepalive diegosouzapw#5102, web-session robustness diegosouzapw#5121, MiniMax/Nemotron diegosouzapw#5136, model-visibility diegosouzapw#5091, failover logs diegosouzapw#5016, disconnect races diegosouzapw#5007, sidebar orphan diegosouzapw#5142, SRE playbooks salvage diegosouzapw#5138, new Security diegosouzapw#5130 + Maintenance roll-up) - Credit salvaged-PR authors (@JxnLexn / @KooshaPari / @herjarsa / @Witroch4) - Remove phantom bullet for CLOSED-not-merged diegosouzapw#5092 (setup aggregator never landed) - Fix isHidden bullet PR citation diegosouzapw#4389 -> diegosouzapw#5086 (@herjarsa) - Back-fill forgotten v3.8.36 bullet: diegosouzapw#5026 crypto.randomUUID ID-gen (@hamsa0x7) - Sync 41 i18n CHANGELOG mirrors; README What's New -> v3.8.38 - Rebaseline cycle drift: eslint 3987->4002, cognitive 833->841, dead-exports 345->346, cyclomatic 1978->1980 (file-size handled by diegosouzapw#5147) * fix(i18n): add missing English UI labels (diegosouzapw#5153) Integrated into release/v3.8.38 * Preserve non-stream reasoning fields for compatible clients (diegosouzapw#5155) Integrated into release/v3.8.38 * feat(compression): ionizer engine — lossy JSON-array sampling reversible via CCR (diegosouzapw#5148) Integrated into release/v3.8.38 * test(combo): gated live smoke for combo strategies (in-process + VPS HTTP) (diegosouzapw#5151) Integrated into release/v3.8.38 * test: refresh release expectations to match current code (diegosouzapw#5150) Integrated into release/v3.8.38 (test-only base-red alignment extracted from diegosouzapw#5150) --------- Co-authored-by: Éder Costa <eder.almeida.costa@gmail.com> Co-authored-by: José Victor Ferreira <root@josevictor.me> Co-authored-by: Hernan Javier Ardila Sanchez <hjasgr@gmail.com> Co-authored-by: fulorgnas <46461624+fulorgnas@users.noreply.github.com> Co-authored-by: Randi <55005611+rdself@users.noreply.github.com> Co-authored-by: Jan Leon <Jan.gaschler@gmail.com> Co-authored-by: R. Beltran <rbeltran8000@gmail.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: KooshaPari <42529354+KooshaPari@users.noreply.github.com> Co-authored-by: Ramel Tecnologia - Rafa Martins <146174365+rafacpti23@users.noreply.github.com> Co-authored-by: herjarsa <herjarsa@users.noreply.github.com> Co-authored-by: Witroch4 <175152067+Witroch4@users.noreply.github.com>
TechNickAI
pushed a commit
that referenced
this pull request
Aug 12, 2026
…n collision #2 + broken import) (diegosouzapw#9688) * test(base): realign six suites with contracts that diegosouzapw#9100/diegosouzapw#8990/diegosouzapw#9009 deliberately changed Continuing the base-red drain — every one of these reproduces on the pure tip. - tests/snapshots/provider/translate-path.json: regenerated via UPDATE_GOLDEN=1. The diff is ADDITION-ONLY — the unorouter block from diegosouzapw#9009; no existing provider entry changed. 3/3. - tests/unit/provider-models-route.test.ts: ff012ff added onboardUser as a bootstrap fallback next to loadCodeAssist; the mock now excludes it from the discovery-URL ledger like it already excluded loadCodeAssist, otherwise it consumed the injected 503 and the retry assertion misfired. 59/59. - tests/unit/responses-commentary-passthrough-6199.test.ts: diegosouzapw#8990 (c996dc9) deliberately preserves `tools` on the TERMINAL response.completed snapshot (Codex CLI rebuilds its tool list from it); the assertion now pins the echoed tools instead of their absence. Still stripped on created/in_progress. 7/7. - tests/unit/vision-compression-authoritative-capability-7237.test.ts: 68cb678 added the 'gpt-5' fragment, so the heuristic-vs-spec DRIFT this suite documented no longer exists; the cases now guard the agreement, keep a conservative-for-unknown-ids probe, and reproduce the strip-bug shape with an explicit false instead of deriving it. 4/4. - tests/unit/provider-limits-proxy-fail-closed.test.ts + tests/unit/image-generation-route.test.ts: diegosouzapw#9100 made the proxy reachability probe NON-BLOCKING (optimistic dispatch; the probe aborts only in-flight requests — its own t14 sibling was updated to this exact pattern). Instant mocks therefore won the race and the PROXY_UNREACHABLE 503 became unobservable (a success or a generic 502). The mocks now stay in flight (never-resolving, so the aborted continuation cannot reach the restored real fetch), and the fail-closed proof is the settled rejection itself plus zero egress AFTER the fast-fail. Production fail-closed semantics are unchanged — the proxy dispatch path still throws; only the mock timing was stale. 3/3 and 20/20. Refs diegosouzapw#9298 * fix(guardrails): forward the router deps seam through callVisionModel tests/unit/guardrails/vision-bridge-sse-and-reasoning.test.ts was 7/7 red on any clean box (CI shard 3/4): callVisionModel() called getBestVisionModel()/ getFallbackModels() WITHOUT the routers' existing VisionBridgeRouterDeps seam, so the credential check always hit the live connections DB — no vision-capable connection meant 'No vision-capable provider connected' before the mocked fetch was ever reached, and on a dev box auto-selection could swap the fixed model under the assertions. The routers already accepted deps; only the forwarding was missing. Added the optional 5th param (backward compatible — the sole production caller, visionBridge.ts, injects its own callVisionModel and is unaffected) and the suite now pins selection with hasUsableCredentials: async () => null (indeterminate → the fixed model is honored, DB untouched). 7/7. Sibling suites re-run green: vision-bridge-callmodel 2/2, visionBridge 25/25, visionBridgeHelpers.callVisionModel 8/8, visionBridgeRouter 10/10, vision-bridge-cc-no-reroute 8/8. Refs diegosouzapw#9298 * fix(db,combo): clear the NEW base-reds the 08-06 merge batch introduced The tip moved while the first sweep PR (diegosouzapw#9600) was in review, and three fresh base-reds landed with it — same classes as before, all reproduced on the pure tip 9995bc4: 1. ANOTHER migration collision: diegosouzapw#9061 shipped 134_ccr_blocks.sql onto the slot 134_proxy_logs_egress_ip.sql (diegosouzapw#9291) has held since 08-04. getMigrationFiles() throws on collision, so every DB-touching test died at bootstrap again. Renumbered to 139 (next free slot). No retroactive guard needed this time: both statements are IF NOT EXISTS, and no DB can have applied it as 134 — the runner refused to run at all while the collision existed. 2. BROKEN IMPORT killing the combo module graph: diegosouzapw#8894 imported preferAntigravityConnectionsWithStoredProject from ../antigravityProjectPersistence.ts — a module that exists NOWHERE in the repo (it came from an unmerged sibling branch). Anything importing quotaStrategies.ts died with ERR_MODULE_NOT_FOUND. Implemented the helper in the real persistence module (antigravityProjectPersist.ts, diegosouzapw#8491) with the semantics the call site needs — prefer connections that already carry a stored projectId, never emptying the pool — and pointed the import there. New regression suite tests/unit/antigravity-prefer-stored-project.test.ts (5/5), including an import-graph probe that reproduces the break shape. 3. Sibling-test drift from diegosouzapw#9106 (gemini-3.1-pro-high now user-callable): its own suites were updated but provider-models-route.test.ts was not. Expected discovery list realigned; testFrozen 1784->1787 justified in the baseline (irreducible +2 after comment compression; gate counts split-newlines). Also regenerated tests/snapshots/provider/translate-path.json — addition-only: devin-cli-agentic, raycast, regolo (today's provider merges), zero removals. image-generation-route 20/20 (was import-dead), provider-models-route 59/59, antigravity-prefer-stored-project 5/5, provider-translate-path-golden 3/3. Refs diegosouzapw#9298 * fix(changelog): convert the diegosouzapw#9415 fragment to the required bullet shape Another base-red from the 08-06 batch: bd4407c landed changelog.d/features/9415-newapi-sub2api-aggregator-balance.md as YAML frontmatter + a prose paragraph. Every other fragment in changelog.d/ is a single markdown bullet, and both consumers enforce that — scripts/check/check-changelog-integrity.mjs:97 and the release aggregator (scripts/release/aggregate-changelog.mjs:57) reject anything that does not start with '- ', so 'Merge integrity (changelog + generated skills)' was red for every PR targeting the release branch. Rewritten as a bullet with the standard issue link, preserving the feature description (aggregator gateway toggle, /api/user/self balance read, dashboard badge, quota-preflight skip, NEWAPI_AGGREGATOR_BALANCE flag default off, quotaPerUnit override). Swept the rest of changelog.d/ — this was the only malformed fragment. check:changelog-integrity OK. Refs diegosouzapw#9298 * fix(types,docs): clear the 5 typecheck errors and the fabricated env vars on the base Third pass over the base-reds, from the 2026-08-06T22:51Z verdict on diegosouzapw#9298 — it reported "Typecheck (core)" with only the FIRST error; there are five, all on the pure tip 9995bc4. Two are real production defects. **Real bugs** - open-sse/services/compression/engines/ccr/index.ts:295 called enforceGlobalBudget(entry.bytes) against an (owner, bytes) signature. The `bytes` argument arrived undefined, so `ccrTotalBytes + undefined` is NaN, `NaN > MAX` is false (the eviction loop exits immediately) and `NaN <= MAX` is false (the re-admit is refused). The diegosouzapw#9061 durable tier therefore NEVER repopulated its in-memory map: every retrieve after a restart or an eviction re-read from SQLite forever, and evictions could not prefer the owning principal. Fixed and pinned by a new case in tests/unit/ccr-durable-store-9061.test.ts (11/11) — verified failing against the buggy call and passing against the fix. - open-sse/services/combo/fusionPanel.ts:54 read `step.model` after diegosouzapw#8894 widened ComboStep with ComboProviderWildcardStep (which carries modelPattern, not model), so a wildcard step in a fusion panel pushed `undefined` onto the panel. Now resolved through getComboModelString(), which already handles every step shape and returns null for the ones without a concrete model id. **Type-only** - accountSemaphore.ts:203 — isBypassed() returns a plain boolean and cannot narrow `number | null` (an `x is null | undefined` predicate would be unsound: 0 bypasses too). Added resolveActiveCap(), the narrowing companion isBypassed is now defined in terms of; the acquire path uses the narrowed value. - comboStructure.ts:140 — same diegosouzapw#8894 widening: `prompt` only exists on a model step, so it is now read under a kind check. - firecrawlQuotaFetcher.ts:136 — the function returns full FirecrawlQuota objects but was annotated Promise<QuotaInfo | null>, which made the custom-base literal an excess-property error. Widened to the accurate type (FirecrawlQuota extends QuotaInfo, so callers are unaffected). **Fabricated docs (the "Docs sync + fabricated-docs (strict)" HARD failure)** docs/ops/VM_DEPLOYMENT_GUIDE.md recommended OMNIROUTE_MAX_POOL_SIZE and OMNIROUTE_DB_POOL_SIZE (diegosouzapw#9471). Neither is read anywhere in the codebase. Replaced with the two knobs that do exist and are already documented in ENVIRONMENT.md: OMNIROUTE_MEMORY_MB and OMNIROUTE_CHAT_MAX_HEAVY_IN_FLIGHT. typecheck:core 5 errors -> 0. check:fabricated-docs + check:env-doc-sync OK. accountSemaphore 6/6, ccr-durable-store 11/11, ccr-protocol 9/9, combo-fusion-strategy 10/10, combo-fusion-comboref 5/5, combo-fusion-warn 4/4, firecrawl-executor 7/7, executor-firecrawl-fetch 4/4. Refs diegosouzapw#9298 * fix(tests): type the diegosouzapw#3440 vertex helpers instead of `any` (the 3 base ESLint errors) The "ESLint errors: 3 error(s)" HARD failure in the diegosouzapw#9298 verdict is tests/unit/vertex-functioncall-id-3440.test.ts lines 32/41/50: the three find*(result: any) walkers. `@typescript-eslint/no-explicit-any` is an ERROR in tests/ (and open-sse/) since diegosouzapw#6218, and this file landed on 2026-08-04 without a suppressions entry, so every run of `lint:json --max-warnings 0` failed. That step prints nothing on failure, which is why the gate looked like a silent crash across the open PRs. Replaced with a GeminiRequestLike interface describing exactly what the three walkers traverse (contents[].parts[]), so the assertions keep their meaning and nothing is cast away. eslint on the file: clean. Suite: 6/6. Refs diegosouzapw#9298 * docs(proxy): use an RFC 5737 documentation IP in the proxy examples The diegosouzapw#9298 verdict headlines its docs failure with `L810 [stale-version] 1.2.3: const removed = await failOneproxyProxy("1.2.3.4", 8080)`. That is a false positive: check-deprecated-versions.mjs matches `/\bv?[12]\.\d+\.\d+\b/`, and the example IP literal 1.2.3.4 contains "1.2.3". Swapped both occurrences in PROXY_GUIDE.md (and its pl mirror) for 203.0.113.7, from the RFC 5737 documentation range that exists precisely for examples — it cannot collide with a version pattern and is the correct thing to print in docs regardless. Drift count 64 -> 62; no gate threshold was touched. The gate that actually FAILED under "Docs sync + fabricated-docs (strict)" was check:fabricated-docs (the invented pool env vars), fixed in the previous commit; this one removes the misleading line the verdict quotes. * test(base): allowlist probeUtils and realign the diegosouzapw#7849 suite to the replacement bound Two more base-reds, both visible only after the migration collision stopped killing the shards. **check-db-rules — src/lib/db/probeUtils.ts not classified** diegosouzapw#9541 added probeUtils.ts (transient-error retry for the SQLite corruption probe). It is imported ONLY by src/lib/db/core.ts, exactly like its siblings schemaColumns / optimizationSettings / providerNodeSelect, so re-exporting it through localDb.ts would push callers toward the barrel-import anti-pattern the gate exists to prevent. Added to INTENTIONALLY_INTERNAL with that rationale. check-db-rules 22/22, check:db-rules exit 0. **session-dedup-memory-7849 — pinned a mechanism that was replaced** 7f36b19 (diegosouzapw#7855 follow-up) swapped the shared "suffix work budget" for the MAX_SUFFIX_STARTS / MAX_TOTAL_BLOCK_BYTES guards and deleted both the budget and its SUFFIX_WORK_BUDGET_WARNING string. It updated session-dedup.test.ts but not this sibling, so 3 of its 4 cases asserted a warning that can no longer be emitted. Realigned to the contract that actually survives — which is the invariant diegosouzapw#7849 was opened for, not the mechanism: - the pathological pair must stay BOUNDED (completes in <4s, body intact) — measured at ~280ms on the current guards; - it must FAIL OPEN — original body returned by identity, compressed false, stats null (the explanatory zero-savings stats belonged to the removed budget path, which skipped before producing any); - the 512 MiB child fixture must still exit 0 with the full engine chain (session-dedup, lite, rtk, headroom, caveman) — that IS the OOM guard — and session-dedup must still report its skip, now pinned by prefix since the reason string moved with the mechanism. No threshold was loosened and no case was deleted: 4/4 here, 8/8 on the sibling session-dedup.test.ts. Refs diegosouzapw#9298 * docs(mcp): bump the tool count to 105 and realign two vitest count pins Three more base-reds from the same 08-06 batch, all count/contract drift that the merged PRs left in sibling files. **Docs Gates (fast-path) — 3 STRICT drifts** check:docs-counts measures the MCP tool set from live code: it is 105 now (diegosouzapw#8925 added omniroute_create_combo), while README.md, AGENTS.md and docs/frameworks/MCP-SERVER.md still claimed 104. Updated all five occurrences (two of them inside SVG alt text). check:docs-all exits 0. **Vitest (fast-path) — 2 failures** - open-sse/mcp-server/__tests__/essentialTools.test.ts pinned 11 phase-1 tools; diegosouzapw#8925 shipped omniroute_create_combo as phase 1, making it 12. Verified by enumerating MCP_ESSENTIAL_TOOLS directly. - tests/unit/autoCombo/provider-family-combos.test.ts pinned the auto/glm provider set to [auggie, glm, zai]. diegosouzapw#8914 (Devin ACP bridge) added devin-cli-agentic, whose catalog (registry/devin/catalog.ts:90-93) advertises the glm-5-2* line — so it belongs in the family pool for exactly the reason the test's own comment gives for auggie: a no-auth backend that genuinely serves a family model is a legitimate member. Expected set updated, invariant unchanged. npm run test:vitest 36/36 files, 340/340 tests. Refs diegosouzapw#9298 * fix(combo,usage,oauth): drain the base-reds the shard fix exposed With the migration collision and the broken import out of the way the four unit shards actually run, and a further layer of base-reds became visible on the pure tip 9995bc4. Three are production defects. **Production defects** - open-sse/services/combo/runtimeUnitCapacity.ts:58 called resolveComboTargets() WITHOUT the hidden-model snapshot, so it fell back to the default getHiddenModelsByProvider() — a fresh full key_value read PER nested combo-ref unit, on every request. diegosouzapw#8878 threaded the snapshot through the other call sites and missed this one. Threaded it from executeRuntimeUnitCombo (and from the dispatchPrelude call site), restoring the one-snapshot-per-request invariant combo-hidden-leaf-routing.test.ts pins. 9/9. - open-sse/services/usage/firecrawl.ts silently ignored its own `apiKey` parameter: 91bb6aa moved the fetch to fetchFirecrawlQuota(connectionId, connection), which reads the key off the connection record, so any caller passing the key directly got "Firecrawl API key not available". The explicit key is now merged into the connection passed down. firecrawl-usage 8/8. - src/lib/oauth/constants/oauth.ts was missing a RAYCAST entry in PROVIDERS while src/lib/oauth/providers/index.ts registers `raycast` (diegosouzapw#8895), so every consumer reading PROVIDERS did not know Raycast Pro exists. Also added its OAUTH_TEST_CONFIG entry (checkExpiry only — it is an `import_token` provider with refreshToken always null), which diegosouzapw#8408's guard explicitly requires rather than grandfathering. oauth-providers-config 25/25, oauth-test-config-8408 2/2. **Count / contract drift from the same batch** - feature flags 45 -> 46, APIKEY_PROVIDERS 197 -> 198 (Raycast Pro diegosouzapw#8895), unique MCP tools 107 -> 108. Each re-derived from the source of truth. - vi + pt-BR locales: translated the 8 keys diegosouzapw#9415 added (providers.newApiAggregator* and providers.modelTestQuotaTooltip) instead of relaxing the parity guard. i18n-vi 5/5, i18n-pt-br 3/3. - login-bootstrap-route: diegosouzapw#9491 added `authenticated` to the require-login payload so /login can redirect an active session; the three deepEqual bodies now carry it. 10/10. **Flaky-by-construction, made deterministic** tests/unit/chat-combo-live-test.test.ts asserted the early-keepalive frame with a 100ms mocked upstream while resolveKeepaliveThreshold() is 2000ms for openai/*. It only ever passed while unrelated handler latency happened to push the total past the threshold — incidental, not deterministic, and it stopped holding once the handler got faster. The mock now sleeps 2400ms so the slow path is guaranteed and the assertion means what it says. 5/5. typecheck:core exit 0. check:file-size (base-relative) OK. Refs diegosouzapw#9298 * test(base): run the orphaned diegosouzapw#8890 suite and realign three mechanism pins **check:test-discovery — a suite that had NEVER executed** diegosouzapw#8890 landed open-sse/services/__tests__/fail-fast-concurrency-gate.test.ts into a directory no runner collects (only one explicit file from that folder is in vitest.mcp.config.ts), so it ran zero times since it merged. Wired it into the runner AND into check-test-discovery.mjs's mirrored collector list, which the gate keeps in sync deliberately. It passes 4/4 now that it actually runs — test:vitest goes 36 -> 37 files, 340 -> 344 tests. **check-db-rules-classification** — 37 -> 38 audited modules, adding probeUtils alongside the INTENTIONALLY_INTERNAL entry from the previous commit. **ratelimit-reservoir-refresh** — diegosouzapw#9604 (rolling RPM leases) DELETED Bottleneck's fixed-window reservoir, so currentReservoir() is null and the poll for `reservoir === 2` could never settle. It updated several sibling suites but not this one. The pin on the removed mechanism is gone; what remains is the invariant the original Bottleneck heartbeat bug actually broke and that diegosouzapw#9529 opened this test for — after a header-learned updateSettings() the limiter must keep admitting work, proven by racing a post-exhaustion request against a 5s timer. 1/1. **translator-openai-to-gemini** — diegosouzapw#9568 (c9a3361) made buildChangedToolNameMap emit IDENTITY entries too, because Gemini lowercases tool names in functionCall responses and the response translator needs a key to map them back. Any request carrying tools therefore carries `_toolNameMap` in the Antigravity envelope now. Expected key list updated and the map's contents asserted explicitly rather than left implicit. 45/45. Refs diegosouzapw#9298 * fix(db): restore node-backed synced catalogs and realign the diegosouzapw#8944 context hints **Production regression from diegosouzapw#9294 (d69f521)** lookupModelMeta moved from getSyncedAvailableModels(providerId) to getActiveSyncedCatalog(providerId). The new reader unions models only from rows in `provider_connections` with isActive = 1 — but a provider NODE lives in `provider_nodes` and NEVER has a connections row, so filtering by active connection ids silently dropped every node's synced catalog. The consequence was not just a missing list: lookupModelMeta reads that catalog for RUNTIME METADATA, so for openai-compatible nodes it took out - `supportedThinkingEfforts`, which is what splitSyncedEffortSuffix needs — so `<prefix>/<model>-high` stopped resolving to the base id and the effort was never derived (diegosouzapw#7694), and - `contextWindow` / `maxInputTokens`, used by the combo context-window filter. getActiveSyncedCatalog now falls back to the provider-wide key_value set — the exact pre-diegosouzapw#9294 source — when no active connection carries a catalog, and marks that fallback explicitly NON-authoritative. diegosouzapw#9294's live-catalog gating is about what an active connection actually serves, so a node-backed catalog informs metadata while never being able to reject a model as unavailable. `available` therefore stays fail-open for nodes, as it was before. sync-reasoning-supported-efforts-7694 23/23 (was 21/2). live-model-catalog-reconciliation-8926 11/11 and combo-provider-wildcard 23/23 confirm diegosouzapw#9294's own coverage is untouched. **diegosouzapw#8944 sibling-test drift** 714a315 ("Treat context metadata as a routing hint") deliberately turned the context-window check from a HARD filter into an ordering hint: a catalog-too-small target is demoted, not removed, because a stale catalog entry must never delete the only target that could accept the request at runtime. The PR updated one case in this suite and left three asserting the old drop behaviour. Realigned to the new contract — the too-small target must lose the ordering to the fitting one while remaining present — and renamed them from "still rejects"/"still dropped" to "is demoted"/"ordered last" so the names stop describing the removed behaviour. 14/14. **file-size** tests/unit/translator-openai-to-gemini.test.ts testFrozen 1616 -> 1619: the frozen value sat exactly at the base size, so the 3 lines the previous commit's _toolNameMap alignment needs could not fit. Justified in the baseline. typecheck:core exit 0. Refs diegosouzapw#9298 * chore(stryker): register the two covering suites missing from tap.testFiles check:mutation-test-coverage flags any unit test that covers a mutated module but is absent from stryker.conf.json tap.testFiles — without the entry its mutant kills do not count toward the module's score. - tests/unit/antigravity-prefer-stored-project.test.ts covers open-sse/services/combo/quotaStrategies.ts (added earlier in this PR). - tests/unit/executor-devin-cli-agentic-acp.test.ts covers src/sse/services/auth.ts — pre-existing drift, same gate, same fix. Inserted in alphabetical position only; the rest of the file is byte-identical (it is not prettier-formatted upstream and reformatting it is out of scope here). Refs diegosouzapw#9298 * fix(db): drop the never-wired getSessionModelUsageCounts (knip regression) The dead-code ratchet only ran once the earlier Fast Quality Gates steps stopped failing, and it lands at 228 vs baseline 227. The extra symbol is src/lib/db/contextHandoffs.ts::getSessionModelUsageCounts, added by diegosouzapw#8894 "for least-used strategy" and never wired: the least-used branch in applyStrategyOrdering.ts uses the pre-existing sortTargetsByUsage(), and the helper has no caller in src/, open-sse/ or tests/. It is the same incomplete-PR shape as that PR's import of a module which does not exist in the repo (fixed earlier in this branch). Removed rather than baselined — bumping the ratchet would loosen the gate, and removal is exactly the remedy the gate prescribes. Same treatment the Dario installer's never-wired uninstall() got in diegosouzapw#9600. The implementation is recoverable from a598fbb whenever someone actually wires a session-aware least-used strategy. check:dead-code 228 -> 227 (baseline untouched). check:db-rules exit 0. context-handoff 13/13, db-context-handoffs 7/7, service-context-handoff 11/11. Refs diegosouzapw#9298 * fix(security): embed the Raycast signature secret via resolvePublicCred (HR#11) The secret-scan ratchet only ran once the earlier Fast Quality Gates steps stopped failing, and it lands at 1 finding vs baseline 0. The finding is open-sse/services/raycast.ts:19 — RAYCAST_DEFAULT_SIG_SECRET, a 64-hex request-signature secret that diegosouzapw#8895 committed as a bare string literal. It is genuinely public (community-extracted from the Raycast macOS client; the SAME value ships to every install, it is not a per-user credential), which is exactly the category Hard Rule #11 governs: public upstream credentials MUST go through resolvePublicCred() (open-sse/utils/publicCreds.ts), never a literal — see docs/security/PUBLIC_CREDS.md. So the fix is the mandated pattern, not a .gitleaks.toml allowlist entry: added `raycast_sig_secret` to EMBEDDED_DEFAULTS as the XOR-masked byte sequence and resolved it with the existing RAYCAST_SIG_SECRET env override. The providerSpecificData.sigSecret override is untouched. Verified the decoded value is byte-identical to the literal it replaces. check:secrets secretFindings 1 -> 0. check:public-creds exit 0. publicCreds 12/12, raycast-auth 6/6, raycast-local-extract 1/1, trae-publiccred 3/3. typecheck:core exit 0. Refs diegosouzapw#9298 --------- Co-authored-by: diegosouzapw <diegosouzapw@users.noreply.github.com>
TechNickAI
pushed a commit
that referenced
this pull request
Aug 12, 2026
…routing (diegosouzapw#9195) Three linked bugs prevented the Custom Models 'Vision capable' toggle from affecting Combo routing, causing 400 capability_mismatch on image requests sent through Combos targeting a custom vision model. Bug #1 (catalog, dead guard): modelType === 'chat' was always false for chat models because modelType was only assigned 'embedding', 'rerank', 'image', or 'audio'. Changed the guard to !modelType || modelType === 'chat' so getCustomVisionCapabilityFields() fires for custom chat models. Bug #2 (catalog, synced-first ordering): When a model appeared in both syncedAvailableModels (from discovery) and customModels, the custom row was skipped entirely, losing the vision override. Now merge vision fields into the existing synced entry when the custom model has an explicit supportsVision boolean. Bug #3 (routing capabilities): getResolvedModelCapabilities() / resolveVisionCapability() had no path to consult the customModels supportsVision flag. Added a sync DB lookup helper and a new customVisionOverride parameter so the dashboard toggle affects Combo routing. Co-authored-by: diegosouzapw <diegosouzapw@users.noreply.github.com>
TechNickAI
pushed a commit
that referenced
this pull request
Aug 12, 2026
…n package (diegosouzapw#8299) * fix: align three stub implementations with original code - chatUrlMatcher: restore original 3-arg signature (u, matchDomain, chatUrl) with PLACEHOLDER-aware path segment matching - shouldUseGrokBrowserBacked: remove required param, restore env-var logic checking both WEB_COOKIE_USE_BROWSER and OMNIROUTE_BROWSER_POOL - browserPool.ts: add Turbopack rationale comment and join-trick helper to satisfy the optional-import test assertions - browserBackedChat.ts: replace any types with typed BrowserPoolModule interface Verification: 40/40 browser node:test pass, typecheck:core 0 errors * fix: remove duplicate getMod/modPromise in browserBackedChat stub Two copies of the module proxy got committed — the typed BrowserPoolModule version at lines 50-56 and a stale any-typed duplicate at lines 64-71. Removed the duplicate, keeping the typed version. Verification: - 40/40 browser tests pass (both previously-failing suites now green) - typecheck:core: 0 errors - env kill switch (OMNIROUTE_BROWSER_POOL=off): verified * fix(pr-8299): address all 5 review issues Issue #1: Add @omniroute/browser-pool path to root tsconfig.json paths Issue #2: Fix tryBackedChat fallback — call browserBackedChat outside if(loaded) guard Issue #3: Fix grokClearance stub signature (signal?: AbortSignal) → string|null Issue #4: Add comment clarifying async __resetBrowserPoolMetricsForTest vs upstream sync Issue #5: Add test case for package-absent fallback in tryBackedChat All 25 browser tests pass across 4 suites. typecheck:core passes. * chore: move sqlite-vec to optionalDependencies, fix js-tiktoken static import Both changes ensure native binary dependencies are properly categorized as optional: - sqlite-vec: moved from dependencies to optionalDependencies. Only used via lazy _require("sqlite-vec") in vectorStore.ts — zero static imports. - js-tiktoken: already in optionalDependencies, import changed to createRequire pattern to avoid crash when package is not installed (same pattern as sqlite-vec in vectorStore.ts). Resolves ScoutDeps findings from browser-pool pluginization audit. * docs(issues): fix stale interfaces.ts path in browser-pool proposal The proposal originally planned open-sse/interfaces/browserPool.ts for the BrowserPoolProvider interface, but the shipped implementation puts it in packages/browser-pool/src/interfaces.ts instead. Update the references so the doc matches what was actually built — the stale path was tripping check:fabricated-docs (--strict). Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> * fix: sync package-lock.json with playwright 1.62.0 Co-authored-by: oyi77 <oyi77@users.noreply.github.com> * test: keep browser warmup disabled in tryBackedChat unit tests * fix(pr-8299): keep grokClearance on the evolved release implementation (rebase reconciliation) --------- Co-authored-by: oyi77 <oyi77@users.noreply.github.com> Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> Co-authored-by: diegosouzapw <diegosouzapw@users.noreply.github.com>
TechNickAI
pushed a commit
that referenced
this pull request
Aug 12, 2026
…resh (diegosouzapw#9173) * refactor(cursor): extracts token extraction into shared lib Moves tryIdeAuth/tryAgentAuth and supporting helpers out of the auto-import route into src/lib/cursor/tokenExtractor.ts, and adds an agent-cli-state.json fallback candidate path to tryAgentAuth (alongside the existing auth.json candidate) so the extraction logic can be reused by the upcoming renewal orchestrator. * feat(cursor): adds cursor-agent-backed token renewal orchestrator Builds the renewal orchestrator in src/lib/cursor/renewal.ts: a bounded, unattended-safe --list-models nudge, a side-effect-free status availability check, an in-flight spawn lock keyed by command, and renewCursorConnection() which nudges cursor-agent then independently re-scrapes the IDE and cursor-agent credential sources to detect whichever refreshed. Extends cursorAgent.ts's binary resolution and spawn helper with fixed-paths-only mode and a SIGKILL follow-up for background use. Adds a generic keyed-mutex utility (src/shared/utils/keyedMutex.ts) for serializing a connection's renew-then-persist cycle, and forwards a busy-timeout through driverFactory's node:sqlite fallback path. * feat(cursor): proactively renews Cursor sessions in the sweep Adds src/lib/tokenHealthCheckCursor.ts, sweep-side glue that calls the renewal orchestrator and persists the result, wired into tokenHealthCheck.ts's checkConnection() via a new Cursor-specific branch placed ahead of the generic no-refresh-token fallthrough. Carves out a non-terminal exception for a Cursor connection that already landed at testStatus "expired" via the request-time 401 path, excluding permanently-dead account_deactivated connections. Extends buildRefreshFailureUpdate() with an overrides param so Cursor's failure path can use a distinct, non-terminal errorCode instead of the generic refresh_failed/expired taxonomy. * feat(cursor): adds local-only manual refresh route Adds POST /api/providers/[id]/refresh-cursor, a dedicated loopback-only route that calls the renewal orchestrator on demand for a single Cursor connection, bounded by a 30s per-connection cooldown. Classifies the new route in LOCAL_ONLY_API_PATTERNS and closes the manage-scope-bypass gap for dynamic-segment spawn-capable routes under /api/providers/ via a new SPAWN_CAPABLE_PATTERNS / SPAWN_CAPABLE_PATTERN_ANCESTORS mechanism, which also retroactively covers the pre-existing /login route. The existing shared /api/providers/[id]/refresh route is untouched and stays remote-reachable for every other provider. * feat(cursor): surfaces a dismissible cursor-agent nudge Adds GET /api/providers/cursor/agent-availability, a credential-free LOCAL_ONLY route returning only { cursorAgentAvailable: boolean }, backed by a 5-minute cached wrapper around the renewal orchestrator's existing availability check. Surfaces a dismissible dashboard banner on the Cursor provider page suggesting cursor-agent installation when it isn't detected, following the existing dismissible-banner convention. Also fixes a pre-existing bracket character in a routeGuard.ts comment that was silently truncating check-openapi-security-tiers.mjs's view of LOCAL_ONLY_API_PREFIXES. * fix(cursor): wires manual refresh button to the new route Branches handleRefreshToken to call the dedicated Cursor refresh route instead of the generic /refresh route, which silently 502s for Cursor connections today since they carry no refresh token. Every other provider's refresh behavior is unaffected. Adds the cursorSessionUnchanged i18n key and syncs it (plus a pre-existing, unrelated 28-key backlog) across all 42 locale files. * fix(cursor): addresses Phase 4/4.5 review findings Restores the legacy stdout/stderr auth-pattern fallback in checkCursorAgentAvailability() that the plan's Task 2 Step 4 required but the implementation had dropped. Threads an optional deps parameter through checkCursorConnectionIfNeeded() so its error branch is reachable in tests, and switches both it and the manual-refresh route to exhaustive switch statements over the renewal result. Adds a short-lived host-keyed dedup cache around tryIdeAuth() so multiple due Cursor connections sharing a host don't each open the same state.vscdb file in one sweep tick. Adds opportunistic eviction to the manual-refresh cooldown map, an outer try/catch to the availability route for defense-in-depth consistency with the plan's other routes, and corrects a stale JSDoc claim about the /login route's auth check. Documents the now-empirically-confirmed agent-cli-state.json schema mismatch found while validating against a real cursor-agent install. * docs(cursor): adds changelog fragments for the renewal plan Adds one fragment per user-facing outcome per changelog.d/README.md's convention for a PR that both fixes and adds. PR number placeholder to be filled in once the PR is opened. * fix(i18n): translates the new Cursor keys into Vietnamese The i18n:sync-ui run in an earlier commit left __MISSING__ sentinels for the 4 new Cursor keys in every locale, but Vietnamese has a dedicated completeness test requiring zero internal missing markers. Provides real translations for cursorSessionUnchanged, cursorAgentNudgeTitle, cursorAgentNudgeBody, and cursorAgentNudgeDismiss. * fix(cursor): addresses quality-gate Layer 1.5 findings Restores a comment that misrepresented execFile's actual argv shape after an earlier bracket-removal fix, this time avoiding literal closing-bracket characters entirely so the openapi checker's naive array parser can't be broken by either version. Bounds the sweep- and manual-route-triggered tryIdeAuth() busy-timeout to 250ms (down from the interactive auto-import path's 2000ms), since both share the main event loop with all other in-flight requests and should fail fast on a WAL-lock collision rather than block the whole instance for up to ~4s. Has the manual refresh route bypass the sweep's IDE-auth dedup cache so a click always sees a fresh read, consistent with this plan's existing "manual actions never see stale cached data" convention. Documents the previously-missing agent-availability route in ROUTE_GUARD_TIERS.md's spawn-capable table. * fix(cursor): adds SIGKILL follow-up to the status-check spawn Matches the nudge spawn's existing SIGTERM+SIGKILL pattern so an unresponsive cursor-agent status check can't leak a lingering process if it ignores SIGTERM. * docs(cursor): fills in the PR number for changelog fragments Renames the 3 changelog.d fragments to their PR-numbered filenames and replaces the (#PR) placeholder with diegosouzapw#9173, now that the PR exists. * fix(cursor): corrects changelog fragments to reference PR diegosouzapw#9173 The prior commit only staged the git mv rename — a git add invocation with a stale (pre-rename) pathspec aborted before the actual (#PR) -> (diegosouzapw#9173) content edit was staged, so the rename landed without the fix it was meant to carry. This captures the actual content change. * docs(cursor): regenerates the agent-skills catalog for the new route check:agent-skills-sync (CI's Merge integrity gate) requires SKILL.md files to stay in sync with the live route catalog. Adding /api/providers/cursor/agent-availability in an earlier commit needed a regen this branch never ran. * chore(quality): rebaselines file-size caps grown by agentrouter merges Two already-merged agentrouter commits (564c204, ec150a0) on release/v3.8.50 grew open-sse/executors/base.ts, open-sse/handlers/chatCore.ts, and tests/unit/chatcore-translation-paths.test.ts past their frozen caps before this PR branched — unrelated to the Cursor renewal changes here. No PR branch is left to fix the growth in-place, so the caps are bumped to the current real sizes, following the existing release-green rebaseline precedent in this file. * fix(sse): imports getModel helpers from db/models, not localDb A recently-merged agentrouter commit added a @/lib/localDb import in chatCore.ts, violating the no-restricted-imports rule (Hard Rule #2 — never barrel-import from localDb.ts). Points the import at the owning module, src/lib/db/models.ts, where both functions are actually defined, and prunes the now-stale suppression entry. * fix(sse): scopes CC-relay anthropic-beta to its own requestDefaults Two already-merged agentrouter commits widened usesClaudeCodeProtocol()'s native-Claude system-transform block (billing header + selectBetaFlags-derived anthropic-beta) to also run for generic CC-compatible relay connections, not just real claude traffic and agentrouter's own wire-image mimicry. selectBetaFlags() has no visibility into a relay's own providerSpecificData.requestDefaults, so its header replacement silently wiped out an earlier context-1m append and force-included redact-thinking regardless of the relay's own opt-in. Restores both for plain CC-compatible relays only; real claude/agentrouter traffic is unaffected. Also bumps four stale hardcoded Codex/Claude Code CLI version-string test assertions (0.144.1->0.146.0, 2.1.219->2.1.220) that drifted when the same two commits bumped the version constants without updating their tests, and rebaselines base.ts's frozen file-size cap for this fix's own +35 lines. * fix(sse): preserves bare CC-relay native treatment and context-1m The previous commit's fix was too broad in one direction: excluding ALL CC-compatible relays from the native-Claude header block broke two pre-existing tests (cc-compatible-provider.test.ts, v3.6.6) that rely on that treatment for a 'vanilla' relay with no providerSpecificData.requestDefaults configured. Refines the gate to this whole native-Claude header-replacement block: replace headers for real claude traffic, agentrouter's wire-image mimicry, OR a CC-relay with no requestDefaults at all — only a relay with EXPLICIT requestDefaults (context1m/redactThinking/summarizeThinking) gets to keep buildHeaders()'s own correctly-computed header set. A redact-thinking-beta strip (unconditional, a no-op when native treatment didn't apply) covers the one remaining gap: selectBetaFlags() force-includes it for a bare relay's opaque client, which a bare relay never explicitly opted into. Verified against all three previously-conflicting pre-existing tests simultaneously: executor-default-base.test.ts's '1M beta' test, both cc-compatible-provider.test.ts SSE-forcing tests, and provider-request-failure-pipeline.test.ts's 'keeps request beta headers' test (the last of which was already broken by the raw agentrouter merge, confirmed via direct comparison against that exact commit). * fix(sse): fills in remaining stale CLI version literals The same two agentrouter commits bumped Codex/Claude Code CLI version constants (0.144.1->0.146.0, 2.1.219->2.1.220) without updating every hardcoded test assertion. This round covers the ones the previous version-string commit missed: the anthropic-cache-fingerprint billing-version constant, a cc-bridge-transforms body assertion, the UI-mirror parity test's own snapshot plus its RoutingTab.tsx source of truth, an integration test's User-Agent assertion (inconsistent with its own dynamic Version assertion two lines up), and the translate-path golden snapshot. Also updates a stale doc comment referencing the old literal by value instead of by constant name. * fix(cursor): imports from db/ modules, not the localDb barrel Both files violated Hard Rule #2 (never barrel-import from localDb.ts) — a genuine lint error that had gone uncaught locally. refresh-cursor/route.ts imported getCachedProviderConnectionById from @/lib/localDb instead of its owning module, @/lib/db/readCache. tokenHealthCheckCursor.ts copied the same pattern from its sibling tokenHealthCheckCopilot.ts (an existing, already-suppressed violation) for updateProviderConnection; imports it from @/lib/db/providers instead, with no circular-import fallout (verified via the existing token-health-check-cursor and refresh-cursor-route test suites). * fix(db): removes stale raw-SQL allowlist entry for cursor route The cursor auto-import route no longer contains raw SQL — that query now lives in src/lib/cursor/tokenExtractor.ts, outside the route/handler scope check-db-rules scans. The allowlist entry was stale, tripping the stale-enforcement gate. * fix(test): registers cursor test files in stryker tap.testFiles Three unit test files covering mutation-tested modules (route-guard-cursor-agent-availability, route-guard-cursor-refresh, cursor-renewal) were missing from stryker.conf.json's tap.testFiles, tripping the mutation-test-coverage gate's drift detection. * chore(ci): retriggers checks (stuck GH Actions runner on shard 2/4) * fix(sse): restores CC-relay context1m/redact-thinking test coverage Rebasing onto release/v3.8.50's new tip (35405be, an unrelated agentrouter protocol-inference commit) silently flipped two assertions this branch's own earlier fix (687fbda) depends on, in the same test files that commit touched for other reasons: - executor-default-base.test.ts: calls[0] (a bare CC-relay with no requestDefaults) expected redact-thinking-beta absent; flipped to present. calls[1] (context1m+redactThinking requestDefaults) expected the context-1m beta preserved; flipped to absent. - provider-request-failure-pipeline.test.ts: expected Accept: text/event-stream and the context-1m beta present for a relay with explicit requestDefaults; flipped to application/json and absent. 35405be did not touch open-sse/executors/base.ts at all, so these were test-only edits made without visibility into the still-unmerged CC-relay header-preservation fix on this branch — they quietly matched the assertions back to the pre-fix (buggy) behavior instead. Restores the original, validated expectations; all three interdependent test files (executor-default-base, cc-compatible-provider, provider-request-failure-pipeline) verified passing together again. * ci: re-trigger checks after GitHub Actions incident (2026-08-07, resolved) * ci: re-trigger checks (previous push event was dropped) * fix(quality): restore dropped vi.json cursor-renewal keys + rebaseline test growth vi.json was missing 4 keys (cursorSessionUnchanged, cursorAgentNudgeTitle/Body/Dismiss) that this PR's own pre-merge branch had translated -- the original merge's 'git checkout --theirs' resolution for the 7 conflicted locale files discarded them since upstream's vi.json has no cursor-token-renewal feature. Restored from pre-merge tip a38003e. Also rebaselines combo-routing-engine.test.ts (3457->3464) for the comment growth from the ALL_ACCOUNTS_INACTIVE fix, caught by CI's PR-mode check:file-size. * chore(tests): drop explanatory comments on ALL_TARGETS_SKIPPED assertions Kept the assertion value fix (ALL_ACCOUNTS_INACTIVE -> ALL_TARGETS_SKIPPED); the comments were unnecessary. Reverts the file-size baseline bump these comments caused (combo-routing-engine.test.ts back to its original 3457).
TechNickAI
pushed a commit
that referenced
this pull request
Aug 12, 2026
…w#9485) * feat(providers): add DeepSeek V4 thinking effort aliases * docs(changelog): add DeepSeek effort alias entry * fix(catalog): scope effort-tier fallback to declared models and harden resolver Addresses reviewer findings on diegosouzapw#9485: - CRITICAL #1: catalog no longer synthesizes unresolvable effort aliases for static reasoning models without declared tiers (cheaperinference, cline, etc.) - CRITICAL #2: tiered static models survive synced-coverage suppression so normal installs with synced DeepSeek base models still expose aliases - WARNING #3: registry suffix resolution short-circuits when the raw id matches a direct custom or synced model, preserving custom apiFormat/targetFormat - WARNING #4: empty synced effort array no longer erases the registry fallback - WARNING #5: isFlash check is robust to suffixed/prefixed model ids - Added regression tests for blast radius, custom-model shadowing, none-path, and suffixed isFlash * fix(combos): expose static registry effort tiers in Combo Builder (diegosouzapw#9485) Static provider registry models (e.g. DeepSeek V4 Flash/Pro) declare supportedThinkingEfforts, but buildModelOptions() only ran appendSyncedEffortVariants() over DB-synced rows. Synced metadata for a DeepSeek connection can omit supportedThinkingEfforts, so the catalog/ Playground surfaced the declared aliases while the Combo Builder picker showed only the bare base ids. Feed builtInModels with declared effort tiers through the same appendSyncedEffortVariants() utility used for synced rows, inheriting the base entry's contextLength/outputTokenLimit/supportedEndpoints/ supportsThinking and preserving its source. DeepSeek is not skipped by shouldExposeSyncedEffortVariants(), so Flash (none/low/high/max) and Pro (none/high/max) aliases now appear in the Combo Builder for any connection whose synced rows omit effort metadata. Regression test seeds a DeepSeek connection with effort-less synced rows and asserts the exact alias sets, source preservation, and metadata inheritance.
TechNickAI
pushed a commit
that referenced
this pull request
Aug 12, 2026
* feat(providers): add Zylo UnoRouter and Poolside registries
* feat(providers): integrate audited free-tier gateways
* feat: add wave2 free-tier provider registries
* feat(providers): add Mixlayer Speka and TokenReply registries
* feat: add wave 2 free-tier provider registries
* fix: align meganova provider slug
* feat(providers): integrate wave2 free-tier gateways
* feat(providers): add Wave 3-A free-tier registries
* feat(providers): add HelyxAI Auriko and Poixe registries
* feat(providers): add Naga AI and Chat Oripe registries
* feat(providers): integrate wave3 free-tier gateways
* feat(providers): add FreeInference registry
* feat(providers): add Free.ai registry
* feat(providers): integrate wave4 free-tier gateways
* feat: add RTL layout compatibility CSS (fixes #7680) (#7987)
Co-authored-by: Austin Liu <austinliu@Austins-MacBook-Air-3.local>
* [v3.8.50] feat(ci): extend i18n glossary-consistency gate to ko (#8244)
* fix(dashboard): correct machine-translated Korean UI strings in ko.json
Fix 527 mistranslated values in the Korean locale, all verified against
the en.json source:
- Restore protected product/protocol names garbled by machine translation
(응록→ngrok, 인류/인류학→Anthropic, 쌍둥이자리→Gemini, 반중력→Antigravity,
꼬리비늘 깔때기→Tailscale Funnel, 진공→VACUUM, 우편번호→ZIP)
- Fix wrong-sense homonym translations (달리기→실행 중 for Running,
장애인→비활성화됨 for Disabled, 열쇠→키 for Key, 안타→적중 for Hits,
유물→아티팩트 for Artifacts, 건강검진→상태 확인 for Healthcheck)
- Repair translated identifiers that broke literal values (양말5→socks5,
볼록-세션-id→convex-session-id, 채팅/완료→chat/completions,
메시지/보내기→message/send JSON-RPC methods)
- Replace key-name dumps shipped as values ("Table Name", "Overview
Title", "Cli Tools Redirect Title" etc.) with real Korean translations
- Unify ngrok casing (Ngrok→ngrok) and trailing punctuation with the
English source; align terminology across fixes (공급자, 폴백, 사용자 정의)
All {placeholder} tokens, markdown, and protected terms preserved
verbatim; i18n UI coverage and ko validation gates pass.
* feat(ci): extend i18n glossary-consistency gate to ko
Follow-up to #8224 (ko.json mistranslation cleanup): the glossary gate
only checked zh-CN, leaving the Korean catalog unguarded against the
next machine-translation run reintroducing the garbage it fixed.
- Add scripts/i18n/glossary/ko.json: 9 canonical concepts (provider,
fallback, running/disabled states, key, export, healthcheck, port,
artifacts) plus protectedTermMistranslations for 10 verified garbled
renderings (응록→ngrok, 인류→Anthropic, 쌍둥이자리→Gemini,
반중력→Antigravity, 꼬리비늘→Tailscale, 진공→VACUUM, 양말5→socks5,
우편번호→ZIP, 클로드→Claude, 옴니루트→OmniRoute)
- Extend check-glossary-consistency.mjs to merge per-locale
protectedTermMistranslations from the glossary file with the legacy
zh-CN KNOWN_MISTRANSLATIONS map (behavior for zh-CN unchanged)
- Add ngrok/Anthropic/Claude/Gemini/Antigravity/Tailscale/VACUUM/
socks5/ZIP to protected-terms.json
- Wire --locale=ko into the i18n-glossary CI job and add the
i18n:check-glossary:ko npm script
- Tests: merge semantics (3 new unit tests), #8224 regression guards
for src + bin/cli ko catalogs, and real-file pass assertions for ko
Every enforced synonym/mistranslation was verified to have zero
occurrences in both real ko catalogs; collision-prone candidates
(안타 ⊂ 안타깝게도, 배우 ⊂ 배우기) were deliberately excluded.
* test(tail): retire stale i18n __MISSING__ repro + fix qianfan website URL (#8263)
Base-red slice 6, rebased onto the advanced release/v3.8.49 (91fd5f9). The oauth
grok-cli #7610 guard was already fixed on the base by #8027 (it reads the warning
from grokCliAuthJson.ts) — dropped from this slice to avoid a conflicting duplicate.
Remaining two, still red on the current base:
- i18n #7258: the "focused repro" asserted zh-TW.json STILL carries raw __MISSING__:
placeholders. That backlog was filled (the "no locale has a raw __MISSING__: leaf"
invariant is the durable guard); retired the now-inverted repro.
- qianfan: Baidu renamed the product page (product/wenxinworkshop -> product-s/
qianfan_home); updated the expected website URL.
Validated (clean env): i18n 4/0, qianfan 5/0; oauth-modal-grok 2/0 already green on base.
Co-authored-by: Probe Test <probe@example.com>
* [v3.8.50] feat(ui): add global model search to Combo builder (#8285)
* Feat: Busca Global de Modelos no Combo Builder
* Fix: assembleStandalone src and dest equality check on Windows
* fix(ui): i18n global model search + drop pnpm-lock + extract search panel
- Drop pnpm-lock.yaml (repo is npm-workspaces; package-lock.json is canonical).
- i18n: replace hardcoded Portuguese strings in the new global model search
UI (Combo Builder) with getI18nOrFallback()/t() EN-fallback calls; add the
10 new keys (builderModeStep, builderModeGlobal, builderGlobal*) to en.json
and propagate __MISSING__ placeholders to all 42 locales.
- Extract the mode-toggle + global-search panel JSX into a new
GlobalModelSearchPanel component, and the allGlobalModels/
filteredGlobalModels/add-step/add-all logic into pure, unit-tested helpers
(buildGlobalModelList, filterGlobalModelList, addGlobalModelStep,
addAllGlobalSearchMatches) in src/lib/combos/builderDraft.ts, keeping
combos/page.tsx under its frozen file-size budget.
- Revert the unrelated local-tooling .source/dynamic.ts one-liner to match
origin/release/v3.8.49.
- Add unit tests for the new builderDraft helpers.
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
---------
Co-authored-by: Gleisson de Jesus Santos <T034183@embasanet.ba.gov.br>
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
Co-authored-by: ikelvingo <im.kelvinwong@gmail.com>
Co-authored-by: Diego Rodrigues de Sa e Souza <diegosouza.pw@gmail.com>
Co-authored-by: diegosouzapw <diegosouzapw@users.noreply.github.com>
* [v3.8.50] feat: extract CloakBrowser/browser-pool into optional plugin package (#8299)
* fix: align three stub implementations with original code
- chatUrlMatcher: restore original 3-arg signature (u, matchDomain, chatUrl)
with PLACEHOLDER-aware path segment matching
- shouldUseGrokBrowserBacked: remove required param, restore env-var logic
checking both WEB_COOKIE_USE_BROWSER and OMNIROUTE_BROWSER_POOL
- browserPool.ts: add Turbopack rationale comment and join-trick helper
to satisfy the optional-import test assertions
- browserBackedChat.ts: replace any types with typed BrowserPoolModule interface
Verification: 40/40 browser node:test pass, typecheck:core 0 errors
* fix: remove duplicate getMod/modPromise in browserBackedChat stub
Two copies of the module proxy got committed — the typed BrowserPoolModule
version at lines 50-56 and a stale any-typed duplicate at lines 64-71.
Removed the duplicate, keeping the typed version.
Verification:
- 40/40 browser tests pass (both previously-failing suites now green)
- typecheck:core: 0 errors
- env kill switch (OMNIROUTE_BROWSER_POOL=off): verified
* fix(pr-8299): address all 5 review issues
Issue #1: Add @omniroute/browser-pool path to root tsconfig.json paths
Issue #2: Fix tryBackedChat fallback — call browserBackedChat outside if(loaded) guard
Issue #3: Fix grokClearance stub signature (signal?: AbortSignal) → string|null
Issue #4: Add comment clarifying async __resetBrowserPoolMetricsForTest vs upstream sync
Issue #5: Add test case for package-absent fallback in tryBackedChat
All 25 browser tests pass across 4 suites. typecheck:core passes.
* chore: move sqlite-vec to optionalDependencies, fix js-tiktoken static import
Both changes ensure native binary dependencies are properly categorized as optional:
- sqlite-vec: moved from dependencies to optionalDependencies. Only used via
lazy _require("sqlite-vec") in vectorStore.ts — zero static imports.
- js-tiktoken: already in optionalDependencies, import changed to createRequire
pattern to avoid crash when package is not installed (same pattern as sqlite-vec
in vectorStore.ts).
Resolves ScoutDeps findings from browser-pool pluginization audit.
* docs(issues): fix stale interfaces.ts path in browser-pool proposal
The proposal originally planned open-sse/interfaces/browserPool.ts for
the BrowserPoolProvider interface, but the shipped implementation puts
it in packages/browser-pool/src/interfaces.ts instead. Update the
references so the doc matches what was actually built — the stale
path was tripping check:fabricated-docs (--strict).
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
* fix: sync package-lock.json with playwright 1.62.0
Co-authored-by: oyi77 <oyi77@users.noreply.github.com>
* test: keep browser warmup disabled in tryBackedChat unit tests
* fix(pr-8299): keep grokClearance on the evolved release implementation (rebase reconciliation)
---------
Co-authored-by: oyi77 <oyi77@users.noreply.github.com>
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
Co-authored-by: diegosouzapw <diegosouzapw@users.noreply.github.com>
* [v3.8.50] fix(adobe-firefly): live x-arp-session-id / Arkose wire (stop HTTP 408) (#8571)
* feat(adobe-firefly): reference image attach + /v1/images/edits (follow-up #8006)
Upload source images to Firefly storage (POST /v2/storage/image) and attach
them as referenceBlobs on generate-async, matching live firefly.adobe.com
captures (usage:general for nano multi-ref; usage:subject for gpt-image).
Also wire built-in adobe-firefly through OpenAI-compatible POST /v1/images/edits
(multipart or JSON data URLs, up to 4 refs) so Media edit-with-references
and Open WebUI image-edit hit the same path as image2image generate.
Unit suite: tests/unit/adobe-firefly.test.ts 41/41.
* test(api): add route-level coverage for Adobe Firefly /v1/images/edits + fix typecheck/file-size drift
Covers the referenceBlobs upload path, the 4-reference cap error, and the
credentials/rate-limit branches added to the /v1/images/edits route for
adobe-firefly (#8510). Also fixes a Buffer/BodyInit typecheck mismatch in
uploadAdobeFireflyImage and corrects the adobeFireflyClient.ts file-size
baseline entry to match the gate's actual LOC count (it counts the trailing
newline, so the frozen value is 2317, not 2316), plus a testFrozen entry for
adobe-firefly.test.ts's own +159 line growth from this PR. Moves the
handleAdobeFireflyImageGeneration re-export out of the middle of the import
block in imageGeneration.ts for readability.
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
---------
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
* [v3.8.50] fix(adobe-firefly): durable session, Chrome recovery, browser sign-in (#8578)
* fix(adobe-firefly): durable session, off-screen Chrome recovery, browser sign-in
Rebuild x-arp-session-id from Cookie pieces (sid/ark/forter) so aux_sid is never
sent as ARP. Sticky ARP + submit spacing reduce mid-batch colligo 408 thrash.
Add optional managed Chrome warm (off-screen headed by default; Forter rejects
headless) and POST /api/providers/{id}/login browser sign-in that returns JWT+Cookie
after a fresh SSO. Visible sign-in resets off-screen window placement and clears
prior Adobe session when adding another account.
* fix(adobe-firefly): cast Node Buffer to ArrayBuffer and harden chrome runtime null close
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
* fix(docs): sync docs-counts gate and env var contract for adobe-firefly
Update executor/OAuth-provider counts in ARCHITECTURE.md and
CODEBASE_DOCUMENTATION.md to match the real code (89 executors, 21
OAuth providers), and document the Adobe Firefly Chrome-driven
session-refresh env vars in .env.example and ENVIRONMENT.md so the
env/docs contract tests pass.
Co-authored-by: artickc <artickc@users.noreply.github.com>
---------
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
Co-authored-by: diegosouzapw <diegosouzapw@users.noreply.github.com>
Co-authored-by: artickc <artickc@users.noreply.github.com>
* fix(github): honor per-model targetFormat override for Copilot custom models (#8713)
GithubExecutor.buildUrl() only consulted the static PROVIDER_MODELS registry
via getModelTargetFormat("gh", model), so a custom Copilot model (e.g.
gpt-5.6-terra/gpt-5.6-luna) with its dashboard "Target Format" set to
OpenAI Responses API always still routed to /chat/completions and got
rejected upstream with "model ... is not accessible via the
/chat/completions endpoint" — the setting had no effect on real routing.
chatCore already resolves the correct per-request targetFormat (including
the custom-model override) via resolveChatCoreTargetFormat(), but that value
was never threaded past chatCore into the executor's own URL-building
decision. Mirrors the zai/glm-coding-apikey fix (#7364) for the identical
class of bug: chatCore/executionCredentials.ts now surfaces the resolved
override onto providerSpecificData.targetFormat when it resolves to
openai-responses for the github provider, and GithubExecutor.buildUrl()
prefers that value over the static registry lookup when present.
Verified: 6 new regression tests plus all 95 pre-existing github/executor
tests green.
Co-authored-by: Wital <wital@example.com>
* fix(test): revive orphaned vitest tests and fix CI routing (#8718)
* [v3.8.50] fix(api): serve stale model catalog during refresh (#8728)
* fix(api): make model catalog refresh response-safe
* fix(api): invalidate model catalog mutation paths
* fix(db): preserve aliases backup import after catalog rebase
---------
Co-authored-by: Erick Kinnee <erick@ekinnee.dev>
* fix(antigravity): quota-aware account selection and projectId persistence (#8891)
* fix(antigravity): per-model quota + 30min credits_exhausted reprobe
- accountFallback.ts: hasPerModelQuota() now treats antigravity/agy as
per-model quota. A single-model 429 no longer cascades to all models
in the provider.
- connectionRecovery.ts: credits_exhausted removed from terminal set;
isCreditsExhaustedReprobeCandidate() with 30min default. Loads
active+inactive rows so inactive credits_exhausted accounts can recover.
- tests/unit/quota-connection-recovery.test.ts: 6 cases covering pure
helpers + tick wiring.
* fix(antigravity): persist projectId and prefer healthy accounts
Save Cloud Code projectId after runtime discovery, skip accounts missing
projectId when alternatives exist, and mark missing_project_id on 422.
* fix(antigravity): skip quota-exhausted models during account selection
Avoid repeatedly dispatching to Antigravity models that already report
exhausted quota, reducing wasted upstream calls and combo fallback latency.
---------
Co-authored-by: hermes <hermes@nous.local>
* feat(alibaba): free-tier routing with live quota sync (#8893)
* feat(alibaba): add free-tier routing with console quota and builtin allowlist
Classify DashScope free vs paid models via console quota API, a hardcoded
operator allowlist fallback, and per-connection drained tracking. Wire wildcard
combo expansion, model refresh, combo exhaustion, and audit redaction for
Alibaba console credentials.
* fix(routing): reset forced connection pin and persist Alibaba free-tier drain
Drop session affinity pins when a forced connection is excluded after 429,
and record Alibaba free-tier exhaustion on upstream 403 so per-key drained
lists stay accurate without blocking sibling keys.
* fix(alibaba): prefer live quota sync over static free-tier allowlist
Stop unioning the builtin text allowlist when a console quota snapshot exists,
treat expired quotaValidityPeriod as not_capable, and add a dated JSON pack plus
sync-alibaba-allowlist script for operator refresh without code edits.
* docs(alibaba): document free-tier console path + allowlist env overrides
Adds the 4 ALIBABA_FREE_TIER_*_FE_PATH / ALIBABA_FREE_TIER_ALLOWLIST_PATH
env vars (referenced by alibabaFreeTierQuotaFetcher.ts and
alibabaFreeTierAllowlist.ts) to .env.example and
docs/reference/ENVIRONMENT.md so the env/docs contract check passes.
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
* refactor(open-sse): split alibabaFreeTierQuotaFetcher.ts under file-size cap
Extract pure parsing/classification/eligibility-filtering logic into
alibabaFreeTierQuotaClassify.ts and shared types/primitives into
alibabaFreeTierQuotaTypes.ts, leaving the HTTP/console-fetch flow in the
original file. Public API is unchanged (re-exported), behavior is identical.
Co-authored-by: AndrianBalanescu <AndrianBalanescu@users.noreply.github.com>
* fix: resolve typecheck errors in alibaba-free-tier routing
---------
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
Co-authored-by: diegosouzapw <diegosouzapw@users.noreply.github.com>
Co-authored-by: AndrianBalanescu <AndrianBalanescu@users.noreply.github.com>
Co-authored-by: AndrianBalanescu <andrian@balanescu.dev>
* feat: improve provider quota layouts (#8916)
* feat: improve provider quota layouts (#8916)
Adds Full/Compact layout toggle for provider quota cards. Compact mode
shows condensed card grid with key metrics; Full mode shows expanded
detail. Toggle persists via localStorage.
Changes:
- ProviderLimits/index.tsx: layout mode state + toggle button
- QuotaCardGrid.tsx: compact/full card rendering
- ProviderQuotaWidget.tsx: compact/home view
- HomePageClient.tsx: minor wiring fix
- tests/unit/quota-card-grid-compact-layout-8916.test.ts: structural guard
- file-size-baseline.json: rebaseline for ProviderLimits/index.tsx (1163)
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
* fix(ci): restore providerId contract + reorder grid source + rebaseline translator drift
- ProviderQuotaWidget.tsx: restore size={18} on non-compact ProviderIcon
to satisfy base-branch test #3064 pinned contract.
- QuotaCardGrid.tsx: reorder branches so non-compact (default) layout
renders first in source. Same runtime behavior; satisfies base tests
#3520/#6815/#7072 that inspect the first div/grid-cols class.
- file-size-baseline.json: bump testFrozen translator-openai-to-gemini
1619->1622 (+3 upstream drift absorbed in merge of release/v3.8.50).
Closes upstream CI: Unit Tests 2/4, 3/4, 4/4 + Fast Quality Gates.
codeql-ratchet is upstream repo-wide (not our code) — external.
---------
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
* fix(i18n): localize SubscriptionTab UI strings instead of hardcoded Chinese (#8930)
The proxy subscription tab (System -> Proxy -> Subscriptions) displayed
Chinese text regardless of the selected language. The component called
useTranslations("settings") but bypassed t() for all ~50 UI strings.
- Replace every hardcoded Chinese string in SubscriptionTab.tsx with
t("proxySubscription.<key>") calls
- Add 53 new keys under settings.proxySubscription to en.json (English)
and zh-CN.json (Chinese) with full manual translations
- Propagate to all 41 other locales via generate-multilang.mjs (Google
Translate), per docs/guides/I18N.md workflow
All 42 locales at 100% i18n coverage with zero __MISSING__ markers.
* Fix custom tool output pairing during context compression (#8933)
* Fix custom tool output pairing during compression (#8932)
* Bypass proxy compaction for native Codex context
* fix(sse): extract Codex tool-call output repair to leaf module for file-size gate
repairMissingCodexToolCallOutputs (added by #8932 for custom_tool_call
pairing) pushed codex.ts past the frozen file-size baseline. Extract it
to open-sse/executors/codex/toolCallRepair.ts, leaving only the wiring
call in codex.ts. Rebaseline the test file's genuine +41 line growth
from #8932's new custom_tool_call_output coverage.
Co-authored-by: JxnLexn <JxnLexn@users.noreply.github.com>
---------
Co-authored-by: diegosouzapw <diegosouzapw@users.noreply.github.com>
Co-authored-by: JxnLexn <JxnLexn@users.noreply.github.com>
* feat(combos): let combo builders test providers and add only working models (#9011)
* fix(sse): preserve Claude Code tool-name casing via Gemini/Antigravity (#9008) (#9016)
Stop blindly lowercasing PascalCase tool_use names on the Gemini→Claude path so Claude Code no longer rejects Read/WebSearch as missing tools.
* fix(vision): preserve images for text-only routes (#9037)
* fix(vision): preserve images for text-only routes
* fix(i18n): complete Vietnamese vision bridge copy
* fix(ci): drain prerelease tag input
---------
Co-authored-by: rinseaid <rinseaid@rinseaid.net>
* feat(i18n): complete zh-CN localization for compression engines and dashboard UI (#9038)
* feat(i18n): complete zh-CN localization for compression engines and dashboard UI
- Translate all compression engine names and descriptions (Caveman, Lite,
Aggressive, Ultra, OmniGlyph, Headroom, Session Dedup, RTK, CCR, LLMLingua)
- Translate all __MISSING__ entries (50+ strings) across settings, cache,
OAuth, compression exclusions, and provider onboarding
- Translate hardcoded dashboard UI strings (analytics tables, playground,
cliproxy/9Router exposure cards, Qdrant config, OneProxy, forgot-password)
- Localize PWA manifest and A2A agent card (manifest.ts, agent.json route)
- Add missing translation keys (hermes roles, API protocol, embedded services,
memory/Qdrant, Obsidian, Codex auto-ping, reasoning routing)
* fix(i18n): restore cliCommon.comparison.acp keys dropped in the release merge
The release merge kept only the author's translated `flow` value and dropped
`title`, `desc` and `examples`, which exist on every sibling entry
(code/agent). Restore the three from the release while keeping the author's
`flow` translation.
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
---------
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
* fix(resilience): recover idle-capacity limiter wedges early (#9041)
* fix(resilience): recover idle-capacity limiter wedges early
* docs(changelog): note limiter wedge recovery
* fix(resilience): harden limiter wedge recovery
* fix(resilience): close limiter recovery review gaps
* test(resilience): preserve scoped exhaustion guards
* docs(changelog): remove self-credit suffix
* test: include limiter regressions in mutation coverage
* chore(quality): reconcile v3.8.50 file-size baselines
* fix(docs): add WAF MDX title frontmatter
* fix(docs): complete WAF frontmatter metadata
* fix: skills & memory — tool-name encoding, schema normalization, warm-cache, combo id, Ponytail catalog (#9058)
* feat(skills): add Ponytail minimalism skill as external catalog entry
- Add 'external' SkillCategory + SkillArea
- Register ponytail (MIT, DietrichGebert/ponytail) in CURATED_SKILLS
- Generator: external skills carry content in custom block, no api/cli body
- Generate skills/ponytail/SKILL.md with original content preserved
- Update catalog test counts 45 -> 46
* fix(skills+memory): builtin handler fallback in executor, skip vector upsert for deleted memories
- skills: Next.js compiles SkillExecutor into multiple chunks (own singleton
each); route chunk lacked builtin handlers registered at startup via
instrumentation. execute() now falls back to builtinSkills registry, so
POST /api/skills/executions works for file_read/web_fetch/etc.
- memory: scheduleVectorUpsert is fire-and-forget and embeddings are slow;
health-check verify (create->delete test memory) left queued upserts
failing with 'memory not found' every 30s. Check existence before embedding
and skip quietly.
* fix(skills): encode tool names with @ and . for providers rejecting them
Skill tools were advertised as 'name@version' (e.g. test-fr2@1.0.0), but
DeepSeek/Groq/OpenAI reject function names not matching ^[a-zA-Z0-9_-]+$.
Names already valid are left untouched; invalid ones are reversibly encoded
as omr_skill_<base64url> and decoded in interception before registry lookup.
* fix(combos): include DB id column in combo records for dashboard links
getCombos() selected only data/sort_order/context_cache_protection, so
combos whose JSON blob lacked an id field returned id: undefined. The
dashboard then linked to /dashboard/combos/undefined and Combo Control
Center failed with 'Combo not found'. Merge the id column into parsed
rows (authoritative, only when the blob has no id).
* fix(skills): normalize flat skill schemas to object schema for Gemini/Claude
Stored skill schemas are flat property maps ({ text: { type: string } }),
which OpenAI-compatible providers tolerate but Gemini
(function_declarations[].parameters) rejects with 'Unknown name ... Cannot
find field'. Wrap bare maps into { type: 'object', properties: {...} } for
all three tool formats.
* fix(skills): warm registry cache before skill injection in chat path
injectSkills() lists the in-memory skillRegistry, which is empty after a
cold start until something calls loadFromDatabase(). The interception path
already warms the cache (#2815); the injection path did not, so skills
were silently skipped (no_enabled_skills) for the first requests after
restart. Warm the cache for the chat owner before injection.
---------
Co-authored-by: Egor <egorich-print@users.noreply.github.com>
* fix(translator): honor Chat targets for Responses clients (#9161)
Honor explicit Chat targets for Responses-shaped clients while preserving native Responses providers and selecting token fields from the outbound protocol.
Includes focused regression coverage and the required changelog fragment.
* test(mcp): guard Node 24 bundled MCP startup (#9162)
* feat(cursor): proactively renews Cursor sessions and fixes manual refresh (#9173)
* refactor(cursor): extracts token extraction into shared lib
Moves tryIdeAuth/tryAgentAuth and supporting helpers out of the
auto-import route into src/lib/cursor/tokenExtractor.ts, and adds
an agent-cli-state.json fallback candidate path to tryAgentAuth
(alongside the existing auth.json candidate) so the extraction
logic can be reused by the upcoming renewal orchestrator.
* feat(cursor): adds cursor-agent-backed token renewal orchestrator
Builds the renewal orchestrator in src/lib/cursor/renewal.ts: a
bounded, unattended-safe --list-models nudge, a side-effect-free
status availability check, an in-flight spawn lock keyed by
command, and renewCursorConnection() which nudges cursor-agent
then independently re-scrapes the IDE and cursor-agent credential
sources to detect whichever refreshed. Extends cursorAgent.ts's
binary resolution and spawn helper with fixed-paths-only mode and
a SIGKILL follow-up for background use. Adds a generic keyed-mutex
utility (src/shared/utils/keyedMutex.ts) for serializing a
connection's renew-then-persist cycle, and forwards a busy-timeout
through driverFactory's node:sqlite fallback path.
* feat(cursor): proactively renews Cursor sessions in the sweep
Adds src/lib/tokenHealthCheckCursor.ts, sweep-side glue that calls
the renewal orchestrator and persists the result, wired into
tokenHealthCheck.ts's checkConnection() via a new Cursor-specific
branch placed ahead of the generic no-refresh-token fallthrough.
Carves out a non-terminal exception for a Cursor connection that
already landed at testStatus "expired" via the request-time 401
path, excluding permanently-dead account_deactivated connections.
Extends buildRefreshFailureUpdate() with an overrides param so
Cursor's failure path can use a distinct, non-terminal errorCode
instead of the generic refresh_failed/expired taxonomy.
* feat(cursor): adds local-only manual refresh route
Adds POST /api/providers/[id]/refresh-cursor, a dedicated
loopback-only route that calls the renewal orchestrator on demand
for a single Cursor connection, bounded by a 30s per-connection
cooldown. Classifies the new route in LOCAL_ONLY_API_PATTERNS and
closes the manage-scope-bypass gap for dynamic-segment spawn-capable
routes under /api/providers/ via a new SPAWN_CAPABLE_PATTERNS /
SPAWN_CAPABLE_PATTERN_ANCESTORS mechanism, which also retroactively
covers the pre-existing /login route. The existing shared
/api/providers/[id]/refresh route is untouched and stays
remote-reachable for every other provider.
* feat(cursor): surfaces a dismissible cursor-agent nudge
Adds GET /api/providers/cursor/agent-availability, a credential-free
LOCAL_ONLY route returning only { cursorAgentAvailable: boolean },
backed by a 5-minute cached wrapper around the renewal orchestrator's
existing availability check. Surfaces a dismissible dashboard banner
on the Cursor provider page suggesting cursor-agent installation
when it isn't detected, following the existing dismissible-banner
convention. Also fixes a pre-existing bracket character in a
routeGuard.ts comment that was silently truncating
check-openapi-security-tiers.mjs's view of LOCAL_ONLY_API_PREFIXES.
* fix(cursor): wires manual refresh button to the new route
Branches handleRefreshToken to call the dedicated Cursor refresh
route instead of the generic /refresh route, which silently 502s
for Cursor connections today since they carry no refresh token.
Every other provider's refresh behavior is unaffected. Adds the
cursorSessionUnchanged i18n key and syncs it (plus a pre-existing,
unrelated 28-key backlog) across all 42 locale files.
* fix(cursor): addresses Phase 4/4.5 review findings
Restores the legacy stdout/stderr auth-pattern fallback in
checkCursorAgentAvailability() that the plan's Task 2 Step 4
required but the implementation had dropped. Threads an optional
deps parameter through checkCursorConnectionIfNeeded() so its
error branch is reachable in tests, and switches both it and the
manual-refresh route to exhaustive switch statements over the
renewal result. Adds a short-lived host-keyed dedup cache around
tryIdeAuth() so multiple due Cursor connections sharing a host
don't each open the same state.vscdb file in one sweep tick.
Adds opportunistic eviction to the manual-refresh cooldown map,
an outer try/catch to the availability route for defense-in-depth
consistency with the plan's other routes, and corrects a stale
JSDoc claim about the /login route's auth check. Documents the
now-empirically-confirmed agent-cli-state.json schema mismatch
found while validating against a real cursor-agent install.
* docs(cursor): adds changelog fragments for the renewal plan
Adds one fragment per user-facing outcome per changelog.d/README.md's
convention for a PR that both fixes and adds. PR number placeholder
to be filled in once the PR is opened.
* fix(i18n): translates the new Cursor keys into Vietnamese
The i18n:sync-ui run in an earlier commit left __MISSING__
sentinels for the 4 new Cursor keys in every locale, but
Vietnamese has a dedicated completeness test requiring zero
internal missing markers. Provides real translations for
cursorSessionUnchanged, cursorAgentNudgeTitle,
cursorAgentNudgeBody, and cursorAgentNudgeDismiss.
* fix(cursor): addresses quality-gate Layer 1.5 findings
Restores a comment that misrepresented execFile's actual argv shape
after an earlier bracket-removal fix, this time avoiding literal
closing-bracket characters entirely so the openapi checker's naive
array parser can't be broken by either version. Bounds the sweep-
and manual-route-triggered tryIdeAuth() busy-timeout to 250ms
(down from the interactive auto-import path's 2000ms), since both
share the main event loop with all other in-flight requests and
should fail fast on a WAL-lock collision rather than block the
whole instance for up to ~4s. Has the manual refresh route bypass
the sweep's IDE-auth dedup cache so a click always sees a fresh
read, consistent with this plan's existing "manual actions never
see stale cached data" convention. Documents the previously-missing
agent-availability route in ROUTE_GUARD_TIERS.md's spawn-capable
table.
* fix(cursor): adds SIGKILL follow-up to the status-check spawn
Matches the nudge spawn's existing SIGTERM+SIGKILL pattern so an
unresponsive cursor-agent status check can't leak a lingering
process if it ignores SIGTERM.
* docs(cursor): fills in the PR number for changelog fragments
Renames the 3 changelog.d fragments to their PR-numbered filenames and replaces the (#PR) placeholder with #9173, now that the PR exists.
* fix(cursor): corrects changelog fragments to reference PR #9173
The prior commit only staged the git mv rename — a git add invocation with a stale (pre-rename) pathspec aborted before the actual (#PR) -> (#9173) content edit was staged, so the rename landed without the fix it was meant to carry. This captures the actual content change.
* docs(cursor): regenerates the agent-skills catalog for the new route
check:agent-skills-sync (CI's Merge integrity gate) requires SKILL.md files to stay in sync with the live route catalog. Adding /api/providers/cursor/agent-availability in an earlier commit needed a regen this branch never ran.
* chore(quality): rebaselines file-size caps grown by agentrouter merges
Two already-merged agentrouter commits (564c204ef, ec150a006) on release/v3.8.50 grew open-sse/executors/base.ts, open-sse/handlers/chatCore.ts, and tests/unit/chatcore-translation-paths.test.ts past their frozen caps before this PR branched — unrelated to the Cursor renewal changes here. No PR branch is left to fix the growth in-place, so the caps are bumped to the current real sizes, following the existing release-green rebaseline precedent in this file.
* fix(sse): imports getModel helpers from db/models, not localDb
A recently-merged agentrouter commit added a @/lib/localDb import in chatCore.ts, violating the no-restricted-imports rule (Hard Rule #2 — never barrel-import from localDb.ts). Points the import at the owning module, src/lib/db/models.ts, where both functions are actually defined, and prunes the now-stale suppression entry.
* fix(sse): scopes CC-relay anthropic-beta to its own requestDefaults
Two already-merged agentrouter commits widened usesClaudeCodeProtocol()'s native-Claude system-transform block (billing header + selectBetaFlags-derived anthropic-beta) to also run for generic CC-compatible relay connections, not just real claude traffic and agentrouter's own wire-image mimicry. selectBetaFlags() has no visibility into a relay's own providerSpecificData.requestDefaults, so its header replacement silently wiped out an earlier context-1m append and force-included redact-thinking regardless of the relay's own opt-in. Restores both for plain CC-compatible relays only; real claude/agentrouter traffic is unaffected.
Also bumps four stale hardcoded Codex/Claude Code CLI version-string test assertions (0.144.1->0.146.0, 2.1.219->2.1.220) that drifted when the same two commits bumped the version constants without updating their tests, and rebaselines base.ts's frozen file-size cap for this fix's own +35 lines.
* fix(sse): preserves bare CC-relay native treatment and context-1m
The previous commit's fix was too broad in one direction: excluding ALL CC-compatible relays from the native-Claude header block broke two pre-existing tests (cc-compatible-provider.test.ts, v3.6.6) that rely on that treatment for a 'vanilla' relay with no providerSpecificData.requestDefaults configured.
Refines the gate to this whole native-Claude header-replacement block: replace headers for real claude traffic, agentrouter's wire-image mimicry, OR a CC-relay with no requestDefaults at all — only a relay with EXPLICIT requestDefaults (context1m/redactThinking/summarizeThinking) gets to keep buildHeaders()'s own correctly-computed header set. A redact-thinking-beta strip (unconditional, a no-op when native treatment didn't apply) covers the one remaining gap: selectBetaFlags() force-includes it for a bare relay's opaque client, which a bare relay never explicitly opted into.
Verified against all three previously-conflicting pre-existing tests simultaneously: executor-default-base.test.ts's '1M beta' test, both cc-compatible-provider.test.ts SSE-forcing tests, and provider-request-failure-pipeline.test.ts's 'keeps request beta headers' test (the last of which was already broken by the raw agentrouter merge, confirmed via direct comparison against that exact commit).
* fix(sse): fills in remaining stale CLI version literals
The same two agentrouter commits bumped Codex/Claude Code CLI version constants (0.144.1->0.146.0, 2.1.219->2.1.220) without updating every hardcoded test assertion. This round covers the ones the previous version-string commit missed: the anthropic-cache-fingerprint billing-version constant, a cc-bridge-transforms body assertion, the UI-mirror parity test's own snapshot plus its RoutingTab.tsx source of truth, an integration test's User-Agent assertion (inconsistent with its own dynamic Version assertion two lines up), and the translate-path golden snapshot. Also updates a stale doc comment referencing the old literal by value instead of by constant name.
* fix(cursor): imports from db/ modules, not the localDb barrel
Both files violated Hard Rule #2 (never barrel-import from localDb.ts) — a genuine lint error that had gone uncaught locally. refresh-cursor/route.ts imported getCachedProviderConnectionById from @/lib/localDb instead of its owning module, @/lib/db/readCache. tokenHealthCheckCursor.ts copied the same pattern from its sibling tokenHealthCheckCopilot.ts (an existing, already-suppressed violation) for updateProviderConnection; imports it from @/lib/db/providers instead, with no circular-import fallout (verified via the existing token-health-check-cursor and refresh-cursor-route test suites).
* fix(db): removes stale raw-SQL allowlist entry for cursor route
The cursor auto-import route no longer contains raw SQL — that query
now lives in src/lib/cursor/tokenExtractor.ts, outside the
route/handler scope check-db-rules scans. The allowlist entry was
stale, tripping the stale-enforcement gate.
* fix(test): registers cursor test files in stryker tap.testFiles
Three unit test files covering mutation-tested modules
(route-guard-cursor-agent-availability, route-guard-cursor-refresh,
cursor-renewal) were missing from stryker.conf.json's tap.testFiles,
tripping the mutation-test-coverage gate's drift detection.
* chore(ci): retriggers checks (stuck GH Actions runner on shard 2/4)
* fix(sse): restores CC-relay context1m/redact-thinking test coverage
Rebasing onto release/v3.8.50's new tip (35405be60, an unrelated
agentrouter protocol-inference commit) silently flipped two assertions
this branch's own earlier fix (687fbda62) depends on, in the same test
files that commit touched for other reasons:
- executor-default-base.test.ts: calls[0] (a bare CC-relay with no
requestDefaults) expected redact-thinking-beta absent; flipped to
present. calls[1] (context1m+redactThinking requestDefaults) expected
the context-1m beta preserved; flipped to absent.
- provider-request-failure-pipeline.test.ts: expected Accept:
text/event-stream and the context-1m beta present for a relay with
explicit requestDefaults; flipped to application/json and absent.
35405be60 did not touch open-sse/executors/base.ts at all, so these
were test-only edits made without visibility into the still-unmerged
CC-relay header-preservation fix on this branch — they quietly matched
the assertions back to the pre-fix (buggy) behavior instead. Restores
the original, validated expectations; all three interdependent test
files (executor-default-base, cc-compatible-provider,
provider-request-failure-pipeline) verified passing together again.
* ci: re-trigger checks after GitHub Actions incident (2026-08-07, resolved)
* ci: re-trigger checks (previous push event was dropped)
* fix(quality): restore dropped vi.json cursor-renewal keys + rebaseline test growth
vi.json was missing 4 keys (cursorSessionUnchanged, cursorAgentNudgeTitle/Body/Dismiss) that this PR's own pre-merge branch had translated -- the original merge's 'git checkout --theirs' resolution for the 7 conflicted locale files discarded them since upstream's vi.json has no cursor-token-renewal feature. Restored from pre-merge tip a38003e30. Also rebaselines combo-routing-engine.test.ts (3457->3464) for the comment growth from the ALL_ACCOUNTS_INACTIVE fix, caught by CI's PR-mode check:file-size.
* chore(tests): drop explanatory comments on ALL_TARGETS_SKIPPED assertions
Kept the assertion value fix (ALL_ACCOUNTS_INACTIVE -> ALL_TARGETS_SKIPPED); the comments were unnecessary. Reverts the file-size baseline bump these comments caused (combo-routing-engine.test.ts back to its original 3457).
* fix(dashboard): make connection Default Model editable and optional (#9172) (#9179)
* fix(dashboard): make connection Default Model editable and optional
* docs(changelog): retitle fragment with PR number
---------
Co-authored-by: Diego Rodrigues de Sa e Souza <diegosouza.pw@gmail.com>
* fix(combo): recover provider circuit breaker from HALF_OPEN on success (#9207)
The combo success path called recordProviderSuccess (cooldown-only)
without notifying the circuit breaker. When a provider breaker entered
HALF_OPEN after repeated failures, successful probe requests never
transitioned it back to CLOSED -- the breaker stayed stuck indefinitely.
Production evidence: agy breaker HALF_OPEN with 699 requests at 98%
success rate, never recovering.
Root cause: combo.ts calls recordProviderSuccess from
providerCooldownTracker.ts (resets cooldown failureCount only) but
never calls breaker._onSuccess(). The failure path in accountFallback.ts
calls breaker._onFailure(), creating an asymmetry.
Fix: add recordProviderSuccess to accountFallback.ts as the symmetric
counterpart of recordProviderFailure. Uses getProviderBreaker (not
configureProviderBreaker) to avoid overwriting the breaker's resetTimeout
with default profile values. Calls breaker._onSuccess() for all non-OPEN
states (CLOSED/DEGRADED/HALF_OPEN), matching execute()'s behavior.
* fix(command-code): preserve literal max effort for command-code provider (#9257)
* fix(command-code): preserve literal max effort for command-code provider
* test(command-code): type the new sanitizeReasoningEffortForProvider assertions
The 3 new command-code reasoning-effort test cases cast the function's
unknown return value with `as any`, which pushes the file's frozen
no-explicit-any suppression count (48) to 51 and trips the "No new
ESLint warnings" gate. Use a minimal EffortCarrierResult shape instead
of any, matching the fields the assertions actually read.
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
* test(v1-models): type the API key lookup in the #9320 auth-leak regression test
The release-tip test file added by #9320 used `(k: any)` in an Array.find
callback, which is not covered by config/quality/eslint-suppressions.json
(the file was added after the suppressions snapshot was frozen). That
leaves the "No new ESLint warnings" gate red for any branch that merges
this exact release/v3.8.50 tip, unrelated to this PR's own diff. Fixing
it here with a minimal derived type (Awaited<ReturnType<typeof
getApiKeys>>[number]) unblocks the gate without touching the frozen
suppressions baseline.
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
---------
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
* feat(sse): server-side template expansion for combo system prompts (#5501) (#9414)
* feat(sse): server-side template expansion for combo system prompts (#5501)
* fix(quality-gates): register combo-system-prompt-templates-5501 test in stryker tap.testFiles
check:mutation-test-coverage --strict flagged tests/unit/combo-system-prompt-templates-5501.test.ts
as covering src/shared/utils/circuitBreaker.ts without being listed in stryker.conf.json
tap.testFiles, so its mutant kills wouldn't count.
Co-authored-by: maxmad64bis <maxmad64bis@users.noreply.github.com>
---------
Co-authored-by: Max <maxmad64@gmail.com>
Co-authored-by: diegosouzapw <diegosouzapw@users.noreply.github.com>
Co-authored-by: maxmad64bis <maxmad64bis@users.noreply.github.com>
* fix(translator): normalize streamed optional tool arguments (#9423)
* fix: preserve Codex cache usage for Claude suggestions
Co-Authored-By: Claude <noreply@anthropic.com>
* fix: normalize streamed optional tool arguments
Co-Authored-By: Claude <noreply@anthropic.com>
---------
Co-authored-by: Kittisak Tangsiri <kittisak@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
* ci: re-trigger checks after GitHub Actions incident (2026-08-07, resolved) (#9441)
* fix(sse): preserve client cache boundaries when hoisting system roles (#9457)
Hoisting a mid-conversation `system`/`developer` message into the top-level
`system` field carried its `cache_control` marker along. Anthropic assembles the
cache prefix as tools -> system -> messages, so the marker ended the cached
prefix at the system block and left the accumulated conversation without a
breakpoint: that turn was billed as fresh input and the next one rebuilt the
cache.
`relocateHoistedCacheBoundary` moves the marker to the nearest preceding block
that can carry a breakpoint, skipping thinking blocks, empty text and anything
the upstream normalisation discards or empties out. If that block already
carries the client's own marker, both are kept - unless the hoisted one, now
ahead of the target in `system[]`, would put a 5m breakpoint before a 1h one,
which Anthropic rejects; it is dropped in that case. Either way the breakpoint
count never grows.
normalizeClaudeUpstreamMessages rewrites tool_result and inlined file/document
blocks into plain text after the hoist, which silently discarded any marker on
them - including a relocated one. The replacement block now inherits it.
Both hoisting implementations share the helper; a fix touching only
claudeSystemRole.ts would leave extractSystemMessagesToBody broken, and the
native Claude path reaches the former through normalizeClaudeUpstreamMessages.
Capability-gated hoisting for strict providers (#7293) is unaffected.
Fixes #9436
Co-authored-by: LeonG606 <leongudat01@gmail.com>
Co-authored-by: Diego Rodrigues de Sa e Souza <diegosouza.pw@gmail.com>
* fix(adobe-firefly): harden CDP warm, risk session, and browser sign-in (#9549)
* fix(adobe-firefly): open browser sign-in and resolve provider slug in /login
POST /api/providers/[id]/login passed the connection DB id to
inAppLoginService.startLogin, but TOKEN_EXTRACTION_CONFIGS is keyed by
provider slug — so browser login never launched for web-cookie providers.
Adobe Firefly also cannot use cookie extraction: the IMS JWT only appears
on Authorization headers to firefly-3p.ff.adobe.io. Add a dedicated
Playwright interceptor and persist credentials with camelCase keys that
updateProviderConnection actually reads.
* fix(adobe-firefly): use system Chrome/Edge CDP for browser sign-in
Playwright is not available inside the pkg-packaged VibeProxyServices.exe,
so import('playwright') always failed with 'Playwright not installed' and
never opened a window. Launch Chrome/Edge with --remote-debugging-port and
capture the firefly-3p Authorization Bearer via pure CDP WebSocket instead.
* fix(adobe-firefly): live x-arp-session-id / Arkose wire (stop 408 under load)
Browser generate-async requires x-arp-session-id as base64({sid,ark,ftr}) with a
real Arkose blob (sherlockToken). JWT alone frequently returns colligo HTTP 408
system under load while credits still work.
- Match live ftr magic __UDF43-m4_31ck + Arkose pk in synthetic ARP fallback
- Ranked extract of sherlockToken / x-arp from Cookie, HAR, fetch() paste, and
space-joined JWT+ARP (PasswordBox newline collapse)
- Reuse one ARP for storage upload + generate-async
- Clearer 408 errors when browser ARP is missing vs stale
- Unit suite 42/42
* fix(adobe-firefly): durable session ARP rebuild and aux_sid false-positive
Rebuild x-arp-session-id from forterToken/arkose/ff_session_guid instead of
ranking long Cookie pairs (e.g. aux_sid=…) as opaque ARP, which caused colligo
HTTP 408. Cache IMS JWT + cookie sessions, rotate ARP on 408 retries, and keep
Playwright warm-up opt-in only (headless Forter is rejected).
Also expand synthetic ARP shape with bfp/fpjs to match live successful captures.
* fix(adobe-firefly): renew sessions through durable CDP
* fix(adobe-firefly): isolate browser sessions per account
* fix(adobe-firefly): make account login fresh and deterministic
* docs(adobe-firefly): document renewal controls
* fix(adobe-firefly): harden CDP warm, risk session, and browser sign-in
Stop colligo 408 thrash from stale Forter and frozen Google login during
Sign in with browser:
- CDP warm: clear Firefly origin storage + risk cookies (keep SSO); require
forter age under 10 minutes on loop and timeout paths; dual CDP queues;
await Runtime.runIfWaitingForDebugger; profile-lock launch retries
- Session: connectionId fingerprint; write-back JWT+Cookie; warm-fail
cooldown; fail closed risk_session_stale when forter is known-stale
- Client: submit gate around generate-async; max 2 attempts when forter
known-stale; poll 401 one refresh; pass sessionBrowserKey through handlers
- Login route: pure system Chrome/Edge CDP only; camelCase credential persist
- Unit: browser-login + firefly suites green (60)
* fix(adobe-firefly): dedupe CDP session hardening blocks after rebase
Remove duplicated guard blocks and test bodies introduced when rebasing
the CDP session hardening work onto release/v3.8.50, which already
carries the hardened implementation.
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
---------
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
* fix(translator): preserve Kimi K3 Responses reasoning (#9556)
* fix(translator): preserve Kimi K3 Responses reasoning
* fix(translator): make K3 reasoning preservation model-driven
* fix(translator): replay cached Kimi reasoning before fallback
* fix(translator): keep authentic K3 reasoning through cleanup
* refactor(reasoning): use replay policy for K3
* fix(settings): use provider prefixes in model overrides (#9569)
* [v3.8.50] feat(providers): add support for TinyCMS Web (#8736)
* feat(providers): add support for TinyCMS Web including WASM-based cryptographic signing and Proof-of-Work emulation
* feat(providers): add unit tests, ESLint suppressions, and fix hardcoded userid for TinyCMS Web
- Add unit tests for WASM init, UUID validation, challenge flow (15 tests)
- Add WASM source comment explaining binary origin
- Replace hardcoded userid with dynamic provider-specific data
- Add ESLint suppressions for no-explicit-any in WASM bridge code
- Add explanatory comments for DOM shim (runtime WASM-bindgen, not test mocks)
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
* refactor(providers): extract TinyCMS DOM shims into an explicit setup function
tinycmsSigner.ts installed its window/document/HTMLCanvasElement/
CanvasRenderingContext2D shims for the wasm-bindgen glue as a module-load
side effect. That meant merely importing the module (even transitively,
e.g. through the provider registry from an unrelated test) mutated
global state for the rest of the test process.
Extract the shim installation into setupDomMocks(), which returns a
restore callback:
- initTinyCmsWasm() calls it once before instantiating the WASM module
(production path — unchanged behavior, still automatic).
- tests/unit/provider-tinycms-web.test.ts now calls it explicitly in a
`before` hook and restores the previous globals in `after`, so the
shims never leak into other test files.
As a side effect, replacing five separate `as any` casts with a single
typed `global as Record<string, any>` handle drops the file's
no-explicit-any count from 5 to 1; eslint-suppressions.json updated to
match.
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
* docs(providers): regenerate PROVIDER_REFERENCE.md for tinycms-web
Mechanical `npm run gen:provider-reference` run after merging release/
v3.8.50 into this branch — the generated table was stale for both the
new tinycms-web entry this PR adds and the release's own cheaperinference
addition. Total providers 290 -> 292, Web Cookie Providers 31 -> 32.
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
---------
Co-authored-by: diegosouzapw <diegosouzapw@users.noreply.github.com>
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
* [v3.8.50] fix: passthrough non-standard cache token fields for DeepSeek / MiniMax / Bedrock across streaming, non-streaming, and Dashboard paths (#8591)
* fix(#8171): map DeepSeek prompt_cache_hit_tokens into prompt_tokens_details.cached_tokens
DeepSeek native API returns cache stats in flat top-level fields
(prompt_cache_hit_tokens / prompt_cache_miss_tokens) instead of
the standard prompt_tokens_details.cached_tokens. The usage
sanitizer (sanitizeUsage / sanitizeResponsesUsage) was stripping
these non-standard fields, so clients never received real cache
hit counts even when the upstream served cached responses.
Changes:
- sanitizeUsage(): map prompt_cache_hit_tokens into
prompt_tokens_details.cached_tokens when the latter is unset
- sanitizeResponsesUsage(): same mapping for input_tokens_details
- filterUsageForFormat(): add prompt_cache_hit_tokens and
prompt_cache_miss_tokens to the default format allow list
so they survive field-level filtering
* fix: passthrough non-standard cache token fields for DeepSeek / MiniMax / Bedrock across streaming, non-streaming, and Dashboard paths
* fix(sse): shrink cache-hit token passthrough to fit file-size gate
PR #8591 added a DeepSeek/MiniMax/Bedrock flat cache-hit-token ->
nested prompt_tokens_details.cached_tokens mapping (#8171) that grew
responseSanitizer.ts and stream.ts past their frozen file-size
baselines.
- Extract the chat-completions/Responses-API mapping logic into a new
leaf module (responseSanitizer/cacheHitTokens.ts).
- Move the streaming-path rebuild into filterUsageForFormat()
(usageTracking.ts), the single conversion chokepoint both stream.ts
call sites already used, eliminating the duplicated stream.ts patch
entirely.
- Rebaseline responseSanitizer.ts by the 2 lines that remain
irreducible (the mandatory ES import for the extracted helper).
Behavior verified unchanged via the existing response-sanitizer and
stream-handler unit suites.
Co-authored-by: ikelvingo <ikelvingo@users.noreply.github.com>
---------
Co-authored-by: diegosouzapw <diegosouzapw@users.noreply.github.com>
Co-authored-by: ikelvingo <ikelvingo@users.noreply.github.com>
* docs: fix stale tool count (105 -> 104) in MCP server docs (#10002)
The doc's own breakdown at line 11 (42+3+4+3+6+8+8+6+22+2) sums to
104, matching the two existing '104 unique tools' mentions. The
'105 tools' mentions in the intro and cardinality-reduction section
were stale and inconsistent with the documented source of truth.
* refactor(providers): remove retired GitHub Models (#9023)
* docs: clarify free-provider model refresh outcomes (#9087)
* docs: document provider model refresh fix
Document the verified live-model refresh path for stale provider catalogs,
record the current Pollinations anonymous-access limitation, and sync the
provider-count references after regenerating the provider reference.
Co-Authored-By: Oz <oz-agent@warp.dev>
* docs: note codex local env and mac path
Co-Authored-By: Oz <oz-agent@warp.dev>
---------
Co-authored-by: Oz <oz-agent@warp.dev>
* feat(providers): add Naga.ac and ChatAnywhere aggregator providers (#6674) (#9421)
Co-authored-by: diegosouzapw <diegosouzapw@users.noreply.github.com>
* fix(providers): switch minimax from claude to openai format so images work (#9463)
* fix(providers): switch minimax from claude to openai format so images work
The Anthropic-compatible /anthropic/v1/messages endpoint rejects image
input with 403. MiniMax's OpenAI-compatible /v1/chat/completions endpoint
supports image_url natively for MiniMax-M3.
- minimax + minimax-cn: format claude→openai, baseUrl→/v1/chat/completions
- Remove Anthropic-Version header + ?beta=true suffix (not needed for openai)
- Remove minimax/minimax-cn from ?beta=true executor case
- Update cache-control tests (openai format uses different caching path)
- Fix reasoning-split test names (no longer claude format)
TDD: 2 registry tests assert format=openai (red→green).
Refs: Hermes Agent #15715, MiniMax OpenAI-compatible API docs.
* fix(sse): re-align stream-readiness-policy tests with minimax's openai format
PR #9463 switched minimax/minimax-cn from claude to openai format so images
work. The stream-readiness bump for Claude-format replicas is keyed off the
registry's format field (single source of truth), so minimax legitimately
falls out of that group now. Swap the "Claude-format replica" test fixtures
to agentrouter (still format: "claude") and add explicit coverage that
minimax no longer gets the claude_format_heavy_reasoning bump.
---------
Co-authored-by: diegosouzapw <diegosouzapw@users.noreply.github.com>
* fix(providers): reject the dashboard password as a connection API key (#9572)
* fix(providers): refuse to store the dashboard password as a connection API key
A browser autofilled the management password into a connection's API-key field.
The resulting credential authenticates against nothing, so every request routed
through that connection came back 401, and because the field looks like any
other password input the same autofill fired again while the connection was
being repaired by hand.
The refusal belongs on the write path rather than in the form. Twenty routes
create or update connections and all of them funnel through
createProviderConnection and updateProviderConnection, so one check there covers
every entry point including a future one. The two other places that write
api_key are left alone on purpose: one re-encrypts rows that already exist and
the other is the one-time db.json import, and neither takes a value an operator
just typed.
Update checks the incoming value, never the merged one. A connection that
already holds the password has to stay editable or the operator cannot repair
the exact state this prevents, and re-checking the merged value would spend a
bcrypt round on every unrelated field edit.
Only a real match blocks the write. An unreadable settings row or a throwing
bcrypt call logs and allows, because a guard against one specific mistake must
not turn into a way to lock out every connection write.
Signed-off-by: Minxi Hou <houminxi@gmail.com>
* fix(providers): compare the untrimmed credential, and cover the guard's branches
The guard trimmed the incoming value before comparing it, which catches a paste
carrying whitespace the password does not have. It missed the mirror case:
neither the login route nor the set-password route trims, so a dashboard
password may itself begin or end with a space, and an autofill reproducing it
exactly was trimmed into a value that no longer matched the stored hash. The
write then went through, which is the state this guard exists to prevent. Both
forms are compared now, the second only when the first fails on a string that
differs, so an ordinary key still costs a single bcrypt round.
Two branches carried no coverage and both are load-bearing. The catch that logs
and allows is the only path that lets a write through; a stored hash bcrypt
cannot parse reaches it without needing a mock, since the shape check accepts an
impossible cost factor that the comparison then rejects. The early return is
what keeps a token renewal -- a write carrying tokens but no apiKey -- from
paying for a settings read and a bcrypt round every time it fires, and the same
unparseable hash makes that path observable, so an absent warning is proof the
return happened.
The narrower scope is deliberate and now says so in the code: the OAuth tokens
arrive from a provider's token endpoint rather than from a form, so extending
the comparison to them would charge every renewal for a field no autofill can
reach.
Signed-off-by: Minxi Hou <houminxi@gmail.com>
---------
Signed-off-by: Minxi Hou <houminxi@gmail.com>
* fix: restore unorouter api and catalog metadata (#9594)
Co-authored-by: diegosouzapw <diegosouzapw@users.noreply.github.com>
* ci(test): route orphaned Vitest tests through blocking CI (#9605)
* ci(test): route orphaned Vitest tests through blocking CI
* docs: fix advisory status in AGENTS.md and refresh baseline note
* fix(changelog): fix fragment format for #9415
* fix(changelog): preserve upstream fragment format
---------
Co-authored-by: diegosouzapw <diegosouzapw@users.noreply.github.com>
* fix: pass max reasoning effort through by default, add global model registry fallback (#8057) (#9612)
* feat(db): add a job registry for scheduled background work (#9631)
* feat(db): add a job registry for scheduled background work
Background jobs each ship their own timer today, so there is no list of what
is scheduled, no history of what ran, and no way to pause one without an
environment variable and a restart. The registry gives them one home: a jobs
table holding the schedule, a job_runs table holding the outcomes, and a
loopback-only API to inspect and control both.
Cron jobs read their expression through an optional cronGetter rather than the
stored column, so an operator changing OMNIROUTE_WARMUP_CRON does not need the
row rewritten. register() is an idempotent upsert that refreshes the schedule
but never overwrites `enabled` or `created_at`, which is what lets a job be
re-registered on every boot without discarding the operator's toggle.
Run history is pruned per job rather than globally, and safeRun records a
failure for a handler that throws as well as one that returns success:false,
so a crashing job leaves a trail instead of a gap.
The API is under /api/jobs and gated to loopback in the route guard. It can
trigger a run and flip a job off, which is runtime administration and does not
belong on a remotely reachable surface.
Signed-off-by: Minxi Hou <houminxi@gmail.com>
* feat(jobs): move the budget reset and token health check onto the registry
Both jobs owned their own timer and started themselves as an import side effect,
so nothing could report whether they were running, when they last ran, or why a
run failed. They now register with the job registry and are started from it, which
also means their schedule and run history are visible through /api/jobs.
startAll() runs each interval job's first tick synchronously, so both entry points
start the registry only after initializeCloudSync() has been awaited. The old
wiring reached that ordering two different ways: the budget reset was started
after the init call, and the health check's first sweep sat behind a 10s timer.
Replacing both with one startAll() would otherwise have moved the two handlers
in front of the initialisation they run against.
Both entry points also register the same pair of jobs. Registering one and not
the other is how a background job goes missing without anything failing.
sweep() now returns how many connections it swept, so the health check can record
a real records_affected the way the budget reset does. The migration documents
that column as a per-job count, and hardcoding zero would have left one of the two
jobs reporting a number the schema promises but the code never produces. A skipped
or empty sweep reports zero. Every existing caller ignores the return value.
The token health check keeps its own disable semantics: the handler still calls
isHealthCheckDisabled() before sweeping, so OMNIROUTE_DISABLE_TOKEN_HEALTHCHECK,
the production-build phase and the automated-test guard behave as before. Its
registry adapter lives in src/lib/jobs/ next to the budget reset rather than in
tokenHealthCheck.ts, which is already above its frozen size ceiling on the base
branch and should not grow further. The adapter lets a failing sweep throw rather
than reporting it itself, matching the budget reset: safeRun records a thrown
error as a failure run with its message.
The warmup job is seeded disabled. Its handler arrives with the warmup scheduler,
and startAll() filters on enabled before it looks for a handler, so seeding it
enabled here would warn about the missing handler on every boot.
* fix: allowlist cron-parser dep and document OMNIROUTE_RUNNOW_TIMEOUT_MS env var
Co-authored-by: diegosouzapw <diegosouza.pw@gmail.com>
* chore: align rebased branch with release tip (migration renumbered 139->146 in release; feature already cherry-picked in #9886)
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
---------
Signed-off-by: Minxi Hou <houminxi@gmail.com>
Co-authored-by: diegosouzapw <diegosouzapw@users.noreply.github.com>
Co-authored-by: diegosouzapw <diegosouza.pw@gmail.com>
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
*…
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
tests/unit/tracked two files that differ only in case:db-apiKeys-crud.test.ts(camelCase, 542 lines / 54 tests)db-apikeys-crud.test.ts(lowercase, 188 lines / 8 tests)On case-insensitive filesystems (macOS/APFS, default Windows) only one can exist in the working tree. A fresh
git clonetherefore warns:…and checks out just one of the pair, leaving the repo in a confused state (
git statusreports a phantom modification from the collision).Fix
src/lib/db/apiKeys.tsand thefiles=camelCaseconvention, and is the larger/maintained superset.access_scheduleJSON →nullthrottleDelayMs/maxRequestsPerDay/maxRequestsPerMinutescalar fieldsstreamDefaultModepersistenceallowedCombospersistencemaxSessionsclamped to0scopesback to[]createApiKeydefaults +sk-{machineId}-key formattest.afterhook that closes the SQLite handle and removes the temp data dir, so the suite exits cleanly under the native runner (perCLAUDE.md→ "Database Handles in Tests"). The canonical file previously leaked both.Verification
Exit code 0 (no hang). ESLint and Prettier clean.
Note
The same collision exists upstream in
diegosouzapw/OmniRoute(identical blobs) and has not been fixed there. This PR can be ported upstream if desired.