Files
Hermes-ui/packages/client/src/api/hermes/profiles.ts
T
ekko 26423984d1 fix: profile import file upload, startup health check, sidebar scroll, node-pty fallback
- Change profile import from server path input to browser file upload (multipart)
- Fix startup script to wait for health check before opening browser
- Add overflow scroll with hidden scrollbar to sidebar nav
- Graceful degradation when node-pty fails to load (WSL compatibility)
- Remove rename button from profile cards
- Restrict profile name input to English letters, numbers, hyphens
- Use raw.githubusercontent.com URLs in README setup script

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-16 15:19:05 +08:00

123 lines
3.0 KiB
TypeScript

import { request, getBaseUrlValue, getApiKey } from '../client'
export interface HermesProfile {
name: string
active: boolean
model: string
gateway: string
alias: string
}
export interface HermesProfileDetail {
name: string
path: string
model: string
provider: string
gateway: string
skills: number
hasEnv: boolean
hasSoulMd: boolean
}
export async function fetchProfiles(): Promise<HermesProfile[]> {
const res = await request<{ profiles: HermesProfile[] }>('/api/hermes/profiles')
return res.profiles
}
export async function fetchProfileDetail(name: string): Promise<HermesProfileDetail> {
const res = await request<{ profile: HermesProfileDetail }>(`/api/hermes/profiles/${encodeURIComponent(name)}`)
return res.profile
}
export async function createProfile(name: string, clone?: boolean): Promise<boolean> {
try {
await request('/api/hermes/profiles', {
method: 'POST',
body: JSON.stringify({ name, clone }),
})
return true
} catch {
return false
}
}
export async function deleteProfile(name: string): Promise<boolean> {
try {
await request(`/api/hermes/profiles/${encodeURIComponent(name)}`, { method: 'DELETE' })
return true
} catch {
return false
}
}
export async function renameProfile(name: string, newName: string): Promise<boolean> {
try {
await request(`/api/hermes/profiles/${encodeURIComponent(name)}/rename`, {
method: 'POST',
body: JSON.stringify({ new_name: newName }),
})
return true
} catch {
return false
}
}
export async function switchProfile(name: string): Promise<boolean> {
try {
await request('/api/hermes/profiles/active', {
method: 'PUT',
body: JSON.stringify({ name }),
})
return true
} catch {
return false
}
}
export async function exportProfile(name: string): Promise<boolean> {
try {
const baseUrl = getBaseUrlValue()
const token = getApiKey()
const headers: Record<string, string> = {}
if (token) headers['Authorization'] = `Bearer ${token}`
const res = await fetch(`${baseUrl}/api/hermes/profiles/${encodeURIComponent(name)}/export`, {
method: 'POST',
headers,
})
if (!res.ok) throw new Error()
const blob = await res.blob()
const url = URL.createObjectURL(blob)
const a = document.createElement('a')
a.href = url
a.download = `hermes-profile-${name}.tar.gz`
a.click()
URL.revokeObjectURL(url)
return true
} catch {
return false
}
}
export async function importProfile(file: File): Promise<boolean> {
try {
const baseUrl = getBaseUrlValue()
const token = getApiKey()
const headers: Record<string, string> = {}
if (token) headers['Authorization'] = `Bearer ${token}`
const formData = new FormData()
formData.append('file', file)
const res = await fetch(`${baseUrl}/api/hermes/profiles/import`, {
method: 'POST',
headers,
body: formData,
})
return res.ok
} catch {
return false
}
}