feat: add token auth, login page, skill toggle, and route restructure

- Add token-based authentication with auto-generated token stored in server/data/.token
- Add login page with URL token auto-fill support
- Add route guards requiring auth for all pages except login
- Restructure routes: / for login, /chat for conversations
- Add skill enable/disable toggle via config.yaml skills.disabled
- Unify logo to /logo.png across sidebar, login, messages, and empty state
- Hide sidebar on login page, prevent flash with router.isReady()
- Fix session export JSON parse error when CLI returns non-JSON output
- Display token in CLI on server start

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
ekko
2026-04-14 21:48:53 +08:00
parent be4624b8b4
commit 1f45254dd0
19 changed files with 464 additions and 12 deletions
+16
View File
@@ -1,3 +1,5 @@
import router from '@/router'
const DEFAULT_BASE_URL = ''
function getBaseUrl(): string {
@@ -16,6 +18,14 @@ export function setApiKey(key: string) {
localStorage.setItem('hermes_api_key', key)
}
export function clearApiKey() {
localStorage.removeItem('hermes_api_key')
}
export function hasApiKey(): boolean {
return !!getApiKey()
}
export async function request<T>(path: string, options: RequestInit = {}): Promise<T> {
const base = getBaseUrl()
const url = `${base}${path}`
@@ -31,6 +41,12 @@ export async function request<T>(path: string, options: RequestInit = {}): Promi
const res = await fetch(url, { ...options, headers })
// Global 401 handler — redirect to login
if (res.status === 401) {
router.replace({ name: 'login' })
throw new Error('Unauthorized')
}
if (!res.ok) {
const text = await res.text().catch(() => '')
throw new Error(`API Error ${res.status}: ${text || res.statusText}`)