export {} declare global { interface Window { hermesDesktop: { // Resolve a backend connection. Omit `profile` (or pass the primary) for // the window's backend; pass a named profile to lazily spawn/reuse that // profile's backend from the pool. getConnection: (profile?: string | null) => Promise // Keepalive: mark a pool profile backend as recently used so the idle // reaper spares it while its chat is active. touchBackend: (profile?: string | null) => Promise<{ ok: boolean }> getGatewayWsUrl: (profile?: null | string) => Promise getBootProgress: () => Promise getConnectionConfig: () => Promise saveConnectionConfig: (payload: DesktopConnectionConfigInput) => Promise applyConnectionConfig: (payload: DesktopConnectionConfigInput) => Promise testConnectionConfig: (payload: DesktopConnectionConfigInput) => Promise probeConnectionConfig: (remoteUrl: string) => Promise oauthLoginConnectionConfig: (remoteUrl: string) => Promise oauthLogoutConnectionConfig: (remoteUrl?: string) => Promise profile: { get: () => Promise // Persists the desktop's profile choice and relaunches the local // backend under the new HERMES_HOME (reloads the window). Pass null to // clear the preference. set: (name: string | null) => Promise } api: (request: HermesApiRequest) => Promise notify: (payload: HermesNotification) => Promise requestMicrophoneAccess: () => Promise readFileDataUrl: (filePath: string) => Promise readFileText: (filePath: string) => Promise selectPaths: (options?: HermesSelectPathsOptions) => Promise writeClipboard: (text: string) => Promise saveImageFromUrl: (url: string) => Promise saveImageBuffer: (data: ArrayBuffer | Uint8Array, ext: string) => Promise saveClipboardImage: () => Promise getPathForFile: (file: File) => string normalizePreviewTarget: (target: string, baseDir?: string) => Promise watchPreviewFile: (url: string) => Promise stopPreviewFileWatch: (id: string) => Promise setTitleBarTheme?: (payload: HermesTitleBarTheme) => void setPreviewShortcutActive?: (active: boolean) => void openExternal: (url: string) => Promise fetchLinkTitle: (url: string) => Promise settings: { getDefaultProjectDir: () => Promise<{ defaultLabel: string; dir: null | string }> pickDefaultProjectDir: () => Promise<{ canceled: boolean; dir: null | string }> setDefaultProjectDir: (dir: null | string) => Promise<{ dir: null | string }> } revealLogs: () => Promise<{ ok: boolean; path: string; error?: string }> getRecentLogs: () => Promise<{ path: string; lines: string[] }> readDir: (path: string) => Promise gitRoot?: (path: string) => Promise terminal: { dispose: (id: string) => Promise onData: (id: string, callback: (payload: string) => void) => () => void onExit: (id: string, callback: (payload: HermesTerminalExit) => void) => () => void resize: (id: string, size: { cols: number; rows: number }) => Promise start: (options?: { cols?: number; cwd?: string; rows?: number }) => Promise write: (id: string, data: string) => Promise } onClosePreviewRequested?: (callback: () => void) => () => void onOpenUpdatesRequested?: (callback: () => void) => () => void onWindowStateChanged?: (callback: (payload: HermesWindowState) => void) => () => void onPreviewFileChanged: (callback: (payload: HermesPreviewFileChanged) => void) => () => void onBackendExit: (callback: (payload: BackendExit) => void) => () => void onPowerResume?: (callback: () => void) => () => void onBootProgress: (callback: (payload: DesktopBootProgress) => void) => () => void getBootstrapState: () => Promise resetBootstrap: () => Promise<{ ok: boolean }> repairBootstrap: () => Promise<{ ok: boolean }> cancelBootstrap: () => Promise<{ ok: boolean; cancelled: boolean }> onBootstrapEvent: (callback: (payload: DesktopBootstrapEvent) => void) => () => void getVersion: () => Promise updates: { check: () => Promise apply: (opts?: DesktopUpdateApplyOptions) => Promise getBranch: () => Promise<{ branch: string }> setBranch: (name: string) => Promise<{ branch: string }> onProgress: (callback: (payload: DesktopUpdateProgress) => void) => () => void } } } } export interface HermesTerminalSession { cwd: string id: string shell: string } export interface HermesTerminalExit { code: number | null signal: string | null } export interface DesktopVersionInfo { appVersion: string electronVersion: string nodeVersion: string platform: string hermesRoot: string } export interface DesktopUpdateCommit { sha: string summary: string author: string at: number } export interface DesktopUpdateStatus { supported: boolean branch?: string currentBranch?: string reason?: string message?: string error?: string behind?: number currentSha?: string targetSha?: string commits?: DesktopUpdateCommit[] dirty?: boolean fetchedAt?: number } export type DesktopUpdateDirtyStrategy = 'abort' | 'stash' | 'force' export interface DesktopUpdateApplyOptions { dirtyStrategy?: DesktopUpdateDirtyStrategy } export interface DesktopUpdateApplyResult { ok: boolean branch?: string error?: string message?: string /** True when no staged updater exists (CLI install) and the user should run * `hermes update` themselves. `command` is the exact line to run. */ manual?: boolean command?: string hermesRoot?: string } export type DesktopUpdateStage = 'idle' | 'prepare' | 'fetch' | 'pull' | 'pydeps' | 'restart' | 'manual' | 'error' export interface DesktopUpdateProgress { stage: DesktopUpdateStage message: string percent: number | null error: string | null at: number } export interface HermesConnection { baseUrl: string isFullscreen: boolean mode?: 'local' | 'remote' authMode?: 'oauth' | 'token' nativeOverlayWidth: number source?: 'env' | 'local' | 'settings' token: string wsUrl: string logs: string[] // Set for pool (non-primary) backends so the renderer knows which profile a // connection belongs to. profile?: string windowButtonPosition: { x: number; y: number } | null } export interface HermesTitleBarTheme { background: string foreground: string } export interface HermesWindowState { isFullscreen: boolean nativeOverlayWidth: number windowButtonPosition: { x: number; y: number } | null } export interface DesktopActiveProfile { // The desktop's stored profile preference, or null when unset (legacy launch // that defers to the sticky active_profile / default). profile: string | null } export interface DesktopConnectionConfig { envOverride: boolean mode: 'local' | 'remote' remoteAuthMode: 'oauth' | 'token' remoteOauthConnected: boolean remoteTokenPreview: string | null remoteTokenSet: boolean remoteUrl: string } export interface DesktopConnectionConfigInput { mode: 'local' | 'remote' remoteAuthMode?: 'oauth' | 'token' remoteToken?: string remoteUrl?: string } export interface DesktopConnectionTestResult { baseUrl: string ok: boolean version: string | null } export interface DesktopAuthProvider { name: string displayName: string // True when this provider authenticates with a username + password // (the gateway's /login page renders a credential form) rather than an // OAuth redirect. The session/cookie/ws-ticket machinery is identical; // only the login-page form and the desktop's button copy differ. supportsPassword?: boolean } export interface DesktopConnectionProbeResult { baseUrl: string reachable: boolean authMode: 'oauth' | 'token' | 'unknown' providers: DesktopAuthProvider[] version: string | null error: string | null } export interface DesktopOauthLoginResult { ok: boolean baseUrl: string connected: boolean } export interface DesktopOauthLogoutResult { ok: boolean connected: boolean } export interface DesktopBootProgress { error: string | null fakeMode: boolean message: string phase: string progress: number running: boolean timestamp: number } // First-launch install ("bootstrap") event types -- emitted by // electron/bootstrap-runner.cjs and observed by the renderer install overlay. // Mirrors the event shapes emitted by runBootstrap()'s onEvent callback. export interface DesktopBootstrapStageDescriptor { name: string title?: string category?: string needs_user_input?: boolean } export type DesktopBootstrapStageState = 'pending' | 'running' | 'succeeded' | 'skipped' | 'failed' export interface DesktopBootstrapStageResult { state: DesktopBootstrapStageState durationMs: number | null startedAt: number | null json: { ok: boolean; skipped?: boolean; reason?: string | null; stage: string } | null error: string | null } export interface DesktopBootstrapUnsupportedPlatform { platform: string activeRoot: string installCommand: string docsUrl: string } export interface DesktopBootstrapState { active: boolean manifest: { type: 'manifest'; stages: DesktopBootstrapStageDescriptor[]; protocolVersion: number | null } | null stages: Record error: string | null log: Array<{ ts: number; stage: string | null; line: string; stream?: 'stdout' | 'stderr' }> startedAt: number | null completedAt: number | null unsupportedPlatform: DesktopBootstrapUnsupportedPlatform | null } export type DesktopBootstrapEvent = | { type: 'manifest'; stages: DesktopBootstrapStageDescriptor[]; protocolVersion: number | null } | { type: 'stage' name: string state: DesktopBootstrapStageState durationMs?: number json?: DesktopBootstrapStageResult['json'] error?: string | null } | { type: 'log'; stage?: string | null; line: string; stream?: 'stdout' | 'stderr' } | { type: 'complete'; marker: Record } | { type: 'failed'; stage?: string | null; error: string } | { type: 'unsupported-platform' platform: string activeRoot: string installCommand: string docsUrl: string } export interface HermesApiRequest { path: string method?: string body?: unknown timeoutMs?: number // Route this REST call to a specific profile's backend. Omit for the primary // (window) backend. Read-only cross-profile data is served by the primary, so // this is only needed for profile-scoped live/settings calls. profile?: string | null } export interface HermesNotification { title?: string body?: string silent?: boolean } export interface HermesPreviewTarget { binary?: boolean byteSize?: number kind: 'file' | 'url' label: string large?: boolean language?: string mimeType?: string path?: string previewKind?: 'binary' | 'html' | 'image' | 'text' renderMode?: 'preview' | 'source' source: string url: string } export interface HermesReadFileTextResult { binary?: boolean byteSize?: number language?: string mimeType?: string path: string text: string truncated?: boolean } export interface HermesPreviewWatch { id: string path: string } export interface HermesReadDirEntry { name: string path: string isDirectory: boolean } export interface HermesReadDirResult { entries: HermesReadDirEntry[] error?: string } export interface HermesPreviewFileChanged { id: string path: string url: string } export interface HermesSelectPathsOptions { title?: string defaultPath?: string directories?: boolean multiple?: boolean filters?: Array<{ name: string; extensions: string[] }> } export interface BackendExit { code: number | null signal: string | null }