diff --git a/package-lock.json b/package-lock.json index cf0490c53b..c3fc223c25 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "omniroute", - "version": "2.0.10", + "version": "2.0.11", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "omniroute", - "version": "2.0.10", + "version": "2.0.11", "hasInstallScript": true, "license": "MIT", "workspaces": [ diff --git a/package.json b/package.json index 23d77085ad..28121864fd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "omniroute", - "version": "2.0.11", + "version": "2.0.12", "description": "Smart AI Router with auto fallback — route to FREE & cheap models, zero downtime. Works with Cursor, Cline, Claude Desktop, Codex, and any OpenAI-compatible tool.", "type": "module", "bin": { diff --git a/src/app/(dashboard)/dashboard/agents/page.tsx b/src/app/(dashboard)/dashboard/agents/page.tsx index a61b7b7a9d..3660e6cba9 100644 --- a/src/app/(dashboard)/dashboard/agents/page.tsx +++ b/src/app/(dashboard)/dashboard/agents/page.tsx @@ -3,6 +3,7 @@ import { useState, useEffect, useCallback } from "react"; import { Card, Button, Input } from "@/shared/components"; import { useTranslations } from "next-intl"; +import { AI_PROVIDERS } from "@/shared/constants/config"; interface AgentInfo { id: string; @@ -29,6 +30,7 @@ export default function AgentsPage() { const [refreshing, setRefreshing] = useState(false); const [showAddForm, setShowAddForm] = useState(false); const [addLoading, setAddLoading] = useState(false); + const [settings, setSettings] = useState>({}); const [newAgent, setNewAgent] = useState({ name: "", binary: "", @@ -36,6 +38,7 @@ export default function AgentsPage() { spawnArgs: "", }); const t = useTranslations("agents"); + const ts = useTranslations("settings"); const fetchAgents = useCallback(async () => { try { @@ -52,8 +55,26 @@ export default function AgentsPage() { useEffect(() => { fetchAgents(); + // Also fetch settings for CLI fingerprint + fetch("/api/settings") + .then((r) => r.json()) + .then((d) => setSettings(d)) + .catch(() => {}); }, [fetchAgents]); + const updateSetting = async (key: string, value: any) => { + try { + const res = await fetch("/api/settings", { + method: "PATCH", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ [key]: value }), + }); + if (res.ok) setSettings((prev) => ({ ...prev, [key]: value })); + } catch (err) { + console.error("Failed to update setting:", err); + } + }; + const handleRefresh = async () => { setRefreshing(true); try { @@ -64,7 +85,7 @@ export default function AgentsPage() { }); const data = await res.json(); setAgents(data.agents || []); - await fetchAgents(); // Re-fetch for summary + await fetchAgents(); } catch (err) { console.error("Failed to refresh:", err); } finally { @@ -156,6 +177,70 @@ export default function AgentsPage() { )} + {/* CLI Fingerprint Matching */} + +
+
+ +
+

{ts("cliFingerprint")}

+
+
+

{ts("cliFingerprintDesc")}

+
+ {(["codex", "claude", "github", "antigravity"] as const).map((providerId) => { + const providerMeta = Object.values(AI_PROVIDERS).find( + (p: any) => p.id === providerId + ) as any; + const isEnabled = (settings.cliCompatProviders || []).includes(providerId); + const displayName = providerMeta?.name || providerId; + const icon = providerMeta?.icon || "terminal"; + const color = providerMeta?.color || "#888"; + return ( + + ); + })} +
+ {(settings.cliCompatProviders || []).length > 0 && ( +

+ verified + {ts("cliFingerprintEnabled", { + count: (settings.cliCompatProviders || []).length, + })} +

+ )} +
+
+ {/* Agent Grid */}
{agents.map((agent) => ( diff --git a/src/app/(dashboard)/dashboard/settings/components/SecurityTab.tsx b/src/app/(dashboard)/dashboard/settings/components/SecurityTab.tsx index bd83ec2a7a..5583361467 100644 --- a/src/app/(dashboard)/dashboard/settings/components/SecurityTab.tsx +++ b/src/app/(dashboard)/dashboard/settings/components/SecurityTab.tsx @@ -248,76 +248,6 @@ export default function SecurityTab() {
- {/* CLI Fingerprint Matching */} - -
-
- -
-

{t("cliFingerprint")}

-
-
-

{t("cliFingerprintDesc")}

-
- {(["codex", "claude", "github", "antigravity"] as const).map((providerId) => { - const providerMeta = Object.values(AI_PROVIDERS).find( - (p: any) => p.id === providerId - ) as any; - const isEnabled = (settings.cliCompatProviders || []).includes(providerId); - const displayName = providerMeta?.name || providerId; - const icon = providerMeta?.icon || "terminal"; - const color = providerMeta?.color || "#888"; - return ( - - ); - })} -
- {(settings.cliCompatProviders || []).length > 0 && ( -

- verified - {t("cliFingerprintEnabled", { - count: (settings.cliCompatProviders || []).length, - })} -

- )} -
-
- diff --git a/src/i18n/messages/ar.json b/src/i18n/messages/ar.json index 5c50cf1810..02e0cf0c21 100644 --- a/src/i18n/messages/ar.json +++ b/src/i18n/messages/ar.json @@ -102,7 +102,8 @@ "themeCyan": "كيان", "endpoints": "نقاط النهاية", "playground": "ملعب النماذج", - "agents": "وكلاء" + "agents": "وكلاء", + "cliToolsShort": "أدوات" }, "themesPage": { "title": "المواضيع", diff --git a/src/i18n/messages/bg.json b/src/i18n/messages/bg.json index 257322135f..25984c3018 100644 --- a/src/i18n/messages/bg.json +++ b/src/i18n/messages/bg.json @@ -102,7 +102,8 @@ "themeCyan": "Циан", "endpoints": "Крайни точки", "playground": "Площадка", - "agents": "Агенти" + "agents": "Агенти", + "cliToolsShort": "Инструменти" }, "themesPage": { "title": "Теми", diff --git a/src/i18n/messages/da.json b/src/i18n/messages/da.json index f2fbc425f9..b8fb607ca6 100644 --- a/src/i18n/messages/da.json +++ b/src/i18n/messages/da.json @@ -102,7 +102,8 @@ "themeCyan": "Turkis", "endpoints": "Endpoints", "playground": "Legeplads", - "agents": "Agenter" + "agents": "Agenter", + "cliToolsShort": "Værktøjer" }, "themesPage": { "title": "Temaer", diff --git a/src/i18n/messages/de.json b/src/i18n/messages/de.json index 2dc4819c90..db8b9eafe1 100644 --- a/src/i18n/messages/de.json +++ b/src/i18n/messages/de.json @@ -102,7 +102,8 @@ "themeCyan": "Cyan", "endpoints": "Endpunkte", "playground": "Spielwiese", - "agents": "Agenten" + "agents": "Agenten", + "cliToolsShort": "Werkzeuge" }, "themesPage": { "title": "Themen", diff --git a/src/i18n/messages/en.json b/src/i18n/messages/en.json index 69ee31cfba..d98f24defd 100644 --- a/src/i18n/messages/en.json +++ b/src/i18n/messages/en.json @@ -102,7 +102,8 @@ "themeGreen": "Green", "themeViolet": "Violet", "themeOrange": "Orange", - "themeCyan": "Cyan" + "themeCyan": "Cyan", + "cliToolsShort": "Tools" }, "themesPage": { "title": "Themes", diff --git a/src/i18n/messages/es.json b/src/i18n/messages/es.json index 3b69525252..391bf064a4 100644 --- a/src/i18n/messages/es.json +++ b/src/i18n/messages/es.json @@ -102,7 +102,8 @@ "themeCyan": "cian", "endpoints": "Endpoints", "playground": "Playground", - "agents": "Agentes" + "agents": "Agentes", + "cliToolsShort": "Herramientas" }, "themesPage": { "title": "Temas", diff --git a/src/i18n/messages/fi.json b/src/i18n/messages/fi.json index 706075d486..47d8201360 100644 --- a/src/i18n/messages/fi.json +++ b/src/i18n/messages/fi.json @@ -102,7 +102,8 @@ "themeCyan": "Syaani", "endpoints": "Päätepisteet", "playground": "Leikkipaikka", - "agents": "Agentit" + "agents": "Agentit", + "cliToolsShort": "Työkalut" }, "themesPage": { "title": "Teemat", diff --git a/src/i18n/messages/fr.json b/src/i18n/messages/fr.json index f8c89eebba..4d4bbe4fa2 100644 --- a/src/i18n/messages/fr.json +++ b/src/i18n/messages/fr.json @@ -102,7 +102,8 @@ "themeCyan": "Cyan", "endpoints": "Points d'accès", "playground": "Playground", - "agents": "Agents" + "agents": "Agents", + "cliToolsShort": "Outils" }, "themesPage": { "title": "Thèmes", diff --git a/src/i18n/messages/he.json b/src/i18n/messages/he.json index e14e562034..005826cb0d 100644 --- a/src/i18n/messages/he.json +++ b/src/i18n/messages/he.json @@ -102,7 +102,8 @@ "themeCyan": "Cyan", "endpoints": "נקודות קצה", "playground": "Playground", - "agents": "סוכנים" + "agents": "סוכנים", + "cliToolsShort": "כלים" }, "themesPage": { "title": "Themes", diff --git a/src/i18n/messages/hu.json b/src/i18n/messages/hu.json index bfea2cc7b1..27ef81d4a3 100644 --- a/src/i18n/messages/hu.json +++ b/src/i18n/messages/hu.json @@ -102,7 +102,8 @@ "themeCyan": "Cián", "endpoints": "Végpontok", "playground": "Játszótér", - "agents": "Ügynökök" + "agents": "Ügynökök", + "cliToolsShort": "Eszközök" }, "themesPage": { "title": "Témák", diff --git a/src/i18n/messages/id.json b/src/i18n/messages/id.json index 45cd1e7d9a..cd164363c8 100644 --- a/src/i18n/messages/id.json +++ b/src/i18n/messages/id.json @@ -102,7 +102,8 @@ "themeCyan": "Cyan", "endpoints": "Endpoint", "playground": "Playground", - "agents": "Agen" + "agents": "Agen", + "cliToolsShort": "Alat" }, "themesPage": { "title": "Themes", diff --git a/src/i18n/messages/in.json b/src/i18n/messages/in.json index 15e550d614..915e6c59e0 100644 --- a/src/i18n/messages/in.json +++ b/src/i18n/messages/in.json @@ -102,7 +102,8 @@ "themeCyan": "Cyan", "endpoints": "Endpoint", "playground": "Playground", - "agents": "एजेंट" + "agents": "एजेंट", + "cliToolsShort": "उपकरण" }, "themesPage": { "title": "Themes", diff --git a/src/i18n/messages/it.json b/src/i18n/messages/it.json index 1d622389b1..8b9bcd0c6d 100644 --- a/src/i18n/messages/it.json +++ b/src/i18n/messages/it.json @@ -102,7 +102,8 @@ "themeCyan": "Cyan", "endpoints": "Endpoint", "playground": "Playground", - "agents": "Agenti" + "agents": "Agenti", + "cliToolsShort": "Strumenti" }, "themesPage": { "title": "Themes", diff --git a/src/i18n/messages/ja.json b/src/i18n/messages/ja.json index 7b72f4c309..a40e5add3c 100644 --- a/src/i18n/messages/ja.json +++ b/src/i18n/messages/ja.json @@ -102,7 +102,8 @@ "themeCyan": "Cyan", "endpoints": "エンドポイント", "playground": "プレイグラウンド", - "agents": "エージェント" + "agents": "エージェント", + "cliToolsShort": "ツール" }, "themesPage": { "title": "Themes", diff --git a/src/i18n/messages/ko.json b/src/i18n/messages/ko.json index bb4a8cdabc..8d89e639a4 100644 --- a/src/i18n/messages/ko.json +++ b/src/i18n/messages/ko.json @@ -102,7 +102,8 @@ "themeCyan": "Cyan", "endpoints": "엔드포인트", "playground": "플레이그라운드", - "agents": "에이전트" + "agents": "에이전트", + "cliToolsShort": "도구" }, "themesPage": { "title": "Themes", diff --git a/src/i18n/messages/ms.json b/src/i18n/messages/ms.json index fc14ee0413..6019deba89 100644 --- a/src/i18n/messages/ms.json +++ b/src/i18n/messages/ms.json @@ -102,7 +102,8 @@ "themeCyan": "Cyan", "endpoints": "Titik Akhir", "playground": "Playground", - "agents": "Ejen" + "agents": "Ejen", + "cliToolsShort": "Alat" }, "themesPage": { "title": "Themes", diff --git a/src/i18n/messages/nl.json b/src/i18n/messages/nl.json index 1be295d1ee..5a142276e5 100644 --- a/src/i18n/messages/nl.json +++ b/src/i18n/messages/nl.json @@ -102,7 +102,8 @@ "themeCyan": "Cyan", "endpoints": "Eindpunten", "playground": "Speeltuin", - "agents": "Agenten" + "agents": "Agenten", + "cliToolsShort": "Gereedschap" }, "themesPage": { "title": "Themes", diff --git a/src/i18n/messages/no.json b/src/i18n/messages/no.json index ac7668f5f7..0d93c32a2c 100644 --- a/src/i18n/messages/no.json +++ b/src/i18n/messages/no.json @@ -102,7 +102,8 @@ "themeCyan": "Cyan", "endpoints": "Endepunkter", "playground": "Lekeplass", - "agents": "Agenter" + "agents": "Agenter", + "cliToolsShort": "Verktøy" }, "themesPage": { "title": "Themes", diff --git a/src/i18n/messages/phi.json b/src/i18n/messages/phi.json index 85403c3c30..3530ccf23c 100644 --- a/src/i18n/messages/phi.json +++ b/src/i18n/messages/phi.json @@ -102,7 +102,8 @@ "themeCyan": "Cyan", "endpoints": "Mga Endpoint", "playground": "Playground", - "agents": "Mga Agent" + "agents": "Mga Agent", + "cliToolsShort": "Mga Tool" }, "themesPage": { "title": "Themes", diff --git a/src/i18n/messages/pl.json b/src/i18n/messages/pl.json index 53ae0bab48..919db53fa7 100644 --- a/src/i18n/messages/pl.json +++ b/src/i18n/messages/pl.json @@ -102,7 +102,8 @@ "themeCyan": "Cyan", "endpoints": "Punkty końcowe", "playground": "Plac zabaw", - "agents": "Agenci" + "agents": "Agenci", + "cliToolsShort": "Narzędzia" }, "themesPage": { "title": "Themes", diff --git a/src/i18n/messages/pt-BR.json b/src/i18n/messages/pt-BR.json index f42ba2edac..07b3931bc0 100644 --- a/src/i18n/messages/pt-BR.json +++ b/src/i18n/messages/pt-BR.json @@ -102,7 +102,8 @@ "themeCyan": "Cyan", "endpoints": "Endpoints", "playground": "Playground", - "agents": "Agentes" + "agents": "Agentes", + "cliToolsShort": "Ferramentas" }, "themesPage": { "title": "Themes", diff --git a/src/i18n/messages/pt.json b/src/i18n/messages/pt.json index 47ddb6f78e..9423b29112 100644 --- a/src/i18n/messages/pt.json +++ b/src/i18n/messages/pt.json @@ -102,7 +102,8 @@ "themeOrange": "Laranja", "themeCyan": "Ciano", "playground": "Playground", - "agents": "Agentes" + "agents": "Agentes", + "cliToolsShort": "Ferramentas" }, "themesPage": { "title": "Themes", diff --git a/src/i18n/messages/ro.json b/src/i18n/messages/ro.json index 5fa092b3ab..84557f1e28 100644 --- a/src/i18n/messages/ro.json +++ b/src/i18n/messages/ro.json @@ -102,7 +102,8 @@ "themeCyan": "Cyan", "endpoints": "Puncte finale", "playground": "Playground", - "agents": "Agenți" + "agents": "Agenți", + "cliToolsShort": "Instrumente" }, "themesPage": { "title": "Themes", diff --git a/src/i18n/messages/ru.json b/src/i18n/messages/ru.json index 440020b6b5..f9f0b94910 100644 --- a/src/i18n/messages/ru.json +++ b/src/i18n/messages/ru.json @@ -102,7 +102,8 @@ "themeCyan": "Голубой", "endpoints": "Конечные точки", "playground": "Площадка", - "agents": "Агенты" + "agents": "Агенты", + "cliToolsShort": "Инструменты" }, "themesPage": { "title": "Темы", diff --git a/src/i18n/messages/sk.json b/src/i18n/messages/sk.json index c07ca77acc..efa2c09c6f 100644 --- a/src/i18n/messages/sk.json +++ b/src/i18n/messages/sk.json @@ -102,7 +102,8 @@ "themeCyan": "Cyan", "endpoints": "Koncové body", "playground": "Ihrisko", - "agents": "Agenti" + "agents": "Agenti", + "cliToolsShort": "Nástroje" }, "themesPage": { "title": "Themes", diff --git a/src/i18n/messages/sv.json b/src/i18n/messages/sv.json index 067f8d27f5..1c8677445d 100644 --- a/src/i18n/messages/sv.json +++ b/src/i18n/messages/sv.json @@ -102,7 +102,8 @@ "themeCyan": "Cyan", "endpoints": "Ändpunkter", "playground": "Lekplats", - "agents": "Agenter" + "agents": "Agenter", + "cliToolsShort": "Verktyg" }, "themesPage": { "title": "Themes", diff --git a/src/i18n/messages/th.json b/src/i18n/messages/th.json index d1e48e72d4..8179ee5cc2 100644 --- a/src/i18n/messages/th.json +++ b/src/i18n/messages/th.json @@ -102,7 +102,8 @@ "themeCyan": "Cyan", "endpoints": "จุดปลายทาง", "playground": "Playground", - "agents": "เอเจนต์" + "agents": "เอเจนต์", + "cliToolsShort": "เครื่องมือ" }, "themesPage": { "title": "ธีมส์", diff --git a/src/i18n/messages/uk-UA.json b/src/i18n/messages/uk-UA.json index dc9ed0ecb5..fbb55eca92 100644 --- a/src/i18n/messages/uk-UA.json +++ b/src/i18n/messages/uk-UA.json @@ -102,7 +102,8 @@ "themeCyan": "Cyan", "endpoints": "Кінцеві точки", "playground": "Playground", - "agents": "Агенти" + "agents": "Агенти", + "cliToolsShort": "Інструменти" }, "themesPage": { "title": "Themes", diff --git a/src/i18n/messages/vi.json b/src/i18n/messages/vi.json index 5dd4d43a66..fac363b221 100644 --- a/src/i18n/messages/vi.json +++ b/src/i18n/messages/vi.json @@ -102,7 +102,8 @@ "themeCyan": "Cyan", "endpoints": "Điểm cuối", "playground": "Playground", - "agents": "Tác nhân" + "agents": "Tác nhân", + "cliToolsShort": "Công cụ" }, "themesPage": { "title": "Themes", diff --git a/src/i18n/messages/zh-CN.json b/src/i18n/messages/zh-CN.json index 4b72b7f0f0..b6f52e0282 100644 --- a/src/i18n/messages/zh-CN.json +++ b/src/i18n/messages/zh-CN.json @@ -102,7 +102,8 @@ "themeCyan": "Cyan", "endpoints": "端点", "playground": "模型试验场", - "agents": "代理" + "agents": "代理", + "cliToolsShort": "工具" }, "themesPage": { "title": "Themes", diff --git a/src/shared/components/Sidebar.tsx b/src/shared/components/Sidebar.tsx index 0a177e32ce..09672b03a7 100644 --- a/src/shared/components/Sidebar.tsx +++ b/src/shared/components/Sidebar.tsx @@ -18,22 +18,27 @@ const navItemDefs = [ { href: "/dashboard/api-manager", i18nKey: "apiManager", icon: "vpn_key" }, { href: "/dashboard/providers", i18nKey: "providers", icon: "dns" }, { href: "/dashboard/combos", i18nKey: "combos", icon: "layers" }, - { href: "/dashboard/logs", i18nKey: "logs", icon: "description" }, { href: "/dashboard/costs", i18nKey: "costs", icon: "account_balance_wallet" }, { href: "/dashboard/analytics", i18nKey: "analytics", icon: "analytics" }, { href: "/dashboard/limits", i18nKey: "limits", icon: "tune" }, - { href: "/dashboard/health", i18nKey: "health", icon: "health_and_safety" }, - { href: "/dashboard/cli-tools", i18nKey: "cliTools", icon: "terminal" }, - { href: "/dashboard/media", i18nKey: "media", icon: "auto_awesome" }, +]; + +const cliItemDefs = [ + { href: "/dashboard/cli-tools", i18nKey: "cliToolsShort", icon: "terminal" }, + { href: "/dashboard/agents", i18nKey: "agents", icon: "smart_toy" }, ]; const debugItemDefs = [ { href: "/dashboard/translator", i18nKey: "translator", icon: "translate" }, { href: "/dashboard/playground", i18nKey: "playground", icon: "science" }, - { href: "/dashboard/agents", i18nKey: "agents", icon: "smart_toy" }, + { href: "/dashboard/media", i18nKey: "media", icon: "auto_awesome" }, ]; -const systemItemDefs = [{ href: "/dashboard/settings", i18nKey: "settings", icon: "settings" }]; +const systemItemDefs = [ + { href: "/dashboard/health", i18nKey: "health", icon: "health_and_safety" }, + { href: "/dashboard/logs", i18nKey: "logs", icon: "description" }, + { href: "/dashboard/settings", i18nKey: "settings", icon: "settings" }, +]; const helpItemDefs = [ { href: "/docs", i18nKey: "docs", icon: "menu_book" }, @@ -110,6 +115,7 @@ export default function Sidebar({ // Resolve i18n keys → labels const resolveItems = (defs) => defs.map((d) => ({ ...d, label: t(d.i18nKey) })); const navItems = resolveItems(navItemDefs); + const cliItems = resolveItems(cliItemDefs); const debugItems = resolveItems(debugItemDefs); const systemItems = resolveItems(systemItemDefs); const helpItems = resolveItems(helpItemDefs); @@ -238,6 +244,17 @@ export default function Sidebar({ > {navItems.map(renderNavLink)} + {/* CLI section */} +
+ {!collapsed && ( +

+ CLI +

+ )} + {collapsed &&
} + {cliItems.map(renderNavLink)} +
+ {/* Debug section */} {showDebug && (