optionally (default off) allow keep gerbil in the tray, fix moe expert updating, dep upgrades, moving things to a new troubleshooting setting tab

This commit is contained in:
lone-cloud 2025-10-01 00:49:29 -07:00
parent fd2db3e40e
commit 0f214bdbe2
22 changed files with 754 additions and 362 deletions

View file

@ -1,7 +1,7 @@
{ {
"name": "gerbil", "name": "gerbil",
"productName": "Gerbil", "productName": "Gerbil",
"version": "1.6.1", "version": "1.6.2",
"description": "Run Large Language Models locally", "description": "Run Large Language Models locally",
"main": "out/main/index.js", "main": "out/main/index.js",
"homepage": "./", "homepage": "./",
@ -39,14 +39,14 @@
"license": "AGPL-3.0-or-later", "license": "AGPL-3.0-or-later",
"devDependencies": { "devDependencies": {
"@eslint/js": "^9.36.0", "@eslint/js": "^9.36.0",
"@types/node": "^24.5.2", "@types/node": "^24.6.1",
"@types/react": "^19.1.14", "@types/react": "^19.1.16",
"@types/react-dom": "^19.1.9", "@types/react-dom": "^19.1.9",
"@typescript-eslint/eslint-plugin": "^8.44.1", "@typescript-eslint/eslint-plugin": "^8.45.0",
"@typescript-eslint/parser": "^8.44.1", "@typescript-eslint/parser": "^8.45.0",
"@vitejs/plugin-react": "^5.0.3", "@vitejs/plugin-react": "^5.0.4",
"cross-env": "^10.0.0", "cross-env": "^10.1.0",
"electron": "^38.1.2", "electron": "^38.2.0",
"electron-builder": "^26.0.12", "electron-builder": "^26.0.12",
"electron-vite": "^4.0.1", "electron-vite": "^4.0.1",
"eslint": "^9.36.0", "eslint": "^9.36.0",
@ -60,13 +60,13 @@
"jiti": "^2.6.0", "jiti": "^2.6.0",
"prettier": "^3.6.2", "prettier": "^3.6.2",
"rollup-plugin-visualizer": "^6.0.3", "rollup-plugin-visualizer": "^6.0.3",
"typescript": "^5.9.2", "typescript": "^5.9.3",
"vite": "^7.1.7" "vite": "^7.1.7"
}, },
"dependencies": { "dependencies": {
"@codemirror/search": "^6.5.11", "@codemirror/search": "^6.5.11",
"@codemirror/theme-one-dark": "^6.1.3", "@codemirror/theme-one-dark": "^6.1.3",
"@codemirror/view": "^6.38.3", "@codemirror/view": "^6.38.4",
"@fontsource/inter": "^5.2.8", "@fontsource/inter": "^5.2.8",
"@mantine/core": "8.3.1", "@mantine/core": "8.3.1",
"@mantine/hooks": "8.3.1", "@mantine/hooks": "8.3.1",
@ -79,7 +79,7 @@
"react-dom": "^19.1.1", "react-dom": "^19.1.1",
"react-error-boundary": "^6.0.0", "react-error-boundary": "^6.0.0",
"systeminformation": "^5.27.10", "systeminformation": "^5.27.10",
"winston": "^3.17.0", "winston": "^3.18.3",
"winston-daily-rotate-file": "^5.0.0", "winston-daily-rotate-file": "^5.0.0",
"yauzl": "^3.2.0", "yauzl": "^3.2.0",
"zustand": "^5.0.8" "zustand": "^5.0.8"

View file

@ -17,6 +17,7 @@ import { NotepadContainer } from '@/components/Notepad/Container';
import { useUpdateChecker } from '@/hooks/useUpdateChecker'; import { useUpdateChecker } from '@/hooks/useUpdateChecker';
import { useKoboldVersionsStore } from '@/stores/koboldVersions'; import { useKoboldVersionsStore } from '@/stores/koboldVersions';
import { usePreferencesStore } from '@/stores/preferences'; import { usePreferencesStore } from '@/stores/preferences';
import { useLaunchConfigStore } from '@/stores/launchConfig';
import { STATUSBAR_HEIGHT, TITLEBAR_HEIGHT } from '@/constants'; import { STATUSBAR_HEIGHT, TITLEBAR_HEIGHT } from '@/constants';
import type { DownloadItem } from '@/types/electron'; import type { DownloadItem } from '@/types/electron';
import type { InterfaceTab, Screen } from '@/types'; import type { InterfaceTab, Screen } from '@/types';
@ -29,13 +30,44 @@ export const App = () => {
const [ejectConfirmModalOpen, setEjectConfirmModalOpen] = useState(false); const [ejectConfirmModalOpen, setEjectConfirmModalOpen] = useState(false);
const isInterfaceScreen = currentScreen === 'interface'; const isInterfaceScreen = currentScreen === 'interface';
const { resolvedColorScheme: appColorScheme } = usePreferencesStore(); const { resolvedColorScheme: appColorScheme, systemMonitoringEnabled } =
usePreferencesStore();
const { setColorScheme } = useMantineColorScheme(); const { setColorScheme } = useMantineColorScheme();
const { model, sdmodel } = useLaunchConfigStore();
useEffect(() => { useEffect(() => {
setColorScheme(appColorScheme); setColorScheme(appColorScheme);
}, [appColorScheme, setColorScheme]); }, [appColorScheme, setColorScheme]);
useEffect(() => {
const updateTray = async () => {
const config = await window.electronAPI.kobold.getSelectedConfig();
const displayModel = model || sdmodel || null;
const modelName = displayModel
? displayModel.split('/').pop() || displayModel
: null;
window.electronAPI.app.updateTrayState({
screen: currentScreen,
model: modelName,
config: config || null,
monitoringEnabled: systemMonitoringEnabled,
});
};
void updateTray();
}, [currentScreen, model, sdmodel, systemMonitoringEnabled]);
useEffect(() => {
const ejectCleanup = window.electronAPI.app.onTrayEject(() => {
performEject();
});
return () => {
ejectCleanup();
};
}, []);
const { const {
updateInfo: binaryUpdateInfo, updateInfo: binaryUpdateInfo,
showUpdateModal, showUpdateModal,

View file

@ -167,14 +167,11 @@ export const AdvancedTab = () => {
</Group> </Group>
<NumberInput <NumberInput
value={moeexperts} value={moeexperts}
onChange={(value) => onChange={(value) => handleMoeexpertsChange(Number(value))}
handleMoeexpertsChange(Number(value) || -1)
}
min={-1} min={-1}
max={128} max={128}
step={1} step={1}
size="sm" size="sm"
placeholder="-1"
/> />
</div> </div>
@ -192,7 +189,6 @@ export const AdvancedTab = () => {
max={999} max={999}
step={1} step={1}
size="sm" size="sm"
placeholder="0"
/> />
</div> </div>
</Group> </Group>

View file

@ -261,7 +261,7 @@ export const LaunchScreen = ({ onLaunch }: LaunchScreenProps) => {
return cleanup; return cleanup;
}, [loadConfigFiles]); }, [loadConfigFiles]);
const handleLaunchClick = () => { const handleLaunchClick = useCallback(() => {
handleLaunch({ handleLaunch({
autoGpuLayers, autoGpuLayers,
gpuLayers, gpuLayers,
@ -295,7 +295,51 @@ export const LaunchScreen = ({ onLaunch }: LaunchScreenProps) => {
moecpu, moecpu,
moeexperts, moeexperts,
}); });
}; }, [
handleLaunch,
autoGpuLayers,
gpuLayers,
contextSize,
port,
host,
multiuser,
multiplayer,
remotetunnel,
nocertify,
websearch,
noshift,
flashattention,
noavx2,
failsafe,
backend,
lowvram,
gpuDeviceSelection,
gpuPlatform,
tensorSplit,
quantmatmul,
usemmap,
additionalArguments,
sdt5xxl,
sdclipl,
sdclipg,
sdphotomaker,
sdvae,
sdlora,
sdconvdirect,
moecpu,
moeexperts,
]);
useEffect(() => {
const cleanup = window.electronAPI.app.onTrayLaunch(() => {
if (!model && !sdmodel) return;
if (isLaunching) return;
handleLaunchClick();
});
return cleanup;
}, [model, sdmodel, isLaunching, handleLaunchClick]);
return ( return (
<Container size="sm" mt="md"> <Container size="sm" mt="md">

View file

@ -1,85 +1,28 @@
import { useState, useEffect } from 'react'; import { useState, useEffect } from 'react';
import { import { Stack, Text, Switch } from '@mantine/core';
Stack,
Text,
Group,
TextInput,
Button,
rem,
Switch,
} from '@mantine/core';
import { Folder, FolderOpen, Monitor, ExternalLink } from 'lucide-react';
import { usePreferencesStore } from '@/stores/preferences'; import { usePreferencesStore } from '@/stores/preferences';
export const GeneralTab = () => { export const GeneralTab = () => {
const [installDir, setInstallDir] = useState(''); const [enableSystemTray, setEnableSystemTray] = useState(false);
const { systemMonitoringEnabled, setSystemMonitoringEnabled } = const { systemMonitoringEnabled, setSystemMonitoringEnabled } =
usePreferencesStore(); usePreferencesStore();
useEffect(() => { useEffect(() => {
loadCurrentInstallDir(); loadSystemTrayPreference();
}, []); }, []);
const loadCurrentInstallDir = async () => { const loadSystemTrayPreference = async () => {
const currentDir = await window.electronAPI.kobold.getCurrentInstallDir(); const enabled = await window.electronAPI.app.getEnableSystemTray();
if (currentDir) { setEnableSystemTray(enabled);
setInstallDir(currentDir);
}
}; };
const handleSelectInstallDir = async () => { const handleSystemTrayToggle = async (checked: boolean) => {
const selectedDir = setEnableSystemTray(checked);
await window.electronAPI.kobold.selectInstallDirectory(); await window.electronAPI.app.setEnableSystemTray(checked);
if (selectedDir) {
setInstallDir(selectedDir);
}
};
const handleOpenInstallDir = async () => {
if (installDir) {
await window.electronAPI.app.openPath(installDir);
}
}; };
return ( return (
<Stack gap="lg" h="100%"> <Stack gap="lg" h="100%">
<div>
<Text fw={500} mb="sm">
Installation Directory
</Text>
<Text size="sm" c="dimmed" mb="md">
Choose where application files will be downloaded and stored
</Text>
<Group gap="xs">
<TextInput
value={installDir}
readOnly
placeholder="Default installation directory"
style={{ flex: 1 }}
leftSection={<Folder style={{ width: rem(16), height: rem(16) }} />}
/>
<Button
variant="outline"
onClick={handleSelectInstallDir}
leftSection={
<FolderOpen style={{ width: rem(16), height: rem(16) }} />
}
>
Browse
</Button>
<Button
variant="outline"
onClick={handleOpenInstallDir}
disabled={!installDir}
leftSection={
<ExternalLink style={{ width: rem(16), height: rem(16) }} />
}
>
Open
</Button>
</Group>
</div>
<div> <div>
<Text fw={500} mb="sm"> <Text fw={500} mb="sm">
Status Bar Status Bar
@ -98,33 +41,19 @@ export const GeneralTab = () => {
<div> <div>
<Text fw={500} mb="sm"> <Text fw={500} mb="sm">
Troubleshooting System Tray
</Text> </Text>
<Text size="sm" c="dimmed" mb="md"> <Text size="sm" c="dimmed" mb="md">
Diagnostic tools and configuration access Add a system tray icon with quick access to launch, eject, and monitor
system metrics
</Text> </Text>
<Group gap="xs"> <Switch
<Button label="Enable system tray icon"
variant="outline" checked={enableSystemTray}
size="compact-sm" onChange={(event) =>
leftSection={ handleSystemTrayToggle(event.currentTarget.checked)
<FolderOpen style={{ width: rem(16), height: rem(16) }} /> }
} />
onClick={() => window.electronAPI.app.showLogsFolder()}
>
Show Logs
</Button>
<Button
variant="outline"
size="compact-sm"
leftSection={
<Monitor style={{ width: rem(16), height: rem(16) }} />
}
onClick={() => window.electronAPI.app.viewConfigFile()}
>
View Config
</Button>
</Group>
</div> </div>
</Stack> </Stack>
); );

View file

@ -7,11 +7,13 @@ import {
GitBranch, GitBranch,
Monitor, Monitor,
Info, Info,
Wrench,
} from 'lucide-react'; } from 'lucide-react';
import { GeneralTab } from '@/components/settings/GeneralTab'; import { GeneralTab } from '@/components/settings/GeneralTab';
import { VersionsTab } from '@/components/settings/VersionsTab'; import { VersionsTab } from '@/components/settings/VersionsTab';
import { AppearanceTab } from '@/components/settings/AppearanceTab'; import { AppearanceTab } from '@/components/settings/AppearanceTab';
import { SystemTab } from '@/components/settings/SystemTab'; import { SystemTab } from '@/components/settings/SystemTab';
import { TroubleshootingTab } from '@/components/settings/TroubleshootingTab';
import { AboutTab } from '@/components/settings/AboutTab'; import { AboutTab } from '@/components/settings/AboutTab';
import type { Screen } from '@/types'; import type { Screen } from '@/types';
import { Modal } from '@/components/Modal'; import { Modal } from '@/components/Modal';
@ -139,6 +141,14 @@ export const SettingsModal = ({
> >
System System
</Tabs.Tab> </Tabs.Tab>
<Tabs.Tab
value="troubleshooting"
leftSection={
<Wrench style={{ width: rem(16), height: rem(16) }} />
}
>
Troubleshooting
</Tabs.Tab>
<Tabs.Tab <Tabs.Tab
value="about" value="about"
leftSection={<Info style={{ width: rem(16), height: rem(16) }} />} leftSection={<Info style={{ width: rem(16), height: rem(16) }} />}
@ -165,6 +175,10 @@ export const SettingsModal = ({
<SystemTab /> <SystemTab />
</Tabs.Panel> </Tabs.Panel>
<Tabs.Panel value="troubleshooting">
<TroubleshootingTab />
</Tabs.Panel>
<Tabs.Panel value="about"> <Tabs.Panel value="about">
<AboutTab /> <AboutTab />
</Tabs.Panel> </Tabs.Panel>

View file

@ -0,0 +1,104 @@
import { useState, useEffect } from 'react';
import { Stack, Text, Group, TextInput, Button, rem } from '@mantine/core';
import { Folder, FolderOpen, Monitor, ExternalLink } from 'lucide-react';
export const TroubleshootingTab = () => {
const [installDir, setInstallDir] = useState('');
useEffect(() => {
loadCurrentInstallDir();
}, []);
const loadCurrentInstallDir = async () => {
const currentDir = await window.electronAPI.kobold.getCurrentInstallDir();
if (currentDir) {
setInstallDir(currentDir);
}
};
const handleSelectInstallDir = async () => {
const selectedDir =
await window.electronAPI.kobold.selectInstallDirectory();
if (selectedDir) {
setInstallDir(selectedDir);
}
};
const handleOpenInstallDir = async () => {
if (installDir) {
await window.electronAPI.app.openPath(installDir);
}
};
return (
<Stack gap="lg" h="100%">
<div>
<Text fw={500} mb="sm">
Installation Directory
</Text>
<Text size="sm" c="dimmed" mb="md">
Choose where application files will be downloaded and stored
</Text>
<Group gap="xs">
<TextInput
value={installDir}
readOnly
placeholder="Default installation directory"
style={{ flex: 1 }}
leftSection={<Folder style={{ width: rem(16), height: rem(16) }} />}
/>
<Button
variant="outline"
onClick={handleSelectInstallDir}
leftSection={
<FolderOpen style={{ width: rem(16), height: rem(16) }} />
}
>
Browse
</Button>
<Button
variant="outline"
onClick={handleOpenInstallDir}
disabled={!installDir}
leftSection={
<ExternalLink style={{ width: rem(16), height: rem(16) }} />
}
>
Open
</Button>
</Group>
</div>
<div>
<Text fw={500} mb="sm">
Diagnostics
</Text>
<Text size="sm" c="dimmed" mb="md">
Diagnostic tools and configuration access
</Text>
<Group gap="xs">
<Button
variant="outline"
size="compact-sm"
leftSection={
<FolderOpen style={{ width: rem(16), height: rem(16) }} />
}
onClick={() => window.electronAPI.app.showLogsFolder()}
>
Show Logs
</Button>
<Button
variant="outline"
size="compact-sm"
leftSection={
<Monitor style={{ width: rem(16), height: rem(16) }} />
}
onClick={() => window.electronAPI.app.viewConfigFile()}
>
View Config
</Button>
</Group>
</div>
</Stack>
);
};

View file

@ -9,6 +9,7 @@ import {
initialize as initializeConfig, initialize as initializeConfig,
getInstallDir, getInstallDir,
} from '@/main/modules/config'; } from '@/main/modules/config';
import { createTray } from '@/main/modules/tray';
import { safeExecute } from '@/utils/node/logging'; import { safeExecute } from '@/utils/node/logging';
import { stopKoboldCpp } from '@/main/modules/koboldcpp/launcher'; import { stopKoboldCpp } from '@/main/modules/koboldcpp/launcher';
import { stopFrontend as stopSillyTavern } from '@/main/modules/sillytavern'; import { stopFrontend as stopSillyTavern } from '@/main/modules/sillytavern';
@ -27,6 +28,7 @@ export async function initializeApp() {
await ensureDir(installDir); await ensureDir(installDir);
createMainWindow(); createMainWindow();
createTray();
setupIPCHandlers(); setupIPCHandlers();

View file

@ -1,10 +1,10 @@
import { argv, exit } from 'process'; import { argv, exit } from 'process';
import { getAppVersion } from '@/utils/node/fs';
if (argv[1] === '--version') { if (argv[1] === '--version') {
(async () => { (async () => {
try { try {
const version = await getAppVersion(); const { app } = await import('electron');
const version = await app.getVersion();
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
console.log(version); console.log(version);
} catch { } catch {

View file

@ -2,6 +2,7 @@ import { ipcMain, app } from 'electron';
import { join } from 'path'; import { join } from 'path';
import { release } from 'os'; import { release } from 'os';
import { platform, versions, arch } from 'process'; import { platform, versions, arch } from 'process';
import type { Screen } from '@/types';
import { import {
stopKoboldCpp, stopKoboldCpp,
launchKoboldCppWithCustomFrontends, launchKoboldCppWithCustomFrontends,
@ -25,11 +26,11 @@ import {
get as getConfig, get as getConfig,
set as setConfig, set as setConfig,
getSelectedConfig, getSelectedConfig,
setSelectedConfig,
getInstallDir, getInstallDir,
getColorScheme, getColorScheme,
setColorScheme, getEnableSystemTray,
} from '@/main/modules/config'; } from '@/main/modules/config';
import { createTray, updateTrayState } from '@/main/modules/tray';
import { getConfigDir, openPathHandler, openUrl } from '@/utils/node/path'; import { getConfigDir, openPathHandler, openUrl } from '@/utils/node/path';
import { logError } from '@/utils/node/logging'; import { logError } from '@/utils/node/logging';
import { stopFrontend as stopSillyTavernFrontend } from '@/main/modules/sillytavern'; import { stopFrontend as stopSillyTavernFrontend } from '@/main/modules/sillytavern';
@ -76,7 +77,6 @@ import {
isUpdateDownloaded, isUpdateDownloaded,
canAutoUpdate, canAutoUpdate,
} from '@/main/modules/autoUpdater'; } from '@/main/modules/autoUpdater';
import { getAppVersion } from '@/utils/node/fs';
export function setupIPCHandlers() { export function setupIPCHandlers() {
const mainWindow = getMainWindow(); const mainWindow = getMainWindow();
@ -102,7 +102,7 @@ export function setupIPCHandlers() {
ipcMain.handle('kobold:getSelectedConfig', () => getSelectedConfig()); ipcMain.handle('kobold:getSelectedConfig', () => getSelectedConfig());
ipcMain.handle('kobold:setSelectedConfig', (_, configName) => ipcMain.handle('kobold:setSelectedConfig', (_, configName) =>
setSelectedConfig(configName) setConfig('selectedConfig', configName)
); );
ipcMain.handle('kobold:setCurrentVersion', (_, version) => ipcMain.handle('kobold:setCurrentVersion', (_, version) =>
@ -162,12 +162,12 @@ export function setupIPCHandlers() {
ipcMain.on('config:set', (_, key, value) => setConfig(key, value)); ipcMain.on('config:set', (_, key, value) => setConfig(key, value));
ipcMain.handle('app:getVersion', () => getAppVersion()); ipcMain.handle('app:getVersion', () => app.getVersion());
ipcMain.handle('app:getVersionInfo', async () => { ipcMain.handle('app:getVersionInfo', async () => {
const [appVersion, nodeJsSystemVersion, uvVersion, aurPackageVersion] = const [appVersion, nodeJsSystemVersion, uvVersion, aurPackageVersion] =
await Promise.all([ await Promise.all([
getAppVersion(), app.getVersion(),
getSystemNodeVersion(), getSystemNodeVersion(),
getUvVersion(), getUvVersion(),
getAURVersion(), getAURVersion(),
@ -222,7 +222,29 @@ export function setupIPCHandlers() {
ipcMain.handle('app:getColorScheme', () => getColorScheme()); ipcMain.handle('app:getColorScheme', () => getColorScheme());
ipcMain.handle('app:setColorScheme', (_, colorScheme) => ipcMain.handle('app:setColorScheme', (_, colorScheme) =>
setColorScheme(colorScheme) setConfig('colorScheme', colorScheme)
);
ipcMain.handle('app:getEnableSystemTray', () => getEnableSystemTray());
ipcMain.handle('app:setEnableSystemTray', async (_, enabled: boolean) => {
await setConfig('enableSystemTray', enabled);
createTray();
});
ipcMain.handle(
'app:updateTrayState',
(
_,
state: {
screen?: Screen | null;
model?: string | null;
config?: string | null;
monitoringEnabled?: boolean;
}
) => {
updateTrayState(state);
}
); );
ipcMain.handle('app:openExternal', async (_, url) => openUrl(url)); ipcMain.handle('app:openExternal', async (_, url) => openUrl(url));

View file

@ -14,6 +14,7 @@ import { platform, on } from 'process';
import type { ChildProcess } from 'child_process'; import type { ChildProcess } from 'child_process';
import yauzl from 'yauzl'; import yauzl from 'yauzl';
import { createWriteStream } from 'fs'; import { createWriteStream } from 'fs';
import { app } from 'electron';
import { logError, safeExecute, tryExecute } from '@/utils/node/logging'; import { logError, safeExecute, tryExecute } from '@/utils/node/logging';
import { sendKoboldOutput } from './window'; import { sendKoboldOutput } from './window';
@ -21,7 +22,7 @@ import { getInstallDir } from './config';
import { COMFYUI, SERVER_READY_SIGNALS, GITHUB_API } from '@/constants'; import { COMFYUI, SERVER_READY_SIGNALS, GITHUB_API } from '@/constants';
import { terminateProcess } from '@/utils/node/process'; import { terminateProcess } from '@/utils/node/process';
import { parseKoboldConfig } from '@/utils/node/kobold'; import { parseKoboldConfig } from '@/utils/node/kobold';
import { getAppVersion, ensureDir } from '@/utils/node/fs'; import { ensureDir } from '@/utils/node/fs';
import { detectGPU } from './hardware'; import { detectGPU } from './hardware';
import { getUvEnvironment } from './dependencies'; import { getUvEnvironment } from './dependencies';
@ -559,7 +560,7 @@ export async function startFrontend(args: string[]) {
stdio: 'pipe', stdio: 'pipe',
}); });
const version = await getAppVersion(); const version = await app.getVersion();
sendKoboldOutput(`ComfyUI started via Gerbil v${version}`); sendKoboldOutput(`ComfyUI started via Gerbil v${version}`);
if (comfyUIProcess.stdout) { if (comfyUIProcess.stdout) {

View file

@ -30,6 +30,7 @@ interface AppConfig {
dismissedUpdates?: DismissedUpdate[]; dismissedUpdates?: DismissedUpdate[];
zoomLevel?: number; zoomLevel?: number;
notepad?: SavedNotepadState; notepad?: SavedNotepadState;
enableSystemTray?: boolean;
} }
let config: AppConfig = {}; let config: AppConfig = {};
@ -98,18 +99,8 @@ export async function setCurrentKoboldBinary(binaryPath: string) {
export const getSelectedConfig = () => config.selectedConfig; export const getSelectedConfig = () => config.selectedConfig;
export async function setSelectedConfig(configName: string) {
config.selectedConfig = configName;
await saveConfig();
}
export const getColorScheme = () => config.colorScheme || 'auto'; export const getColorScheme = () => config.colorScheme || 'auto';
export async function setColorScheme(colorScheme: MantineColorScheme) {
config.colorScheme = colorScheme;
await saveConfig();
}
export function getBackgroundColor() { export function getBackgroundColor() {
const colorScheme = getColorScheme(); const colorScheme = getColorScheme();
@ -124,42 +115,4 @@ export function getBackgroundColor() {
export const getWindowBounds = () => config.windowBounds; export const getWindowBounds = () => config.windowBounds;
export async function setWindowBounds(bounds: WindowBounds) { export const getEnableSystemTray = () => config.enableSystemTray ?? false;
config.windowBounds = bounds;
await saveConfig();
}
export const getFrontendPreference = () => config.frontendPreference;
export async function setFrontendPreference(preference: FrontendPreference) {
config.frontendPreference = preference;
await saveConfig();
}
export const getHasSeenWelcome = () => config.hasSeenWelcome;
export async function setHasSeenWelcome(hasSeenWelcome: boolean) {
config.hasSeenWelcome = hasSeenWelcome;
await saveConfig();
}
export const getSkipEjectConfirmation = () => config.skipEjectConfirmation;
export async function setSkipEjectConfirmation(skipEjectConfirmation: boolean) {
config.skipEjectConfirmation = skipEjectConfirmation;
await saveConfig();
}
export const getDismissedUpdates = () => config.dismissedUpdates || [];
export async function setDismissedUpdates(dismissedUpdates: DismissedUpdate[]) {
config.dismissedUpdates = dismissedUpdates;
await saveConfig();
}
export const getZoomLevel = () => config.zoomLevel;
export async function setZoomLevel(zoomLevel: number) {
config.zoomLevel = zoomLevel;
await saveConfig();
}

View file

@ -5,6 +5,8 @@ import { platform, env as processEnv } from 'process';
import { execa } from 'execa'; import { execa } from 'execa';
import { app } from 'electron'; import { app } from 'electron';
import { PRODUCT_NAME } from '@/constants';
async function executeCommand( async function executeCommand(
command: string, command: string,
args: string[], args: string[],
@ -166,7 +168,7 @@ export async function getAURVersion() {
} }
try { try {
const { stdout } = await execa('pacman', ['-Q', 'gerbil'], { const { stdout } = await execa('pacman', ['-Q', PRODUCT_NAME], {
timeout: 1000, timeout: 1000,
reject: false, reject: false,
}); });

View file

@ -1,4 +1,4 @@
import { readdir, stat } from 'fs/promises'; import { readdir, stat, rm } from 'fs/promises';
import { join } from 'path'; import { join } from 'path';
import { execa } from 'execa'; import { execa } from 'execa';
@ -159,7 +159,6 @@ export async function deleteRelease(binaryPath: string) {
const releaseDir = binaryPath.split(/[/\\]/).slice(0, -1).join('/'); const releaseDir = binaryPath.split(/[/\\]/).slice(0, -1).join('/');
if (await pathExists(releaseDir)) { if (await pathExists(releaseDir)) {
const { rm } = await import('fs/promises');
await rm(releaseDir, { recursive: true, force: true }); await rm(releaseDir, { recursive: true, force: true });
clearVersionCache(binaryPath); clearVersionCache(binaryPath);

View file

@ -5,6 +5,7 @@ import { spawn } from 'child_process';
import { getGPUData } from '@/utils/node/gpu'; import { getGPUData } from '@/utils/node/gpu';
import { detectGPU } from './hardware'; import { detectGPU } from './hardware';
import { tryExecute, safeExecute } from '@/utils/node/logging'; import { tryExecute, safeExecute } from '@/utils/node/logging';
import { isTrayActive, updateMetrics } from './tray';
export interface CpuMetrics { export interface CpuMetrics {
usage: number; usage: number;
@ -53,6 +54,10 @@ let isRunning = false;
const updateFrequency = 1000; const updateFrequency = 1000;
let mainWindow: BrowserWindow | null = null; let mainWindow: BrowserWindow | null = null;
let latestCpuMetrics: CpuMetrics | null = null;
let latestMemoryMetrics: MemoryMetrics | null = null;
let latestGpuMetrics: GpuMetrics | null = null;
export function startMonitoring(window: BrowserWindow) { export function startMonitoring(window: BrowserWindow) {
if (isRunning) return; if (isRunning) return;
@ -93,6 +98,12 @@ export function stopMonitoring() {
isRunning = false; isRunning = false;
} }
function updateTrayWithMetrics() {
if (isTrayActive()) {
updateMetrics(latestCpuMetrics, latestMemoryMetrics, latestGpuMetrics);
}
}
async function collectAndSendCpuMetrics() { async function collectAndSendCpuMetrics() {
await tryExecute(async () => { await tryExecute(async () => {
const cpuData = await currentLoad(); const cpuData = await currentLoad();
@ -110,6 +121,9 @@ async function collectAndSendCpuMetrics() {
} catch {} } catch {}
} }
latestCpuMetrics = metrics;
updateTrayWithMetrics();
if (mainWindow && !mainWindow.isDestroyed()) { if (mainWindow && !mainWindow.isDestroyed()) {
mainWindow.webContents.send('cpu-metrics', metrics); mainWindow.webContents.send('cpu-metrics', metrics);
} }
@ -127,6 +141,9 @@ async function collectAndSendMemoryMetrics() {
usage: Math.round((usedBytes / totalBytes) * 100), usage: Math.round((usedBytes / totalBytes) * 100),
}; };
latestMemoryMetrics = metrics;
updateTrayWithMetrics();
if (mainWindow && !mainWindow.isDestroyed()) { if (mainWindow && !mainWindow.isDestroyed()) {
mainWindow.webContents.send('memory-metrics', metrics); mainWindow.webContents.send('memory-metrics', metrics);
} }
@ -150,6 +167,9 @@ async function collectAndSendGpuMetrics() {
})), })),
}; };
latestGpuMetrics = metrics;
updateTrayWithMetrics();
if (mainWindow && !mainWindow.isDestroyed()) { if (mainWindow && !mainWindow.isDestroyed()) {
mainWindow.webContents.send('gpu-metrics', metrics); mainWindow.webContents.send('gpu-metrics', metrics);
} }

View file

@ -1,7 +1,8 @@
import { spawn } from 'child_process'; import { spawn } from 'child_process';
import type { ChildProcess } from 'child_process';
import { join } from 'path'; import { join } from 'path';
import { on } from 'process'; import { on } from 'process';
import { app } from 'electron';
import type { ChildProcess } from 'child_process';
import { logError } from '@/utils/node/logging'; import { logError } from '@/utils/node/logging';
import { sendKoboldOutput } from './window'; import { sendKoboldOutput } from './window';
@ -9,7 +10,6 @@ import { getInstallDir } from './config';
import { OPENWEBUI, SERVER_READY_SIGNALS } from '@/constants'; import { OPENWEBUI, SERVER_READY_SIGNALS } from '@/constants';
import { terminateProcess } from '@/utils/node/process'; import { terminateProcess } from '@/utils/node/process';
import { parseKoboldConfig } from '@/utils/node/kobold'; import { parseKoboldConfig } from '@/utils/node/kobold';
import { getAppVersion } from '@/utils/node/fs';
import { getUvEnvironment } from './dependencies'; import { getUvEnvironment } from './dependencies';
let openWebUIProcess: ChildProcess | null = null; let openWebUIProcess: ChildProcess | null = null;
@ -69,7 +69,10 @@ export async function startFrontend(args: string[]) {
isImageMode, isImageMode,
} = parseKoboldConfig(args); } = parseKoboldConfig(args);
const [, appVersion] = await Promise.all([stopFrontend(), getAppVersion()]); const [, appVersion] = await Promise.all([
stopFrontend(),
app.getVersion(),
]);
sendKoboldOutput( sendKoboldOutput(
`Preparing Open WebUI to connect at ${koboldHost}:${koboldPort}${isImageMode ? ' (with image generation)' : ''}...` `Preparing Open WebUI to connect at ${koboldHost}:${koboldPort}${isImageMode ? ' (with image generation)' : ''}...`

249
src/main/modules/tray.ts Normal file
View file

@ -0,0 +1,249 @@
import {
app,
Tray,
Menu,
nativeImage,
MenuItemConstructorOptions,
} from 'electron';
import { join } from 'path';
import { resourcesPath } from 'process';
import { getEnableSystemTray } from './config';
import { getMainWindow } from './window';
import type { CpuMetrics, MemoryMetrics, GpuMetrics } from './monitoring';
import type { Screen } from '@/types';
import { PRODUCT_NAME } from '@/constants';
let tray: Tray | null = null;
let currentMetrics: {
cpu: CpuMetrics | null;
memory: MemoryMetrics | null;
gpu: GpuMetrics | null;
} = {
cpu: null,
memory: null,
gpu: null,
};
interface TrayAppState {
currentScreen: Screen | null;
isLaunched: boolean;
currentModel: string | null;
currentConfig: string | null;
monitoringEnabled: boolean;
}
const appState: TrayAppState = {
currentScreen: null,
isLaunched: false,
currentModel: null,
currentConfig: null,
monitoringEnabled: false,
};
export function updateTrayState(state: {
screen?: Screen | null;
model?: string | null;
config?: string | null;
monitoringEnabled?: boolean;
}) {
if (state.screen !== undefined) {
appState.currentScreen = state.screen;
appState.isLaunched = state.screen === 'interface';
}
if (state.model !== undefined) {
appState.currentModel = state.model;
}
if (state.config !== undefined) {
appState.currentConfig = state.config;
}
if (state.monitoringEnabled !== undefined) {
appState.monitoringEnabled = state.monitoringEnabled;
}
updateTrayMenu();
}
export function updateMetrics(
cpu: CpuMetrics | null,
memory: MemoryMetrics | null,
gpu: GpuMetrics | null
) {
currentMetrics = { cpu, memory, gpu };
updateTrayTooltip();
}
function buildTooltipText() {
const parts: string[] = [];
if (
appState.monitoringEnabled &&
currentMetrics.cpu &&
currentMetrics.memory
) {
const metrics: string[] = [];
const cpuText = `CPU: ${currentMetrics.cpu.usage}%${currentMetrics.cpu.temperature ? `${currentMetrics.cpu.temperature}°C` : ''}`;
metrics.push(cpuText);
const ramText = `RAM: ${currentMetrics.memory.used.toFixed(2)} GB / ${currentMetrics.memory.total.toFixed(2)} GB (${currentMetrics.memory.usage}%)`;
metrics.push(ramText);
if (currentMetrics.gpu?.gpus) {
currentMetrics.gpu.gpus.forEach((gpu, index) => {
const gpuLabel =
currentMetrics.gpu!.gpus.length > 1 ? `GPU ${index + 1}` : 'GPU';
const gpuText = `${gpuLabel}: ${gpu.usage}%${gpu.temperature ? `${gpu.temperature}°C` : ''}`;
metrics.push(gpuText);
const vramLabel =
currentMetrics.gpu!.gpus.length > 1 ? `VRAM ${index + 1}` : 'VRAM';
const vramText = `${vramLabel}: ${gpu.memoryUsed.toFixed(2)} GB / ${gpu.memoryTotal.toFixed(2)} GB (${gpu.memoryUsage}%)`;
metrics.push(vramText);
});
}
parts.push(...metrics);
} else {
parts.push(PRODUCT_NAME);
}
return parts.join('\n');
}
function updateTrayTooltip() {
if (tray) {
tray.setToolTip(buildTooltipText());
}
}
function buildContextMenu() {
const mainWindow = getMainWindow();
const isVisible = mainWindow.isVisible();
const menuTemplate: MenuItemConstructorOptions[] = [];
if (isVisible) {
menuTemplate.push({
label: 'Hide Gerbil',
click: () => {
mainWindow.hide();
},
});
} else {
menuTemplate.push({
label: 'Show Gerbil',
click: () => {
mainWindow.show();
mainWindow.focus();
},
});
}
menuTemplate.push({ type: 'separator' });
if (appState.currentScreen === 'launch' && !appState.isLaunched) {
menuTemplate.push({
label: 'Launch with Current Config',
enabled: !!appState.currentConfig,
click: () => {
const mainWindow = getMainWindow();
mainWindow.webContents.send('tray:launch');
},
});
} else if (appState.isLaunched && appState.currentScreen === 'interface') {
if (appState.currentModel) {
menuTemplate.push({
label: `Running: ${appState.currentModel}`,
enabled: false,
});
}
menuTemplate.push({
label: 'Eject Model',
click: () => {
const mainWindow = getMainWindow();
mainWindow.webContents.send('tray:eject');
},
});
}
menuTemplate.push(
{ type: 'separator' },
{
label: 'Quit',
click: () => {
app.quit();
},
}
);
return Menu.buildFromTemplate(menuTemplate);
}
export function createTray() {
const isEnabled = getEnableSystemTray();
if (!isEnabled) {
destroyTray();
return;
}
if (tray) {
return;
}
let iconPath: string;
if (app.isPackaged) {
iconPath = join(resourcesPath, 'assets', 'icon.png');
} else {
iconPath = join(__dirname, '../../src/assets/icon.png');
}
const icon = nativeImage.createFromPath(iconPath);
if (icon.isEmpty()) {
return;
}
tray = new Tray(icon.resize({ width: 16, height: 16 }));
updateTrayTooltip();
tray.setContextMenu(buildContextMenu());
tray.on('click', () => {
const mainWindow = getMainWindow();
if (mainWindow.isVisible()) {
mainWindow.hide();
} else {
mainWindow.show();
mainWindow.focus();
}
});
const mainWindow = getMainWindow();
mainWindow.on('show', () => {
if (tray) {
tray.setContextMenu(buildContextMenu());
}
});
mainWindow.on('hide', () => {
if (tray) {
tray.setContextMenu(buildContextMenu());
}
});
}
export function destroyTray() {
if (tray) {
tray.destroy();
tray = null;
}
}
export function updateTrayMenu() {
if (tray) {
tray.setContextMenu(buildContextMenu());
updateTrayTooltip();
}
}
export const isTrayActive = () => tray !== null;

View file

@ -10,7 +10,9 @@ import {
getWindowBounds, getWindowBounds,
setWindowBounds, setWindowBounds,
WindowBounds, WindowBounds,
getEnableSystemTray,
} from './config'; } from './config';
import { isTrayActive } from './tray';
let mainWindow: BrowserWindow | null = null; let mainWindow: BrowserWindow | null = null;
@ -146,9 +148,14 @@ export function createMainWindow() {
}, },
})); }));
mainWindow.on('close', () => { mainWindow.on('close', (event) => {
saveBounds(); if (getEnableSystemTray() && isTrayActive()) {
app.quit(); event.preventDefault();
mainWindow?.hide();
} else {
saveBounds();
app.quit();
}
}); });
setupContextMenu(mainWindow); setupContextMenu(mainWindow);

View file

@ -102,6 +102,24 @@ const appAPI: AppAPI = {
getColorScheme: () => ipcRenderer.invoke('app:getColorScheme'), getColorScheme: () => ipcRenderer.invoke('app:getColorScheme'),
setColorScheme: (colorScheme) => setColorScheme: (colorScheme) =>
ipcRenderer.invoke('app:setColorScheme', colorScheme), ipcRenderer.invoke('app:setColorScheme', colorScheme),
getEnableSystemTray: () => ipcRenderer.invoke('app:getEnableSystemTray'),
setEnableSystemTray: (enabled) =>
ipcRenderer.invoke('app:setEnableSystemTray', enabled),
updateTrayState: (state) => ipcRenderer.invoke('app:updateTrayState', state),
onTrayLaunch: (callback) => {
const handler = () => callback();
ipcRenderer.on('tray:launch', handler);
return () => {
ipcRenderer.removeListener('tray:launch', handler);
};
},
onTrayEject: (callback) => {
const handler = () => callback();
ipcRenderer.on('tray:eject', handler);
return () => {
ipcRenderer.removeListener('tray:eject', handler);
};
},
openExternal: (url) => ipcRenderer.invoke('app:openExternal', url), openExternal: (url) => ipcRenderer.invoke('app:openExternal', url),
openPerformanceManager: () => openPerformanceManager: () =>
ipcRenderer.invoke('app:openPerformanceManager'), ipcRenderer.invoke('app:openPerformanceManager'),

View file

@ -5,7 +5,7 @@ import type {
GPUMemoryInfo, GPUMemoryInfo,
SystemMemoryInfo, SystemMemoryInfo,
} from '@/types/hardware'; } from '@/types/hardware';
import type { BackendOption, BackendSupport } from '@/types'; import type { BackendOption, BackendSupport, Screen } from '@/types';
import type { MantineColorScheme } from '@mantine/core'; import type { MantineColorScheme } from '@mantine/core';
import type { import type {
CpuMetrics, CpuMetrics,
@ -175,6 +175,16 @@ export interface AppAPI {
setZoomLevel: (level: number) => Promise<void>; setZoomLevel: (level: number) => Promise<void>;
getColorScheme: () => Promise<MantineColorScheme>; getColorScheme: () => Promise<MantineColorScheme>;
setColorScheme: (colorScheme: MantineColorScheme) => Promise<void>; setColorScheme: (colorScheme: MantineColorScheme) => Promise<void>;
getEnableSystemTray: () => Promise<boolean>;
setEnableSystemTray: (enabled: boolean) => Promise<void>;
updateTrayState: (state: {
screen?: Screen | null;
model?: string | null;
config?: string | null;
monitoringEnabled?: boolean;
}) => Promise<void>;
onTrayLaunch: (callback: () => void) => () => void;
onTrayEject: (callback: () => void) => () => void;
openExternal: (url: string) => Promise<void>; openExternal: (url: string) => Promise<void>;
openPerformanceManager: () => Promise<{ openPerformanceManager: () => Promise<{
success: boolean; success: boolean;

View file

@ -40,8 +40,3 @@ export const ensureDir = async (path: string) => {
} }
} }
}; };
export const getAppVersion = async () => {
const { app } = await import('electron');
return app.getVersion();
};

348
yarn.lock
View file

@ -315,15 +315,15 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@codemirror/view@npm:^6.0.0, @codemirror/view@npm:^6.17.0, @codemirror/view@npm:^6.23.0, @codemirror/view@npm:^6.27.0, @codemirror/view@npm:^6.35.0, @codemirror/view@npm:^6.38.3": "@codemirror/view@npm:^6.0.0, @codemirror/view@npm:^6.17.0, @codemirror/view@npm:^6.23.0, @codemirror/view@npm:^6.27.0, @codemirror/view@npm:^6.35.0, @codemirror/view@npm:^6.38.4":
version: 6.38.3 version: 6.38.4
resolution: "@codemirror/view@npm:6.38.3" resolution: "@codemirror/view@npm:6.38.4"
dependencies: dependencies:
"@codemirror/state": "npm:^6.5.0" "@codemirror/state": "npm:^6.5.0"
crelt: "npm:^1.0.6" crelt: "npm:^1.0.6"
style-mod: "npm:^4.1.0" style-mod: "npm:^4.1.0"
w3c-keyname: "npm:^2.2.4" w3c-keyname: "npm:^2.2.4"
checksum: 10c0/70c9ec6d6a6528d64613c922165cc156f564435be50767167785fa97cb1be29d1d4c95a550405ce8144bc4147138ca463c6f1b94afa6b42b45e4f9cbe9045ec5 checksum: 10c0/8133e7d723f5ca82449e866cffdd267f72c5f924b5a88bdbc1ae29ca3e3274c8c5695342c82da8eb5b0509688ef8a0cfc6d517352a5329cfc3fed2cbbd504ce4
languageName: node languageName: node
linkType: hard linkType: hard
@ -334,14 +334,14 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@dabh/diagnostics@npm:^2.0.2": "@dabh/diagnostics@npm:^2.0.8":
version: 2.0.3 version: 2.0.8
resolution: "@dabh/diagnostics@npm:2.0.3" resolution: "@dabh/diagnostics@npm:2.0.8"
dependencies: dependencies:
colorspace: "npm:1.1.x" "@so-ric/colorspace": "npm:^1.1.6"
enabled: "npm:2.0.x" enabled: "npm:2.0.x"
kuler: "npm:^2.0.0" kuler: "npm:^2.0.0"
checksum: 10c0/a5133df8492802465ed01f2f0a5784585241a1030c362d54a602ed1839816d6c93d71dde05cf2ddb4fd0796238c19774406bd62fa2564b637907b495f52425fe checksum: 10c0/64701c272f7de02800039fea99796507670fe5f67d4eb7718599351ec156936efd123fcab7ee18f9d7874939caaacc08e7c7a6bb05ff8cda6d930ad041cc555c
languageName: node languageName: node
linkType: hard linkType: hard
@ -1099,10 +1099,10 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@rolldown/pluginutils@npm:1.0.0-beta.35": "@rolldown/pluginutils@npm:1.0.0-beta.38":
version: 1.0.0-beta.35 version: 1.0.0-beta.38
resolution: "@rolldown/pluginutils@npm:1.0.0-beta.35" resolution: "@rolldown/pluginutils@npm:1.0.0-beta.38"
checksum: 10c0/feb6ab8f77ef2bde675099409c3ccd6a168f35a3c3e88482df3ca42494260fd42befe36e8e90ce358847a12aaab94cd8fe7069cf1e905edf91eb411d933906d9 checksum: 10c0/8353ec2528349f79e27d1a3193806725b85830da334e935cbb606d88c1177c58ea6519c578e4e93e5f677f5b22aecb8738894dbed14603e14b6bffe3facf1002
languageName: node languageName: node
linkType: hard linkType: hard
@ -1288,6 +1288,16 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@so-ric/colorspace@npm:^1.1.6":
version: 1.1.6
resolution: "@so-ric/colorspace@npm:1.1.6"
dependencies:
color: "npm:^5.0.2"
text-hex: "npm:1.0.x"
checksum: 10c0/f3ad26afefbb8d6101ea7c385cd5f402d4291c2ffc9cabe37030d5fdb8bda980ee534a0d7c250f8233fc3a59b99272410177cd98b219f6b3770f91a0fdb6eb3e
languageName: node
linkType: hard
"@szmarczak/http-timer@npm:^4.0.5": "@szmarczak/http-timer@npm:^4.0.5":
version: 4.0.6 version: 4.0.6
resolution: "@szmarczak/http-timer@npm:4.0.6" resolution: "@szmarczak/http-timer@npm:4.0.6"
@ -1419,12 +1429,12 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@types/node@npm:*, @types/node@npm:^24.5.2": "@types/node@npm:*":
version: 24.5.2 version: 24.6.0
resolution: "@types/node@npm:24.5.2" resolution: "@types/node@npm:24.6.0"
dependencies: dependencies:
undici-types: "npm:~7.12.0" undici-types: "npm:~7.13.0"
checksum: 10c0/96baaca6564d39c6f7f6eddd73ce41e2a7594ef37225cd52df3be36fad31712af8ae178387a72d0b80f2e2799e7fd30c014bc0ae9eb9f962d9079b691be00c48 checksum: 10c0/06f1aa1b5d9a8c26285b34c25aee554f31a1dc0b39627cc14e7c1c6967e75a47ab9f409eee14796cbcc004ae4059fa884cb6092ecfb368c9656d16686d7cc9d8
languageName: node languageName: node
linkType: hard linkType: hard
@ -1437,6 +1447,15 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@types/node@npm:^24.6.1":
version: 24.6.1
resolution: "@types/node@npm:24.6.1"
dependencies:
undici-types: "npm:~7.13.0"
checksum: 10c0/f2f8aea441d72139345cfa2e392af51bc27d12eb5f74b9b4d202046a2e82ab70d6da89c46a2ac7feea98854c2919e53070869d4af9d448e173a77249fcb7bca3
languageName: node
linkType: hard
"@types/plist@npm:^3.0.1": "@types/plist@npm:^3.0.1":
version: 3.0.5 version: 3.0.5
resolution: "@types/plist@npm:3.0.5" resolution: "@types/plist@npm:3.0.5"
@ -1456,12 +1475,12 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@types/react@npm:^19.1.14": "@types/react@npm:^19.1.16":
version: 19.1.14 version: 19.1.16
resolution: "@types/react@npm:19.1.14" resolution: "@types/react@npm:19.1.16"
dependencies: dependencies:
csstype: "npm:^3.0.2" csstype: "npm:^3.0.2"
checksum: 10c0/0d1629e065413be79c949f011845836e7f515c8f97dbfef057719be2f312b404405d2d064cb28e03363c62c153c100e84268c09dd9aeda488858d45033b520f0 checksum: 10c0/3d781f715f15f308b601d74142fae77c65679c318a3bb0a319df898f39095e738ba7ed7061cec971b19b6d33969ef9cd50fec92b034024ef3fcc25bb9a2eb3d0
languageName: node languageName: node
linkType: hard linkType: hard
@ -1497,106 +1516,106 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@typescript-eslint/eslint-plugin@npm:^8.44.1": "@typescript-eslint/eslint-plugin@npm:^8.45.0":
version: 8.44.1 version: 8.45.0
resolution: "@typescript-eslint/eslint-plugin@npm:8.44.1" resolution: "@typescript-eslint/eslint-plugin@npm:8.45.0"
dependencies: dependencies:
"@eslint-community/regexpp": "npm:^4.10.0" "@eslint-community/regexpp": "npm:^4.10.0"
"@typescript-eslint/scope-manager": "npm:8.44.1" "@typescript-eslint/scope-manager": "npm:8.45.0"
"@typescript-eslint/type-utils": "npm:8.44.1" "@typescript-eslint/type-utils": "npm:8.45.0"
"@typescript-eslint/utils": "npm:8.44.1" "@typescript-eslint/utils": "npm:8.45.0"
"@typescript-eslint/visitor-keys": "npm:8.44.1" "@typescript-eslint/visitor-keys": "npm:8.45.0"
graphemer: "npm:^1.4.0" graphemer: "npm:^1.4.0"
ignore: "npm:^7.0.0" ignore: "npm:^7.0.0"
natural-compare: "npm:^1.4.0" natural-compare: "npm:^1.4.0"
ts-api-utils: "npm:^2.1.0" ts-api-utils: "npm:^2.1.0"
peerDependencies: peerDependencies:
"@typescript-eslint/parser": ^8.44.1 "@typescript-eslint/parser": ^8.45.0
eslint: ^8.57.0 || ^9.0.0 eslint: ^8.57.0 || ^9.0.0
typescript: ">=4.8.4 <6.0.0" typescript: ">=4.8.4 <6.0.0"
checksum: 10c0/86d17444c38992a5dc0e45c107a2c2545eb26a1314c2475e7518e4b7645781be4449ec49463667d63aaffaa002e2edacbd2098104cc83e8399e3dd6e0fb6ed51 checksum: 10c0/0c60a0e5d07fa8618348db38b5a81e66143d528e1b3cdb5678bbc6c60590cd559b27c98c36f5663230fc4cf6920dff2cd604de30b58df26a37fcfcc5dc1dbd45
languageName: node languageName: node
linkType: hard linkType: hard
"@typescript-eslint/parser@npm:^8.44.1": "@typescript-eslint/parser@npm:^8.45.0":
version: 8.44.1 version: 8.45.0
resolution: "@typescript-eslint/parser@npm:8.44.1" resolution: "@typescript-eslint/parser@npm:8.45.0"
dependencies: dependencies:
"@typescript-eslint/scope-manager": "npm:8.44.1" "@typescript-eslint/scope-manager": "npm:8.45.0"
"@typescript-eslint/types": "npm:8.44.1" "@typescript-eslint/types": "npm:8.45.0"
"@typescript-eslint/typescript-estree": "npm:8.44.1" "@typescript-eslint/typescript-estree": "npm:8.45.0"
"@typescript-eslint/visitor-keys": "npm:8.44.1" "@typescript-eslint/visitor-keys": "npm:8.45.0"
debug: "npm:^4.3.4" debug: "npm:^4.3.4"
peerDependencies: peerDependencies:
eslint: ^8.57.0 || ^9.0.0 eslint: ^8.57.0 || ^9.0.0
typescript: ">=4.8.4 <6.0.0" typescript: ">=4.8.4 <6.0.0"
checksum: 10c0/278d7f6a8a686fade0cff372faabb5e114f98ce4032bd991e8905622c720f3a4867b99f7a07897aa2e26311efd8cbb84669059ab57ac99c644b9fbae7564b251 checksum: 10c0/8b419bcf795b112a39fcac05dcf147835059345b6399035ffa3f76a9d8e320f3fac79cae2fe4320dcda83fa059b017ca7626a7b4e3da08a614415c8867d169b8
languageName: node languageName: node
linkType: hard linkType: hard
"@typescript-eslint/project-service@npm:8.44.1": "@typescript-eslint/project-service@npm:8.45.0":
version: 8.44.1 version: 8.45.0
resolution: "@typescript-eslint/project-service@npm:8.44.1" resolution: "@typescript-eslint/project-service@npm:8.45.0"
dependencies: dependencies:
"@typescript-eslint/tsconfig-utils": "npm:^8.44.1" "@typescript-eslint/tsconfig-utils": "npm:^8.45.0"
"@typescript-eslint/types": "npm:^8.44.1" "@typescript-eslint/types": "npm:^8.45.0"
debug: "npm:^4.3.4" debug: "npm:^4.3.4"
peerDependencies: peerDependencies:
typescript: ">=4.8.4 <6.0.0" typescript: ">=4.8.4 <6.0.0"
checksum: 10c0/2caaa94832574658f1b451d94a319fcd476ad34171e6dff6607da9a5f91387011206487b7743fc71c9c91099632871fa6d209783cbc0a7cb3bac5cbf9d36cdae checksum: 10c0/98af065a1a3ed9d3d1eb265e09d3e9c2ae676d500a8c1d764f5609fe2c1b86749516b709804eb814fae688be7809d11748b9ae691d43c28da51dac390ca81fa9
languageName: node languageName: node
linkType: hard linkType: hard
"@typescript-eslint/scope-manager@npm:8.44.1": "@typescript-eslint/scope-manager@npm:8.45.0":
version: 8.44.1 version: 8.45.0
resolution: "@typescript-eslint/scope-manager@npm:8.44.1" resolution: "@typescript-eslint/scope-manager@npm:8.45.0"
dependencies: dependencies:
"@typescript-eslint/types": "npm:8.44.1" "@typescript-eslint/types": "npm:8.45.0"
"@typescript-eslint/visitor-keys": "npm:8.44.1" "@typescript-eslint/visitor-keys": "npm:8.45.0"
checksum: 10c0/a6f3b2d9fbda037327574bb2a7d3831cc100122fe660545a8220e4eed0ee36e42262ce78cc7438dd155100d0abca38edd9e6941e29abe6f8ba7f935223059b89 checksum: 10c0/54cd36206f6b4fc8e1e48576ed01e0d6ab20c2a9c4c7d90d5cc3a2d317dd8a13abe148ffecf471b16f1224aba5749e0905472745626bef9ae5bed771776f4abe
languageName: node languageName: node
linkType: hard linkType: hard
"@typescript-eslint/tsconfig-utils@npm:8.44.1, @typescript-eslint/tsconfig-utils@npm:^8.44.1": "@typescript-eslint/tsconfig-utils@npm:8.45.0, @typescript-eslint/tsconfig-utils@npm:^8.45.0":
version: 8.44.1 version: 8.45.0
resolution: "@typescript-eslint/tsconfig-utils@npm:8.44.1" resolution: "@typescript-eslint/tsconfig-utils@npm:8.45.0"
peerDependencies: peerDependencies:
typescript: ">=4.8.4 <6.0.0" typescript: ">=4.8.4 <6.0.0"
checksum: 10c0/05fee17cdb38729f82bdfff3bf2844435f5f8e4e55cdaf1bbff72c410ab98a4f9e166011f1eda01f715053d4bc9eb2d8d6c05e9e7114cc08946c4c81785367a0 checksum: 10c0/227a9b7a5baaf35466fd369992cb933192515df1156ddf22f438deb344c2523695208e1036f5590b20603f31724de75a47fe0ee84e2fd4c8e9f3606f23f68112
languageName: node languageName: node
linkType: hard linkType: hard
"@typescript-eslint/type-utils@npm:8.44.1": "@typescript-eslint/type-utils@npm:8.45.0":
version: 8.44.1 version: 8.45.0
resolution: "@typescript-eslint/type-utils@npm:8.44.1" resolution: "@typescript-eslint/type-utils@npm:8.45.0"
dependencies: dependencies:
"@typescript-eslint/types": "npm:8.44.1" "@typescript-eslint/types": "npm:8.45.0"
"@typescript-eslint/typescript-estree": "npm:8.44.1" "@typescript-eslint/typescript-estree": "npm:8.45.0"
"@typescript-eslint/utils": "npm:8.44.1" "@typescript-eslint/utils": "npm:8.45.0"
debug: "npm:^4.3.4" debug: "npm:^4.3.4"
ts-api-utils: "npm:^2.1.0" ts-api-utils: "npm:^2.1.0"
peerDependencies: peerDependencies:
eslint: ^8.57.0 || ^9.0.0 eslint: ^8.57.0 || ^9.0.0
typescript: ">=4.8.4 <6.0.0" typescript: ">=4.8.4 <6.0.0"
checksum: 10c0/f17b9ae60327b9187354499d67c2667811ca2b09d436cf6c13b89ba6eaceabd5695f87644a8cb4dc93da5e4188612a6bc7b07b1b022ad75ca360ff2608a64511 checksum: 10c0/ce0f4c209c2418ebeb65e7de053499fb68bf6000bdd71068594fdb8c8ac3dbbd62935a3cea233989491f7da3ef5db87e7efd2910133c6abf6d0cbf57248f6442
languageName: node languageName: node
linkType: hard linkType: hard
"@typescript-eslint/types@npm:8.44.1, @typescript-eslint/types@npm:^8.44.1": "@typescript-eslint/types@npm:8.45.0, @typescript-eslint/types@npm:^8.45.0":
version: 8.44.1 version: 8.45.0
resolution: "@typescript-eslint/types@npm:8.44.1" resolution: "@typescript-eslint/types@npm:8.45.0"
checksum: 10c0/cba2d724ac0c7e5a35945aa2f7f8ed96dd5508942e30ec88274dcd2e8fa2c177b0952403c7eb6cacbcc2014224bd36685947d140c093637e3a4e5495c52fbd9f checksum: 10c0/0213a0573c671d13bc91961a2b2e814ec7f6381ff093bce6704017bd96b2fc7fee25906c815cedb32a0601cf5071ca6c7c5f940d087c3b0d3dd7d4bc03478278
languageName: node languageName: node
linkType: hard linkType: hard
"@typescript-eslint/typescript-estree@npm:8.44.1": "@typescript-eslint/typescript-estree@npm:8.45.0":
version: 8.44.1 version: 8.45.0
resolution: "@typescript-eslint/typescript-estree@npm:8.44.1" resolution: "@typescript-eslint/typescript-estree@npm:8.45.0"
dependencies: dependencies:
"@typescript-eslint/project-service": "npm:8.44.1" "@typescript-eslint/project-service": "npm:8.45.0"
"@typescript-eslint/tsconfig-utils": "npm:8.44.1" "@typescript-eslint/tsconfig-utils": "npm:8.45.0"
"@typescript-eslint/types": "npm:8.44.1" "@typescript-eslint/types": "npm:8.45.0"
"@typescript-eslint/visitor-keys": "npm:8.44.1" "@typescript-eslint/visitor-keys": "npm:8.45.0"
debug: "npm:^4.3.4" debug: "npm:^4.3.4"
fast-glob: "npm:^3.3.2" fast-glob: "npm:^3.3.2"
is-glob: "npm:^4.0.3" is-glob: "npm:^4.0.3"
@ -1605,32 +1624,32 @@ __metadata:
ts-api-utils: "npm:^2.1.0" ts-api-utils: "npm:^2.1.0"
peerDependencies: peerDependencies:
typescript: ">=4.8.4 <6.0.0" typescript: ">=4.8.4 <6.0.0"
checksum: 10c0/cef0827614cf33eab54de2f671c6e6d8cab45286ea4980e8205a7a50504e0c0984f1c12c69c7046ee3aedf29a745f0c823324dcd36c59c81b179517d6de5017f checksum: 10c0/8c2f44a00fe859a6cd4b50157c484c5b6a1c7af5d48e89ae79c5f4924947964962fc8f478ad4c2ade788907fceee9b72d4e376508ea79b51392f91082a37d239
languageName: node languageName: node
linkType: hard linkType: hard
"@typescript-eslint/utils@npm:8.44.1": "@typescript-eslint/utils@npm:8.45.0":
version: 8.44.1 version: 8.45.0
resolution: "@typescript-eslint/utils@npm:8.44.1" resolution: "@typescript-eslint/utils@npm:8.45.0"
dependencies: dependencies:
"@eslint-community/eslint-utils": "npm:^4.7.0" "@eslint-community/eslint-utils": "npm:^4.7.0"
"@typescript-eslint/scope-manager": "npm:8.44.1" "@typescript-eslint/scope-manager": "npm:8.45.0"
"@typescript-eslint/types": "npm:8.44.1" "@typescript-eslint/types": "npm:8.45.0"
"@typescript-eslint/typescript-estree": "npm:8.44.1" "@typescript-eslint/typescript-estree": "npm:8.45.0"
peerDependencies: peerDependencies:
eslint: ^8.57.0 || ^9.0.0 eslint: ^8.57.0 || ^9.0.0
typescript: ">=4.8.4 <6.0.0" typescript: ">=4.8.4 <6.0.0"
checksum: 10c0/5f855c8a18c3112160c04d1d7bad5abee5e4712574d2f75b8a898f4e132e6e0dee3112f98010a1def47bbf0ac2fb05b6e81d343e577d144769a8d685b42b0809 checksum: 10c0/b3c83a23813b15e20e303d7153789508c01e06dec355b1a80547c59aa36998d498102f45fcd13f111031fac57270608abb04d20560248d4448fd00b1cf4dc4ab
languageName: node languageName: node
linkType: hard linkType: hard
"@typescript-eslint/visitor-keys@npm:8.44.1": "@typescript-eslint/visitor-keys@npm:8.45.0":
version: 8.44.1 version: 8.45.0
resolution: "@typescript-eslint/visitor-keys@npm:8.44.1" resolution: "@typescript-eslint/visitor-keys@npm:8.45.0"
dependencies: dependencies:
"@typescript-eslint/types": "npm:8.44.1" "@typescript-eslint/types": "npm:8.45.0"
eslint-visitor-keys: "npm:^4.2.1" eslint-visitor-keys: "npm:^4.2.1"
checksum: 10c0/b2b06c9c45b1c27d9fc05805a5d6bac3cf8f17d2ccaa59bd40718e911df474b47b85dbab3494522917d9ba469338246f226b5332c3be2da52636f8a3b842fbf7 checksum: 10c0/119adcf50c902dad7f7757bcdd88fad0a23a171d309d9b7cefe78af12e451cf84c04ae611f4c31f7e23f16c2b47665ad92e6e5648fc77d542ef306f465bf1f29
languageName: node languageName: node
linkType: hard linkType: hard
@ -1679,19 +1698,19 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@vitejs/plugin-react@npm:^5.0.3": "@vitejs/plugin-react@npm:^5.0.4":
version: 5.0.3 version: 5.0.4
resolution: "@vitejs/plugin-react@npm:5.0.3" resolution: "@vitejs/plugin-react@npm:5.0.4"
dependencies: dependencies:
"@babel/core": "npm:^7.28.4" "@babel/core": "npm:^7.28.4"
"@babel/plugin-transform-react-jsx-self": "npm:^7.27.1" "@babel/plugin-transform-react-jsx-self": "npm:^7.27.1"
"@babel/plugin-transform-react-jsx-source": "npm:^7.27.1" "@babel/plugin-transform-react-jsx-source": "npm:^7.27.1"
"@rolldown/pluginutils": "npm:1.0.0-beta.35" "@rolldown/pluginutils": "npm:1.0.0-beta.38"
"@types/babel__core": "npm:^7.20.5" "@types/babel__core": "npm:^7.20.5"
react-refresh: "npm:^0.17.0" react-refresh: "npm:^0.17.0"
peerDependencies: peerDependencies:
vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0
checksum: 10c0/3fc071455630a0584c170c544d20fc3edaccfb60a1e03ea14ca76f049f2657eb645aba9c216db016b8d70e4f894285a78fcd92ef63a2fcfa7864da378ac52761 checksum: 10c0/bb9360a4b4c0abf064d22211756b999faf23889ac150de490590ca7bd029b0ef7f4cd8ba3a32b86682a62d46fb7bebd75b3fa9835c57c78123f4a646de2e0136
languageName: node languageName: node
linkType: hard linkType: hard
@ -2452,15 +2471,6 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"color-convert@npm:^1.9.3":
version: 1.9.3
resolution: "color-convert@npm:1.9.3"
dependencies:
color-name: "npm:1.1.3"
checksum: 10c0/5ad3c534949a8c68fca8fbc6f09068f435f0ad290ab8b2f76841b9e6af7e0bb57b98cb05b0e19fe33f5d91e5a8611ad457e5f69e0a484caad1f7487fd0e8253c
languageName: node
linkType: hard
"color-convert@npm:^2.0.1": "color-convert@npm:^2.0.1":
version: 2.0.1 version: 2.0.1
resolution: "color-convert@npm:2.0.1" resolution: "color-convert@npm:2.0.1"
@ -2470,47 +2480,45 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"color-name@npm:1.1.3": "color-convert@npm:^3.0.1":
version: 1.1.3 version: 3.1.2
resolution: "color-name@npm:1.1.3" resolution: "color-convert@npm:3.1.2"
checksum: 10c0/566a3d42cca25b9b3cd5528cd7754b8e89c0eb646b7f214e8e2eaddb69994ac5f0557d9c175eb5d8f0ad73531140d9c47525085ee752a91a2ab15ab459caf6d6 dependencies:
color-name: "npm:^2.0.0"
checksum: 10c0/5b83147015024931a06b57b197d09fc1f67f2efc93dfea5f042aba4788a95b13aebe511b0a929e0e837e442fd91a60c27de8e6761ff30e1a1e2fb634cca8a976
languageName: node languageName: node
linkType: hard linkType: hard
"color-name@npm:^1.0.0, color-name@npm:~1.1.4": "color-name@npm:^2.0.0":
version: 2.0.2
resolution: "color-name@npm:2.0.2"
checksum: 10c0/40372a581fdeca099b824b6a14dac095387ae83457ed0fafe6f37053515c1094365f0d26b5f29df941be748051b490a0aa3f2ea0c29126a90ab2add482942701
languageName: node
linkType: hard
"color-name@npm:~1.1.4":
version: 1.1.4 version: 1.1.4
resolution: "color-name@npm:1.1.4" resolution: "color-name@npm:1.1.4"
checksum: 10c0/a1a3f914156960902f46f7f56bc62effc6c94e84b2cae157a526b1c1f74b677a47ec602bf68a61abfa2b42d15b7c5651c6dbe72a43af720bc588dff885b10f95 checksum: 10c0/a1a3f914156960902f46f7f56bc62effc6c94e84b2cae157a526b1c1f74b677a47ec602bf68a61abfa2b42d15b7c5651c6dbe72a43af720bc588dff885b10f95
languageName: node languageName: node
linkType: hard linkType: hard
"color-string@npm:^1.6.0": "color-string@npm:^2.0.0":
version: 1.9.1 version: 2.1.2
resolution: "color-string@npm:1.9.1" resolution: "color-string@npm:2.1.2"
dependencies: dependencies:
color-name: "npm:^1.0.0" color-name: "npm:^2.0.0"
simple-swizzle: "npm:^0.2.2" checksum: 10c0/d1d3e8123b2a6a6715e539b347ce000925305946092d566697bb872b1b8951a8699a842b4e5e6324733bef7e4cd3517c50aeecf2a6aae12efc7ca5697ac95178
checksum: 10c0/b0bfd74c03b1f837f543898b512f5ea353f71630ccdd0d66f83028d1f0924a7d4272deb278b9aef376cacf1289b522ac3fb175e99895283645a2dc3a33af2404
languageName: node languageName: node
linkType: hard linkType: hard
"color@npm:^3.1.3": "color@npm:^5.0.2":
version: 3.2.1 version: 5.0.2
resolution: "color@npm:3.2.1" resolution: "color@npm:5.0.2"
dependencies: dependencies:
color-convert: "npm:^1.9.3" color-convert: "npm:^3.0.1"
color-string: "npm:^1.6.0" color-string: "npm:^2.0.0"
checksum: 10c0/39345d55825884c32a88b95127d417a2c24681d8b57069413596d9fcbb721459ef9d9ec24ce3e65527b5373ce171b73e38dbcd9c830a52a6487e7f37bf00e83c checksum: 10c0/a5eeee197651a5fe84ab578a8477827e2c2e56b82832aae2b6c60469240be3bc1f03f99686223b1c4e48107c9e20b980475524faab7e6bab1cb9104313910f0e
languageName: node
linkType: hard
"colorspace@npm:1.1.x":
version: 1.1.4
resolution: "colorspace@npm:1.1.4"
dependencies:
color: "npm:^3.1.3"
text-hex: "npm:1.0.x"
checksum: 10c0/af5f91ff7f8e146b96e439ac20ed79b197210193bde721b47380a75b21751d90fa56390c773bb67c0aedd34ff85091883a437ab56861c779bd507d639ba7e123
languageName: node languageName: node
linkType: hard linkType: hard
@ -2574,16 +2582,16 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"cross-env@npm:^10.0.0": "cross-env@npm:^10.1.0":
version: 10.0.0 version: 10.1.0
resolution: "cross-env@npm:10.0.0" resolution: "cross-env@npm:10.1.0"
dependencies: dependencies:
"@epic-web/invariant": "npm:^1.0.0" "@epic-web/invariant": "npm:^1.0.0"
cross-spawn: "npm:^7.0.6" cross-spawn: "npm:^7.0.6"
bin: bin:
cross-env: dist/bin/cross-env.js cross-env: dist/bin/cross-env.js
cross-env-shell: dist/bin/cross-env-shell.js cross-env-shell: dist/bin/cross-env-shell.js
checksum: 10c0/d16ffc3734106577d57b6253d81ab50294623bd59f96e161033eaf99c1c308ffbaba8463c23a6c0f72e841eff467cb7007a0a551f27554fcf2bbf6598cd828f9 checksum: 10c0/834a862db456ba1fedf6c6da43436b123ae38f514fa286d6f0937c14fa83f13469f77f70f2812db041ae2d84f82bac627040b8686030aca27fbdf113dfa38b63
languageName: node languageName: node
linkType: hard linkType: hard
@ -2929,16 +2937,16 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"electron@npm:^38.1.2": "electron@npm:^38.2.0":
version: 38.1.2 version: 38.2.0
resolution: "electron@npm:38.1.2" resolution: "electron@npm:38.2.0"
dependencies: dependencies:
"@electron/get": "npm:^2.0.0" "@electron/get": "npm:^2.0.0"
"@types/node": "npm:^22.7.7" "@types/node": "npm:^22.7.7"
extract-zip: "npm:^2.0.1" extract-zip: "npm:^2.0.1"
bin: bin:
electron: cli.js electron: cli.js
checksum: 10c0/63f768e8ac396221db17c280e483ac838067e881ee61eb78c5c8f587017e51c587cc1eb687f29672b5e63c0af8a5d818d721d49aef20bac082544a8cf2d323ea checksum: 10c0/86c1a429b11d273c606d6827bdd114e6b0d57c8d12867e27c3f8542f1f5d85bda8da4330d17ad1556007860e4b2ac6aa71699a0648c9021bfdd83e4224e01c20
languageName: node languageName: node
linkType: hard linkType: hard
@ -3860,21 +3868,21 @@ __metadata:
dependencies: dependencies:
"@codemirror/search": "npm:^6.5.11" "@codemirror/search": "npm:^6.5.11"
"@codemirror/theme-one-dark": "npm:^6.1.3" "@codemirror/theme-one-dark": "npm:^6.1.3"
"@codemirror/view": "npm:^6.38.3" "@codemirror/view": "npm:^6.38.4"
"@eslint/js": "npm:^9.36.0" "@eslint/js": "npm:^9.36.0"
"@fontsource/inter": "npm:^5.2.8" "@fontsource/inter": "npm:^5.2.8"
"@mantine/core": "npm:8.3.1" "@mantine/core": "npm:8.3.1"
"@mantine/hooks": "npm:8.3.1" "@mantine/hooks": "npm:8.3.1"
"@types/node": "npm:^24.5.2" "@types/node": "npm:^24.6.1"
"@types/react": "npm:^19.1.14" "@types/react": "npm:^19.1.16"
"@types/react-dom": "npm:^19.1.9" "@types/react-dom": "npm:^19.1.9"
"@types/yauzl": "npm:^2.10.3" "@types/yauzl": "npm:^2.10.3"
"@typescript-eslint/eslint-plugin": "npm:^8.44.1" "@typescript-eslint/eslint-plugin": "npm:^8.45.0"
"@typescript-eslint/parser": "npm:^8.44.1" "@typescript-eslint/parser": "npm:^8.45.0"
"@uiw/react-codemirror": "npm:^4.25.2" "@uiw/react-codemirror": "npm:^4.25.2"
"@vitejs/plugin-react": "npm:^5.0.3" "@vitejs/plugin-react": "npm:^5.0.4"
cross-env: "npm:^10.0.0" cross-env: "npm:^10.1.0"
electron: "npm:^38.1.2" electron: "npm:^38.2.0"
electron-builder: "npm:^26.0.12" electron-builder: "npm:^26.0.12"
electron-updater: "npm:6.6.2" electron-updater: "npm:6.6.2"
electron-vite: "npm:^4.0.1" electron-vite: "npm:^4.0.1"
@ -3895,9 +3903,9 @@ __metadata:
react-error-boundary: "npm:^6.0.0" react-error-boundary: "npm:^6.0.0"
rollup-plugin-visualizer: "npm:^6.0.3" rollup-plugin-visualizer: "npm:^6.0.3"
systeminformation: "npm:^5.27.10" systeminformation: "npm:^5.27.10"
typescript: "npm:^5.9.2" typescript: "npm:^5.9.3"
vite: "npm:^7.1.7" vite: "npm:^7.1.7"
winston: "npm:^3.17.0" winston: "npm:^3.18.3"
winston-daily-rotate-file: "npm:^5.0.0" winston-daily-rotate-file: "npm:^5.0.0"
yauzl: "npm:^3.2.0" yauzl: "npm:^3.2.0"
zustand: "npm:^5.0.8" zustand: "npm:^5.0.8"
@ -4372,13 +4380,6 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"is-arrayish@npm:^0.3.1":
version: 0.3.4
resolution: "is-arrayish@npm:0.3.4"
checksum: 10c0/1fa672a2f0bedb74154440310f616c0b6e53a95cf0625522ae050f06626d1cabd1a3d8085c882dc45c61ad0e7df2529aff122810b3b4a552880bf170d6df94e0
languageName: node
linkType: hard
"is-async-function@npm:^2.0.0": "is-async-function@npm:^2.0.0":
version: 2.1.1 version: 2.1.1
resolution: "is-async-function@npm:2.1.1" resolution: "is-async-function@npm:2.1.1"
@ -6601,15 +6602,6 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"simple-swizzle@npm:^0.2.2":
version: 0.2.4
resolution: "simple-swizzle@npm:0.2.4"
dependencies:
is-arrayish: "npm:^0.3.1"
checksum: 10c0/846c3fdd1325318d5c71295cfbb99bfc9edc4c8dffdda5e6e9efe30482bbcd32cf360fc2806f46ac43ff7d09bcfaff20337bb79f826f0e6a8e366efd3cdd7868
languageName: node
linkType: hard
"simple-update-notifier@npm:2.0.0": "simple-update-notifier@npm:2.0.0":
version: 2.0.0 version: 2.0.0
resolution: "simple-update-notifier@npm:2.0.0" resolution: "simple-update-notifier@npm:2.0.0"
@ -7152,23 +7144,23 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"typescript@npm:>=5, typescript@npm:^5.9.2": "typescript@npm:>=5, typescript@npm:^5.9.3":
version: 5.9.2 version: 5.9.3
resolution: "typescript@npm:5.9.2" resolution: "typescript@npm:5.9.3"
bin: bin:
tsc: bin/tsc tsc: bin/tsc
tsserver: bin/tsserver tsserver: bin/tsserver
checksum: 10c0/cd635d50f02d6cf98ed42de2f76289701c1ec587a363369255f01ed15aaf22be0813226bff3c53e99d971f9b540e0b3cc7583dbe05faded49b1b0bed2f638a18 checksum: 10c0/6bd7552ce39f97e711db5aa048f6f9995b53f1c52f7d8667c1abdc1700c68a76a308f579cd309ce6b53646deb4e9a1be7c813a93baaf0a28ccd536a30270e1c5
languageName: node languageName: node
linkType: hard linkType: hard
"typescript@patch:typescript@npm%3A>=5#optional!builtin<compat/typescript>, typescript@patch:typescript@npm%3A^5.9.2#optional!builtin<compat/typescript>": "typescript@patch:typescript@npm%3A>=5#optional!builtin<compat/typescript>, typescript@patch:typescript@npm%3A^5.9.3#optional!builtin<compat/typescript>":
version: 5.9.2 version: 5.9.3
resolution: "typescript@patch:typescript@npm%3A5.9.2#optional!builtin<compat/typescript>::version=5.9.2&hash=5786d5" resolution: "typescript@patch:typescript@npm%3A5.9.3#optional!builtin<compat/typescript>::version=5.9.3&hash=5786d5"
bin: bin:
tsc: bin/tsc tsc: bin/tsc
tsserver: bin/tsserver tsserver: bin/tsserver
checksum: 10c0/34d2a8e23eb8e0d1875072064d5e1d9c102e0bdce56a10a25c0b917b8aa9001a9cf5c225df12497e99da107dc379360bc138163c66b55b95f5b105b50578067e checksum: 10c0/ad09fdf7a756814dce65bc60c1657b40d44451346858eea230e10f2e95a289d9183b6e32e5c11e95acc0ccc214b4f36289dcad4bf1886b0adb84d711d336a430
languageName: node languageName: node
linkType: hard linkType: hard
@ -7191,10 +7183,10 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"undici-types@npm:~7.12.0": "undici-types@npm:~7.13.0":
version: 7.12.0 version: 7.13.0
resolution: "undici-types@npm:7.12.0" resolution: "undici-types@npm:7.13.0"
checksum: 10c0/326e455bbc0026db1d6b81c76a1cf10c63f7e2f9821db2e24fdc258f482814e5bfa8481f8910d07c68e305937c5c049610fdc441c5e8b7bb0daca7154fb8a306 checksum: 10c0/44bbb0935425291351bfd8039571f017295b5d6dc5727045d0a4fea8c6ffe73a6703b48ce010f9cb539b9041a75b463f8cfe1e7309cab7486452505fb0d66151
languageName: node languageName: node
linkType: hard linkType: hard
@ -7551,12 +7543,12 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"winston@npm:^3.17.0": "winston@npm:^3.18.3":
version: 3.17.0 version: 3.18.3
resolution: "winston@npm:3.17.0" resolution: "winston@npm:3.18.3"
dependencies: dependencies:
"@colors/colors": "npm:^1.6.0" "@colors/colors": "npm:^1.6.0"
"@dabh/diagnostics": "npm:^2.0.2" "@dabh/diagnostics": "npm:^2.0.8"
async: "npm:^3.2.3" async: "npm:^3.2.3"
is-stream: "npm:^2.0.0" is-stream: "npm:^2.0.0"
logform: "npm:^2.7.0" logform: "npm:^2.7.0"
@ -7566,7 +7558,7 @@ __metadata:
stack-trace: "npm:0.0.x" stack-trace: "npm:0.0.x"
triple-beam: "npm:^1.3.0" triple-beam: "npm:^1.3.0"
winston-transport: "npm:^4.9.0" winston-transport: "npm:^4.9.0"
checksum: 10c0/ec8eaeac9a72b2598aedbff50b7dac82ce374a400ed92e7e705d7274426b48edcb25507d78cff318187c4fb27d642a0e2a39c57b6badc9af8e09d4a40636a5f7 checksum: 10c0/0bd666590d7f1f2e1fa1273b699463e14b2fcf2bab503e16bc62f275c4b52f14c3dda7bb255d5cc4cef046dd3e112c45518ec8f3c3536ab666421b7265d8c45b
languageName: node languageName: node
linkType: hard linkType: hard