feat: implement menu service for context menu management

feat: add provider API service for managing provider accounts and keys
feat: create provider runtime sync service for agent runtime management
feat: introduce script execution service for running automation scripts
feat: develop script store service for managing script metadata and storage
feat: implement theme service for managing application theme settings
feat: add updater service for handling application updates
feat: create window service for managing application windows and their states
This commit is contained in:
DEV_DSW
2026-04-22 09:26:39 +08:00
parent 9b8214cdd4
commit 416399e7a8
19 changed files with 33 additions and 33 deletions

View File

@@ -0,0 +1,111 @@
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<void> {
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<void> {
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<void> {
const launchAtStartup = configManager.get<boolean>(CONFIG_KEYS.LAUNCH_AT_STARTUP);
await applyLaunchAtStartupSetting(Boolean(launchAtStartup));
}