feat: add macOS permission infrastructure for autocomplete

This commit is contained in:
CREDO23 2026-04-02 13:26:32 +02:00
parent bcc227a4dd
commit ec2b7851b6
5 changed files with 91 additions and 0 deletions

View file

@ -6,4 +6,9 @@ export const IPC_CHANNELS = {
SET_QUICK_ASK_MODE: 'set-quick-ask-mode',
GET_QUICK_ASK_MODE: 'get-quick-ask-mode',
REPLACE_TEXT: 'replace-text',
// Permissions
GET_PERMISSIONS_STATUS: 'get-permissions-status',
REQUEST_ACCESSIBILITY: 'request-accessibility',
REQUEST_INPUT_MONITORING: 'request-input-monitoring',
RESTART_APP: 'restart-app',
} as const;

View file

@ -1,5 +1,11 @@
import { app, ipcMain, shell } from 'electron';
import { IPC_CHANNELS } from './channels';
import {
getPermissionsStatus,
requestAccessibility,
requestInputMonitoring,
restartApp,
} from '../modules/permissions';
export function registerIpcHandlers(): void {
ipcMain.on(IPC_CHANNELS.OPEN_EXTERNAL, (_event, url: string) => {
@ -16,4 +22,20 @@ export function registerIpcHandlers(): void {
ipcMain.handle(IPC_CHANNELS.GET_APP_VERSION, () => {
return app.getVersion();
});
ipcMain.handle(IPC_CHANNELS.GET_PERMISSIONS_STATUS, () => {
return getPermissionsStatus();
});
ipcMain.handle(IPC_CHANNELS.REQUEST_ACCESSIBILITY, () => {
requestAccessibility();
});
ipcMain.handle(IPC_CHANNELS.REQUEST_INPUT_MONITORING, () => {
requestInputMonitoring();
});
ipcMain.handle(IPC_CHANNELS.RESTART_APP, () => {
restartApp();
});
}

View file

@ -0,0 +1,50 @@
import { app } from 'electron';
type PermissionStatus = 'authorized' | 'denied' | 'not determined' | 'restricted' | 'limited';
export interface PermissionsStatus {
accessibility: PermissionStatus;
inputMonitoring: PermissionStatus;
}
function isMac(): boolean {
return process.platform === 'darwin';
}
function getNodeMacPermissions() {
return require('node-mac-permissions');
}
export function getPermissionsStatus(): PermissionsStatus {
if (!isMac()) {
return { accessibility: 'authorized', inputMonitoring: 'authorized' };
}
const perms = getNodeMacPermissions();
return {
accessibility: perms.getAuthStatus('accessibility'),
inputMonitoring: perms.getAuthStatus('input-monitoring'),
};
}
export function allPermissionsGranted(): boolean {
const status = getPermissionsStatus();
return status.accessibility === 'authorized' && status.inputMonitoring === 'authorized';
}
export function requestAccessibility(): void {
if (!isMac()) return;
const perms = getNodeMacPermissions();
perms.askForAccessibilityAccess();
}
export async function requestInputMonitoring(): Promise<string> {
if (!isMac()) return 'authorized';
const perms = getNodeMacPermissions();
return perms.askForInputMonitoringAccess('listen');
}
export function restartApp(): void {
app.relaunch();
app.exit(0);
}

View file

@ -21,4 +21,9 @@ contextBridge.exposeInMainWorld('electronAPI', {
setQuickAskMode: (mode: string) => ipcRenderer.invoke(IPC_CHANNELS.SET_QUICK_ASK_MODE, mode),
getQuickAskMode: () => ipcRenderer.invoke(IPC_CHANNELS.GET_QUICK_ASK_MODE),
replaceText: (text: string) => ipcRenderer.invoke(IPC_CHANNELS.REPLACE_TEXT, text),
// Permissions
getPermissionsStatus: () => ipcRenderer.invoke(IPC_CHANNELS.GET_PERMISSIONS_STATUS),
requestAccessibility: () => ipcRenderer.invoke(IPC_CHANNELS.REQUEST_ACCESSIBILITY),
requestInputMonitoring: () => ipcRenderer.invoke(IPC_CHANNELS.REQUEST_INPUT_MONITORING),
restartApp: () => ipcRenderer.invoke(IPC_CHANNELS.RESTART_APP),
});