From a5c0576c3b5975bb3c517fbe952f1106646e9f84 Mon Sep 17 00:00:00 2001 From: diegosouzapw Date: Fri, 19 Jun 2026 07:14:16 -0300 Subject: [PATCH 01/74] chore(release): open v3.8.30 development cycle --- CHANGELOG.md | 6 ++++++ docs/i18n/ar/CHANGELOG.md | 6 ++++++ docs/i18n/az/CHANGELOG.md | 6 ++++++ docs/i18n/bg/CHANGELOG.md | 6 ++++++ docs/i18n/bn/CHANGELOG.md | 6 ++++++ docs/i18n/cs/CHANGELOG.md | 6 ++++++ docs/i18n/da/CHANGELOG.md | 6 ++++++ docs/i18n/de/CHANGELOG.md | 6 ++++++ docs/i18n/es/CHANGELOG.md | 6 ++++++ docs/i18n/fa/CHANGELOG.md | 6 ++++++ docs/i18n/fi/CHANGELOG.md | 6 ++++++ docs/i18n/fr/CHANGELOG.md | 6 ++++++ docs/i18n/gu/CHANGELOG.md | 6 ++++++ docs/i18n/he/CHANGELOG.md | 6 ++++++ docs/i18n/hi/CHANGELOG.md | 6 ++++++ docs/i18n/hu/CHANGELOG.md | 6 ++++++ docs/i18n/id/CHANGELOG.md | 6 ++++++ docs/i18n/in/CHANGELOG.md | 6 ++++++ docs/i18n/it/CHANGELOG.md | 6 ++++++ docs/i18n/ja/CHANGELOG.md | 6 ++++++ docs/i18n/ko/CHANGELOG.md | 6 ++++++ docs/i18n/mr/CHANGELOG.md | 6 ++++++ docs/i18n/ms/CHANGELOG.md | 6 ++++++ docs/i18n/nl/CHANGELOG.md | 6 ++++++ docs/i18n/no/CHANGELOG.md | 6 ++++++ docs/i18n/phi/CHANGELOG.md | 6 ++++++ docs/i18n/pl/CHANGELOG.md | 6 ++++++ docs/i18n/pt-BR/CHANGELOG.md | 6 ++++++ docs/i18n/pt/CHANGELOG.md | 6 ++++++ docs/i18n/ro/CHANGELOG.md | 6 ++++++ docs/i18n/ru/CHANGELOG.md | 6 ++++++ docs/i18n/sk/CHANGELOG.md | 6 ++++++ docs/i18n/sv/CHANGELOG.md | 6 ++++++ docs/i18n/sw/CHANGELOG.md | 6 ++++++ docs/i18n/ta/CHANGELOG.md | 6 ++++++ docs/i18n/te/CHANGELOG.md | 6 ++++++ docs/i18n/th/CHANGELOG.md | 6 ++++++ docs/i18n/tr/CHANGELOG.md | 6 ++++++ docs/i18n/uk-UA/CHANGELOG.md | 6 ++++++ docs/i18n/ur/CHANGELOG.md | 6 ++++++ docs/i18n/vi/CHANGELOG.md | 6 ++++++ docs/i18n/zh-CN/CHANGELOG.md | 6 ++++++ docs/reference/openapi.yaml | 2 +- electron/package-lock.json | 4 ++-- electron/package.json | 2 +- open-sse/package.json | 2 +- package-lock.json | 6 +++--- package.json | 2 +- 48 files changed, 261 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 442f581904c9..a098f75312d5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,12 @@ --- +## [3.8.30] — TBD + +_In development — bullets added per PR; finalized at release._ + +--- + ## [3.8.29] — 2026-06-19 ### ✨ New Features diff --git a/docs/i18n/ar/CHANGELOG.md b/docs/i18n/ar/CHANGELOG.md index b63570a59b6a..9907f91bb3b0 100644 --- a/docs/i18n/ar/CHANGELOG.md +++ b/docs/i18n/ar/CHANGELOG.md @@ -4,6 +4,12 @@ --- +## [3.8.30] — TBD + +_See English CHANGELOG for v3.8.30 details._ + +--- + ## [3.8.29] — 2026-06-19 ### ✨ New Features diff --git a/docs/i18n/az/CHANGELOG.md b/docs/i18n/az/CHANGELOG.md index d8a95c191202..5c62db0ab822 100644 --- a/docs/i18n/az/CHANGELOG.md +++ b/docs/i18n/az/CHANGELOG.md @@ -4,6 +4,12 @@ --- +## [3.8.30] — TBD + +_See English CHANGELOG for v3.8.30 details._ + +--- + ## [3.8.29] — 2026-06-19 ### ✨ New Features diff --git a/docs/i18n/bg/CHANGELOG.md b/docs/i18n/bg/CHANGELOG.md index d8a95c191202..5c62db0ab822 100644 --- a/docs/i18n/bg/CHANGELOG.md +++ b/docs/i18n/bg/CHANGELOG.md @@ -4,6 +4,12 @@ --- +## [3.8.30] — TBD + +_See English CHANGELOG for v3.8.30 details._ + +--- + ## [3.8.29] — 2026-06-19 ### ✨ New Features diff --git a/docs/i18n/bn/CHANGELOG.md b/docs/i18n/bn/CHANGELOG.md index 7601b3631fd8..0510df08babe 100644 --- a/docs/i18n/bn/CHANGELOG.md +++ b/docs/i18n/bn/CHANGELOG.md @@ -4,6 +4,12 @@ --- +## [3.8.30] — TBD + +_See English CHANGELOG for v3.8.30 details._ + +--- + ## [3.8.29] — 2026-06-19 ### ✨ New Features diff --git a/docs/i18n/cs/CHANGELOG.md b/docs/i18n/cs/CHANGELOG.md index 377f3274edfe..d2af0546f6b0 100644 --- a/docs/i18n/cs/CHANGELOG.md +++ b/docs/i18n/cs/CHANGELOG.md @@ -4,6 +4,12 @@ --- +## [3.8.30] — TBD + +_See English CHANGELOG for v3.8.30 details._ + +--- + ## [3.8.29] — 2026-06-19 ### ✨ New Features diff --git a/docs/i18n/da/CHANGELOG.md b/docs/i18n/da/CHANGELOG.md index 4fbdc37c7fe2..1483d835d673 100644 --- a/docs/i18n/da/CHANGELOG.md +++ b/docs/i18n/da/CHANGELOG.md @@ -4,6 +4,12 @@ --- +## [3.8.30] — TBD + +_See English CHANGELOG for v3.8.30 details._ + +--- + ## [3.8.29] — 2026-06-19 ### ✨ New Features diff --git a/docs/i18n/de/CHANGELOG.md b/docs/i18n/de/CHANGELOG.md index a0d876fbf1e3..6860d238604a 100644 --- a/docs/i18n/de/CHANGELOG.md +++ b/docs/i18n/de/CHANGELOG.md @@ -4,6 +4,12 @@ --- +## [3.8.30] — TBD + +_See English CHANGELOG for v3.8.30 details._ + +--- + ## [3.8.29] — 2026-06-19 ### ✨ New Features diff --git a/docs/i18n/es/CHANGELOG.md b/docs/i18n/es/CHANGELOG.md index 62bbdf0123ed..6a60c3344a36 100644 --- a/docs/i18n/es/CHANGELOG.md +++ b/docs/i18n/es/CHANGELOG.md @@ -4,6 +4,12 @@ --- +## [3.8.30] — TBD + +_See English CHANGELOG for v3.8.30 details._ + +--- + ## [3.8.29] — 2026-06-19 ### ✨ New Features diff --git a/docs/i18n/fa/CHANGELOG.md b/docs/i18n/fa/CHANGELOG.md index b5e817398aee..b2b4033ea69c 100644 --- a/docs/i18n/fa/CHANGELOG.md +++ b/docs/i18n/fa/CHANGELOG.md @@ -4,6 +4,12 @@ --- +## [3.8.30] — TBD + +_See English CHANGELOG for v3.8.30 details._ + +--- + ## [3.8.29] — 2026-06-19 ### ✨ New Features diff --git a/docs/i18n/fi/CHANGELOG.md b/docs/i18n/fi/CHANGELOG.md index e5b16cd3a608..85ad82fd6b04 100644 --- a/docs/i18n/fi/CHANGELOG.md +++ b/docs/i18n/fi/CHANGELOG.md @@ -4,6 +4,12 @@ --- +## [3.8.30] — TBD + +_See English CHANGELOG for v3.8.30 details._ + +--- + ## [3.8.29] — 2026-06-19 ### ✨ New Features diff --git a/docs/i18n/fr/CHANGELOG.md b/docs/i18n/fr/CHANGELOG.md index a599d5dd3cf1..d55e8efa79d6 100644 --- a/docs/i18n/fr/CHANGELOG.md +++ b/docs/i18n/fr/CHANGELOG.md @@ -4,6 +4,12 @@ --- +## [3.8.30] — TBD + +_See English CHANGELOG for v3.8.30 details._ + +--- + ## [3.8.29] — 2026-06-19 ### ✨ New Features diff --git a/docs/i18n/gu/CHANGELOG.md b/docs/i18n/gu/CHANGELOG.md index e3d09b2d8594..6def692e174c 100644 --- a/docs/i18n/gu/CHANGELOG.md +++ b/docs/i18n/gu/CHANGELOG.md @@ -4,6 +4,12 @@ --- +## [3.8.30] — TBD + +_See English CHANGELOG for v3.8.30 details._ + +--- + ## [3.8.29] — 2026-06-19 ### ✨ New Features diff --git a/docs/i18n/he/CHANGELOG.md b/docs/i18n/he/CHANGELOG.md index befa055c6d03..e6bbb24fc7fa 100644 --- a/docs/i18n/he/CHANGELOG.md +++ b/docs/i18n/he/CHANGELOG.md @@ -4,6 +4,12 @@ --- +## [3.8.30] — TBD + +_See English CHANGELOG for v3.8.30 details._ + +--- + ## [3.8.29] — 2026-06-19 ### ✨ New Features diff --git a/docs/i18n/hi/CHANGELOG.md b/docs/i18n/hi/CHANGELOG.md index 14d76393cef6..86cced1324c0 100644 --- a/docs/i18n/hi/CHANGELOG.md +++ b/docs/i18n/hi/CHANGELOG.md @@ -4,6 +4,12 @@ --- +## [3.8.30] — TBD + +_See English CHANGELOG for v3.8.30 details._ + +--- + ## [3.8.29] — 2026-06-19 ### ✨ New Features diff --git a/docs/i18n/hu/CHANGELOG.md b/docs/i18n/hu/CHANGELOG.md index c0114a710c3d..381ac584b4c9 100644 --- a/docs/i18n/hu/CHANGELOG.md +++ b/docs/i18n/hu/CHANGELOG.md @@ -4,6 +4,12 @@ --- +## [3.8.30] — TBD + +_See English CHANGELOG for v3.8.30 details._ + +--- + ## [3.8.29] — 2026-06-19 ### ✨ New Features diff --git a/docs/i18n/id/CHANGELOG.md b/docs/i18n/id/CHANGELOG.md index bc0ac07019e9..c916318d95be 100644 --- a/docs/i18n/id/CHANGELOG.md +++ b/docs/i18n/id/CHANGELOG.md @@ -4,6 +4,12 @@ --- +## [3.8.30] — TBD + +_See English CHANGELOG for v3.8.30 details._ + +--- + ## [3.8.29] — 2026-06-19 ### ✨ New Features diff --git a/docs/i18n/in/CHANGELOG.md b/docs/i18n/in/CHANGELOG.md index b13f260523d3..71ae655755e8 100644 --- a/docs/i18n/in/CHANGELOG.md +++ b/docs/i18n/in/CHANGELOG.md @@ -4,6 +4,12 @@ --- +## [3.8.30] — TBD + +_See English CHANGELOG for v3.8.30 details._ + +--- + ## [3.8.29] — 2026-06-19 ### ✨ New Features diff --git a/docs/i18n/it/CHANGELOG.md b/docs/i18n/it/CHANGELOG.md index db20d62978dc..8c6abbb898e0 100644 --- a/docs/i18n/it/CHANGELOG.md +++ b/docs/i18n/it/CHANGELOG.md @@ -4,6 +4,12 @@ --- +## [3.8.30] — TBD + +_See English CHANGELOG for v3.8.30 details._ + +--- + ## [3.8.29] — 2026-06-19 ### ✨ New Features diff --git a/docs/i18n/ja/CHANGELOG.md b/docs/i18n/ja/CHANGELOG.md index 06aa083a6657..087f412ed963 100644 --- a/docs/i18n/ja/CHANGELOG.md +++ b/docs/i18n/ja/CHANGELOG.md @@ -4,6 +4,12 @@ --- +## [3.8.30] — TBD + +_See English CHANGELOG for v3.8.30 details._ + +--- + ## [3.8.29] — 2026-06-19 ### ✨ New Features diff --git a/docs/i18n/ko/CHANGELOG.md b/docs/i18n/ko/CHANGELOG.md index 41ccfeb7bdb1..e5c44b0c86ef 100644 --- a/docs/i18n/ko/CHANGELOG.md +++ b/docs/i18n/ko/CHANGELOG.md @@ -4,6 +4,12 @@ --- +## [3.8.30] — TBD + +_See English CHANGELOG for v3.8.30 details._ + +--- + ## [3.8.29] — 2026-06-19 ### ✨ New Features diff --git a/docs/i18n/mr/CHANGELOG.md b/docs/i18n/mr/CHANGELOG.md index 166ad11d0e93..5ad9641aaea9 100644 --- a/docs/i18n/mr/CHANGELOG.md +++ b/docs/i18n/mr/CHANGELOG.md @@ -4,6 +4,12 @@ --- +## [3.8.30] — TBD + +_See English CHANGELOG for v3.8.30 details._ + +--- + ## [3.8.29] — 2026-06-19 ### ✨ New Features diff --git a/docs/i18n/ms/CHANGELOG.md b/docs/i18n/ms/CHANGELOG.md index 6cf625e5085b..7ff721712a28 100644 --- a/docs/i18n/ms/CHANGELOG.md +++ b/docs/i18n/ms/CHANGELOG.md @@ -4,6 +4,12 @@ --- +## [3.8.30] — TBD + +_See English CHANGELOG for v3.8.30 details._ + +--- + ## [3.8.29] — 2026-06-19 ### ✨ New Features diff --git a/docs/i18n/nl/CHANGELOG.md b/docs/i18n/nl/CHANGELOG.md index c2d4099f3ff3..0cb713bbb443 100644 --- a/docs/i18n/nl/CHANGELOG.md +++ b/docs/i18n/nl/CHANGELOG.md @@ -4,6 +4,12 @@ --- +## [3.8.30] — TBD + +_See English CHANGELOG for v3.8.30 details._ + +--- + ## [3.8.29] — 2026-06-19 ### ✨ New Features diff --git a/docs/i18n/no/CHANGELOG.md b/docs/i18n/no/CHANGELOG.md index c8fc82d951df..3940a40d38a8 100644 --- a/docs/i18n/no/CHANGELOG.md +++ b/docs/i18n/no/CHANGELOG.md @@ -4,6 +4,12 @@ --- +## [3.8.30] — TBD + +_See English CHANGELOG for v3.8.30 details._ + +--- + ## [3.8.29] — 2026-06-19 ### ✨ New Features diff --git a/docs/i18n/phi/CHANGELOG.md b/docs/i18n/phi/CHANGELOG.md index d4e2a9f4d320..0389f27f6b2d 100644 --- a/docs/i18n/phi/CHANGELOG.md +++ b/docs/i18n/phi/CHANGELOG.md @@ -4,6 +4,12 @@ --- +## [3.8.30] — TBD + +_See English CHANGELOG for v3.8.30 details._ + +--- + ## [3.8.29] — 2026-06-19 ### ✨ New Features diff --git a/docs/i18n/pl/CHANGELOG.md b/docs/i18n/pl/CHANGELOG.md index a84f45a9b175..5b86b8bb5d08 100644 --- a/docs/i18n/pl/CHANGELOG.md +++ b/docs/i18n/pl/CHANGELOG.md @@ -4,6 +4,12 @@ --- +## [3.8.30] — TBD + +_See English CHANGELOG for v3.8.30 details._ + +--- + ## [3.8.29] — 2026-06-19 ### ✨ New Features diff --git a/docs/i18n/pt-BR/CHANGELOG.md b/docs/i18n/pt-BR/CHANGELOG.md index 4a98bd9f77ba..fb69dff78b75 100644 --- a/docs/i18n/pt-BR/CHANGELOG.md +++ b/docs/i18n/pt-BR/CHANGELOG.md @@ -4,6 +4,12 @@ --- +## [3.8.30] — TBD + +_See English CHANGELOG for v3.8.30 details._ + +--- + ## [3.8.29] — 2026-06-19 ### ✨ New Features diff --git a/docs/i18n/pt/CHANGELOG.md b/docs/i18n/pt/CHANGELOG.md index b2176d2dd7ca..2ba7b6995846 100644 --- a/docs/i18n/pt/CHANGELOG.md +++ b/docs/i18n/pt/CHANGELOG.md @@ -4,6 +4,12 @@ --- +## [3.8.30] — TBD + +_See English CHANGELOG for v3.8.30 details._ + +--- + ## [3.8.29] — 2026-06-19 ### ✨ New Features diff --git a/docs/i18n/ro/CHANGELOG.md b/docs/i18n/ro/CHANGELOG.md index cec32be3e962..4f70d4133cf8 100644 --- a/docs/i18n/ro/CHANGELOG.md +++ b/docs/i18n/ro/CHANGELOG.md @@ -4,6 +4,12 @@ --- +## [3.8.30] — TBD + +_See English CHANGELOG for v3.8.30 details._ + +--- + ## [3.8.29] — 2026-06-19 ### ✨ New Features diff --git a/docs/i18n/ru/CHANGELOG.md b/docs/i18n/ru/CHANGELOG.md index 1186d4ff73c2..849b5d700a64 100644 --- a/docs/i18n/ru/CHANGELOG.md +++ b/docs/i18n/ru/CHANGELOG.md @@ -4,6 +4,12 @@ --- +## [3.8.30] — TBD + +_See English CHANGELOG for v3.8.30 details._ + +--- + ## [3.8.29] — 2026-06-19 ### ✨ New Features diff --git a/docs/i18n/sk/CHANGELOG.md b/docs/i18n/sk/CHANGELOG.md index 9ef7d66e5bab..705120fae844 100644 --- a/docs/i18n/sk/CHANGELOG.md +++ b/docs/i18n/sk/CHANGELOG.md @@ -4,6 +4,12 @@ --- +## [3.8.30] — TBD + +_See English CHANGELOG for v3.8.30 details._ + +--- + ## [3.8.29] — 2026-06-19 ### ✨ New Features diff --git a/docs/i18n/sv/CHANGELOG.md b/docs/i18n/sv/CHANGELOG.md index a13330e6c829..9a38010e3a69 100644 --- a/docs/i18n/sv/CHANGELOG.md +++ b/docs/i18n/sv/CHANGELOG.md @@ -4,6 +4,12 @@ --- +## [3.8.30] — TBD + +_See English CHANGELOG for v3.8.30 details._ + +--- + ## [3.8.29] — 2026-06-19 ### ✨ New Features diff --git a/docs/i18n/sw/CHANGELOG.md b/docs/i18n/sw/CHANGELOG.md index dc1429ba8d42..4d4c646da2b8 100644 --- a/docs/i18n/sw/CHANGELOG.md +++ b/docs/i18n/sw/CHANGELOG.md @@ -4,6 +4,12 @@ --- +## [3.8.30] — TBD + +_See English CHANGELOG for v3.8.30 details._ + +--- + ## [3.8.29] — 2026-06-19 ### ✨ New Features diff --git a/docs/i18n/ta/CHANGELOG.md b/docs/i18n/ta/CHANGELOG.md index aa2e7ae930d3..a4ded531845d 100644 --- a/docs/i18n/ta/CHANGELOG.md +++ b/docs/i18n/ta/CHANGELOG.md @@ -4,6 +4,12 @@ --- +## [3.8.30] — TBD + +_See English CHANGELOG for v3.8.30 details._ + +--- + ## [3.8.29] — 2026-06-19 ### ✨ New Features diff --git a/docs/i18n/te/CHANGELOG.md b/docs/i18n/te/CHANGELOG.md index a4a6c2d7019d..6cda7131d3d3 100644 --- a/docs/i18n/te/CHANGELOG.md +++ b/docs/i18n/te/CHANGELOG.md @@ -4,6 +4,12 @@ --- +## [3.8.30] — TBD + +_See English CHANGELOG for v3.8.30 details._ + +--- + ## [3.8.29] — 2026-06-19 ### ✨ New Features diff --git a/docs/i18n/th/CHANGELOG.md b/docs/i18n/th/CHANGELOG.md index 5f2de98e86fb..4470761d5608 100644 --- a/docs/i18n/th/CHANGELOG.md +++ b/docs/i18n/th/CHANGELOG.md @@ -4,6 +4,12 @@ --- +## [3.8.30] — TBD + +_See English CHANGELOG for v3.8.30 details._ + +--- + ## [3.8.29] — 2026-06-19 ### ✨ New Features diff --git a/docs/i18n/tr/CHANGELOG.md b/docs/i18n/tr/CHANGELOG.md index 87db93102cef..a1ace61b2457 100644 --- a/docs/i18n/tr/CHANGELOG.md +++ b/docs/i18n/tr/CHANGELOG.md @@ -4,6 +4,12 @@ --- +## [3.8.30] — TBD + +_See English CHANGELOG for v3.8.30 details._ + +--- + ## [3.8.29] — 2026-06-19 ### ✨ New Features diff --git a/docs/i18n/uk-UA/CHANGELOG.md b/docs/i18n/uk-UA/CHANGELOG.md index 5879094fcaad..c7822fdd6d87 100644 --- a/docs/i18n/uk-UA/CHANGELOG.md +++ b/docs/i18n/uk-UA/CHANGELOG.md @@ -4,6 +4,12 @@ --- +## [3.8.30] — TBD + +_See English CHANGELOG for v3.8.30 details._ + +--- + ## [3.8.29] — 2026-06-19 ### ✨ New Features diff --git a/docs/i18n/ur/CHANGELOG.md b/docs/i18n/ur/CHANGELOG.md index be21fb32a509..a1b65e8f08ae 100644 --- a/docs/i18n/ur/CHANGELOG.md +++ b/docs/i18n/ur/CHANGELOG.md @@ -4,6 +4,12 @@ --- +## [3.8.30] — TBD + +_See English CHANGELOG for v3.8.30 details._ + +--- + ## [3.8.29] — 2026-06-19 ### ✨ New Features diff --git a/docs/i18n/vi/CHANGELOG.md b/docs/i18n/vi/CHANGELOG.md index 67e980004edd..8ce2ca5a9217 100644 --- a/docs/i18n/vi/CHANGELOG.md +++ b/docs/i18n/vi/CHANGELOG.md @@ -4,6 +4,12 @@ --- +## [3.8.30] — TBD + +_See English CHANGELOG for v3.8.30 details._ + +--- + ## [3.8.29] — 2026-06-19 ### ✨ New Features diff --git a/docs/i18n/zh-CN/CHANGELOG.md b/docs/i18n/zh-CN/CHANGELOG.md index a463c503ab89..3845ab12dd53 100644 --- a/docs/i18n/zh-CN/CHANGELOG.md +++ b/docs/i18n/zh-CN/CHANGELOG.md @@ -4,6 +4,12 @@ --- +## [3.8.30] — TBD + +_See English CHANGELOG for v3.8.30 details._ + +--- + ## [3.8.29] — 2026-06-19 ### ✨ New Features diff --git a/docs/reference/openapi.yaml b/docs/reference/openapi.yaml index 519c20797aaf..6f59c196248e 100644 --- a/docs/reference/openapi.yaml +++ b/docs/reference/openapi.yaml @@ -1,7 +1,7 @@ openapi: 3.1.0 info: title: OmniRoute API - version: 3.8.29 + version: 3.8.30 description: | OmniRoute is a local-first AI API proxy router. It provides an OpenAI-compatible endpoint that routes requests to multiple AI providers with load balancing, diff --git a/electron/package-lock.json b/electron/package-lock.json index e216407f05b4..6de22529aafa 100644 --- a/electron/package-lock.json +++ b/electron/package-lock.json @@ -1,12 +1,12 @@ { "name": "omniroute-desktop", - "version": "3.8.29", + "version": "3.8.30", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "omniroute-desktop", - "version": "3.8.29", + "version": "3.8.30", "license": "MIT", "dependencies": { "electron-updater": "^6.8.9" diff --git a/electron/package.json b/electron/package.json index a29b659b845e..5599de2ccc3f 100644 --- a/electron/package.json +++ b/electron/package.json @@ -1,6 +1,6 @@ { "name": "omniroute-desktop", - "version": "3.8.29", + "version": "3.8.30", "description": "OmniRoute Desktop Application", "main": "main.js", "author": { diff --git a/open-sse/package.json b/open-sse/package.json index 2f9c0ada1854..330b69e72abf 100644 --- a/open-sse/package.json +++ b/open-sse/package.json @@ -1,6 +1,6 @@ { "name": "@omniroute/open-sse", - "version": "3.8.29", + "version": "3.8.30", "description": "Express SSE sidecar for OmniRoute — handles streaming, protocol translation, and provider orchestration", "type": "module", "main": "index.js", diff --git a/package-lock.json b/package-lock.json index 562d70237607..77a475c19984 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "omniroute", - "version": "3.8.29", + "version": "3.8.30", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "omniroute", - "version": "3.8.29", + "version": "3.8.30", "hasInstallScript": true, "license": "MIT", "workspaces": [ @@ -28227,7 +28227,7 @@ }, "open-sse": { "name": "@omniroute/open-sse", - "version": "3.8.29" + "version": "3.8.30" } } } diff --git a/package.json b/package.json index 20fce8d61548..d22a8838bfc0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "omniroute", - "version": "3.8.29", + "version": "3.8.30", "description": "Unified AI router with 160+ providers, RTK+Caveman compression, auto fallback, MCP/A2A, desktop, PWA, and OpenAI-compatible APIs.", "type": "module", "bin": { From c34d37a11ee9e4b188cdeb896fe7b04c753c43f5 Mon Sep 17 00:00:00 2001 From: Diego Rodrigues de Sa e Souza <8016841+diegosouzapw@users.noreply.github.com> Date: Fri, 19 Jun 2026 09:36:41 -0300 Subject: [PATCH 02/74] feat(cli): Codex CLI launcher + setup commands (#4270) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat(cli): Codex CLI launcher + setup commands Two new CLI subcommands mirroring the `launch`/`configure` pattern, for driving the OpenAI Codex CLI against OmniRoute: - `omniroute launch-codex` — boots OmniRoute (if needed) and launches Codex CLI pointed at it (local or remote VPS), with no manual env/config editing. - `omniroute setup-codex` — generates ~/.codex profile files from OmniRoute's live model catalog. Registered in the command registry; en.json + pt-BR.json locale sections added (keeps the cli-i18n-catalog top-level parity gate green). CODEX-CLI-CONFIGURATION.md refreshed. Consolidated from work-in-progress that was uncommitted on the shared checkout; reconstructed on release/v3.8.30. * chore(vscode): reduce git repo-detection overhead for nested worktrees Disable VS Code's git auto-repository-detection / submodule scan / autofetch so the Source Control view stops indexing the ~44 nested repos (worktrees + _references/* + _mono_repo/*), which caused constant "validating" churn. Only the root repo is tracked. Editor-only settings; no runtime impact. --- .vscode/settings.json | 9 + bin/cli/commands/launch-codex.mjs | 103 +++++++ bin/cli/commands/registry.mjs | 4 + bin/cli/commands/setup-codex.mjs | 223 ++++++++++++++ bin/cli/locales/en.json | 6 + bin/cli/locales/pt-BR.json | 6 + docs/guides/CODEX-CLI-CONFIGURATION.md | 393 ++++++++++++++----------- 7 files changed, 568 insertions(+), 176 deletions(-) create mode 100644 bin/cli/commands/launch-codex.mjs create mode 100644 bin/cli/commands/setup-codex.mjs diff --git a/.vscode/settings.json b/.vscode/settings.json index c5699ad0fa1f..261dc258aaf2 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -20,6 +20,15 @@ }, "git.ignoreLimitWarning": true, + // ─── Git: não adicionar os ~44 repos aninhados (9 worktrees + _references/* + + // _mono_repo/* + _ideia/_tasks/.agents) ao Source Control. Era a causa do + // "validando muito": um git status + watcher por repo. Só o repo raiz fica. ─── + "git.autoRepositoryDetection": false, + "git.repositoryScanMaxDepth": 0, + "git.detectSubmodules": false, + "git.autofetch": false, + "git.autorefresh": true, + // ─── Performance: não seguir o symlink de node_modules criado pelas worktrees ─── // As worktrees em .worktrees/ apontam node_modules para o checkout principal; // sem isto a busca atravessa o symlink mesmo com node_modules excluído. diff --git a/bin/cli/commands/launch-codex.mjs b/bin/cli/commands/launch-codex.mjs new file mode 100644 index 000000000000..76e77799014a --- /dev/null +++ b/bin/cli/commands/launch-codex.mjs @@ -0,0 +1,103 @@ +import { spawn } from "node:child_process"; +import { t } from "../i18n.mjs"; + +/** + * Health-check an OmniRoute endpoint (local or remote) before launching Codex. + * @param {string} baseUrl + * @param {number} timeoutMs + * @returns {Promise} + */ +async function healthCheck(baseUrl, timeoutMs = 3000) { + try { + const res = await fetch(`${baseUrl.replace(/\/v1$/, "")}/api/monitoring/health`, { + signal: AbortSignal.timeout(timeoutMs), + }); + return res.ok; + } catch { + return false; + } +} + +/** + * Build the env for the Codex child process. + * Injects OMNIROUTE_API_KEY if an explicit api-key was provided on the command line + * (useful when launching against a remote VPS whose key differs from ~/.bashrc). + * @param {Record} baseEnv + * @param {string|undefined} apiKey + * @returns {Record} + */ +export function buildCodexEnv(baseEnv, apiKey) { + const env = { ...baseEnv }; + if (apiKey) env.OMNIROUTE_API_KEY = apiKey; + return env; +} + +/** + * @param {{port?:string, remote?:string, profile?:string, apiKey?:string}} opts + * @param {string[]} codexArgs pass-through args for the codex binary + * @returns {Promise} exit code + */ +export async function runLaunchCodexCommand(opts = {}, codexArgs = []) { + const port = Number(opts.port ?? process.env.PORT ?? 20128) || 20128; + const baseUrl = opts.remote ?? `http://localhost:${port}/v1`; + + const ok = await healthCheck(baseUrl); + if (!ok) { + const location = opts.remote ?? `port ${port}`; + console.error( + (t("launch.notRunning") || "OmniRoute is not running on port {port}. Start it with 'omniroute serve'.") + .replace("{port}", String(location)) + ); + return 1; + } + + const profile = opts.profile; + const extraArgs = profile ? ["--profile", profile, ...codexArgs] : codexArgs; + const env = buildCodexEnv(process.env, opts.apiKey ?? opts["api-key"]); + + return await new Promise((resolve) => { + const child = spawn("codex", extraArgs, { env, stdio: "inherit" }); + child.on("error", (err) => { + if (err?.code === "ENOENT") { + console.error( + "The 'codex' CLI was not found in PATH. Install with:\n" + + " npm install -g @openai/codex" + ); + resolve(127); + } else { + console.error(String(err?.message || err)); + resolve(1); + } + }); + child.on("exit", (code) => resolve(code ?? 0)); + }); +} + +export function registerLaunchCodex(program) { + program + .command("launch-codex") + .description( + t("launchCodex.description") || + "Launch Codex CLI pointed at OmniRoute (local or remote VPS)" + ) + .option("--port ", "Local OmniRoute port (ignored when --remote is set)", "20128") + .option( + "--remote ", + "Remote OmniRoute base URL, e.g. http://100.67.86.91:20128/v1 (overrides --port)" + ) + .option("--profile ", "Codex profile to activate (passed as --profile )") + .option("-p, --p ", "Alias for --profile") + .option( + "--api-key ", + "OmniRoute API key (overrides OMNIROUTE_API_KEY env var for this invocation)" + ) + .allowUnknownOption(true) + .allowExcessArguments(true) + .argument("[codexArgs...]", "arguments passed through to the codex binary") + .action(async (codexArgs, opts) => { + // -p is an alias for --profile + const merged = { ...opts, profile: opts.profile ?? opts.p }; + const exitCode = await runLaunchCodexCommand(merged, codexArgs ?? []); + if (exitCode !== 0) process.exit(exitCode); + }); +} diff --git a/bin/cli/commands/registry.mjs b/bin/cli/commands/registry.mjs index f3d4f197a1bb..bffba542cc0c 100644 --- a/bin/cli/commands/registry.mjs +++ b/bin/cli/commands/registry.mjs @@ -56,6 +56,8 @@ import { registerTray } from "./tray.mjs"; import { registerAutostart } from "./autostart.mjs"; import { registerRepl } from "./repl.mjs"; import { registerLaunch } from "./launch.mjs"; +import { registerLaunchCodex } from "./launch-codex.mjs"; +import { registerSetupCodex } from "./setup-codex.mjs"; import { registerConnect } from "./connect.mjs"; import { registerTokens } from "./tokens.mjs"; import { registerConfigure } from "./configure.mjs"; @@ -122,6 +124,8 @@ export function registerCommands(program) { registerAutostart(program); registerRepl(program); registerLaunch(program); + registerLaunchCodex(program); + registerSetupCodex(program); registerConnect(program); registerTokens(program); registerConfigure(program); diff --git a/bin/cli/commands/setup-codex.mjs b/bin/cli/commands/setup-codex.mjs new file mode 100644 index 000000000000..39d86fe89b6a --- /dev/null +++ b/bin/cli/commands/setup-codex.mjs @@ -0,0 +1,223 @@ +/** + * omniroute setup-codex — Remote-aware Codex CLI profile generator. + * + * Connects to a running OmniRoute instance (local or remote VPS), fetches the + * live model catalog via GET /v1/models, then generates ~/.codex/.config.toml + * profile files for each model — so you can switch providers with a single flag + * (`codex --profile glm52`) without editing config files by hand. + * + * Primary use-case: configure a local Codex CLI to use models from a VPS. + * omniroute setup-codex --remote http://100.67.86.91:20128 --api-key sk-xxx + * + * The command is idempotent: re-running updates existing profile files in place. + */ + +import { existsSync, mkdirSync, writeFileSync } from "node:fs"; +import { join } from "node:path"; +import os from "node:os"; +import { printHeading, printInfo, printSuccess, printError } from "../io.mjs"; +import { t } from "../i18n.mjs"; + +// ── Model categorisation ────────────────────────────────────────────────────── + +/** + * Map a model ID (as returned by /v1/models) to a Codex profile configuration. + * Returns null for models that should not get their own profile (e.g. aliases). + * + * @param {string} modelId + * @returns {{ name:string, ctx:number, compact:number, effort?:string, summary?:boolean, toolLimit:number }|null} + */ +function categoriseModel(modelId) { + const id = modelId.toLowerCase(); + + // ── Thinking models (max effort, detailed summary) ──────────────────────── + const thinkingPatterns = [ + { re: /kmc\/kimi-k2\.7/, name: "kimi-k27", ctx: 131072, compact: 112000, toolLimit: 32768 }, + { re: /kmc\/kimi-k2\.6/, name: "kimi-k26", ctx: 131072, compact: 112000, toolLimit: 32768 }, + { re: /glm\/glm-5\.2-max/, name: "glm52max", ctx: 131072, compact: 112000, toolLimit: 32768 }, + { re: /glm\/glm-5\.2$/, name: "glm52", ctx: 131072, compact: 112000, toolLimit: 32768 }, + { re: /opencode-go\/mimo-v2\.5-pro/, name: "mimo-pro", ctx: 131072, compact: 112000, toolLimit: 32768 }, + { re: /opencode-go\/qwen3\.7-plus/, name: "qwen37plus", ctx: 32768, compact: 28000, toolLimit: 16384 }, + ]; + + // ── Good models (high effort) ───────────────────────────────────────────── + const goodPatterns = [ + { re: /ollamacloud\/deepseek-v4-pro/, name: "deepseek-pro", ctx: 131072, compact: 112000, toolLimit: 32768 }, + { re: /opencode-go\/mimo-v2\.5$/, name: "mimo", ctx: 131072, compact: 112000, toolLimit: 32768 }, + ]; + + // ── Simple models (no effort) ───────────────────────────────────────────── + const simplePatterns = [ + { re: /ollamacloud\/gemma4:31b/, name: "gemma4", ctx: 32768, compact: 28000, toolLimit: 16384 }, + { re: /ollamacloud\/nemotron-3-super/, name: "nemotron", ctx: 32768, compact: 28000, toolLimit: 16384 }, + { re: /ollamacloud\/gpt-oss:20b/, name: "gptoss", ctx: 32768, compact: 28000, toolLimit: 16384 }, + ]; + + // ── Fast models (low effort) ────────────────────────────────────────────── + const fastPatterns = [ + { re: /ollamacloud\/deepseek-v4-flash/, name: "deepseek-flash", ctx: 65536, compact: 56000, toolLimit: 16384 }, + { re: /ollamacloud\/gemini-3-flash/, name: "gemini-flash", ctx: 1000000, compact: 850000, toolLimit: 32768 }, + { re: /glm\/glm-5-turbo/, name: "glm5turbo", ctx: 131072, compact: 112000, toolLimit: 16384 }, + { re: /glm\/glm-4\.7-flash/, name: "glm47flash", ctx: 131072, compact: 112000, toolLimit: 16384 }, + ]; + + for (const p of thinkingPatterns) { + if (p.re.test(id)) return { ...p, effort: "xhigh", summary: true }; + } + for (const p of goodPatterns) { + if (p.re.test(id)) return { ...p, effort: "high", summary: false }; + } + for (const p of simplePatterns) { + if (p.re.test(id)) return { ...p, effort: undefined, summary: false }; + } + for (const p of fastPatterns) { + if (p.re.test(id)) return { ...p, effort: "low", summary: false }; + } + + return null; +} + +/** Build the TOML content for a single profile. */ +function buildProfileToml(modelId, cfg) { + const lines = [ + `# codex --profile ${cfg.name}`, + `# ${modelId}`, + `model = "${modelId}"`, + `model_provider = "omniroute"`, + ]; + + if (cfg.effort) { + lines.push(`model_reasoning_effort = "${cfg.effort}"`); + } + if (cfg.summary) { + lines.push(`model_reasoning_summary = "detailed"`); + } + + lines.push( + `model_context_window = ${cfg.ctx}`, + `model_auto_compact_token_limit = ${cfg.compact}`, + `tool_output_token_limit = ${cfg.toolLimit}` + ); + + return lines.join("\n") + "\n"; +} + +// ── Command ─────────────────────────────────────────────────────────────────── + +/** + * @param {{remote?:string, port?:string, apiKey?:string, codexHome?:string, dryRun?:boolean, only?:string}} opts + * @returns {Promise} + */ +export async function runSetupCodexCommand(opts = {}) { + const port = Number(opts.port ?? process.env.PORT ?? 20128) || 20128; + const baseUrl = (opts.remote ?? `http://localhost:${port}`).replace(/\/v1$/, ""); + const apiKey = opts.apiKey ?? opts["api-key"] ?? process.env.OMNIROUTE_API_KEY ?? ""; + const codexHome = opts.codexHome ?? opts["codex-home"] ?? join(os.homedir(), ".codex"); + const dryRun = Boolean(opts.dryRun ?? opts["dry-run"]); + const onlyFilter = opts.only ? opts.only.split(",").map((s) => s.trim()) : null; + + printHeading(`OmniRoute → Codex CLI profile generator`); + printInfo(`Connecting to ${baseUrl} …`); + + // ── Fetch model catalog ─────────────────────────────────────────────────── + let models; + try { + const headers = { "Content-Type": "application/json" }; + if (apiKey) headers["Authorization"] = `Bearer ${apiKey}`; + + const res = await fetch(`${baseUrl}/v1/models`, { + headers, + signal: AbortSignal.timeout(10000), + }); + if (!res.ok) throw new Error(`HTTP ${res.status} ${res.statusText}`); + const body = await res.json(); + models = body.data ?? body.models ?? []; + } catch (err) { + printError(`Failed to fetch models: ${err.message}`); + printInfo( + "Make sure OmniRoute is running and the --remote URL is correct.\n" + + "You may also need --api-key if OmniRoute requires authentication." + ); + return 1; + } + + printInfo(`Received ${models.length} models from ${baseUrl}`); + + // ── Ensure codex home exists ────────────────────────────────────────────── + if (!dryRun && !existsSync(codexHome)) { + mkdirSync(codexHome, { recursive: true }); + } + + // ── Generate profiles ───────────────────────────────────────────────────── + let written = 0; + let skipped = 0; + + for (const m of models) { + const id = typeof m === "string" ? m : (m.id ?? ""); + if (!id) continue; + if (onlyFilter && !onlyFilter.some((f) => id.includes(f))) continue; + + const cfg = categoriseModel(id); + if (!cfg) continue; + + const filePath = join(codexHome, `${cfg.name}.config.toml`); + const content = buildProfileToml(id, cfg); + + if (dryRun) { + console.log(`\n── [dry-run] ${filePath} ──`); + console.log(content); + } else { + writeFileSync(filePath, content, "utf8"); + printSuccess(` ✓ ${cfg.name}.config.toml (${id})`); + } + written++; + } + + skipped = models.length - written; + + if (!dryRun) { + console.log(""); + printSuccess(`${written} profiles written to ${codexHome}`); + if (skipped > 0) { + printInfo(`${skipped} models skipped (no matching profile pattern)`); + } + console.log("\nTo use a profile:"); + console.log(" codex --profile # e.g. codex --profile glm52"); + console.log(" codex -p # short form"); + } else { + console.log(`\n[dry-run] ${written} profiles would be written (${skipped} skipped)`); + } + + return 0; +} + +export function registerSetupCodex(program) { + program + .command("setup-codex") + .description( + "Fetch the live model catalog from OmniRoute (local or remote VPS) and generate " + + "~/.codex/.config.toml profiles for each supported model" + ) + .option("--port ", "Local OmniRoute port (ignored when --remote is set)", "20128") + .option( + "--remote ", + "Remote OmniRoute URL, e.g. http://100.67.86.91:20128 — fetches models from there" + ) + .option( + "--api-key ", + "OmniRoute API key for the remote instance (defaults to OMNIROUTE_API_KEY env var)" + ) + .option( + "--codex-home ", + "Directory where profile files are written (default: ~/.codex)" + ) + .option( + "--only ", + "Comma-separated substrings — only generate profiles for matching model IDs (e.g. glm,kimi)" + ) + .option("--dry-run", "Print what would be written without touching the filesystem") + .action(async (opts) => { + const exitCode = await runSetupCodexCommand(opts); + if (exitCode !== 0) process.exit(exitCode); + }); +} diff --git a/bin/cli/locales/en.json b/bin/cli/locales/en.json index cdecdabafe53..c29660784197 100644 --- a/bin/cli/locales/en.json +++ b/bin/cli/locales/en.json @@ -1271,5 +1271,11 @@ }, "configure": { "description": "Pick a provider+model from the active server and write a local CLI config" + }, + "launchCodex": { + "description": "Launch Codex CLI pointed at OmniRoute (local or remote VPS)" + }, + "setupCodex": { + "description": "Generate ~/.codex profile files from OmniRoute live model catalog" } } diff --git a/bin/cli/locales/pt-BR.json b/bin/cli/locales/pt-BR.json index e907b7c28f12..e7d99eba4593 100644 --- a/bin/cli/locales/pt-BR.json +++ b/bin/cli/locales/pt-BR.json @@ -1270,5 +1270,11 @@ }, "configure": { "description": "Escolhe um provedor+modelo do servidor ativo e grava uma configuração de CLI local" + }, + "launchCodex": { + "description": "Inicia o Codex CLI apontando para o OmniRoute (local ou VPS remoto)" + }, + "setupCodex": { + "description": "Gera os arquivos de perfil ~/.codex a partir do catálogo de modelos ao vivo do OmniRoute" } } diff --git a/docs/guides/CODEX-CLI-CONFIGURATION.md b/docs/guides/CODEX-CLI-CONFIGURATION.md index 531782cc3de5..1c4f072ff3df 100644 --- a/docs/guides/CODEX-CLI-CONFIGURATION.md +++ b/docs/guides/CODEX-CLI-CONFIGURATION.md @@ -1,7 +1,7 @@ --- title: "Codex CLI — Configuration with OmniRoute" -version: 3.8.16 -lastUpdated: 2026-06-08 +version: 3.8.29 +lastUpdated: 2026-06-18 --- # Codex CLI — Configuration with OmniRoute @@ -21,7 +21,6 @@ model_provider = "omniroute" model_reasoning_effort = "xhigh" model_context_window = 400000 model_auto_compact_token_limit = 350000 -model_max_output_tokens = 65536 # max tokens per response (model cap = 128k) tool_output_token_limit = 32768 # history storage cap per tool call [model_providers.omniroute] @@ -49,9 +48,9 @@ export OMNIROUTE_API_KEY="" ## `wire_api = "responses"` — why it works for all models -Codex CLI deprecated `wire_api = "chat"` (Chat Completions) in February 2026 and now **requires** `wire_api = "responses"` (OpenAI Responses API). +Codex CLI deprecated `wire_api = "chat"` (Chat Completions) in February 2026 and now **requires** `wire_api = "responses"` (OpenAI Responses API). Setting `wire_api = "chat"` causes an immediate startup crash since v0.138. -DeepSeek and Mistral only expose a Chat Completions endpoint — not the Responses API. If you pointed Codex directly at DeepSeek or Mistral, it would fail with a 404. +DeepSeek, GLM, Kimi and others only expose a Chat Completions endpoint — not the Responses API. If you pointed Codex directly at them, it would fail. **OmniRoute solves this transparently:** @@ -60,54 +59,53 @@ Codex CLI → wire_api = "responses" → POST /v1/responses (OmniRoute) → OmniRoute Responses ↔ Chat Completions transformer - → POST /chat/completions (DeepSeek / Mistral / any provider) + → POST /chat/completions (DeepSeek / Mistral / GLM / Kimi / any provider) ``` -You never need a separate translation proxy (`codex-relay`, `LiteLLM`, etc.) when using OmniRoute. **All models use `wire_api = "responses"`** — OmniRoute handles the rest. +You never need a separate translation proxy when using OmniRoute. **All models use `wire_api = "responses"`** — OmniRoute handles the rest. + +> **`wire_api` is the default** — the field defaults to `"responses"` and can be omitted entirely from `config.toml`. Only ever set it explicitly if you're documenting intent. --- ## Context window and compaction -### Why this matters - -If the session history exceeds the model's context window, the Codex CLI either crashes or truncates silently. Different models have very different limits — setting these explicitly prevents surprises. - ### Token configuration fields | Field | Description | |-------|-------------| | `model_context_window` | Total token budget for the active model. Set to the model's advertised limit. | | `model_auto_compact_token_limit` | Threshold that triggers automatic history compaction. **Maximum: 90% of `model_context_window`** — values above 90% are silently ignored. | -| `model_max_output_tokens` | **Maximum tokens per response** (equivalent to Claude's `CLAUDE_CODE_MAX_OUTPUT_TOKENS`). Caps the output sent to the API on every request. Exists in CLI config since mid-2025 (Issue #4138, now fixed). | | `tool_output_token_limit` | Cap on tokens stored per tool call output in history. Prevents a single large tool response from filling the window. **This is not the max output** — it is a history storage cap. | -| `compact_prompt` | Inline override for the system prompt used during compaction. | -| `experimental_compact_prompt_file` | Load the compaction prompt from a file (experimental). | - -> **`model_max_output_tokens` vs `tool_output_token_limit`**: these are two different things. -> - `model_max_output_tokens` = max tokens the model may produce in a single API response. -> - `tool_output_token_limit` = max tokens stored per tool call in the session history. - -### Context windows and output caps by model - -| Model | OmniRoute ID | Context window | Max output (model) | `model_max_output_tokens` | `auto_compact` | `tool_output_limit` | -|-------|-------------|----------------|--------------------|---------------------------|----------------|----------------------| -| GPT-5.5 | `cx/gpt-5.5` | 1,050,000 (400k reliable) | **128,000** | 65,536 | 350,000 | 32,768 | -| DeepSeek V4 Pro | `ds/deepseek-v4-pro` | 1,000,000 | **384,000** | 65,536 | 900,000 | 65,536 | -| Mistral Large Latest | `mistral/mistral-large-latest` | 262,144 (256k) | ~128,000 | 32,768 | 220,000 | 16,384 | - -> **Why not set `model_max_output_tokens` to the model's maximum?** -> For a coding assistant that writes whole files and long diffs, 64k (65,536) is a practical sweet spot. The model can generate files up to ~50k tokens without hitting the cap. Reserve the higher limits for edge cases — they increase cost on every request regardless of output length. - -> **Compaction formula:** `effective_window = model_context_window - min(model_max_output_tokens, 20000)`. Values above 20k do not reduce the compaction trigger — the formula caps the output reservation at 20k. So setting `model_max_output_tokens = 65536` does not require lowering `model_auto_compact_token_limit`. - -> **Rule of thumb:** set `model_auto_compact_token_limit` to 85–90% of `model_context_window`. Never go above 90% — it is silently ignored. - -### How compaction works - -When the session history exceeds `model_auto_compact_token_limit`, Codex CLI automatically summarises older turns into a compact form. The session continues without interruption — you lose verbatim history but keep context. This is different from truncation (which loses context). - -For models with smaller windows (Mistral 256k), compaction fires earlier and more often. Setting a tighter `tool_output_token_limit` reduces how fast the window fills with tool call results. +| `compact_prompt` | Inline override for the system prompt used during compaction (v0.138+). | + +> **Note on `model_max_output_tokens`**: This field is **not part of the Codex CLI config schema** (absent from the Codex Rust codebase). It is silently ignored if set. Do not rely on it — use `tool_output_token_limit` to control how much tool output is stored in history. + +### Context windows by model + +| Model | OmniRoute ID | Context window | `auto_compact` | `tool_output_limit` | +|-------|-------------|----------------|----------------|----------------------| +| GPT-5.5 | `cx/gpt-5.5` | 400k reliable (1M max) | 350,000 | 32,768 | +| Kimi K2.7 (thinking) | `kmc/kimi-k2.7` | 131,072 | 112,000 | 32,768 | +| Kimi K2.6 | `kmc/kimi-k2.6` | 131,072 | 112,000 | 32,768 | +| GLM-5.2 / 5.2-max (thinking) | `glm/glm-5.2` | 131,072 | 112,000 | 32,768 | +| MiMo V2.5 Pro (thinking) | `opencode-go/mimo-v2.5-pro` | 131,072 | 112,000 | 32,768 | +| Qwen 3.7 Plus (thinking) | `opencode-go/qwen3.7-plus` | 32,768 | 28,000 | 16,384 | +| DeepSeek V4 Pro (OllamaCloud) | `ollamacloud/deepseek-v4-pro` | 131,072 | 112,000 | 32,768 | +| DeepSeek V4 Pro | `ds/deepseek-v4-pro` | 1,000,000 | 900,000 | 65,536 | +| MiMo V2.5 | `opencode-go/mimo-v2.5` | 131,072 | 112,000 | 32,768 | +| Gemma 4 31B (OllamaCloud) | `ollamacloud/gemma4:31b` | 32,768 | 28,000 | 16,384 | +| Nemotron 3 Super (OllamaCloud) | `ollamacloud/nemotron-3-super` | 32,768 | 28,000 | 16,384 | +| GPT-OSS 20B (OllamaCloud) | `ollamacloud/gpt-oss:20b` | 32,768 | 28,000 | 16,384 | +| DeepSeek V4 Flash (OllamaCloud) | `ollamacloud/deepseek-v4-flash` | 65,536 | 56,000 | 16,384 | +| Gemini 3 Flash Preview (OllamaCloud) | `ollamacloud/gemini-3-flash-preview` | 1,000,000 | 850,000 | 32,768 | +| GLM-5 Turbo | `glm/glm-5-turbo` | 131,072 | 112,000 | 16,384 | +| GLM-4.7 Flash | `glm/glm-4.7-flash` | 131,072 | 112,000 | 16,384 | +| Mistral Large Latest | `mistral/mistral-large-latest` | 262,144 | 220,000 | 16,384 | + +> **Compaction formula:** `effective_window = model_context_window - min(tool_output_token_limit, 20000)`. Values above 20k do not change the compaction trigger. + +> **Rule of thumb:** set `model_auto_compact_token_limit` to 85–88% of `model_context_window`. Never go above 90% — silently ignored. --- @@ -122,236 +120,279 @@ All Codex models in OmniRoute use the `cx/` prefix: | `cx/gpt-5.4-mini` | GPT-5.4 mini | | `cx/gpt-5.1-codex-mini` | GPT-5.1 Codex mini | -Other providers use their own prefix (`ds/`, `mistral/`, etc.) — the prefix matches the OmniRoute provider alias. - -> **Never use bare `gpt-5.5` or `codex/gpt-5.5`** — OmniRoute does not recognize those formats for the Codex provider. +Other providers use their own prefix (`kmc/`, `glm/`, `ds/`, `ollamacloud/`, `opencode-go/`, `mistral/`) — the prefix matches the OmniRoute provider alias. --- ## Reasoning Effort -Controls how much the model "thinks" before responding. Higher effort = better quality, higher latency and cost. - -### Available values +Controls how much the model "thinks" before responding. -| Value | Recommended for | -|-------|-----------------| +| Value | Use for | +|-------|---------| | `none` | No reasoning — direct response | -| `low` | Trivial tasks (rename a variable, format code) | +| `low` | Trivial tasks (rename, format) | | `medium` | **Server default** when not specified | -| `high` | Intermediate tasks (refactoring, debugging) | +| `high` | Intermediate tasks (refactoring, debug) | | `xhigh` | Architecture, deep analysis, complex problems | -> **Note:** `model_reasoning_effort` applies to models that support reasoning (GPT-5.x, DeepSeek V4 Pro). Mistral Large does not expose a reasoning effort parameter — setting it has no effect on Mistral. +```bash +# Per invocation override +codex -c model_reasoning_effort=low "rename variable x to count" +codex -c model_reasoning_effort=xhigh "design the auth module" +``` + +--- -### How to configure +## Profiles — named configurations per model/workflow -**In `config.toml` (global default):** -```toml -model_reasoning_effort = "xhigh" -``` +Profiles let you switch model + context window with a single flag. Each profile is a flat +`~/.codex/.config.toml` that overlays on top of the base `config.toml`. + +> **Naming rule (Codex CLI v0.137+):** file must be `~/.codex/.config.toml` — **no `profile-` prefix**. +> The CLI resolves `-p kimi-k27` → `~/.codex/kimi-k27.config.toml`. If the file is not found, the default applies silently. -**Per invocation via `-c` (overrides global):** ```bash -codex -c model_reasoning_effort=low "rename variable x to count" -codex -c model_reasoning_effort=xhigh "design the auth module architecture" +codex --profile kimi-k27 "analyze 10k lines of this codebase" +codex -p glm52 "architecture review" +codex --profile deepseek-flash "rename variable" # fast, cheap ``` -**Combining model and effort:** +### Effort profiles (same model, different effort) + ```bash -codex -m cx/gpt-5.4 -c model_reasoning_effort=medium "refactor the handler" +codex -p low # cx/gpt-5.5, effort=low +codex -p medium # cx/gpt-5.5, effort=medium +codex -p high # cx/gpt-5.5, effort=high +codex -p xhigh # cx/gpt-5.5, effort=xhigh (default) +codex -p chat # cx/gpt-5.5, no effort set (server default) ``` -> **About the default:** If `model_reasoning_effort` is not set, OmniRoute falls back to `"medium"`. Set it explicitly for serious engineering work. +### Thinking models (alto pensamento) — xhigh + detailed summary ---- +| Profile | Model | Context | Use for | +|---------|-------|---------|---------| +| `kimi-k27` | `kmc/kimi-k2.7` | 128k | Best thinking quality (Kimi) | +| `glm52` | `glm/glm-5.2` | 128k | GLM thinking | +| `glm52max` | `glm/glm-5.2-max` | 128k | GLM thinking max | +| `mimo-pro` | `opencode-go/mimo-v2.5-pro` | 128k | MiMo thinking | +| `qwen37plus` | `opencode-go/qwen3.7-plus` | 32k | Qwen thinking | -## Selecting a model via the CLI +### Good models (bons) — high effort -### 1. `--model` / `-m` flag — per invocation +| Profile | Model | Context | Use for | +|---------|-------|---------|---------| +| `kimi-k26` | `kmc/kimi-k2.6` | 128k | General purpose (Kimi) | +| `deepseek-pro` | `ollamacloud/deepseek-v4-pro` | 128k | DeepSeek Pro via OllamaCloud | +| `deepseek` | `ds/deepseek-v4-pro` | 1M | DeepSeek Pro direct, huge context | +| `mimo` | `opencode-go/mimo-v2.5` | 128k | MiMo general | -```bash -codex -m cx/gpt-5.5 "analyze the full pipeline" -codex -m ds/deepseek-v4-pro "deep analysis of this algorithm" -codex -m mistral/mistral-large-latest "quick review" -``` +### Simple models (simples) — no reasoning effort -**Priority:** CLI flags > profiles > config.toml +| Profile | Model | Context | Use for | +|---------|-------|---------|---------| +| `gemma4` | `ollamacloud/gemma4:31b` | 32k | Cost-effective, capable | +| `nemotron` | `ollamacloud/nemotron-3-super` | 32k | NVIDIA Nemotron | +| `gptoss` | `ollamacloud/gpt-oss:20b` | 32k | Open-source GPT | -### 2. `/model` — interactive switch inside a session +### Fast models (rápidos) — low effort -During an open session, type `/model` + Enter to open the model picker. +| Profile | Model | Context | Use for | +|---------|-------|---------|---------| +| `deepseek-flash` | `ollamacloud/deepseek-v4-flash` | 64k | Quick tasks | +| `gemini-flash` | `ollamacloud/gemini-3-flash-preview` | 1M | Very fast, huge context | +| `glm5turbo` | `glm/glm-5-turbo` | 128k | GLM Turbo | +| `glm47flash` | `glm/glm-4.7-flash` | 128k | GLM Flash | +| `mistral` | `mistral/mistral-large-latest` | 256k | Mistral Large | + +### Quick decision table + +| Task | Recommended profile | +|------|---------------------| +| Rename, format, boilerplate | `--profile deepseek-flash` or `-p low` | +| Explain, light review | `-p chat` or `-p gemini-flash` | +| Debug, moderate refactor | `-p medium` or `-p kimi-k26` | +| New feature, complex tests | `-p high` or `-p mimo` | +| Architecture, deep analysis | `-p kimi-k27` or `-p glm52` or `-p xhigh` | +| Codebase analysis (needs 1M ctx) | `--profile deepseek` or `--profile gemini-flash` | +| Maximum thinking quality | `-p glm52max` or `-p mimo-pro` | +| Cost-conscious | `-p gemma4` or `-p gptoss` | + +--- -### 3. `-c key=value` — inline override for any field +## Generating profiles automatically with `omniroute setup-codex` + +If you run OmniRoute on a VPS, you can auto-generate profile files from the live model catalog: ```bash -# Change context window for one run -codex -m ds/deepseek-v4-pro -c model_context_window=1000000 -c model_auto_compact_token_limit=900000 "task" +# From a VPS (uses local OmniRoute on port 20128) +omniroute setup-codex + +# From any machine — point at your VPS +omniroute setup-codex --remote http://100.x.x.x:20128 --api-key sk-xxx + +# Preview without writing files +omniroute setup-codex --remote http://100.x.x.x:20128 --dry-run + +# Only generate GLM and Kimi profiles +omniroute setup-codex --only glm,kimi + +# Write to a custom directory +omniroute setup-codex --codex-home /path/to/.codex ``` +The command fetches `/v1/models`, categorises each model (thinking / good / simple / fast) and writes `~/.codex/.config.toml` for each. Idempotent — safe to re-run. + --- -## Profiles — named usage profiles +## Launching Codex with `omniroute launch-codex` -Profiles let you have named configurations for different workflows. Each profile is a file at `~/.codex/.config.toml` that layers on top of the base `config.toml`. +Health-checks your OmniRoute instance before launching Codex: -> **Naming rule (Codex CLI v0.137+):** the file must be named `~/.codex/.config.toml` — **no `profile-` prefix**. The CLI resolves `-p chat` to `~/.codex/chat.config.toml`. If the file is not found, the default silently applies with no error. +```bash +# Launch against local OmniRoute (default port 20128) +omniroute launch-codex -### How to use +# Launch with a specific profile +omniroute launch-codex --profile kimi-k27 -```bash -codex --profile deepseek "analyze 10k lines of this codebase" -codex --profile mistral "quick code review" -codex --profile low "rename variable" -codex -p chat "explain this function" +# Launch against a remote VPS +omniroute launch-codex --remote http://100.x.x.x:20128/v1 --api-key sk-xxx + +# Pass extra args to codex +omniroute launch-codex --profile glm52 -- --yolo "fix this bug" ``` -### All available profiles +--- -#### `chat.config.toml` — no reasoning effort (server default = medium) -```toml -model = "cx/gpt-5.5" -model_provider = "omniroute" -# No model_reasoning_effort — uses server default (medium) -``` +## New Codex CLI features (v0.138–v0.141) -#### `low.config.toml` / `medium.config.toml` / `high.config.toml` / `xhigh.config.toml` -```toml -model = "cx/gpt-5.5" -model_reasoning_effort = "low" # or medium / high / xhigh -model_provider = "omniroute" -``` -Context window is inherited from `config.toml` (400k for gpt-5.5). +| Version | Feature | +|---------|---------| +| v0.138 | Desktop app handoff (`/app`), v2 personal access tokens, `--profile` as the exclusive profile selector (legacy in-file `[profiles]` tables crash on startup) | +| v0.139 | `web_search = "live"` — native web search from code mode; `oneOf`/`allOf` in MCP tool schemas; `codex doctor` env diagnostics | +| v0.140 | `/usage` token view in-session; `/import` from Claude Code sessions; `codex delete ` subcommand; Amazon Bedrock auth via `aws` object in provider config | +| v0.141 | E2E encrypted Noise relay for remote executors; SQLite WAL fix; P-521 TLS support | + +### New `config.toml` fields (post-v0.137) -#### `deepseek.config.toml` — DeepSeek V4 Pro, 1M context ```toml -model = "ds/deepseek-v4-pro" -model_provider = "omniroute" +# Native web search (v0.139) +web_search = "live" # "disabled" | "cached" | "live" -model_context_window = 1000000 -model_auto_compact_token_limit = 900000 -model_max_output_tokens = 65536 # practical cap; model max = 384k -tool_output_token_limit = 65536 -``` +# Separate developer system prompt (v0.138) +developer_instructions = "Always prefer functional style." -#### `mistral.config.toml` — Mistral Large Latest, 256k context -```toml -model = "mistral/mistral-large-latest" -model_provider = "omniroute" +# Custom compaction prompt +compact_prompt = "Summarise the above as bullet points." + +# Route /review to a cheaper model +review_model = "glm/glm-5-turbo" -model_context_window = 262144 -model_auto_compact_token_limit = 220000 -model_max_output_tokens = 32768 # ~32k; Mistral Large model max ~128k -tool_output_token_limit = 16384 +# OpenAI service tier +service_tier = "fast" # "fast" | "flex" ``` -### Quick decision table +### New `[model_providers.]` fields -| Task | Profile | -|------|---------| -| Rename, format, boilerplate | `--profile low` | -| Explain, light PR review | `--profile chat` | -| Debug, moderate refactor | `--profile medium` | -| New feature, complex tests | `--profile high` | -| Architecture, system analysis | `--profile xhigh` (default) | -| Long codebase analysis (needs 1M ctx) | `--profile deepseek` | -| Quick tasks, cost-conscious | `--profile mistral` | +```toml +[model_providers.omniroute] +base_url = "http://100.x.x.x:20128/v1" +env_key = "OMNIROUTE_API_KEY" +requires_openai_auth = false ---- +# Static extra headers on every request +[model_providers.omniroute.http_headers] +"X-Custom-Header" = "value" -## Multiple models and servers +# Headers read from env vars +[model_providers.omniroute.env_http_headers] +"X-Trace-Id" = "TRACE_ID" -### Multiple models — same server +# Extra URL query params (useful for Azure api-version) +[model_providers.omniroute.query_params] +"api-version" = "2024-12-01-preview" +``` -Change only `model` and `model_provider` (and context window fields if the model differs): +### Amazon Bedrock auth (v0.140) ```toml -model = "ds/deepseek-v4-pro" -model_provider = "omniroute" -model_context_window = 1000000 -model_auto_compact_token_limit = 900000 +[model_providers.bedrock] +base_url = "https://bedrock-runtime.us-east-1.amazonaws.com" + +[model_providers.bedrock.aws] +profile = "default" # ~/.aws/credentials profile +region = "us-east-1" ``` -### Multiple servers +--- -```toml -model = "cx/gpt-5.5" -model_provider = "omniroute-main" +## Multiple servers +```toml [model_providers.omniroute-main] -name = "OmniRoute (Main)" -base_url = "http://192.168.0.1:20128/v1" -env_key = "OMNIROUTE_API_KEY" -requires_openai_auth = false -wire_api = "responses" +base_url = "http://192.168.0.1:20128/v1" +env_key = "OMNIROUTE_API_KEY" [model_providers.omniroute-tailscale] -name = "OmniRoute (Tailscale)" -base_url = "http://100.x.x.x:20128/v1" -env_key = "OMNIROUTE_API_KEY" -requires_openai_auth = false -wire_api = "responses" - -[model_providers.omniroute-staging] -name = "OmniRoute (Staging)" -base_url = "http://192.168.0.2:20128/v1" -env_key = "OMNIROUTE_STAGING_KEY" -requires_openai_auth = false -wire_api = "responses" +base_url = "http://100.x.x.x:20128/v1" +env_key = "OMNIROUTE_API_KEY" ``` -> All providers use `wire_api = "responses"` — OmniRoute handles translation for each upstream provider internally. - --- ## Claude Code — equivalent configuration -Claude Code (Anthropic's CLI) uses a different mechanism for the same concept: environment variables in `~/.bashrc` / `~/.zshrc`. - | Codex CLI (`config.toml`) | Claude Code (env var) | Effect | |---------------------------|-----------------------|--------| -| `model_max_output_tokens = 65536` | `CLAUDE_CODE_MAX_OUTPUT_TOKENS=65536` | Max tokens per response | -| `model_context_window = 400000` | *(determined by the model — not configurable)* | Context window | | `tool_output_token_limit = 32768` | *(not directly exposed)* | Per-tool history cap | +| `model_context_window = 400000` | *(determined by the model)* | Context window | +| — | `CLAUDE_CODE_MAX_OUTPUT_TOKENS=65536` | Max tokens per response | ```bash -# ~/.bashrc — Claude Code token cap (equivalent to Codex model_max_output_tokens) +# ~/.bashrc — Claude Code token cap export CLAUDE_CODE_MAX_OUTPUT_TOKENS=65536 ``` -> **Why 64k and not 128k?** The Claude 4.x family supports up to 128k output, but for interactive coding sessions 64k covers any file or diff you realistically generate. Setting 128k reserves the full slot on every request, which increases latency and cost even for short responses. Use 128k only for batch/document-generation workflows where you routinely need very long outputs. - ---- - -## About `[notice.model_migrations]` - -Auto-generated by the Codex CLI to record acknowledged deprecation warnings. **Not an alias system** — safe to ignore. - --- ## Quick reference — CLI flags | Flag | Short | Effect | |------|-------|--------| -| `--model ` | `-m` | Overrides `model` for the current invocation | +| `--model ` | `-m` | Overrides `model` for this invocation | | `--profile ` | `-p` | Loads `~/.codex/.config.toml` | -| `--config key=value` | `-c` | Overrides any config.toml field | +| `--config key=value` | `-c` | Overrides any config.toml field (repeatable) | | `--enable ` | — | Force-enables a feature flag | | `--disable ` | — | Force-disables a feature flag | +| `--search` | — | Enable live web search for this invocation | + +New in v0.140: +```bash +codex delete # delete a session +codex delete --force # skip confirmation +codex debug models --bundled # list bundled model catalog as JSON +``` Inside an interactive session: | Command | Effect | |---------|--------| | `/model` | Opens the model picker | +| `/usage` | Shows token usage for this session (v0.140) | +| `/app` | Hands off to the desktop app (v0.138) | +| `/import` | Import a Claude Code session (v0.140) | | `/help` | Lists all slash commands | --- ## Troubleshooting +**`Error: wire_api = "chat" is no longer supported`** +Remove `wire_api = "chat"` from your config. Set `wire_api = "responses"` or omit the field (defaults to `"responses"` since v0.138). + **`Error: model not found`** -Verify the model exists in OmniRoute with the correct prefix. Open `/dashboard/providers/` and check available models. +Verify the model exists in OmniRoute with the correct prefix. Use `omniroute models list` or open `/dashboard/providers/`. **`Authentication error`** Confirm `OMNIROUTE_API_KEY` is exported: `echo $OMNIROUTE_API_KEY`. @@ -360,10 +401,10 @@ Confirm `OMNIROUTE_API_KEY` is exported: `echo $OMNIROUTE_API_KEY`. Verify OmniRoute is running and the `base_url` host/port is correct for your network (local vs Tailscale vs VPS). **Session crashes near context limit** -Set `model_context_window` and `model_auto_compact_token_limit` explicitly for the model you are using. See the context window table above. +Set `model_context_window` and `model_auto_compact_token_limit` explicitly. See the context window table above. -**Compaction fires too late / history is cut** -Lower `model_auto_compact_token_limit` to trigger compaction earlier (e.g. 75% of the window). Never set it above 90% — silently ignored. +**Compaction fires too late** +Lower `model_auto_compact_token_limit` to 80–85% of the window. Never set above 90%. -**DeepSeek / Mistral returns 404** -You are likely pointing Codex directly at the provider API. Route through OmniRoute — it translates Responses API → Chat Completions automatically. Confirm `base_url` points to your OmniRoute instance, not directly to `api.deepseek.com` or `api.mistral.ai`. +**Profile not loading (`-p ` silently ignored)** +Confirm the file exists at `~/.codex/.config.toml` (no `profile-` prefix). Run `ls ~/.codex/*.config.toml`. From 8aa9d6330b41c0c51e9bd6ab12b160c7176c13ac Mon Sep 17 00:00:00 2001 From: Diego Rodrigues de Sa e Souza <8016841+diegosouzapw@users.noreply.github.com> Date: Fri, 19 Jun 2026 10:17:00 -0300 Subject: [PATCH 03/74] chore(ci): align electron audit gate to root advisory policy (#4275) Align electron audit gate to root policy (critical blocks, high warns). Un-blocks the Lint job on release/v3.8.30. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d22a8838bfc0..aace26853bef 100644 --- a/package.json +++ b/package.json @@ -159,7 +159,7 @@ "quality:scan": "node scripts/quality/run-all-gates.mjs", "quality:scan:fast": "node scripts/quality/run-all-gates.mjs --fast", "audit:deps": "npm audit --audit-level=critical && (npm audit --audit-level=high || echo '::warning::high-severity advisories present (non-blocking)') && npm run audit:electron", - "audit:electron": "npm --prefix electron audit --audit-level=moderate", + "audit:electron": "npm --prefix electron audit --audit-level=critical && (npm --prefix electron audit --audit-level=high || echo '::warning::electron high-severity advisories present (non-blocking)')", "typecheck:core": "tsc --pretty false -p tsconfig.typecheck-core.json", "typecheck:noimplicit:core": "tsc --pretty false -p tsconfig.typecheck-noimplicit-core.json", "backfill-aggregation": "node --import tsx src/scripts/backfillAggregation.ts", From 3517d935e488ac64f500d4b3ac443fb437397c3a Mon Sep 17 00:00:00 2001 From: diegosouzapw Date: Fri, 19 Jun 2026 10:20:07 -0300 Subject: [PATCH 04/74] docs(design): add OmniRoute design system and visual identity specification Introduce a design system and visual identity plan to unify the OmniRoute dashboard and marketing site. The document covers color alignment, missing design tokens, and the implementation strategy for a consistent brand experience. --- DESING.md | 254 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 254 insertions(+) create mode 100644 DESING.md diff --git a/DESING.md b/DESING.md new file mode 100644 index 000000000000..e71f88c77d3f --- /dev/null +++ b/DESING.md @@ -0,0 +1,254 @@ +# OmniRoute — Design System & Visual Identity + +> **Status:** analysis + standardization plan (no code applied yet — this doc is the spec to approve before implementation). +> **Date:** 2026-06-16 · **Scope:** unify the OmniRoute dashboard (`src/`) with the marketing site (`_mono_repo/omnirouteSite/`) into **one visual identity** — same graph-paper grid background, same color tokens, standardized components. + +--- + +## 1. Purpose + +The marketing site (`viral.omniroute.online`, `why.omniroute.online`, `omniroute.online`) and the product dashboard should look like **one product**. The site already borrowed its palette from the dashboard — its `css/tokens.css` even says _"Palette mirrors the OmniRoute dashboard (src/app/globals.css)"_. So the two are already ~80% aligned at the color level. What's missing on the dashboard: + +1. The **graph-paper grid wallpaper** the site uses on every page. +2. A handful of **shared design tokens** the site has but the dashboard lacks (radius scale, brand gradient, `surface-2`, mono font). +3. **Component-level consistency** — a number of dashboard components bypass the theme tokens with hardcoded hex/rgba. + +This document is the analysis and the plan. **Nothing is changed until approved.** + +--- + +## 2. Principles + +- **Single source of truth = `src/app/globals.css`.** The site mirrors the dashboard, never the other way around. New tokens land in `globals.css` first. +- **Tokens, never literals.** Components consume semantic tokens (`bg-surface`, `text-primary`, `border-border`), never raw `#hex`. +- **Subtle, not loud.** The grid is a faint wallpaper that sits behind content — it must never reduce text contrast or fight the UI. +- **Theme-aware.** Everything works in both `.dark` (default-ish, the product's signature look) and light. +- **Surgical rollout.** Ship the grid + tokens first (low risk, high visibility), then component cleanups in waves. + +--- + +## 3. Current state — what's already aligned vs. what's not + +### 3.1 Colors — already unified ✅ + +Every brand color and surface already matches the site **by value** (only the names differ — dashboard prefixes with `--color-`). Verified in `src/app/globals.css:30-128`: + +| Concept | Site token (`tokens.css`) | Dashboard token (`globals.css`) | Match | +| -------------------------- | ------------------------------------------- | ------------------------------- | ------------ | +| primary | `--primary #e54d5e` | `--color-primary #e54d5e` | ✅ | +| primary-hover | `--primary-hover #c93d4e` | `--color-primary-hover #c93d4e` | ✅ | +| accent | `--accent #6366f1` | `--color-accent #6366f1` | ✅ | +| accent-2 | `--accent-2 #8b5cf6` | `--color-accent-hover #8b5cf6` | ✅ (renamed) | +| accent-3 | `--accent-3 #a855f7` | `--color-accent-light #a855f7` | ✅ (renamed) | +| success / warning / error | `#22c55e / #f59e0b / #ef4444` | identical | ✅ | +| traffic lights | `#ff5f56 / #ffbd2e / #27c93f` | identical | ✅ | +| dark bg / surface / border | `#0b0e14 / #161b22 / rgba(255,255,255,.08)` | identical | ✅ | +| light bg / surface / text | `#f9f9fb / #fff / #1a1a2e` | identical | ✅ | + +**Conclusion:** there is no color migration to do. The identity is already shared; we are _finishing_ it, not rebuilding it. + +### 3.2 Gaps — what the dashboard is missing + +| Gap | Site has | Dashboard | Action | +| ----------------------- | ------------------------------------------------------------------------------ | ---------------------------------------------------------- | ---------------------- | +| **Grid wallpaper** | `body::before` graph-paper, `--grid-line`, `--grid-size 46px`, `--section-alt` | none (flat `--color-bg`) | **Part A** | +| **Radius scale** | `--radius 14px`, `--radius-sm 9px` | none — primitives use ad-hoc `rounded-md/lg/xl` (6/8/12px) | **Part B** | +| **Brand gradient** | `--grad-brand 135deg primary→accent-3` | none — only a one-off `.bg-hero-gradient` | **Part B** | +| **Nested surface** | `--surface-2 #1c2230` | none | **Part B** | +| **Mono font** | `--font-mono` (ui-monospace stack) | none (code/terminal areas have no token) | **Part B** | +| **`text-muted` (dark)** | `#8b8b9e` | `#a1a1aa` (zinc-400) | reconcile — **Part B** | + +### 3.3 Theming mechanics (so we don't break anything) + +- **Tailwind v4, CSS-first** (no `tailwind.config.*`). Tokens are defined in `:root`/`.dark` and exposed to utilities via `@theme inline` (`globals.css:130-179`). +- **Dark via `.dark` class** on `` (`@custom-variant dark` at `globals.css:22`), toggled by a custom Zustand store (`src/store/themeStore.ts`), default theme = `system` (`src/shared/constants/appConfig.ts:11`). The site uses `html[data-theme="light"]` instead — **the mechanisms differ but never meet** (separate origins), so no conflict. We keep the dashboard's `.dark` mechanism. +- **Runtime primary override** exists (`themeStore.ts:85-97`, presets in `COLOR_THEMES`) — users can swap `--color-primary`. Any new token (gradient, etc.) that references `--color-primary` will inherit those overrides for free. ✅ + +--- + +## 4. Part A — The graph-paper grid background (headline ask) + +### 4.1 What it is + +The exact recipe from the site (`_mono_repo/omnirouteSite/css/base.css`): a **fixed, full-viewport pseudo-element** painting two 1px line gradients, sitting at `z-index:-1` behind all content. + +```css +body::before { + content: ""; + position: fixed; + inset: 0; + z-index: -1; + pointer-events: none; + background-image: + linear-gradient(to right, var(--grid-line) 1px, transparent 1px), + linear-gradient(to bottom, var(--grid-line) 1px, transparent 1px); + background-size: var(--grid-size) var(--grid-size); +} +``` + +**Why this works even though `body` has an opaque `background-color`:** a `::before` with `z-index:-1` paints _above_ the element's own background but _below_ its in-flow content. So `--color-bg` is the base fill, the grid is layered on top of it, and the app renders above the grid. + +### 4.2 Precedent already in the codebase + +`src/app/landing/page.tsx:16-26` **already implements this same grid per-page** — but with **red** lines (`#E54D5E`, opacity `0.06`) at **50px**, plus animated orbs. So the pattern is proven in the product; we are promoting it to a **global, theme-aware** wallpaper and (optionally) retiring the duplicate. + +### 4.3 Tokens to add (in `globals.css`) + +```css +:root { + /* light */ + --grid-line: rgba(0, 0, 0, 0.045); + --grid-size: 46px; + --section-alt: rgba(0, 0, 0, 0.022); +} +.dark { + /* dark */ + --grid-line: rgba(255, 255, 255, 0.035); + --section-alt: rgba(255, 255, 255, 0.018); +} +``` + +### 4.4 The single blocker + +The grid is global by construction (it covers the panel, `auth`/`login`, error pages — every route — at once). Exactly **one** element hides it inside the panel: + +- `src/shared/components/layouts/DashboardLayout.tsx:62` — the outer wrapper paints an opaque `bg-bg`: + + ```jsx +
+ ``` + + Everything below it is already transparent — `
` (`:93`), the scroll container (`:102`), the `max-w-7xl` inner (`:103`). So **removing `bg-bg` from this one line** lets the body grid show through the entire content area (the body's `--color-bg` remains the base fill underneath the grid). + + ```diff + -
+ +
+ ``` + +### 4.5 Chrome interaction (sidebar / header) + +- `Header` (`src/shared/components/Header.tsx:207`, `bg-bg`) and `Sidebar` (`src/shared/components/Sidebar.tsx:430`, `bg-sidebar`) stay **opaque** → the grid shows in the **content area only**, with solid chrome framing it. This is the recommended, calm default and matches how the site separates chrome from canvas. +- _Optional vibrancy variant:_ make the header translucent (`bg-bg/80 backdrop-blur`) so the grid runs behind it. A `.bg-vibrancy` helper already exists (`globals.css:370`). **Decision D3 below.** + +### 4.6 Login / auth / error pages + +These render directly under `` (no panel chrome) and their page wrappers are mostly transparent — the global grid appears behind them automatically. One exception: `src/app/login/page.tsx:124,139` uses opaque `bg-bg` wrappers; soften the same way if we want the grid there too (minor, **D4**). + +### 4.7 Landing page + +`landing/page.tsx` keeps its richer animated background (orbs + vignette). Options: (a) leave it as-is (its own splash identity), or (b) align its grid to the global tokens (46px, neutral lines) for consistency. **Recommend (a)** — it's a marketing splash, not a panel screen. **Decision D5.** + +--- + +## 5. Part B — Token unification + +Add to `globals.css` (`:root` + `@theme inline`) so the dashboard gains the site's missing tokens. None of these change existing colors; they add the _missing_ primitives. + +```css +:root { + --surface-2: #f5f5fa; /* light: nested panels */ + --radius: 14px; + --radius-sm: 9px; + --grad-brand: linear-gradient(135deg, var(--color-primary), var(--color-accent-light)); + --font-mono: ui-monospace, "JetBrains Mono", "Fira Code", "SF Mono", monospace; +} +.dark { + --surface-2: #1c2230; +} + +@theme inline { + --color-surface-2: var(--surface-2); /* enables bg-surface-2 */ + --radius-lg: var(--radius); /* enables rounded-lg = 14px */ + --radius-md: var(--radius-sm); /* enables rounded-md = 9px */ + --font-mono: var(--font-mono); /* enables font-mono */ +} +``` + +| Token | Why | Consumers | +| -------------------------- | --------------------------------------------------------------- | ----------------------------------------------------------- | +| `--radius` / `--radius-sm` | One radius scale (14/9) instead of 6/8/12 ad-hoc | Button, Card, Modal, Input, Select | +| `--grad-brand` | Brand gradient for primary CTAs (red→violet), matching the site | Button `primary`, hero/CTA surfaces | +| `--surface-2` | Nested panels / table headers / inset rows | Card.Section, DataTable header, inputs | +| `--font-mono` | Code blocks, terminal, IDs, endpoints | ConsoleLogViewer, code snippets, `localhost:20128/v1` chips | +| `--text-muted` reconcile | Pick one value site↔panel | global | + +**Decision D2 (text-muted):** site `#8b8b9e` vs dashboard `#a1a1aa`. Recommend keeping the **dashboard's `#a1a1aa`** (it's the live product, slightly higher contrast) and updating the _site_ to match. Low priority, cosmetic. + +--- + +## 6. Part C — Component standardization + +The component layer is **custom** (no shadcn/Radix), Tailwind v4, semantic tokens **mostly** adopted (`bg-surface`, `border-white/10`, `ring-primary`) — good adoption (195 files import the shared barrel). The work is removing the **bypasses**. Home: `src/shared/components/`. + +Ranked by impact × reach: + +| # | Item | File(s) | Problem → Target | +| --- | ------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| C1 | **Radius alignment** | `Button.tsx:14-18`, `Card.tsx:39`, `Modal.tsx`, `Input.tsx`, `Select.tsx` | mixed 6/8/12px → repoint to `--radius`/`--radius-sm` (14/9) | +| C2 | **Button gradient + `accent` variant** | `Button.tsx:5-12` | primary is flat red→red (`from-primary to-primary-hover`); align to `--grad-brand` (red→violet) and add the missing `accent` variant (indigo `#6366f1` is unused by buttons) — **highest visibility, ~195 importers**. **Decision D1.** | +| C3 | **Tables** | `DataTable.tsx:122-176`, `logTableStyles.ts`, `globals.css:405-414` (Ant remnants) | `DataTable` is 100% inline hardcoded rgba + references non-existent vars (`--text-secondary`, `--bg-table-header`); migrate to tokens, retire the 2 divergent table styles. Tables are everywhere (providers/connections/logs) — worst offender. | +| C4 | **Centralize status colors** | `flow/edgeStyles.ts:7-12`, `TokenHealthBadge.tsx:14-19`, `DegradationBadge.tsx`, `ProviderCascadeNode.tsx`, `Badge.tsx`, +5 `statusColor` helpers | 6+ copies of the same `#22c55e/#f59e0b/#ef4444` hex; create one `statusColors` module driven off `--color-success/warning/error`. Critical for circuit-breaker / cooldown / lockout badges to read consistently. | +| C5 | **Card border** | `Card.tsx:39` | uses `border-white/5`; brand border is `/8` → align | +| C6 | **Focus ring reconcile** | `globals.css:183` vs component `ring-primary/30` | global `:focus-visible` is indigo (`--color-accent`), components are red (`ring-primary`) — pick one (recommend **accent/indigo** globally, it reads as the "interactive" color) | +| C7 | **Add `Checkbox` + `Textarea` primitives** | currently raw ``/`