2026-03-17 16:25:21 +02:00
|
|
|
const { contextBridge, ipcRenderer } = require('electron');
|
2026-03-20 20:13:58 +02:00
|
|
|
const { IPC_CHANNELS } = require('./ipc/channels');
|
2026-03-17 16:25:21 +02:00
|
|
|
|
|
|
|
|
contextBridge.exposeInMainWorld('electronAPI', {
|
|
|
|
|
versions: {
|
|
|
|
|
electron: process.versions.electron,
|
|
|
|
|
node: process.versions.node,
|
|
|
|
|
chrome: process.versions.chrome,
|
|
|
|
|
platform: process.platform,
|
|
|
|
|
},
|
2026-03-20 20:13:58 +02:00
|
|
|
openExternal: (url: string) => ipcRenderer.send(IPC_CHANNELS.OPEN_EXTERNAL, url),
|
|
|
|
|
getAppVersion: () => ipcRenderer.invoke(IPC_CHANNELS.GET_APP_VERSION),
|
2026-03-17 16:25:21 +02:00
|
|
|
onDeepLink: (callback: (url: string) => void) => {
|
|
|
|
|
const listener = (_event: unknown, url: string) => callback(url);
|
2026-03-20 20:13:58 +02:00
|
|
|
ipcRenderer.on(IPC_CHANNELS.DEEP_LINK, listener);
|
2026-03-17 16:25:21 +02:00
|
|
|
return () => {
|
2026-03-20 20:13:58 +02:00
|
|
|
ipcRenderer.removeListener(IPC_CHANNELS.DEEP_LINK, listener);
|
2026-03-17 16:25:21 +02:00
|
|
|
};
|
|
|
|
|
},
|
2026-04-24 19:14:37 +02:00
|
|
|
onChatScreenCapture: (callback: (dataUrl: string) => void) => {
|
|
|
|
|
const listener = (_event: unknown, dataUrl: string) => callback(dataUrl);
|
|
|
|
|
ipcRenderer.on(IPC_CHANNELS.CHAT_SCREEN_CAPTURE, listener);
|
|
|
|
|
return () => {
|
|
|
|
|
ipcRenderer.removeListener(IPC_CHANNELS.CHAT_SCREEN_CAPTURE, listener);
|
|
|
|
|
};
|
|
|
|
|
},
|
2026-03-25 16:22:32 +02:00
|
|
|
getQuickAskText: () => ipcRenderer.invoke(IPC_CHANNELS.QUICK_ASK_TEXT),
|
2026-03-27 20:35:29 +02:00
|
|
|
setQuickAskMode: (mode: string) => ipcRenderer.invoke(IPC_CHANNELS.SET_QUICK_ASK_MODE, mode),
|
|
|
|
|
getQuickAskMode: () => ipcRenderer.invoke(IPC_CHANNELS.GET_QUICK_ASK_MODE),
|
2026-03-26 20:10:10 +02:00
|
|
|
replaceText: (text: string) => ipcRenderer.invoke(IPC_CHANNELS.REPLACE_TEXT, text),
|
2026-04-02 13:26:32 +02:00
|
|
|
// Permissions
|
|
|
|
|
getPermissionsStatus: () => ipcRenderer.invoke(IPC_CHANNELS.GET_PERMISSIONS_STATUS),
|
|
|
|
|
requestAccessibility: () => ipcRenderer.invoke(IPC_CHANNELS.REQUEST_ACCESSIBILITY),
|
2026-04-03 19:57:48 +02:00
|
|
|
requestScreenRecording: () => ipcRenderer.invoke(IPC_CHANNELS.REQUEST_SCREEN_RECORDING),
|
2026-04-27 18:49:15 +02:00
|
|
|
captureFullScreen: () => ipcRenderer.invoke(IPC_CHANNELS.CAPTURE_FULL_SCREEN),
|
2026-04-02 13:26:32 +02:00
|
|
|
restartApp: () => ipcRenderer.invoke(IPC_CHANNELS.RESTART_APP),
|
2026-04-02 11:17:49 +05:30
|
|
|
// Folder sync
|
|
|
|
|
selectFolder: () => ipcRenderer.invoke(IPC_CHANNELS.FOLDER_SYNC_SELECT_FOLDER),
|
|
|
|
|
addWatchedFolder: (config: any) => ipcRenderer.invoke(IPC_CHANNELS.FOLDER_SYNC_ADD_FOLDER, config),
|
|
|
|
|
removeWatchedFolder: (folderPath: string) => ipcRenderer.invoke(IPC_CHANNELS.FOLDER_SYNC_REMOVE_FOLDER, folderPath),
|
|
|
|
|
getWatchedFolders: () => ipcRenderer.invoke(IPC_CHANNELS.FOLDER_SYNC_GET_FOLDERS),
|
|
|
|
|
getWatcherStatus: () => ipcRenderer.invoke(IPC_CHANNELS.FOLDER_SYNC_GET_STATUS),
|
|
|
|
|
onFileChanged: (callback: (data: any) => void) => {
|
|
|
|
|
const listener = (_event: unknown, data: any) => callback(data);
|
|
|
|
|
ipcRenderer.on(IPC_CHANNELS.FOLDER_SYNC_FILE_CHANGED, listener);
|
|
|
|
|
return () => {
|
|
|
|
|
ipcRenderer.removeListener(IPC_CHANNELS.FOLDER_SYNC_FILE_CHANGED, listener);
|
|
|
|
|
};
|
|
|
|
|
},
|
|
|
|
|
onWatcherReady: (callback: (data: any) => void) => {
|
|
|
|
|
const listener = (_event: unknown, data: any) => callback(data);
|
|
|
|
|
ipcRenderer.on(IPC_CHANNELS.FOLDER_SYNC_WATCHER_READY, listener);
|
|
|
|
|
return () => {
|
|
|
|
|
ipcRenderer.removeListener(IPC_CHANNELS.FOLDER_SYNC_WATCHER_READY, listener);
|
|
|
|
|
};
|
|
|
|
|
},
|
|
|
|
|
pauseWatcher: () => ipcRenderer.invoke(IPC_CHANNELS.FOLDER_SYNC_PAUSE),
|
|
|
|
|
resumeWatcher: () => ipcRenderer.invoke(IPC_CHANNELS.FOLDER_SYNC_RESUME),
|
2026-04-02 22:20:11 +05:30
|
|
|
signalRendererReady: () => ipcRenderer.invoke(IPC_CHANNELS.FOLDER_SYNC_RENDERER_READY),
|
2026-04-03 00:40:49 +05:30
|
|
|
getPendingFileEvents: () => ipcRenderer.invoke(IPC_CHANNELS.FOLDER_SYNC_GET_PENDING_EVENTS),
|
|
|
|
|
acknowledgeFileEvents: (eventIds: string[]) => ipcRenderer.invoke(IPC_CHANNELS.FOLDER_SYNC_ACK_EVENTS, eventIds),
|
2026-04-08 15:46:52 +05:30
|
|
|
listFolderFiles: (config: any) => ipcRenderer.invoke(IPC_CHANNELS.FOLDER_SYNC_LIST_FILES, config),
|
2026-04-08 16:07:25 +05:30
|
|
|
seedFolderMtimes: (folderPath: string, mtimes: Record<string, number>) =>
|
|
|
|
|
ipcRenderer.invoke(IPC_CHANNELS.FOLDER_SYNC_SEED_MTIMES, folderPath, mtimes),
|
2026-04-03 00:28:24 +05:30
|
|
|
|
2026-04-03 02:56:24 +05:30
|
|
|
// Browse files via native dialog
|
|
|
|
|
browseFiles: () => ipcRenderer.invoke(IPC_CHANNELS.BROWSE_FILES),
|
2026-04-03 00:28:24 +05:30
|
|
|
readLocalFiles: (paths: string[]) => ipcRenderer.invoke(IPC_CHANNELS.READ_LOCAL_FILES, paths),
|
2026-04-27 21:00:40 +05:30
|
|
|
readAgentLocalFileText: (virtualPath: string, searchSpaceId?: number | null) =>
|
|
|
|
|
ipcRenderer.invoke(IPC_CHANNELS.READ_AGENT_LOCAL_FILE_TEXT, virtualPath, searchSpaceId),
|
|
|
|
|
writeAgentLocalFileText: (virtualPath: string, content: string, searchSpaceId?: number | null) =>
|
|
|
|
|
ipcRenderer.invoke(IPC_CHANNELS.WRITE_AGENT_LOCAL_FILE_TEXT, virtualPath, content, searchSpaceId),
|
2026-04-06 23:02:25 -07:00
|
|
|
|
|
|
|
|
// Auth token sync across windows
|
|
|
|
|
getAuthTokens: () => ipcRenderer.invoke(IPC_CHANNELS.GET_AUTH_TOKENS),
|
|
|
|
|
setAuthTokens: (bearer: string, refresh: string) =>
|
|
|
|
|
ipcRenderer.invoke(IPC_CHANNELS.SET_AUTH_TOKENS, { bearer, refresh }),
|
2026-04-07 00:43:40 -07:00
|
|
|
|
|
|
|
|
// Keyboard shortcut configuration
|
|
|
|
|
getShortcuts: () => ipcRenderer.invoke(IPC_CHANNELS.GET_SHORTCUTS),
|
|
|
|
|
setShortcuts: (config: Record<string, string>) =>
|
|
|
|
|
ipcRenderer.invoke(IPC_CHANNELS.SET_SHORTCUTS, config),
|
2026-04-07 04:45:48 -07:00
|
|
|
|
2026-04-20 12:42:06 -07:00
|
|
|
// Launch on system startup
|
|
|
|
|
getAutoLaunch: () => ipcRenderer.invoke(IPC_CHANNELS.GET_AUTO_LAUNCH),
|
|
|
|
|
setAutoLaunch: (enabled: boolean, openAsHidden?: boolean) =>
|
|
|
|
|
ipcRenderer.invoke(IPC_CHANNELS.SET_AUTO_LAUNCH, { enabled, openAsHidden }),
|
|
|
|
|
|
2026-04-07 04:45:48 -07:00
|
|
|
// Active search space
|
|
|
|
|
getActiveSearchSpace: () => ipcRenderer.invoke(IPC_CHANNELS.GET_ACTIVE_SEARCH_SPACE),
|
|
|
|
|
setActiveSearchSpace: (id: string) =>
|
|
|
|
|
ipcRenderer.invoke(IPC_CHANNELS.SET_ACTIVE_SEARCH_SPACE, id),
|
2026-04-18 14:35:14 -07:00
|
|
|
|
|
|
|
|
// Analytics bridge — lets posthog-js running inside the Next.js renderer
|
|
|
|
|
// mirror identify/reset/capture into the Electron main-process PostHog
|
|
|
|
|
// client so desktop-only events are attributed to the logged-in user.
|
|
|
|
|
analyticsIdentify: (userId: string, properties?: Record<string, unknown>) =>
|
|
|
|
|
ipcRenderer.invoke(IPC_CHANNELS.ANALYTICS_IDENTIFY, { userId, properties }),
|
|
|
|
|
analyticsReset: () => ipcRenderer.invoke(IPC_CHANNELS.ANALYTICS_RESET),
|
|
|
|
|
analyticsCapture: (event: string, properties?: Record<string, unknown>) =>
|
|
|
|
|
ipcRenderer.invoke(IPC_CHANNELS.ANALYTICS_CAPTURE, { event, properties }),
|
|
|
|
|
getAnalyticsContext: () => ipcRenderer.invoke(IPC_CHANNELS.ANALYTICS_GET_CONTEXT),
|
2026-04-23 15:45:59 +05:30
|
|
|
// Agent filesystem mode
|
2026-04-27 21:00:40 +05:30
|
|
|
getAgentFilesystemSettings: (searchSpaceId?: number | null) =>
|
|
|
|
|
ipcRenderer.invoke(IPC_CHANNELS.AGENT_FILESYSTEM_GET_SETTINGS, searchSpaceId),
|
|
|
|
|
getAgentFilesystemMounts: (searchSpaceId?: number | null) =>
|
|
|
|
|
ipcRenderer.invoke(IPC_CHANNELS.AGENT_FILESYSTEM_GET_MOUNTS, searchSpaceId),
|
|
|
|
|
listAgentFilesystemFiles: (options: {
|
|
|
|
|
rootPath: string;
|
|
|
|
|
searchSpaceId?: number | null;
|
|
|
|
|
excludePatterns?: string[] | null;
|
|
|
|
|
fileExtensions?: string[] | null;
|
|
|
|
|
}) => ipcRenderer.invoke(IPC_CHANNELS.AGENT_FILESYSTEM_LIST_FILES, options),
|
2026-04-27 23:08:32 +05:30
|
|
|
startAgentFilesystemTreeWatch: (options: {
|
|
|
|
|
searchSpaceId?: number | null;
|
|
|
|
|
rootPaths: string[];
|
|
|
|
|
excludePatterns?: string[] | null;
|
|
|
|
|
fileExtensions?: string[] | null;
|
|
|
|
|
}) => ipcRenderer.invoke(IPC_CHANNELS.AGENT_FILESYSTEM_TREE_WATCH_START, options),
|
|
|
|
|
stopAgentFilesystemTreeWatch: (searchSpaceId?: number | null) =>
|
|
|
|
|
ipcRenderer.invoke(IPC_CHANNELS.AGENT_FILESYSTEM_TREE_WATCH_STOP, searchSpaceId),
|
|
|
|
|
onAgentFilesystemTreeDirty: (
|
|
|
|
|
callback: (data: {
|
|
|
|
|
searchSpaceId: number | null;
|
|
|
|
|
reason: 'watcher_event' | 'safety_poll';
|
|
|
|
|
rootPath: string;
|
|
|
|
|
changedPath: string | null;
|
|
|
|
|
timestamp: number;
|
|
|
|
|
}) => void
|
|
|
|
|
) => {
|
|
|
|
|
const listener = (
|
|
|
|
|
_event: unknown,
|
|
|
|
|
data: {
|
|
|
|
|
searchSpaceId: number | null;
|
|
|
|
|
reason: 'watcher_event' | 'safety_poll';
|
|
|
|
|
rootPath: string;
|
|
|
|
|
changedPath: string | null;
|
|
|
|
|
timestamp: number;
|
|
|
|
|
}
|
|
|
|
|
) => callback(data);
|
|
|
|
|
ipcRenderer.on(IPC_CHANNELS.AGENT_FILESYSTEM_TREE_DIRTY, listener);
|
|
|
|
|
return () => {
|
|
|
|
|
ipcRenderer.removeListener(IPC_CHANNELS.AGENT_FILESYSTEM_TREE_DIRTY, listener);
|
|
|
|
|
};
|
|
|
|
|
},
|
2026-04-23 15:45:59 +05:30
|
|
|
setAgentFilesystemSettings: (settings: {
|
|
|
|
|
mode?: "cloud" | "desktop_local_folder";
|
2026-04-24 01:45:13 +05:30
|
|
|
localRootPaths?: string[] | null;
|
2026-04-27 21:00:40 +05:30
|
|
|
}, searchSpaceId?: number | null) =>
|
|
|
|
|
ipcRenderer.invoke(IPC_CHANNELS.AGENT_FILESYSTEM_SET_SETTINGS, { searchSpaceId, settings }),
|
2026-04-23 15:45:59 +05:30
|
|
|
pickAgentFilesystemRoot: () => ipcRenderer.invoke(IPC_CHANNELS.AGENT_FILESYSTEM_PICK_ROOT),
|
2026-03-17 16:25:21 +02:00
|
|
|
});
|