import { app } from 'electron'; import { mkdir, rm, writeFile } from 'node:fs/promises'; import { dirname, join } from 'node:path'; import { CONFIG_KEYS } from '@runtime/lib/constants'; import configManager from '@electron/service/config-service'; import { logManager } from '@electron/service/logger'; const LINUX_AUTOSTART_DIR = join('.config', 'autostart'); function getApplicationName(): string { const applicationName = typeof app.getName === 'function' ? app.getName() : ''; return applicationName.trim() || 'zn-ai'; } function sanitizeDesktopFileName(name: string): string { const normalized = name .trim() .toLowerCase() .replace(/[^a-z0-9]+/g, '-') .replace(/^-+|-+$/g, ''); return normalized || 'zn-ai'; } function quoteDesktopArg(value: string): string { if (!value) return '""'; const escaped = value.replace(/(["\\`$])/g, '\\$1'); if (/[\s"'\\`$]/.test(value)) { return `"${escaped}"`; } return value; } function getLinuxExecCommand(): string { if (app.isPackaged) { return quoteDesktopArg(process.execPath); } const launchArgs = process.argv.slice(1).filter(Boolean); const commandParts = [process.execPath, ...launchArgs].map(quoteDesktopArg); return commandParts.join(' '); } function getLinuxDesktopEntryPath(): string { const desktopFileName = `${sanitizeDesktopFileName(getApplicationName())}.desktop`; return join(app.getPath('home'), LINUX_AUTOSTART_DIR, desktopFileName); } function getLinuxDesktopEntry(): string { const applicationName = getApplicationName(); return [ '[Desktop Entry]', 'Type=Application', 'Version=1.0', `Name=${applicationName}`, `Comment=${applicationName} desktop application`, `Exec=${getLinuxExecCommand()}`, 'Terminal=false', 'Categories=Utility;', 'X-GNOME-Autostart-enabled=true', '', ].join('\n'); } async function applyLinuxLaunchAtStartup(enabled: boolean): Promise { const targetPath = getLinuxDesktopEntryPath(); if (enabled) { await mkdir(dirname(targetPath), { recursive: true }); await writeFile(targetPath, getLinuxDesktopEntry(), 'utf8'); logManager.info(`Launch-at-startup enabled via desktop entry: ${targetPath}`); return; } await rm(targetPath, { force: true }); logManager.info(`Launch-at-startup disabled and desktop entry removed: ${targetPath}`); } function applyWindowsOrMacLaunchAtStartup(enabled: boolean): void { app.setLoginItemSettings({ openAtLogin: enabled, openAsHidden: false, }); logManager.info(`Launch-at-startup ${enabled ? 'enabled' : 'disabled'} via login items`); } export async function applyLaunchAtStartupSetting(enabled: boolean): Promise { try { if (process.platform === 'linux') { await applyLinuxLaunchAtStartup(enabled); return; } if (process.platform === 'win32' || process.platform === 'darwin') { applyWindowsOrMacLaunchAtStartup(enabled); return; } logManager.warn(`Launch-at-startup unsupported on platform: ${process.platform}`); } catch (error) { logManager.error(`Failed to apply launch-at-startup=${enabled}:`, error); } } export async function syncLaunchAtStartupSettingFromConfig(): Promise { const launchAtStartup = configManager.get(CONFIG_KEYS.LAUNCH_AT_STARTUP); await applyLaunchAtStartupSetting(Boolean(launchAtStartup)); }