From a99f93ce79dc221e9ffd7ea4cf00766685965a7f Mon Sep 17 00:00:00 2001 From: Egor Date: Tue, 16 Sep 2025 16:21:21 -0700 Subject: [PATCH] more system monitoring optimizations, trying for 1 update/sec on windows too --- package.json | 6 +- src/components/StatusBar.tsx | 16 +- src/main/modules/monitoring.ts | 15 +- src/utils/node/gpu.ts | 577 +++++++++++++++++++++++---------- yarn.lock | 30 +- 5 files changed, 437 insertions(+), 207 deletions(-) diff --git a/package.json b/package.json index 8f691c9..9703ad7 100644 --- a/package.json +++ b/package.json @@ -39,14 +39,14 @@ "license": "AGPL-3.0-or-later", "devDependencies": { "@eslint/js": "^9.35.0", - "@types/node": "^24.5.0", + "@types/node": "^24.5.1", "@types/react": "^19.1.13", "@types/react-dom": "^19.1.9", "@typescript-eslint/eslint-plugin": "^8.44.0", "@typescript-eslint/parser": "^8.44.0", "@vitejs/plugin-react": "^5.0.2", "cross-env": "^10.0.0", - "electron": "^38.1.0", + "electron": "^38.1.1", "electron-builder": "^26.0.12", "electron-vite": "^4.0.0", "eslint": "^9.35.0", @@ -74,7 +74,7 @@ "react": "^19.1.1", "react-dom": "^19.1.1", "react-error-boundary": "^6.0.0", - "systeminformation": "^5.27.9", + "systeminformation": "^5.27.10", "winston": "^3.17.0", "winston-daily-rotate-file": "^5.0.0", "yauzl": "^3.2.0", diff --git a/src/components/StatusBar.tsx b/src/components/StatusBar.tsx index 9c72d3e..5bbfac5 100644 --- a/src/components/StatusBar.tsx +++ b/src/components/StatusBar.tsx @@ -65,14 +65,14 @@ export const StatusBar = ({ maxDataPoints = 60 }: StatusBarProps) => { <> )} @@ -81,14 +81,14 @@ export const StatusBar = ({ maxDataPoints = 60 }: StatusBarProps) => { 1 ? ` ${index + 1}` : ''}`} - value={`${gpu.usage.toFixed(1)}%`} - tooltipLabel={`${gpu.usage.toFixed(1)}%`} + value={`${gpu.usage}%`} + tooltipLabel={`${gpu.usage}%`} /> 1 ? ` ${index + 1}` : ''}`} - value={`${gpu.memoryUsage.toFixed(1)}%`} - tooltipLabel={`${gpu.memoryUsed.toFixed(1)} GB / ${gpu.memoryTotal.toFixed(1)} GB (${gpu.memoryUsage.toFixed(1)}%)`} + value={`${gpu.memoryUsage}%`} + tooltipLabel={`${gpu.memoryUsed.toFixed(2)} GB / ${gpu.memoryTotal.toFixed(2)} GB (${gpu.memoryUsage}%)`} /> ))} diff --git a/src/main/modules/monitoring.ts b/src/main/modules/monitoring.ts index 94a3d20..ba3cdce 100644 --- a/src/main/modules/monitoring.ts +++ b/src/main/modules/monitoring.ts @@ -1,4 +1,3 @@ -import { platform } from 'process'; import si from 'systeminformation'; import { BrowserWindow } from 'electron'; import { logError } from '@/main/modules/logging'; @@ -46,7 +45,7 @@ let cpuInterval: ReturnType | null = null; let memoryInterval: ReturnType | null = null; let gpuInterval: ReturnType | null = null; let isRunning = false; -const updateFrequency = platform === 'win32' ? 2000 : 1000; +const updateFrequency = 1000; let mainWindow: BrowserWindow | null = null; export function startMonitoring(window: BrowserWindow) { @@ -91,7 +90,7 @@ async function collectAndSendCpuMetrics() { try { const cpuData = await si.currentLoad(); const metrics: CpuMetrics = { - usage: cpuData.currentLoad, + usage: Math.round(cpuData.currentLoad), }; if (mainWindow && !mainWindow.isDestroyed()) { @@ -108,9 +107,9 @@ async function collectAndSendMemoryMetrics() { const usedBytes = memData.active || memData.used; const totalBytes = memData.total; const metrics: MemoryMetrics = { - used: Math.round((usedBytes / (1024 * 1024 * 1024)) * 10) / 10, - total: Math.round((totalBytes / (1024 * 1024 * 1024)) * 10) / 10, - usage: (usedBytes / totalBytes) * 100, + used: usedBytes / (1024 * 1024 * 1024), + total: totalBytes / (1024 * 1024 * 1024), + usage: Math.round((usedBytes / totalBytes) * 100), }; if (mainWindow && !mainWindow.isDestroyed()) { @@ -127,12 +126,12 @@ async function collectAndSendGpuMetrics() { const metrics: GpuMetrics = { gpus: gpuData.map((gpuInfo) => ({ name: gpuInfo.deviceName, - usage: gpuInfo.usage, + usage: Math.round(gpuInfo.usage), memoryUsed: gpuInfo.memoryUsed, memoryTotal: gpuInfo.memoryTotal, memoryUsage: gpuInfo.memoryTotal > 0 - ? (gpuInfo.memoryUsed / gpuInfo.memoryTotal) * 100 + ? Math.round((gpuInfo.memoryUsed / gpuInfo.memoryTotal) * 100) : 0, })), }; diff --git a/src/utils/node/gpu.ts b/src/utils/node/gpu.ts index 3adb4c1..94447fd 100644 --- a/src/utils/node/gpu.ts +++ b/src/utils/node/gpu.ts @@ -3,6 +3,31 @@ import { join } from 'path'; import { spawn } from 'child_process'; import { platform } from 'process'; +interface CachedGPUInfo { + deviceName: string; + devicePath: string; + memoryTotal: number; +} + +interface WindowsCachedGPUInfo { + deviceName: string; + memoryTotal: number; + luid: string; +} + +interface GPUData { + deviceName: string; + usage: number; + memoryUsed: number; + memoryTotal: number; +} + +let linuxGpuCache: CachedGPUInfo[] | null = null; +let windowsGpuCache: WindowsCachedGPUInfo[] | null = null; + +let linuxCachePromise: Promise | null = null; +let windowsCachePromise: Promise | null = null; + export async function getGPUData() { if (platform === 'win32') { return getWindowsGPUData(); @@ -13,19 +38,20 @@ export async function getGPUData() { } } -async function getWindowsGPUData() { - return new Promise< - { - deviceName: string; - usage: number; - memoryUsed: number; - memoryTotal: number; - }[] - >((resolve) => { +async function initializeWindowsGPUCache() { + if (windowsGpuCache !== null) { + return windowsGpuCache; + } + + if (windowsCachePromise !== null) { + return windowsCachePromise; + } + + windowsCachePromise = new Promise((resolve) => { const script = ` -# Get GPU basic info and total VRAM from registry $gpus = Get-WmiObject -Class Win32_VideoController | Where-Object {$_.Name -notlike "*Microsoft*"} $correctVRAM = @{} +$gpuToLuid = @{} try { $regPath = "HKLM:\\SYSTEM\\CurrentControlSet\\Control\\Class\\{4d36e968-e325-11ce-bfc1-08002be10318}" @@ -42,196 +68,342 @@ try { } } catch {} -# Get VRAM usage from GPU Adapter Memory counters (what Task Manager uses) -$vramUsageByLuid = @{} try { $adapterMemory = Get-Counter "\\GPU Adapter Memory(*)\\Dedicated Usage" -ErrorAction SilentlyContinue if ($adapterMemory) { foreach ($sample in $adapterMemory.CounterSamples) { $instanceName = $sample.InstanceName - $usageBytes = $sample.CookedValue - $vramUsageByLuid[$instanceName] = $usageBytes - } - } -} catch {} - -# Get GPU utilization from performance counters -$gpuUtilization = @{} -try { - $engineCounters = Get-Counter "\\GPU Engine(*)\\Utilization Percentage" -ErrorAction SilentlyContinue - if ($engineCounters) { - $utilizationByLuid = @{} - foreach ($sample in $engineCounters.CounterSamples) { - $instanceName = $sample.InstanceName - $utilization = $sample.CookedValue - - if ($instanceName -match "luid_(0x[0-9a-fA-F]+_0x[0-9a-fA-F]+)") { + if ($instanceName -match "luid_(0x[0-9a-fA-F]+_0x[0-9a-fA-F]+)_([^_]+)") { $luid = $matches[1] - if (-not $utilizationByLuid[$luid]) { - $utilizationByLuid[$luid] = 0 - } - $utilizationByLuid[$luid] = [Math]::Max($utilizationByLuid[$luid], $utilization) - } - } - - # Find the main GPU LUID (the one with actual VRAM usage) - $mainLuid = "" - $maxVramUsage = 0 - foreach ($luid in $vramUsageByLuid.Keys) { - if ($vramUsageByLuid[$luid] -gt $maxVramUsage) { - $maxVramUsage = $vramUsageByLuid[$luid] - $mainLuid = $luid - } - } - - # Extract LUID from main adapter - if ($mainLuid -match "luid_(0x[0-9a-fA-F]+_0x[0-9a-fA-F]+)") { - $mainLuidKey = $matches[1] - foreach ($gpu in $gpus) { - if ($utilizationByLuid[$mainLuidKey]) { - $gpuUtilization[$gpu.Name] = $utilizationByLuid[$mainLuidKey] + $gpuNameFromCounter = $matches[2] + + foreach ($gpu in $gpus) { + $cleanGpuName = $gpu.Name -replace '[^a-zA-Z0-9]', '' + $cleanCounterName = $gpuNameFromCounter -replace '[^a-zA-Z0-9]', '' + + if ($cleanGpuName -eq $cleanCounterName -or $gpu.Name -like "*$gpuNameFromCounter*") { + $gpuToLuid[$gpu.Name] = $luid + break + } } } } } } catch {} -# Output results foreach ($gpu in $gpus) { $totalVRAM = $correctVRAM[$gpu.Name] if (-not $totalVRAM -or $totalVRAM -le 0) { $totalVRAM = $gpu.AdapterRAM } - # Get VRAM usage for the main GPU (highest usage LUID) - $usedVRAM = 0 - $maxUsage = 0 - foreach ($luid in $vramUsageByLuid.Keys) { - $usage = $vramUsageByLuid[$luid] - if ($usage -gt $maxUsage) { - $maxUsage = $usage - $usedVRAM = $usage - } + $luid = $gpuToLuid[$gpu.Name] + if ($luid) { + Write-Output "$($gpu.Name)|$totalVRAM|$luid" } - - $utilization = 0 - if ($gpuUtilization[$gpu.Name]) { - $utilization = $gpuUtilization[$gpu.Name] - } - - Write-Output "$($gpu.Name)|$totalVRAM|$usedVRAM|$utilization" } `; - const powershell = spawn( - 'powershell.exe', - [ - '-NoProfile', - '-NonInteractive', - '-ExecutionPolicy', - 'Bypass', - '-Command', - script, - ], - { - stdio: ['pipe', 'pipe', 'pipe'], - windowsHide: true, - shell: false, + let timeoutHandle: ReturnType | null = null; + let powershellProcess: ReturnType | null = null; + + const cleanup = () => { + if (timeoutHandle) { + clearTimeout(timeoutHandle); + timeoutHandle = null; } - ); + if (powershellProcess && !powershellProcess.killed) { + powershellProcess.kill('SIGTERM'); + } + }; - let output = ''; + try { + powershellProcess = spawn( + 'powershell.exe', + [ + '-NoProfile', + '-NonInteractive', + '-ExecutionPolicy', + 'Bypass', + '-Command', + script, + ], + { + stdio: ['pipe', 'pipe', 'pipe'], + windowsHide: true, + shell: false, + } + ); - powershell.stdout.on('data', (data) => { - output += data.toString(); - }); + let output = ''; - powershell.on('close', (code) => { - const gpus: { - deviceName: string; - usage: number; - memoryUsed: number; - memoryTotal: number; - }[] = []; + if (powershellProcess.stdout) { + powershellProcess.stdout.on('data', (data) => { + output += data.toString(); + }); + } - if (code === 0 && output.trim()) { - const lines = output.trim().split('\n'); - for (const line of lines) { - const parts = line.split('|'); - if (parts.length === 4 && parts[0]) { - const name = parts[0].trim(); - const totalRAM = parseInt(parts[1]) || 0; - const usedRAM = parseInt(parts[2]) || 0; - const utilization = parseFloat(parts[3]) || 0; + powershellProcess.on('close', (code) => { + cleanup(); + const gpus = []; - gpus.push({ - deviceName: name, - usage: Math.round(utilization * 100) / 100, - memoryUsed: usedRAM > 0 ? usedRAM / (1024 * 1024 * 1024) : 0, - memoryTotal: totalRAM > 0 ? totalRAM / (1024 * 1024 * 1024) : 0, - }); + if (code === 0 && output.trim()) { + const lines = output.trim().split('\n'); + for (const line of lines) { + const parts = line.split('|'); + if (parts.length === 3 && parts[0]) { + const name = parts[0].trim(); + const totalRAM = parseInt(parts[1]) || 0; + const luid = parts[2].trim(); + + if (name && luid && totalRAM >= 0) { + gpus.push({ + deviceName: name, + memoryTotal: + totalRAM > 0 ? totalRAM / (1024 * 1024 * 1024) : 0, + luid, + }); + } + } } } - } - resolve(gpus); - }); + windowsGpuCache = gpus; + windowsCachePromise = null; + resolve(gpus); + }); - powershell.on('error', () => resolve([])); + powershellProcess.on('error', () => { + cleanup(); + windowsGpuCache = []; + windowsCachePromise = null; + resolve([]); + }); - setTimeout(() => { - powershell.kill('SIGTERM'); + timeoutHandle = setTimeout(() => { + cleanup(); + windowsGpuCache = []; + windowsCachePromise = null; + resolve([]); + }, 8000); + } catch { + cleanup(); + windowsGpuCache = []; + windowsCachePromise = null; resolve([]); - }, 5000); + } }); + + return windowsCachePromise; } -async function getLinuxGPUData() { +async function getWindowsGPUData() { try { - const drmPath = '/sys/class/drm'; - const entries = await readdir(drmPath); - const cardEntries = entries.filter( - (entry) => entry.startsWith('card') && !entry.includes('-') - ); + const cachedGPUs = await initializeWindowsGPUCache(); - const gpus = []; - for (const card of cardEntries) { - const devicePath = join(drmPath, card, 'device'); + return new Promise((resolve) => { + const script = ` +$vramUsageByLuid = @{} +$utilizationByLuid = @{} +$job1 = $null +$job2 = $null - let deviceName = 'Unknown GPU'; +try { + $job1 = Start-Job -ScriptBlock { + try { + $adapterMemory = Get-Counter "\\GPU Adapter Memory(*)\\Dedicated Usage" -ErrorAction SilentlyContinue + if ($adapterMemory) { + $result = @{} + foreach ($sample in $adapterMemory.CounterSamples) { + $instanceName = $sample.InstanceName + $usageBytes = $sample.CookedValue + if ($instanceName -match "luid_(0x[0-9a-fA-F]+_0x[0-9a-fA-F]+)") { + $luid = $matches[1] + $result[$luid] = $usageBytes + } + } + return $result + } + } catch {} + return @{} + } + + $job2 = Start-Job -ScriptBlock { + try { + $engineCounters = Get-Counter "\\GPU Engine(*)\\Utilization Percentage" -ErrorAction SilentlyContinue + if ($engineCounters) { + $result = @{} + foreach ($sample in $engineCounters.CounterSamples) { + $instanceName = $sample.InstanceName + $utilization = $sample.CookedValue + + if ($instanceName -match "luid_(0x[0-9a-fA-F]+_0x[0-9a-fA-F]+)") { + $luid = $matches[1] + if (-not $result[$luid]) { + $result[$luid] = 0 + } + $result[$luid] = [Math]::Max($result[$luid], $utilization) + } + } + return $result + } + } catch {} + return @{} + } + + if ($job1) { $vramUsageByLuid = Receive-Job $job1 -Wait } + if ($job2) { $utilizationByLuid = Receive-Job $job2 -Wait } + +} catch {} +finally { + if ($job1) { Remove-Job $job1 -Force -ErrorAction SilentlyContinue } + if ($job2) { Remove-Job $job2 -Force -ErrorAction SilentlyContinue } +} + +foreach ($luid in $vramUsageByLuid.Keys) { + $vramUsed = $vramUsageByLuid[$luid] + $utilization = 0 + if ($utilizationByLuid[$luid]) { + $utilization = $utilizationByLuid[$luid] + } + Write-Output "$luid|$vramUsed|$utilization" +} +`; + + let timeoutHandle: ReturnType | null = null; + let powershellProcess: ReturnType | null = null; + + const cleanup = () => { + if (timeoutHandle) { + clearTimeout(timeoutHandle); + timeoutHandle = null; + } + if (powershellProcess && !powershellProcess.killed) { + powershellProcess.kill('SIGTERM'); + } + }; try { - const deviceNameData = await readFile(`${devicePath}/device`, 'utf8'); - const deviceId = deviceNameData.trim(); + powershellProcess = spawn( + 'powershell.exe', + [ + '-NoProfile', + '-NonInteractive', + '-ExecutionPolicy', + 'Bypass', + '-Command', + script, + ], + { + stdio: ['pipe', 'pipe', 'pipe'], + windowsHide: true, + shell: false, + } + ); - const vendorData = await readFile(`${devicePath}/vendor`, 'utf8'); - const vendorId = vendorData.trim(); + let output = ''; - const modalias = await readFile(`${devicePath}/modalias`, 'utf8'); - - if (vendorId === '0x1002') { - deviceName = 'AMD GPU'; - } else if (vendorId === '0x10de') { - deviceName = 'NVIDIA GPU'; - } else if (vendorId === '0x8086') { - deviceName = 'Intel GPU'; - } else { - deviceName = `GPU (${vendorId}:${deviceId})`; + if (powershellProcess.stdout) { + powershellProcess.stdout.on('data', (data) => { + output += data.toString(); + }); } - if (modalias.includes('i915')) { - deviceName = 'Intel GPU'; - } else if (modalias.includes('amdgpu')) { - deviceName = 'AMD GPU'; - } else if ( - modalias.includes('nouveau') || - modalias.includes('nvidia') - ) { - deviceName = 'NVIDIA GPU'; - } + powershellProcess.on('close', (code) => { + cleanup(); + const gpus: GPUData[] = []; + + if (code === 0 && output.trim() && cachedGPUs.length > 0) { + const luidToData = new Map< + string, + { vramUsed: number; utilization: number } + >(); + + const lines = output.trim().split('\n'); + for (const line of lines) { + const parts = line.split('|'); + if (parts.length === 3) { + const luid = parts[0].trim(); + const vramUsed = Math.max(0, parseInt(parts[1]) || 0); + const utilization = Math.max( + 0, + Math.min(100, parseFloat(parts[2]) || 0) + ); + + luidToData.set(luid, { vramUsed, utilization }); + } + } + + for (const cachedGPU of cachedGPUs) { + const gpuData = luidToData.get(cachedGPU.luid); + if (gpuData) { + gpus.push({ + deviceName: cachedGPU.deviceName, + usage: gpuData.utilization, + memoryUsed: + gpuData.vramUsed > 0 + ? parseFloat( + (gpuData.vramUsed / (1024 * 1024 * 1024)).toFixed(2) + ) + : 0, + memoryTotal: parseFloat( + Math.max(0, cachedGPU.memoryTotal).toFixed(2) + ), + }); + } + } + } + + resolve(gpus); + }); + + powershellProcess.on('error', () => { + cleanup(); + resolve([]); + }); + + timeoutHandle = setTimeout(() => { + cleanup(); + resolve([]); + }, 8000); } catch { + cleanup(); + resolve([]); + } + }); + } catch { + return []; + } +} + +async function initializeLinuxGPUCache() { + if (linuxGpuCache !== null) { + return linuxGpuCache; + } + + if (linuxCachePromise !== null) { + return linuxCachePromise; + } + + linuxCachePromise = (async () => { + try { + const drmPath = '/sys/class/drm'; + const entries = await readdir(drmPath); + const cardEntries = entries.filter( + (entry) => entry.startsWith('card') && !entry.includes('-') + ); + + const gpus = []; + for (const card of cardEntries) { + const devicePath = join(drmPath, card, 'device'); + + let deviceName = 'Unknown GPU'; + try { - const modalias = await readFile(`${devicePath}/modalias`, 'utf8'); + const [modalias] = await Promise.all([ + readFile(`${devicePath}/modalias`, 'utf8').catch(() => ''), + ]); + if (modalias.includes('i915')) { deviceName = 'Intel GPU'; } else if (modalias.includes('amdgpu')) { @@ -241,37 +413,96 @@ async function getLinuxGPUData() { modalias.includes('nvidia') ) { deviceName = 'NVIDIA GPU'; + } else { + try { + const [vendorData, deviceData] = await Promise.all([ + readFile(`${devicePath}/vendor`, 'utf8').catch(() => ''), + readFile(`${devicePath}/device`, 'utf8').catch(() => ''), + ]); + + const vendorId = vendorData.trim(); + const deviceId = deviceData.trim(); + + if (vendorId === '0x1002') { + deviceName = 'AMD GPU'; + } else if (vendorId === '0x10de') { + deviceName = 'NVIDIA GPU'; + } else if (vendorId === '0x8086') { + deviceName = 'Intel GPU'; + } else { + deviceName = `GPU (${vendorId}:${deviceId})`; + } + } catch { + void 0; + } } } catch { void 0; } + + try { + const memTotalData = await readFile( + `${devicePath}/mem_info_vram_total`, + 'utf8' + ); + const memoryTotal = Math.max( + 0, + (parseInt(memTotalData.trim(), 10) || 0) / (1024 * 1024 * 1024) + ); + + if (memoryTotal > 0) { + gpus.push({ + deviceName, + devicePath, + memoryTotal, + }); + } + } catch { + continue; + } } - try { - const usageData = await readFile( - `${devicePath}/gpu_busy_percent`, - 'utf8' - ); - const memUsedData = await readFile( - `${devicePath}/mem_info_vram_used`, - 'utf8' - ); - const memTotalData = await readFile( - `${devicePath}/mem_info_vram_total`, - 'utf8' - ); + linuxGpuCache = gpus; + linuxCachePromise = null; + return gpus; + } catch { + linuxGpuCache = []; + linuxCachePromise = null; + return []; + } + })(); - const usage = parseInt(usageData.trim(), 10) || 0; - const memoryUsed = - (parseInt(memUsedData.trim(), 10) || 0) / (1024 * 1024 * 1024); - const memoryTotal = - (parseInt(memTotalData.trim(), 10) || 0) / (1024 * 1024 * 1024); + return linuxCachePromise; +} + +async function getLinuxGPUData() { + try { + const cachedGPUs = await initializeLinuxGPUCache(); + + const gpus: GPUData[] = []; + for (const cachedGPU of cachedGPUs) { + try { + const [usageData, memUsedData] = await Promise.all([ + readFile(`${cachedGPU.devicePath}/gpu_busy_percent`, 'utf8'), + readFile(`${cachedGPU.devicePath}/mem_info_vram_used`, 'utf8'), + ]); + + const usage = Math.max( + 0, + Math.min(100, parseInt(usageData.trim(), 10) || 0) + ); + const memoryUsed = Math.max( + 0, + (parseInt(memUsedData.trim(), 10) || 0) / (1024 * 1024 * 1024) + ); gpus.push({ - deviceName, + deviceName: cachedGPU.deviceName, usage, - memoryUsed, - memoryTotal, + memoryUsed: parseFloat(memoryUsed.toFixed(2)), + memoryTotal: parseFloat( + Math.max(0, cachedGPU.memoryTotal).toFixed(2) + ), }); } catch { continue; diff --git a/yarn.lock b/yarn.lock index c898897..9bcc3c7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1287,12 +1287,12 @@ __metadata: languageName: node linkType: hard -"@types/node@npm:*, @types/node@npm:^24.5.0": - version: 24.5.0 - resolution: "@types/node@npm:24.5.0" +"@types/node@npm:*, @types/node@npm:^24.5.1": + version: 24.5.1 + resolution: "@types/node@npm:24.5.1" dependencies: undici-types: "npm:~7.12.0" - checksum: 10c0/c5beff68481e2cc667279a1478b34a1cfd048dbff914219cb5888967938d134907836b6c4d6d141dc862489cb09ef28f7d446c7a3b475181fd126c0fcd2916fa + checksum: 10c0/5f0cb038be789b58170e616452ba1f8ebb85bf2fbce58a7e32b1eb08391f64f5e31a9cdbccefbfcd9e6d73b66b564b5e037a1d678ab20213559a32e1d7b6ce17 languageName: node linkType: hard @@ -2705,16 +2705,16 @@ __metadata: languageName: node linkType: hard -"electron@npm:^38.1.0": - version: 38.1.0 - resolution: "electron@npm:38.1.0" +"electron@npm:^38.1.1": + version: 38.1.1 + resolution: "electron@npm:38.1.1" dependencies: "@electron/get": "npm:^2.0.0" "@types/node": "npm:^22.7.7" extract-zip: "npm:^2.0.1" bin: electron: cli.js - checksum: 10c0/186082b15862b0e9617828ca395a79311ebe2a713bb2eb15a67cf6bea208e8cda892395a143e72915e189088ac71e91b29c1a46a0c4d343022cbc33004d4d302 + checksum: 10c0/0b1e5955679de6b9a9a12fa7a51beaaa5dcf15655888670c39e3a49914f8dba580a1f94b46d83e7f8e5dc7fd22c16b130dd5040208d7a86431cf06e16933d9e8 languageName: node linkType: hard @@ -3648,7 +3648,7 @@ __metadata: "@fontsource/inter": "npm:^5.2.7" "@mantine/core": "npm:^8.3.1" "@mantine/hooks": "npm:^8.3.1" - "@types/node": "npm:^24.5.0" + "@types/node": "npm:^24.5.1" "@types/react": "npm:^19.1.13" "@types/react-dom": "npm:^19.1.9" "@types/yauzl": "npm:^2.10.3" @@ -3657,7 +3657,7 @@ __metadata: "@vitejs/plugin-react": "npm:^5.0.2" axios: "npm:^1.12.2" cross-env: "npm:^10.0.0" - electron: "npm:^38.1.0" + electron: "npm:^38.1.1" electron-builder: "npm:^26.0.12" electron-vite: "npm:^4.0.0" eslint: "npm:^9.35.0" @@ -3676,7 +3676,7 @@ __metadata: react-dom: "npm:^19.1.1" react-error-boundary: "npm:^6.0.0" rollup-plugin-visualizer: "npm:^6.0.3" - systeminformation: "npm:^5.27.9" + systeminformation: "npm:^5.27.10" typescript: "npm:^5.9.2" vite: "npm:^7.1.5" winston: "npm:^3.17.0" @@ -6694,12 +6694,12 @@ __metadata: languageName: node linkType: hard -"systeminformation@npm:^5.27.9": - version: 5.27.9 - resolution: "systeminformation@npm:5.27.9" +"systeminformation@npm:^5.27.10": + version: 5.27.10 + resolution: "systeminformation@npm:5.27.10" bin: systeminformation: lib/cli.js - checksum: 10c0/d65aeb68e40d432fb1ec6e1723fa147959cbeb1b43a25c2014b768f0ee099266da6370b3f1593a6a7ca77643f58c9b754d470d225a7afd466d1108c846a67a3c + checksum: 10c0/aaaafb3d5738150e4d63908b4516f712810ed9047dc69ba061eacb1c2aa2824bfc352a1dff596e9d81db8a75c2f27da1a3e5daaa88fffb658a3f5a68288a1d02 conditions: (os=darwin | os=linux | os=win32 | os=freebsd | os=openbsd | os=netbsd | os=sunos | os=android) languageName: node linkType: hard