feat: Hermes Workspace branding — Nous blue theme, caduceus avatar, all ClawSuite→Hermes text, Powered by badge
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* ClawSuite Electron Main Process
|
||||
* Hermes Workspace Electron Main Process
|
||||
* Wraps the Vite-built web app in a native desktop window
|
||||
*/
|
||||
|
||||
@@ -104,7 +104,7 @@ function createWindow() {
|
||||
height: 900,
|
||||
minWidth: 800,
|
||||
minHeight: 600,
|
||||
title: 'ClawSuite',
|
||||
title: 'Hermes Workspace',
|
||||
icon: existsSync(iconPath) ? iconPath : undefined,
|
||||
titleBarStyle: 'hiddenInset', // macOS native title bar
|
||||
trafficLightPosition: { x: 16, y: 16 },
|
||||
@@ -155,10 +155,10 @@ function createTray() {
|
||||
if (!existsSync(iconPath)) return
|
||||
|
||||
tray = new Tray(nativeImage.createFromPath(iconPath))
|
||||
tray.setToolTip('ClawSuite')
|
||||
tray.setToolTip('Hermes Workspace')
|
||||
|
||||
const contextMenu = Menu.buildFromTemplate([
|
||||
{ label: 'Open ClawSuite', click: () => mainWindow?.show() },
|
||||
{ label: 'Open Hermes Workspace', click: () => mainWindow?.show() },
|
||||
{ type: 'separator' },
|
||||
{ label: 'Gateway Status', enabled: false },
|
||||
{ type: 'separator' },
|
||||
@@ -269,4 +269,4 @@ app.on('before-quit', () => {
|
||||
})
|
||||
|
||||
// Set app name
|
||||
app.setName('ClawSuite')
|
||||
app.setName('Hermes Workspace')
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* ClawSuite Electron Preload Script
|
||||
* Hermes Workspace Electron Preload Script
|
||||
* Exposes safe IPC bridge to renderer
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "clawsuite",
|
||||
"version": "4.0.0",
|
||||
"description": "Supercharged dashboard for OpenClaw AI agents — chat, file explorer, terminal, and usage tracking",
|
||||
"name": "hermes-workspace",
|
||||
"version": "1.0.0-hackathon",
|
||||
"description": "Desktop workspace for Hermes Agent — chat, orchestration, and multi-agent coding pipelines",
|
||||
"author": "Eric (https://github.com/outsourc-e)",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
|
||||
BIN
public/hermes-favicon.ico
Normal file
BIN
public/hermes-favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.9 KiB |
BIN
public/hermes-icon.png
Normal file
BIN
public/hermes-icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 29 KiB |
BIN
public/hermes-logo.png
Normal file
BIN
public/hermes-logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.3 MiB |
@@ -23,7 +23,7 @@ const TIPS = [
|
||||
emoji: '🧠',
|
||||
text: 'Your agent has memory — it remembers context across sessions',
|
||||
},
|
||||
{ emoji: '🚀', text: 'ClawSuite works with any OpenClaw gateway instance' },
|
||||
{ emoji: '🚀', text: 'Hermes Workspace works with any OpenClaw gateway instance' },
|
||||
{
|
||||
emoji: '🎯',
|
||||
text: 'Pin important sessions to keep them at the top of your sidebar',
|
||||
|
||||
@@ -478,7 +478,7 @@ export function IsometricOffice({ sessions, className }: IsometricOfficeProps) {
|
||||
{/* Office info */}
|
||||
<div className="absolute bottom-3 left-3 rounded bg-slate-900/80 px-2 py-1 backdrop-blur">
|
||||
<span className="text-[9px] font-mono text-accent-400/60">
|
||||
🦞 ClawSuite Office
|
||||
🦞 Hermes Workspace Office
|
||||
</span>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@ export function LoginScreen() {
|
||||
<circle cx="50" cy="50" r="15" fill="currentColor" />
|
||||
</svg>
|
||||
<h1 className="text-2xl font-bold tracking-tight text-primary-900">
|
||||
ClawSuite
|
||||
Hermes Workspace
|
||||
</h1>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -7,8 +7,7 @@ type AvatarProps = {
|
||||
}
|
||||
|
||||
/**
|
||||
* Assistant avatar — matches the ClawSuite favicon/hero logo.
|
||||
* Orange gradient rounded square with dark claw brackets < | >
|
||||
* Assistant avatar — Hermes Agent caduceus on Nous blue.
|
||||
*/
|
||||
function AssistantAvatarComponent({ size = 28, className }: AvatarProps) {
|
||||
return (
|
||||
@@ -20,41 +19,19 @@ function AssistantAvatarComponent({ size = 28, className }: AvatarProps) {
|
||||
style={{ width: size, height: size }}
|
||||
>
|
||||
<defs>
|
||||
<linearGradient id="ava-orange" x1="0%" y1="0%" x2="100%" y2="100%">
|
||||
<stop offset="0%" stopColor="#ea580c" />
|
||||
<stop offset="50%" stopColor="#f97316" />
|
||||
<stop offset="100%" stopColor="#fb923c" />
|
||||
<linearGradient id="ava-hermes" x1="0%" y1="0%" x2="100%" y2="100%">
|
||||
<stop offset="0%" stopColor="#1E30AA" />
|
||||
<stop offset="50%" stopColor="#3050FF" />
|
||||
<stop offset="100%" stopColor="#5070FF" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
{/* Orange background */}
|
||||
<rect
|
||||
x="5"
|
||||
y="5"
|
||||
width="90"
|
||||
height="90"
|
||||
rx="20"
|
||||
fill="url(#ava-orange)"
|
||||
/>
|
||||
{/* Left claw bracket */}
|
||||
<path
|
||||
d="M 40 35 L 30 50 L 40 65"
|
||||
stroke="#1e293b"
|
||||
strokeWidth="5"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
fill="none"
|
||||
/>
|
||||
{/* Right claw bracket */}
|
||||
<path
|
||||
d="M 60 35 L 70 50 L 60 65"
|
||||
stroke="#1e293b"
|
||||
strokeWidth="5"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
fill="none"
|
||||
/>
|
||||
{/* Center cursor bar */}
|
||||
<rect x="47" y="40" width="6" height="20" rx="3" fill="#1e293b" />
|
||||
<rect x="5" y="5" width="90" height="90" rx="20" fill="url(#ava-hermes)" />
|
||||
<rect x="47" y="22" width="6" height="56" rx="3" fill="#FFD700" />
|
||||
<path d="M 35 30 Q 50 22, 50 30" stroke="#FFD700" strokeWidth="3" fill="none" strokeLinecap="round" />
|
||||
<path d="M 65 30 Q 50 22, 50 30" stroke="#FFD700" strokeWidth="3" fill="none" strokeLinecap="round" />
|
||||
<path d="M 38 58 Q 30 50, 38 42 Q 46 34, 50 38" stroke="#E8ECFF" strokeWidth="3.5" fill="none" strokeLinecap="round" />
|
||||
<path d="M 62 58 Q 70 50, 62 42 Q 54 34, 50 38" stroke="#E8ECFF" strokeWidth="3.5" fill="none" strokeLinecap="round" />
|
||||
<circle cx="50" cy="22" r="5" fill="#FFD700" />
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -72,8 +72,8 @@ export function GatewayConnectionSetupForm({
|
||||
>
|
||||
<div className={cn('flex gap-3', isBanner ? 'items-start' : 'items-start sm:items-center')}>
|
||||
<img
|
||||
src="/logo-icon.png"
|
||||
alt="ClawSuite logo"
|
||||
src="/hermes-icon.png"
|
||||
alt="Hermes Workspace logo"
|
||||
width={isBanner ? 24 : 32}
|
||||
height={isBanner ? 24 : 32}
|
||||
className={cn(
|
||||
|
||||
@@ -44,7 +44,7 @@ const CLOUD_PLAN_OPTIONS: Array<{
|
||||
plan: 'free',
|
||||
name: 'Free',
|
||||
price: '$0/mo',
|
||||
description: 'Try ClawSuite Cloud with free AI models',
|
||||
description: 'Try Hermes Workspace Cloud with free AI models',
|
||||
cta: 'Start Free',
|
||||
},
|
||||
{
|
||||
@@ -283,7 +283,7 @@ function GatewayStepContent() {
|
||||
const normalizedEmail = waitlistEmail.trim()
|
||||
if (!normalizedEmail) {
|
||||
setCloudProvisionStatus('error')
|
||||
setCloudProvisionError('Enter your email to provision a ClawSuite Cloud gateway.')
|
||||
setCloudProvisionError('Enter your email to provision a Hermes Workspace Cloud gateway.')
|
||||
return
|
||||
}
|
||||
|
||||
@@ -309,7 +309,7 @@ function GatewayStepContent() {
|
||||
const errorMessage =
|
||||
data && 'error' in data && typeof data.error === 'string'
|
||||
? data.error
|
||||
: 'Failed to provision your free ClawSuite Cloud gateway.'
|
||||
: 'Failed to provision your free Hermes Workspace Cloud gateway.'
|
||||
setCloudProvisionStatus('error')
|
||||
setCloudProvisionError(errorMessage)
|
||||
return
|
||||
@@ -329,7 +329,7 @@ function GatewayStepContent() {
|
||||
setCloudProvisionStatus('success')
|
||||
} catch {
|
||||
setCloudProvisionStatus('error')
|
||||
setCloudProvisionError('Failed to provision your free ClawSuite Cloud gateway.')
|
||||
setCloudProvisionError('Failed to provision your free Hermes Workspace Cloud gateway.')
|
||||
}
|
||||
}
|
||||
|
||||
@@ -392,15 +392,15 @@ function GatewayStepContent() {
|
||||
<div className="mb-6 flex flex-col items-center text-center">
|
||||
<div className="mb-4 flex size-20 items-center justify-center rounded-2xl shadow-lg">
|
||||
<img
|
||||
src="/logo-icon.png"
|
||||
alt="ClawSuite logo"
|
||||
src="/hermes-icon.png"
|
||||
alt="Hermes Workspace logo"
|
||||
width={64}
|
||||
height={64}
|
||||
className="size-16"
|
||||
/>
|
||||
</div>
|
||||
<h2 className="mb-2 text-2xl font-semibold text-primary-900">
|
||||
Welcome to ClawSuite
|
||||
Welcome to Hermes Workspace
|
||||
</h2>
|
||||
<p className="max-w-md text-sm leading-relaxed text-primary-600">
|
||||
Your AI command center
|
||||
@@ -425,7 +425,7 @@ function GatewayStepContent() {
|
||||
/>
|
||||
<SetupModeCard
|
||||
icon={CloudIcon}
|
||||
title="ClawSuite Cloud"
|
||||
title="Hermes Workspace Cloud"
|
||||
description="No setup needed. Managed hosting with one click. (Coming soon)"
|
||||
selected={setupMode === 'cloud'}
|
||||
onClick={() => handleSetupModeChange('cloud')}
|
||||
@@ -438,7 +438,7 @@ function GatewayStepContent() {
|
||||
<div className="mb-4 flex flex-col gap-3 sm:flex-row sm:items-start sm:justify-between">
|
||||
<div>
|
||||
<h3 className="text-base font-semibold text-primary-900">
|
||||
ClawSuite Cloud Plans
|
||||
Hermes Workspace Cloud Plans
|
||||
</h3>
|
||||
<p className="mt-1 text-sm text-primary-600">
|
||||
Use this email as your Cloud login, then start free or continue to
|
||||
@@ -582,7 +582,7 @@ function GatewayStepContent() {
|
||||
<div className="mb-4">
|
||||
<h3 className="text-base font-semibold text-primary-900">Setting up local gateway</h3>
|
||||
<p className="mt-1 text-sm text-primary-600">
|
||||
ClawSuite is installing and starting OpenClaw in the background.
|
||||
Hermes Workspace is installing and starting OpenClaw in the background.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -113,7 +113,7 @@ export function MobilePromptTrigger() {
|
||||
<div className="min-w-0 flex-1 text-center">
|
||||
<p className="text-sm font-semibold text-white">Set up mobile access</p>
|
||||
<p className="text-xs text-primary-300">
|
||||
Connect your phone to this ClawSuite instance in a few steps.
|
||||
Connect your phone to this Hermes Workspace instance in a few steps.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -79,7 +79,7 @@ export function MobileSetupModal({ isOpen, onClose }: MobileSetupModalProps) {
|
||||
const steps = [
|
||||
{
|
||||
title: 'Install Tailscale on your desktop',
|
||||
body: 'Install Tailscale on the machine running ClawSuite, then sign in.',
|
||||
body: 'Install Tailscale on the machine running Hermes Workspace, then sign in.',
|
||||
showTailscaleIcon: true,
|
||||
action: (
|
||||
<a
|
||||
@@ -148,7 +148,7 @@ export function MobileSetupModal({ isOpen, onClose }: MobileSetupModalProps) {
|
||||
),
|
||||
},
|
||||
{
|
||||
title: 'Open ClawSuite on your phone',
|
||||
title: 'Open Hermes Workspace on your phone',
|
||||
body: networkUrl?.source === 'tailscale'
|
||||
? 'Your Tailscale address — open this on your phone browser.'
|
||||
: networkUrl?.source === 'lan'
|
||||
|
||||
@@ -23,7 +23,7 @@ export type OnboardingStep = {
|
||||
export const ONBOARDING_STEPS: OnboardingStep[] = [
|
||||
{
|
||||
id: 'welcome',
|
||||
title: 'Welcome to ClawSuite',
|
||||
title: 'Welcome to Hermes Workspace',
|
||||
description:
|
||||
"Your intelligent workspace for AI-powered automation. Let's take a quick tour of what you can do.",
|
||||
icon: Home01Icon,
|
||||
|
||||
@@ -6,7 +6,7 @@ export const tourSteps: Step[] = [
|
||||
{
|
||||
target: 'body',
|
||||
placement: 'center',
|
||||
title: 'Welcome to ClawSuite! 👋',
|
||||
title: 'Welcome to Hermes Workspace! 👋',
|
||||
content: (
|
||||
<div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: '12px' }}>
|
||||
<OpenClawStudioIcon className="size-12 rounded-xl shadow-sm" />
|
||||
@@ -63,7 +63,7 @@ export const tourSteps: Step[] = [
|
||||
placement: 'right',
|
||||
title: 'Built-in Terminal',
|
||||
content:
|
||||
'Built-in terminal for quick commands. Execute shell commands without leaving ClawSuite.',
|
||||
'Built-in terminal for quick commands. Execute shell commands without leaving Hermes Workspace.',
|
||||
},
|
||||
// Step 9: Usage Meter (in header)
|
||||
{
|
||||
@@ -79,7 +79,7 @@ export const tourSteps: Step[] = [
|
||||
placement: 'right',
|
||||
title: 'Settings & Customization',
|
||||
content:
|
||||
'Configure providers, themes, accent colors, and more. Make ClawSuite yours.',
|
||||
'Configure providers, themes, accent colors, and more. Make Hermes Workspace yours.',
|
||||
},
|
||||
// Step 11: Finish
|
||||
{
|
||||
@@ -87,6 +87,6 @@ export const tourSteps: Step[] = [
|
||||
placement: 'center',
|
||||
title: "You're all set! 🎉",
|
||||
content:
|
||||
'Start chatting with your AI, explore the tools, and customize ClawSuite to fit your workflow. Need help? Press ? to see all keyboard shortcuts.',
|
||||
'Start chatting with your AI, explore the tools, and customize Hermes Workspace to fit your workflow. Need help? Press ? to see all keyboard shortcuts.',
|
||||
},
|
||||
]
|
||||
|
||||
@@ -63,7 +63,7 @@ const DARK_ENTERPRISE_THEMES = new Set<ThemeId>([
|
||||
'ops-dark',
|
||||
'premium-dark',
|
||||
'sunset-brand',
|
||||
])
|
||||
'hermes',])
|
||||
|
||||
function isDarkEnterpriseTheme(theme: string | null): theme is ThemeId {
|
||||
if (!theme) return false
|
||||
@@ -427,6 +427,13 @@ const ENTERPRISE_THEMES = [
|
||||
desc: 'Warm brown brand immersion',
|
||||
preview: { bg: '#1a0e05', panel: '#2a1a0e', border: '#6b3c1b', accent: '#f59e0b', text: '#ffe7d1' },
|
||||
},
|
||||
{
|
||||
id: 'hermes',
|
||||
label: 'Hermes',
|
||||
icon: '⚕',
|
||||
desc: 'Nous Research deep blue',
|
||||
preview: { bg: '#0A0E1A', panel: '#1A2240', border: 'rgba(48,80,255,0.18)', accent: '#3050FF', text: '#E8ECFF' },
|
||||
},
|
||||
] as const
|
||||
|
||||
function ThemeSwatch({ colors }: { colors: typeof ENTERPRISE_THEMES[number]['preview'] }) {
|
||||
@@ -839,7 +846,7 @@ export function SettingsDialog({ open, onOpenChange }: SettingsDialogProps) {
|
||||
Settings
|
||||
</DialogTitle>
|
||||
<DialogDescription className="sr-only">
|
||||
Configure ClawSuite
|
||||
Configure Hermes Workspace
|
||||
</DialogDescription>
|
||||
</div>
|
||||
<DialogClose
|
||||
|
||||
@@ -260,7 +260,7 @@ export function UpdateNotifier() {
|
||||
<div className="flex-1 min-w-0">
|
||||
<p className="text-sm font-semibold">
|
||||
{phase === 'idle' || phase === 'error'
|
||||
? 'ClawSuite Update'
|
||||
? 'Hermes Workspace Update'
|
||||
: PHASE_LABELS[phase]}
|
||||
</p>
|
||||
<p className="text-xs text-primary-400 truncate">
|
||||
|
||||
@@ -114,7 +114,7 @@ export function WorkspaceShell() {
|
||||
}
|
||||
throw error instanceof Error
|
||||
? error
|
||||
: new Error('Failed to connect to ClawSuite server')
|
||||
: new Error('Failed to connect to Hermes Workspace server')
|
||||
} finally {
|
||||
globalThis.clearTimeout(timeout)
|
||||
}
|
||||
@@ -247,7 +247,7 @@ export function WorkspaceShell() {
|
||||
<div className="flex items-center justify-center h-screen bg-surface">
|
||||
<div className="text-center">
|
||||
<div className="inline-block h-10 w-10 animate-spin rounded-full border-4 border-accent-500 border-r-transparent mb-4" />
|
||||
<p className="text-sm text-primary-500">Initializing ClawSuite...</p>
|
||||
<p className="text-sm text-primary-500">Initializing Hermes Workspace...</p>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
@@ -257,7 +257,7 @@ export function WorkspaceShell() {
|
||||
const errorMessage =
|
||||
authQuery.error instanceof Error
|
||||
? authQuery.error.message
|
||||
: 'Failed to connect to ClawSuite server'
|
||||
: 'Failed to connect to Hermes Workspace server'
|
||||
const showGatewayTip = /gateway|websocket/i.test(errorMessage)
|
||||
|
||||
return (
|
||||
@@ -269,7 +269,7 @@ export function WorkspaceShell() {
|
||||
</span>
|
||||
</div>
|
||||
<h1 className="text-2xl font-semibold text-primary-100">
|
||||
Could not connect to ClawSuite server
|
||||
Could not connect to Hermes Workspace server
|
||||
</h1>
|
||||
<p className="mt-3 text-sm text-primary-300">
|
||||
The server may still be starting up. Wait a moment and try again.
|
||||
@@ -335,7 +335,7 @@ export function WorkspaceShell() {
|
||||
<div className="w-[78px] shrink-0" />
|
||||
{/* Centered title */}
|
||||
<div className="flex-1 text-center">
|
||||
<span className="text-[13px] font-medium text-primary-600 dark:text-primary-400 select-none">ClawSuite</span>
|
||||
<span className="text-[13px] font-medium select-none" style={{ color: "var(--theme-accent, #3050FF)" }}>⚕ Hermes Workspace</span>
|
||||
</div>
|
||||
{/* Right spacer to balance */}
|
||||
<div className="w-[78px] shrink-0" />
|
||||
|
||||
@@ -56,7 +56,7 @@ export async function pingGateway(): Promise<{ ok: boolean; error?: string }> {
|
||||
const data = (await response.json()) as { ok?: boolean; error?: string }
|
||||
return { ok: Boolean(data.ok), error: data.error }
|
||||
} catch {
|
||||
return { ok: false, error: 'Could not reach ClawSuite server' }
|
||||
return { ok: false, error: 'Could not reach Hermes Workspace server' }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -354,7 +354,7 @@ export const useGatewaySetupStore = create<GatewaySetupState>((set, get) => ({
|
||||
|
||||
set({
|
||||
testStatus: 'error',
|
||||
testError: error || 'Gateway not reachable after saving config. You may need to restart ClawSuite.',
|
||||
testError: error || 'Gateway not reachable after saving config. You may need to restart Hermes Workspace.',
|
||||
})
|
||||
return false
|
||||
},
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { useEffect } from 'react'
|
||||
|
||||
const BASE_TITLE = 'ClawSuite'
|
||||
const BASE_TITLE = 'Hermes Workspace'
|
||||
|
||||
/**
|
||||
* Sets document.title for the current page.
|
||||
* Usage: usePageTitle('Dashboard') → "Dashboard — ClawSuite"
|
||||
* Usage: usePageTitle('Dashboard') → "Dashboard — Hermes Workspace"
|
||||
*/
|
||||
export function usePageTitle(page: string) {
|
||||
useEffect(() => {
|
||||
|
||||
@@ -33,7 +33,7 @@ export const defaultStudioSettings: StudioSettings = {
|
||||
gatewayUrl: '',
|
||||
gatewayToken: '',
|
||||
theme: 'system',
|
||||
accentColor: 'orange',
|
||||
accentColor: 'blue',
|
||||
editorFontSize: 13,
|
||||
editorWordWrap: true,
|
||||
editorMinimap: false,
|
||||
@@ -121,8 +121,8 @@ export function applyTheme(theme: SettingsThemeMode) {
|
||||
if (resolvedDark) {
|
||||
// Preserve user's enterprise dark theme if set, otherwise default to ops-dark
|
||||
const stored = localStorage.getItem('clawsuite-theme')
|
||||
const darkThemes = ['ops-dark', 'premium-dark', 'sunset-brand']
|
||||
root.setAttribute('data-theme', darkThemes.includes(stored ?? '') ? (stored as string) : 'ops-dark')
|
||||
const darkThemes = ['ops-dark', 'premium-dark', 'sunset-brand', 'hermes']
|
||||
root.setAttribute('data-theme', darkThemes.includes(stored ?? '') ? (stored as string) : 'hermes')
|
||||
} else {
|
||||
root.setAttribute('data-theme', 'paper-light')
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* React hook for sound notifications in ClawSuite
|
||||
* React hook for sound notifications in Hermes Workspace
|
||||
* Integrates with the agent swarm store to auto-play sounds on state changes
|
||||
*/
|
||||
import { useCallback, useEffect, useMemo, useRef } from 'react'
|
||||
|
||||
@@ -66,7 +66,7 @@ export function getConnectionErrorMessage(
|
||||
switch (kind) {
|
||||
case 'clawsuite_auth_required':
|
||||
return {
|
||||
title: 'ClawSuite Login Required',
|
||||
title: 'Hermes Workspace Login Required',
|
||||
description: 'This instance requires a password to access.',
|
||||
action: 'Enter your password to continue',
|
||||
}
|
||||
@@ -87,7 +87,7 @@ export function getConnectionErrorMessage(
|
||||
case 'gateway_unreachable':
|
||||
return {
|
||||
title: 'Gateway unreachable',
|
||||
description: 'ClawSuite cannot reach the configured OpenClaw gateway.',
|
||||
description: 'Hermes Workspace cannot reach the configured OpenClaw gateway.',
|
||||
action: 'Check that OpenClaw is running and the gateway URL is correct.',
|
||||
}
|
||||
case 'handshake_failed':
|
||||
|
||||
@@ -14,8 +14,8 @@ const PLATFORM_NAMES: Record<string, string> = {
|
||||
whatsapp: 'WhatsApp',
|
||||
signal: 'Signal',
|
||||
imessage: 'iMessage',
|
||||
webchat: 'ClawSuite',
|
||||
'openclaw-control-ui': 'ClawSuite',
|
||||
webchat: 'Hermes Workspace',
|
||||
'openclaw-control-ui': 'Hermes Workspace',
|
||||
slack: 'Slack',
|
||||
irc: 'IRC',
|
||||
googlechat: 'Google Chat',
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Sound Notification System for ClawSuite
|
||||
* Sound Notification System for Hermes Workspace
|
||||
* Uses Web Audio API to synthesize unique sounds without audio files.
|
||||
*/
|
||||
|
||||
|
||||
@@ -3,13 +3,15 @@ export type ThemeId =
|
||||
| 'ops-dark'
|
||||
| 'premium-dark'
|
||||
| 'sunset-brand'
|
||||
| 'hermes'
|
||||
|
||||
const DARK_THEMES: ThemeId[] = ['ops-dark', 'premium-dark', 'sunset-brand']
|
||||
const DARK_THEMES: ThemeId[] = ['ops-dark', 'premium-dark', 'sunset-brand', 'hermes']
|
||||
const THEME_SET = new Set<ThemeId>([
|
||||
'paper-light',
|
||||
'ops-dark',
|
||||
'premium-dark',
|
||||
'sunset-brand',
|
||||
'hermes',
|
||||
])
|
||||
|
||||
export const THEMES: Array<{
|
||||
@@ -18,48 +20,25 @@ export const THEMES: Array<{
|
||||
description: string
|
||||
icon: string
|
||||
}> = [
|
||||
{
|
||||
id: 'paper-light',
|
||||
label: 'Paper Light',
|
||||
description: 'Clean warm gray with soft shadows',
|
||||
icon: '☀️',
|
||||
},
|
||||
{
|
||||
id: 'ops-dark',
|
||||
label: 'Ops Dark',
|
||||
description: 'Slate dark with teal secondary accents',
|
||||
icon: '🖥️',
|
||||
},
|
||||
{
|
||||
id: 'premium-dark',
|
||||
label: 'Premium Dark',
|
||||
description: 'OLED black with high contrast',
|
||||
icon: '✨',
|
||||
},
|
||||
{
|
||||
id: 'sunset-brand',
|
||||
label: 'Sunset Brand',
|
||||
description: 'Warm brown immersion with amber accents',
|
||||
icon: '🌇',
|
||||
},
|
||||
{ id: 'paper-light', label: 'Paper Light', description: 'Clean warm gray with soft shadows', icon: '☀️' },
|
||||
{ id: 'ops-dark', label: 'Ops Dark', description: 'Slate dark with teal secondary accents', icon: '🖥️' },
|
||||
{ id: 'premium-dark', label: 'Premium Dark', description: 'OLED black with high contrast', icon: '✨' },
|
||||
{ id: 'sunset-brand', label: 'Sunset Brand', description: 'Warm brown immersion with amber accents', icon: '🌇' },
|
||||
{ id: 'hermes', label: 'Hermes', description: 'Nous Research deep blue palette', icon: '⚕' },
|
||||
]
|
||||
|
||||
const STORAGE_KEY = 'clawsuite-theme'
|
||||
|
||||
export function getStoredTheme(): ThemeId {
|
||||
if (typeof window === 'undefined') return 'paper-light'
|
||||
if (typeof window === 'undefined') return 'hermes'
|
||||
const stored = localStorage.getItem(STORAGE_KEY)
|
||||
if (stored && THEME_SET.has(stored as ThemeId)) {
|
||||
return stored as ThemeId
|
||||
}
|
||||
return 'paper-light'
|
||||
if (stored && THEME_SET.has(stored as ThemeId)) return stored as ThemeId
|
||||
return 'hermes'
|
||||
}
|
||||
|
||||
export function applyTheme(theme: ThemeId): void {
|
||||
const html = document.documentElement
|
||||
html.setAttribute('data-theme', theme)
|
||||
|
||||
// Also toggle dark class for Tailwind dark: variant
|
||||
if (DARK_THEMES.includes(theme)) {
|
||||
html.classList.add('dark')
|
||||
html.classList.remove('light')
|
||||
@@ -67,7 +46,6 @@ export function applyTheme(theme: ThemeId): void {
|
||||
html.classList.add('light')
|
||||
html.classList.remove('dark')
|
||||
}
|
||||
|
||||
localStorage.setItem(STORAGE_KEY, theme)
|
||||
}
|
||||
|
||||
|
||||
@@ -39,8 +39,8 @@ const themeScript = `
|
||||
(() => {
|
||||
window.process = window.process || { env: {}, platform: 'browser' };
|
||||
|
||||
// Gateway connection via ClawSuite server proxy.
|
||||
// Clients connect to /ws-gateway on the ClawSuite server (same host:port as the page).
|
||||
// Gateway connection via Hermes Workspace server proxy.
|
||||
// Clients connect to /ws-gateway on the Hermes Workspace server (same host:port as the page).
|
||||
// The server proxies internally to ws://127.0.0.1:18789 — so phone/LAN/Docker
|
||||
// users never need direct access to port 18789.
|
||||
// Manual override: set gatewayUrl in settings to skip proxy (e.g. wss:// remote).
|
||||
@@ -52,7 +52,7 @@ const themeScript = `
|
||||
if (manualUrl && typeof manualUrl === 'string' && manualUrl.startsWith('ws')) {
|
||||
window.__GATEWAY_URL__ = manualUrl
|
||||
} else {
|
||||
// Use proxy path — works from any device that can reach ClawSuite
|
||||
// Use proxy path — works from any device that can reach Hermes Workspace
|
||||
const proto = window.location.protocol === 'https:' ? 'wss:' : 'ws:'
|
||||
window.__GATEWAY_URL__ = proto + '//' + window.location.host + '/ws-gateway'
|
||||
}
|
||||
@@ -89,7 +89,7 @@ const themeScript = `
|
||||
}
|
||||
const root = document.documentElement
|
||||
const media = window.matchMedia('(prefers-color-scheme: dark)')
|
||||
// ClawSuite theme class + data-theme attribute
|
||||
// Hermes Workspace theme class + data-theme attribute
|
||||
const enterpriseTheme = localStorage.getItem('clawsuite-theme')
|
||||
const isValidEnterpriseTheme =
|
||||
enterpriseTheme === 'ops-dark' ||
|
||||
@@ -169,7 +169,7 @@ export const Route = createRootRoute({
|
||||
'width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, viewport-fit=cover, interactive-widget=resizes-visual',
|
||||
},
|
||||
{
|
||||
title: 'ClawSuite',
|
||||
title: 'Hermes Workspace',
|
||||
},
|
||||
{
|
||||
name: 'description',
|
||||
@@ -340,7 +340,7 @@ function RootDocument({ children }: { children: React.ReactNode }) {
|
||||
d.id = 'splash-screen';
|
||||
d.style.cssText = 'position:fixed;inset:0;z-index:99999;display:flex;flex-direction:column;align-items:center;justify-content:center;background:'+bg+';transition:opacity 0.8s ease;';
|
||||
d.innerHTML = '<div style="width:96px;height:96px;margin-bottom:20px;filter:drop-shadow(0 8px 32px rgba(249,115,22,0.5))"><svg width="96" height="96" viewBox="0 0 100 100" fill="none" xmlns="http://www.w3.org/2000/svg"><defs><linearGradient id="sOB" x1="0%" y1="0%" x2="100%" y2="100%"><stop offset="0%" stop-color="#ea580c"/><stop offset="50%" stop-color="#f97316"/><stop offset="100%" stop-color="#fb923c"/></linearGradient></defs><rect x="5" y="5" width="90" height="90" rx="16" fill="url(#sOB)"/><rect x="20" y="25" width="60" height="50" rx="4" stroke="#1e293b" stroke-width="3" fill="none"/><circle cx="28" cy="32" r="2.5" fill="#1e293b"/><circle cx="37" cy="32" r="2.5" fill="#1e293b"/><circle cx="46" cy="32" r="2.5" fill="#1e293b"/><path d="M38 45L32 50L38 55" stroke="#1e293b" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" fill="none"/><path d="M62 45L68 50L62 55" stroke="#1e293b" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" fill="none"/><rect x="47" y="46" width="4" height="10" rx="2" fill="#1e293b"><animate attributeName="opacity" values="1;0.3;1" dur="1.2s" repeatCount="indefinite"/></rect></svg></div>'
|
||||
+ '<div style="font:700 24px/1 system-ui,-apple-system,sans-serif;letter-spacing:0.06em;color:'+txt+'">ClawSuite</div>'
|
||||
+ '<div style="font:700 24px/1 system-ui,-apple-system,sans-serif;letter-spacing:0.06em;color:'+txt+'">Hermes Workspace</div>'
|
||||
+ '<div style="margin-top:10px;font:italic 13px/1 system-ui,-apple-system,sans-serif;color:'+muted+'">'+quip+'</div>'
|
||||
+ '<div style="margin-top:28px;width:140px;height:3px;background:#1e293b;border-radius:3px;overflow:hidden"><div id=splash-bar style="width:0%;height:100%;background:linear-gradient(90deg,#ea580c,#f97316,#fb923c);border-radius:3px;transition:width 0.4s ease"></div></div>';
|
||||
document.body.prepend(d);
|
||||
|
||||
@@ -23,7 +23,7 @@ export const Route = createFileRoute('/api/gateway/approvals/$approvalId/$action
|
||||
)
|
||||
}
|
||||
|
||||
// Map ClawSuite action names to gateway ExecApprovalDecision values.
|
||||
// Map Hermes Workspace action names to gateway ExecApprovalDecision values.
|
||||
const decision = action === 'approve' ? 'allow-once' : 'deny'
|
||||
|
||||
try {
|
||||
|
||||
@@ -11,7 +11,7 @@ function ConnectRoute() {
|
||||
<div className="max-w-2xl mx-auto px-6 py-10 space-y-10">
|
||||
<div className="space-y-3">
|
||||
<h1 className="text-3xl font-medium tracking-[-0.02em] text-center mb-10">
|
||||
Connect to ClawSuite
|
||||
Connect to Hermes Workspace
|
||||
</h1>
|
||||
<p className="text-primary-700">
|
||||
This client needs access to your OpenClaw gateway before you can
|
||||
|
||||
@@ -1615,7 +1615,7 @@ function ChatComposerComponent({
|
||||
isDraggingOver &&
|
||||
'outline-primary-500 ring-2 ring-primary-300 bg-primary-50/80',
|
||||
isLoading &&
|
||||
'ring-2 ring-accent-400/70 shadow-[0_0_20px_rgba(249,115,22,0.35)] animate-pulse-glow',
|
||||
'ring-2 ring-accent-400/70 shadow-[0_0_20px_rgba(48,80,255,0.35)] animate-pulse-glow',
|
||||
)}
|
||||
onPaste={handlePaste}
|
||||
onDragEnter={handleDragEnter}
|
||||
|
||||
@@ -47,7 +47,6 @@ import {
|
||||
} from '@/components/ui/tooltip'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { Button, buttonVariants } from '@/components/ui/button'
|
||||
import { OpenClawStudioIcon } from '@/components/icons/clawsuite'
|
||||
import { UserAvatar } from '@/components/avatars'
|
||||
import { SEARCH_MODAL_EVENTS, useSearchModal } from '@/hooks/use-search-modal'
|
||||
import {
|
||||
@@ -1099,8 +1098,8 @@ function ChatSidebarComponent({
|
||||
'w-full pl-1.5 justify-start',
|
||||
)}
|
||||
>
|
||||
<OpenClawStudioIcon className="size-5 rounded-lg overflow-hidden" />
|
||||
ClawSuite
|
||||
<img src="/hermes-icon.png" alt="Hermes" className="size-5 rounded-lg" />
|
||||
Hermes Workspace
|
||||
</Link>
|
||||
</motion.div>
|
||||
) : null}
|
||||
|
||||
@@ -25,7 +25,7 @@ function classifyConnectionError(
|
||||
if (!normalizedError && !status) {
|
||||
return {
|
||||
title: 'Not connected',
|
||||
description: "ClawSuite can't reach the gateway.",
|
||||
description: "Hermes Workspace can't reach the gateway.",
|
||||
action: 'Check that OpenClaw is running, then try again.',
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@ export function useChatSessions({
|
||||
if (activeSession.titleStatus === 'error') return 'New Session'
|
||||
return 'New Session'
|
||||
}
|
||||
return activeFriendlyId === 'main' ? 'ClawSuite' : activeFriendlyId
|
||||
return activeFriendlyId === 'main' ? 'Hermes Workspace' : activeFriendlyId
|
||||
}, [activeFriendlyId, activeSession])
|
||||
|
||||
const sessionsError =
|
||||
|
||||
@@ -45,7 +45,6 @@ import { useVisibleWidgets } from './hooks/use-visible-widgets'
|
||||
import { useDashboardData, buildUsageSummaryText } from './hooks/use-dashboard-data'
|
||||
import { formatMoney, formatRelativeTime } from './lib/formatters'
|
||||
import { ErrorBoundary } from '@/components/error-boundary'
|
||||
import { OpenClawStudioIcon } from '@/components/icons/clawsuite'
|
||||
import { ThemeToggle } from '@/components/theme-toggle'
|
||||
import { SettingsDialog } from '@/components/settings-dialog'
|
||||
import { DashboardOverflowPanel } from '@/components/dashboard-overflow-panel'
|
||||
@@ -643,7 +642,7 @@ export function DashboardScreen() {
|
||||
className="shrink-0 cursor-pointer rounded-xl transition-transform active:scale-95"
|
||||
aria-label="Open quick menu"
|
||||
>
|
||||
<OpenClawStudioIcon className="size-8 rounded-xl overflow-hidden shadow-sm" />
|
||||
<img src="/hermes-icon.png" alt="Hermes" className="size-8 rounded-xl shadow-sm" />
|
||||
{shouldShowLogoTip ? (
|
||||
<div className="absolute !left-1/2 top-full z-30 mt-2 -translate-x-1/2 animate-in fade-in-0 slide-in-from-top-1 duration-300">
|
||||
<div className="relative rounded bg-primary-900 px-2 py-1 text-xs font-medium text-white shadow-md">
|
||||
@@ -663,11 +662,11 @@ export function DashboardScreen() {
|
||||
) : null}
|
||||
</button>
|
||||
) : (
|
||||
<OpenClawStudioIcon className="size-8 shrink-0 rounded-xl overflow-hidden shadow-sm" />
|
||||
<img src="/hermes-icon.png" alt="Hermes" className="size-8 shrink-0 rounded-xl shadow-sm" />
|
||||
)}
|
||||
<div className="flex min-w-0 items-center gap-2">
|
||||
<h1 className="text-sm font-semibold text-ink text-balance md:text-base truncate">
|
||||
ClawSuite
|
||||
Hermes Workspace
|
||||
</h1>
|
||||
{isMobile ? (
|
||||
<span
|
||||
@@ -699,6 +698,11 @@ export function DashboardScreen() {
|
||||
{dashboardData.connection.connected ? 'Connected' : 'Disconnected'}
|
||||
</span>
|
||||
)}
|
||||
{!isMobile && (
|
||||
<span className="inline-flex items-center gap-1 rounded-full border px-2 py-0.5 text-[10px] font-medium" style={{ borderColor: 'var(--theme-accent-border)', color: 'var(--theme-accent)', background: 'var(--theme-accent-subtle)' }}>
|
||||
⚕ Powered by Hermes Agent
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -125,7 +125,7 @@ export function useServicesHealth(gatewayConnected: boolean) {
|
||||
|
||||
return [
|
||||
{
|
||||
name: 'ClawSuite UI',
|
||||
name: 'Hermes Workspace UI',
|
||||
status: isChecking ? 'checking' : (probe?.clawSuiteUi.status ?? 'down'),
|
||||
latencyMs: probe?.clawSuiteUi.latencyMs,
|
||||
},
|
||||
|
||||
@@ -69,7 +69,7 @@ function generateMarkdown(report: ExportableMissionReport): string {
|
||||
}
|
||||
|
||||
lines.push('---')
|
||||
lines.push(`*Exported from ClawSuite Agent Hub on ${new Date().toLocaleString()}*`)
|
||||
lines.push(`*Exported from Hermes Workspace Agent Hub on ${new Date().toLocaleString()}*`)
|
||||
|
||||
return lines.join('\n')
|
||||
}
|
||||
|
||||
@@ -544,7 +544,7 @@ export function OfficeView({
|
||||
{/* Header bar */}
|
||||
<div className="flex shrink-0 flex-wrap items-start justify-between gap-2 border-b border-neutral-200 bg-white/80 px-5 py-3 backdrop-blur dark:border-slate-700 dark:bg-slate-800/80">
|
||||
<div className="flex min-w-0 flex-1 flex-col gap-1">
|
||||
<span className="text-base font-bold text-neutral-900 dark:text-white">ClawSuite Office</span>
|
||||
<span className="text-base font-bold text-neutral-900 dark:text-white">Hermes Workspace Office</span>
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<span className="rounded-full bg-neutral-100 dark:bg-neutral-800 px-2 py-0.5 text-[10px] font-medium text-neutral-600 dark:text-neutral-400 tabular-nums">{agentRows.length} agents</span>
|
||||
<span className="rounded-full bg-emerald-50 dark:bg-emerald-900/30 px-2 py-0.5 text-[10px] font-medium text-emerald-700 dark:text-emerald-400 tabular-nums">{activeCount} working</span>
|
||||
|
||||
@@ -17,7 +17,7 @@ export type WorkflowTemplate = {
|
||||
|
||||
const STORAGE_KEY = 'clawsuite:workflow-templates'
|
||||
|
||||
// Built-in templates that ship with ClawSuite
|
||||
// Built-in templates that ship with Hermes Workspace
|
||||
export const BUILT_IN_TEMPLATES: WorkflowTemplate[] = [
|
||||
{
|
||||
id: 'tpl-code-review',
|
||||
|
||||
@@ -670,7 +670,7 @@ export function NewProjectWizardContent({
|
||||
<input
|
||||
value={name}
|
||||
onChange={(event) => setName(event.target.value)}
|
||||
placeholder="ClawSuite Workspace Refresh"
|
||||
placeholder="Hermes Workspace Workspace Refresh"
|
||||
autoFocus
|
||||
className="w-full rounded-2xl border border-primary-200 bg-white px-4 py-3 text-sm text-primary-900 outline-none transition-colors focus:border-accent-500"
|
||||
/>
|
||||
|
||||
@@ -270,7 +270,7 @@ export function SkillsScreen() {
|
||||
<div className="flex flex-wrap items-center justify-between gap-3">
|
||||
<div className="space-y-1.5">
|
||||
<p className="text-xs font-medium uppercase text-primary-500 tabular-nums">
|
||||
ClawSuite Marketplace
|
||||
Hermes Workspace Marketplace
|
||||
</p>
|
||||
<h1 className="text-2xl font-medium text-ink text-balance sm:text-3xl">
|
||||
Skills Browser
|
||||
@@ -657,7 +657,7 @@ function SecurityScanCard({ security }: { security: SecurityRisk }) {
|
||||
<div className="space-y-1.5">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-primary-500 font-medium w-16 shrink-0">
|
||||
ClawSuite
|
||||
Hermes Workspace
|
||||
</span>
|
||||
<span
|
||||
className={cn(
|
||||
|
||||
@@ -97,7 +97,7 @@ function getDemoTabs(): Array<BrowserTab> {
|
||||
return [
|
||||
{
|
||||
id: 'demo-tab-1',
|
||||
title: 'ClawSuite',
|
||||
title: 'Hermes Workspace',
|
||||
url: 'https://openclaw.local/studio',
|
||||
isActive: true,
|
||||
},
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Local web proxy that strips iframe-blocking headers (X-Frame-Options, CSP).
|
||||
* Allows any website to be embedded in an iframe inside ClawSuite.
|
||||
* Allows any website to be embedded in an iframe inside Hermes Workspace.
|
||||
* Only runs locally — not exposed to the internet.
|
||||
*/
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ export async function launchBrowser(): Promise<BrowserState> {
|
||||
isLaunching = true
|
||||
try {
|
||||
const pw = await getPlaywright()
|
||||
// Headless browser — rendered inside ClawSuite via CDP screencast
|
||||
// Headless browser — rendered inside Hermes Workspace via CDP screencast
|
||||
browserInstance = await pw.chromium.launch({
|
||||
headless: true,
|
||||
args: [
|
||||
|
||||
@@ -16,7 +16,7 @@ type ProviderConfig = {
|
||||
apiKey?: string
|
||||
}
|
||||
|
||||
type ClawSuiteConfig = {
|
||||
type HermesWorkspaceConfig = {
|
||||
models?: {
|
||||
providers?: {
|
||||
anthropic?: ProviderConfig
|
||||
@@ -109,7 +109,7 @@ function buildPrompt(terminalOutput: string, logContent: string): string {
|
||||
}
|
||||
|
||||
function readProviderApiKey(
|
||||
config: ClawSuiteConfig,
|
||||
config: HermesWorkspaceConfig,
|
||||
provider: 'anthropic' | 'openai',
|
||||
): string {
|
||||
const providerConfig = config.models?.providers?.[provider]
|
||||
@@ -129,12 +129,12 @@ function readProviderApiKey(
|
||||
return ''
|
||||
}
|
||||
|
||||
async function readClawSuiteConfig(): Promise<ClawSuiteConfig | null> {
|
||||
async function readHermesWorkspaceConfig(): Promise<HermesWorkspaceConfig | null> {
|
||||
const configPath = path.join(os.homedir(), '.openclaw', 'openclaw.json')
|
||||
|
||||
try {
|
||||
const raw = await fs.readFile(configPath, 'utf8')
|
||||
return JSON.parse(raw) as ClawSuiteConfig
|
||||
return JSON.parse(raw) as HermesWorkspaceConfig
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
@@ -167,7 +167,7 @@ async function resolveProvider(): Promise<ResolvedProvider | null> {
|
||||
return { provider: 'openai', apiKey: openaiEnv }
|
||||
}
|
||||
|
||||
const config = await readClawSuiteConfig()
|
||||
const config = await readHermesWorkspaceConfig()
|
||||
if (!config) return null
|
||||
|
||||
const anthropicApiKey = readProviderApiKey(config, 'anthropic')
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* 2. Falling back to `openclaw config get` CLI commands
|
||||
* 3. Probing default port 18789
|
||||
*
|
||||
* This lets ClawSuite connect seamlessly without manual config.
|
||||
* This lets Hermes Workspace connect seamlessly without manual config.
|
||||
*/
|
||||
|
||||
import { readFile } from 'node:fs/promises'
|
||||
|
||||
@@ -270,7 +270,7 @@ export async function fetchClaudeUsage(): Promise<ProviderUsageResult> {
|
||||
Accept: 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
'anthropic-beta': 'oauth-2025-04-20',
|
||||
'User-Agent': 'ClawSuite',
|
||||
'User-Agent': 'Hermes Workspace',
|
||||
},
|
||||
})
|
||||
} catch (e) {
|
||||
@@ -295,7 +295,7 @@ export async function fetchClaudeUsage(): Promise<ProviderUsageResult> {
|
||||
Accept: 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
'anthropic-beta': 'oauth-2025-04-20',
|
||||
'User-Agent': 'ClawSuite',
|
||||
'User-Agent': 'Hermes Workspace',
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -568,7 +568,7 @@ export async function fetchCodexUsage(): Promise<ProviderUsageResult> {
|
||||
const headers: Record<string, string> = {
|
||||
Authorization: `Bearer ${accessToken}`,
|
||||
Accept: 'application/json',
|
||||
'User-Agent': 'ClawSuite',
|
||||
'User-Agent': 'Hermes Workspace',
|
||||
}
|
||||
if (auth.tokens.account_id) {
|
||||
headers['ChatGPT-Account-Id'] = auth.tokens.account_id
|
||||
|
||||
@@ -458,7 +458,7 @@ export const useGatewayChatStore = create<GatewayChatState>((set, get) => ({
|
||||
|
||||
// Content-text dedup: identical assistant text within the same
|
||||
// session should never appear twice, even if message IDs differ
|
||||
// (e.g. same reply routed from Telegram + ClawSuite).
|
||||
// (e.g. same reply routed from Telegram + Hermes Workspace).
|
||||
if (
|
||||
normalizedMessage.role === 'assistant' &&
|
||||
newPlainText.length > 20 &&
|
||||
|
||||
@@ -383,54 +383,54 @@
|
||||
color: var(--theme-text);
|
||||
}
|
||||
|
||||
:is([data-theme="paper-light"], [data-theme="ops-dark"], [data-theme="premium-dark"], [data-theme="sunset-brand"])
|
||||
:is([data-theme="paper-light"], [data-theme="ops-dark"], [data-theme="premium-dark"], [data-theme="sunset-brand"], [data-theme="hermes"])
|
||||
:is(.border-primary-200, .border-neutral-200, .border-neutral-700, .border-neutral-800, .border-slate-700) {
|
||||
border-color: var(--theme-border) !important;
|
||||
}
|
||||
|
||||
:is([data-theme="paper-light"], [data-theme="ops-dark"], [data-theme="premium-dark"], [data-theme="sunset-brand"])
|
||||
:is([data-theme="paper-light"], [data-theme="ops-dark"], [data-theme="premium-dark"], [data-theme="sunset-brand"], [data-theme="hermes"])
|
||||
:is(.bg-primary-50, .bg-neutral-50, .bg-slate-800) {
|
||||
background-color: var(--theme-panel) !important;
|
||||
}
|
||||
|
||||
:is([data-theme="paper-light"], [data-theme="ops-dark"], [data-theme="premium-dark"], [data-theme="sunset-brand"])
|
||||
:is([data-theme="paper-light"], [data-theme="ops-dark"], [data-theme="premium-dark"], [data-theme="sunset-brand"], [data-theme="hermes"])
|
||||
:is(.bg-white, .bg-primary-100, .bg-neutral-800, .bg-neutral-900) {
|
||||
background-color: var(--theme-card) !important;
|
||||
}
|
||||
|
||||
:is([data-theme="ops-dark"], [data-theme="premium-dark"], [data-theme="sunset-brand"])
|
||||
:is([data-theme="ops-dark"], [data-theme="premium-dark"], [data-theme="sunset-brand"], [data-theme="hermes"])
|
||||
:is(.bg-neutral-900\/60, .bg-neutral-900\/40) {
|
||||
background-color: var(--theme-card2) !important;
|
||||
opacity: 1 !important;
|
||||
}
|
||||
|
||||
:is([data-theme="paper-light"], [data-theme="ops-dark"], [data-theme="premium-dark"], [data-theme="sunset-brand"])
|
||||
:is([data-theme="paper-light"], [data-theme="ops-dark"], [data-theme="premium-dark"], [data-theme="sunset-brand"], [data-theme="hermes"])
|
||||
:is(.text-primary-900, .text-neutral-100, .text-neutral-200) {
|
||||
color: var(--theme-text) !important;
|
||||
}
|
||||
|
||||
:is([data-theme="paper-light"], [data-theme="ops-dark"], [data-theme="premium-dark"], [data-theme="sunset-brand"])
|
||||
:is([data-theme="paper-light"], [data-theme="ops-dark"], [data-theme="premium-dark"], [data-theme="sunset-brand"], [data-theme="hermes"])
|
||||
:is(.text-primary-500, .text-primary-600, .text-neutral-300, .text-neutral-400, .text-neutral-500) {
|
||||
color: var(--theme-muted) !important;
|
||||
}
|
||||
|
||||
:is([data-theme="paper-light"], [data-theme="ops-dark"], [data-theme="premium-dark"], [data-theme="sunset-brand"])
|
||||
:is([data-theme="paper-light"], [data-theme="ops-dark"], [data-theme="premium-dark"], [data-theme="sunset-brand"], [data-theme="hermes"])
|
||||
:is(.ring-orange-300, .ring-accent-500\/20, .border-accent-500) {
|
||||
--tw-ring-color: var(--theme-accent) !important;
|
||||
border-color: var(--theme-accent) !important;
|
||||
}
|
||||
|
||||
:is([data-theme="paper-light"], [data-theme="ops-dark"], [data-theme="premium-dark"], [data-theme="sunset-brand"])
|
||||
:is([data-theme="paper-light"], [data-theme="ops-dark"], [data-theme="premium-dark"], [data-theme="sunset-brand"], [data-theme="hermes"])
|
||||
:is([aria-selected="true"], [data-selected="true"], .border-primary-500) {
|
||||
border-color: var(--theme-accent) !important;
|
||||
}
|
||||
|
||||
:is([data-theme="paper-light"], [data-theme="ops-dark"], [data-theme="premium-dark"], [data-theme="sunset-brand"])
|
||||
:is([data-theme="paper-light"], [data-theme="ops-dark"], [data-theme="premium-dark"], [data-theme="sunset-brand"], [data-theme="hermes"])
|
||||
.bg-surface {
|
||||
background-color: var(--theme-bg) !important;
|
||||
}
|
||||
|
||||
:is([data-theme="paper-light"], [data-theme="ops-dark"], [data-theme="premium-dark"], [data-theme="sunset-brand"])
|
||||
:is([data-theme="paper-light"], [data-theme="ops-dark"], [data-theme="premium-dark"], [data-theme="sunset-brand"], [data-theme="hermes"])
|
||||
.text-ink {
|
||||
color: var(--theme-text) !important;
|
||||
}
|
||||
@@ -1055,13 +1055,46 @@ code {
|
||||
/* Orange glow pulse on composer when agent is actively working */
|
||||
@keyframes pulse-glow {
|
||||
0%, 100% {
|
||||
box-shadow: 0 0 12px rgba(249, 115, 22, 0.25);
|
||||
box-shadow: 0 0 12px var(--theme-accent-subtle, rgba(48, 80, 255, 0.25));
|
||||
}
|
||||
50% {
|
||||
box-shadow: 0 0 28px rgba(249, 115, 22, 0.55);
|
||||
box-shadow: 0 0 28px var(--theme-accent-border, rgba(48, 80, 255, 0.55));
|
||||
}
|
||||
}
|
||||
|
||||
.animate-pulse-glow {
|
||||
animation: pulse-glow 2s ease-in-out infinite;
|
||||
}
|
||||
|
||||
/* ── Hermes / Nous Research ── */
|
||||
[data-theme="hermes"] {
|
||||
--theme-bg: #0A0E1A;
|
||||
--theme-sidebar: #080C16;
|
||||
--theme-panel: #12182A;
|
||||
--theme-card: #1A2240;
|
||||
--theme-card2: #202850;
|
||||
--theme-border: rgba(48, 80, 255, 0.18);
|
||||
--theme-border-subtle: rgba(48, 80, 255, 0.1);
|
||||
--theme-text: #E8ECFF;
|
||||
--theme-muted: #8090BB;
|
||||
--theme-shadow-1: 0 1px 2px rgba(0, 0, 0, 0.55);
|
||||
--theme-shadow-2: 0 6px 16px rgba(0, 0, 0, 0.52);
|
||||
--theme-shadow-3: 0 16px 36px rgba(0, 0, 0, 0.62);
|
||||
--theme-glass: rgba(10, 14, 26, 0.88);
|
||||
--theme-focus: #3050FF;
|
||||
--theme-accent: #3050FF;
|
||||
--theme-accent-secondary: #5070FF;
|
||||
--theme-accent-subtle: rgba(48, 80, 255, 0.14);
|
||||
--theme-accent-border: rgba(48, 80, 255, 0.32);
|
||||
--theme-stripe: rgba(48, 80, 255, 0.06);
|
||||
--theme-header-bg: #080C16;
|
||||
--theme-header-border: rgba(48, 80, 255, 0.18);
|
||||
}
|
||||
|
||||
[data-theme="hermes"] html,
|
||||
[data-theme="hermes"] body,
|
||||
[data-theme="hermes"] #root,
|
||||
[data-theme="hermes"] .dark {
|
||||
background-color: var(--theme-bg);
|
||||
color: var(--theme-text);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user