Merge branch 'main' of github.com:NousResearch/hermes-agent into bb/gui

This commit is contained in:
Brooklyn Nicholson
2026-05-04 12:47:53 -05:00
182 changed files with 9843 additions and 974 deletions
+11 -1
View File
@@ -80,6 +80,14 @@ function RootRedirect() {
return <Navigate to="/sessions" replace />;
}
function UnknownRouteFallback({ pluginsLoading }: { pluginsLoading: boolean }) {
if (pluginsLoading) {
// Render nothing during the plugin-load window — a spinner here would just flash.
return null;
}
return <Navigate to="/sessions" replace />;
}
const CHAT_NAV_ITEM: NavItem = {
path: "/chat",
labelKey: "chat",
@@ -582,7 +590,9 @@ export default function App() {
))}
<Route
path="*"
element={<Navigate to="/sessions" replace />}
element={
<UnknownRouteFallback pluginsLoading={pluginsLoading} />
}
/>
</Routes>
@@ -4,6 +4,7 @@ import { Button } from "@nous-research/ui/ui/components/button";
import { ListItem } from "@nous-research/ui/ui/components/list-item";
import { Typography } from "@/components/NouiTypography";
import { BUILTIN_THEMES, useTheme } from "@/themes";
import type { DashboardTheme } from "@/themes";
import { useI18n } from "@/i18n";
import { cn } from "@/lib/utils";
@@ -11,8 +12,8 @@ import { cn } from "@/lib/utils";
* Compact theme picker mounted next to the language switcher in the header.
* Each dropdown row shows a 3-stop swatch (background / midground / warm
* glow) so users can preview the palette before committing. User-defined
* themes from `~/.hermes/dashboard-themes/*.yaml` that aren't in
* `BUILTIN_THEMES` render without swatches and apply the default palette.
* themes from `~/.hermes/dashboard-themes/*.yaml` use their API-provided
* definitions so they show real palette swatches just like built-ins.
*
* When placed at the bottom of a container (e.g. the sidebar rail), pass
* `dropUp` so the menu opens above the trigger instead of clipping below
@@ -95,7 +96,7 @@ export function ThemeSwitcher({ dropUp = false }: ThemeSwitcherProps) {
{availableThemes.map((th) => {
const isActive = th.name === themeName;
const preset = BUILTIN_THEMES[th.name];
const paletteTheme = BUILTIN_THEMES[th.name] ?? th.definition;
return (
<ListItem
@@ -109,8 +110,8 @@ export function ThemeSwitcher({ dropUp = false }: ThemeSwitcherProps) {
}}
className="gap-3"
>
{preset ? (
<ThemeSwatch theme={preset.name} />
{paletteTheme ? (
<ThemeSwatch theme={paletteTheme} />
) : (
<PlaceholderSwatch />
)}
@@ -144,10 +145,8 @@ export function ThemeSwitcher({ dropUp = false }: ThemeSwitcherProps) {
);
}
function ThemeSwatch({ theme }: { theme: string }) {
const preset = BUILTIN_THEMES[theme];
if (!preset) return <PlaceholderSwatch />;
const { background, midground, warmGlow } = preset.palette;
function ThemeSwatch({ theme }: { theme: DashboardTheme }) {
const { background, midground, warmGlow } = theme.palette;
return (
<div
aria-hidden
+18
View File
@@ -27,6 +27,15 @@ import {
Wrench,
FileQuestion,
Filter,
Cloud,
Sparkles,
LayoutDashboard,
BookOpen,
Route,
History,
Shield,
FileOutput,
RefreshCw,
} from "lucide-react";
import { api } from "@/lib/api";
import { getNestedValue, setNestedValue } from "@/lib/nested";
@@ -66,6 +75,15 @@ const CATEGORY_ICONS: Record<
logging: ClipboardList,
discord: MessageCircle,
auxiliary: Wrench,
bedrock: Cloud,
curator: Sparkles,
kanban: LayoutDashboard,
model_catalog: BookOpen,
openrouter: Route,
sessions: History,
tool_loop_guardrails: Shield,
tool_output: FileOutput,
updates: RefreshCw,
};
function CategoryIcon({
+10 -4
View File
@@ -311,9 +311,7 @@ export function ThemeProvider({ children }: { children: ReactNode }) {
/** All selectable themes (shown in the picker). Starts with just the
* built-ins; the API call below merges in user themes. */
const [availableThemes, setAvailableThemes] = useState<
Array<{ description: string; label: string; name: string }>
>(() =>
const [availableThemes, setAvailableThemes] = useState<ThemeSummary[]>(() =>
Object.values(BUILTIN_THEMES).map((t) => ({
name: t.name,
label: t.label,
@@ -360,6 +358,7 @@ export function ThemeProvider({ children }: { children: ReactNode }) {
name: t.name,
label: t.label,
description: t.description,
definition: t.definition,
})),
);
// Index any definitions the server shipped (user themes).
@@ -430,8 +429,15 @@ const ThemeContext = createContext<ThemeContextValue>({
});
interface ThemeContextValue {
availableThemes: Array<{ description: string; label: string; name: string }>;
availableThemes: ThemeSummary[];
setTheme: (name: string) => void;
theme: DashboardTheme;
themeName: string;
}
interface ThemeSummary {
description: string;
label: string;
name: string;
definition?: DashboardTheme;
}