mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-07-31 04:12:10 +03:00
* chore(release): open v3.8.20 development cycle * fix(images): prefer bare combos over image aliases (#3527) Integrated into release/v3.8.20 * fix(translator): map Codex local_shell tool (#3534) Integrated into release/v3.8.20 * fix(usage): make opencode-go quota fetcher fail-open instead of throwing 500 (#3522) Integrated into release/v3.8.20 * Fix Runtime page breaker state rendering (#3533) Integrated into release/v3.8.20 * Expose provider breaker degradation threshold setting (#3535) Integrated into release/v3.8.20 * fix(executor): strip provider prefix from versioned built-in tool model field (#3532) Integrated into release/v3.8.20 * feat(providers): add Claude Fable 5 support (#3524) Integrated into release/v3.8.20 * feat(resilience): add global provider cooldown tracking to prevent combo re-walking (#3556) Integrated into release/v3.8.20 (default OFF, opt-in) * fix(translator): scope thoughtSignature bypass to Antigravity/CLI only (#3560) Integrated into release/v3.8.20. Co-authored-by: Six7Day <six7day@gmail.com> * fix(routing): normalize thinking:disabled for combo-substituted models that reject it (#3554) (#3563) Integrated into release/v3.8.20 * fix(usage): accept 0/empty budget limits so the dashboard can save and clear (#3537) (#3564) Integrated into release/v3.8.20 * docs(changelog): credit @Six7Day for #3560 thoughtSignature fix (#3414) The #3560 squash co-author trailer landed inline (unparsed by GitHub), so add an explicit CHANGELOG credit ensuring @Six7Day (original #3414) and @oyi77 are on the public record for the Gemini thoughtSignature fix. * fix(gamification): dedup badge unlock via user_badges so events don't re-fire every request (#3472) (#3565) Integrated into release/v3.8.20 * fix(routing): pass through 'auto' keyword on codex /v1/responses instead of rewriting to codex/auto (#3509) (#3566) Integrated into release/v3.8.20 * fix(cli-tools): normalize apiKey null in guide-settings schema so cloud-mode config saves (#3552) (#3567) Integrated into release/v3.8.20 * fix(catalog): reclassify PublicAI from keyless to one-time-initial (requires API key) (#3558) (#3568) Integrated into release/v3.8.20 * fix(gemini-web): surface missing Playwright browser as actionable 503 + cooldown hint, not a retryable 500 loop (#3516) (#3570) Integrated into release/v3.8.20 * fix(security): sanitize raw err.message in web executors + embeddings/search response bodies (Rule #12) (#3494, #3495) (#3573) Integrated into release/v3.8.20 * fix(dashboard): point CustomHostsManager + FeatureFlagsGrid at real routes (#3486, #3487) (#3574) Integrated into release/v3.8.20 * chore(providers): remove dead krutrim entry (#3483) + docs(api): fix agent-bridge per-agent state route (#3489) (#3575) Integrated into release/v3.8.20 * docs(api): correct API_REFERENCE.md paths for skills/plugins/admin/cache/acp/system-info (#3497) (#3577) Integrated into release/v3.8.20 * fix(proxy): drive SOCKS5 UI option from runtime ENABLE_SOCKS5_PROXY, not build-time NEXT_PUBLIC (#3508) (#3579) Integrated into release/v3.8.20 * fix(playground): filter playground models by node prefix so custom-endpoint models appear (#3505) (#3581) Integrated into release/v3.8.20 * fix(usage): show an informative message instead of a blank Kiro quota card when no usage breakdown (#3506) (#3582) Integrated into release/v3.8.20 * docs(changelog): add the #3506 Kiro quota entry (missed in #3582 due to a stale-base CHANGELOG anchor) (#3583) Integrated into release/v3.8.20 * fix(auto-update): use stable PROJECT_ROOT walker, not frozen process.cwd() (#3561) Integrated into release/v3.8.20. Auto-update PROJECT_ROOT now uses a stable __dirname-anchored upward walker instead of the no-op process.cwd() resolver. * fix: address PR #3518 review comments (lifecycle hooks, regex, indentation, route params) (#3562) Integrated into release/v3.8.20. Addresses #3518 review: regex literals, logs/[id] route params (Next 16), indentation, and wires plugin lifecycle hooks (onInstall/onActivate/onDeactivate/onUninstall) in the loader so manager.ts can register them. Adds Rule #18 regression test. * docs(changelog): credit @ViFigueiredo (#3423) for PROJECT_ROOT + log #3561/#3562 (v3.8.20) * fix: openai to gemini incorrectly translates historical tool calls into text (#3569) Integrated into release/v3.8.20. Standard Gemini direct path now maps historical tool calls to native functionCall/functionResponse parts (signaturelessToolCallMode: native) instead of inert text — validated against the real Gemini API (gemini-2.5-flash returns 200 for signatureless native functionCall, even with tools+thinking; Hard Rule #18). Eliminates the text-serialization leak. Antigravity/CLI sentinel path (#3560) untouched. * docs(changelog)+test: reconcile standard-Gemini native mode (#3569) — update round-2 rationale comment + log VPS validation * docs(changelog): reconcile v3.8.20 — add 9 missing bullets + move [Unreleased] to versioned section * docs(changelog): complete v3.8.20 reconciliation — 27 bullets, 11 contributors --------- Co-authored-by: Alexander Averyanov <alex@averyan.ru> Co-authored-by: Hakan Kurşun <bykamaka@gmail.com> Co-authored-by: Wilson <pedbookmed@gmail.com> Co-authored-by: Randi <55005611+rdself@users.noreply.github.com> Co-authored-by: Giorgos Giakoumettis <giorgos@yiakoumettis.gr> Co-authored-by: PizzaV <103120356+pizzav-xyz@users.noreply.github.com> Co-authored-by: Paijo <14921983+oyi77@users.noreply.github.com> Co-authored-by: Markus Hartung <mail@hartmark.se>
OmniRoute Electron Desktop App
This directory contains the Electron desktop application wrapper for OmniRoute.
Architecture (v1.6.4)
electron/
├── main.js # Main process — window, tray, server lifecycle, CSP, IPC
├── preload.js # Preload script — secure IPC bridge with disposer pattern
├── package.json # Electron-specific dependencies & electron-builder config
├── types.d.ts # TypeScript definitions (AppInfo, ServerStatus, ElectronAPI)
└── assets/ # Application icons and resources
src/shared/hooks/
└── useElectron.ts # React hooks — useSyncExternalStore, zero re-renders
Key Design Decisions
| Decision | Rationale |
|---|---|
waitForServer() polling |
Prevents blank screen on cold start — polls http://localhost:PORT before loading |
stdio: 'pipe' |
Captures server stdout/stderr for logging + readiness detection (not inherit) |
| Disposer pattern | onServerStatus() returns () => void for precise listener cleanup (no removeAllListeners) |
useSyncExternalStore |
Zero re-renders for useIsElectron() — no useState + useEffect cycle |
| CSP via session headers | Content-Security-Policy restricts script-src, connect-src etc. per Electron best practices |
| Platform-conditional titlebar | titleBarStyle: 'hiddenInset' only on macOS; default on Windows/Linux |
Development
Prerequisites
- Build the Next.js app first:
npm run build
- Install Electron dependencies:
cd electron
npm install
Running in Development
- Start the Next.js development server:
npm run dev
- In another terminal, start Electron:
cd electron
npm run dev
Running in Production Mode
- Build Next.js in standalone mode:
npm run build
- Start Electron:
cd electron
npm start
Building
Build for Current Platform
cd electron
npm run build
Build for Specific Platforms
# Windows
npm run build:win
# macOS (x64 + arm64)
npm run build:mac
# Linux
npm run build:linux
Output
Built applications are placed in dist-electron/:
- Windows:
.exeinstaller (NSIS) + portable.exe - macOS:
.dmginstaller (Intel + Apple Silicon) - Linux:
.AppImage
Installation
macOS
- Download the latest
.dmgfrom the Releases page. - Open the
.dmgfile. - Drag
OmniRoute.appto the Applications folder. - Launch from Applications.
⚠️ Note: The app is not signed with an Apple Developer certificate yet. If macOS blocks the app, run:
xattr -cr /Applications/OmniRoute.appOr right-click the app → Open → Open (to bypass Gatekeeper on first launch).
Windows
Installer (Recommended):
- Download
OmniRoute.Setup.*.exefrom Releases. - Run the installer.
- Launch from Start Menu or Desktop shortcut.
Portable (No Installation):
- Download
OmniRoute.exefrom Releases. - Run directly from any folder.
Linux
- Download the
.AppImagefrom Releases. - Make it executable:
chmod +x OmniRoute-*.AppImage - Run:
./OmniRoute-*.AppImage
Features
- Server Readiness — Waits for health check before showing window
- System Tray — Minimize to tray with quick actions (open, port change, quit)
- Port Management — Change port from tray menu (server restarts automatically)
- Window Controls — Custom minimize, maximize, close via IPC
- Content Security Policy — Restrictive CSP via session headers
- Offline Support — Bundled Next.js standalone server
- Single Instance — Only one app instance can run at a time
Configuration
Environment Variables
| Variable | Default | Description |
|---|---|---|
OMNIROUTE_PORT |
20128 |
Server port |
OMNIROUTE_MEMORY_MB |
512 |
Node.js heap limit (64–16384 MB) |
NODE_ENV |
production |
Set to development for dev mode |
Custom Icon
Place your icons in assets/:
icon.ico— Windows icon (256×256)icon.icns— macOS icon bundleicon.png— Linux/general use (512×512)tray-icon.png— System tray icon (16×16 or 32×32)
IPC Channels
Invoke (Renderer → Main, async)
| Channel | Returns | Description |
|---|---|---|
get-app-info |
AppInfo |
App name, version, platform, isDev, port |
open-external |
void |
Open URL in default browser (http/https only) |
get-data-dir |
string |
Get userData directory path |
restart-server |
{ success } |
Stop + restart server (5s timeout + SIGKILL) |
Send (Renderer → Main, fire-and-forget)
| Channel | Description |
|---|---|
window-minimize |
Minimize window |
window-maximize |
Toggle maximize/restore |
window-close |
Close window (minimize to tray) |
Receive (Main → Renderer, events)
| Channel | Payload | Emitted When |
|---|---|---|
server-status |
ServerStatus |
Server starts, stops, errors, or restarts |
port-changed |
number |
Port change via tray menu |
Note
: Listeners return disposer functions for precise cleanup. See
useServerStatusandusePortChangedhooks.
Security
| Feature | Implementation |
|---|---|
| Context Isolation | contextIsolation: true — renderer cannot access Node.js |
| Node Integration | nodeIntegration: false — no require() in renderer |
| IPC Whitelist | Channel names validated in preload via safeInvoke/safeSend/safeOn |
| URL Validation | shell.openExternal() only allows http: / https: protocols |
| CSP | Content-Security-Policy header set via session.webRequest.onHeadersReceived |
| Web Security | webSecurity: true — same-origin policy enforced |
React Hooks
| Hook | Returns | Description |
|---|---|---|
useIsElectron() |
boolean |
Zero-render detection via useSyncExternalStore |
useElectronAppInfo() |
{ appInfo, loading, error } |
App info from main process |
useDataDir() |
{ dataDir, loading, error } |
User data directory |
useWindowControls() |
{ minimize, maximize, close } |
Window control actions |
useOpenExternal() |
{ openExternal } |
Open URLs in browser |
useServerControls() |
{ restart, restarting } |
Server restart control |
useServerStatus(cb) |
Disposer | Listen for server status events |
usePortChanged(cb) |
Disposer | Listen for port change events |
Troubleshooting
App Won't Start
- Check if port 20128 is available:
lsof -i :20128 - Check console logs for
[Electron]prefix - Verify the build output exists in
.build/next/standalone
White Screen
- Verify Next.js build exists — server readiness waits 30s max
- Check
[Server]and[Server:err]log output - Look for CSP violations in developer console
Build Fails
Ensure you have build tools installed:
- Windows: Visual Studio Build Tools
- macOS: Xcode Command Line Tools
- Linux:
build-essential,libsecret-1-dev
License
MIT