Phase 004: remove the desktop shell, website tooling, and bundled hermes CLI

- Drop all desktop/Electron branches, scripts, and UI (title bar, pets,
  desktop bridge); LAN endpoint kind is now web/custom only
- Replace the bundled hermes CLI with user-side installation: add
  GET /api/hermes/cli-status plus a HermesMissingView onboarding guide
- Remove the version-management UI (snapshots handled by git) and prune
  dead website/mcu/claude scripts and lockfile entries
This commit is contained in:
2026-10-16 15:33:56 +08:00
parent 8c1ddf415f
commit 4701bf0ad0
49 changed files with 354 additions and 2403 deletions
@@ -5,20 +5,11 @@ interface CompletionNotificationPayload {
tag?: string
}
interface HermesDesktopBridge {
isDesktop?: boolean
notifyCompletion?: (payload: CompletionNotificationPayload) => Promise<boolean>
}
export interface CompletionNotificationPermissionResult {
granted: boolean
reason?: 'unsupported' | 'insecure' | 'denied'
}
type WindowWithHermesDesktop = Window & typeof globalThis & {
hermesDesktop?: HermesDesktopBridge
}
function withTimeout<T>(promise: Promise<T>, timeoutMs: number, fallback: T): Promise<T> {
return new Promise<T>((resolve) => {
const timer = window.setTimeout(() => resolve(fallback), timeoutMs)
@@ -35,11 +26,6 @@ function withTimeout<T>(promise: Promise<T>, timeoutMs: number, fallback: T): Pr
})
}
function desktopBridge(): HermesDesktopBridge | undefined {
if (typeof window === 'undefined') return undefined
return (window as WindowWithHermesDesktop).hermesDesktop
}
function supportsBrowserNotification(): boolean {
return typeof window !== 'undefined' && 'Notification' in window
}
@@ -76,12 +62,7 @@ async function showServiceWorkerNotification(payload: CompletionNotificationPayl
}
}
export function isDesktopNotificationRuntime(): boolean {
return desktopBridge()?.isDesktop === true
}
export async function requestCompletionNotificationPermission(): Promise<CompletionNotificationPermissionResult> {
if (isDesktopNotificationRuntime()) return { granted: true }
if (!supportsBrowserNotification()) return { granted: false, reason: 'unsupported' }
if (!isBrowserNotificationSecureContext()) return { granted: false, reason: 'insecure' }
if (Notification.permission === 'granted') return { granted: true }
@@ -102,16 +83,6 @@ export async function requestCompletionNotificationPermission(): Promise<Complet
}
export async function showCompletionNotification(payload: CompletionNotificationPayload): Promise<boolean> {
const bridge = desktopBridge()
if (bridge?.isDesktop && bridge.notifyCompletion) {
try {
return await bridge.notifyCompletion(payload)
} catch (err) {
console.warn('Failed to show desktop completion notification:', err)
return false
}
}
if (!supportsBrowserNotification() || !isBrowserNotificationSecureContext() || Notification.permission !== 'granted') {
return false
}