import { contextBridge, ipcRenderer, webUtils } from 'electron' import { type AgentEvent, type AgentQuestionAnswer, type AgentRequest, type AgentRuntimeDetection, type AgentRuntimeStatus, type AppInfo, type BrowserBackRequest, type BrowserClickRequest, type BrowserCloseTabRequest, type BrowserCreateTabRequest, type BrowserLiveState, type BrowserListTabsRequest, type BrowserNavigateRequest, type BrowserReloadRequest, type BrowserScreenshotRequest, type BrowserScreenshotResult, type BrowserSelectRequest, type BrowserSetViewportRequest, type BrowserSnapshotRequest, type BrowserSnapshotResult, type BrowserStopLoadingRequest, type BrowserTabSummary, type BrowserTypeRequest, type ContextAttachment, type ContextFileSelectionProgress, type DesktopApi, type KnowledgeLibrary, type KnowledgeSearchReference, type KnowledgeSnapshot, type PastedImageInput, type RuntimeConversationCompactInput, type RuntimeConversationCompactResult, type RuntimeCustomizationSettings, type RuntimeNativeSnapshot, type RuntimeNativeSnapshotInput, type RuntimeSettings, type RuntimeSettingsInput, type RuntimeConfigActionInput, type RuntimeFileSelectionKind, type RemoteProjectSaveProgress, type RemoteProjectSaveRequest, type WindowCaptureOption } from '../shared/contracts' import { ipcChannels } from '../shared/ipc-channels' import type { BrowserProfileCreateInput, BrowserProfileRenameInput, BuiltinMcpServerId, CapabilityDiagnosticReport, CapabilitySnapshot, ComputerCapabilityId, McpServerTestResult, ObsidianConnectionTestResult, WebSearchTestResult } from '../shared/capability-contracts' import type { AssistantProject, AssistantArtifact, AssistantMemory, AssistantSchedule, AssistantHeartbeatConfig, AssistantHeartbeatEntry, AssistantHeartbeatRun, AssistantExpert, AssistantTask, ExecutionStats, ActivityHistoryPage, ActivityHistoryPageRequest, ActivityHistoryReconcileRequest, ActivityHistorySnapshot, ActivityHistorySummary, ActivityHistorySummaryRequest, ActivityHistoryUpdate, ActivityHistoryUpdateResult, ActivityRecord, TokenUsageSummary, ConversationBranchInput, ConversationSnapshot, LocalConversationSaveBatch, WorkspaceChanges, WorkspaceDirectoryListing, WorkspaceFilePreview, ProjectCreateInput, MemoryCreateInput, ScheduleCreateInput, HeartbeatCreateInput, HeartbeatUpdateInput, ExpertCreateInput, ExpertUpdateInput } from '../shared/assistant-contracts' import type { ChannelConnectionTestResult, ChannelRuntimeStatusChange, ChannelSettingsApply, ChannelSettingsSnapshot, CredentialChannel, DingTalkChannelSettingsInput, TelegramChannelSettingsInput, WeComChannelSettingsInput } from '../shared/channel-settings-contracts' import type { ApplicationSettings, ApplicationSettingsUpdate, ModelDownloadSource, VersionCheckResult } from '../shared/application-settings-contracts' import type { LocalToolDiagnoseTarget, LocalToolEnvironmentProgress, LocalToolEnvironmentSettings, LocalToolEnvironmentSnapshot, LocalToolKind } from '../shared/local-tool-environment-contracts' import type { ReleaseNotesSnapshot } from '../shared/release-notes-contracts' import type { SpeechModelSnapshot, SpeechTranscriptionInput, SpeechTranscriptionResult } from '../shared/speech-model-contracts' import type { EmbeddingDiagnosticResult, EmbeddingModelProgressSnapshot, EmbeddingModelSnapshot, EmbeddingSettingsSnapshot, KnowledgeEmbeddingIndexSnapshot } from '../shared/embedding-contracts' import type { DocumentOcrAssets, DocumentOcrFailure, DocumentOcrModelProgressSnapshot, DocumentOcrRequest, DocumentOcrResult, DocumentParsingDiagnostic, DocumentParsingSettings, DocumentParsingSnapshot, DocumentParsingTestPurpose } from '../shared/document-parsing-contracts' import type { AgentRuntimeSelection } from '../shared/runtime-selection-contracts' import type { AgentPackageDownloadProgress, AgentPackageInventory } from '../shared/agent-package-contracts' import type { AgentArchitecture } from '../shared/agent-installation-contracts' import type { WeixinBindingSnapshot } from '../shared/weixin-channel-contracts' import type { RemoteChannelActivity } from '../shared/remote-channel-contracts' import type { SshHostDraftInspectionRequest, SshDirectoryBrowseResult, SshHostKeyInspection, RemoteEnvironmentUpdateProgress, RemoteEnvironmentUpdateRequest, SshHostRemoteEnvironment, SshHostRemovalResult, SshHostAgentConnectionStatus, SshHostsSnapshot, SshHostValidationRequest, SshHostValidationResult } from '../shared/ssh-host-contracts' import type { MagicNoteAnalysisStreamEvent, MagicNoteDraftAnalysis, MagicNoteDetail, MagicNoteCreateResult, MagicNoteSummary, MagicNoteEntryCreateResult, MagicNoteTag, MagicNoteTagRenameResult, MagicNotesSnapshot, MagicTodoItem, MagicTodoStatus, MagicTodoUpdateResult, MagicTodosSnapshot } from '../shared/magic-notes-contracts' import type { KnowledgeChunkDeleteInput, KnowledgeChunkPage, KnowledgeChunkUpdateInput, KnowledgeChunksListInput, KnowledgeDocumentOpenInput, KnowledgeDocumentRebuildInput, KnowledgeLibraryRebuildInput, KnowledgeReferenceContext, KnowledgeReferenceContextInput, KnowledgeReferenceOpenInput, KnowledgeRetrievalResponse, KnowledgeRetrieveInput, KnowledgeSettingsUpdateInput } from '../shared/knowledge-contracts' import type { RuntimeExtensionAction, RuntimeExtensionMarketplaceSnapshot } from '../shared/runtime-extension-contracts' import type { GlobalShortcutSettings, GlobalShortcutSettingsSnapshot, GlobalShortcutSettingsUpdateResult } from '../shared/shortcut' import type { FeedbackSubmitInput, FeedbackSubmitResult } from '../shared/feedback-contracts' import type { RemoteProjectRecoverySnapshot, RemoteProjectRecoveryState } from '../shared/remote-project-recovery-contracts' import type { TerminalAckRequest, TerminalCloseRequest, TerminalCreateRequest, TerminalEvent, TerminalResizeRequest, TerminalSnapshot, TerminalSnapshotRequest, TerminalWriteRequest } from '../shared/terminal-contracts' const desktopApi: DesktopApi = { openRuntimeNativeClient: (input) => ipcRenderer.invoke(ipcChannels.runtimeNativeClientOpen, input), getRuntimeNativeClient: (input) => ipcRenderer.invoke(ipcChannels.runtimeNativeClientGet, input), stopRuntimeNativeClient: (input) => ipcRenderer.invoke(ipcChannels.runtimeNativeClientStop, input), storageUpgrade: { getProgress: () => ipcRenderer.invoke(ipcChannels.storageUpgradeProgress), act: async (action) => { await ipcRenderer.invoke(ipcChannels.storageUpgradeAction, action) } }, app: { getInfo: () => ipcRenderer.invoke(ipcChannels.appInfo) as Promise, show: async () => { await ipcRenderer.invoke(ipcChannels.appShow) }, hide: async () => { await ipcRenderer.invoke(ipcChannels.appHide) }, minimize: async () => { await ipcRenderer.invoke(ipcChannels.windowMinimize) }, toggleMaximize: async () => { await ipcRenderer.invoke(ipcChannels.windowToggleMaximize) }, close: async () => { await ipcRenderer.invoke(ipcChannels.windowClose) }, isMaximized: () => ipcRenderer.invoke(ipcChannels.windowIsMaximized) as Promise, onMaximizedChanged: (listener) => { const handler = ( _event: Electron.IpcRendererEvent, maximized: boolean ): void => listener(maximized) ipcRenderer.on(ipcChannels.windowMaximizedChanged, handler) return () => ipcRenderer.removeListener( ipcChannels.windowMaximizedChanged, handler ) }, onPreviewEscape: (listener) => { const handler = (): void => listener() ipcRenderer.on(ipcChannels.windowPreviewEscape, handler) return () => ipcRenderer.removeListener(ipcChannels.windowPreviewEscape, handler) }, onBeforeQuit: (listener) => { const handler = ( _event: Electron.IpcRendererEvent, requestId: string ): void => { const acknowledge = (): void => { void ipcRenderer.invoke( ipcChannels.appRendererPersistenceComplete, requestId ) } void listener().then(acknowledge, acknowledge) } ipcRenderer.on( ipcChannels.appRendererPersistenceRequest, handler ) void ipcRenderer.invoke(ipcChannels.appRendererPersistenceReady) return () => ipcRenderer.removeListener( ipcChannels.appRendererPersistenceRequest, handler ) }, clearLocalData: async () => { await ipcRenderer.invoke(ipcChannels.appClearLocalData) }, onNewConversation: (listener) => { const handler = (): void => listener() ipcRenderer.on(ipcChannels.conversationNew, handler) return () => ipcRenderer.removeListener(ipcChannels.conversationNew, handler) }, onOpenSettings: (listener) => { const handler = (_event: Electron.IpcRendererEvent, category?: unknown): void => listener(category === 'model' || category === 'document-parsing' ? category : undefined) ipcRenderer.on(ipcChannels.settingsOpen, handler) return () => ipcRenderer.removeListener(ipcChannels.settingsOpen, handler) } }, clipboard: { readText: () => ipcRenderer.invoke(ipcChannels.clipboardReadText) as Promise, writeText: async (text: string) => { await ipcRenderer.invoke(ipcChannels.clipboardWriteText, text) } }, agent: { getStatus: (selection) => ipcRenderer.invoke( ipcChannels.agentStatus, selection ) as Promise, run: async (request: AgentRequest) => { await ipcRenderer.invoke(ipcChannels.agentRun, request) }, cancel: async (requestId: string) => { await ipcRenderer.invoke(ipcChannels.agentCancel, requestId) }, respondQuestion: async ( questionId: string, answers?: AgentQuestionAnswer[] ) => { await ipcRenderer.invoke(ipcChannels.agentQuestionRespond, { questionId, answers: answers ?? [] }) }, compactConversation: (input: RuntimeConversationCompactInput) => ipcRenderer.invoke( ipcChannels.agentCompactConversation, input ) as Promise, onEvent: (listener) => { const handler = (_event: Electron.IpcRendererEvent, payload: AgentEvent): void => listener(payload) ipcRenderer.on(ipcChannels.agentEvent, handler) return () => ipcRenderer.removeListener(ipcChannels.agentEvent, handler) } }, browser: { createTab: (request: BrowserCreateTabRequest) => ipcRenderer.invoke( ipcChannels.browserCreateTab, request ) as Promise, listTabs: (request: BrowserListTabsRequest) => ipcRenderer.invoke( ipcChannels.browserListTabs, request ) as Promise, closeTab: async (request: BrowserCloseTabRequest) => { await ipcRenderer.invoke(ipcChannels.browserCloseTab, request) }, navigate: async ( requestOrConversation: BrowserNavigateRequest | string, url?: string ) => { await ipcRenderer.invoke( ipcChannels.browserNavigate, typeof requestOrConversation === 'string' ? { conversationId: requestOrConversation, url } : requestOrConversation ) }, back: async (requestOrConversation: BrowserBackRequest | string) => { await ipcRenderer.invoke( ipcChannels.browserBack, typeof requestOrConversation === 'string' ? { conversationId: requestOrConversation } : requestOrConversation ) }, reload: async (requestOrConversation: BrowserReloadRequest | string) => { await ipcRenderer.invoke( ipcChannels.browserReload, typeof requestOrConversation === 'string' ? { conversationId: requestOrConversation } : requestOrConversation ) }, stopLoading: async ( requestOrConversation: BrowserStopLoadingRequest | string ) => { await ipcRenderer.invoke( ipcChannels.browserStopLoading, typeof requestOrConversation === 'string' ? { conversationId: requestOrConversation } : requestOrConversation ) }, snapshot: (request: BrowserSnapshotRequest) => ipcRenderer.invoke( ipcChannels.browserSnapshot, request ) as Promise, click: async (request: BrowserClickRequest) => { await ipcRenderer.invoke(ipcChannels.browserClick, request) }, type: async (request: BrowserTypeRequest) => { await ipcRenderer.invoke(ipcChannels.browserType, request) }, select: async (request: BrowserSelectRequest) => { await ipcRenderer.invoke(ipcChannels.browserSelect, request) }, screenshot: (request: BrowserScreenshotRequest) => ipcRenderer.invoke( ipcChannels.browserScreenshot, request ) as Promise, setViewport: async (request: BrowserSetViewportRequest) => { await ipcRenderer.invoke(ipcChannels.browserSetViewport, request) }, stop: async (conversationId: string) => { await ipcRenderer.invoke( ipcChannels.browserStop, { conversationId } ) }, onState: (listener) => { const handler = ( _event: Electron.IpcRendererEvent, payload: BrowserLiveState ): void => listener(payload) ipcRenderer.on(ipcChannels.browserState, handler) return () => ipcRenderer.removeListener(ipcChannels.browserState, handler) } }, terminal: { create: (request: TerminalCreateRequest) => ipcRenderer.invoke( ipcChannels.terminalCreate, request ) as Promise, write: async (request: TerminalWriteRequest) => { await ipcRenderer.invoke(ipcChannels.terminalWrite, request) }, resize: async (request: TerminalResizeRequest) => { await ipcRenderer.invoke(ipcChannels.terminalResize, request) }, close: (request: TerminalCloseRequest) => ipcRenderer.invoke( ipcChannels.terminalClose, request ) as Promise, getSnapshot: (request: TerminalSnapshotRequest) => ipcRenderer.invoke( ipcChannels.terminalSnapshot, request ) as Promise, ack: async (request: TerminalAckRequest) => { await ipcRenderer.invoke(ipcChannels.terminalAck, request) }, onEvent: (listener) => { const handler = ( _event: Electron.IpcRendererEvent, payload: TerminalEvent ): void => listener(payload) ipcRenderer.on(ipcChannels.terminalEvent, handler) return () => ipcRenderer.removeListener(ipcChannels.terminalEvent, handler) } }, settings: { getRuntime: () => ipcRenderer.invoke( ipcChannels.runtimeSettingsGet ) as Promise, updateRuntime: (input: RuntimeSettingsInput) => ipcRenderer.invoke( ipcChannels.runtimeSettingsUpdate, input ) as Promise, selectWorkspace: () => ipcRenderer.invoke( ipcChannels.runtimeSettingsSelectWorkspace ) as Promise, detectAgentRuntimes: () => ipcRenderer.invoke( ipcChannels.runtimeSettingsDetect ) as Promise, selectRuntimeFile: (kind: RuntimeFileSelectionKind) => ipcRenderer.invoke( ipcChannels.runtimeSettingsSelectFile, kind ) as Promise, openRuntimeConfig: async (input: RuntimeConfigActionInput) => { await ipcRenderer.invoke( ipcChannels.runtimeSettingsOpenConfig, input ) }, testModelConnection: (profileId: string) => ipcRenderer.invoke( ipcChannels.runtimeSettingsTestModel, profileId ) as Promise, testRuntime: (selection: AgentRuntimeSelection) => ipcRenderer.invoke( ipcChannels.runtimeSettingsTest, selection ) as Promise }, sshHosts: { getSnapshot: () => ipcRenderer.invoke( ipcChannels.sshHostsGet ) as Promise, onAgentConnectionStatus: (listener) => { const handler = ( _event: Electron.IpcRendererEvent, status: SshHostAgentConnectionStatus ): void => listener(status) ipcRenderer.on( ipcChannels.sshHostsAgentConnectionStatus, handler ) return () => ipcRenderer.removeListener( ipcChannels.sshHostsAgentConnectionStatus, handler ) }, getAgentPackageInventory: (refresh = false) => ipcRenderer.invoke( ipcChannels.sshHostsAgentPackageInventory, { refresh } ) as Promise, downloadAgentPackage: (architecture: AgentArchitecture, platform: 'linux' | 'darwin' = 'linux') => ipcRenderer.invoke( ipcChannels.sshHostsAgentPackageDownload, { architecture, platform } ) as Promise, importAgentPackage: () => ipcRenderer.invoke( ipcChannels.sshHostsAgentPackageImport ) as Promise, exportAgentPackage: async (architecture: AgentArchitecture, platform: 'linux' | 'darwin' = 'linux') => { await ipcRenderer.invoke( ipcChannels.sshHostsAgentPackageExport, { architecture, platform } ) }, onAgentPackageProgress: (listener) => { const handler = ( _event: Electron.IpcRendererEvent, progress: AgentPackageDownloadProgress ): void => listener(progress) ipcRenderer.on( ipcChannels.sshHostsAgentPackageProgress, handler ) return () => ipcRenderer.removeListener( ipcChannels.sshHostsAgentPackageProgress, handler ) }, remove: (hostId: string) => ipcRenderer.invoke(ipcChannels.sshHostsRemove, { hostId }) as Promise, inspectDraftHostKey: (input: SshHostDraftInspectionRequest) => ipcRenderer.invoke( ipcChannels.sshHostsInspectDraftKey, input ) as Promise, discardCandidate: async (candidateId: string) => { await ipcRenderer.invoke( ipcChannels.sshHostsDiscardCandidate, { candidateId } ) }, validateAndSave: (input: SshHostValidationRequest) => ipcRenderer.invoke( ipcChannels.sshHostsValidateAndSave, input ) as Promise, getRemoteEnvironment: (hostId: string) => ipcRenderer.invoke( ipcChannels.sshHostsRemoteEnvironment, { hostId } ) as Promise, updateRemoteEnvironment: async ( input: RemoteEnvironmentUpdateRequest ) => { await ipcRenderer.invoke( ipcChannels.sshHostsUpdateRemoteEnvironment, input ) }, cancelRemoteEnvironmentUpdate: async (hostId: string) => { await ipcRenderer.invoke( ipcChannels.sshHostsCancelRemoteEnvironmentUpdate, { hostId } ) }, onRemoteEnvironmentUpdateProgress: (listener) => { const handler = ( _event: Electron.IpcRendererEvent, progress: RemoteEnvironmentUpdateProgress ): void => listener(progress) ipcRenderer.on( ipcChannels.sshHostsRemoteEnvironmentUpdateProgress, handler ) return () => ipcRenderer.removeListener( ipcChannels.sshHostsRemoteEnvironmentUpdateProgress, handler ) }, browseDirectories: (hostId: string, path?: string) => ipcRenderer.invoke(ipcChannels.sshHostsBrowseDirectories, { hostId, ...(path === undefined ? {} : { path }) }) as Promise, cancelDirectoryBrowse: async () => { await ipcRenderer.invoke( ipcChannels.sshHostsCancelDirectoryBrowse ) } }, channels: { onStatusChanged: (listener) => { const handler = ( _event: Electron.IpcRendererEvent, change: ChannelRuntimeStatusChange ): void => listener(change) ipcRenderer.on(ipcChannels.channelStatusChanged, handler) return () => ipcRenderer.removeListener(ipcChannels.channelStatusChanged, handler) }, getSnapshot: () => ipcRenderer.invoke( ipcChannels.channelSettingsGet ) as Promise, apply: (input: ChannelSettingsApply) => ipcRenderer.invoke( ipcChannels.channelSettingsApply, input ) as Promise, testConnection: ( channel: CredentialChannel, settings?: WeComChannelSettingsInput | DingTalkChannelSettingsInput | TelegramChannelSettingsInput ) => ipcRenderer.invoke(ipcChannels.channelSettingsTest, { channel, settings }) as Promise, getWeixinBinding: () => ipcRenderer.invoke( ipcChannels.weixinBindingGet ) as Promise, startWeixinBinding: () => ipcRenderer.invoke( ipcChannels.weixinBindingStart ) as Promise, submitWeixinVerification: (code: string) => ipcRenderer.invoke( ipcChannels.weixinBindingVerify, { code } ) as Promise, disconnectWeixin: () => ipcRenderer.invoke( ipcChannels.weixinBindingDisconnect ) as Promise, onWeixinBindingChanged: (listener) => { const handler = ( _event: Electron.IpcRendererEvent, snapshot: WeixinBindingSnapshot ): void => listener(snapshot) ipcRenderer.on(ipcChannels.weixinBindingChanged, handler) return () => ipcRenderer.removeListener( ipcChannels.weixinBindingChanged, handler ) }, onRemoteActivity: (listener) => { const handler = ( _event: Electron.IpcRendererEvent, activity: RemoteChannelActivity ): void => listener(activity) ipcRenderer.on(ipcChannels.remoteChannelActivity, handler) return () => ipcRenderer.removeListener( ipcChannels.remoteChannelActivity, handler ) } }, updates: { onSettingsChanged: (listener) => { const handler = ( _event: Electron.IpcRendererEvent, settings: ApplicationSettings ): void => listener(settings) ipcRenderer.on(ipcChannels.applicationSettingsChanged, handler) return () => ipcRenderer.removeListener(ipcChannels.applicationSettingsChanged, handler) }, getSettings: () => ipcRenderer.invoke( ipcChannels.applicationSettingsGet ) as Promise, updateSettings: (input: ApplicationSettingsUpdate) => ipcRenderer.invoke( ipcChannels.applicationSettingsUpdate, input ) as Promise, check: () => ipcRenderer.invoke( ipcChannels.versionCheck ) as Promise, openReleasePage: async () => { await ipcRenderer.invoke(ipcChannels.versionOpenReleasePage) }, onResult: (listener) => { const handler = ( _event: Electron.IpcRendererEvent, result: VersionCheckResult ): void => listener(result) ipcRenderer.on(ipcChannels.versionCheckResult, handler) return () => ipcRenderer.removeListener(ipcChannels.versionCheckResult, handler) } }, localToolEnvironment: { getSnapshot: () => ipcRenderer.invoke( ipcChannels.localToolEnvironmentGet ) as Promise, updateSettings: (settings: LocalToolEnvironmentSettings) => ipcRenderer.invoke( ipcChannels.localToolEnvironmentUpdate, settings ) as Promise, refreshCandidates: () => ipcRenderer.invoke( ipcChannels.localToolEnvironmentRefresh ) as Promise, selectExecutable: (kind: LocalToolKind) => ipcRenderer.invoke( ipcChannels.localToolEnvironmentSelectExecutable, { kind } ) as Promise, diagnose: (kind: LocalToolDiagnoseTarget) => ipcRenderer.invoke( ipcChannels.localToolEnvironmentDiagnose, { kind } ) as Promise, installPython: () => ipcRenderer.invoke( ipcChannels.localToolEnvironmentInstallPython ) as Promise, cancelPython: () => ipcRenderer.invoke( ipcChannels.localToolEnvironmentCancelPython ) as Promise, removePython: () => ipcRenderer.invoke( ipcChannels.localToolEnvironmentRemovePython ) as Promise, onProgress: (listener) => { const handler = ( _event: Electron.IpcRendererEvent, progress: LocalToolEnvironmentProgress ): void => listener(progress) ipcRenderer.on(ipcChannels.localToolEnvironmentProgress, handler) return () => ipcRenderer.removeListener( ipcChannels.localToolEnvironmentProgress, handler ) } }, feedback: { submit: (input: FeedbackSubmitInput) => ipcRenderer.invoke( ipcChannels.feedbackSubmit, input ) as Promise }, shortcuts: { getSettings: () => ipcRenderer.invoke( ipcChannels.shortcutSettingsGet ) as Promise, updateSettings: (input: GlobalShortcutSettings) => ipcRenderer.invoke( ipcChannels.shortcutSettingsUpdate, input ) as Promise }, releaseNotes: { getPending: () => ipcRenderer.invoke( ipcChannels.releaseNotesGetPending ) as Promise, acknowledge: async (version: string) => { await ipcRenderer.invoke( ipcChannels.releaseNotesAcknowledge, { version } ) } }, localInference: { openSettings: (category) => ipcRenderer.invoke(ipcChannels.localInferenceOpenSettings, category), getSnapshot: () => ipcRenderer.invoke(ipcChannels.localInferenceGet), act: (input) => ipcRenderer.invoke(ipcChannels.localInferenceAct, input), cancel: (taskId) => ipcRenderer.invoke(ipcChannels.localInferenceCancel, { taskId }) }, sharing: { getSettings: () => ipcRenderer.invoke(ipcChannels.sharingSettingsGet), saveSettings: input => ipcRenderer.invoke(ipcChannels.sharingSettingsSave, input), registerDevice: () => ipcRenderer.invoke(ipcChannels.sharingRegister), getCatalog: () => ipcRenderer.invoke(ipcChannels.sharingCatalog), publish: input => ipcRenderer.invoke(ipcChannels.sharingPublish, input), revoke: id => ipcRenderer.invoke(ipcChannels.sharingRevoke, id) }, speechModels: { getSnapshot: () => ipcRenderer.invoke( ipcChannels.speechModelsGet ) as Promise, install: ( modelId: string, expectedDownloadSource: ModelDownloadSource ) => ipcRenderer.invoke( ipcChannels.speechModelsInstall, { modelId, expectedDownloadSource } ) as Promise, cancel: (modelId: string) => ipcRenderer.invoke( ipcChannels.speechModelsCancel, { modelId } ) as Promise, remove: (modelId: string) => ipcRenderer.invoke( ipcChannels.speechModelsRemove, { modelId } ) as Promise, select: (modelId: string | null) => ipcRenderer.invoke( ipcChannels.speechModelsSelect, { modelId } ) as Promise, importArchive: (modelId: string) => ipcRenderer.invoke( ipcChannels.speechModelsImportArchive, { modelId } ) as Promise, exportArchive: (modelId: string) => ipcRenderer.invoke( ipcChannels.speechModelsExportArchive, { modelId } ) as Promise, openRepository: async (modelId: string) => { await ipcRenderer.invoke( ipcChannels.speechModelsOpenRepository, { modelId } ) }, openModelsDirectory: async () => { await ipcRenderer.invoke(ipcChannels.speechModelsOpenDirectory) } }, speech: { transcribe: (input: SpeechTranscriptionInput) => ipcRenderer.invoke( ipcChannels.speechTranscribe, input ) as Promise, cancel: (requestId: string) => ipcRenderer.invoke( ipcChannels.speechTranscriptionCancel, requestId ) as Promise }, embeddings: { getSnapshot: () => ipcRenderer.invoke( ipcChannels.embeddingSettingsGet ) as Promise, getModelProgress: () => ipcRenderer.invoke( ipcChannels.embeddingModelsProgress ) as Promise, diagnose: (connectionId: string) => ipcRenderer.invoke( ipcChannels.embeddingDiagnose, { connectionId } ) as Promise, setCurrent: (connectionId: string) => ipcRenderer.invoke( ipcChannels.embeddingSetCurrent, { connectionId } ) as Promise, installModel: ( modelId: string, expectedDownloadSource: ModelDownloadSource ) => ipcRenderer.invoke( ipcChannels.embeddingModelsInstall, { modelId, expectedDownloadSource } ) as Promise, cancelModelOperation: (modelId: string) => ipcRenderer.invoke( ipcChannels.embeddingModelsCancel, { modelId } ) as Promise, importModelArchive: (modelId: string) => ipcRenderer.invoke( ipcChannels.embeddingModelsImportArchive, { modelId } ) as Promise, removeModel: (modelId: string) => ipcRenderer.invoke( ipcChannels.embeddingModelsRemove, { modelId } ) as Promise }, documentParsing: { getResult: (id) => ipcRenderer.invoke(ipcChannels.documentParsingResult, { id }), readResultImage: (id, imageId, thumbnail) => ipcRenderer.invoke(ipcChannels.documentParsingImage, { id, imageId, thumbnail }), openResultOriginal: (id) => ipcRenderer.invoke(ipcChannels.documentParsingOriginal, { id }), releaseResult: (id) => ipcRenderer.invoke(ipcChannels.documentParsingRelease, { id }), cancelTest: (operationId) => ipcRenderer.invoke(ipcChannels.documentParsingCancel, { id: operationId }), checkHttp: () => ipcRenderer.invoke(ipcChannels.documentParsingCheckHttp), getSnapshot: () => ipcRenderer.invoke( ipcChannels.documentParsingGet ) as Promise, getOcrModelProgress: () => ipcRenderer.invoke( ipcChannels.documentOcrModelsProgress ) as Promise, update: (input: DocumentParsingSettings & { apiKey?: string; clearApiKey?: boolean }) => ipcRenderer.invoke( ipcChannels.documentParsingUpdate, input ) as Promise, test: (purpose: DocumentParsingTestPurpose, operationId?: string) => ipcRenderer.invoke( ipcChannels.documentParsingTest, { purpose, ...(operationId ? { operationId } : {}) } ) as Promise, installOcrModel: ( modelId: string, expectedDownloadSource: ModelDownloadSource ) => ipcRenderer.invoke( ipcChannels.documentOcrModelsInstall, { modelId, expectedDownloadSource } ) as Promise, cancelOcrModelOperation: (modelId: string) => ipcRenderer.invoke( ipcChannels.documentOcrModelsCancel, { modelId } ) as Promise, removeOcrModel: (modelId: string) => ipcRenderer.invoke( ipcChannels.documentOcrModelsRemove, { modelId } ) as Promise, importOcrModelArchive: (modelId: string) => ipcRenderer.invoke( ipcChannels.documentOcrModelsImportArchive, { modelId } ) as Promise, exportOcrModelArchive: (modelId: string) => ipcRenderer.invoke( ipcChannels.documentOcrModelsExportArchive, { modelId } ) as Promise, openOcrModelRepository: async (modelId: string) => { await ipcRenderer.invoke( ipcChannels.documentOcrModelsOpenRepository, { modelId } ) }, openOcrModelsDirectory: async () => { await ipcRenderer.invoke( ipcChannels.documentOcrModelsOpenDirectory ) }, getOcrAssets: (modelId: string) => ipcRenderer.invoke( ipcChannels.documentParsingOcrAssets, { modelId } ) as Promise, respondOcr: async ( response: DocumentOcrResult | DocumentOcrFailure ) => { await ipcRenderer.invoke( ipcChannels.documentParsingOcrRespond, response ) }, onOcrRequest: (listener) => { const handler = ( _event: Electron.IpcRendererEvent, request: DocumentOcrRequest ): void => listener(request) ipcRenderer.on(ipcChannels.documentParsingOcrRequest, handler) return () => ipcRenderer.removeListener( ipcChannels.documentParsingOcrRequest, handler ) }, onOcrCancel: (listener) => { const handler = ( _event: Electron.IpcRendererEvent, requestId: string ): void => listener(requestId) ipcRenderer.on(ipcChannels.documentParsingOcrCancel, handler) return () => ipcRenderer.removeListener( ipcChannels.documentParsingOcrCancel, handler ) } }, projects: { list: (includeArchived = false) => ipcRenderer.invoke( ipcChannels.projectsList, includeArchived ) as Promise, create: (input: ProjectCreateInput) => ipcRenderer.invoke( ipcChannels.projectsCreate, input ) as Promise, update: (projectId: string, input: ProjectCreateInput) => ipcRenderer.invoke( ipcChannels.projectsUpdate, { projectId, input } ) as Promise, setArchived: async (projectId: string, archived: boolean) => { await ipcRenderer.invoke(ipcChannels.projectsSetArchived, { projectId, archived }) }, delete: async (projectId: string, confirmation: string) => { await ipcRenderer.invoke(ipcChannels.projectsDelete, { projectId, confirmation }) }, remote: { save: (input: RemoteProjectSaveRequest) => ipcRenderer.invoke( ipcChannels.remoteProjectSave, input ) as Promise, cancelCurrent: async () => { await ipcRenderer.invoke(ipcChannels.remoteProjectCancelCurrent) }, onSaveProgress: (listener) => { const handler = ( _event: Electron.IpcRendererEvent, progress: RemoteProjectSaveProgress ): void => listener(progress) ipcRenderer.on( ipcChannels.remoteProjectSaveProgress, handler ) return () => ipcRenderer.removeListener( ipcChannels.remoteProjectSaveProgress, handler ) }, getRecoverySnapshot: () => ipcRenderer.invoke( ipcChannels.remoteProjectRecoveryGet ) as Promise, retryRecovery: (projectId: string) => ipcRenderer.invoke( ipcChannels.remoteProjectRecoveryRetry, { projectId } ) as Promise, onRecoveryProgress: (listener) => { const handler = ( _event: Electron.IpcRendererEvent, state: RemoteProjectRecoveryState ): void => listener(state) ipcRenderer.on( ipcChannels.remoteProjectRecoveryProgress, handler ) return () => ipcRenderer.removeListener( ipcChannels.remoteProjectRecoveryProgress, handler ) } } }, conversations: { imageOperations: { cancel: (input) => ipcRenderer.invoke(ipcChannels.imageOperationCancel, input), regenerate: (input) => ipcRenderer.invoke(ipcChannels.imageOperationRegenerate, input), onChanged: (listener) => { const handler = (_event: Electron.IpcRendererEvent, operation: import('../shared/image-generation-contracts').ImageOperation): void => listener(operation) ipcRenderer.on(ipcChannels.imageOperationChanged, handler) return () => ipcRenderer.removeListener(ipcChannels.imageOperationChanged, handler) } }, list: () => ipcRenderer.invoke( ipcChannels.conversationsList ) as Promise, listSummaries: (detailIds = []) => ipcRenderer.invoke(ipcChannels.conversationsListSummaries, { detailIds }), get: (conversationId) => ipcRenderer.invoke(ipcChannels.conversationsGet, conversationId), search: (query, conversationIds = []) => ipcRenderer.invoke(ipcChannels.conversationsSearch, { query, conversationIds }), replace: async (conversations: ConversationSnapshot[]) => { await ipcRenderer.invoke( ipcChannels.conversationsReplace, conversations ) }, saveLocal: async (batch: LocalConversationSaveBatch) => { await ipcRenderer.invoke( ipcChannels.conversationsSaveLocal, batch ) }, setPinned: async (input) => { await ipcRenderer.invoke(ipcChannels.conversationsSetPinned, input) }, setStoryGraph: async (input) => { await ipcRenderer.invoke(ipcChannels.conversationsSetStoryGraph, input) }, branchLocal: (input: ConversationBranchInput) => ipcRenderer.invoke( ipcChannels.conversationsBranchLocal, input ) as Promise, deleteLocal: (conversationId: string) => ipcRenderer.invoke( ipcChannels.conversationsDeleteLocal, conversationId ) as Promise, onChanged: (listener) => { const handler = ( _event: Electron.IpcRendererEvent, conversationId?: string ): void => listener(conversationId) ipcRenderer.on(ipcChannels.conversationsChanged, handler) return () => ipcRenderer.removeListener( ipcChannels.conversationsChanged, handler ) } }, conversationQueue: { getAttachments: (itemId) => ipcRenderer.invoke(ipcChannels.conversationQueueAttachments, itemId), restoreToDraft: (itemId, draftText) => ipcRenderer.invoke(ipcChannels.conversationQueueRestoreDraft, { itemId, draftText }), list: (conversationId?: string) => ipcRenderer.invoke( ipcChannels.conversationQueueList, conversationId ), enqueueUser: (input) => ipcRenderer.invoke( ipcChannels.conversationQueueEnqueueUser, input ), remove: async (itemId: string) => { await ipcRenderer.invoke( ipcChannels.conversationQueueRemove, itemId ) }, interruptAndRun: async (itemId: string) => { await ipcRenderer.invoke( ipcChannels.conversationQueueInterruptAndRun, itemId ) }, releaseUser: async (itemId: string) => { await ipcRenderer.invoke( ipcChannels.conversationQueueReleaseUser, itemId ) }, ready: async (conversationId: string) => { await ipcRenderer.invoke( ipcChannels.conversationQueueReady, conversationId ) }, onChanged: (listener) => { const handler = ( _event: Electron.IpcRendererEvent, conversationId?: string ): void => listener(conversationId) ipcRenderer.on(ipcChannels.conversationQueueChanged, handler) return () => ipcRenderer.removeListener( ipcChannels.conversationQueueChanged, handler ) }, onDispatch: (listener) => { const handler = ( _event: Electron.IpcRendererEvent, dispatch: Parameters[0] ): void => listener(dispatch) ipcRenderer.on(ipcChannels.conversationQueueDispatch, handler) return () => ipcRenderer.removeListener( ipcChannels.conversationQueueDispatch, handler ) } }, workspace: { importFiles: (projectId, path) => ipcRenderer.invoke(ipcChannels.workspaceImportFiles, { projectId, path }), manage: (projectId, action) => ipcRenderer.invoke(ipcChannels.workspaceManage, { projectId, action }), getFileDiff: (projectId: string, path: string) => ipcRenderer.invoke(ipcChannels.workspaceFileDiff, { projectId, path }) as Promise, getChanges: (projectId: string) => ipcRenderer.invoke( ipcChannels.workspaceChangesGet, projectId ) as Promise, listDirectory: (projectId: string, path: string) => ipcRenderer.invoke(ipcChannels.workspaceDirectoryList, { projectId, path }) as Promise, readFile: ( projectId: string, path: string, offsetBytes?: number ) => ipcRenderer.invoke(ipcChannels.workspaceFileRead, { projectId, path, offsetBytes }) as Promise, openPath: async ( projectId: string, path: string, type: 'file' | 'directory' ) => { await ipcRenderer.invoke(ipcChannels.workspacePathOpen, { projectId, path, type }) } }, tasks: { list: () => ipcRenderer.invoke(ipcChannels.tasksList) as Promise, getExecutionStats: (input) => ipcRenderer.invoke(ipcChannels.tasksExecutionStats, input) as Promise, onExecutionStatsChanged: (listener) => { const handler = (): void => listener() ipcRenderer.on(ipcChannels.tasksExecutionStatsChanged, handler) return () => { ipcRenderer.removeListener(ipcChannels.tasksExecutionStatsChanged, handler) } }, setStatus: async ( taskId: string, status: 'completed' | 'cancelled' ) => { await ipcRenderer.invoke(ipcChannels.tasksSetStatus, { taskId, status }) } }, activityHistory: { get: () => ipcRenderer.invoke( ipcChannels.activityHistoryGet ) as Promise, replace: async ( records: ActivityRecord[], legacyHistoryMayBeIncomplete: boolean ) => { await ipcRenderer.invoke(ipcChannels.activityHistoryReplace, { records, legacyHistoryMayBeIncomplete }) }, update: (update: ActivityHistoryUpdate) => ipcRenderer.invoke(ipcChannels.activityHistoryUpdate, update) as Promise, clear: async () => { await ipcRenderer.invoke(ipcChannels.activityHistoryClear) }, page: (request: ActivityHistoryPageRequest) => ipcRenderer.invoke(ipcChannels.activityHistoryPage, request) as Promise, summary: (request: ActivityHistorySummaryRequest) => ipcRenderer.invoke(ipcChannels.activityHistorySummary, request) as Promise, reconcile: (request: ActivityHistoryReconcileRequest) => ipcRenderer.invoke(ipcChannels.activityHistoryReconcile, request) as Promise }, usage: { getTokenSummary: () => ipcRenderer.invoke( ipcChannels.tokenUsageSummary ) as Promise, onChanged: (listener) => { const handler = (): void => listener() ipcRenderer.on(ipcChannels.tokenUsageChanged, handler) return () => ipcRenderer.removeListener(ipcChannels.tokenUsageChanged, handler) } }, artifacts: { list: (projectId?: string) => ipcRenderer.invoke( ipcChannels.artifactsList, projectId ) as Promise, get: (artifactId: string) => ipcRenderer.invoke( ipcChannels.artifactsGet, artifactId ) as Promise, importFiles: (projectId?: string) => ipcRenderer.invoke( ipcChannels.artifactsImportFiles, projectId ) as Promise }, memory: { list: (scopeId?: string) => ipcRenderer.invoke( ipcChannels.memoryList, scopeId ) as Promise, create: (input: MemoryCreateInput) => ipcRenderer.invoke( ipcChannels.memoryCreate, input ) as Promise, setStatus: async ( memoryId: string, status: AssistantMemory['status'] ) => { await ipcRenderer.invoke(ipcChannels.memorySetStatus, { memoryId, status }) }, remove: async (memoryId: string) => { await ipcRenderer.invoke(ipcChannels.memoryRemove, memoryId) } }, schedules: { list: (projectId?: string) => ipcRenderer.invoke( ipcChannels.schedulesList, projectId ) as Promise, create: (input: ScheduleCreateInput) => ipcRenderer.invoke( ipcChannels.schedulesCreate, input ) as Promise, setEnabled: async (scheduleId: string, enabled: boolean) => { await ipcRenderer.invoke(ipcChannels.schedulesSetEnabled, { scheduleId, enabled }) }, remove: async (scheduleId: string) => { await ipcRenderer.invoke(ipcChannels.schedulesRemove, scheduleId) }, runNow: async (scheduleId: string) => { await ipcRenderer.invoke(ipcChannels.schedulesRunNow, scheduleId) } }, heartbeats: { list: (projectId?: string) => ipcRenderer.invoke(ipcChannels.heartbeatsList, { projectId }) as Promise, create: (input: HeartbeatCreateInput) => ipcRenderer.invoke( ipcChannels.heartbeatsCreate, input ) as Promise, update: (heartbeatId: string, input: HeartbeatUpdateInput) => ipcRenderer.invoke(ipcChannels.heartbeatsUpdate, { id: heartbeatId, config: input }) as Promise, setPaused: async (heartbeatId: string, paused: boolean) => { await ipcRenderer.invoke(ipcChannels.heartbeatsSetPaused, { id: heartbeatId, paused }) }, remove: async (heartbeatId: string) => { await ipcRenderer.invoke(ipcChannels.heartbeatsRemove, { id: heartbeatId }) }, runNow: (heartbeatId: string) => ipcRenderer.invoke(ipcChannels.heartbeatsRunNow, { id: heartbeatId, idempotencyKey: crypto.randomUUID() }) as Promise, history: (heartbeatId?: string) => ipcRenderer.invoke(ipcChannels.heartbeatsHistory, { configId: heartbeatId, limit: 200 }) as Promise<{ runs: AssistantHeartbeatRun[] entries: AssistantHeartbeatEntry[] }> }, supervision: { activity: (input) => ipcRenderer.invoke(ipcChannels.supervisionActivity, input), pause: (input) => ipcRenderer.invoke(ipcChannels.supervisionPause, input), cancel: (input) => ipcRenderer.invoke(ipcChannels.supervisionCancel, input), execution: () => ipcRenderer.invoke(ipcChannels.supervisionExecution), resume: (input) => ipcRenderer.invoke(ipcChannels.supervisionResume, input), batches: (input) => ipcRenderer.invoke(ipcChannels.supervisionBatches, input), overview: (input) => ipcRenderer.invoke(ipcChannels.supervisionOverview, input), run: (input: unknown) => ipcRenderer.invoke(ipcChannels.supervisionRun, input), graph: (input) => ipcRenderer.invoke(ipcChannels.supervisionGraph, input) as Promise>, source: (sourceId: string) => ipcRenderer.invoke(ipcChannels.supervisionSource, { sourceId }) as Promise | undefined>, sourceContext: (sourceId: string) => ipcRenderer.invoke(ipcChannels.supervisionSourceContext, { sourceId }) as Promise>, continueContext: (input) => ipcRenderer.invoke(ipcChannels.supervisionContinueContext, input) as Promise>, continue: async (input) => { await ipcRenderer.invoke(ipcChannels.supervisionContinue, input) }, knowledgePreview: (input) => ipcRenderer.invoke(ipcChannels.supervisionKnowledgePreview, input) as Promise>, knowledgeCommit: (input) => ipcRenderer.invoke(ipcChannels.supervisionKnowledgeCommit, input) as Promise>, entityAction: (input) => ipcRenderer.invoke(ipcChannels.supervisionEntityAction, input) as Promise, relationAction: (input) => ipcRenderer.invoke(ipcChannels.supervisionRelationAction, input) as Promise, suggestions: (input) => ipcRenderer.invoke(ipcChannels.supervisionSuggestions, input ?? {}), suggestionAction: (input) => ipcRenderer.invoke(ipcChannels.supervisionSuggestionAction, input), retrySuggestions: (input) => ipcRenderer.invoke(ipcChannels.supervisionRetrySuggestions, input), stories: (input) => ipcRenderer.invoke(ipcChannels.supervisionStories, input), storyAction: (input) => ipcRenderer.invoke(ipcChannels.supervisionStoryAction, input) as Promise, retryStories: (input) => ipcRenderer.invoke(ipcChannels.supervisionRetryStories, input) }, experts: { list: () => ipcRenderer.invoke( ipcChannels.expertsList ) as Promise, create: (input: ExpertCreateInput) => ipcRenderer.invoke( ipcChannels.expertsCreate, input ) as Promise, update: (expertId: string, input: ExpertUpdateInput) => ipcRenderer.invoke(ipcChannels.expertsUpdate, { expertId, input }) as Promise, remove: async (expertId: string) => { await ipcRenderer.invoke(ipcChannels.expertsRemove, expertId) } }, capabilities: { getSnapshot: () => ipcRenderer.invoke( ipcChannels.capabilitiesSnapshot ) as Promise, importSkill: (kind) => ipcRenderer.invoke( ipcChannels.capabilitiesImportSkill, kind ) as Promise, removeSkill: (skillId) => ipcRenderer.invoke( ipcChannels.capabilitiesRemoveSkill, skillId ) as Promise, setSkillEnabled: (skillId, enabled) => ipcRenderer.invoke(ipcChannels.capabilitiesToggleSkill, { skillId, enabled }) as Promise, setSkillAssignments: (skillId, assignments) => ipcRenderer.invoke(ipcChannels.capabilitiesAssignSkill, { skillId, assignments }) as Promise, setBuiltinMcpServerEnabled: ( serverId: BuiltinMcpServerId, enabled: boolean ) => ipcRenderer.invoke(ipcChannels.capabilitiesToggleBuiltinMcp, { serverId, enabled }) as Promise, updateObsidianSettings: (input) => ipcRenderer.invoke(ipcChannels.capabilitiesUpdateObsidianSettings, input) as Promise, testObsidianConnection: (input) => ipcRenderer.invoke(ipcChannels.capabilitiesTestObsidianConnection, input) as Promise, selectObsidianVault: () => ipcRenderer.invoke(ipcChannels.capabilitiesSelectObsidianVault) as Promise, setBuiltinMcpServerAssignments: ( serverId: BuiltinMcpServerId, assignments ) => ipcRenderer.invoke(ipcChannels.capabilitiesAssignBuiltinMcp, { serverId, assignments }) as Promise, saveMcpServer: (serverId, input) => ipcRenderer.invoke(ipcChannels.capabilitiesSaveMcp, { serverId, input }) as Promise, removeMcpServer: (serverId) => ipcRenderer.invoke( ipcChannels.capabilitiesRemoveMcp, serverId ) as Promise, testMcpServer: (serverId) => ipcRenderer.invoke( ipcChannels.capabilitiesTestMcp, serverId ) as Promise, setWebSearchEnabled: (enabled: boolean) => ipcRenderer.invoke( ipcChannels.capabilitiesToggleWebSearch, enabled ) as Promise, testWebSearch: () => ipcRenderer.invoke( ipcChannels.capabilitiesTestWebSearch ) as Promise, setComputerCapabilityEnabled: ( capabilityId: ComputerCapabilityId, enabled: boolean ) => ipcRenderer.invoke(ipcChannels.capabilitiesToggleComputer, { capabilityId, enabled }) as Promise, setComputerCapabilityBrowserProfile: ( capabilityId: ComputerCapabilityId, browserProfileId: string | null ) => ipcRenderer.invoke(ipcChannels.capabilitiesConfigureComputer, { capabilityId, browserProfileId }) as Promise, diagnoseComputerCapability: (capabilityId: ComputerCapabilityId) => ipcRenderer.invoke( ipcChannels.capabilitiesDiagnoseComputer, capabilityId ) as Promise, createBrowserProfile: (input: BrowserProfileCreateInput) => ipcRenderer.invoke( ipcChannels.capabilitiesCreateBrowserProfile, input ) as Promise, renameBrowserProfile: (input: BrowserProfileRenameInput) => ipcRenderer.invoke( ipcChannels.capabilitiesRenameBrowserProfile, input ) as Promise, setDefaultBrowserProfile: (profileId: string) => ipcRenderer.invoke(ipcChannels.capabilitiesDefaultBrowserProfile, { profileId }) as Promise, removeBrowserProfile: (profileId: string) => ipcRenderer.invoke(ipcChannels.capabilitiesRemoveBrowserProfile, { profileId }) as Promise }, runtimeExtensions: { getSnapshot: () => ipcRenderer.invoke( ipcChannels.runtimeExtensionsSnapshot ) as Promise, apply: (action: RuntimeExtensionAction) => ipcRenderer.invoke( ipcChannels.runtimeExtensionsApply, action ) as Promise }, runtimeCustomization: { getSettings: () => ipcRenderer.invoke( ipcChannels.runtimeCustomizationGet ) as Promise, updateSettings: (settings: RuntimeCustomizationSettings) => ipcRenderer.invoke( ipcChannels.runtimeCustomizationUpdate, settings ) as Promise, getNativeSnapshot: (input: RuntimeNativeSnapshotInput) => ipcRenderer.invoke( ipcChannels.runtimeNativeSnapshot, input ) as Promise }, context: { imageCapability: (conversationId, runtimeSelection) => ipcRenderer.invoke(ipcChannels.contextImageCapability, { conversationId, runtimeSelection }), copyToDraft: (conversationId, id, operationId) => ipcRenderer.invoke(ipcChannels.contextCopyToDraft, { conversationId, id, operationId }), pendingParsing: (conversationId) => ipcRenderer.invoke(ipcChannels.contextPendingParsing, conversationId), retryParsing: (conversationId, id, operationId) => ipcRenderer.invoke(ipcChannels.contextRetryParsing, { conversationId, id, operationId }), dismissParsing: (conversationId, id) => ipcRenderer.invoke(ipcChannels.contextDismissParsing, { conversationId, id }), cancelImport: (operationId) => ipcRenderer.invoke(ipcChannels.contextCancelImport, operationId), reparseDraft: (conversationId, id, operationId) => ipcRenderer.invoke(ipcChannels.contextReparse, { conversationId, id, operationId }), cancelParsing: (operationId) => ipcRenderer.invoke(ipcChannels.contextCancelParsing, operationId), sendOriginal: (conversationId, id) => ipcRenderer.invoke(ipcChannels.contextSendOriginal, { conversationId, id }), openOriginal: (id) => ipcRenderer.invoke(ipcChannels.contextOpenOriginal, id), readOutput: (input) => ipcRenderer.invoke(ipcChannels.contextReadOutput, input), addResultImages: (conversationId, resultId, imageIds) => ipcRenderer.invoke(ipcChannels.contextAddResultImages, { conversationId, resultId, imageIds }), onDraftChanged: (listener) => { const handler = (_event: Electron.IpcRendererEvent, conversationId: string, attachments: ContextAttachment[]): void => listener(conversationId, attachments) ipcRenderer.on(ipcChannels.contextDraftChanged, handler) return () => ipcRenderer.removeListener(ipcChannels.contextDraftChanged, handler) }, getDraft: (conversationId) => ipcRenderer.invoke(ipcChannels.contextGetDraft, { conversationId }), saveDraft: (conversationId, ids) => ipcRenderer.invoke(ipcChannels.contextSaveDraft, { conversationId, ids }), getFilePath: (file) => webUtils.getPathForFile(file), importFiles: (paths, conversationId) => ipcRenderer.invoke( ipcChannels.contextImportFiles, { paths, ...(conversationId ? { conversationId } : {}) } ) as Promise, selectFiles: (conversationId) => ipcRenderer.invoke( ipcChannels.contextSelectFiles, ...(conversationId ? [conversationId] : []) ) as Promise, onFileSelectionProgress: (listener) => { const handler = ( _event: Electron.IpcRendererEvent, progress: ContextFileSelectionProgress ): void => listener(progress) ipcRenderer.on(ipcChannels.contextFileSelectionProgress, handler) return () => ipcRenderer.removeListener( ipcChannels.contextFileSelectionProgress, handler ) }, addPastedImage: (input: PastedImageInput) => ipcRenderer.invoke( ipcChannels.contextAddPastedImage, input ) as Promise, captureScreen: () => ipcRenderer.invoke( ipcChannels.contextCaptureScreen ) as Promise, listWindows: () => ipcRenderer.invoke( ipcChannels.contextListWindows ) as Promise, captureWindow: (sourceId) => ipcRenderer.invoke( ipcChannels.contextCaptureWindow, { sourceId } ) as Promise, readClipboard: () => ipcRenderer.invoke( ipcChannels.contextReadClipboard ) as Promise, remove: async (contextId: string) => { await ipcRenderer.invoke(ipcChannels.contextRemove, contextId) } }, magicNotes: { search: (input) => ipcRenderer.invoke(ipcChannels.magicNotesSearch, input) as Promise, list: () => ipcRenderer.invoke( ipcChannels.magicNotesList ) as Promise, get: (noteId: string) => ipcRenderer.invoke(ipcChannels.magicNotesGet, { noteId }) as Promise, create: (input) => ipcRenderer.invoke( ipcChannels.magicNotesCreate, input ) as Promise, update: (input) => ipcRenderer.invoke( ipcChannels.magicNotesUpdate, input ) as Promise, remove: async (noteId: string) => { await ipcRenderer.invoke(ipcChannels.magicNotesDelete, { noteId }) }, createTag: (input) => ipcRenderer.invoke( ipcChannels.magicNotesCreateTag, input ) as Promise, renameTag: (input) => ipcRenderer.invoke( ipcChannels.magicNotesRenameTag, input ) as Promise, removeTag: async (tagId: string) => { await ipcRenderer.invoke(ipcChannels.magicNotesDeleteTag, { tagId }) }, createEntry: (input) => ipcRenderer.invoke( ipcChannels.magicNotesCreateEntry, input ) as Promise, updateEntry: (input) => ipcRenderer.invoke( ipcChannels.magicNotesUpdateEntry, input ) as Promise, removeEntry: (entryId: string) => ipcRenderer.invoke(ipcChannels.magicNotesDeleteEntry, { entryId }) as Promise, analyze: (entryId, options) => ipcRenderer.invoke(ipcChannels.magicNotesAnalyze, { entryId, ...options }) as Promise, analyzeDraft: (content, options) => ipcRenderer.invoke( ipcChannels.magicNotesAnalyzeDraft, { content, ...options } ) as Promise, listTodos: () => ipcRenderer.invoke( ipcChannels.magicTodosList ) as Promise, getTodoStatus: () => ipcRenderer.invoke( ipcChannels.magicTodosStatus ) as Promise, updateTodo: (input) => ipcRenderer.invoke( ipcChannels.magicTodosUpdate, input ) as Promise, analyzeTodo: (todoId, options) => ipcRenderer.invoke(ipcChannels.magicTodosAnalyze, { todoId, ...options }) as Promise, onAnalysisEvent: (listener) => { const handler = ( _event: Electron.IpcRendererEvent, payload: MagicNoteAnalysisStreamEvent ): void => listener(payload) ipcRenderer.on(ipcChannels.magicNotesAnalysisEvent, handler) return () => ipcRenderer.removeListener( ipcChannels.magicNotesAnalysisEvent, handler ) }, onChanged: (listener) => { const handler = (): void => listener() ipcRenderer.on(ipcChannels.magicNotesChanged, handler) return () => ipcRenderer.removeListener(ipcChannels.magicNotesChanged, handler) }, onTodoStatusChanged: (listener) => { const handler = (): void => listener() ipcRenderer.on(ipcChannels.magicTodosStatusChanged, handler) return () => ipcRenderer.removeListener( ipcChannels.magicTodosStatusChanged, handler ) } }, knowledge: { externalInstancesList: () => ipcRenderer.invoke(ipcChannels.externalInstancesList), externalInstancesSave: (input) => ipcRenderer.invoke(ipcChannels.externalInstancesSave,input), externalInstancesTest: (input) => ipcRenderer.invoke(ipcChannels.externalInstancesTest,input), externalInstancesSetEnabled: (input) => ipcRenderer.invoke(ipcChannels.externalInstancesSetEnabled,input), externalInstancesDelete: (input) => ipcRenderer.invoke(ipcChannels.externalInstancesDelete,input), externalCatalogList: (input) => ipcRenderer.invoke(ipcChannels.externalCatalogList,input), externalCatalogGet: (input) => ipcRenderer.invoke(ipcChannels.externalCatalogGet,input), externalBindingsCreate: (input) => ipcRenderer.invoke(ipcChannels.externalBindingsCreate,input), externalBindingsUpdate: (input) => ipcRenderer.invoke(ipcChannels.externalBindingsUpdate,input), externalRetrievalTest: (input) => ipcRenderer.invoke(ipcChannels.externalRetrievalTest,input), getSnapshot: (libraryId?: string) => ipcRenderer.invoke( ipcChannels.knowledgeSnapshot, libraryId ) as Promise, createLibrary: (input) => ipcRenderer.invoke( ipcChannels.knowledgeCreateLibrary, input ) as Promise, updateLibrary: async (libraryId, update) => { await ipcRenderer.invoke(ipcChannels.knowledgeUpdateLibrary, { libraryId, ...update }) }, deleteLibrary: async (libraryId) => { await ipcRenderer.invoke( ipcChannels.knowledgeDeleteLibrary, libraryId ) }, reextractGraph: (libraryId) => ipcRenderer.invoke( ipcChannels.knowledgeReextractGraph, libraryId ) as Promise, selectFiles: async (libraryId, graphStrategy) => { await ipcRenderer.invoke(ipcChannels.knowledgeSelectFiles, { libraryId, graphStrategy }) }, selectDirectory: async (libraryId, graphStrategy) => { await ipcRenderer.invoke( ipcChannels.knowledgeSelectDirectory, { libraryId, graphStrategy } ) }, importDroppedFiles: async (libraryId, files, graphStrategy) => { const paths = files .map((file) => webUtils.getPathForFile(file)) .filter(Boolean) await ipcRenderer.invoke(ipcChannels.knowledgeImportPaths, { libraryId, paths, graphStrategy }) }, importPaths: async (libraryId, paths, graphStrategy) => { await ipcRenderer.invoke(ipcChannels.knowledgeImportPaths, { libraryId, paths, graphStrategy }) }, importUrl: async (libraryId, url, graphStrategy) => { await ipcRenderer.invoke(ipcChannels.knowledgeImportUrl, { libraryId, url, graphStrategy }) }, syncSource: async (sourceId) => { await ipcRenderer.invoke(ipcChannels.knowledgeSyncSource, sourceId) }, pauseSource: async (sourceId) => { await ipcRenderer.invoke(ipcChannels.knowledgePauseSource, sourceId) }, retrySource: async (sourceId) => { await ipcRenderer.invoke(ipcChannels.knowledgeRetrySource, sourceId) }, removeSource: async (sourceId) => { await ipcRenderer.invoke(ipcChannels.knowledgeRemoveSource, sourceId) }, search: (libraryIds, query) => ipcRenderer.invoke(ipcChannels.knowledgeSearch, { libraryIds, query }) as Promise, retrieve: (input: KnowledgeRetrieveInput) => ipcRenderer.invoke( ipcChannels.knowledgeRetrieve, input ) as Promise, updateSettings: (input: KnowledgeSettingsUpdateInput) => ipcRenderer.invoke( ipcChannels.knowledgeUpdateSettings, input ) as Promise, listChunks: (input: KnowledgeChunksListInput) => ipcRenderer.invoke( ipcChannels.knowledgeListChunks, input ) as Promise, updateChunk: async (input: KnowledgeChunkUpdateInput) => { await ipcRenderer.invoke(ipcChannels.knowledgeUpdateChunk, input) }, deleteChunk: async (input: KnowledgeChunkDeleteInput) => { await ipcRenderer.invoke(ipcChannels.knowledgeDeleteChunk, input) }, rebuildDocument: (input: KnowledgeDocumentRebuildInput) => ipcRenderer.invoke( ipcChannels.knowledgeRebuildDocument, input ) as Promise, openDocumentSource: async (input: KnowledgeDocumentOpenInput) => { await ipcRenderer.invoke( ipcChannels.knowledgeOpenDocumentSource, input ) }, rebuildLibrary: (input: KnowledgeLibraryRebuildInput) => ipcRenderer.invoke( ipcChannels.knowledgeRebuildLibrary, input ) as Promise<{ rebuilt: number; failed: number }>, cancelRebuild: (knowledgeBaseId: string) => ipcRenderer.invoke( ipcChannels.knowledgeCancelRebuild, knowledgeBaseId ) as Promise, getEmbeddingIndex: (knowledgeBaseId: string) => ipcRenderer.invoke(ipcChannels.knowledgeEmbeddingIndexGet, { knowledgeBaseId }) as Promise, rebuildEmbeddingIndex: (knowledgeBaseId: string) => ipcRenderer.invoke( ipcChannels.knowledgeEmbeddingIndexRebuild, { knowledgeBaseId } ) as Promise, cancelEmbeddingIndex: ( knowledgeBaseId: string, jobId: string ) => ipcRenderer.invoke( ipcChannels.knowledgeEmbeddingIndexCancel, { knowledgeBaseId, jobId } ) as Promise, cancelTask: (taskId: string) => ipcRenderer.invoke( ipcChannels.knowledgeTaskCancel, { taskId } ) as Promise, retryTask: async (taskId: string) => { await ipcRenderer.invoke( ipcChannels.knowledgeTaskRetry, { taskId } ) }, getReferenceContext: (input: KnowledgeReferenceContextInput) => ipcRenderer.invoke( ipcChannels.knowledgeReferenceContext, input ) as Promise, openReferenceSource: async (input: KnowledgeReferenceOpenInput) => { await ipcRenderer.invoke( ipcChannels.knowledgeOpenReferenceSource, input ) }, createEntity: async (libraryId, input) => { await ipcRenderer.invoke(ipcChannels.knowledgeCreateEntity, { libraryId, input }) }, updateEntity: async (entityId, update) => { await ipcRenderer.invoke(ipcChannels.knowledgeUpdateEntity, { entityId, update }) }, moveEntity: async (entityId, position) => { await ipcRenderer.invoke(ipcChannels.knowledgeMoveEntity, { entityId, position }) }, deleteEntity: async (entityId) => { await ipcRenderer.invoke(ipcChannels.knowledgeDeleteEntity, entityId) }, mergeEntities: async (sourceEntityId, targetEntityId) => { await ipcRenderer.invoke(ipcChannels.knowledgeMergeEntities, { sourceEntityId, targetEntityId }) }, createRelation: async (libraryId, input) => { await ipcRenderer.invoke(ipcChannels.knowledgeCreateRelation, { libraryId, input }) }, updateRelation: async (relationId, input) => { await ipcRenderer.invoke(ipcChannels.knowledgeUpdateRelation, { relationId, input }) }, deleteRelation: async (relationId) => { await ipcRenderer.invoke( ipcChannels.knowledgeDeleteRelation, relationId ) } } } contextBridge.exposeInMainWorld('goodbuddy', desktopApi)