Commit Graph

1208 Commits

Author SHA1 Message Date
Paijo
5b72dc6250 feat: adaptive keepalive threshold for web-session providers (#3397)
Integrated into release/v3.8.16
2026-06-08 00:47:34 -03:00
Diego Rodrigues de Sa e Souza
929caeb910 Release v3.8.15 (#3373)
* chore(release): open v3.8.15 development cycle

Version bump 3.8.14 -> 3.8.15 (root + electron + open-sse + openapi + lockfiles)
and seed the v3.8.15 changelog placeholder (root + 41 i18n mirrors).

* fix(catalog): add getTokenLimit fallback for combo targets with unknown context (#3369)

Integrated into release/v3.8.15. Fixes applied on the contributor's branch: removed duplicate JSDoc opening in accountFallback.ts and dropped a test asserting unreachable catalog behavior (models with no registry/spec/synced source are filtered before the getTokenLimit fallback at catalog.ts:499).

* fix(combo): add 429 to PROVIDER_FAILURE_ERROR_CODES to prevent infinite retry loop (#3366)

Integrated into release/v3.8.15. Comment block reconciled on the contributor's branch to remove the contradictory 'intentionally excluded' text that remained from the original code.

* fix(auto-combo): include no-auth providers declaratively (#3365)

Integrated into release/v3.8.15. Cleanup applied on contributor's branch: removed duplicate migration 095 (already exists from PR #3338), reverted CHANGELOG.md and i18n changelogs to release versions (release process owns these), dropped package version-bump noise from stale fork base. Core feature — declarative no-auth via serviceKinds metadata, declarative VEO as 'video' provider, anonymousFallback flag for opencode-zen/opencode-go — integrated cleanly.

* fix(migrations): restore 095_provider_node_custom_headers migration

The squash merge of PR #3365 accidentally deleted this migration because
the cleanup commit on the contributor's branch included 'git rm' for the
file (which was a duplicate on their branch). The migration was merged
in v3.8.14 via PR #3338 and must be present in the release branch.

Restoring from git history.

* fix: update Command Code base URL from /alpha/ to /provider/v1/ (#3372)

Integrated into release/v3.8.15.

* feat(error-rules): provider-specific error classification with scope (#3370)

Integrated into release/v3.8.15. PR has genuine value beyond #3369: (1) getProviderErrorRuleMatch now accepts native Headers objects from fetch(); (2) checkFallbackError also uses the provider rule registry — the real end-to-end wiring in the combo fallback path; (3) S4 end-to-end test proving the wiring fires. Merge commit on contributor branch resolved the add/add conflict by taking the #3370 version throughout.

* fix(auto-combo): validate web-session credentials (#3371)

Integrated into release/v3.8.15. Core feature: provider-aware web-session credential validation — hasUsableWebSessionCredential() replaces the broad Object.keys check in virtualFactory.ts, ensuring only sessions with the required storageKeys are included in auto-combo. Cleanup: removed duplicate 095 migration, reverted CHANGELOG/i18n, dropped package bump noise.

* fix(migrations): restore 095_provider_node_custom_headers (deleted again by #3371 squash)

Same issue as after #3365: git rm in the contributor cleanup commit
was included in the squash, deleting this migration from release.
Permanent fix needed: use 'git checkout origin/release -- <file>'
instead of 'git rm' when cleaning up duplicate files in contributor branches.

* fix(kiro): probe Windows %APPDATA%\kiro\storage.db in auto-import (#3363) (#3375)

Integrated into release/v3.8.15. Test fix applied: kiro-windows-auto-import-3363.test.ts now sets DATA_DIR to a fresh temp dir before importing app modules, ensuring isAuthRequired() sees an empty settings DB (no password → auth not required). This fixed test 4 (synthetic SQLite) which was getting 401 due to settings DB state leakage.

* chore(release): finalize v3.8.15 changelog — 2026-06-07

---------

Co-authored-by: Hernan Javier Ardila Sanchez <hjasgr@gmail.com>
Co-authored-by: Paijo <14921983+oyi77@users.noreply.github.com>
Co-authored-by: Muhammad Nabil Muyassar Rahman <65392758+TapZe@users.noreply.github.com>
Co-authored-by: kiro-agent[bot] <245459735+kiro-agent[bot]@users.noreply.github.com>
2026-06-07 12:16:33 -03:00
Diego Rodrigues de Sa e Souza
7db430a352 Release v3.8.14 (#3340)
* chore(release): open v3.8.14 development cycle

Version bump 3.8.13 -> 3.8.14 (root + electron + open-sse + openapi + lockfiles).
Seed the v3.8.14 changelog with the four post-tag hotfixes that shipped to
Docker/Electron in v3.8.13 but missed the immutable npm 3.8.13 (#3336 SSRF /
CodeQL #323, #3334/#3335/#3339 Electron packaging). i18n CHANGELOG mirrors get
the in-progress placeholder section.

* feat: add per-provider custom headers support for OpenAI/Anthropic-compatible nodes (#3338)

Integrated into release/v3.8.14

* fix: Kiro Builder ID token import fails with Bad credentials (#3333)

Integrated into release/v3.8.14 — adds Builder ID cached-creds + OIDC refresh path for Kiro token import, with regression tests (#3333).

* Improve code quality: auto-pr/docstrings-1780792063 (#3337)

Integrated into release/v3.8.14 — docstring for context analytics route re-export.

* fix(catalog): remove minimaxai/minimax-m3 from NVIDIA NIM tier (404 upstream) (#3329) (#3341)

NVIDIA NIM does not host minimaxai/minimax-m3 — every request returns
404 page not found, while sibling minimaxai/minimax-m2.7 on the same provider
works. Advertising a model that 404s is a catalog bug; remove it from the nvidia
tier (it remains on the tiers that actually serve MiniMax M3). Re-add only once
NVIDIA serves it.

Co-authored-by: mikmaneggahommie <mikmaneggahommie@users.noreply.github.com>

* fix(cli): write OpenCode config to ~/.config on all platforms incl. Windows (#3330) (#3343)

resolveOpencodeConfigDir used %APPDATA% on Windows, but OpenCode reads its
config from XDG ~/.config/opencode/ on every platform (on Windows:
%USERPROFILE%\.config\opencode\, NOT %APPDATA%). So a Windows user who
configured OpenCode via the dashboard had the file written where OpenCode never
looks — it silently had no effect.

Use the XDG path (XDG_CONFIG_HOME || ~/.config) unconditionally. Update the UI
note + route JSDoc, and flip the three tests that encoded the old %APPDATA%
behavior (t40 per-platform + card-note, cli-runtime-extended getCliConfigPaths).

Co-authored-by: abdulkadirozyurt <abdulkadirozyurt@users.noreply.github.com>

* fix(proxy): make auto-selection fallback opt-in (#3332) (#3344)

selectWorkingProxyFallback (Step 11 of resolveProxyForConnection) listed ALL
registry proxies, ignoring assignments and per-connection proxy_enabled, and
returned the first working one with level:'autoSelect'. So a single proxy added
to the registry silently became a global fallback for every connection's traffic.

Gate it behind a new PROXY_AUTO_SELECT_ENABLED feature flag (default off): the
fallback now no-ops unless the operator opts in. No registry proxy becomes a
silent global default anymore.

Co-authored-by: hertznsk <hertznsk@users.noreply.github.com>

* fix(sse): treat MiniMax M3 as multimodal so vision isn't stripped (#3328) (#3342)

MiniMax M3 via the opencode provider (oc/minimax-m3-free) appeared blind:
image inputs didn't reach the model, while the same model in Cline could
see them. Verified empirically that MiniMax M3 on the opencode upstream IS
multimodal -- a base64 image is described correctly (it returns 403 only
for remote image URLs, which it doesn't accept).

Root cause: OmniRoute treated MiniMax M3 as a non-vision model in two
places, so when compression was active the image was replaced with a text
placeholder before dispatch:
- compression's modelSupportsVision() heuristic (lite.ts) only matched
  gpt-4/4o/claude-3/gemini/vision -- minimax was absent -> replaceImageUrls
  stripped the image.
- the opencode minimax-m3-free catalog entry lacked supportsVision, so the
  combo vision-capability gate could also exclude/mishandle it.

Add 'minimax-m3' to the vision heuristic and supportsVision: true to the
opencode minimax-m3-free entry. TDD: a failing-then-passing test in
compression/lite.test.ts proves replaceImageUrls now keeps images for
minimax-m3 ids, plus a registry assertion mirroring the #2822 qwen test.

Reported-by: @mikmaneggahommie

* docs(i18n): translate 25 core documentation files to Indonesian (#3348)

Integrated into release/v3.8.14 — Indonesian i18n docs.

* fix(review): resolve /review-reviews battery findings (LEDGER-1..11) on v3.8.14 (#3350)

Integrated into release/v3.8.14 — /review-reviews battery hardening (LEDGER-1..11) for #3338 custom-headers + #3333 kiro, plus cycle-test drift fixes (#3329/#3330/#3332).

* fix(provider-proxy): honor per-account proxy toggles (#3349)

Integrated into release/v3.8.14 — honor per-account proxy toggles + auto-fallback opt-in via PROXY_AUTO_SELECT_ENABLED.

* fix(dashboard): remove duplicate Distribute Proxies button on provider page (#3352)

* fix(providers): reduce proxy label noise (#3346)

Integrated into release/v3.8.14 — reduce proxy label noise + a11y (aria-label/sr-only).

* fix(duckduckgo): restore bare Response contract and rebase onto release/v3.8.14 (#3323)

Integrated into release/v3.8.14 — browser-backed cookie providers (duckduckgo/claude-web) with restored executor contract + unit tests.

* fix(noauth): expose only usable model aliases (#3345)

Integrated into release/v3.8.14 — noauth usable-alias filtering + registry alias plumbing (veo-free).

* fix(dashboard): stop infinite config-load loop on Hermes Agent detail page (#3353)

* fix(electron): tree-kill the server on exit/update to release the omniroute.exe lock (#3347) (#3354)

* chore(release): finalize v3.8.14 changelog + clear release-gate drift

- CHANGELOG: finalize the v3.8.14 section (date, full New Features/Bug Fixes/
  Maintenance coverage of all 16 cycle commits, Contributors hall of 12).
- docs: document OMNIROUTE_BROWSER_POOL + WEB_COOKIE_USE_BROWSER (#3323) in
  .env.example + ENVIRONMENT.md; regenerate the id/llm.txt strict mirror (#3348
  had translated it; llm.txt mirrors must match root).
- test(proxy-fetch): #3323 made tlsClient.available a computed getter — stub it
  via Object.defineProperty instead of assignment (5 tests were red on the base).

* fix(translator): coerce Gemini functionDeclaration parameters to an OBJECT schema (#3357) (#3360)

* fix(gemini): resolve truncation/suppression of false positive textual tool call markers in backticks (#3358)

Integrated into release/v3.8.14 — Gemini/Antigravity textual tool-call marker normalization (no false-positive suppression + split-chunk buffering).

* docs(changelog): add #3358 Gemini textual tool-call normalization to v3.8.14

* fix(dashboard): surface real analytics error instead of generic placeholder (#3356) (#3361)

The Analytics page discarded the server's error body on a non-OK response and
rendered a generic "An error occurred", so users (and maintainers) could not see
why /api/usage/analytics 500'd after an upgrade. Now the route returns the real
reason via buildErrorBody (sanitized, Hard Rule #12) and the page surfaces it via
a new readFetchErrorMessage helper that handles both the OpenAI-style and legacy
error shapes.

Reported-by: @superti4r

---------

Co-authored-by: PizzaV <103120356+pizzav-xyz@users.noreply.github.com>
Co-authored-by: Someres <168349709+quanturbo@users.noreply.github.com>
Co-authored-by: Dong Mengzhe <154944819+Lang-Qiu@users.noreply.github.com>
Co-authored-by: mikmaneggahommie <mikmaneggahommie@users.noreply.github.com>
Co-authored-by: abdulkadirozyurt <abdulkadirozyurt@users.noreply.github.com>
Co-authored-by: hertznsk <hertznsk@users.noreply.github.com>
Co-authored-by: Krisna Santosa <54174372+KrisnaSantosa15@users.noreply.github.com>
Co-authored-by: Randi <55005611+rdself@users.noreply.github.com>
Co-authored-by: Wilson <pedbookmed@gmail.com>
Co-authored-by: Paijo <14921983+oyi77@users.noreply.github.com>
Co-authored-by: Ardem2025 <ardemb22@gmail.com>
2026-06-07 07:20:02 -03:00
Diego Rodrigues de Sa e Souza
df2379053e fix(security): use trusted internal origin for provider auto-sync self-fetch (CodeQL #323 SSRF) (#3336)
POST /api/providers fires a credential-bearing self-fetch to the new
connection's /sync-models route (forwarding the management cookie + internal
sync auth headers). #3267 built that origin from new URL(request.url).origin —
the client-controlled Host header — so a (management-authenticated) caller
could redirect the internal request to an arbitrary host, exfiltrating the
internal sync auth token (CodeQL js/request-forgery, critical, alert #323).

Derive the origin from the trusted loopback/env-pinned base URL via a new
getModelSyncInternalBaseUrl() helper (same source the model-sync scheduler
already uses), never from the incoming request. Adds a regression test.
2026-06-06 21:20:26 -03:00
Diego Rodrigues de Sa e Souza
a25d5f1ef6 Release v3.8.13 (#3327)
* chore(release): open v3.8.13 development cycle

Bump 3.8.12 → 3.8.13 across package.json, lockfile, electron/, open-sse/, and
docs/reference/openapi.yaml; add the [3.8.13] cycle placeholder to the root
CHANGELOG and the 41 i18n mirrors. Integration branch for the v3.8.13 cycle —
fixes/features land here via per-issue PRs and it merges to main at release time.

* fix(ci): skip auto-deploy when VPS host is unreachable from the runner (#3299)

Integrated into release/v3.8.13

* fix(dev): auto-rebuild better-sqlite3 on Node ABI mismatch at dev startup (#3301)

Integrated into release/v3.8.13

* feat(api): accept path-scoped API keys on client API routes (#3300)

Integrated into release/v3.8.13

* fix(sse): harden against empty responses causing Copilot Chat failures (#3297)

Integrated into release/v3.8.13

* fix(api): remove Completions.me rickroll provider (discussion #3293) (#3302)

Integrated into release/v3.8.13

* fix(opencode-provider): extract contextLength from live model catalog (#3298)

Integrated into release/v3.8.13

* feat(web-cookie): self-service login infrastructure + auto-refresh daemon (#3292)

Integrated into release/v3.8.13

* docs(changelog): record the v3.8.13 PRs merged this round (#3292/#3300/#3297/#3298/#3301/#3302/#3299)

* fix(auth): harden URL token extraction — drop query-string fallback, gate to client routes (security follow-up to #3300) (#3309)

Security follow-up to #3300 — integrated into release/v3.8.13

* docs: rename resolve-issues → review-issues skill references

* fix(dashboard): keep no-auth providers visible under 'Show configured only' (#3290) (#3312)

no-auth providers (opencode, duckduckgo-web, theoldllm, veoaifree-web) never
create a DB connection row so stats.total stays 0, which the configured-only
filter treated as 'unconfigured' and hid them — even though they are always
usable and appear unconditionally in /v1/models. filterConfiguredProviderEntries
now treats displayAuthType === 'no-auth' as configured.

Co-authored-by: uniQta <uniQta@users.noreply.github.com>

* fix(cli): resolve update paths relative to script + recursive backup (#3295) (#3313)

omniroute update always failed on a global install:
- getCurrentVersion() read package.json from process.cwd(), which on a global
  npm/brew install is the user's working dir, not the package root → null →
  'Could not determine current version'.
- createBackup() resolved bin/ from cwd too, and passed the 'cli' directory to
  copyFileSync → EISDIR, swallowed by the catch → 'Failed to create backup'.

Both now resolve package.json/bin relative to the script via import.meta.url,
and the backup uses cpSync({recursive:true}) so the cli/ directory is copied.

Co-authored-by: uniQta <uniQta@users.noreply.github.com>

* fix(theoldllm): read upstream body once to avoid [502] body-already-read (#3296) (#3314)

On the cached-token path the executor never enters the refresh branch, so the
same upstream Response was read with .text() twice (token-rejection check +
final body). A Response body is single-use, so the second read threw
'Body is unusable: Body has already been read', caught and surfaced as [502].

Read the body once into finalBody and only re-read after a token-rejection
refetch.

Co-authored-by: onizukashonan14-png <onizukashonan14-png@users.noreply.github.com>

* fix(sse): strip leaked internal tool envelopes from streaming output (#3311)

Integrated into release/v3.8.13

* fix(sse): expose Claude + Gemini budget tiers in the antigravity catalog (#3184) (#3303)

Integrated into release/v3.8.13 (#3184)

* fix(catalog): compute combo context_length from known targets only (#3304)

Integrated into release/v3.8.13 — live contextLength + known-targets combo context (#3298 follow-up)

* chore(i18n): add message keys for proxy UI + vscode/ollama endpoint (#3307)

Integrated into release/v3.8.13 — i18n message keys for proxy UI + vscode/ollama

* feat(dashboard): i18n the proxy settings UI (#3310)

Integrated into release/v3.8.13 — i18n the proxy settings UI

* feat(api): model catalog enrichment + MCP model-catalog tools (#3306)

Integrated into release/v3.8.13 — model catalog enrichment + MCP model-catalog tools, reconciled with #3309 URL-token hardening

* test(catalog): align Antigravity preview-alias test with #3303 budget tiers

#3303 added the Gemini `-high`/`-low` budget tiers to ANTIGRAVITY_PUBLIC_MODELS
(user-callable on the Antigravity OAuth backend, verified via #3184), but did
not update the catalog-route test that asserted `antigravity/gemini-3.1-pro-high`
must NOT be exposed. The assertion now reflects the intended behavior — the
client-visible budget alias IS surfaced — while keeping the legacy
`gemini-claude-*` alias keys unexposed. Caught running the full catalog suite
on the merged release HEAD (the #3303 round only ran the antigravity-aliases
and usage-hardening files).

* docs(changelog): record the 6 PRs merged this review round into v3.8.13

#3306/#3307/#3310 (New Features — VS Code split: catalog+MCP, i18n keys, proxy
UI i18n), #3311/#3303/#3304 (Bug Fixes — SSE envelope sanitizer, antigravity
budget tiers, combo known-targets context_length).

* chore(release): finalize v3.8.13 changelog and cleanup

Finalize the v3.8.13 changelog with release date, maintenance notes,
and contributor credits. Update MCP docs to reference the correct tool
inventory diagram, exclude nested .claude worktrees from ESLint scans,
and tighten a response sanitizer type guard.

* fix(dashboard): refresh connections after provider auth import (#3320)

Integrated into release/v3.8.13 — refresh connections after provider auth import

* fix(codex): strip client-only params on native /responses passthrough (#3317) (#3325)

A /v1/responses request against the built-in codex/ provider does an
openai-responses -> openai-responses passthrough (CodexExecutor.transformRequest
returns the body early for _nativeCodexPassthrough). It forwarded client-only
fields verbatim and the Codex upstream rejected them with 400 Unsupported
parameter: prompt_cache_retention / safety_identifier / user — breaking Factory
Droid (which injects all three). The chat-completions path already strips these
(base.ts #1884, openai-responses translator #2770) but the passthrough skips
translation. Strip the three fields in the shared block before the passthrough
return; user is removed unconditionally since Codex /responses always rejects it.

Co-authored-by: tycronk20 <tycronk20@users.noreply.github.com>

* fix(dashboard): normalize agent-bridge /state response to stop page crash (#3318) (#3326)

The Agent Bridge page seeded a well-shaped initialData default then replaced it
wholesale with the raw /api/tools/agent-bridge/state response. The route returns
{ server, agents } but the UI reads { serverState, agentStates, bypassPatterns,
mappings }, so serverState became undefined and AgentBridgeServerCard crashed on
serverState.running — surfaced as the full-page 'Internal Server Error' boundary
(client render error, not a real 5xx).

Add a shared normalizeAgentBridgeState() that maps the route shape into the page
contract (server.running/certExists -> serverState) and always returns safe
defaults (never undefined serverState). Wired into both the SSR loader (page.tsx)
and the polling hook. The legacy 'agents' entry shape differs from AgentStateEntry
so it is not coerced; full route<->page contract reconciliation (port, upstreamCa,
bypassPatterns, mappings, agentStates) is a follow-up.

Co-authored-by: tycronk20 <tycronk20@users.noreply.github.com>

* docs: VS Code/Ollama endpoints + env & i18n tooling (#3319)

Integrated into release/v3.8.13 — VS Code/Ollama docs + env & i18n tooling

* feat(provider): test-all endpoint, rate-limit overrides, visibility f… (#3267)

Integrated into release/v3.8.13 — provider test-all endpoint, rate-limit overrides, model visibility

* feat: auto-combo optimization, playground model dropdown, only-configured toggle (#3322)

Integrated into release/v3.8.13 — auto-combo candidate expansion + playground dropdown + only-configured toggle

* feat(api): VS Code Copilot Ollama-compatible BYOK endpoint (#3316)

Integrated into release/v3.8.13 — VS Code Copilot Ollama-compatible BYOK endpoint (reconciled with #3306/#3309 auth hardening)

* chore(release): document #3320 in the v3.8.13 changelog + contributor credits

---------

Co-authored-by: Felipe Almeman <4226997+zhiru@users.noreply.github.com>
Co-authored-by: Wilson <pedbookmed@gmail.com>
Co-authored-by: Hernan Javier Ardila Sanchez <hjasgr@gmail.com>
Co-authored-by: Paijo <14921983+oyi77@users.noreply.github.com>
Co-authored-by: uniQta <uniQta@users.noreply.github.com>
Co-authored-by: onizukashonan14-png <onizukashonan14-png@users.noreply.github.com>
Co-authored-by: tycronk20 <tycronk20@users.noreply.github.com>
Co-authored-by: Vinayrnani <vinayrnani@gmail.com>
2026-06-06 19:13:11 -03:00
diegosouzapw
5bebf0e53c fix(quota,sse): clear SonarCloud new-reliability findings on the v3.8.12 diff
- chipotle/grokTls: explicit null checks instead of a Promise in a boolean
  conditional (behavior-preserving; clears the 2 MAJOR reliability bugs)
- sqliteQuotaStore.poolUsage: drop the unreachable dimMap scan loops (dimMap
  was never populated) — the lightweight snapshot already returns no
  dimensions; poolUsageWithDimensions() is the plan-aware path
- BudgetTab: presentation role + keyboard handler on the checkbox wrapper
2026-06-06 06:49:46 -03:00
Paijo
1c8f3bee97 fix(quota): resolve poolUsage dead code, burn rate, saturation signals, webhooks, and embeddings enforcement (#3280)
Integrated into release/v3.8.12. Quota Sharing Engine fixes: poolUsageWithDimensions promoted to the QuotaStore interface, single-snapshot burn rate, zero-weight normalization, Anthropic saturation signals, quota.exceeded webhook on block, and embeddings enforcement. Validated: 10/10 PR tests + 34 quota/embedding regression files green, typecheck + lint clean. Dropped the committed .omo/ agent-tooling artifacts.
2026-06-06 03:41:03 -03:00
Diego Rodrigues de Sa e Souza
36932b62a7 fix(api): harden private webhook opt-in against cloud-metadata SSRF (#3269) (#3281)
Follow-up to the #3269 private-webhook opt-in. With the opt-in on, the private-host
check was bypassed entirely, leaving cloud-metadata endpoints (169.254.169.254,
metadata.google.internal, 100.100.100.200, link-local 169.254.0.0/16) reachable — the
classic SSRF -> IAM-credential pivot — and the webhook test endpoint returned the
upstream body, making it a content-exfiltration primitive against internal services.

- outboundUrlGuard: add isCloudMetadataHost(); parseAndValidateWebhookUrl blocks those
  hosts UNCONDITIONALLY, even when private targets are opted in.
- webhooks/[id]/test: redact responseBody for private targets (status + latency only).

Regression test: tests/unit/webhook-metadata-guard-3269.test.ts (RED before, GREEN after);
existing webhook SSRF/opt-in suites stay green (34/34).
2026-06-06 03:08:16 -03:00
Diego Rodrigues de Sa e Souza
a5d19bf4b9 fix(api): allow private webhook targets behind explicit opt-in (#3269) (#3279)
Webhooks hardcoded parseAndValidatePublicUrl, which blocks any RFC1918/loopback host —
breaking self-hosted setups that legitimately point webhooks at internal services
(n8n, Home Assistant, a LAN box). Provider URLs already had an opt-in
(OMNIROUTE_ALLOW_PRIVATE_PROVIDER_URLS); webhooks now reuse it.

- outboundUrlGuard: add parseAndValidateWebhookUrl — gates the private-host check on
  arePrivateProviderUrlsAllowed() (default OFF); protocol + embedded-credential checks
  stay unconditional.
- swap all webhook call sites (create/update/test/validate-url + dispatcher x2) to it.

Regression test: tests/unit/webhook-private-optin-3269.test.ts (RED before, GREEN after);
existing webhook SSRF/dispatcher suites stay green (33/33).
2026-06-06 02:59:09 -03:00
Diego Rodrigues de Sa e Souza
30ebe0ae2e feat(free-tiers): per-model free-token budget + Monthly Budget dashboard card (#3263)
Free-token budget catalog + per-model budget + Monthly Budget dashboard card (joins #3257 + #3263 into one).

Integrated into release/v3.8.12.
2026-06-06 02:38:35 -03:00
Lenine Júnior
5d8f265192 feat(dashboard): bulk activate/deactivate/retest for selected provider connections (#3271)
Bulk activate/deactivate/retest for selected provider connections.

Integrated into release/v3.8.12. Thanks @leninejunior.
2026-06-06 02:33:17 -03:00
Wilson
07d9010668 fix(v1/responses): skip codex rewrite for combo names (#3233, #3227) (#3268)
Regression test for the /v1/responses combo-name codex-rewrite guard (#3233, #3227).

Integrated into release/v3.8.12. Thanks @wilsonicdev.
2026-06-06 00:39:57 -03:00
Thiago Reis
583bceb53d fix(providers): improve refresh validation and model catalog UI (#3261)
Provider refresh/validation, OpenRouter catalog and proxy UI fixes — incl. NVIDIA NIM /models-suffix path fix (real-VPS validated).

Integrated into release/v3.8.12. Thanks @strangersp.
2026-06-06 00:26:40 -03:00
diegosouzapw
396a79f02a fix(api,dashboard): validate /v1/images/edits JSON body + drop duplicate proxy handler
Clear the two release-gate failures the CI Lint+Build jobs surfaced (release-branch
drift — PR merges bypassed pre-push):

- fix(api): /v1/images/edits parsed request.json() without a Zod guard
  (route-validation t06 / hard rule #7). Add ImageEditJsonSchema.safeParse so a
  malformed body (non-object / wrong types) is rejected with 400 instead of
  silently parsed; valid JSON/data-URL bodies behave exactly as before. (#3214, #3215)
- fix(dashboard): remove a duplicate handleToggleProxyEnabled /
  handleTogglePerKeyProxyEnabled / handleDistributeProxies block in
  providers/[id]/page.tsx — a bad merge of the proxy PRs declared all three twice,
  breaking the webpack build ("Identifier already declared"). The removed copy was
  byte-identical to the kept one. (#3170, #3171, #3172)
2026-06-05 16:03:24 -03:00
Diego Rodrigues de Sa e Souza
cf7f684bd8 fix(api): don't force combo names to codex/ on /v1/responses (#3227, #3233) (#3244)
The Codex CLI WS->HTTP fallback rewrite (resolveResponsesApiModel) prefixes a
bare model id with codex/ whenever codex/<id> resolves to codex. Codex accepts
arbitrary model strings, so a combo name with no slash (e.g. n8n-text,
paid-premium) was rewritten to codex/<combo> and sent to Codex instead of being
resolved as a combo — regressing combos via /v1/responses in v3.8.9+. Skip the
rewrite when the bare id is a combo (getComboByName). + unit test.
2026-06-05 14:16:10 -03:00
Wilson
c222143071 fix(cli): show OpenCode Free in Hermes Agent picker (#3240)
Show OpenCode Free in the Hermes Agent model picker via alwaysIncludeProviders.

Integrated into release/v3.8.11. Thanks @wilsonicdev.
2026-06-05 13:12:52 -03:00
Wilson
5ec8fa222a fix(usage): route agy quota through antigravity (#3232)
Route agy quota through the Antigravity usage implementation (closes #3230).

Integrated into release/v3.8.11. Thanks @wilsonicdev.
2026-06-05 13:12:40 -03:00
Felipe Almeman
2942ba874e Feat/codex device flow (#3195)
Codex public device-flow connect link (ticket-gated) + dashboard CTA. Integrated into release/v3.8.11.
2026-06-05 12:06:35 -03:00
Diego Rodrigues de Sa e Souza
b4d5610d86 fix(dashboard): correct misleading provider credential hints (#3180, #3091) (#3224)
- grok-web: the credential hint named only "sso" while Grok needs both "sso"
  and "sso-rw"; users pasted just sso and hit anti-bot 403s. Name both
  (credentialName + placeholder). The underlying Cloudflare anti-bot 403 is
  upstream and tracked separately on #3180.
- vertex: the Service Account JSON placeholder was an untranslated stub literal
  ("Vertex Service Account Placeholder") in 40 locales, making the field look
  broken even though SA-JSON auth is fully supported. Replace with real
  instructional text (zh localized; pt-BR already translated).

Guard test pins both hints.
2026-06-05 10:20:38 -03:00
Diego Rodrigues de Sa e Souza
5a2e93d20a fix(dashboard): show friendly provider name (not UUID) in home topology (#3198) (#3222)
getProviderConfig falls back to { name: providerId } for unknown ids, so the
label precedence config.name || p.name let the raw internal UUID of a custom
provider shadow the friendly name HomePageClient already resolved into p.name.
Extract resolveTopologyNodeLabel (entry name first) + unit test.
2026-06-05 10:14:06 -03:00
Diego Rodrigues de Sa e Souza
ec4f8c4d42 feat(api): combo/alias resolution + OpenAI-compatible edits for image routes (#3214, #3215) (#3219)
Image routes now resolve a requested model the same way across /v1/images/generations
and /v1/images/edits, via a shared resolver: built-in id -> custom provider prefix ->
bare combo/alias name (e.g. "image" -> its single image target). Previously a bare
combo name fell through to "Invalid image model".

/v1/images/edits gains two capabilities for custom OpenAI-compatible providers:
- multipart edit forwarding to the node's {base_url}/images/edits (was hard-rejected
  unless chatgpt-web);
- JSON/data-URL edit input (images:[{image_url:"data:..."}]), converted to the same
  fields the multipart reader produces (was "Invalid multipart body").

The chatgpt-web conversation-continuation edit flow is unchanged.
2026-06-05 09:37:32 -03:00
Diego Rodrigues de Sa e Souza
c116bfbc7f fix(db): open import-validation DB via resilient driver factory (#3025) (#3218)
The db-backups import route statically imported better-sqlite3, which is
stripped from the Next standalone server's node_modules in the packaged
Electron app. Loading the route then crashed with "Cannot find module
'better-sqlite3'" on the Windows installer, even though node:sqlite was
available. Route the upload integrity-check through openDatabaseAsync
(better-sqlite3 -> node:sqlite -> sql.js), matching every other DB path.

Adds a guard test so no API route can reintroduce a direct native import.
2026-06-05 09:23:17 -03:00
Diego Rodrigues de Sa e Souza
6fe7c6b5b1 fix(provider-models): keep a deleted synced model deleted across re-fetch (#3199) (#3212)
Follow-up to #3204: deleting a synced (fetched) model removed it from the
synced set, but the DELETE route didn't mark it hidden and the re-import path
didn't skip hidden ids, so the next auto-fetch re-added it. Now the route
marks the id hidden on delete and replaceSyncedAvailableModelsForConnection
filters hidden ids, so the deletion sticks.

Co-authored-by: tjengbudi <tjengbudi@users.noreply.github.com>
2026-06-05 02:56:03 -03:00
Diego Rodrigues de Sa e Souza
fa0aa1e25d fix(images): use provider node base_url + resolve prefix for custom image providers (#3205) (#3208)
The image-generation handler read credentials.baseUrl (always undefined),
so custom OpenAI-compatible image providers fell back to the Gemini endpoint
(401). Resolve from providerSpecificData.baseUrl like the chat path, and
rewrite prefix/model to the internal node id before the exact-id lookup.

Co-authored-by: ngocquynh85 <ngocquynh85@users.noreply.github.com>
2026-06-05 02:50:54 -03:00
Wilson
7b4bda13b1 fix(models): allow deleting synced/fetched models (e.g. llamacpp) via DELETE /api/provider-models (#3204)
Integrated into release/v3.8.11
2026-06-05 02:44:38 -03:00
PizzaV
c48e0851f7 feat(proxy): add proxy distribution UI with per-connection toggles (#3172)
Integrated into release/v3.8.11
2026-06-05 02:05:33 -03:00
PizzaV
de5c842301 feat(proxy): auto-fallback proxy selection when validation fails (#3171)
Integrated into release/v3.8.11
2026-06-05 01:57:40 -03:00
Xiangzhe
4a5e123bad fix(auth): honor REQUIRE_API_KEY feature flag (#3188)
Integrated into release/v3.8.11
2026-06-05 00:53:27 -03:00
Felipe Almeman
a7494e415e Fix/codex import auth (#3185)
Integrated into release/v3.8.11
2026-06-05 00:47:35 -03:00
Diego Rodrigues de Sa e Souza
68d5a0ab27 Release v3.8.10 (#3140)
* chore(release): open v3.8.10 development cycle

Bump 3.8.9 → 3.8.10 across package.json, lockfile, electron, open-sse, and
docs/reference/openapi.yaml; add the [3.8.10] CHANGELOG section (root + 41 i18n
mirrors) as the integration target for the cycle. Entries land here as work
merges into release/v3.8.10; finalized by the release flow.

* fix(providers): resolve web provider alias collisions

Assign unique aliases to HuggingChat, Kimi Web, and Qwen Web so they no longer shadow primary providers or trigger startup warnings.

Add a unit test to enforce provider alias uniqueness and prevent future collisions. Also expand local ignore and VS Code exclude rules for agent, build, and worktree artifacts.

* fix(responses): normalize image_url parts across input paths (#3150)

Normalize image_url parts across all Responses input paths. Integrated into release/v3.8.10.

* fix(api-manager): preserve API key expiration local time (#3146)

Preserve API key expiration local time + clear button. Integrated into release/v3.8.10.

* Strip previous_response_id for stateless Responses upstreams (#3143)

Strip previous_response_id for stateless Responses upstreams (auto/strip/preserve). Integrated into release/v3.8.10.

* fix(opencode-plugin): map thinking cap to interleaved in model+combo (#3138)

Map caps.thinking to ModelV2.capabilities.interleaved for opencode-plugin. Integrated into release/v3.8.10.

* fix(providers): use synced models as fallback for all providers (#3148)

Use synced models as authoritative local catalog for all providers (+regression test). Integrated into release/v3.8.10.

* fix(qoder): bifurcate validation by token type — PAT→Cosy, regular API key→dashscope (#3149)

Bifurcate Qoder validation by token type (PAT→Cosy, regular→dashscope) +regression test. Integrated into release/v3.8.10.

* fix(antigravity): dynamic model resolution via MITM alias table (#3144)

Dynamic antigravity MITM model resolution in the executor (+bug fix +regression test; DB import dropped from client-reachable config). Integrated into release/v3.8.10.

* Feature/batch allow big (#3128)

Podman deployment options + larger upload body-size limits (+CONTAINER_HOST docs). Integrated into release/v3.8.10.

* fix(fireworks): preserve fully-qualified router/model IDs (#3133) (#3160)

Fireworks router IDs (accounts/fireworks/routers/...) were double-prefixed
with accounts/fireworks/models/ → upstream 404. Add optional
acceptedModelIdPrefixes to the registry entry and skip the prepend when the
model already starts with an accepted prefix.

Co-authored-by: KooshaPari <KooshaPari@users.noreply.github.com>

* fix(llama-cpp): route to configured local baseUrl instead of OpenAI (#3136) (#3161)

llama-cpp was missing from the local-provider group in buildUrl(), so it
fell through to the OpenAI baseUrl and returned an OpenAI 401. Add the
case to resolve the connection's providerSpecificData.baseUrl.

Co-authored-by: tjengbudi <tjengbudi@users.noreply.github.com>

* fix(t3-chat-web): parse cookies + convexSessionId from stored credential (#3007) (#3162)

The executor read credentials.cookies/convexSessionId, but the pipeline
only stores the pasted string under apiKey → t3.chat always 400'd. Parse
both values from apiKey (fallback accessToken), mirroring validation.ts.

Co-authored-by: minhtran162 <minhtran162@users.noreply.github.com>

* fix(minimax): stop capping MiniMax-M3 / M2.7 max_tokens at 8192 (#3141) (#3163)

MiniMax-M3 had no MODEL_SPECS entry and capitalized MiniMax-M2.7 missed
its lowercase spec (case-sensitive lookup) → both fell to the 8192 default
cap. Add the M3 spec (512K output), alias the capitalized ids, and make
getModelSpec lookups case-insensitive.

Co-authored-by: totaltube <totaltube@users.noreply.github.com>

* fix(github-copilot): discover model catalog live from api.githubcopilot.com (#3120, #3121) (#3164)

The github (Copilot) provider had a static hardcoded catalog with no
discovery source, so Import Models never refreshed (#3120) and advertised
non-entitled models that 400 on use (#3121). Add a live /models fetch with
fallback to the static list.

Co-authored-by: gabrielmoreira <gabrielmoreira@users.noreply.github.com>

* fix(combo): invalidate nested-combo cache on edits + log DATA_DIR (#3147) (#3165)

Editing a combo did not invalidate the 10s nested-combo expansion caches
(chat.ts getCombosCachedForChat + chatCore.ts getCombosCached; the exported
clearCombosCache was dead code), so a removed nested target/model could be
served as a phantom for up to 10s. Wire a shared monotonic combos-cache
version in readCache (bumped by invalidateDbCache("combos") on every combo
write); both cache layers treat a version mismatch as a miss.

Also log the resolved DATA_DIR/SQLITE_FILE absolute path at DB init so the
reporter's 'persists across restart + volume wipe' symptom (a multi-replica
Docker volume/DATA_DIR mismatch, not a routing bug) is diagnosable from logs.

Includes consolidated CHANGELOG entries for #3133/#3136/#3007/#3141/#3120/#3121.

Co-authored-by: ViFigueiredo <ViFigueiredo@users.noreply.github.com>

* fix(web-tools): parse bare JSON tool calls (#3157)

Parse bare JSON tool calls for deepseek-web (#2820) + fuzzy tool-name matching. Integrated into release/v3.8.10.

* fix(misc): minor fixes across reasoning cache, account fallback, binary manager (#3177)

Misc: ProviderProfile export, DeepSeek reasoning regex, binary guard. Integrated into release/v3.8.10.

* fix(kiro): minor OAuth social exchange tweaks (#3176)

Kiro social OAuth: optional targetProvider passthrough. Integrated into release/v3.8.10.

* deps: bump hono from 4.12.18 to 4.12.23 (#3179)

Bump hono to 4.12.23. Integrated into release/v3.8.10.

* fix(providerRegistry): update kilocode format and executor (#3166)

kilocode: openai format + default executor (matches kilo-gateway) + registry test. Integrated into release/v3.8.10.

* feat(metrics): cross-request TTFT and gap latency after tool calls (#3173)

Cross-request TTFT + gap-after-tool latency metrics (+test). Integrated into release/v3.8.10.

* feat(dashboard): provider stats API endpoint and dashboard page (#3175)

Provider stats dashboard + API (SQL moved to db module per Hard Rule #5, +test). Integrated into release/v3.8.10.

* fix(usage): sequential+spaced OAuth quota sync, reactive force-refresh, actionable 401 (#3156)

Sequential+spaced OAuth quota sync, reactive force-refresh on 401, actionable 401 in UI. Integrated into release/v3.8.10.

* fix(healthcheck): per-provider proactive-refresh skip list (rescue short-TTL OAuth) (#3159)

Per-provider proactive-refresh skip list (OMNIROUTE_HEALTHCHECK_SKIP_PROVIDERS) to rescue short-TTL OAuth. Integrated into release/v3.8.10.

* feat(quota): show OAuth token expiry on provider cards (small, blue, informative) (#3178)

Show OAuth token expiry on provider cards (small, blue, informative). Integrated into release/v3.8.10.

* fix(providers): empty refresh must not resurface just-cleared synced models (#3181)

Empty refresh must not resurface just-cleared synced models (fixes the release-blocking provider-models-route test). Integrated into release/v3.8.10.

* chore(release): v3.8.10 — 2026-06-04 (finalize CHANGELOG)

---------

Co-authored-by: Wilson <pedbookmed@gmail.com>
Co-authored-by: Xiangzhe <32761048+xz-dev@users.noreply.github.com>
Co-authored-by: Jan Leon <Jan.gaschler@gmail.com>
Co-authored-by: M.M <mr.maatoug@gmail.com>
Co-authored-by: Hernan Javier Ardila Sanchez <hjasgr@gmail.com>
Co-authored-by: Markus Hartung <mail@hartmark.se>
Co-authored-by: KooshaPari <KooshaPari@users.noreply.github.com>
Co-authored-by: tjengbudi <tjengbudi@users.noreply.github.com>
Co-authored-by: minhtran162 <minhtran162@users.noreply.github.com>
Co-authored-by: totaltube <totaltube@users.noreply.github.com>
Co-authored-by: gabrielmoreira <gabrielmoreira@users.noreply.github.com>
Co-authored-by: ViFigueiredo <ViFigueiredo@users.noreply.github.com>
Co-authored-by: PizzaV <103120356+pizzav-xyz@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Nicolas Lorin <androw95220@gmail.com>
2026-06-04 20:05:38 -03:00
diegosouzapw
b6bda19919 fix(quality): explicit promise-existence checks + protocol-aware WebDAV URL
SonarCloud new-code findings:
- combo.ts / sync-models route: `if (cachedPromise)` -> `!= null` (intentional
  in-flight-promise reuse; explicit existence check, no behaviour change).
- ObsidianSourceCard WebDAV URL: inherit window.location.protocol instead of
  hard-coding http:// (https when behind a TLS proxy) — clears the http hotspot.
2026-06-03 23:53:03 -03:00
diegosouzapw
8dd9749a93 fix(build): correct modelResolution import path in responses route (#3113)
The webpack build failed: route.ts imported '../internal/codex-responses-ws/
modelResolution' (resolves to api/v1/internal/, which doesn't exist). The module
lives at api/internal/codex-responses-ws/. Switched to the @/app/api/... alias.
typecheck/tests passed (tsx resolves leniently; tests import the module directly),
only the production build caught it.
2026-06-03 19:47:42 -03:00
diegosouzapw
cad93f35ce fix(lint): escape quotes in ObsidianSourceCard JSX (react/no-unescaped-entities) 2026-06-03 18:58:29 -03:00
Oğuzhan Sert
8dc93ade6d fix(i18n): Turkish locale-aware search and sorting (#3115)
* feat(i18n): add Turkish locale-aware text helpers (search/sort)

* test(i18n): cover null/whitespace edges + document compareTr/normalize contract

* fix(i18n): route dashboard search through Turkish-safe matchesSearch

* fix(i18n): sort user-visible lists with Turkish collation (compareTr)

* fix(i18n): keep providerId tiebreaker as ASCII sort (technical id)

* docs(i18n): document intentional lang=en in global-error boundary

* chore(lint): guard against locale-unsafe toLowerCase().includes search

* fix(i18n): migrate missed provider-name search + harden lint disable placement

* fix(i18n): downgrade no-restricted-syntax to warn (incremental adoption)

The rule errored on ~19 pre-existing toLowerCase().includes() call-sites in
src/app accumulated since this PR's base. Keep it as a warning so the guard-rail
guides future code without breaking the 0-errors lint gate (project policy:
0 errors, warnings tolerated).

---------

Co-authored-by: diegosouzapw <diegosouza.pw@gmail.com>
2026-06-03 18:58:01 -03:00
Diego Rodrigues de Sa e Souza
ed170229e7 fix(responses): resolve bare ChatGPT model ids to codex on HTTP fallback path (#3113)
When the Codex CLI falls back from WebSocket to HTTP (after 1008 Policy
Violation or reconnect exhaustion), it POSTs to /v1/responses with the
bare model id it was configured with (e.g. "gpt-5.5") — never the
provider-prefixed form. OmniRoute's normal routing resolved that bare id
to openrouter, not codex, producing:

  "No credentials for provider: openrouter"

Fix: add resolveResponsesApiModel() (extending modelResolution.ts) and
call it in /v1/responses before delegating to handleChat. The function
applies the same codex-preference logic as resolveCodexWsModelInfo:

  bare "gpt-5.5" → codex/gpt-5.5 has a codex provider → rewrite 
  bare "gpt-4o"  → codex/gpt-4o not in registry      → pass through 
  "anthropic/x"  → has "/" → skip resolution           → pass through 

Errors are caught; original request is returned on any failure.
8 unit tests added (TDD — watched each fail before implementing).

Refs: openai/codex#15492, openai/codex#13041, openai/codex#13039
2026-06-03 18:12:34 -03:00
Diego Rodrigues de Sa e Souza
5f7f74dc6a fix(dashboard): qualify vendor-namespaced Playground models with provider prefix (#3050) (#3102)
The provider Playground (LlmChatCard) only added the providerId/ prefix to models without a slash, so vendor-namespaced ids (moonshotai/kimi-k2.6, nvidia/zyphra/...) were sent bare and rejected with 'Ambiguous model' when the same id exists under multiple providers. Extracted qualifyPlaygroundModel() which always prefixes with the provider unless already qualified. Bug 1 ('unhashable type: dict') is an upstream NVIDIA NIM server error, not OmniRoute. Tests: 4 cases for the qualifier.
2026-06-03 07:56:16 -03:00
Diego Rodrigues de Sa e Souza
8a25d9e229 fix(dashboard): make 'Import from /models' work for no-auth providers (#3047) (#3099)
No-auth providers (OpenCode Free) have no connection row, so handleImportModels returned early and /api/providers/[id]/models 404'd — the import button silently no-op'd. The route now serves the provider's registry/static model catalog when called with a no-auth provider id, and handleImportModels falls back to the provider id when there is no connection. Test: route returns the opencode catalog (source local_catalog) and still 404s for unknown ids.
2026-06-03 07:48:19 -03:00
Xiangzhe
948f232517 fix: sync SiliconFlow models from configured endpoint (#3094)
Integrated into release/v3.8.9. SiliconFlow tests pass.
2026-06-03 07:19:38 -03:00
Brandon Bennett
9db306e2f8 feat(observability): add Obsidian context source with 24 MCP tools (#3077)
Integrated into release/v3.8.9. Fixes applied: removed .serena/ from repo (gitignored), resolved import conflicts preserving agentSkillTools, fixed TS errors.
2026-06-03 06:45:04 -03:00
Paijo
9141e98458 fix(providers): fix claude-web 403, move no-auth providers out of web-cookie (#3090)
Integrated into release/v3.8.9 — resolved conflicts with release branch (allowAutoSolve:true preserved, duckduckgo-web correctly kept in NOAUTH_PROVIDERS).
2026-06-03 06:35:45 -03:00
diegosouzapw
5943e5d528 feat: add Codex WS flag and Xiaomi MiMo usage tracking
Add a global OMNIROUTE_CODEX_WS_ENABLED kill-switch for Codex WebSocket transport, defaulting to enabled if feature flag lookup fails.

Track Xiaomi MiMo monthly token usage from OmniRoute usage history and expose it through the usage fetcher provider list.
2026-06-03 00:41:11 -03:00
diegosouzapw
0f900f1d56 fix(usage): handle MiniMax coding plan percent quotas
Support MiniMax Coding Plan quota responses that expose remaining usage as
percentages instead of request counts, including the text quota surfaced under
the `general` model.

Also document Codex CLI WebSocket configuration, clarifying that bare ChatGPT
model ids must be used instead of `codex/`-prefixed ids.
2026-06-03 00:41:10 -03:00
diegosouzapw
705ab8e690 fix(quality): clear SonarCloud quality-gate findings on PR #2930
Quality Gate was failing on New Code with 1 hotspot, 1 vulnerability and
4 reliability bugs. Resolved each at the source (no SonarCloud mark-as-safe):

Reliability (4 bugs → rating back to A):
- usage.ts: drop duplicate `case "opencode-go"` (S1862) — the 2nd case was
  dead (first match wins) and would have called the wrong usage fetcher.
  Also de-duplicate the same id in USAGE_FETCHER_PROVIDERS (mirrors the switch;
  prevented a double quota-fetcher registration).
- ApiManagerPageClient.tsx: a dangling `.find(...)?.timestamp || null` expression
  (S905) discarded the better matcher — `lastUsed` silently lost the
  name-fallback for legacy logs without apiKeyId. Assign the complete matcher.
- chat.ts / auth.ts: `Promise` used in a boolean conditional (S6544). Both are
  intentional (memoized promise / mutex default), not a forgotten await —
  made the intent explicit via `!== null` and `??` (behaviour identical).

Security (vulnerability → rating back to A):
- nvidia-startswith-diag.ts: neutralize CR/LF before logging env-derived
  values (S5145 log injection) in the ad-hoc diagnostic script.

Security Hotspot (reviewed → 0 open):
- pluginWorker.ts uses `vm.runInContext` to run plugin code — that IS the
  worker's purpose, inside a hardened vm sandbox (createContext, require
  allow-list of just `crypto`, 10s timeout); not eval/new Function. Suppress
  S1523 scoped only to pluginWorker.ts in sonar-project.properties, with the
  same documented-justification pattern as the existing hotspot suppressions.
2026-06-03 00:17:56 -03:00
diegosouzapw
72b4804c1b Merge main into release/v3.8.8
Back-merge to resolve PR #2930 (release/v3.8.8 -> main) conflicts. Release is a
superset of main's features, so all ~44 content conflicts resolved to the
release ("ours") version; generated .source/* dropped.

Reconciliation:
- auth.ts: port #3058 (getProviderSearchPool expands custom provider_nodes
  prefixes to internal connection ids) — release lacked this main fix.
- quota-plan-registry.test.ts: align knownProviders() 6 -> 10 (pre-existing
  stale assertion vs the registry).
2026-06-02 17:46:48 -03:00
diegosouzapw
e438139b03 feat(quota): live real-time codex quota on the page (cascade-safe serialized refresh)
Symptom: freshly-added Codex accounts (e.g. davi/gabriel) showed "No quota data"
even when healthy. Root cause: the quota path reuses the access_token without
refreshing rotating providers (#3019, anti Auth0 family-revocation cascade), so a
Codex account whose short-lived access_token has expired can never surface quota
from the sync — the live fetch returns "Codex token expired".

Fix (opt-in, cascade-safe):
- refreshAndUpdateCredentials gains `allowRotatingRefresh` + a pure exported gate
  `shouldAttemptRotatingRefresh`. The actual token mint is wrapped in
  `serializeRefresh` (one refresh at a time per Auth0 rotation group) — so even N
  concurrent per-account requests can never refresh siblings in parallel.
- The BULK scheduler (syncAllProviderLimits, concurrent) keeps the flag OFF →
  #3019 fully preserved (guardian test codex-quota-sync-no-proactive-refresh stays
  green). Only the on-demand, per-connection path (`GET /api/usage/[connectionId]`)
  opts in.
- Frontend: the quota page auto-fetches LIVE on open for the VISIBLE connections
  that have no cached quota (scoped to what's on screen — not all connections —
  and skips entries already cached), so expired-token Codex accounts surface real
  quota automatically and cascade-safely.

Adds unit coverage for the gate (bulk skips rotating, on-demand allows; non-rotating
always eligible). typecheck / lint clean.
2026-06-02 09:53:50 -03:00
diegosouzapw
8277b98003 feat(api-manager): split keys into Normal vs Quota sections (compact 2-table layout)
The key list stacked many badges in one column (tall/cluttered) and didn't
distinguish quota keys. Now renders two sections — "Normal keys" and "Quota keys"
(purple QUOTA pill) — sharing the same compact table header via an extracted
renderKeyRow(). Quota rows prepend a qtSd-only mode chip + group-name chips
(resolved by fetching /api/quota/pools + /api/quota/groups → poolId→group map).
Empty sections are hidden. i18n en/pt-BR for the new labels.

Source-scan test + i18n parity in api-manager-quota-keys-section.test.ts.
2026-06-02 07:06:00 -03:00
Xiangzhe
62f08de540 fix(home): pass providerId to quota widget icons (#3064)
Co-authored-by: xz-dev <xz-dev@users.noreply.github.com>
2026-06-02 05:14:23 -03:00
diegosouzapw
831f82858f feat(quota-share): beta banner, Responses + codex-WS endpoints in card, plan presets
- Beta banner scoped to the Quota Share page (functional-but-bugs-expected) with a
  pre-filled "open an issue" link (labels quota-share,beta). Page-only.
- Endpoints card now also surfaces POST /v1/responses (codex/github) and the
  codex-only WS /v1/responses line (the Responses-over-WebSocket proxy), each gated
  on the in-scope provider slug.
- planRegistry: seed xiaomi-mimo (4.1B-token weekly "lite" cap) and kimi-coding so the
  PoolWizard "Limite" step pre-fills a fair-share limit for these no-balance-API
  providers (fair-share enforces from the proxy's own token count, not an upstream
  balance — set the real cap manually in step 2).
- docs(API_REFERENCE): document the codex Responses-over-WebSocket endpoint.
- i18n en/pt-BR for all new keys.

Tracked in _tasks/features-v3.8.8/quota-share-key-redesign.plan.md (codex-WS config
toggle + per-provider balance fetchers + %-quota attribution are planned follow-ups).
2026-06-02 05:02:52 -03:00
diegosouzapw
11eb74c828 fix(quota-share): endpoints card default view shows real qtSd combos, not placeholders
The "Available endpoints" card's no-key (default) view generated representative
model ids from a hardcoded PREVIEW_MODELS_BY_PROVIDER map, so providers absent
from that map (claude, xiaomi-mimo, kimi-coding) rendered fake "model-a/b/c"
placeholders. It now fetches the REAL minted qtSd/* combos from /api/combos,
parses them (parseQuotaModelName), and groups by group → provider — falling back
to the placeholder map only when the fetch fails or returns nothing. The per-key
view already showed real models via /api/quota/keys/[id]/models; this aligns the
default view with it.

Verified on the local VPS: an exclusive key (share01) returns ONLY the real qtSd
models of its groups (claudao + chinas) and a non-quota key returns []. The
remaining /v1/models leak (non-quota keys still see qtSd among all models) is
tracked in the quota-key redesign plan.
2026-06-02 03:43:23 -03:00
CitrusIce
7b87d2f169 fix(combo): align custom provider ids across creation and auth lookup (#3058)
* fix(combo): align custom provider ids

* fix(combo): tighten alias resolution

---------

Co-authored-by: minisforum <no@mail.com>
2026-06-02 02:18:06 -03:00