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 // Reconnect-after-wake recovery: liveness-probe the cached PRIMARY backend // and drop it if a remote one has gone unreachable, so the next // getConnection() rebuilds a reachable descriptor instead of the renderer // re-dialing a dead remote forever. No-op for local backends (they // self-heal via the child 'exit' handler). `rebuilt` is true when a stale // remote cache was dropped. revalidateConnection: () => Promise<{ ok: boolean; rebuilt: boolean }> // 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 // Open (or focus) a standalone OS window for a single chat session so // the user can work with multiple chats side by side. Returns ok:false // with an error code when the sessionId is empty/invalid. `watch` opens // a spectator window (lazy resume — no agent build) for live-streaming // a running subagent's session. openSessionWindow: (sessionId: string, opts?: { watch?: boolean }) => Promise<{ ok: boolean; error?: string }> // Open (or focus) a compact secondary window on the new-session draft. openNewSessionWindow: () => Promise<{ ok: boolean; error?: string }> getBootProgress: () => Promise getConnectionConfig: (profile?: null | string) => 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 setNativeTheme?: (mode: 'dark' | 'light' | 'system') => void setTranslucency?: (payload: { intensity: number }) => void setPreviewShortcutActive?: (active: boolean) => void openExternal: (url: string) => Promise fetchLinkTitle: (url: string) => Promise sanitizeWorkspaceCwd: (cwd?: null | string) => Promise<{ cwd: string; sanitized: boolean }> settings: { getDefaultProjectDir: () => Promise<{ defaultLabel: string; dir: null | string; resolvedCwd: 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 // Resolve git-worktree identity for a batch of session cwds, reading git's // on-disk metadata locally. Returns null per cwd that isn't inside a // checkout (or can't be read — e.g. a remote backend's path). worktrees?: (cwds: 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 onDeepLink?: ( callback: (payload: { kind: string; name: string; params: Record }) => void ) => () => void signalDeepLinkReady?: () => Promise<{ ok: boolean }> onWindowStateChanged?: (callback: (payload: HermesWindowState) => void) => () => void onFocusSession?: (callback: (sessionId: string) => void) => () => void onNotificationAction?: (callback: (payload: { actionId: string; sessionId?: string }) => 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 } uninstall: { summary: () => Promise run: (mode: DesktopUninstallMode) => Promise } themes: { // Download a VS Code Marketplace extension and return the raw color // theme files it contributes. The renderer converts + persists them. fetchMarketplace: (id: string) => Promise // Search the Marketplace for color-theme extensions. An empty query // returns the most-installed themes. searchMarketplace: (query: string) => Promise } } } } export interface DesktopMarketplaceSearchItem { extensionId: string displayName: string publisher: string description: string installs: number } export interface DesktopMarketplaceThemeFile { label: string /** VS Code's `uiTheme` for this entry (vs-dark / vs / hc-black). */ uiTheme?: string /** Raw theme JSON (JSONC) text, parsed + converted by the renderer. */ contents: string } export interface DesktopMarketplaceThemeResult { extensionId: string displayName: string themes: DesktopMarketplaceThemeFile[] } 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 type DesktopUninstallMode = 'full' | 'gui' | 'lite' export interface DesktopUninstallSummary { hermes_home: string agent_installed: boolean gui_installed: boolean source_built_artifacts: string[] packaged_app_paths: string[] userdata_dir: string userdata_exists: boolean platform: string running_app_path?: null | string probe?: string } export interface DesktopUninstallResult { ok: boolean mode?: DesktopUninstallMode willRemoveAppBundle?: boolean scriptPath?: string error?: string message?: 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' // The profile this config describes, or null for the global/default // connection. Per-profile entries let a profile point at its own backend. profile: null | string remoteAuthMode: 'oauth' | 'token' remoteOauthConnected: boolean remoteTokenPreview: string | null remoteTokenSet: boolean remoteUrl: string } export interface DesktopConnectionConfigInput { mode: 'local' | 'remote' // When set, the save/apply/test targets this profile's per-profile remote // override instead of the global connection. profile?: null | string 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 kind?: string sessionId?: string actions?: { id: string; text: string }[] } 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 HermesWorktreeInfo { // Main repo root — the shared grouping key for a checkout and all its linked // worktrees. repoRoot: string // This cwd's own worktree root. worktreeRoot: string // True when this is the repo's primary checkout (.git is a directory). isMainWorktree: boolean // Current branch (or short detached-HEAD sha), null when unreadable. branch: null | 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 }